diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/acinclude.m4 openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/acinclude.m4 --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/acinclude.m4 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/acinclude.m4 2020-03-11 16:15:44.000000000 +0000 @@ -183,6 +183,8 @@ [AC_DEFINE([HAVE_TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST], [1], [Define to 1 if TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST is avaiable.])]) + AC_CHECK_MEMBERS([struct tcf_t.firstuse], [], [], [#include ]) + AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([#include ], [ int x = TCA_VLAN_PUSH_VLAN_PRIORITY; @@ -242,7 +244,6 @@ esac DPDK_LIB="-ldpdk" - DPDK_EXTRA_LIB="" ovs_save_CFLAGS="$CFLAGS" ovs_save_LDFLAGS="$LDFLAGS" @@ -255,13 +256,12 @@ AC_LANG_PROGRAM( [ #include -#if RTE_LIBRTE_VHOST_NUMA +#if defined(RTE_LIBRTE_VHOST_NUMA) || defined(RTE_EAL_NUMA_AWARE_HUGEPAGES) #error #endif ], []) ], [], [AC_SEARCH_LIBS([get_mempolicy],[numa],[],[AC_MSG_ERROR([unable to find libnuma, install the dependency package])]) - DPDK_EXTRA_LIB="-lnuma" AC_DEFINE([VHOST_NUMA], [1], [NUMA Aware vHost support detected in DPDK.])]) AC_COMPILE_IFELSE([ @@ -274,7 +274,6 @@ ], []) ], [], [AC_SEARCH_LIBS([pcap_dump],[pcap],[],[AC_MSG_ERROR([unable to find libpcap, install the dependency package])]) - DPDK_EXTRA_LIB="-lpcap" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM( [ @@ -297,7 +296,7 @@ DPDKLIB_FOUND=false save_LIBS=$LIBS for extras in "" "-ldl"; do - LIBS="$DPDK_LIB $extras $save_LIBS $DPDK_EXTRA_LIB" + LIBS="$DPDK_LIB $extras $save_LIBS" AC_LINK_IFELSE( [AC_LANG_PROGRAM([#include #include ], @@ -467,8 +466,10 @@ OVS_GREP_IFELSE([$KSRC/include/linux/err.h], [IS_ERR_OR_NULL]) OVS_GREP_IFELSE([$KSRC/include/linux/err.h], [PTR_ERR_OR_ZERO]) - OVS_GREP_IFELSE([$KSRC/include/linux/jump_label.h], [DEFINE_STATIC_KEY_FALSE], + OVS_GREP_IFELSE([$KSRC/include/linux/jump_label.h], [static_branch_unlikely(], [OVS_DEFINE([HAVE_UPSTREAM_STATIC_KEY])]) + OVS_GREP_IFELSE([$KSRC/include/linux/jump_label.h], [DEFINE_STATIC_KEY_FALSE], + [OVS_DEFINE([HAVE_DEFINE_STATIC_KEY])]) OVS_GREP_IFELSE([$KSRC/include/linux/etherdevice.h], [eth_hw_addr_random]) OVS_GREP_IFELSE([$KSRC/include/linux/etherdevice.h], [ether_addr_copy]) @@ -584,6 +585,8 @@ [ndo_change_mtu], [OVS_DEFINE([HAVE_RHEL7_MAX_MTU])]) OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [nf_hook_state]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netfilter.h], [nf_hook_state], + [struct net ], [OVS_DEFINE([HAVE_NF_HOOK_STATE_NET])]) OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [nf_register_net_hook]) OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [nf_hookfn.*nf_hook_ops], [OVS_DEFINE([HAVE_NF_HOOKFN_ARG_OPS])]) @@ -615,8 +618,8 @@ [nf_ct_is_untracked]) OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_zones.h], [nf_ct_zone_init]) - OVS_FIND_FIELD_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_l3proto.h], - [net_ns_get]) + OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_l3proto.h], + [net_ns_get]) OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_labels.h], [nf_connlabels_get]) OVS_FIND_PARAM_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_labels.h], @@ -893,6 +896,27 @@ [OVS_DEFINE([HAVE_VOID_NDO_GET_STATS64])]) OVS_GREP_IFELSE([$KSRC/include/linux/timer.h], [init_timer_deferrable], [OVS_DEFINE([HAVE_INIT_TIMER_DEFERRABLE])]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/net/inet_frag.h], [inet_frags], + [rnd], + [OVS_DEFINE([HAVE_INET_FRAGS_RND])]) + OVS_GREP_IFELSE([$KSRC/include/linux/overflow.h], [__LINUX_OVERFLOW_H], + [OVS_DEFINE([HAVE_OVERFLOW_H])]) + OVS_GREP_IFELSE([$KSRC/include/linux/overflow.h], [struct_size], + [OVS_DEFINE([HAVE_STRUCT_SIZE])]) + OVS_GREP_IFELSE([$KSRC/include/linux/mm.h], [kvmalloc_array], + [OVS_DEFINE([HAVE_KVMALLOC_ARRAY])]) + OVS_GREP_IFELSE([$KSRC/include/linux/mm.h], [kvmalloc_node], + [OVS_DEFINE([HAVE_KVMALLOC_NODE])]) + OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_l3proto.h], + [nf_conntrack_l3proto], + [OVS_DEFINE([HAVE_NF_CONNTRACK_L3PROATO_H])]) + OVS_FIND_PARAM_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_core.h], + [nf_conntrack_in], [nf_hook_state], + [OVS_DEFINE([HAVE_NF_CONNTRACK_IN_TAKES_NF_HOOK_STATE])]) + OVS_GREP_IFELSE([$KSRC/include/net/ipv6_frag.h], [IP6_DEFRAG_CONNTRACK_IN], + [OVS_DEFINE([HAVE_IPV6_FRAG_H])]) + OVS_GREP_IFELSE([$KSRC/include/net/dst_ops.h], [bool confirm_neigh], + [OVS_DEFINE([HAVE_DST_OPS_CONFIRM_NEIGH])]) if cmp -s datapath/linux/kcompat.h.new \ datapath/linux/kcompat.h >/dev/null 2>&1; then diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/build-aux/generate-dhparams-c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/build-aux/generate-dhparams-c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/build-aux/generate-dhparams-c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/build-aux/generate-dhparams-c 2020-03-11 16:15:44.000000000 +0000 @@ -25,6 +25,7 @@ (openssl dhparam -C -in lib/dh1024.pem -noout && openssl dhparam -C -in lib/dh2048.pem -noout && openssl dhparam -C -in lib/dh4096.pem -noout) | sed ' + s/^static DH/DH/ s/\(get_dh[0-9]*\)()/\1(void)/ s/\(DH_set0_pqg\)/my_\1/ s/[ ]*$// diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/configure.ac openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/configure.ac --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/configure.ac 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/configure.ac 2020-03-11 16:15:44.000000000 +0000 @@ -13,7 +13,7 @@ # limitations under the License. AC_PREREQ(2.63) -AC_INIT(openvswitch, 2.10.1, bugs@openvswitch.org) +AC_INIT(openvswitch, 2.10.5, bugs@openvswitch.org) AC_CONFIG_SRCDIR([datapath/datapath.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) @@ -110,7 +110,7 @@ #include ]]) AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r sendmmsg clock_gettime]) AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h]) -AC_CHECK_HEADERS([linux/net_namespace.h stdatomic.h]) +AC_CHECK_HEADERS([linux/net_namespace.h stdatomic.h bits/floatn-common.h]) AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include #include ]]) @@ -173,6 +173,7 @@ OVS_ENABLE_OPTION([-Qunused-arguments]) OVS_ENABLE_OPTION([-Wshadow]) OVS_ENABLE_OPTION([-Wno-null-pointer-arithmetic]) +OVS_ENABLE_OPTION([-Warray-bounds-pointer-arithmetic]) OVS_CONDITIONAL_CC_OPTION([-Wno-unused], [HAVE_WNO_UNUSED]) OVS_CONDITIONAL_CC_OPTION([-Wno-unused-parameter], [HAVE_WNO_UNUSED_PARAMETER]) OVS_ENABLE_WERROR diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/compat.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/compat.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/compat.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/compat.h 2020-03-11 16:15:44.000000000 +0000 @@ -28,6 +28,13 @@ #include #include +/* Fix grsecurity patch compilation issue. */ +#ifdef CONSTIFY_PLUGIN +#include +#undef __read_mostly +#define __read_mostly +#endif + /* Even though vanilla 3.10 kernel has grp->id, RHEL 7 kernel is missing * this field. */ #ifdef HAVE_GENL_MULTICAST_GROUP_WITH_ID diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/conntrack.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/conntrack.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/conntrack.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/conntrack.c 2020-03-11 16:15:44.000000000 +0000 @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef CONFIG_NF_NAT_NEEDED #include @@ -569,6 +570,11 @@ return -EPFNOSUPPORT; } + /* The key extracted from the fragment that completed this datagram + * likely didn't have an L4 header, so regenerate it. + */ + ovs_flow_key_update_l3l4(skb, key); + key->ip.frag = OVS_FRAG_TYPE_NONE; skb_clear_hash(skb); skb->ignore_df = 1; @@ -987,6 +993,11 @@ struct nf_conn *ct; if (!cached) { + struct nf_hook_state state = { + .hook = NF_INET_PRE_ROUTING, + .pf = info->family, + .net = net, + }; struct nf_conn *tmpl = info->ct; int err; @@ -998,8 +1009,7 @@ nf_ct_set(skb, tmpl, IP_CT_NEW); } - err = nf_conntrack_in(net, info->family, - NF_INET_PRE_ROUTING, skb); + err = nf_conntrack_in(skb, &state); if (err != NF_ACCEPT) return -ENOENT; @@ -1687,10 +1697,6 @@ OVS_NLERR(log, "Failed to allocate conntrack template"); return -ENOMEM; } - - __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status); - nf_conntrack_get(&ct_info.ct->ct_general); - if (helper) { err = ovs_ct_add_helper(&ct_info, helper, key, log); if (err) @@ -1702,6 +1708,8 @@ if (err) goto err_free_ct; + __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status); + nf_conntrack_get(&ct_info.ct->ct_general); return 0; err_free_ct: __ovs_ct_free_action(&ct_info); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/flow.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/flow.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/flow.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/flow.c 2020-03-11 16:15:44.000000000 +0000 @@ -254,21 +254,18 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) { + unsigned short frag_off; + unsigned int payload_ofs = 0; unsigned int nh_ofs = skb_network_offset(skb); unsigned int nh_len; - int payload_ofs; struct ipv6hdr *nh; - uint8_t nexthdr; - __be16 frag_off; - int err; + int err, nexthdr, flags = 0; err = check_header(skb, nh_ofs + sizeof(*nh)); if (unlikely(err)) return err; nh = ipv6_hdr(skb); - nexthdr = nh->nexthdr; - payload_ofs = (u8 *)(nh + 1) - skb->data; key->ip.proto = NEXTHDR_NONE; key->ip.tos = ipv6_get_dsfield(nh); @@ -277,22 +274,23 @@ key->ipv6.addr.src = nh->saddr; key->ipv6.addr.dst = nh->daddr; - payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off); - - if (frag_off) { - if (frag_off & htons(~0x7)) + nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags); + if (flags & IP6_FH_F_FRAG) { + if (frag_off) { key->ip.frag = OVS_FRAG_TYPE_LATER; - else - key->ip.frag = OVS_FRAG_TYPE_FIRST; + key->ip.proto = nexthdr; + return 0; + } + key->ip.frag = OVS_FRAG_TYPE_FIRST; } else { key->ip.frag = OVS_FRAG_TYPE_NONE; } - /* Delayed handling of error in ipv6_skip_exthdr() as it - * always sets frag_off to a valid value which may be + /* Delayed handling of error in ipv6_find_hdr() as it + * always sets flags and frag_off to a valid value which may be * used to set key->ip.frag above. */ - if (unlikely(payload_ofs < 0)) + if (unlikely(nexthdr < 0)) return -EPROTO; nh_len = payload_ofs - nh_ofs; @@ -543,79 +541,14 @@ } /** - * key_extract - extracts a flow key from an Ethernet frame. + * key_extract_l3l4 - extracts L3/L4 header information. * @skb: sk_buff that contains the frame, with skb->data pointing to the - * Ethernet header + * L3 header * @key: output flow key - * - * The caller must ensure that skb->len >= ETH_HLEN. - * - * Returns 0 if successful, otherwise a negative errno value. - * - * Initializes @skb header fields as follows: - * - * - skb->mac_header: the L2 header. - * - * - skb->network_header: just past the L2 header, or just past the - * VLAN header, to the first byte of the L2 payload. - * - * - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6 - * on output, then just past the IP header, if one is present and - * of a correct length, otherwise the same as skb->network_header. - * For other key->eth.type values it is left untouched. - * - * - skb->protocol: the type of the data starting at skb->network_header. - * Equals to key->eth.type. */ -static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) +static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key) { int error; - struct ethhdr *eth; - - /* Flags are always used as part of stats */ - key->tp.flags = 0; - - skb_reset_mac_header(skb); - - /* Link layer. */ - clear_vlan(key); - if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) { - if (unlikely(eth_type_vlan(skb->protocol))) - return -EINVAL; - - skb_reset_network_header(skb); - key->eth.type = skb->protocol; - } else { - eth = eth_hdr(skb); - ether_addr_copy(key->eth.src, eth->h_source); - ether_addr_copy(key->eth.dst, eth->h_dest); - - __skb_pull(skb, 2 * ETH_ALEN); - /* We are going to push all headers that we pull, so no need to - * update skb->csum here. - */ - - if (unlikely(parse_vlan(skb, key))) - return -ENOMEM; - - key->eth.type = parse_ethertype(skb); - if (unlikely(key->eth.type == htons(0))) - return -ENOMEM; - - /* Multiple tagged packets need to retain TPID to satisfy - * skb_vlan_pop(), which will later shift the ethertype into - * skb->protocol. - */ - if (key->eth.cvlan.tci & htons(VLAN_TAG_PRESENT)) - skb->protocol = key->eth.cvlan.tpid; - else - skb->protocol = key->eth.type; - - skb_reset_network_header(skb); - __skb_push(skb, skb->data - skb_mac_header(skb)); - } - - skb_reset_mac_len(skb); /* Network layer. */ if (key->eth.type == htons(ETH_P_IP)) { @@ -644,6 +577,7 @@ offset = nh->frag_off & htons(IP_OFFSET); if (offset) { key->ip.frag = OVS_FRAG_TYPE_LATER; + memset(&key->tp, 0, sizeof(key->tp)); return 0; } #ifdef HAVE_SKB_GSO_UDP @@ -766,8 +700,10 @@ return error; } - if (key->ip.frag == OVS_FRAG_TYPE_LATER) + if (key->ip.frag == OVS_FRAG_TYPE_LATER) { + memset(&key->tp, 0, sizeof(key->tp)); return 0; + } #ifdef HAVE_SKB_GSO_UDP if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP) key->ip.frag = OVS_FRAG_TYPE_FIRST; @@ -816,6 +752,92 @@ return 0; } +/** + * key_extract - extracts a flow key from an Ethernet frame. + * @skb: sk_buff that contains the frame, with skb->data pointing to the + * Ethernet header + * @key: output flow key + * + * The caller must ensure that skb->len >= ETH_HLEN. + * + * Returns 0 if successful, otherwise a negative errno value. + * + * Initializes @skb header fields as follows: + * + * - skb->mac_header: the L2 header. + * + * - skb->network_header: just past the L2 header, or just past the + * VLAN header, to the first byte of the L2 payload. + * + * - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6 + * on output, then just past the IP header, if one is present and + * of a correct length, otherwise the same as skb->network_header. + * For other key->eth.type values it is left untouched. + * + * - skb->protocol: the type of the data starting at skb->network_header. + * Equals to key->eth.type. + */ +static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) +{ + struct ethhdr *eth; + + /* Flags are always used as part of stats */ + key->tp.flags = 0; + + skb_reset_mac_header(skb); + + /* Link layer. */ + clear_vlan(key); + if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) { + if (unlikely(eth_type_vlan(skb->protocol))) + return -EINVAL; + + skb_reset_network_header(skb); + key->eth.type = skb->protocol; + } else { + eth = eth_hdr(skb); + ether_addr_copy(key->eth.src, eth->h_source); + ether_addr_copy(key->eth.dst, eth->h_dest); + + __skb_pull(skb, 2 * ETH_ALEN); + /* We are going to push all headers that we pull, so no need to + * update skb->csum here. + */ + + if (unlikely(parse_vlan(skb, key))) + return -ENOMEM; + + key->eth.type = parse_ethertype(skb); + if (unlikely(key->eth.type == htons(0))) + return -ENOMEM; + + /* Multiple tagged packets need to retain TPID to satisfy + * skb_vlan_pop(), which will later shift the ethertype into + * skb->protocol. + */ + if (key->eth.cvlan.tci & htons(VLAN_CFI_MASK)) + skb->protocol = key->eth.cvlan.tpid; + else + skb->protocol = key->eth.type; + + skb_reset_network_header(skb); + __skb_push(skb, skb->data - skb_mac_header(skb)); + } + + skb_reset_mac_len(skb); + + /* Fill out L3/L4 key info, if any */ + return key_extract_l3l4(skb, key); +} + +/* In the case of conntrack fragment handling it expects L3 headers, + * add a helper. + */ +int ovs_flow_key_update_l3l4(struct sk_buff *skb, struct sw_flow_key *key) +{ + return key_extract_l3l4(skb, key); +} + int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) { int res; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/flow.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/flow.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/flow.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/flow.h 2020-03-11 16:15:44.000000000 +0000 @@ -284,6 +284,7 @@ /* Update the non-metadata part of the flow key using skb. */ int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key); +int ovs_flow_key_update_l3l4(struct sk_buff *skb, struct sw_flow_key *key); int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, struct sk_buff *skb, struct sw_flow_key *key); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/flow_netlink.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/flow_netlink.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/flow_netlink.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/flow_netlink.c 2020-03-11 16:15:44.000000000 +0000 @@ -502,7 +502,7 @@ return -EINVAL; } - if (!nz || !is_all_zero(nla_data(nla), expected_len)) { + if (!nz || !is_all_zero(nla_data(nla), nla_len(nla))) { attrs |= 1ULL << type; a[type] = nla; } @@ -2311,14 +2311,14 @@ struct sw_flow_actions *acts; int new_acts_size; - int req_size = NLA_ALIGN(attr_len); + size_t req_size = NLA_ALIGN(attr_len); int next_offset = offsetof(struct sw_flow_actions, actions) + (*sfa)->actions_len; if (req_size <= (ksize(*sfa) - next_offset)) goto out; - new_acts_size = ksize(*sfa) * 2; + new_acts_size = max(next_offset + req_size, ksize(*sfa) * 2); if (new_acts_size > MAX_ACTIONS_BUFSIZE) { if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size) { @@ -2998,7 +2998,7 @@ * is already present */ if (mac_proto != MAC_PROTO_NONE) return -EINVAL; - mac_proto = MAC_PROTO_NONE; + mac_proto = MAC_PROTO_ETHERNET; break; case OVS_ACTION_ATTR_POP_ETH: @@ -3006,7 +3006,7 @@ return -EINVAL; if (vlan_tci & htons(VLAN_TAG_PRESENT)) return -EINVAL; - mac_proto = MAC_PROTO_ETHERNET; + mac_proto = MAC_PROTO_NONE; break; case OVS_ACTION_ATTR_PUSH_NSH: diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/linux/mm.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/linux/mm.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/linux/mm.h 1970-01-01 00:00:00.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/linux/mm.h 2020-03-11 16:15:44.000000000 +0000 @@ -0,0 +1,44 @@ +#ifndef OVS_MM_H +#define OVS_MM_H + +#include + +#ifndef HAVE_KVMALLOC_ARRAY +#ifndef HAVE_KVMALLOC_NODE +extern void *vmalloc_node(unsigned long size, int node); +#define kvmalloc_node(a, b, c) vmalloc_node(a, c) +#else +extern void *kvmalloc_node(size_t size, gfp_t flags, int node); +#endif /* HAVE_KVMALLOC_NODE */ +static inline void *kvmalloc(size_t size, gfp_t flags) +{ + return kvmalloc_node(size, flags, NUMA_NO_NODE); +} +static inline void *kvzalloc_node(size_t size, gfp_t flags, int node) +{ + return kvmalloc_node(size, flags | __GFP_ZERO, node); +} +static inline void *kvzalloc(size_t size, gfp_t flags) +{ + return kvmalloc(size, flags | __GFP_ZERO); +} + +static inline void *kvmalloc_array(size_t n, size_t size, gfp_t flags) +{ + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) + return NULL; + + return kvmalloc(bytes, flags); +} + +static inline void *kvcalloc(size_t n, size_t size, gfp_t flags) +{ + return kvmalloc_array(n, size, flags | __GFP_ZERO); +} + +#endif +#include_next +#endif /* OVS_MM_H */ + diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/linux/netfilter.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/linux/netfilter.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/linux/netfilter.h 1970-01-01 00:00:00.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/linux/netfilter.h 2020-03-11 16:15:44.000000000 +0000 @@ -0,0 +1,19 @@ +#ifndef __NETFILTER_WRAPPER_H +#define __NETFILTER_WRAPPER_H + +#include_next + +#if !defined(HAVE_NF_HOOK_STATE) || !defined(HAVE_NF_HOOK_STATE_NET) +struct rpl_nf_hook_state { + unsigned int hook; + u_int8_t pf; + struct net_device *in; + struct net_device *out; + struct sock *sk; + struct net *net; + int (*okfn)(struct net *, struct sock *, struct sk_buff *); +}; +#define nf_hook_state rpl_nf_hook_state +#endif + +#endif /* __NETFILTER_WRAPPER_H */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/linux/overflow.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/linux/overflow.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/linux/overflow.h 1970-01-01 00:00:00.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/linux/overflow.h 2020-03-11 16:15:44.000000000 +0000 @@ -0,0 +1,313 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +#if defined(HAVE_OVERFLOW_H) && defined(HAVE_STRUCT_SIZE) +#include_next +#else +#ifndef __LINUX_OVERFLOW_H +#define __LINUX_OVERFLOW_H + +#include + +/* + * In the fallback code below, we need to compute the minimum and + * maximum values representable in a given type. These macros may also + * be useful elsewhere, so we provide them outside the + * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block. + * + * It would seem more obvious to do something like + * + * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0) + * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0) + * + * Unfortunately, the middle expressions, strictly speaking, have + * undefined behaviour, and at least some versions of gcc warn about + * the type_max expression (but not if -fsanitize=undefined is in + * effect; in that case, the warning is deferred to runtime...). + * + * The slightly excessive casting in type_min is to make sure the + * macros also produce sensible values for the exotic type _Bool. [The + * overflow checkers only almost work for _Bool, but that's + * a-feature-not-a-bug, since people shouldn't be doing arithmetic on + * _Bools. Besides, the gcc builtins don't allow _Bool* as third + * argument.] + * + * Idea stolen from + * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html - + * credit to Christian Biere. + */ +#define is_signed_type(type) (((type)(-1)) < (type)1) +#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type))) +#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) +#define type_min(T) ((T)((T)-type_max(T)-(T)1)) + + +#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW +/* + * For simplicity and code hygiene, the fallback code below insists on + * a, b and *d having the same type (similar to the min() and max() + * macros), whereas gcc's type-generic overflow checkers accept + * different types. Hence we don't just make check_add_overflow an + * alias for __builtin_add_overflow, but add type checks similar to + * below. + */ +#define check_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_add_overflow(__a, __b, __d); \ +}) + +#define check_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_sub_overflow(__a, __b, __d); \ +}) + +#define check_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_mul_overflow(__a, __b, __d); \ +}) + +#else + + +/* Checking for unsigned overflow is relatively easy without causing UB. */ +#define __unsigned_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a + __b; \ + *__d < __a; \ +}) +#define __unsigned_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a - __b; \ + __a < __b; \ +}) +/* + * If one of a or b is a compile-time constant, this avoids a division. + */ +#define __unsigned_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a * __b; \ + __builtin_constant_p(__b) ? \ + __b > 0 && __a > type_max(typeof(__a)) / __b : \ + __a > 0 && __b > type_max(typeof(__b)) / __a; \ +}) + +/* + * For signed types, detecting overflow is much harder, especially if + * we want to avoid UB. But the interface of these macros is such that + * we must provide a result in *d, and in fact we must produce the + * result promised by gcc's builtins, which is simply the possibly + * wrapped-around value. Fortunately, we can just formally do the + * operations in the widest relevant unsigned type (u64) and then + * truncate the result - gcc is smart enough to generate the same code + * with and without the (u64) casts. + */ + +/* + * Adding two signed integers can overflow only if they have the same + * sign, and overflow has happened iff the result has the opposite + * sign. + */ +#define __signed_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a + (u64)__b; \ + (((~(__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +/* + * Subtraction is similar, except that overflow can now happen only + * when the signs are opposite. In this case, overflow has happened if + * the result has the opposite sign of a. + */ +#define __signed_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a - (u64)__b; \ + ((((__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +/* + * Signed multiplication is rather hard. gcc always follows C99, so + * division is truncated towards 0. This means that we can write the + * overflow check like this: + * + * (a > 0 && (b > MAX/a || b < MIN/a)) || + * (a < -1 && (b > MIN/a || b < MAX/a) || + * (a == -1 && b == MIN) + * + * The redundant casts of -1 are to silence an annoying -Wtype-limits + * (included in -Wextra) warning: When the type is u8 or u16, the + * __b_c_e in check_mul_overflow obviously selects + * __unsigned_mul_overflow, but unfortunately gcc still parses this + * code and warns about the limited range of __b. + */ + +#define __signed_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + typeof(a) __tmax = type_max(typeof(a)); \ + typeof(a) __tmin = type_min(typeof(a)); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a * (u64)__b; \ + (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \ + (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \ + (__b == (typeof(__b))-1 && __a == __tmin); \ +}) + + +#define check_add_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_add_overflow(a, b, d), \ + __unsigned_add_overflow(a, b, d)) + +#define check_sub_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_sub_overflow(a, b, d), \ + __unsigned_sub_overflow(a, b, d)) + +#define check_mul_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_mul_overflow(a, b, d), \ + __unsigned_mul_overflow(a, b, d)) + + +#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ + +/** check_shl_overflow() - Calculate a left-shifted value and check overflow + * + * @a: Value to be shifted + * @s: How many bits left to shift + * @d: Pointer to where to store the result + * + * Computes *@d = (@a << @s) + * + * Returns true if '*d' cannot hold the result or when 'a << s' doesn't + * make sense. Example conditions: + * - 'a << s' causes bits to be lost when stored in *d. + * - 's' is garbage (e.g. negative) or so large that the result of + * 'a << s' is guaranteed to be 0. + * - 'a' is negative. + * - 'a << s' sets the sign bit, if any, in '*d'. + * + * '*d' will hold the results of the attempted shift, but is not + * considered "safe for use" if false is returned. + */ +#define check_shl_overflow(a, s, d) ({ \ + typeof(a) _a = a; \ + typeof(s) _s = s; \ + typeof(d) _d = d; \ + u64 _a_full = _a; \ + unsigned int _to_shift = \ + _s >= 0 && _s < 8 * sizeof(*d) ? _s : 0; \ + *_d = (_a_full << _to_shift); \ + (_to_shift != _s || *_d < 0 || _a < 0 || \ + (*_d >> _to_shift) != _a); \ +}) + +/** + * array_size() - Calculate size of 2-dimensional array. + * + * @a: dimension one + * @b: dimension two + * + * Calculates size of 2-dimensional array: @a * @b. + * + * Returns: number of bytes needed to represent the array or SIZE_MAX on + * overflow. + */ +static inline __must_check size_t array_size(size_t a, size_t b) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * array3_size() - Calculate size of 3-dimensional array. + * + * @a: dimension one + * @b: dimension two + * @c: dimension three + * + * Calculates size of 3-dimensional array: @a * @b * @c. + * + * Returns: number of bytes needed to represent the array or SIZE_MAX on + * overflow. + */ +static inline __must_check size_t array3_size(size_t a, size_t b, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + if (check_mul_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(n, size, &bytes)) + return SIZE_MAX; + if (check_add_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * struct_size() - Calculate size of structure with trailing array. + * @p: Pointer to the structure. + * @member: Name of the array member. + * @n: Number of elements in the array. + * + * Calculates size of memory needed for structure @p followed by an + * array of @n @member elements. + * + * Return: number of bytes needed or SIZE_MAX on overflow. + */ +#define struct_size(p, member, n) \ + __ab_c_size(n, \ + sizeof(*(p)->member) + __must_be_array((p)->member),\ + sizeof(*(p))) + +#endif /* __LINUX_OVERFLOW_H */ +#endif /* defined(HAVE_OVERFLOW_H) && defined(HAVE_STRUCT_SIZE) */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/linux/static_key.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/linux/static_key.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/linux/static_key.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/linux/static_key.h 2020-03-11 16:15:44.000000000 +0000 @@ -1,6 +1,7 @@ #ifndef _STATIC_KEY_WRAPPER_H #define _STATIC_KEY_WRAPPER_H +#include #include_next #ifndef HAVE_UPSTREAM_STATIC_KEY /* @@ -23,16 +24,16 @@ #define rpl_STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) } #define rpl_STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) } -#define STATIC_KEY_TRUE_INIT \ +#define rpl_STATIC_KEY_TRUE_INIT \ (struct static_key_true) { .key = rpl_STATIC_KEY_INIT_TRUE, } -#define STATIC_KEY_FALSE_INIT \ +#define rpl_STATIC_KEY_FALSE_INIT \ (struct static_key_false){ .key = rpl_STATIC_KEY_INIT_FALSE, } -#define DEFINE_STATIC_KEY_TRUE(name) \ - struct static_key_true name = STATIC_KEY_TRUE_INIT +#define rpl_DEFINE_STATIC_KEY_TRUE(name) \ + struct static_key_true name = rpl_STATIC_KEY_TRUE_INIT -#define DEFINE_STATIC_KEY_FALSE(name) \ - struct static_key_false name = STATIC_KEY_FALSE_INIT +#define rpl_DEFINE_STATIC_KEY_FALSE(name) \ + struct static_key_false name = rpl_STATIC_KEY_FALSE_INIT static inline int rpl_static_key_count(struct static_key *key) { @@ -59,6 +60,14 @@ static_key_slow_dec(key); } +#ifdef HAVE_DEFINE_STATIC_KEY +#undef DEFINE_STATIC_KEY_TRUE +#undef DEFINE_STATIC_KEY_FALSE +#endif + +#define DEFINE_STATIC_KEY_TRUE rpl_DEFINE_STATIC_KEY_TRUE +#define DEFINE_STATIC_KEY_FALSE rpl_DEFINE_STATIC_KEY_FALSE + #define static_branch_likely(x) likely(static_key_enabled(&(x)->key)) #define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key)) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/net/ipv6_frag.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/net/ipv6_frag.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/net/ipv6_frag.h 1970-01-01 00:00:00.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/net/ipv6_frag.h 2020-03-11 16:15:44.000000000 +0000 @@ -0,0 +1,8 @@ +#ifndef __NET_IPV6_FRAG_WRAPPER_H +#define __NET_IPV6_FRAG_WRAPPER_H + +#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) && defined(HAVE_IPV6_FRAG_H) +#include_next +#endif + +#endif /* __NET_IPV6_FRAG_WRAPPER_H */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/net/netfilter/nf_conntrack_core.h 2020-03-11 16:15:44.000000000 +0000 @@ -67,27 +67,6 @@ #define nf_ct_get_tuple rpl_nf_ct_get_tuple #endif /* HAVE_NF_CT_GET_TUPLEPR_TAKES_STRUCT_NET */ -/* Commit 08733a0cb7de ("netfilter: handle NF_REPEAT from nf_conntrack_in()") - * introduced behavioural changes to this function which cannot be detected - * in the headers. Unconditionally backport to kernels older than the one which - * contains this commit. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) -static unsigned int rpl_nf_conntrack_in(struct net *net, u_int8_t pf, - unsigned int hooknum, - struct sk_buff *skb) -{ - int err; - - /* Repeat if requested, see nf_iterate(). */ - do { - err = nf_conntrack_in(net, pf, hooknum, skb); - } while (err == NF_REPEAT); - - return err; -} -#define nf_conntrack_in rpl_nf_conntrack_in -#endif /* < 4.10 */ - #ifdef HAVE_NF_CONN_TIMER #ifndef HAVE_NF_CT_DELETE @@ -125,4 +104,13 @@ #define nf_ct_delete rpl_nf_ct_delete #endif /* HAVE_NF_CONN_TIMER */ +#ifndef HAVE_NF_CONNTRACK_IN_TAKES_NF_HOOK_STATE +static inline unsigned int +rpl_nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state) +{ + return nf_conntrack_in(state->net, state->pf, state->hook, skb); +} +#define nf_conntrack_in rpl_nf_conntrack_in +#endif /* HAVE_NF_CONNTRACK_IN_TAKES_NF_HOOK_STATE */ + #endif /* _NF_CONNTRACK_CORE_WRAPPER_H */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/net/nsh.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/net/nsh.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/include/net/nsh.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/include/net/nsh.h 2020-03-11 16:15:44.000000000 +0000 @@ -247,10 +247,10 @@ #define NSH_M_TYPE1_LEN 24 /* NSH header maximum Length. */ -#define NSH_HDR_MAX_LEN 256 +#define NSH_HDR_MAX_LEN 252 /* NSH context headers maximum Length. */ -#define NSH_CTX_HDRS_MAX_LEN 248 +#define NSH_CTX_HDRS_MAX_LEN 244 static inline struct nshhdr *nsh_hdr(struct sk_buff *skb) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/ip6_gre.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/ip6_gre.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/ip6_gre.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/ip6_gre.c 2020-03-11 16:15:44.000000000 +0000 @@ -377,7 +377,7 @@ if (parms->name[0]) strlcpy(name, parms->name, IFNAMSIZ); else - strcpy(name, "ip6gre%d"); + strlcpy(name, "ovs-ip6gre%d", IFNAMSIZ); dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ip6gre_tunnel_setup); @@ -876,9 +876,6 @@ struct tnl_ptk_info tpi; __be16 protocol; - if (dev->type == ARPHRD_ETHER) - IPCB(skb)->flags = 0; - if (dev->header_ops && dev->type == ARPHRD_IP6GRE) fl6->daddr = ((struct ipv6hdr *)skb->data)->daddr; else @@ -1146,7 +1143,6 @@ goto tx_err; t->parms.o_flags &= ~TUNNEL_KEY; - IPCB(skb)->flags = 0; tun_info = ovs_skb_tunnel_info(skb); if (unlikely(!tun_info || @@ -1200,7 +1196,11 @@ /* TooBig packet may have updated dst->dev's mtu */ if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) +#ifndef HAVE_DST_OPS_CONFIRM_NEIGH dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu); +#else + dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu, false); +#endif err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu, NEXTHDR_GRE); @@ -1716,7 +1716,8 @@ struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); int err; - ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0", + ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), + "ovs-ip6gre0", NET_NAME_UNKNOWN, ip6gre_tunnel_setup); if (!ign->fb_tunnel_dev) { @@ -1983,6 +1984,7 @@ if (data[IFLA_GRE_COLLECT_METADATA]) parms->collect_md = true; + parms->erspan_ver = 1; if (data[IFLA_GRE_ERSPAN_VER]) parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/ip6_tunnel.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/ip6_tunnel.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/ip6_tunnel.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/ip6_tunnel.c 2020-03-11 16:15:44.000000000 +0000 @@ -355,7 +355,7 @@ if (p->name[0]) strlcpy(name, p->name, IFNAMSIZ); else - sprintf(name, "ip6tnl%%d"); + strlcpy(name, "ovs-ip6tnl%d", IFNAMSIZ); dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ip6_tnl_dev_setup); @@ -1410,7 +1410,7 @@ * %SIOCCHGTUNNEL: change tunnel parameters to those given * %SIOCDELTUNNEL: delete tunnel * - * The fallback device "ip6tnl0", created during module + * The fallback device "ovs-ip6tnl0", created during module * initialization, can be used for creating other tunnel devices. * * Return: @@ -2093,7 +2093,7 @@ ip6n->tnls[1] = ip6n->tnls_r_l; err = -ENOMEM; - ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", + ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ovs-ip6tnl0", NET_NAME_UNKNOWN, ip6_tnl_dev_setup); if (!ip6n->fb_tnl_dev) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/ip_gre.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/ip_gre.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/ip_gre.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/ip_gre.c 2020-03-11 16:15:44.000000000 +0000 @@ -312,6 +312,9 @@ if (tpi->proto == htons(ETH_P_TEB)) itn = net_generic(net, gre_tap_net_id); + else if (tpi->proto == htons(ETH_P_ERSPAN) || + tpi->proto == htons(ETH_P_ERSPAN2)) + itn = net_generic(net, erspan_net_id); else itn = net_generic(net, ipgre_net_id); @@ -1229,12 +1232,15 @@ static void erspan_setup(struct net_device *dev) { + struct ip_tunnel *t = netdev_priv(dev); + eth_hw_addr_random(dev); ether_setup(dev); dev->netdev_ops = &erspan_netdev_ops; dev->priv_flags &= ~IFF_TX_SKB_SHARING; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; ip_tunnel_setup(dev, erspan_net_id); + t->erspan_ver = 1; } #ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS @@ -1467,7 +1473,7 @@ static int __net_init ipgre_tap_init_net(struct net *net) { - return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0"); + return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "ovs-gretap0"); } static void __net_exit ipgre_tap_exit_net(struct net *net) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/ip_tunnel.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/ip_tunnel.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/ip_tunnel.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/ip_tunnel.c 2020-03-11 16:15:44.000000000 +0000 @@ -266,7 +266,12 @@ mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; if (skb_dst(skb)) +#ifndef HAVE_DST_OPS_CONFIRM_NEIGH skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); +#else + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), + NULL, skb, mtu, false); +#endif if (skb->protocol == htons(ETH_P_IP)) { if (!skb_is_gso(skb) && diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/lisp.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/lisp.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/lisp.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/lisp.c 2020-03-11 16:15:44.000000000 +0000 @@ -457,6 +457,7 @@ rcu_assign_pointer(lisp->sock, sock); /* Mark socket as an encapsulation socket */ + memset(&tunnel_cfg, 0, sizeof(tunnel_cfg)); tunnel_cfg.sk_user_data = dev; tunnel_cfg.encap_type = 1; tunnel_cfg.encap_rcv = lisp_rcv; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/nf_conntrack_proto.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/nf_conntrack_proto.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/nf_conntrack_proto.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/nf_conntrack_proto.c 2020-03-11 16:15:44.000000000 +0000 @@ -1,7 +1,9 @@ #include #include +#ifdef HAVE_NF_CONNTRACK_L3PROATO_H #include +#endif /* * Upstream net-next commmit 7e35ec0e8044 @@ -11,10 +13,10 @@ * * However, we only need this feature if the underlying nf_conntrack_l3proto * supports net_ns_get/put. Thus, we just mock the functions if - * HAVE_NET_NS_SET is false. + * HAVE_NET_NS_GET is false. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) -#ifdef HAVE_NET_NS_SET +#ifdef HAVE_NET_NS_GET static int nf_ct_netns_do_get(struct net *net, u8 nfproto) { const struct nf_conntrack_l3proto *l3proto; @@ -96,7 +98,7 @@ } EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_put); -#else /* !HAVE_NET_NS_SET */ +#else /* !HAVE_NET_NS_GET */ void rpl_nf_ct_netns_put(struct net *net, uint8_t nfproto) { } @@ -108,5 +110,5 @@ } EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_get); -#endif /* HAVE_NET_NS_SET */ +#endif /* HAVE_NET_NS_GET */ #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/nf_conntrack_reasm.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/nf_conntrack_reasm.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/nf_conntrack_reasm.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/nf_conntrack_reasm.c 2020-03-11 16:15:44.000000000 +0000 @@ -99,6 +99,7 @@ return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); } +#ifdef HAVE_INET_FRAGS_RND static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr, const struct in6_addr *daddr) { @@ -125,6 +126,7 @@ return nf_hash_frag(nq->id, &nq->saddr, &nq->daddr); } +#endif /* HAVE_INET_FRAGS_RND */ static void nf_ct_frag6_expire(unsigned long data) { struct frag_queue *fq; @@ -133,9 +135,14 @@ fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); net = get_net_from_netns_frags6(fq->q.net); +#ifdef HAVE_INET_FRAGS_RND ip6_expire_frag_queue(net, fq, &nf_frags); +#else + ip6_expire_frag_queue(net, fq); +#endif } +#ifdef HAVE_INET_FRAGS_RND /* Creation primitives. */ static inline struct frag_queue *fq_find(struct net *net, __be32 id, u32 user, struct in6_addr *src, @@ -168,7 +175,27 @@ } return container_of(q, struct frag_queue, q); } +#else +static struct frag_queue *fq_find(struct net *net, __be32 id, u32 user, + const struct ipv6hdr *hdr, int iif) +{ + struct frag_v6_compare_key key = { + .id = id, + .saddr = hdr->saddr, + .daddr = hdr->daddr, + .user = user, + .iif = iif, + }; + struct inet_frag_queue *q; + + q = inet_frag_find(&net->nf_frag.frags, &key); + if (!q) + return NULL; + + return container_of(q, struct frag_queue, q); +} +#endif /* HAVE_INET_FRAGS_RND */ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, const struct frag_hdr *fhdr, int nhoff) @@ -317,7 +344,11 @@ return 0; discard_fq: +#ifdef HAVE_INET_FRAGS_RND inet_frag_kill(&fq->q, &nf_frags); +#else + inet_frag_kill(&fq->q); +#endif err: return -1; } @@ -339,7 +370,11 @@ int payload_len; u8 ecn; +#ifdef HAVE_INET_FRAGS_RND inet_frag_kill(&fq->q, &nf_frags); +#else + inet_frag_kill(&fq->q); +#endif WARN_ON(head == NULL); WARN_ON(NFCT_FRAG6_CB(head)->offset != 0); @@ -561,8 +596,13 @@ #endif skb_orphan(skb); +#ifdef HAVE_INET_FRAGS_RND fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr, ip6_frag_ecn(hdr)); +#else + fq = fq_find(net, fhdr->identification, user, hdr, + skb->dev ? skb->dev->ifindex : 0); +#endif if (fq == NULL) return -ENOMEM; @@ -584,7 +624,11 @@ out_unlock: spin_unlock_bh(&fq->q.lock); +#ifdef HAVE_INET_FRAGS_RND inet_frag_put(&fq->q, &nf_frags); +#else + inet_frag_put(&fq->q); +#endif return ret; } @@ -614,10 +658,12 @@ void ovs_netns_frags6_exit(struct net *net) { +#ifdef HAVE_INET_FRAGS_RND struct netns_frags *frags; frags = get_netns_frags6_from_net(net); inet_frags_exit_net(frags, &nf_frags); +#endif } static struct pernet_operations nf_ct_net_ops = { @@ -634,13 +680,17 @@ #ifndef HAVE_DEFRAG_ENABLE_TAKES_NET nf_defrag_ipv6_enable(); #endif +#ifdef HAVE_INET_FRAGS_RND nf_frags.hashfn = nf_hashfn; + nf_frags.match = ip6_frag_match; +#else + nf_frags.rhash_params = ip6_rhash_params; +#endif nf_frags.constructor = ip6_frag_init; nf_frags.destructor = NULL; nf_frags.qsize = sizeof(struct frag_queue); - nf_frags.match = ip6_frag_match; nf_frags.frag_expire = nf_ct_frag6_expire; -#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK +#if defined(HAVE_INET_FRAGS_WITH_FRAGS_WORK) || !defined(HAVE_INET_FRAGS_RND) nf_frags.frags_cache_name = nf_frags_cache_name; #endif #if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/stt.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/stt.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/compat/stt.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/compat/stt.c 2020-03-11 16:15:44.000000000 +0000 @@ -1026,7 +1026,7 @@ error: kfree_skb(skb); dev->stats.tx_errors++; - return NETDEV_TX_OK; + return err; } EXPORT_SYMBOL(ovs_stt_xmit); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/Modules.mk openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/Modules.mk --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/linux/Modules.mk 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/linux/Modules.mk 2020-03-11 16:15:44.000000000 +0000 @@ -86,6 +86,7 @@ linux/compat/include/net/ip6_route.h \ linux/compat/include/net/ip6_tunnel.h \ linux/compat/include/net/ipv6.h \ + linux/compat/include/net/ipv6_frag.h \ linux/compat/include/net/mpls.h \ linux/compat/include/net/net_namespace.h \ linux/compat/include/net/netlink.h \ @@ -112,5 +113,8 @@ linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h \ linux/compat/include/net/sctp/checksum.h \ linux/compat/include/net/erspan.h \ - linux/compat/include/uapi/linux/netfilter.h + linux/compat/include/uapi/linux/netfilter.h \ + linux/compat/include/linux/mm.h \ + linux/compat/include/linux/netfilter.h \ + linux/compat/include/linux/overflow.h EXTRA_DIST += linux/compat/build-aux/export-check-whitelist diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/meter.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/meter.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath/meter.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath/meter.c 2020-03-11 16:15:44.000000000 +0000 @@ -13,11 +13,13 @@ #include #include #include +#include #include #include #include #include +#include #include "datapath.h" #include "meter.h" @@ -216,8 +218,7 @@ return ERR_PTR(-EINVAL); /* Allocate and set up the meter before locking anything. */ - meter = kzalloc(n_bands * sizeof(struct dp_meter_band) + - sizeof(*meter), GFP_KERNEL); + meter = kzalloc(struct_size(meter, bands, n_bands), GFP_KERNEL); if (!meter) return ERR_PTR(-ENOMEM); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/include/OvsDpInterfaceExt.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/include/OvsDpInterfaceExt.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/include/OvsDpInterfaceExt.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/include/OvsDpInterfaceExt.h 2020-03-11 16:15:44.000000000 +0000 @@ -72,6 +72,7 @@ */ #define OVS_WIN_NL_CT_FAMILY_ID (NLMSG_MIN_TYPE + 7) +#define OVS_WIN_NL_CTLIMIT_FAMILY_ID (NLMSG_MIN_TYPE + 8) #define OVS_WIN_NL_INVALID_MCGRP_ID 0 #define OVS_WIN_NL_MCGRP_START_ID 100 diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/BufferMgmt.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/BufferMgmt.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/BufferMgmt.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/BufferMgmt.c 2020-03-11 16:15:44.000000000 +0000 @@ -1622,6 +1622,7 @@ { POVS_BUFFER_CONTEXT ctx; UINT16 flags; + UINT32 dataOffsetDelta; PNET_BUFFER_LIST parent; NDIS_STATUS status; NDIS_HANDLE poolHandle; @@ -1653,6 +1654,7 @@ nb = NET_BUFFER_LIST_FIRST_NB(nbl); flags = ctx->flags; + dataOffsetDelta = ctx->dataOffsetDelta; if (!(flags & OVS_BUFFER_FRAGMENT) && NET_BUFFER_DATA_LENGTH(nb) != ctx->origDataLength) { UINT32 diff; @@ -1667,7 +1669,7 @@ } } - if (ctx->flags & OVS_BUFFER_PRIVATE_CONTEXT) { + if (flags & OVS_BUFFER_PRIVATE_CONTEXT) { NdisFreeNetBufferListContext(nbl, sizeof (OVS_BUFFER_CONTEXT)); } @@ -1740,7 +1742,7 @@ #ifdef DBG InterlockedDecrement((LONG volatile *)&ovsPool->fragNBLCount); #endif - NdisFreeFragmentNetBufferList(nbl, ctx->dataOffsetDelta, 0); + NdisFreeFragmentNetBufferList(nbl, dataOffsetDelta, 0); } if (parent != NULL) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/Conntrack.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/Conntrack.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/Conntrack.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/Conntrack.c 2020-03-11 16:15:44.000000000 +0000 @@ -27,13 +27,17 @@ #define WINDOWS_TICK 10000000 #define SEC_TO_UNIX_EPOCH 11644473600LL #define SEC_TO_NANOSEC 1000000000LL +#define CT_MAX_ZONE (UINT16_MAX + 1) KSTART_ROUTINE OvsConntrackEntryCleaner; static PLIST_ENTRY ovsConntrackTable; static OVS_CT_THREAD_CTX ctThreadCtx; static PNDIS_RW_LOCK_EX *ovsCtBucketLock = NULL; +static NDIS_SPIN_LOCK ovsCtZoneLock; +static POVS_CT_ZONE_INFO zoneInfo = NULL; extern POVS_SWITCH_CONTEXT gOvsSwitchContext; static ULONG ctTotalEntries; +static ULONG defaultCtLimit; static __inline OvsCtFlush(UINT16 zone, struct ovs_key_ct_tuple_ipv4 *tuple); static __inline NDIS_STATUS @@ -94,6 +98,20 @@ ZwClose(threadHandle); threadHandle = NULL; + zoneInfo = OvsAllocateMemoryWithTag(sizeof(OVS_CT_ZONE_INFO) * + CT_MAX_ZONE, OVS_CT_POOL_TAG); + if (zoneInfo == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto freeBucketLock; + } + + NdisAllocateSpinLock(&ovsCtZoneLock); + defaultCtLimit = CT_MAX_ENTRIES; + for (UINT32 i = 0; i < CT_MAX_ZONE; i++) { + zoneInfo[i].entries = 0; + zoneInfo[i].limit = defaultCtLimit; + } + status = OvsNatInit(); if (status != STATUS_SUCCESS) { @@ -149,6 +167,25 @@ OvsFreeMemoryWithTag(ovsCtBucketLock, OVS_CT_POOL_TAG); ovsCtBucketLock = NULL; OvsNatCleanup(); + NdisFreeSpinLock(&ovsCtZoneLock); + if (zoneInfo) { + OvsFreeMemoryWithTag(zoneInfo, OVS_CT_POOL_TAG); + } +} + +VOID +OvsCtSetZoneLimit(int zone, ULONG value) { + NdisAcquireSpinLock(&ovsCtZoneLock); + if (zone == -1) { + /* Set default limit for all zones. */ + defaultCtLimit = value; + for (UINT32 i = 0; i < CT_MAX_ZONE; i++) { + zoneInfo[i].limit = value; + } + } else { + zoneInfo[(UINT16)zone].limit = value; + } + NdisReleaseSpinLock(&ovsCtZoneLock); } /* @@ -263,6 +300,7 @@ &entry->link); NdisInterlockedIncrement((PLONG)&ctTotalEntries); + NdisInterlockedIncrement((PLONG)&zoneInfo[ctx->key.zone].entries); NdisReleaseRWLock(ovsCtBucketLock[bucketIdx], &lockState); return TRUE; } @@ -437,6 +475,7 @@ if (entry->natInfo.natAction) { OvsNatDeleteKey(&entry->key); } + NdisInterlockedDecrement((PLONG)&zoneInfo[entry->key.zone].entries); OvsPostCtEventEntry(entry, OVS_EVENT_CT_DELETE); RemoveEntryList(&entry->link); OVS_RELEASE_SPIN_LOCK(&(entry->lock), irql); @@ -770,6 +809,7 @@ ovs_u128 v, m, pktMdLabel = {0}; memcpy(&v, val, sizeof v); memcpy(&m, mask, sizeof m); + memcpy(&pktMdLabel, &entry->labels, sizeof(struct ovs_key_ct_labels)); pktMdLabel.u64.lo = v.u64.lo | (pktMdLabel.u64.lo & ~(m.u64.lo)); pktMdLabel.u64.hi = v.u64.hi | (pktMdLabel.u64.hi & ~(m.u64.hi)); @@ -877,12 +917,16 @@ &entryCreated); } else { - if (commit && ctTotalEntries >= CT_MAX_ENTRIES) { + if (commit && (ctTotalEntries >= CT_MAX_ENTRIES || + zoneInfo[ctx.key.zone].entries >= zoneInfo[ctx.key.zone].limit)) { /* Don't proceed with processing if the max limit has been hit. * This blocks only new entries from being created and doesn't * affect existing connections. */ - OVS_LOG_ERROR("Conntrack Limit hit: %lu", ctTotalEntries); + OVS_LOG_ERROR("Conntrack Limit hit: zone(%u), zoneLimit(%lu)," + "zoneEntries(%lu), ctTotalEntries(%lu)", + zone, zoneInfo[ctx.key.zone].limit, + zoneInfo[ctx.key.zone].entries, ctTotalEntries); return NDIS_STATUS_RESOURCES; } /* If no matching entry was found, create one and add New state */ @@ -1783,4 +1827,124 @@ return STATUS_SUCCESS; } +static NTSTATUS +OvsCreateNlMsgFromCtLimit(POVS_MESSAGE msgIn, + PVOID outBuffer, + UINT32 outBufLen, + PCHAR attr, + UINT32 numAttrs, + int dpIfIndex) +{ + NTSTATUS status = STATUS_SUCCESS; + NL_BUFFER nlBuffer; + PNL_MSG_HDR nlMsg; + PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg); + + NlBufInit(&nlBuffer, outBuffer, outBufLen); + + if (!NlFillOvsMsg(&nlBuffer, msgIn->nlMsg.nlmsgType, NLM_F_MULTI, + msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid, + msgIn->genlMsg.cmd, msgIn->genlMsg.version, + dpIfIndex)) { + return STATUS_INVALID_BUFFER_SIZE; + } + + if (genlMsgHdr->cmd == OVS_CT_LIMIT_CMD_GET && numAttrs) { + POVS_CT_ZONE_LIMIT zoneLimitAttr = (POVS_CT_ZONE_LIMIT) attr; + UINT32 offset = NlMsgStartNested(&nlBuffer, OVS_CT_LIMIT_ATTR_ZONE_LIMIT); + if (!offset) { + /* Starting the nested attribute failed. */ + status = STATUS_INVALID_BUFFER_SIZE; + goto done; + } + + /* Insert OVS_CT_ZONE_LIMIT attributes.*/ + for (UINT32 i = 0; i < numAttrs; i++) { + if (zoneLimitAttr) { + zoneLimitAttr->limit = zoneInfo[zoneLimitAttr->zone_id].limit; + zoneLimitAttr->count = zoneInfo[zoneLimitAttr->zone_id].entries; + if (zoneLimitAttr->zone_id == -1) { + zoneLimitAttr->limit = defaultCtLimit; + } + NlMsgPutTail(&nlBuffer, (const PCHAR)zoneLimitAttr, + sizeof(OVS_CT_ZONE_LIMIT)); + } else { + status = STATUS_INVALID_PARAMETER; + break; + } + zoneLimitAttr = (POVS_CT_ZONE_LIMIT)((PCHAR) zoneLimitAttr + + sizeof(OVS_CT_ZONE_LIMIT)); + } + NlMsgEndNested(&nlBuffer, offset); + } + +done: + nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuffer, 0, 0); + nlMsg->nlmsgLen = NlBufSize(&nlBuffer); + + return status; +} + +NTSTATUS +OvsCtLimitHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx, + UINT32 *replyLen) +{ + NTSTATUS status; + POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer; + POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer; + PNL_MSG_HDR nlMsgHdr = &(msgIn->nlMsg); + PGENL_MSG_HDR genlMsgHdr = &(msgIn->genlMsg); + POVS_HDR ovsHdr = &(msgIn->ovsHdr); + PCHAR attr = NULL; + UINT32 numAttrs = 0; + UINT32 attrOffset = NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN; + + static const NL_POLICY ovsCtLimitPolicy[] = { + [OVS_CT_LIMIT_ATTR_ZONE_LIMIT] = { .type = NL_A_NESTED, .optional = TRUE } + }; + PNL_ATTR nlAttrs[ARRAY_SIZE(ovsCtLimitPolicy)]; + + if ((NlAttrParse(nlMsgHdr, attrOffset, NlMsgAttrsLen(nlMsgHdr), + ovsCtLimitPolicy, ARRAY_SIZE(ovsCtLimitPolicy), + nlAttrs, ARRAY_SIZE(nlAttrs))) + != TRUE) { + OVS_LOG_ERROR("Attr Parsing failed for msg: %p", nlMsgHdr); + return STATUS_INVALID_PARAMETER; + } + + if (nlAttrs[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) { + numAttrs = NlAttrGetSize(nlAttrs[OVS_CT_LIMIT_ATTR_ZONE_LIMIT])/sizeof(OVS_CT_ZONE_LIMIT); + attr = NlAttrGet(nlAttrs[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]); + } + + if (genlMsgHdr->cmd == OVS_CT_LIMIT_CMD_SET || + genlMsgHdr->cmd == OVS_CT_LIMIT_CMD_DEL) { + POVS_CT_ZONE_LIMIT zoneLimitAttr = (POVS_CT_ZONE_LIMIT)attr; + for (UINT32 i = 0; i < numAttrs; i++) { + /* Parse zone limit attributes. */ + if (zoneLimitAttr) { + if (genlMsgHdr->cmd == OVS_CT_LIMIT_CMD_DEL) { + zoneLimitAttr->limit = CT_MAX_ENTRIES; + } + OvsCtSetZoneLimit(zoneLimitAttr->zone_id, zoneLimitAttr->limit); + } else { + OVS_LOG_ERROR("Failed to get zone limit attribute at index(%u)," + " numAttrs(%u)", i, numAttrs); + return STATUS_INVALID_PARAMETER; + } + zoneLimitAttr = (POVS_CT_ZONE_LIMIT)((PCHAR) zoneLimitAttr + + sizeof(OVS_CT_ZONE_LIMIT)); + } + } + + /* Output buffer has been validated while validating transact dev op. */ + ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut); + status = OvsCreateNlMsgFromCtLimit(msgIn, msgOut, + usrParamsCtx->outputLength, + attr, numAttrs, ovsHdr->dp_ifindex); + *replyLen = msgOut->nlMsg.nlmsgLen; + + return status; +} + #pragma warning(pop) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/Conntrack.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/Conntrack.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/Conntrack.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/Conntrack.h 2020-03-11 16:15:44.000000000 +0000 @@ -132,6 +132,18 @@ BOOLEAN related; } OvsConntrackKeyLookupCtx; +/* Per zone strucuture. */ +typedef struct _OVS_CT_ZONE_INFO { + ULONG limit; + ULONG entries; +} OVS_CT_ZONE_INFO, *POVS_CT_ZONE_INFO; + +typedef struct _OVS_CT_ZONE_LIMIT { + int zone_id; + ULONG limit; + ULONG count; +} OVS_CT_ZONE_LIMIT, *POVS_CT_ZONE_LIMIT; + #define CT_MAX_ENTRIES 1 << 21 #define CT_HASH_TABLE_SIZE ((UINT32)1 << 10) #define CT_HASH_TABLE_MASK (CT_HASH_TABLE_SIZE - 1) @@ -175,8 +187,7 @@ tcp = (TCPHdr *)((PCHAR)ipHdr + ipHdr->ihl * 4); if (tcp->doff * 4 >= sizeof *tcp) { NdisMoveMemory(dest, tcp, sizeof(TCPHdr)); - *tcpPayloadLen = ntohs((ipHdr->tot_len) - (ipHdr->ihl * 4) - - (TCP_HDR_LEN(tcp))); + *tcpPayloadLen = TCP_DATA_LENGTH(ipHdr, tcp); return storage; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/Datapath.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/Datapath.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/Datapath.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/Datapath.c 2020-03-11 16:15:44.000000000 +0000 @@ -99,7 +99,8 @@ OvsSubscribePacketCmdHandler, OvsReadPacketCmdHandler, OvsCtDeleteCmdHandler, - OvsCtDumpCmdHandler; + OvsCtDumpCmdHandler, + OvsCtLimitHandler; static NTSTATUS HandleGetDpTransaction(POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen); @@ -324,6 +325,34 @@ .opsCount = ARRAY_SIZE(nlNetdevFamilyCmdOps) }; + +/* Netlink conntrack limit family. */ +NETLINK_CMD nlCtLimitFamilyCmdOps[] = { + { .cmd = OVS_CT_LIMIT_CMD_GET, + .handler = OvsCtLimitHandler, + .supportedDevOp = OVS_TRANSACTION_DEV_OP, + .validateDpIndex = FALSE + }, + { .cmd = OVS_CT_LIMIT_CMD_SET, + .handler = OvsCtLimitHandler, + .supportedDevOp = OVS_TRANSACTION_DEV_OP, + .validateDpIndex = FALSE + }, + { .cmd = OVS_CT_LIMIT_CMD_DEL, + .handler = OvsCtLimitHandler, + .supportedDevOp = OVS_TRANSACTION_DEV_OP, + .validateDpIndex = FALSE + }, +}; + +NETLINK_FAMILY nlCtLimitFamilyOps = { + .name = OVS_CT_LIMIT_FAMILY, + .id = OVS_WIN_NL_CTLIMIT_FAMILY_ID, + .version = OVS_CT_LIMIT_VERSION, + .maxAttr = OVS_CT_LIMIT_ATTR_MAX, + .cmds = nlCtLimitFamilyCmdOps, + .opsCount = ARRAY_SIZE(nlCtLimitFamilyCmdOps) +}; static NTSTATUS MapIrpOutputBuffer(PIRP irp, UINT32 bufferLength, UINT32 requiredLength, @@ -941,6 +970,9 @@ case OVS_WIN_NL_NETDEV_FAMILY_ID: nlFamilyOps = &nlNetdevFamilyOps; break; + case OVS_WIN_NL_CTLIMIT_FAMILY_ID: + nlFamilyOps = &nlCtLimitFamilyOps; + break; default: status = STATUS_INVALID_PARAMETER; goto done; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/IpFragment.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/IpFragment.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/IpFragment.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/IpFragment.c 2020-03-11 16:15:44.000000000 +0000 @@ -230,7 +230,7 @@ /* *---------------------------------------------------------------------------- * OvsProcessIpv4Fragment - * Reassemble the fragments once all the fragments are recieved and + * Reassemble the fragments once all the fragments are received and * return NDIS_STATUS_PENDING for the pending fragments * XXX - Instead of copying NBls, Keep the NBLs in limbo state. *---------------------------------------------------------------------------- @@ -403,7 +403,7 @@ entry->tail = fragStorage; } - /*Update Maximum recieved Unit */ + /*Update Maximum Receive Unit */ entry->mru = entry->mru > (ETH_HEADER_LENGTH + ipHdrLen + payloadLen) ? entry->mru : (ETH_HEADER_LENGTH + ipHdrLen + payloadLen); entry->numFragments++; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/IpFragment.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/IpFragment.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/IpFragment.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/IpFragment.h 2020-03-11 16:15:44.000000000 +0000 @@ -57,7 +57,7 @@ #define IP_FRAG_HASH_TABLE_SIZE ((UINT32)1 << 10) #define IP_FRAG_HASH_TABLE_MASK (IP_FRAG_HASH_TABLE_SIZE - 1) -/*30s -Sufficient time to recieve all fragments.*/ +/*30s -Sufficient time to receive all fragments.*/ #define IPFRAG_ENTRY_TIMEOUT 300000000LL #define IPFRAG_CLEANUP_INTERVAL IPFRAG_ENTRY_TIMEOUT * 2 /*1m.*/ PNET_BUFFER_LIST OvsIpv4FragmentNBL(PVOID ovsContext, diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/IpHelper.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/IpHelper.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/IpHelper.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/IpHelper.c 2020-03-11 16:15:44.000000000 +0000 @@ -40,34 +40,6 @@ static ERESOURCE ovsInstanceListLock; /* - * This structure is used to define each adapter instance. - * - * Note: - * Only when the internal IP is configured and virtual - * internal port is connected, the IP helper request can be - * queued. - * - * We only keep internal IP for reference, it will not be used for determining - * SRC IP of the Tunnel. - * - * The lock must not raise the IRQL higher than PASSIVE_LEVEL in order for the - * route manipulation functions, i.e. GetBestRoute, to work. - */ -typedef struct _OVS_IPHELPER_INSTANCE -{ - LIST_ENTRY link; - - BOOLEAN isIpConfigured; - UINT32 portNo; - GUID netCfgId; - MIB_IF_ROW2 internalRow; - MIB_IPINTERFACE_ROW internalIPRow; - UINT32 ipAddress; - - ERESOURCE lock; -} OVS_IPHELPER_INSTANCE, *POVS_IPHELPER_INSTANCE; - -/* * FWD_ENTRY --------> IPFORWARD_ENTRY * | * |--------------------------------------> IPENIGH_ENTRY @@ -100,7 +72,7 @@ static POVS_IPFORWARD_ENTRY OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix); static VOID OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf); static VOID OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr); -static VOID OvsRemoveAllFwdEntriesWithPortNo(UINT32 portNo); +static VOID OvsRemoveIPNeighEntriesWithInstance(POVS_IPHELPER_INSTANCE instance); static VOID OvsCleanupIpHelperRequestList(VOID); static VOID OvsCleanupFwdTable(VOID); static VOID OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn); @@ -1070,7 +1042,7 @@ RtlCopyMemory(entry->macAddr, ipNeigh->PhysicalAddress, ETH_ADDR_LEN); InitializeListHead(&entry->fwdList); - entry->context = (PVOID)instance; + entry->instance = instance; return entry; } @@ -1271,18 +1243,16 @@ static VOID -OvsRemoveAllFwdEntriesWithPortNo(UINT32 portNo) +OvsRemoveIPNeighEntriesWithInstance(POVS_IPHELPER_INSTANCE instance) { - UINT32 i; - PLIST_ENTRY link, next; - - for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) { - LIST_FORALL_SAFE(&ovsFwdHashTable[i], link, next) { - POVS_FWD_ENTRY fwdEntry; - - fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link); - if (fwdEntry->info.srcPortNo == portNo) { - OvsRemoveFwdEntry(fwdEntry); + if (ovsNumFwdEntries) { + POVS_IPNEIGH_ENTRY ipn; + PLIST_ENTRY link, next; + LIST_FORALL_SAFE(&ovsSortedIPNeighList, link, next) { + ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink); + POVS_IPHELPER_INSTANCE ipnInstance = ipn->instance; + if (ipnInstance == instance) { + OvsRemoveIPNeighEntry(ipn); } } } @@ -1885,7 +1855,7 @@ IsEqualGUID(&instance->netCfgId, &netCfgInstanceId)) { NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0); - OvsRemoveAllFwdEntriesWithPortNo(instance->portNo); + OvsRemoveIPNeighEntriesWithInstance(instance); NdisReleaseRWLock(ovsTableLock, &lockState); RemoveEntryList(&instance->link); @@ -1934,16 +1904,18 @@ ipAddr = ipn->ipAddr; MIB_IPNET_ROW2 ipNeigh; NTSTATUS status; - POVS_IPHELPER_INSTANCE instance = (POVS_IPHELPER_INSTANCE)ipn->context; + POVS_IPHELPER_INSTANCE instance = ipn->instance; NdisReleaseSpinLock(&ovsIpHelperLock); - ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE); - status = OvsGetOrResolveIPNeigh(&instance->internalRow, - ipAddr, &ipNeigh); - OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status); + if (instance) { + ExAcquireResourceExclusiveLite(&instance->lock, TRUE); - ExReleaseResourceLite(&ovsInstanceListLock); + status = OvsGetOrResolveIPNeigh(&instance->internalRow, + ipAddr, &ipNeigh); + OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status); + ExReleaseResourceLite(&instance->lock); + } NdisAcquireSpinLock(&ovsIpHelperLock); } if (!IsListEmpty(&ovsIpHelperRequestList)) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/IpHelper.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/IpHelper.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/IpHelper.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/IpHelper.h 2020-03-11 16:15:44.000000000 +0000 @@ -32,17 +32,44 @@ #define OVS_IPNEIGH_TIMEOUT 100000000 // 10 s + /* + * This structure is used to define each adapter instance. + * + * Note: + * Only when the internal IP is configured and virtual + * internal port is connected, the IP helper request can be + * queued. + * + * We only keep internal IP for reference, it will not be used for determining + * SRC IP of the Tunnel. + * + * The lock must not raise the IRQL higher than PASSIVE_LEVEL in order for the + * route manipulation functions, i.e. GetBestRoute, to work. + */ +typedef struct _OVS_IPHELPER_INSTANCE +{ + LIST_ENTRY link; + + BOOLEAN isIpConfigured; + UINT32 portNo; + GUID netCfgId; + MIB_IF_ROW2 internalRow; + MIB_IPINTERFACE_ROW internalIPRow; + UINT32 ipAddress; + + ERESOURCE lock; +} OVS_IPHELPER_INSTANCE, *POVS_IPHELPER_INSTANCE; typedef struct _OVS_IPNEIGH_ENTRY { - UINT8 macAddr[ETH_ADDR_LEN]; - UINT16 refCount; - UINT32 ipAddr; - UINT32 pad; - UINT64 timeout; - LIST_ENTRY link; - LIST_ENTRY slink; - LIST_ENTRY fwdList; - PVOID context; + UINT8 macAddr[ETH_ADDR_LEN]; + UINT16 refCount; + UINT32 ipAddr; + UINT32 pad; + UINT64 timeout; + LIST_ENTRY link; + LIST_ENTRY slink; + LIST_ENTRY fwdList; + POVS_IPHELPER_INSTANCE instance; } OVS_IPNEIGH_ENTRY, *POVS_IPNEIGH_ENTRY; typedef struct _OVS_IPFORWARD_ENTRY { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/Vport.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/Vport.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/datapath-windows/ovsext/Vport.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/datapath-windows/ovsext/Vport.c 2020-03-11 16:15:44.000000000 +0000 @@ -632,13 +632,13 @@ OvsRemoveAndDeleteVport(NULL, switchContext, vport, FALSE, TRUE); OvsPostVportEvent(&event); } - NdisReleaseRWLock(switchContext->dispatchLock, &lockState); if (isInternalPort) { OvsInternalAdapterDown(vport->portNo, vport->netCfgInstanceId); OvsRemoveAndDeleteVport(NULL, switchContext, vport, TRUE, TRUE); OvsPostVportEvent(&event); } + NdisReleaseRWLock(switchContext->dispatchLock, &lockState); done: VPORT_NIC_EXIT(nicParam); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/changelog openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/changelog --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/changelog 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/changelog 2020-03-11 16:21:39.000000000 +0000 @@ -1,8 +1,12 @@ -openvswitch (2.10.0+2018.08.28+git.8ca7c82b7d+ds1-12+deb10u2~bpo10+1) UNRELEASED; urgency=medium +openvswitch (2.10.4+2020.01.14.b2ccc307f1+dfsg1-1+deb10u3) UNRELEASED; urgency=medium - * Rebuilt by bop. + * New upstream point release + git head. + * Refreshed patches. Disabled "disable-failed-tests.patch" which doesn't + apply anymore. + * Disable patch: + Fix_vswitchd_abort_when_a_port_is_added_and_the_controller_is_down.patch. - -- Jenkins Fri, 06 Mar 2020 12:35:38 +0000 + -- Thomas Goirand Wed, 11 Mar 2020 17:21:39 +0100 openvswitch (2.10.0+2018.08.28+git.8ca7c82b7d+ds1-12+deb10u2) buster; urgency=medium diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/blacklist-ofproto-async-msg-ctrl-of1.3-because-of-mips.patch openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/blacklist-ofproto-async-msg-ctrl-of1.3-because-of-mips.patch --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/blacklist-ofproto-async-msg-ctrl-of1.3-because-of-mips.patch 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/blacklist-ofproto-async-msg-ctrl-of1.3-because-of-mips.patch 2020-03-11 16:21:39.000000000 +0000 @@ -5,9 +5,11 @@ Forwarded: not-needed Last-Update: 2018-10-22 ---- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1.orig/tests/ofproto.at -+++ openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto.at -@@ -3446,121 +3446,6 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) +Index: openvswitch/tests/ofproto.at +=================================================================== +--- openvswitch.orig/tests/ofproto.at ++++ openvswitch/tests/ofproto.at +@@ -3476,121 +3476,6 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) OVS_VSWITCHD_STOP AT_CLEANUP diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/disable-even-more-tests.patch openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/disable-even-more-tests.patch --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/disable-even-more-tests.patch 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/disable-even-more-tests.patch 2020-03-11 16:21:39.000000000 +0000 @@ -4,8 +4,10 @@ Forwarded: no Last-Update: 2018-10-12 ---- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1.orig/tests/ofproto-dpif.at -+++ openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto-dpif.at +Index: openvswitch/tests/ofproto-dpif.at +=================================================================== +--- openvswitch.orig/tests/ofproto-dpif.at ++++ openvswitch/tests/ofproto-dpif.at @@ -474,93 +474,6 @@ recirc_id(0x1),dp_hash(0xXXXX/0xf),in_po OVS_VSWITCHD_STOP AT_CLEANUP @@ -100,9 +102,11 @@ AT_SETUP([ofproto-dpif - select group with explicit dp_hash selection method]) OVS_VSWITCHD_START ---- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1.orig/tests/ofproto.at -+++ openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto.at -@@ -738,44 +738,6 @@ AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn +Index: openvswitch/tests/ofproto.at +=================================================================== +--- openvswitch.orig/tests/ofproto.at ++++ openvswitch/tests/ofproto.at +@@ -752,44 +752,6 @@ AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn OVS_VSWITCHD_STOP AT_CLEANUP diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/Fix_vswitchd_abort_when_a_port_is_added_and_the_controller_is_down.patch openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/Fix_vswitchd_abort_when_a_port_is_added_and_the_controller_is_down.patch --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/Fix_vswitchd_abort_when_a_port_is_added_and_the_controller_is_down.patch 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/Fix_vswitchd_abort_when_a_port_is_added_and_the_controller_is_down.patch 2020-03-11 16:21:39.000000000 +0000 @@ -41,13 +41,13 @@ Origin: upstream, https://github.com/openvswitch/ovs/commit/903f6c4f8a9bce51984435ca3990f2717c63f703.patch Last-Update: 2020-03-06 -diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c -index 50e0b8f991..9431200249 100644 ---- a/ofproto/connmgr.c -+++ b/ofproto/connmgr.c -@@ -1538,6 +1538,10 @@ ofconn_receives_async_msg(const struct ofconn *ofconn, - ovs_assert(reason < 32); - ovs_assert((unsigned int) type < OAM_N_TYPES); +Index: openvswitch/ofproto/connmgr.c +=================================================================== +--- openvswitch.orig/ofproto/connmgr.c ++++ openvswitch/ofproto/connmgr.c +@@ -1542,6 +1542,10 @@ ofconn_receives_async_msg(const struct o + return false; + } + if (!rconn_is_connected(ofconn->rconn)) { + return false; @@ -56,11 +56,11 @@ /* Keep the following code in sync with the documentation in the * "Asynchronous Messages" section in 'topics/design' */ -diff --git a/tests/bridge.at b/tests/bridge.at -index 1c36185632..ee398bdb1e 100644 ---- a/tests/bridge.at -+++ b/tests/bridge.at -@@ -79,3 +79,24 @@ AT_CHECK([ovs-vsctl --columns=status list controller | dnl +Index: openvswitch/tests/bridge.at +=================================================================== +--- openvswitch.orig/tests/bridge.at ++++ openvswitch/tests/bridge.at +@@ -103,3 +103,24 @@ AT_CHECK([ovs-appctl -t ovs-vswitchd ver OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) OVS_APP_EXIT_AND_WAIT([ovsdb-server]) AT_CLEANUP diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/ovs-dev-ovs-macros-Make-tests-log-how-long-they-waited-when-they-succeed..diff openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/ovs-dev-ovs-macros-Make-tests-log-how-long-they-waited-when-they-succeed..diff --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/ovs-dev-ovs-macros-Make-tests-log-how-long-they-waited-when-they-succeed..diff 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/ovs-dev-ovs-macros-Make-tests-log-how-long-they-waited-when-they-succeed..diff 2020-03-11 16:21:39.000000000 +0000 @@ -21,7 +21,7 @@ sort $exp_text > expout } ]) -@@ -4290,6 +4288,9 @@ test_dhcp() { +@@ -4298,6 +4296,9 @@ test_dhcp() { # dhcp message type request=${request}3501${dhcp_type}ff diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/removed-tests-which-are-failing-in-mips-and-armel.patch openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/removed-tests-which-are-failing-in-mips-and-armel.patch --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/removed-tests-which-are-failing-in-mips-and-armel.patch 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/removed-tests-which-are-failing-in-mips-and-armel.patch 2020-03-11 16:21:39.000000000 +0000 @@ -4,8 +4,10 @@ Forwarded: not-needed Last-Update: 2018-10-10 ---- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1.orig/tests/ofproto-dpif.at -+++ openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto-dpif.at +Index: openvswitch/tests/ofproto-dpif.at +=================================================================== +--- openvswitch.orig/tests/ofproto-dpif.at ++++ openvswitch/tests/ofproto-dpif.at @@ -1864,70 +1864,6 @@ OVS_VSWITCHD_STOP AT_CLEANUP @@ -77,9 +79,11 @@ AT_SETUP([ofproto-dpif - MPLS handling]) OVS_VSWITCHD_START([dnl add-port br0 p1 -- set Interface p1 type=dummy ---- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1.orig/tests/ofproto.at -+++ openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto.at -@@ -3599,215 +3599,6 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) +Index: openvswitch/tests/ofproto.at +=================================================================== +--- openvswitch.orig/tests/ofproto.at ++++ openvswitch/tests/ofproto.at +@@ -3629,215 +3629,6 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) OVS_VSWITCHD_STOP AT_CLEANUP diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/remove-non-deterministic-tests.patch openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/remove-non-deterministic-tests.patch --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/remove-non-deterministic-tests.patch 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/remove-non-deterministic-tests.patch 2020-03-11 16:21:39.000000000 +0000 @@ -5,8 +5,10 @@ Forwarded: no Last-Update: 2018-12-14 ---- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1.orig/tests/ovsdb-cluster.at -+++ openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovsdb-cluster.at +Index: openvswitch/tests/ovsdb-cluster.at +=================================================================== +--- openvswitch.orig/tests/ovsdb-cluster.at ++++ openvswitch/tests/ovsdb-cluster.at @@ -246,36 +246,3 @@ AT_SETUP([OVSDB 5-server torture test - AT_KEYWORDS([ovsdb server positive unix cluster cluster5]) ovsdb_torture_test 5 5 kill diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/remove-tests-broken-in-mips64el-and-mipsel.patch openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/remove-tests-broken-in-mips64el-and-mipsel.patch --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/remove-tests-broken-in-mips64el-and-mipsel.patch 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/remove-tests-broken-in-mips64el-and-mipsel.patch 2020-03-11 16:21:39.000000000 +0000 @@ -6,9 +6,11 @@ Forwarded: no Last-Update: 2018-08-30 ---- openvswitch-2.8.1+dfsg1.orig/tests/ofproto-dpif.at -+++ openvswitch-2.8.1+dfsg1/tests/ofproto-dpif.at -@@ -1888,13 +1888,6 @@ +Index: openvswitch/tests/ofproto-dpif.at +=================================================================== +--- openvswitch.orig/tests/ofproto-dpif.at ++++ openvswitch/tests/ofproto-dpif.at +@@ -1888,13 +1888,6 @@ flow-dump from non-dpdk interfaces: packets:1, bytes:14, used:0.001s, actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=1,rule_cookie=0,controller_id=0,max_len=65535)) ]) @@ -22,7 +24,7 @@ AT_CHECK([ovs-appctl revalidator/purge]) AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl -P nxt_packet_in --detach --no-chdir --pidfile 2> ofctl_monitor.log]) -@@ -6559,25 +6552,6 @@ +@@ -6627,25 +6620,6 @@ AT_CHECK([ovs-appctl time/warp 2000 100] AT_CHECK([ovs-appctl revalidator/purge], [0]) OVS_VSWITCHD_STOP OVS_APP_EXIT_AND_WAIT([test-sflow]) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/remove-yet-another-mips-failing-test.patch openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/remove-yet-another-mips-failing-test.patch --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/remove-yet-another-mips-failing-test.patch 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/remove-yet-another-mips-failing-test.patch 2020-03-11 16:21:39.000000000 +0000 @@ -3,9 +3,11 @@ Forwarded: no Last-Update: 2018-10-25 ---- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1.orig/tests/ovn.at -+++ openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovn.at -@@ -2039,208 +2039,6 @@ OVN_CLEANUP([hv1],[hv2]) +Index: openvswitch/tests/ovn.at +=================================================================== +--- openvswitch.orig/tests/ovn.at ++++ openvswitch/tests/ovn.at +@@ -2047,208 +2047,6 @@ OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/series openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/series --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/debian/patches/series 2020-03-06 12:35:38.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/debian/patches/series 2020-03-11 16:21:39.000000000 +0000 @@ -1,7 +1,7 @@ remove-include-debian-automake.mk.patch remove-tests-broken-in-mips64el-and-mipsel.patch remove-bfd-decay-tests.patch -disable-failed-tests.patch +#disable-failed-tests.patch py3-compat.patch use-python3-m-sphinx-to-build-doc.patch ovs-dev-ovs-macros-Make-tests-log-how-long-they-waited-when-they-succeed..diff @@ -10,4 +10,4 @@ blacklist-ofproto-async-msg-ctrl-of1.3-because-of-mips.patch remove-yet-another-mips-failing-test.patch remove-non-deterministic-tests.patch -Fix_vswitchd_abort_when_a_port_is_added_and_the_controller_is_down.patch +#Fix_vswitchd_abort_when_a_port_is_added_and_the_controller_is_down.patch diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/faq/releases.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/faq/releases.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/faq/releases.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/faq/releases.rst 2020-03-11 16:15:44.000000000 +0000 @@ -165,10 +165,10 @@ 2.4.x 2.0 2.5.x 2.2 2.6.x 16.07.2 - 2.7.x 16.11.7 + 2.7.x 16.11.8 2.8.x 17.05.2 - 2.9.x 17.11.3 - 2.10.x 17.11.3 + 2.9.x 17.11.6 + 2.10.x 17.11.6 ============ ======= Q: Are all the DPDK releases that OVS versions work with maintained? diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/faq/vlan.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/faq/vlan.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/faq/vlan.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/faq/vlan.rst 2020-03-11 16:15:44.000000000 +0000 @@ -191,7 +191,7 @@ $ ovs-vsctl add-port br0 vlan9 tag=9 \ -- set interface vlan9 type=internal $ ip addr add 192.168.0.7/24 dev vlan9 - $ ip link set vlan0 up + $ ip link set vlan9 up See also the following question. @@ -203,7 +203,7 @@ $ ip link set br0 up $ ovs-vsctl add-port br0 vlan9 tag=9 -- set interface vlan9 type=internal $ ip addr add 192.168.0.9/24 dev vlan9 - $ ip link set vlan0 up + $ ip link set vlan9 up but other hosts that are only on VLAN 0 can reach the IP address configured on VLAN 9. What's going on? diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/howto/dpdk.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/howto/dpdk.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/howto/dpdk.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/howto/dpdk.rst 2020-03-11 16:15:44.000000000 +0000 @@ -284,7 +284,7 @@ We must configure with appropriate software versions to ensure this feature is supported. - .. list-table:: Recommended BIOS Settings + .. list-table:: VM Configuration :header-rows: 1 * - Setting diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/internals/mailing-lists.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/internals/mailing-lists.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/internals/mailing-lists.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/internals/mailing-lists.rst 2020-03-11 16:15:44.000000000 +0000 @@ -93,4 +93,4 @@ The `security`__ mailing list is for submitting security vulnerabilities to the security team. -__ security@ovs.org +__ security@openvswitch.org diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/intro/install/dpdk.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/intro/install/dpdk.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/intro/install/dpdk.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/intro/install/dpdk.rst 2020-03-11 16:15:44.000000000 +0000 @@ -42,7 +42,7 @@ In addition to the requirements described in :doc:`general`, building Open vSwitch with DPDK will require the following: -- DPDK 17.11.3 +- DPDK 17.11.6 - A `DPDK supported NIC`_ @@ -71,9 +71,9 @@ #. Download the `DPDK sources`_, extract the file and set ``DPDK_DIR``:: $ cd /usr/src/ - $ wget http://fast.dpdk.org/rel/dpdk-17.11.3.tar.xz - $ tar xf dpdk-17.11.3.tar.xz - $ export DPDK_DIR=/usr/src/dpdk-stable-17.11.3 + $ wget http://fast.dpdk.org/rel/dpdk-17.11.6.tar.xz + $ tar xf dpdk-17.11.6.tar.xz + $ export DPDK_DIR=/usr/src/dpdk-stable-17.11.6 $ cd $DPDK_DIR #. (Optional) Configure DPDK as a shared library @@ -661,7 +661,6 @@ Limitations ------------ -- Currently DPDK ports does not use HW offload functionality. - Network Interface Firmware requirements: Each release of DPDK is validated against a specific firmware version for a supported Network Interface. New firmware versions introduce bug fixes, performance diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/intro/what-is-ovs.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/intro/what-is-ovs.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/intro/what-is-ovs.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/intro/what-is-ovs.rst 2020-03-11 16:15:44.000000000 +0000 @@ -33,9 +33,9 @@ Overview -------- -.. NOTE(stephenfin): The below line numbers may need to be updated if the - README is modified +.. NOTE(stephenfin): The below start-after/end-before may need to be updated + if the README is modified. .. include:: ../../README.rst - :start-line: 13 - :end-line: 71 + :start-after: What is Open vSwitch? + :end-before: What other documentation is available? diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/ref/ovsdb-server.7.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/ref/ovsdb-server.7.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/ref/ovsdb-server.7.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/ref/ovsdb-server.7.rst 2020-03-11 16:15:44.000000000 +0000 @@ -455,9 +455,10 @@ For , RFC 7047 only allows the use of ``!=``, ``==``, ``includes``, and ``excludes`` operators with set types. Open vSwitch 2.4 and later extend to allow the use of ``<``, ``<=``, ``>=``, and ``>`` operators with -columns with type "set of 0 or 1 integer" and "set of 0 or 1 real". These -conditions evaluate to false when the column is empty, and otherwise as -described in RFC 7047 for integer and real types. +a column with type "set of 0 or 1 integer" and an integer argument, and with +"set of 0 or 1 real" and a real argument. These conditions evaluate to false +when the column is empty, and otherwise as described in RFC 7047 for integer +and real types. is specified in Section 5.1 in the RFC with the following change: A condition can be either a 3-element JSON array as described in the RFC or a diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/topics/dpdk/vhost-user.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/topics/dpdk/vhost-user.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/topics/dpdk/vhost-user.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/topics/dpdk/vhost-user.rst 2020-03-11 16:15:44.000000000 +0000 @@ -320,9 +320,9 @@ DPDK sources to VM and build DPDK:: $ cd /root/dpdk/ - $ wget http://fast.dpdk.org/rel/dpdk-17.11.3.tar.xz - $ tar xf dpdk-17.11.3.tar.xz - $ export DPDK_DIR=/root/dpdk/dpdk-stable-17.11.3 + $ wget http://fast.dpdk.org/rel/dpdk-17.11.6.tar.xz + $ tar xf dpdk-17.11.6.tar.xz + $ export DPDK_DIR=/root/dpdk/dpdk-stable-17.11.6 $ export DPDK_TARGET=x86_64-native-linuxapp-gcc $ export DPDK_BUILD=$DPDK_DIR/$DPDK_TARGET $ cd $DPDK_DIR @@ -500,12 +500,6 @@ Because of this limitation, this feature is considered 'experimental'. -The feature currently does not fully work with QEMU >= v2.7 due to a bug in -DPDK which will be addressed in an upcoming release. The patch to fix this -issue can be found on -`Patchwork -`__ - Further information can be found in the `DPDK documentation `__ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/topics/tracing.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/topics/tracing.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/topics/tracing.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/topics/tracing.rst 2020-03-11 16:15:44.000000000 +0000 @@ -39,7 +39,7 @@ -------------- In order to understand the tool, let's use the following flows as an -example: +example:: table=3,ip,tcp,tcp_dst=80,action=output:2 table=2,ip,tcp,tcp_dst=22,action=output:1 diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/tutorials/ovs-conntrack.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/tutorials/ovs-conntrack.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Documentation/tutorials/ovs-conntrack.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Documentation/tutorials/ovs-conntrack.rst 2020-03-11 16:15:44.000000000 +0000 @@ -325,7 +325,7 @@ (flow #2) $ ovs-ofctl add-flow br0 \ - "table=0, priority=50, ct_state=+trk,+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0" + "table=0, priority=50, ct_state=+trk+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0" Now that the packet is coming back from conntrack, the ct_state would have the "trk" set. @@ -364,7 +364,7 @@ "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_r0, actions=ct(table=0)" (flow #4) $ ovs-ofctl add-flow br0 \ - "table=0, priority=50, ct_state=+trk,+est, tcp, in_port=veth_r0, actions=veth_l0" + "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_r0, actions=veth_l0" flow #3 matches untracked packets coming back from server (10.0.0.2) and sends @@ -400,7 +400,7 @@ (flow #5) $ ovs-ofctl add-flow br0 \ - "table=0, priority=50, ct_state=+trk,+est, tcp, in_port=veth_l0, actions=veth_r0" + "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_l0, actions=veth_r0" Send the third TCP ack segment using scapy (at the "left" scapy session) (flags=0x10 is ack):: @@ -557,7 +557,7 @@ (flow #2) $ ovs-ofctl add-flow br0 \ - "table=0, priority=50, ct_state=+trk,+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0" + "table=0, priority=50, ct_state=+trk+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0" (flow #3) $ ovs-ofctl add-flow br0 \ @@ -565,8 +565,8 @@ (flow #4) $ ovs-ofctl add-flow br0 \ - "table=0, priority=50, ct_state=+trk,+est, tcp, in_port=veth_r0, actions=veth_l0" + "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_r0, actions=veth_l0" (flow #5) $ ovs-ofctl add-flow br0 \ - "table=0, priority=50, ct_state=+trk,+est, tcp, in_port=veth_l0, actions=veth_r0" + "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_l0, actions=veth_r0" diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/linux/pkt_cls.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/linux/pkt_cls.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/linux/pkt_cls.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/linux/pkt_cls.h 2020-03-11 16:15:44.000000000 +0000 @@ -64,7 +64,9 @@ __u64 install; __u64 lastuse; __u64 expires; +#ifdef HAVE_STRUCT_TCF_T_FIRSTUSE __u64 firstuse; +#endif }; #define tc_gen \ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/compiler.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/compiler.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/compiler.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/compiler.h 2020-03-11 16:15:44.000000000 +0000 @@ -236,6 +236,18 @@ #define OVS_PREFETCH_WRITE(addr) #endif +/* Since Visual Studio 2015 there has been an effort to make offsetof a + * builtin_offsetof, unfortunately both implementation (the regular define and + * the built in one) are buggy and cause issues when using them via + * the C compiler. + * e.g.: https://bit.ly/2UvWwti + */ +#if _MSC_VER >= 1900 +#undef offsetof +#define offsetof(type, member) \ + ((size_t)((char *)&(((type *)0)->member) - (char *)0)) +#endif + /* Build assertions. * * Use BUILD_ASSERT_DECL as a declaration or a statement, or BUILD_ASSERT as diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/meta-flow.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/meta-flow.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/meta-flow.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/meta-flow.h 2020-03-11 16:15:44.000000000 +0000 @@ -1454,7 +1454,7 @@ */ MFF_IP_TTL, - /* "ip_frag". + /* "ip_frag" (aka "nw_frag"). * * IP fragment information. * diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/nsh.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/nsh.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/nsh.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/nsh.h 2020-03-11 16:15:44.000000000 +0000 @@ -263,10 +263,10 @@ #define NSH_M_TYPE1_LEN 24 /* NSH header maximum Length. */ -#define NSH_HDR_MAX_LEN 256 +#define NSH_HDR_MAX_LEN 252 /* NSH context headers maximum Length. */ -#define NSH_CTX_HDRS_MAX_LEN 248 +#define NSH_CTX_HDRS_MAX_LEN 244 static inline uint16_t nsh_hdr_len(const struct nsh_hdr *nsh) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/ofp-actions.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/ofp-actions.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/ofp-actions.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/ofp-actions.h 2020-03-11 16:15:44.000000000 +0000 @@ -275,16 +275,20 @@ * Action structure for actions that do not have any extra data beyond the * action type. */ struct ofpact_null { - struct ofpact ofpact; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ); }; /* OFPACT_OUTPUT. * * Used for OFPAT10_OUTPUT. */ struct ofpact_output { - struct ofpact ofpact; - ofp_port_t port; /* Output port. */ - uint16_t max_len; /* Max send len, for port OFPP_CONTROLLER. */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ofp_port_t port; /* Output port. */ + uint16_t max_len; /* Max send len, for port OFPP_CONTROLLER. */ + ); }; #define NX_CTLR_NO_METER 0 @@ -321,27 +325,33 @@ * * Used for OFPAT10_ENQUEUE. */ struct ofpact_enqueue { - struct ofpact ofpact; - ofp_port_t port; - uint32_t queue; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ofp_port_t port; + uint32_t queue; + ); }; /* OFPACT_OUTPUT_REG. * * Used for NXAST_OUTPUT_REG. */ struct ofpact_output_reg { - struct ofpact ofpact; - uint16_t max_len; - struct mf_subfield src; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint16_t max_len; + struct mf_subfield src; + ); }; /* OFPACT_OUTPUT_TRUNC. * * Used for NXAST_OUTPUT_TRUNC. */ struct ofpact_output_trunc { - struct ofpact ofpact; - ofp_port_t port; /* Output port. */ - uint32_t max_len; /* Max send len. */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ofp_port_t port; /* Output port. */ + uint32_t max_len; /* Max send len. */ + ); }; /* Bundle slave choice algorithm to apply. @@ -371,19 +381,21 @@ * * Used for NXAST_BUNDLE. */ struct ofpact_bundle { - struct ofpact ofpact; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; - /* Slave choice algorithm to apply to hash value. */ - enum nx_bd_algorithm algorithm; + /* Slave choice algorithm to apply to hash value. */ + enum nx_bd_algorithm algorithm; - /* What fields to hash and how. */ - enum nx_hash_fields fields; - uint16_t basis; /* Universal hash parameter. */ + /* What fields to hash and how. */ + enum nx_hash_fields fields; + uint16_t basis; /* Universal hash parameter. */ - struct mf_subfield dst; + struct mf_subfield dst; - /* Slaves for output. */ - unsigned int n_slaves; + /* Slaves for output. */ + unsigned int n_slaves; + ); ofp_port_t slaves[]; }; @@ -396,10 +408,12 @@ * * Used for OFPAT10_SET_VLAN_VID and OFPAT11_SET_VLAN_VID. */ struct ofpact_vlan_vid { - struct ofpact ofpact; - uint16_t vlan_vid; /* VLAN VID in low 12 bits, 0 in other bits. */ - bool push_vlan_if_needed; /* OF 1.0 semantics if true. */ - bool flow_has_vlan; /* VLAN present at action validation time? */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint16_t vlan_vid; /* VLAN VID in low 12 bits, other bits 0. */ + bool push_vlan_if_needed; /* OF 1.0 semantics if true. */ + bool flow_has_vlan; /* VLAN present at action validation time? */ + ); }; /* OFPACT_SET_VLAN_PCP. @@ -411,84 +425,104 @@ * * Used for OFPAT10_SET_VLAN_PCP and OFPAT11_SET_VLAN_PCP. */ struct ofpact_vlan_pcp { - struct ofpact ofpact; - uint8_t vlan_pcp; /* VLAN PCP in low 3 bits, 0 in other bits. */ - bool push_vlan_if_needed; /* OF 1.0 semantics if true. */ - bool flow_has_vlan; /* VLAN present at action validation time? */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t vlan_pcp; /* VLAN PCP in low 3 bits, other bits 0. */ + bool push_vlan_if_needed; /* OF 1.0 semantics if true. */ + bool flow_has_vlan; /* VLAN present at action validation? */ + ); }; /* OFPACT_PUSH_VLAN. * * Used for OFPAT11_PUSH_VLAN. */ struct ofpact_push_vlan { - struct ofpact ofpact; - ovs_be16 ethertype; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ovs_be16 ethertype; + ); }; /* OFPACT_SET_ETH_SRC, OFPACT_SET_ETH_DST. * * Used for OFPAT10_SET_DL_SRC, OFPAT10_SET_DL_DST. */ struct ofpact_mac { - struct ofpact ofpact; - struct eth_addr mac; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + struct eth_addr mac; + ); }; /* OFPACT_SET_IPV4_SRC, OFPACT_SET_IPV4_DST. * * Used for OFPAT10_SET_NW_SRC, OFPAT10_SET_NW_DST. */ struct ofpact_ipv4 { - struct ofpact ofpact; - ovs_be32 ipv4; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ovs_be32 ipv4; + ); }; /* OFPACT_SET_IP_DSCP. * * Used for OFPAT10_SET_NW_TOS. */ struct ofpact_dscp { - struct ofpact ofpact; - uint8_t dscp; /* DSCP in high 6 bits, rest ignored. */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t dscp; /* DSCP in high 6 bits, rest ignored. */ + ); }; /* OFPACT_SET_IP_ECN. * * Used for OFPAT11_SET_NW_ECN. */ struct ofpact_ecn { - struct ofpact ofpact; - uint8_t ecn; /* ECN in low 2 bits, rest ignored. */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t ecn; /* ECN in low 2 bits, rest ignored. */ + ); }; /* OFPACT_SET_IP_TTL. * * Used for OFPAT11_SET_NW_TTL. */ struct ofpact_ip_ttl { - struct ofpact ofpact; - uint8_t ttl; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t ttl; + ); }; /* OFPACT_SET_L4_SRC_PORT, OFPACT_SET_L4_DST_PORT. * * Used for OFPAT10_SET_TP_SRC, OFPAT10_SET_TP_DST. */ struct ofpact_l4_port { - struct ofpact ofpact; - uint16_t port; /* TCP, UDP or SCTP port number. */ - uint8_t flow_ip_proto; /* IP proto from corresponding match, or 0 */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint16_t port; /* TCP, UDP or SCTP port number. */ + uint8_t flow_ip_proto; /* IP proto from corresponding match, or 0 */ + ); }; /* OFPACT_REG_MOVE. * * Used for NXAST_REG_MOVE. */ struct ofpact_reg_move { - struct ofpact ofpact; - struct mf_subfield src; - struct mf_subfield dst; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + struct mf_subfield src; + struct mf_subfield dst; + ); }; /* OFPACT_STACK_PUSH, OFPACT_STACK_POP. * * Used for NXAST_STACK_PUSH and NXAST_STACK_POP. */ struct ofpact_stack { - struct ofpact ofpact; - struct mf_subfield subfield; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + struct mf_subfield subfield; + ); }; /* OFPACT_SET_FIELD. @@ -517,59 +551,73 @@ * * Used for NXAST_PUSH_MPLS, OFPAT11_PUSH_MPLS. */ struct ofpact_push_mpls { - struct ofpact ofpact; - ovs_be16 ethertype; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ovs_be16 ethertype; + ); }; /* OFPACT_POP_MPLS * * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS.. */ struct ofpact_pop_mpls { - struct ofpact ofpact; - ovs_be16 ethertype; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ovs_be16 ethertype; + ); }; /* OFPACT_SET_TUNNEL. * * Used for NXAST_SET_TUNNEL, NXAST_SET_TUNNEL64. */ struct ofpact_tunnel { - struct ofpact ofpact; - uint64_t tun_id; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint64_t tun_id; + ); }; /* OFPACT_SET_QUEUE. * * Used for NXAST_SET_QUEUE. */ struct ofpact_queue { - struct ofpact ofpact; - uint32_t queue_id; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint32_t queue_id; + ); }; /* OFPACT_FIN_TIMEOUT. * * Used for NXAST_FIN_TIMEOUT. */ struct ofpact_fin_timeout { - struct ofpact ofpact; - uint16_t fin_idle_timeout; - uint16_t fin_hard_timeout; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint16_t fin_idle_timeout; + uint16_t fin_hard_timeout; + ); }; /* OFPACT_WRITE_METADATA. * * Used for NXAST_WRITE_METADATA. */ struct ofpact_metadata { - struct ofpact ofpact; - ovs_be64 metadata; - ovs_be64 mask; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ovs_be64 metadata; + ovs_be64 mask; + ); }; /* OFPACT_METER. * * Used for OFPIT13_METER. */ struct ofpact_meter { - struct ofpact ofpact; - uint32_t meter_id; - uint32_t provider_meter_id; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint32_t meter_id; + uint32_t provider_meter_id; + ); }; /* OFPACT_WRITE_ACTIONS, OFPACT_CLONE. @@ -657,25 +705,27 @@ * * Used for NXAST_NAT. */ struct ofpact_nat { - struct ofpact ofpact; - uint8_t range_af; /* AF_UNSPEC, AF_INET, or AF_INET6 */ - uint16_t flags; /* NX_NAT_F_* */ - struct { + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t range_af; /* AF_UNSPEC, AF_INET, or AF_INET6 */ + uint16_t flags; /* NX_NAT_F_* */ struct { - uint16_t min; - uint16_t max; - } proto; - union { - struct { - ovs_be32 min; - ovs_be32 max; - } ipv4; struct { - struct in6_addr min; - struct in6_addr max; - } ipv6; - } addr; - } range; + uint16_t min; + uint16_t max; + } proto; + union { + struct { + ovs_be32 min; + ovs_be32 max; + } ipv4; + struct { + struct in6_addr min; + struct in6_addr max; + } ipv6; + } addr; + } range; + ); }; @@ -683,11 +733,13 @@ * * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE, NXAST_RESUBMIT_TABLE_CT. */ struct ofpact_resubmit { - struct ofpact ofpact; - ofp_port_t in_port; - uint8_t table_id; - bool with_ct_orig; /* Resubmit with Conntrack original direction tuple - * fields in place of IP header fields. */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ofp_port_t in_port; + uint8_t table_id; + bool with_ct_orig; /* Resubmit with Conntrack original direction tuple + * fields in place of IP header fields. */ + ); }; /* Bits for 'flags' in struct nx_action_learn. @@ -747,7 +799,7 @@ * NX_LEARN_DST_LOAD only. */ uint16_t src_type; /* One of NX_LEARN_SRC_*. */ uint16_t dst_type; /* One of NX_LEARN_DST_*. */ - uint8_t n_bits; /* Number of bits in source and dest. */ + uint32_t n_bits; /* Number of bits in source and dest. */ ); /* Followed by 'DIV_ROUND_UP(n_bits, 8)' bytes of immediate data for * match 'dst_type's NX_LEARN_DST_MATCH and NX_LEARN_DST_LOAD when @@ -870,37 +922,43 @@ * * Used for NXAST_CONJUNCTION. */ struct ofpact_conjunction { - struct ofpact ofpact; - uint8_t clause; - uint8_t n_clauses; - uint32_t id; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t clause; + uint8_t n_clauses; + uint32_t id; + ); }; /* OFPACT_MULTIPATH. * * Used for NXAST_MULTIPATH. */ struct ofpact_multipath { - struct ofpact ofpact; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; - /* What fields to hash and how. */ - enum nx_hash_fields fields; - uint16_t basis; /* Universal hash parameter. */ - - /* Multipath link choice algorithm to apply to hash value. */ - enum nx_mp_algorithm algorithm; - uint16_t max_link; /* Number of output links, minus 1. */ - uint32_t arg; /* Algorithm-specific argument. */ + /* What fields to hash and how. */ + enum nx_hash_fields fields; + uint16_t basis; /* Universal hash parameter. */ + + /* Multipath link choice algorithm to apply to hash value. */ + enum nx_mp_algorithm algorithm; + uint16_t max_link; /* Number of output links, minus 1. */ + uint32_t arg; /* Algorithm-specific argument. */ - /* Where to store the result. */ - struct mf_subfield dst; + /* Where to store the result. */ + struct mf_subfield dst; + ); }; /* OFPACT_NOTE. * * Used for NXAST_NOTE. */ struct ofpact_note { - struct ofpact ofpact; - size_t length; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + size_t length; + ); uint8_t data[]; }; @@ -922,23 +980,25 @@ * * Used for NXAST_SAMPLE, NXAST_SAMPLE2, and NXAST_SAMPLE3. */ struct ofpact_sample { - struct ofpact ofpact; - uint16_t probability; /* Always positive. */ - uint32_t collector_set_id; - uint32_t obs_domain_id; - uint32_t obs_point_id; - ofp_port_t sampling_port; - enum nx_action_sample_direction direction; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint16_t probability; /* Always positive. */ + uint32_t collector_set_id; + uint32_t obs_domain_id; + uint32_t obs_point_id; + ofp_port_t sampling_port; + enum nx_action_sample_direction direction; + ); }; /* OFPACT_DEC_TTL. * * Used for OFPAT11_DEC_NW_TTL, NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. */ struct ofpact_cnt_ids { - struct ofpact ofpact; - - /* Controller ids. */ - unsigned int n_controllers; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + unsigned int n_controllers; + ); uint16_t cnt_ids[]; }; @@ -946,54 +1006,63 @@ * * Used for OFPAT11_SET_MPLS_LABEL and NXAST_SET_MPLS_LABEL */ struct ofpact_mpls_label { - struct ofpact ofpact; - - ovs_be32 label; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ovs_be32 label; + ); }; /* OFPACT_SET_MPLS_TC. * * Used for OFPAT11_SET_MPLS_TC and NXAST_SET_MPLS_TC */ struct ofpact_mpls_tc { - struct ofpact ofpact; - - uint8_t tc; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t tc; + ); }; /* OFPACT_SET_MPLS_TTL. * * Used for OFPAT11_SET_MPLS_TTL and NXAST_SET_MPLS_TTL */ struct ofpact_mpls_ttl { - struct ofpact ofpact; - - uint8_t ttl; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t ttl; + ); }; /* OFPACT_GOTO_TABLE * * Used for OFPIT11_GOTO_TABLE */ struct ofpact_goto_table { - struct ofpact ofpact; - uint8_t table_id; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint8_t table_id; + ); }; /* OFPACT_GROUP. * * Used for OFPAT11_GROUP. */ struct ofpact_group { - struct ofpact ofpact; - uint32_t group_id; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + uint32_t group_id; + ); }; /* OFPACT_UNROLL_XLATE. * * Used only internally. */ struct ofpact_unroll_xlate { - struct ofpact ofpact; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; - /* Metadata in xlate context, visible to controller via PACKET_INs. */ - uint8_t rule_table_id; /* 0xFF if none. */ - ovs_be64 rule_cookie; /* OVS_BE64_MAX if none. */ + /* Metadata in xlate context, visible to controller via PACKET_INs. */ + uint8_t rule_table_id; /* 0xFF if none. */ + ovs_be64 rule_cookie; /* OVS_BE64_MAX if none. */ + ); }; /* OFPACT_ENCAP. @@ -1001,10 +1070,12 @@ * Used for NXAST_ENCAP. */ struct ofpact_encap { - struct ofpact ofpact; - ovs_be32 new_pkt_type; /* Packet type of the header to add. */ - uint16_t hdr_size; /* New header size in bytes. */ - uint16_t n_props; /* Number of encap properties. */ + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; + ovs_be32 new_pkt_type; /* Packet type of the header to add. */ + uint16_t hdr_size; /* New header size in bytes. */ + uint16_t n_props; /* Number of encap properties. */ + ); struct ofpact_ed_prop props[]; /* Properties in internal format. */ }; @@ -1012,15 +1083,17 @@ * * Used for NXAST_DECAP. */ struct ofpact_decap { - struct ofpact ofpact; + OFPACT_PADDED_MEMBERS( + struct ofpact ofpact; - /* New packet type. - * - * The special value (0,0xFFFE) "Use next proto" is used to request OVS to - * automatically set the new packet type based on the decap'ed header's - * next protocol. - */ - ovs_be32 new_pkt_type; + /* New packet type. + * + * The special value (0,0xFFFE) "Use next proto" is used to request OVS + * to automatically set the new packet type based on the decap'ed + * header's next protocol. + */ + ovs_be32 new_pkt_type; + ); }; /* Converting OpenFlow to ofpacts. */ @@ -1094,7 +1167,11 @@ /* Output. */ struct ofpbuf *ofpacts; enum ofputil_protocol *usable_protocols; + + /* Parse context. */ + unsigned int depth; }; +#define MAX_OFPACT_PARSE_DEPTH 100 char *ofpacts_parse_actions(const char *, const struct ofpact_parse_params *) OVS_WARN_UNUSED_RESULT; char *ofpacts_parse_instructions(const char *, @@ -1142,21 +1219,23 @@ * * Initializes the parts of 'ofpact' that identify it as having type * OFPACT_ and length OFPACT__SIZE and zeros the rest. - * - * _SIZE - * - * The size of the action structure. For a fixed-length action, this is - * sizeof(struct ) rounded up to a multiple of OFPACT_ALIGNTO. For - * a variable-length action, this is the offset to the variable-length - * part. */ #define OFPACT(ENUM, STRUCT, MEMBER, NAME) \ BUILD_ASSERT_DECL(offsetof(struct STRUCT, ofpact) == 0); \ \ - enum { OFPACT_##ENUM##_SIZE \ - = (offsetof(struct STRUCT, MEMBER) != 0 \ - ? offsetof(struct STRUCT, MEMBER) \ - : OFPACT_ALIGN(sizeof(struct STRUCT))) }; \ + /* Action structures must be a multiple of OFPACT_ALIGNTO bytes. */ \ + BUILD_ASSERT_DECL(sizeof(struct STRUCT) % OFPACT_ALIGNTO == 0); \ + \ + /* Variable-length data must start at a multiple of OFPACT_ALIGNTO \ + * bytes. */ \ + BUILD_ASSERT_DECL(offsetof(struct STRUCT, MEMBER) \ + % OFPACT_ALIGNTO == 0); \ + \ + /* If there is variable-length data, it starts at the end of the \ + * structure. */ \ + BUILD_ASSERT_DECL(!offsetof(struct STRUCT, MEMBER) \ + || (offsetof(struct STRUCT, MEMBER) \ + == sizeof(struct STRUCT))); \ \ static inline struct STRUCT * \ ofpact_get_##ENUM(const struct ofpact *ofpact) \ @@ -1176,14 +1255,14 @@ ofpact_put_##ENUM(struct ofpbuf *ofpacts) \ { \ return (struct STRUCT *) ofpact_put(ofpacts, OFPACT_##ENUM, \ - OFPACT_##ENUM##_SIZE); \ + sizeof(struct STRUCT)); \ } \ \ static inline void \ ofpact_init_##ENUM(struct STRUCT *ofpact) \ { \ ofpact_init(&ofpact->ofpact, OFPACT_##ENUM, \ - OFPACT_##ENUM##_SIZE); \ + sizeof(struct STRUCT)); \ } \ \ static inline void \ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/ofp-group.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/ofp-group.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/ofp-group.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/ofp-group.h 2020-03-11 16:15:44.000000000 +0000 @@ -103,7 +103,9 @@ void ofputil_uninit_group_mod(struct ofputil_group_mod *gm); struct ofpbuf *ofputil_encode_group_mod(enum ofp_version ofp_version, - const struct ofputil_group_mod *gm); + const struct ofputil_group_mod *gm, + const struct ovs_list *new_buckets, + int group_existed); enum ofperr ofputil_decode_group_mod(const struct ofp_header *, struct ofputil_group_mod *); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/ofp-monitor.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/ofp-monitor.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/openvswitch/ofp-monitor.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/openvswitch/ofp-monitor.h 2020-03-11 16:15:44.000000000 +0000 @@ -125,7 +125,20 @@ }; /* reason == OFPRFR_GROUP_MOD. */ - struct ofputil_group_mod *group_mod; + struct { + struct ofputil_group_mod *group_mod; + + /* If nonnull, points to the full set of new buckets that resulted + * from a OFPGC15_INSERT_BUCKET or OFPGC15_REMOVE_BUCKET command. + * Needed to translate such group_mods into OpenFlow 1.1-1.4 + * OFPGC11_MODIFY. */ + const struct ovs_list *new_buckets; + + /* If nonnegative, specifies whether the group existed before the + * command was executed. Needed to translate OVS's nonstandard + * OFPGC11_ADD_OR_MOD into a standard command. */ + int group_existed; + }; }; }; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/sparse/bits/floatn.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/sparse/bits/floatn.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/include/sparse/bits/floatn.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/include/sparse/bits/floatn.h 2020-03-11 16:15:44.000000000 +0000 @@ -27,6 +27,9 @@ #define __HAVE_FLOAT128 0 #define __HAVE_FLOAT64X 0 +#ifdef HAVE_BITS_FLOATN_COMMON_H +/* Introduced in glibc 2.27 */ #include +#endif #endif /* for sparse */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/bfd.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/bfd.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/bfd.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/bfd.c 2020-03-11 16:15:44.000000000 +0000 @@ -672,19 +672,18 @@ if (flow->dl_type == htons(ETH_TYPE_IP)) { memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); - if (flow->nw_proto == IPPROTO_UDP && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { - memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); - if (flow->tp_dst == htons(BFD_DEST_PORT)) { - bool check_tnl_key; + if (flow->nw_proto == IPPROTO_UDP + && !(flow->nw_frag & FLOW_NW_FRAG_LATER) + && tp_dst_equals(flow, BFD_DEST_PORT, wc)) { + bool check_tnl_key; - atomic_read_relaxed(&bfd->check_tnl_key, &check_tnl_key); - if (check_tnl_key) { - memset(&wc->masks.tunnel.tun_id, 0xff, - sizeof wc->masks.tunnel.tun_id); - return flow->tunnel.tun_id == htonll(0); - } - return true; + atomic_read_relaxed(&bfd->check_tnl_key, &check_tnl_key); + if (check_tnl_key) { + memset(&wc->masks.tunnel.tun_id, 0xff, + sizeof wc->masks.tunnel.tun_id); + return flow->tunnel.tun_id == htonll(0); } + return true; } } return false; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/cmap.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/cmap.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/cmap.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/cmap.c 2020-03-11 16:15:44.000000000 +0000 @@ -568,7 +568,7 @@ { struct cmap_impl *impl = cmap_get_impl(cmap); uint32_t h1 = rehash(impl, hash); - uint32_t h2 = other_hash(hash); + uint32_t h2 = other_hash(h1); struct cmap_node *node; node = cmap_find_bucket_protected(impl, hash, h1); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/conntrack.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/conntrack.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/conntrack.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/conntrack.c 2020-03-11 16:15:44.000000000 +0000 @@ -136,7 +136,7 @@ static int repl_ftp_v4_addr(struct dp_packet *pkt, ovs_be32 v4_addr_rep, char *ftp_data_v4_start, - size_t addr_offset_from_ftp_data_start); + size_t addr_offset_from_ftp_data_start, size_t addr_size); static enum ftp_ctl_pkt process_ftp_ctl_v4(struct conntrack *ct, @@ -144,7 +144,8 @@ const struct conn *conn_for_expectation, ovs_be32 *v4_addr_rep, char **ftp_data_v4_start, - size_t *addr_offset_from_ftp_data_start); + size_t *addr_offset_from_ftp_data_start, + size_t *addr_size); static enum ftp_ctl_pkt detect_ftp_ctl_type(const struct conn_lookup_ctx *ctx, @@ -352,7 +353,7 @@ struct conntrack_bucket *ctb = &ct->buckets[i]; struct conn *conn; - ovs_mutex_destroy(&ctb->cleanup_mutex); + ovs_mutex_lock(&ctb->cleanup_mutex); ct_lock_lock(&ctb->lock); HMAP_FOR_EACH_POP (conn, node, &ctb->connections) { if (conn->conn_type == CT_CONN_TYPE_DEFAULT) { @@ -362,7 +363,9 @@ } hmap_destroy(&ctb->connections); ct_lock_unlock(&ctb->lock); + ovs_mutex_unlock(&ctb->cleanup_mutex); ct_lock_destroy(&ctb->lock); + ovs_mutex_destroy(&ctb->cleanup_mutex); } ct_rwlock_wrlock(&ct->resources_lock); struct nat_conn_key_node *nat_conn_key_node; @@ -637,7 +640,7 @@ reverse_nat_packet(struct dp_packet *pkt, const struct conn *conn) { char *tail = dp_packet_tail(pkt); - char pad = dp_packet_l2_pad_size(pkt); + uint8_t pad = dp_packet_l2_pad_size(pkt); struct conn_key inner_key; const char *inner_l4 = NULL; uint16_t orig_l3_ofs = pkt->l3_ofs; @@ -647,6 +650,8 @@ struct ip_header *nh = dp_packet_l3(pkt); struct icmp_header *icmp = dp_packet_l4(pkt); struct ip_header *inner_l3 = (struct ip_header *) (icmp + 1); + /* This call is already verified to succeed during the code path from + * 'conn_key_extract()' which calls 'extract_l4_icmp()'. */ extract_l3_ipv4(&inner_key, inner_l3, tail - ((char *)inner_l3) - pad, &inner_l4, false); pkt->l3_ofs += (char *) inner_l3 - (char *) nh; @@ -668,6 +673,8 @@ struct icmp6_error_header *icmp6 = dp_packet_l4(pkt); struct ovs_16aligned_ip6_hdr *inner_l3_6 = (struct ovs_16aligned_ip6_hdr *) (icmp6 + 1); + /* This call is already verified to succeed during the code path from + * 'conn_key_extract()' which calls 'extract_l4_icmp6()'. */ extract_l3_ipv6(&inner_key, inner_l3_6, tail - ((char *)inner_l3_6) - pad, &inner_l4); @@ -686,10 +693,9 @@ true); } reverse_pat_packet(pkt, conn); - uint32_t icmp6_csum = packet_csum_pseudoheader6(nh6); icmp6->icmp6_base.icmp6_cksum = 0; - icmp6->icmp6_base.icmp6_cksum = csum_finish( - csum_continue(icmp6_csum, icmp6, tail - (char *) icmp6 - pad)); + icmp6->icmp6_base.icmp6_cksum = packet_csum_upperlayer6(nh6, icmp6, + IPPROTO_ICMPV6, tail - (char *) icmp6 - pad); } pkt->l3_ofs = orig_l3_ofs; pkt->l4_ofs = orig_l4_ofs; @@ -754,6 +760,43 @@ return ctx.conn; } +/* Only used when looking up 'CT_CONN_TYPE_DEFAULT' conns. */ +static struct conn * +conn_lookup_def(const struct conn_key *key, + const struct conntrack_bucket *ctb, uint32_t hash) + OVS_REQUIRES(ctb->lock) +{ + struct conn *conn = NULL; + + HMAP_FOR_EACH_WITH_HASH (conn, node, hash, &ctb->connections) { + if (!conn_key_cmp(&conn->key, key) + && conn->conn_type == CT_CONN_TYPE_DEFAULT) { + break; + } + if (!conn_key_cmp(&conn->rev_key, key) + && conn->conn_type == CT_CONN_TYPE_DEFAULT) { + break; + } + } + return conn; +} + +static struct conn * +conn_lookup_unnat(const struct conn_key *key, + const struct conntrack_bucket *ctb, uint32_t hash) + OVS_REQUIRES(ctb->lock) +{ + struct conn *conn = NULL; + + HMAP_FOR_EACH_WITH_HASH (conn, node, hash, &ctb->connections) { + if (!conn_key_cmp(&conn->key, key) + && conn->conn_type == CT_CONN_TYPE_UN_NAT) { + break; + } + } + return conn; +} + static void conn_seq_skew_set(struct conntrack *ct, const struct conn_key *key, long long now, int seq_skew, bool seq_skew_dir) @@ -777,12 +820,13 @@ nat_conn_keys_remove(&ct->nat_conn_keys, &conn->rev_key, ct->hash_basis); ct_rwlock_unlock(&ct->resources_lock); ct_lock_unlock(&ctb->lock); - unsigned bucket_rev_conn = - hash_to_bucket(conn_key_hash(&conn->rev_key, ct->hash_basis)); + uint32_t hash = conn_key_hash(&conn->rev_key, ct->hash_basis); + unsigned bucket_rev_conn = hash_to_bucket(hash); ct_lock_lock(&ct->buckets[bucket_rev_conn].lock); ct_rwlock_wrlock(&ct->resources_lock); - long long now = time_msec(); - struct conn *rev_conn = conn_lookup(ct, &conn->rev_key, now); + struct conn *rev_conn = conn_lookup_unnat(&conn->rev_key, + &ct->buckets[bucket_rev_conn], + hash); struct nat_conn_key_node *nat_conn_key_node = nat_conn_keys_lookup(&ct->nat_conn_keys, &conn->rev_key, ct->hash_basis); @@ -821,6 +865,22 @@ } } +/* Only called for 'CT_CONN_TYPE_DEFAULT' conns; must be called with no + * locks held and upon return no locks are held. */ +static void +conn_clean_safe(struct conntrack *ct, struct conn *conn, + struct conntrack_bucket *ctb, uint32_t hash) +{ + ovs_mutex_lock(&ctb->cleanup_mutex); + ct_lock_lock(&ctb->lock); + conn = conn_lookup_def(&conn->key, ctb, hash); + if (conn) { + conn_clean(ct, conn, ctb); + } + ct_lock_unlock(&ctb->lock); + ovs_mutex_unlock(&ctb->cleanup_mutex); +} + static bool ct_verify_helper(const char *helper, enum ct_alg_ctl_type ct_alg_ctl) { @@ -852,6 +912,7 @@ enum ct_alg_ctl_type ct_alg_ctl) { struct conn *nc = NULL; + struct conn connl; if (!valid_new(pkt, &ctx->key)) { pkt->md.ct_state = CS_INVALID; @@ -874,9 +935,10 @@ } unsigned bucket = hash_to_bucket(ctx->hash); - nc = new_conn(&ct->buckets[bucket], pkt, &ctx->key, now); - ctx->conn = nc; - nc->rev_key = nc->key; + nc = &connl; + memset(nc, 0, sizeof *nc); + memcpy(&nc->key, &ctx->key, sizeof nc->key); + memcpy(&nc->rev_key, &nc->key, sizeof nc->rev_key); conn_key_reverse(&nc->rev_key); if (ct_verify_helper(helper, ct_alg_ctl)) { @@ -919,6 +981,7 @@ ct_rwlock_wrlock(&ct->resources_lock); bool nat_res = nat_select_range_tuple(ct, nc, conn_for_un_nat_copy); + ct_rwlock_unlock(&ct->resources_lock); if (!nat_res) { goto nat_res_exhaustion; @@ -926,15 +989,25 @@ /* Update nc with nat adjustments made to * conn_for_un_nat_copy by nat_select_range_tuple(). */ - *nc = *conn_for_un_nat_copy; - ct_rwlock_unlock(&ct->resources_lock); + memcpy(nc, conn_for_un_nat_copy, sizeof *nc); } conn_for_un_nat_copy->conn_type = CT_CONN_TYPE_UN_NAT; conn_for_un_nat_copy->nat_info = NULL; conn_for_un_nat_copy->alg = NULL; nat_packet(pkt, nc, ctx->icmp_related); } - hmap_insert(&ct->buckets[bucket].connections, &nc->node, ctx->hash); + struct conn *nconn = new_conn(&ct->buckets[bucket], pkt, &ctx->key, + now); + memcpy(&nconn->key, &nc->key, sizeof nconn->key); + memcpy(&nconn->rev_key, &nc->rev_key, sizeof nconn->rev_key); + memcpy(&nconn->master_key, &nc->master_key, sizeof nconn->master_key); + nconn->alg_related = nc->alg_related; + nconn->alg = nc->alg; + nconn->mark = nc->mark; + nconn->label = nc->label; + nconn->nat_info = nc->nat_info; + ctx->conn = nc = nconn; + hmap_insert(&ct->buckets[bucket].connections, &nconn->node, ctx->hash); atomic_count_inc(&ct->n_conn); } @@ -947,13 +1020,8 @@ * against with firewall rules or a separate firewall. * Also using zone partitioning can limit DoS impact. */ nat_res_exhaustion: - ovs_list_remove(&nc->exp_node); - delete_conn(nc); - /* conn_for_un_nat_copy is a local variable in process_one; this - * memset() serves to document that conn_for_un_nat_copy is from - * this point on unused. */ - memset(conn_for_un_nat_copy, 0, sizeof *conn_for_un_nat_copy); - ct_rwlock_unlock(&ct->resources_lock); + free(nc->alg); + free(nc->nat_info); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); VLOG_WARN_RL(&rl, "Unable to NAT due to tuple space exhaustion - " "if DoS attack, use firewalling and/or zone partitioning."); @@ -967,6 +1035,7 @@ OVS_REQUIRES(ct->buckets[bucket].lock) { bool create_new_conn = false; + struct conn lconn; if (ctx->icmp_related) { pkt->md.ct_state |= CS_RELATED; @@ -993,7 +1062,10 @@ pkt->md.ct_state = CS_INVALID; break; case CT_UPDATE_NEW: - conn_clean(ct, *conn, &ct->buckets[bucket]); + memcpy(&lconn, *conn, sizeof lconn); + ct_lock_unlock(&ct->buckets[bucket].lock); + conn_clean_safe(ct, &lconn, &ct->buckets[bucket], ctx->hash); + ct_lock_lock(&ct->buckets[bucket].lock); create_new_conn = true; break; default: @@ -1008,8 +1080,8 @@ long long now, bool alg_un_nat) { struct conn *nc = xmemdup(conn_for_un_nat_copy, sizeof *nc); - nc->key = conn_for_un_nat_copy->rev_key; - nc->rev_key = conn_for_un_nat_copy->key; + memcpy(&nc->key, &conn_for_un_nat_copy->rev_key, sizeof nc->key); + memcpy(&nc->rev_key, &conn_for_un_nat_copy->key, sizeof nc->rev_key); uint32_t un_nat_hash = conn_key_hash(&nc->key, ct->hash_basis); unsigned un_nat_conn_bucket = hash_to_bucket(un_nat_hash); ct_lock_lock(&ct->buckets[un_nat_conn_bucket].lock); @@ -1182,8 +1254,12 @@ conn = ctx->conn; /* Delete found entry if in wrong direction. 'force' implies commit. */ - if (conn && force && ctx->reply) { - conn_clean(ct, conn, &ct->buckets[bucket]); + if (OVS_UNLIKELY(force && ctx->reply && conn)) { + struct conn lconn; + memcpy(&lconn, conn, sizeof lconn); + ct_lock_unlock(&ct->buckets[bucket].lock); + conn_clean_safe(ct, &lconn, &ct->buckets[bucket], ctx->hash); + ct_lock_lock(&ct->buckets[bucket].lock); conn = NULL; } @@ -1194,7 +1270,7 @@ struct conn_lookup_ctx ctx2; ctx2.conn = NULL; - ctx2.key = conn->rev_key; + memcpy(&ctx2.key, &conn->rev_key, sizeof ctx2.key); ctx2.hash = conn_key_hash(&conn->rev_key, ct->hash_basis); ct_lock_unlock(&ct->buckets[bucket].lock); @@ -1280,7 +1356,7 @@ struct conn conn_for_expectation; if (OVS_UNLIKELY((ct_alg_ctl != CT_ALG_CTL_NONE) && conn)) { - conn_for_expectation = *conn; + memcpy(&conn_for_expectation, conn, sizeof conn_for_expectation); } ct_lock_unlock(&ct->buckets[bucket].lock); @@ -1383,19 +1459,17 @@ for (unsigned i = 0; i < N_CT_TM; i++) { LIST_FOR_EACH_SAFE (conn, next, exp_node, &ctb->exp_lists[i]) { - if (conn->conn_type == CT_CONN_TYPE_DEFAULT) { - if (!conn_expired(conn, now) || count >= limit) { - min_expiration = MIN(min_expiration, conn->expiration); - if (count >= limit) { - /* Do not check other lists. */ - COVERAGE_INC(conntrack_long_cleanup); - return min_expiration; - } - break; + if (!conn_expired(conn, now) || count >= limit) { + min_expiration = MIN(min_expiration, conn->expiration); + if (count >= limit) { + /* Do not check other lists. */ + COVERAGE_INC(conntrack_long_cleanup); + return min_expiration; } - conn_clean(ct, conn, ctb); - count++; + break; } + conn_clean(ct, conn, ctb); + count++; } } return min_expiration; @@ -1413,6 +1487,8 @@ size_t clean_count = 0; atomic_read_relaxed(&ct->n_conn_limit, &n_conn_limit); + size_t clean_min = n_conn_limit > CONNTRACK_BUCKETS * 10 + ? n_conn_limit / (CONNTRACK_BUCKETS * 10) : 1; for (unsigned i = 0; i < CONNTRACK_BUCKETS; i++) { struct conntrack_bucket *ctb = &ct->buckets[i]; @@ -1430,8 +1506,7 @@ * limit to 10% of the global limit equally split among buckets. If * the bucket is busier than the others, we limit to 10% of its * current size. */ - min_exp = sweep_bucket(ct, ctb, now, - MAX(prev_count/10, n_conn_limit/(CONNTRACK_BUCKETS*10))); + min_exp = sweep_bucket(ct, ctb, now, MAX(prev_count / 10, clean_min)); clean_count += prev_count - hmap_count(&ctb->connections); if (min_exp > now) { @@ -1581,19 +1656,14 @@ checksum_valid(const struct conn_key *key, const void *data, size_t size, const void *l3) { - uint32_t csum = 0; - if (key->dl_type == htons(ETH_TYPE_IP)) { - csum = packet_csum_pseudoheader(l3); + uint32_t csum = packet_csum_pseudoheader(l3); + return csum_finish(csum_continue(csum, data, size)) == 0; } else if (key->dl_type == htons(ETH_TYPE_IPV6)) { - csum = packet_csum_pseudoheader6(l3); + return packet_csum_upperlayer6(l3, data, key->nw_proto, size) == 0; } else { return false; } - - csum = csum_continue(csum, data, size); - - return csum_finish(csum) == 0; } static inline bool @@ -1646,9 +1716,10 @@ } static inline bool -extract_l4_tcp(struct conn_key *key, const void *data, size_t size) +extract_l4_tcp(struct conn_key *key, const void *data, size_t size, + size_t *chk_len) { - if (OVS_UNLIKELY(size < TCP_HEADER_LEN)) { + if (OVS_UNLIKELY(size < (chk_len ? *chk_len : TCP_HEADER_LEN))) { return false; } @@ -1661,9 +1732,10 @@ } static inline bool -extract_l4_udp(struct conn_key *key, const void *data, size_t size) +extract_l4_udp(struct conn_key *key, const void *data, size_t size, + size_t *chk_len) { - if (OVS_UNLIKELY(size < UDP_HEADER_LEN)) { + if (OVS_UNLIKELY(size < (chk_len ? *chk_len : UDP_HEADER_LEN))) { return false; } @@ -1677,7 +1749,7 @@ static inline bool extract_l4(struct conn_key *key, const void *data, size_t size, bool *related, const void *l3, - bool validate_checksum); + bool validate_checksum, size_t *chk_len); static uint8_t reverse_icmp_type(uint8_t type) @@ -1709,9 +1781,9 @@ * possible */ static inline int extract_l4_icmp(struct conn_key *key, const void *data, size_t size, - bool *related) + bool *related, size_t *chk_len) { - if (OVS_UNLIKELY(size < ICMP_HEADER_LEN)) { + if (OVS_UNLIKELY(size < (chk_len ? *chk_len : ICMP_HEADER_LEN))) { return false; } @@ -1762,8 +1834,9 @@ key->src = inner_key.src; key->dst = inner_key.dst; key->nw_proto = inner_key.nw_proto; + size_t check_len = ICMP_ERROR_DATA_L4_LEN; - ok = extract_l4(key, l4, tail - l4, NULL, l3, false); + ok = extract_l4(key, l4, tail - l4, NULL, l3, false, &check_len); if (ok) { conn_key_reverse(key); *related = true; @@ -1850,7 +1923,7 @@ key->dst = inner_key.dst; key->nw_proto = inner_key.nw_proto; - ok = extract_l4(key, l4, tail - l4, NULL, l3, false); + ok = extract_l4(key, l4, tail - l4, NULL, l3, false, NULL); if (ok) { conn_key_reverse(key); *related = true; @@ -1871,27 +1944,33 @@ * processed, the function will extract the key from the packet nested * in the ICMP payload and set '*related' to true. * + * 'size' here is the layer 4 size, which can be a nested size if parsing + * an ICMP or ICMP6 header. + * * If 'related' is NULL, it means that we're already parsing a header nested - * in an ICMP error. In this case, we skip checksum and length validation. */ + * in an ICMP error. In this case, we skip the checksum and some length + * validations. */ static inline bool extract_l4(struct conn_key *key, const void *data, size_t size, bool *related, - const void *l3, bool validate_checksum) + const void *l3, bool validate_checksum, size_t *chk_len) { if (key->nw_proto == IPPROTO_TCP) { return (!related || check_l4_tcp(key, data, size, l3, - validate_checksum)) && extract_l4_tcp(key, data, size); + validate_checksum)) + && extract_l4_tcp(key, data, size, chk_len); } else if (key->nw_proto == IPPROTO_UDP) { return (!related || check_l4_udp(key, data, size, l3, - validate_checksum)) && extract_l4_udp(key, data, size); + validate_checksum)) + && extract_l4_udp(key, data, size, chk_len); } else if (key->dl_type == htons(ETH_TYPE_IP) && key->nw_proto == IPPROTO_ICMP) { return (!related || check_l4_icmp(data, size, validate_checksum)) - && extract_l4_icmp(key, data, size, related); + && extract_l4_icmp(key, data, size, related, chk_len); } else if (key->dl_type == htons(ETH_TYPE_IPV6) && key->nw_proto == IPPROTO_ICMPV6) { return (!related || check_l4_icmp6(key, data, size, l3, - validate_checksum)) && extract_l4_icmp6(key, data, size, - related); + validate_checksum)) + && extract_l4_icmp6(key, data, size, related); } else { return false; } @@ -1945,7 +2024,6 @@ * we use a sparse representation (miniflow). * */ - const char *tail = dp_packet_tail(pkt); bool ok; ctx->key.dl_type = dl_type; @@ -1956,11 +2034,11 @@ } else { bool hwol_good_l3_csum = dp_packet_ip_checksum_valid(pkt); /* Validate the checksum only when hwol is not supported. */ - ok = extract_l3_ipv4(&ctx->key, l3, tail - (char *) l3, NULL, + ok = extract_l3_ipv4(&ctx->key, l3, dp_packet_l3_size(pkt), NULL, !hwol_good_l3_csum); } } else if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { - ok = extract_l3_ipv6(&ctx->key, l3, tail - (char *) l3, NULL); + ok = extract_l3_ipv6(&ctx->key, l3, dp_packet_l3_size(pkt), NULL); } else { ok = false; } @@ -1970,8 +2048,9 @@ if (!hwol_bad_l4_csum) { bool hwol_good_l4_csum = dp_packet_l4_checksum_valid(pkt); /* Validate the checksum only when hwol is not supported. */ - if (extract_l4(&ctx->key, l4, tail - l4, &ctx->icmp_related, l3, - !hwol_good_l4_csum)) { + if (extract_l4(&ctx->key, l4, dp_packet_l4_size(pkt), + &ctx->icmp_related, l3, !hwol_good_l4_csum, + NULL)) { ctx->hash = conn_key_hash(&ctx->key, ct->hash_basis); return true; } @@ -2172,7 +2251,9 @@ uint16_t port = first_port; bool all_ports_tried = false; - bool original_ports_tried = false; + /* For DNAT, we don't use ephemeral ports. */ + bool ephemeral_ports_tried = conn->nat_info->nat_action & NAT_ACTION_DST + ? true : false; struct ct_addr first_addr = ct_addr; while (true) { @@ -2218,9 +2299,10 @@ ct_addr = conn->nat_info->min_addr; } if (!memcmp(&ct_addr, &first_addr, sizeof ct_addr)) { - if (!original_ports_tried) { - original_ports_tried = true; + if (!ephemeral_ports_tried) { + ephemeral_ports_tried = true; ct_addr = conn->nat_info->min_addr; + first_addr = ct_addr; min_port = MIN_NAT_EPHEMERAL_PORT; max_port = MAX_NAT_EPHEMERAL_PORT; } else { @@ -2262,8 +2344,10 @@ if (!nat_conn_key_node) { struct nat_conn_key_node *nat_conn_key = xzalloc(sizeof *nat_conn_key); - nat_conn_key->key = nat_conn->rev_key; - nat_conn_key->value = nat_conn->key; + memcpy(&nat_conn_key->key, &nat_conn->rev_key, + sizeof nat_conn_key->key); + memcpy(&nat_conn_key->value, &nat_conn->key, + sizeof nat_conn_key->value); hmap_insert(nat_conn_keys, &nat_conn_key->node, conn_key_hash(&nat_conn_key->key, basis)); return true; @@ -2342,12 +2426,7 @@ new_conn(struct conntrack_bucket *ctb, struct dp_packet *pkt, struct conn_key *key, long long now) { - struct conn *newconn = l4_protos[key->nw_proto]->new_conn(ctb, pkt, now); - if (newconn) { - newconn->key = *key; - } - - return newconn; + return l4_protos[key->nw_proto]->new_conn(ctb, pkt, now); } static void @@ -2540,16 +2619,19 @@ conntrack_flush(struct conntrack *ct, const uint16_t *zone) { for (unsigned i = 0; i < CONNTRACK_BUCKETS; i++) { - struct conn *conn, *next; - - ct_lock_lock(&ct->buckets[i].lock); - HMAP_FOR_EACH_SAFE (conn, next, node, &ct->buckets[i].connections) { - if ((!zone || *zone == conn->key.zone) && - (conn->conn_type == CT_CONN_TYPE_DEFAULT)) { - conn_clean(ct, conn, &ct->buckets[i]); + struct conntrack_bucket *ctb = &ct->buckets[i]; + ovs_mutex_lock(&ctb->cleanup_mutex); + ct_lock_lock(&ctb->lock); + for (unsigned j = 0; j < N_CT_TM; j++) { + struct conn *conn, *next; + LIST_FOR_EACH_SAFE (conn, next, exp_node, &ctb->exp_lists[j]) { + if (!zone || *zone == conn->key.zone) { + conn_clean(ct, conn, ctb); + } } } - ct_lock_unlock(&ct->buckets[i].lock); + ct_lock_unlock(&ctb->lock); + ovs_mutex_unlock(&ctb->cleanup_mutex); } return 0; @@ -2566,15 +2648,19 @@ tuple_to_conn_key(tuple, zone, &ctx.key); ctx.hash = conn_key_hash(&ctx.key, ct->hash_basis); unsigned bucket = hash_to_bucket(ctx.hash); + struct conntrack_bucket *ctb = &ct->buckets[bucket]; - ct_lock_lock(&ct->buckets[bucket].lock); - conn_key_lookup(&ct->buckets[bucket], &ctx, time_msec()); - if (ctx.conn) { - conn_clean(ct, ctx.conn, &ct->buckets[bucket]); + ovs_mutex_lock(&ctb->cleanup_mutex); + ct_lock_lock(&ctb->lock); + conn_key_lookup(ctb, &ctx, time_msec()); + if (ctx.conn && ctx.conn->conn_type == CT_CONN_TYPE_DEFAULT) { + conn_clean(ct, ctx.conn, ctb); } else { + VLOG_WARN("Must flush tuple using the original pre-NATed tuple"); error = ENOENT; } - ct_lock_unlock(&ct->buckets[bucket].lock); + ct_lock_unlock(&ctb->lock); + ovs_mutex_unlock(&ctb->cleanup_mutex); return error; } @@ -2706,21 +2792,29 @@ if (reply) { src_addr = master_conn->key.src.addr; dst_addr = master_conn->key.dst.addr; + alg_exp_node->nat_rpl_dst = true; if (skip_nat) { alg_nat_repl_addr = dst_addr; + } else if (master_conn->nat_info && + master_conn->nat_info->nat_action & NAT_ACTION_DST) { + alg_nat_repl_addr = master_conn->rev_key.src.addr; + alg_exp_node->nat_rpl_dst = false; } else { alg_nat_repl_addr = master_conn->rev_key.dst.addr; } - alg_exp_node->nat_rpl_dst = true; } else { src_addr = master_conn->rev_key.src.addr; dst_addr = master_conn->rev_key.dst.addr; + alg_exp_node->nat_rpl_dst = false; if (skip_nat) { alg_nat_repl_addr = src_addr; + } else if (master_conn->nat_info && + master_conn->nat_info->nat_action & NAT_ACTION_DST) { + alg_nat_repl_addr = master_conn->key.dst.addr; + alg_exp_node->nat_rpl_dst = true; } else { alg_nat_repl_addr = master_conn->key.src.addr; } - alg_exp_node->nat_rpl_dst = false; } if (src_ip_wc) { memset(&src_addr, 0, sizeof src_addr); @@ -2735,7 +2829,8 @@ alg_exp_node->key.dst.port = dst_port; alg_exp_node->master_mark = master_conn->mark; alg_exp_node->master_label = master_conn->label; - alg_exp_node->master_key = master_conn->key; + memcpy(&alg_exp_node->master_key, &master_conn->key, + sizeof alg_exp_node->master_key); /* Take the write lock here because it is almost 100% * likely that the lookup will fail and * expectation_create() will be called below. */ @@ -2756,13 +2851,6 @@ ct_rwlock_unlock(&ct->resources_lock); } -static uint8_t -get_v4_byte_be(ovs_be32 v4_addr, uint8_t index) -{ - uint8_t *byte_ptr = (OVS_FORCE uint8_t *) &v4_addr; - return byte_ptr[index]; -} - static void replace_substring(char *substr, uint8_t substr_size, uint8_t total_size, char *rep_str, @@ -2773,51 +2861,56 @@ memcpy(substr, rep_str, rep_str_size); } +static void +repl_bytes(char *str, char c1, char c2) +{ + while (*str) { + if (*str == c1) { + *str = c2; + } + str++; + } +} + +static void +modify_packet(struct dp_packet *pkt, char *pkt_str, size_t size, + char *repl_str, size_t repl_size, + uint32_t orig_used_size) +{ + replace_substring(pkt_str, size, + (const char *) dp_packet_tail(pkt) - pkt_str, + repl_str, repl_size); + dp_packet_set_size(pkt, orig_used_size + (int) repl_size - (int) size); +} + /* Replace IPV4 address in FTP message with NATed address. */ static int repl_ftp_v4_addr(struct dp_packet *pkt, ovs_be32 v4_addr_rep, char *ftp_data_start, - size_t addr_offset_from_ftp_data_start) + size_t addr_offset_from_ftp_data_start, + size_t addr_size OVS_UNUSED) { enum { MAX_FTP_V4_NAT_DELTA = 8 }; /* Do conservative check for pathological MTU usage. */ uint32_t orig_used_size = dp_packet_size(pkt); - uint16_t allocated_size = dp_packet_get_allocated(pkt); - if (orig_used_size + MAX_FTP_V4_NAT_DELTA > allocated_size) { + if (orig_used_size + MAX_FTP_V4_NAT_DELTA > + dp_packet_get_allocated(pkt)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); - VLOG_WARN_RL(&rl, "Unsupported effective MTU %u used with FTP", - allocated_size); + VLOG_WARN_RL(&rl, "Unsupported effective MTU %u used with FTP V4", + dp_packet_get_allocated(pkt)); return 0; } - size_t remain_size = tcp_payload_length(pkt) - - addr_offset_from_ftp_data_start; - int overall_delta = 0; - char *byte_str = ftp_data_start + addr_offset_from_ftp_data_start; - - /* Replace the existing IPv4 address by the new one. */ - for (uint8_t i = 0; i < 4; i++) { - /* Find the end of the string for this octet. */ - char *next_delim = memchr(byte_str, ',', 4); - ovs_assert(next_delim); - int substr_size = next_delim - byte_str; - remain_size -= substr_size; - - /* Compose the new string for this octet, and replace it. */ - char rep_str[4]; - uint8_t rep_byte = get_v4_byte_be(v4_addr_rep, i); - int replace_size = sprintf(rep_str, "%d", rep_byte); - replace_substring(byte_str, substr_size, remain_size, - rep_str, replace_size); - overall_delta += replace_size - substr_size; - - /* Advance past the octet and the following comma. */ - byte_str += replace_size + 1; - } - - dp_packet_set_size(pkt, orig_used_size + overall_delta); - return overall_delta; + char v4_addr_str[INET_ADDRSTRLEN] = {0}; + ovs_assert(inet_ntop(AF_INET, &v4_addr_rep, v4_addr_str, + sizeof v4_addr_str)); + repl_bytes(v4_addr_str, '.', ','); + modify_packet(pkt, ftp_data_start + addr_offset_from_ftp_data_start, + addr_size, v4_addr_str, strlen(v4_addr_str), + orig_used_size); + return (int) strlen(v4_addr_str) - (int) addr_size; } static char * @@ -2886,7 +2979,8 @@ const struct conn *conn_for_expectation, ovs_be32 *v4_addr_rep, char **ftp_data_v4_start, - size_t *addr_offset_from_ftp_data_start) + size_t *addr_offset_from_ftp_data_start, + size_t *addr_size) { struct tcp_header *th = dp_packet_l4(pkt); size_t tcp_hdr_len = TCP_OFFSET(th->tcp_ctl) * 4; @@ -2942,6 +3036,7 @@ return CT_FTP_CTL_INVALID; } + *addr_size = ftp - ip_addr_start - 1; char *save_ftp = ftp; ftp = terminate_number_str(ftp, MAX_FTP_PORT_DGTS); if (!ftp) { @@ -3134,72 +3229,63 @@ /* Do conservative check for pathological MTU usage. */ uint32_t orig_used_size = dp_packet_size(pkt); - uint16_t allocated_size = dp_packet_get_allocated(pkt); - if (orig_used_size + MAX_FTP_V6_NAT_DELTA > allocated_size) { + if (orig_used_size + MAX_FTP_V6_NAT_DELTA > + dp_packet_get_allocated(pkt)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); - VLOG_WARN_RL(&rl, "Unsupported effective MTU %u used with FTP", - allocated_size); + VLOG_WARN_RL(&rl, "Unsupported effective MTU %u used with FTP V6", + dp_packet_get_allocated(pkt)); return 0; } - char v6_addr_str[IPV6_SCAN_LEN] = {0}; + char v6_addr_str[INET6_ADDRSTRLEN] = {0}; ovs_assert(inet_ntop(AF_INET6, &v6_addr_rep.ipv6_aligned, v6_addr_str, - IPV6_SCAN_LEN - 1)); - - size_t replace_addr_size = strlen(v6_addr_str); - - size_t remain_size = tcp_payload_length(pkt) - - addr_offset_from_ftp_data_start; - - char *pkt_addr_str = ftp_data_start + addr_offset_from_ftp_data_start; - replace_substring(pkt_addr_str, addr_size, remain_size, - v6_addr_str, replace_addr_size); - - int overall_delta = (int) replace_addr_size - (int) addr_size; + sizeof v6_addr_str)); + modify_packet(pkt, ftp_data_start + addr_offset_from_ftp_data_start, + addr_size, v6_addr_str, strlen(v6_addr_str), + orig_used_size); + return (int) strlen(v6_addr_str) - (int) addr_size; +} - dp_packet_set_size(pkt, orig_used_size + overall_delta); - return overall_delta; +/* Increment/decrement a TCP sequence number. */ +static void +adj_seqnum(ovs_16aligned_be32 *val, int32_t inc) +{ + put_16aligned_be32(val, htonl(ntohl(get_16aligned_be32(val)) + inc)); } static void handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx, - struct dp_packet *pkt, - const struct conn *conn_for_expectation, - long long now, enum ftp_ctl_pkt ftp_ctl, bool nat) + struct dp_packet *pkt, const struct conn *ec, long long now, + enum ftp_ctl_pkt ftp_ctl, bool nat) { struct ip_header *l3_hdr = dp_packet_l3(pkt); ovs_be32 v4_addr_rep = 0; struct ct_addr v6_addr_rep; - size_t addr_offset_from_ftp_data_start; + size_t addr_offset_from_ftp_data_start = 0; size_t addr_size = 0; char *ftp_data_start; - bool do_seq_skew_adj = true; enum ct_alg_mode mode = CT_FTP_MODE_ACTIVE; if (detect_ftp_ctl_type(ctx, pkt) != ftp_ctl) { return; } - if (!nat || !conn_for_expectation->seq_skew) { - do_seq_skew_adj = false; - } - struct ovs_16aligned_ip6_hdr *nh6 = dp_packet_l3(pkt); int64_t seq_skew = 0; - if (ftp_ctl == CT_FTP_CTL_OTHER) { - seq_skew = conn_for_expectation->seq_skew; - } else if (ftp_ctl == CT_FTP_CTL_INTEREST) { + if (ftp_ctl == CT_FTP_CTL_INTEREST) { enum ftp_ctl_pkt rc; if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { - rc = process_ftp_ctl_v6(ct, pkt, conn_for_expectation, + rc = process_ftp_ctl_v6(ct, pkt, ec, &v6_addr_rep, &ftp_data_start, &addr_offset_from_ftp_data_start, &addr_size, &mode); } else { - rc = process_ftp_ctl_v4(ct, pkt, conn_for_expectation, + rc = process_ftp_ctl_v4(ct, pkt, ec, &v4_addr_rep, &ftp_data_start, - &addr_offset_from_ftp_data_start); + &addr_offset_from_ftp_data_start, + &addr_size); } if (rc == CT_FTP_CTL_INVALID) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); @@ -3210,79 +3296,59 @@ uint16_t ip_len; if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { - seq_skew = repl_ftp_v6_addr(pkt, v6_addr_rep, ftp_data_start, - addr_offset_from_ftp_data_start, - addr_size, mode); + if (nat) { + seq_skew = repl_ftp_v6_addr(pkt, v6_addr_rep, + ftp_data_start, + addr_offset_from_ftp_data_start, + addr_size, mode); + } + if (seq_skew) { - ip_len = ntohs(nh6->ip6_ctlun.ip6_un1.ip6_un1_plen); - ip_len += seq_skew; + ip_len = ntohs(nh6->ip6_ctlun.ip6_un1.ip6_un1_plen) + + seq_skew; nh6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ip_len); - conn_seq_skew_set(ct, &conn_for_expectation->key, now, - seq_skew, ctx->reply); } } else { - seq_skew = repl_ftp_v4_addr(pkt, v4_addr_rep, ftp_data_start, - addr_offset_from_ftp_data_start); - ip_len = ntohs(l3_hdr->ip_tot_len); + if (nat) { + seq_skew = repl_ftp_v4_addr(pkt, v4_addr_rep, + ftp_data_start, + addr_offset_from_ftp_data_start, + addr_size); + } if (seq_skew) { - ip_len += seq_skew; + ip_len = ntohs(l3_hdr->ip_tot_len) + seq_skew; l3_hdr->ip_csum = recalc_csum16(l3_hdr->ip_csum, l3_hdr->ip_tot_len, htons(ip_len)); l3_hdr->ip_tot_len = htons(ip_len); - conn_seq_skew_set(ct, &conn_for_expectation->key, now, - seq_skew, ctx->reply); } } } else { OVS_NOT_REACHED(); } - } else { - OVS_NOT_REACHED(); } struct tcp_header *th = dp_packet_l4(pkt); - if (do_seq_skew_adj && seq_skew != 0) { - if (ctx->reply != conn_for_expectation->seq_skew_dir) { - - uint32_t tcp_ack = ntohl(get_16aligned_be32(&th->tcp_ack)); - - if ((seq_skew > 0) && (tcp_ack < seq_skew)) { - /* Should not be possible; will be marked invalid. */ - tcp_ack = 0; - } else if ((seq_skew < 0) && (UINT32_MAX - tcp_ack < -seq_skew)) { - tcp_ack = (-seq_skew) - (UINT32_MAX - tcp_ack); - } else { - tcp_ack -= seq_skew; - } - ovs_be32 new_tcp_ack = htonl(tcp_ack); - put_16aligned_be32(&th->tcp_ack, new_tcp_ack); - } else { - uint32_t tcp_seq = ntohl(get_16aligned_be32(&th->tcp_seq)); - if ((seq_skew > 0) && (UINT32_MAX - tcp_seq < seq_skew)) { - tcp_seq = seq_skew - (UINT32_MAX - tcp_seq); - } else if ((seq_skew < 0) && (tcp_seq < -seq_skew)) { - /* Should not be possible; will be marked invalid. */ - tcp_seq = 0; - } else { - tcp_seq += seq_skew; - } - ovs_be32 new_tcp_seq = htonl(tcp_seq); - put_16aligned_be32(&th->tcp_seq, new_tcp_seq); - } + if (nat && ec->seq_skew != 0) { + ctx->reply != ec->seq_skew_dir ? + adj_seqnum(&th->tcp_ack, -ec->seq_skew) : + adj_seqnum(&th->tcp_seq, ec->seq_skew); } th->tcp_csum = 0; - uint32_t tcp_csum; if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { - tcp_csum = packet_csum_pseudoheader6(nh6); + th->tcp_csum = packet_csum_upperlayer6(nh6, th, ctx->key.nw_proto, + dp_packet_l4_size(pkt)); } else { - tcp_csum = packet_csum_pseudoheader(l3_hdr); + uint32_t tcp_csum = packet_csum_pseudoheader(l3_hdr); + th->tcp_csum = csum_finish( + csum_continue(tcp_csum, th, dp_packet_l4_size(pkt))); + } + + if (seq_skew) { + conn_seq_skew_set(ct, &ec->key, now, seq_skew + ec->seq_skew, + ctx->reply); } - const char *tail = dp_packet_tail(pkt); - uint8_t pad = dp_packet_l2_pad_size(pkt); - th->tcp_csum = csum_finish( - csum_continue(tcp_csum, th, tail - (char *) th - pad)); } static void diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/daemon.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/daemon.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/daemon.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/daemon.h 2020-03-11 16:15:44.000000000 +0000 @@ -121,6 +121,7 @@ #define DAEMON_OPTION_HANDLERS \ case OPT_DETACH: \ + set_detach(); \ break; \ \ case OPT_NO_SELF_CONFINEMENT: \ @@ -139,6 +140,7 @@ break; \ \ case OPT_SERVICE: \ + set_detach(); \ break; \ \ case OPT_SERVICE_MONITOR: \ @@ -159,6 +161,7 @@ void control_handler(DWORD request); void set_pipe_handle(const char *pipe_handle); +void set_detach(void); #endif /* _WIN32 */ bool get_detach(void); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/daemon-unix.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/daemon-unix.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/daemon-unix.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/daemon-unix.c 2020-03-11 16:15:44.000000000 +0000 @@ -428,7 +428,7 @@ /* Running in new daemon process. */ ovs_cmdl_proctitle_restore(); - set_subprogram_name(""); + set_subprogram_name(program_name); } /* If daemonization is configured, then starts daemonization, by forking and diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/daemon-windows.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/daemon-windows.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/daemon-windows.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/daemon-windows.c 2020-03-11 16:15:44.000000000 +0000 @@ -82,6 +82,14 @@ "unexpected failure. \n"); } +/* Sets up a following call to service_start() to detach from the foreground + * session, running this process in the background. */ +void +set_detach(void) +{ + detach = true; +} + /* Registers the call-back and configures the actions in case of a failure * with the Windows services manager. */ void @@ -357,7 +365,7 @@ /* We are only interested in the '--detach' and '--pipe-handle'. */ for (i = 0; i < argc; i ++) { - if (!strcmp(argv[i], "--detach")) { + if (!detach && !strcmp(argv[i], "--detach")) { detach = true; } else if (!strncmp(argv[i], "--pipe-handle", 13)) { /* If running as a child, return. */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpctl.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpctl.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpctl.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpctl.c 2020-03-11 16:15:44.000000000 +0000 @@ -51,8 +51,6 @@ #include "util.h" #include "openvswitch/ofp-flow.h" #include "openvswitch/ofp-port.h" -#include "openvswitch/vlog.h" -VLOG_DEFINE_THIS_MODULE(dpctl); typedef int dpctl_command_handler(int argc, const char *argv[], struct dpctl_params *); @@ -2304,8 +2302,6 @@ if (!set_names) { dpctl_p.names = dpctl_p.verbosity > 0; } - VLOG_INFO("set_names=%d verbosity=%d names=%d", set_names, - dpctl_p.verbosity, dpctl_p.names); if (!error) { dpctl_command_handler *handler = (dpctl_command_handler *) aux; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpctl.man openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpctl.man --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpctl.man 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpctl.man 2020-03-11 16:15:44.000000000 +0000 @@ -231,6 +231,8 @@ .IP If \fIct-tuple\fR is provided, flushes the connection entry specified by \fIct-tuple\fR in \fIzone\fR. The zone defaults to 0 if it is not provided. +The userspace connection tracker requires flushing with the original pre-NATed +tuple and a warning log will be otherwise generated. An example of an IPv4 ICMP \fIct-tuple\fR: .IP "ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=1,icmp_type=8,icmp_code=0,icmp_id=10" diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpdk.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpdk.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpdk.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpdk.c 2020-03-11 16:15:44.000000000 +0000 @@ -474,7 +474,23 @@ return false; } - rte_memzone_dump(stdout); + if (VLOG_IS_DBG_ENABLED()) { + size_t size; + char *response = NULL; + FILE *stream = open_memstream(&response, &size); + + if (stream) { + rte_memzone_dump(stream); + fclose(stream); + if (size) { + VLOG_DBG("rte_memzone_dump:\n%s", response); + } + free(response); + } else { + VLOG_DBG("Could not dump memzone. Unable to open memstream: %s.", + ovs_strerror(errno)); + } + } /* We are called from the main thread here */ RTE_PER_LCORE(_lcore_id) = NON_PMD_CORE_ID; @@ -512,8 +528,8 @@ const char *dpdk_init_val = smap_get_def(ovs_other_config, "dpdk-init", "false"); - bool try_only = !strcmp(dpdk_init_val, "try"); - if (!strcmp(dpdk_init_val, "true") || try_only) { + bool try_only = !strcasecmp(dpdk_init_val, "try"); + if (!strcasecmp(dpdk_init_val, "true") || try_only) { static struct ovsthread_once once_enable = OVSTHREAD_ONCE_INITIALIZER; if (ovsthread_once_start(&once_enable)) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif.c 2020-03-11 16:15:44.000000000 +0000 @@ -591,13 +591,8 @@ netdev_ports_insert(netdev, dpif->dpif_class, &dpif_port); } } else { - if (error != EEXIST) { - VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s", - dpif_name(dpif), netdev_name, ovs_strerror(error)); - } else { - /* It's fairly common for upper layers to try to add a duplicate - * port, and they know how to handle it properly. */ - } + VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s", + dpif_name(dpif), netdev_name, ovs_strerror(error)); port_no = ODPP_NONE; } if (port_nop) { @@ -737,16 +732,7 @@ /* Returns the Netlink PID value to supply in OVS_ACTION_ATTR_USERSPACE * actions as the OVS_USERSPACE_ATTR_PID attribute's value, for use in - * flows whose packets arrived on port 'port_no'. In the case where the - * provider allocates multiple Netlink PIDs to a single port, it may use - * 'hash' to spread load among them. The caller need not use a particular - * hash function; a 5-tuple hash is suitable. - * - * (The datapath implementation might use some different hash function for - * distributing packets received via flow misses among PIDs. This means - * that packets received via flow misses might be reordered relative to - * packets received via userspace actions. This is not ordinarily a - * problem.) + * flows whose packets arrived on port 'port_no'. * * A 'port_no' of ODPP_NONE is a special case: it returns a reserved PID, not * allocated to any port, that the client may use for special purposes. @@ -757,10 +743,10 @@ * update all of the flows that it installed that contain * OVS_ACTION_ATTR_USERSPACE actions. */ uint32_t -dpif_port_get_pid(const struct dpif *dpif, odp_port_t port_no, uint32_t hash) +dpif_port_get_pid(const struct dpif *dpif, odp_port_t port_no) { return (dpif->dpif_class->port_get_pid - ? (dpif->dpif_class->port_get_pid)(dpif, port_no, hash) + ? (dpif->dpif_class->port_get_pid)(dpif, port_no) : 0); } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif.h 2020-03-11 16:15:44.000000000 +0000 @@ -274,18 +274,6 @@ * * - Upcalls that specify the "special" Netlink PID are queued separately. * - * Multiple threads may want to read upcalls simultaneously from a single - * datapath. To support multiple threads well, one extends the above preferred - * behavior: - * - * - Each port has multiple PIDs. The datapath distributes "miss" upcalls - * across the PIDs, ensuring that a given flow is mapped in a stable way - * to a single PID. - * - * - For "action" upcalls, the thread can specify its own Netlink PID or - * other threads' Netlink PID of the same port for offloading purpose - * (e.g. in a "round robin" manner). - * * * Packet Format * ============= @@ -470,8 +458,7 @@ struct dpif_port *); int dpif_port_get_name(struct dpif *, odp_port_t port_no, char *name, size_t name_size); -uint32_t dpif_port_get_pid(const struct dpif *, odp_port_t port_no, - uint32_t hash); +uint32_t dpif_port_get_pid(const struct dpif *, odp_port_t port_no); struct dpif_port_dump { const struct dpif *dpif; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netdev.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netdev.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netdev.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netdev.c 2020-03-11 16:15:44.000000000 +0000 @@ -1077,6 +1077,7 @@ static void sorted_poll_list(struct dp_netdev_pmd_thread *pmd, struct rxq_poll **list, size_t *n) + OVS_REQUIRES(pmd->port_mutex) { struct rxq_poll *ret, *poll; size_t i; @@ -2126,7 +2127,7 @@ if (ovs_u128_equals(*mega_ufid, data->mega_ufid)) { cmap_remove(&flow_mark.megaflow_to_mark, CONST_CAST(struct cmap_node *, &data->node), hash); - free(data); + ovsrcu_postpone(free, data); return; } } @@ -2345,9 +2346,9 @@ ovs_mutex_lock(&pmd->dp->port_mutex); port = dp_netdev_lookup_port(pmd->dp, in_port); - if (!port) { + if (!port || netdev_vport_is_vport_class(port->netdev->netdev_class)) { ovs_mutex_unlock(&pmd->dp->port_mutex); - return -1; + goto err_free; } ret = netdev_flow_put(port->netdev, &offload->match, CONST_CAST(struct nlattr *, offload->actions), @@ -2356,20 +2357,22 @@ ovs_mutex_unlock(&pmd->dp->port_mutex); if (ret) { - if (!modification) { - flow_mark_free(mark); - } else { - mark_to_flow_disassociate(pmd, flow); - } - return -1; + goto err_free; } if (!modification) { megaflow_to_mark_associate(&flow->mega_ufid, mark); mark_to_flow_associate(mark, flow); } - return 0; + +err_free: + if (!modification) { + flow_mark_free(mark); + } else { + mark_to_flow_disassociate(pmd, flow); + } + return -1; } static void * @@ -2386,6 +2389,7 @@ ovsrcu_quiesce_start(); ovs_mutex_cond_wait(&dp_flow_offload.cond, &dp_flow_offload.mutex); + ovsrcu_quiesce_end(); } list = ovs_list_pop_front(&dp_flow_offload.list); offload = CONTAINER_OF(list, struct dp_flow_offload_item, node); @@ -3361,6 +3365,16 @@ dpif_flow_hash(dpif, &match.flow, sizeof match.flow, &ufid); } + /* The Netlink encoding of datapath flow keys cannot express + * wildcarding the presence of a VLAN tag. Instead, a missing VLAN + * tag is interpreted as exact match on the fact that there is no + * VLAN. Unless we refactor a lot of code that translates between + * Netlink and struct flow representations, we have to do the same + * here. This must be in sync with 'match' in handle_packet_upcall(). */ + if (!match.wc.masks.vlans[0].tci) { + match.wc.masks.vlans[0].tci = htons(0xffff); + } + /* Must produce a netdev_flow_key for lookup. * Use the same method as employed to create the key when adding * the flow to the dplcs to make sure they match. */ @@ -5050,7 +5064,15 @@ memset(exceeded_rate, 0, cnt * sizeof *exceeded_rate); /* All packets will hit the meter at the same time. */ - long_delta_t = (now - meter->used) / 1000; /* msec */ + long_delta_t = now / 1000 - meter->used / 1000; /* msec */ + + if (long_delta_t < 0) { + /* This condition means that we have several threads fighting for a + meter lock, and the one who received the packets a bit later wins. + Assuming that all racing threads received packets at the same time + to avoid overflow. */ + long_delta_t = 0; + } /* Make sure delta_t will not be too large, so that bucket will not * wrap around below. */ @@ -5238,20 +5260,22 @@ struct ofputil_meter_stats *stats, uint16_t n_bands) { const struct dp_netdev *dp = get_dp_netdev(dpif); - const struct dp_meter *meter; uint32_t meter_id = meter_id_.uint32; + int retval = 0; if (meter_id >= MAX_METERS) { return EFBIG; } - meter = dp->meters[meter_id]; + + meter_lock(dp, meter_id); + const struct dp_meter *meter = dp->meters[meter_id]; if (!meter) { - return ENOENT; + retval = ENOENT; + goto done; } if (stats) { int i = 0; - meter_lock(dp, meter_id); stats->packet_in_count = meter->packet_count; stats->byte_in_count = meter->byte_count; @@ -5259,11 +5283,13 @@ stats->bands[i].packet_count = meter->bands[i].packet_count; stats->bands[i].byte_count = meter->bands[i].byte_count; } - meter_unlock(dp, meter_id); stats->n_bands = i; } - return 0; + +done: + meter_unlock(dp, meter_id); + return retval; } static int @@ -5698,7 +5724,6 @@ recirc_depth = *recirc_depth_get_unsafe(); if (OVS_UNLIKELY(recirc_depth)) { hash = hash_finish(hash, recirc_depth); - dp_packet_set_rss_hash(packet, hash); } return hash; } @@ -5898,20 +5923,13 @@ miniflow_extract(packet, &key->mf); key->len = 0; /* Not computed yet. */ - /* If EMC and SMC disabled skip hash computation */ - if (smc_enable_db == true || cur_min != 0) { - if (!md_is_valid) { - key->hash = dpif_netdev_packet_get_rss_hash_orig_pkt(packet, - &key->mf); - } else { - key->hash = dpif_netdev_packet_get_rss_hash(packet, &key->mf); - } - } - if (cur_min) { - flow = emc_lookup(&cache->emc_cache, key); - } else { - flow = NULL; - } + key->hash = + (md_is_valid == false) + ? dpif_netdev_packet_get_rss_hash_orig_pkt(packet, &key->mf) + : dpif_netdev_packet_get_rss_hash(packet, &key->mf); + + /* If EMC is disabled skip emc_lookup */ + flow = (cur_min != 0) ? emc_lookup(&cache->emc_cache, key) : NULL; if (OVS_LIKELY(flow)) { tcp_flags = miniflow_get_tcp_flags(&key->mf); dp_netdev_queue_batches(packet, flow, tcp_flags, batches, @@ -5977,7 +5995,7 @@ * tag is interpreted as exact match on the fact that there is no * VLAN. Unless we refactor a lot of code that translates between * Netlink and struct flow representations, we have to do the same - * here. */ + * here. This must be in sync with 'match' in dpif_netdev_flow_put(). */ if (!match.wc.masks.vlans[0].tci) { match.wc.masks.vlans[0].tci = htons(0xffff); } @@ -5997,8 +6015,7 @@ * could have already been installed since we last did the flow * lookup before upcall. This could be solved by moving the * mutex lock outside the loop, but that's an awful long time - * to be locking everyone out of making flow installs. If we - * move to a per-core classifier, it would be reasonable. */ + * to be locking revalidators out of making flow modifications. */ ovs_mutex_lock(&pmd->flow_mutex); netdev_flow = dp_netdev_pmd_lookup_flow(pmd, key, NULL); if (OVS_LIKELY(!netdev_flow)) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netdev-perf.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netdev-perf.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netdev-perf.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netdev-perf.c 2020-03-11 16:15:44.000000000 +0000 @@ -206,6 +206,7 @@ " Rx packets: %12"PRIu64" (%.0f Kpps, %.0f cycles/pkt)\n" " Datapath passes: %12"PRIu64" (%.2f passes/pkt)\n" " - EMC hits: %12"PRIu64" (%4.1f %%)\n" + " - SMC hits: %12"PRIu64" (%4.1f %%)\n" " - Megaflow hits: %12"PRIu64" (%4.1f %%, %.2f subtbl lookups/" "hit)\n" " - Upcalls: %12"PRIu64" (%4.1f %%, %.1f us/upcall)\n" @@ -215,6 +216,8 @@ passes, rx_packets ? 1.0 * passes / rx_packets : 0, stats[PMD_STAT_EXACT_HIT], 100.0 * stats[PMD_STAT_EXACT_HIT] / passes, + stats[PMD_STAT_SMC_HIT], + 100.0 * stats[PMD_STAT_SMC_HIT] / passes, stats[PMD_STAT_MASKED_HIT], 100.0 * stats[PMD_STAT_MASKED_HIT] / passes, stats[PMD_STAT_MASKED_HIT] @@ -495,15 +498,7 @@ cycles_per_pkt = cycles / rx_packets; histogram_add_sample(&s->cycles_per_pkt, cycles_per_pkt); } - if (s->current.batches > 0) { - histogram_add_sample(&s->pkts_per_batch, - rx_packets / s->current.batches); - } histogram_add_sample(&s->upcalls, s->current.upcalls); - if (s->current.upcalls > 0) { - histogram_add_sample(&s->cycles_per_upcall, - s->current.upcall_cycles / s->current.upcalls); - } histogram_add_sample(&s->max_vhost_qfill, s->current.max_vhost_qfill); /* Add iteration samples to millisecond stats. */ @@ -559,8 +554,8 @@ cum_ms = history_next(&s->milliseconds); cum_ms->timestamp = now; } - /* Do the next check after 10K cycles (4 us at 2.5 GHz TSC clock). */ - s->next_check_tsc = cycles_counter_update(s) + 10000; + /* Do the next check after 4 us (10K cycles at 2.5 GHz TSC clock). */ + s->next_check_tsc = cycles_counter_update(s) + get_tsc_hz() / 250000; } } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netdev-perf.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netdev-perf.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netdev-perf.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netdev-perf.h 2020-03-11 16:15:44.000000000 +0000 @@ -56,7 +56,7 @@ enum pmd_stat_type { PMD_STAT_EXACT_HIT, /* Packets that had an exact match (emc). */ - PMD_STAT_SMC_HIT, /* Packets that had a sig match hit (SMC). */ + PMD_STAT_SMC_HIT, /* Packets that had a sig match hit (SMC). */ PMD_STAT_MASKED_HIT, /* Packets that matched in the flow table. */ PMD_STAT_MISS, /* Packets that did not match and upcall was ok. */ PMD_STAT_LOST, /* Packets that did not match and upcall failed. */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netdev-unixctl.man openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netdev-unixctl.man --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netdev-unixctl.man 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netdev-unixctl.man 2020-03-11 16:15:44.000000000 +0000 @@ -11,7 +11,7 @@ \fIdp\fR. The special thread "main" sums up the statistics of every non pmd thread. -The sum of "emc hits", "masked hits" and "miss" is the number of +The sum of "emc hits", "smc hits", "megaflow hits" and "miss" is the number of packet lookups performed by the datapath. Beware that a recirculated packet experiences one additional lookup per recirculation, so there may be more lookups than forwarded packets in the datapath. @@ -135,6 +135,7 @@ Rx packets: 2399607 (2381 Kpps, 848 cycles/pkt) Datapath passes: 3599415 (1.50 passes/pkt) - EMC hits: 336472 ( 9.3 %) + - SMC hits: 0 ( 0.0 %) - Megaflow hits: 3262943 (90.7 %, 1.00 subtbl lookups/hit) - Upcalls: 0 ( 0.0 %, 0.0 us/upcall) - Lost upcalls: 0 ( 0.0 %) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netlink.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netlink.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-netlink.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-netlink.c 2020-03-11 16:15:44.000000000 +0000 @@ -78,6 +78,10 @@ #define FLOW_DUMP_MAX_BATCH 50 #define OPERATE_MAX_OPS 50 +#ifndef EPOLLEXCLUSIVE +#define EPOLLEXCLUSIVE (1u << 28) +#endif + struct dpif_netlink_dp { /* Generic Netlink header. */ uint8_t cmd; @@ -170,7 +174,6 @@ #endif struct dpif_handler { - struct dpif_channel *channels;/* Array of channels for each handler. */ struct epoll_event *epoll_events; int epoll_fd; /* epoll fd that includes channel socks. */ int n_events; /* Num events returned by epoll_wait(). */ @@ -193,6 +196,7 @@ struct fat_rwlock upcall_lock; struct dpif_handler *handlers; uint32_t n_handlers; /* Num of upcall handlers. */ + struct dpif_channel *channels; /* Array of channels for each port. */ int uc_array_size; /* Size of 'handler->channels' and */ /* 'handler->epoll_events'. */ @@ -230,7 +234,7 @@ static int dpif_netlink_init(void); static int open_dpif(const struct dpif_netlink_dp *, struct dpif **); static uint32_t dpif_netlink_port_get_pid(const struct dpif *, - odp_port_t port_no, uint32_t hash); + odp_port_t port_no); static void dpif_netlink_handler_uninit(struct dpif_handler *handler); static int dpif_netlink_refresh_channels(struct dpif_netlink *, uint32_t n_handlers); @@ -242,6 +246,42 @@ odp_port_t port_no, const char *port_name, struct dpif_port *dpif_port); +static int +create_nl_sock(struct dpif_netlink *dpif OVS_UNUSED, struct nl_sock **socksp) + OVS_REQ_WRLOCK(dpif->upcall_lock) +{ +#ifndef _WIN32 + return nl_sock_create(NETLINK_GENERIC, socksp); +#else + /* Pick netlink sockets to use in a round-robin fashion from each + * handler's pool of sockets. */ + struct dpif_handler *handler = &dpif->handlers[0]; + struct dpif_windows_vport_sock *sock_pool = handler->vport_sock_pool; + size_t index = handler->last_used_pool_idx; + + /* A pool of sockets is allocated when the handler is initialized. */ + if (sock_pool == NULL) { + *socksp = NULL; + return EINVAL; + } + + ovs_assert(index < VPORT_SOCK_POOL_SIZE); + *socksp = sock_pool[index].nl_sock; + ovs_assert(*socksp); + index = (index == VPORT_SOCK_POOL_SIZE - 1) ? 0 : index + 1; + handler->last_used_pool_idx = index; + return 0; +#endif +} + +static void +close_nl_sock(struct nl_sock *socksp) +{ +#ifndef _WIN32 + nl_sock_destroy(socksp); +#endif +} + static struct dpif_netlink * dpif_netlink_cast(const struct dpif *dpif) { @@ -331,43 +371,6 @@ return 0; } -/* Destroys the netlink sockets pointed by the elements in 'socksp' - * and frees the 'socksp'. */ -static void -vport_del_socksp__(struct nl_sock **socksp, uint32_t n_socks) -{ - size_t i; - - for (i = 0; i < n_socks; i++) { - nl_sock_destroy(socksp[i]); - } - - free(socksp); -} - -/* Creates an array of netlink sockets. Returns an array of the - * corresponding pointers. Records the error in 'error'. */ -static struct nl_sock ** -vport_create_socksp__(uint32_t n_socks, int *error) -{ - struct nl_sock **socksp = xzalloc(n_socks * sizeof *socksp); - size_t i; - - for (i = 0; i < n_socks; i++) { - *error = nl_sock_create(NETLINK_GENERIC, &socksp[i]); - if (*error) { - goto error; - } - } - - return socksp; - -error: - vport_del_socksp__(socksp, n_socks); - - return NULL; -} - #ifdef _WIN32 static void vport_delete_sock_pool(struct dpif_handler *handler) @@ -422,138 +425,44 @@ vport_delete_sock_pool(handler); return error; } - -/* Returns an array pointers to netlink sockets. The sockets are picked from a - * pool. Records the error in 'error'. */ -static struct nl_sock ** -vport_create_socksp_windows(struct dpif_netlink *dpif, int *error) - OVS_REQ_WRLOCK(dpif->upcall_lock) -{ - uint32_t n_socks = dpif->n_handlers; - struct nl_sock **socksp; - size_t i; - - ovs_assert(n_socks <= 1); - socksp = xzalloc(n_socks * sizeof *socksp); - - /* Pick netlink sockets to use in a round-robin fashion from each - * handler's pool of sockets. */ - for (i = 0; i < n_socks; i++) { - struct dpif_handler *handler = &dpif->handlers[i]; - struct dpif_windows_vport_sock *sock_pool = handler->vport_sock_pool; - size_t index = handler->last_used_pool_idx; - - /* A pool of sockets is allocated when the handler is initialized. */ - if (sock_pool == NULL) { - free(socksp); - *error = EINVAL; - return NULL; - } - - ovs_assert(index < VPORT_SOCK_POOL_SIZE); - socksp[i] = sock_pool[index].nl_sock; - socksp[i] = sock_pool[index].nl_sock; - ovs_assert(socksp[i]); - index = (index == VPORT_SOCK_POOL_SIZE - 1) ? 0 : index + 1; - handler->last_used_pool_idx = index; - } - - return socksp; -} - -static void -vport_del_socksp_windows(struct dpif_netlink *dpif, struct nl_sock **socksp) -{ - free(socksp); -} #endif /* _WIN32 */ -static struct nl_sock ** -vport_create_socksp(struct dpif_netlink *dpif, int *error) -{ -#ifdef _WIN32 - return vport_create_socksp_windows(dpif, error); -#else - return vport_create_socksp__(dpif->n_handlers, error); -#endif -} - -static void -vport_del_socksp(struct dpif_netlink *dpif, struct nl_sock **socksp) -{ -#ifdef _WIN32 - vport_del_socksp_windows(dpif, socksp); -#else - vport_del_socksp__(socksp, dpif->n_handlers); -#endif -} - -/* Given the array of pointers to netlink sockets 'socksp', returns - * the array of corresponding pids. If the 'socksp' is NULL, returns - * a single-element array of value 0. */ -static uint32_t * -vport_socksp_to_pids(struct nl_sock **socksp, uint32_t n_socks) -{ - uint32_t *pids; - - if (!socksp) { - pids = xzalloc(sizeof *pids); - } else { - size_t i; - - pids = xzalloc(n_socks * sizeof *pids); - for (i = 0; i < n_socks; i++) { - pids[i] = nl_sock_pid(socksp[i]); - } - } - - return pids; -} - -/* Given the port number 'port_idx', extracts the pids of netlink sockets - * associated to the port and assigns it to 'upcall_pids'. */ +/* Given the port number 'port_idx', extracts the pid of netlink socket + * associated to the port and assigns it to 'upcall_pid'. */ static bool -vport_get_pids(struct dpif_netlink *dpif, uint32_t port_idx, - uint32_t **upcall_pids) +vport_get_pid(struct dpif_netlink *dpif, uint32_t port_idx, + uint32_t *upcall_pid) { - uint32_t *pids; - size_t i; - /* Since the nl_sock can only be assigned in either all - * or none "dpif->handlers" channels, the following check + * or none "dpif" channels, the following check * would suffice. */ - if (!dpif->handlers[0].channels[port_idx].sock) { + if (!dpif->channels[port_idx].sock) { return false; } ovs_assert(!WINDOWS || dpif->n_handlers <= 1); - pids = xzalloc(dpif->n_handlers * sizeof *pids); - - for (i = 0; i < dpif->n_handlers; i++) { - pids[i] = nl_sock_pid(dpif->handlers[i].channels[port_idx].sock); - } - - *upcall_pids = pids; + *upcall_pid = nl_sock_pid(dpif->channels[port_idx].sock); return true; } static int -vport_add_channels(struct dpif_netlink *dpif, odp_port_t port_no, - struct nl_sock **socksp) +vport_add_channel(struct dpif_netlink *dpif, odp_port_t port_no, + struct nl_sock *socksp) { struct epoll_event event; uint32_t port_idx = odp_to_u32(port_no); - size_t i, j; + size_t i; int error; if (dpif->handlers == NULL) { + close_nl_sock(socksp); return 0; } /* We assume that the datapath densely chooses port numbers, which can * therefore be used as an index into 'channels' and 'epoll_events' of - * 'dpif->handler'. */ + * 'dpif'. */ if (port_idx >= dpif->uc_array_size) { uint32_t new_size = port_idx + 1; @@ -563,15 +472,15 @@ return EFBIG; } - for (i = 0; i < dpif->n_handlers; i++) { - struct dpif_handler *handler = &dpif->handlers[i]; + dpif->channels = xrealloc(dpif->channels, + new_size * sizeof *dpif->channels); - handler->channels = xrealloc(handler->channels, - new_size * sizeof *handler->channels); + for (i = dpif->uc_array_size; i < new_size; i++) { + dpif->channels[i].sock = NULL; + } - for (j = dpif->uc_array_size; j < new_size; j++) { - handler->channels[j].sock = NULL; - } + for (i = 0; i < dpif->n_handlers; i++) { + struct dpif_handler *handler = &dpif->handlers[i]; handler->epoll_events = xrealloc(handler->epoll_events, new_size * sizeof *handler->epoll_events); @@ -581,33 +490,33 @@ } memset(&event, 0, sizeof event); - event.events = EPOLLIN; + event.events = EPOLLIN | EPOLLEXCLUSIVE; event.data.u32 = port_idx; for (i = 0; i < dpif->n_handlers; i++) { struct dpif_handler *handler = &dpif->handlers[i]; #ifndef _WIN32 - if (epoll_ctl(handler->epoll_fd, EPOLL_CTL_ADD, nl_sock_fd(socksp[i]), + if (epoll_ctl(handler->epoll_fd, EPOLL_CTL_ADD, nl_sock_fd(socksp), &event) < 0) { error = errno; goto error; } #endif - dpif->handlers[i].channels[port_idx].sock = socksp[i]; - dpif->handlers[i].channels[port_idx].last_poll = LLONG_MIN; } + dpif->channels[port_idx].sock = socksp; + dpif->channels[port_idx].last_poll = LLONG_MIN; return 0; error: - for (j = 0; j < i; j++) { #ifndef _WIN32 - epoll_ctl(dpif->handlers[j].epoll_fd, EPOLL_CTL_DEL, - nl_sock_fd(socksp[j]), NULL); -#endif - dpif->handlers[j].channels[port_idx].sock = NULL; + while (i--) { + epoll_ctl(dpif->handlers[i].epoll_fd, EPOLL_CTL_DEL, + nl_sock_fd(socksp), NULL); } +#endif + dpif->channels[port_idx].sock = NULL; return error; } @@ -618,14 +527,8 @@ uint32_t port_idx = odp_to_u32(port_no); size_t i; - if (!dpif->handlers || port_idx >= dpif->uc_array_size) { - return; - } - - /* Since the sock can only be assigned in either all or none - * of "dpif->handlers" channels, the following check would - * suffice. */ - if (!dpif->handlers[0].channels[port_idx].sock) { + if (!dpif->handlers || port_idx >= dpif->uc_array_size + || !dpif->channels[port_idx].sock) { return; } @@ -633,12 +536,14 @@ struct dpif_handler *handler = &dpif->handlers[i]; #ifndef _WIN32 epoll_ctl(handler->epoll_fd, EPOLL_CTL_DEL, - nl_sock_fd(handler->channels[port_idx].sock), NULL); - nl_sock_destroy(handler->channels[port_idx].sock); + nl_sock_fd(dpif->channels[port_idx].sock), NULL); #endif - handler->channels[port_idx].sock = NULL; handler->event_offset = handler->n_events = 0; } +#ifndef _WIN32 + nl_sock_destroy(dpif->channels[port_idx].sock); +#endif + dpif->channels[port_idx].sock = NULL; } static void @@ -655,10 +560,7 @@ struct dpif_netlink_vport vport_request; uint32_t upcall_pids = 0; - /* Since the sock can only be assigned in either all or none - * of "dpif->handlers" channels, the following check would - * suffice. */ - if (!dpif->handlers[0].channels[i].sock) { + if (!dpif->channels[i].sock) { continue; } @@ -679,11 +581,11 @@ dpif_netlink_handler_uninit(handler); free(handler->epoll_events); - free(handler->channels); } - + free(dpif->channels); free(dpif->handlers); dpif->handlers = NULL; + dpif->channels = NULL; dpif->n_handlers = 0; dpif->uc_array_size = 0; } @@ -846,13 +748,13 @@ { struct dpif_netlink_vport request, reply; struct ofpbuf *buf; - struct nl_sock **socksp = NULL; - uint32_t *upcall_pids; + struct nl_sock *socksp = NULL; + uint32_t upcall_pids = 0; int error = 0; if (dpif->handlers) { - socksp = vport_create_socksp(dpif, &error); - if (!socksp) { + error = create_nl_sock(dpif, &socksp); + if (error) { return error; } } @@ -864,9 +766,11 @@ request.name = name; request.port_no = *port_nop; - upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers); - request.n_upcall_pids = socksp ? dpif->n_handlers : 1; - request.upcall_pids = upcall_pids; + if (socksp) { + upcall_pids = nl_sock_pid(socksp); + } + request.n_upcall_pids = 1; + request.upcall_pids = &upcall_pids; if (options) { request.options = options->data; @@ -882,31 +786,27 @@ dpif_name(&dpif->dpif), *port_nop); } - vport_del_socksp(dpif, socksp); + close_nl_sock(socksp); goto exit; } - if (socksp) { - error = vport_add_channels(dpif, *port_nop, socksp); - if (error) { - VLOG_INFO("%s: could not add channel for port %s", - dpif_name(&dpif->dpif), name); + error = vport_add_channel(dpif, *port_nop, socksp); + if (error) { + VLOG_INFO("%s: could not add channel for port %s", + dpif_name(&dpif->dpif), name); - /* Delete the port. */ - dpif_netlink_vport_init(&request); - request.cmd = OVS_VPORT_CMD_DEL; - request.dp_ifindex = dpif->dp_ifindex; - request.port_no = *port_nop; - dpif_netlink_vport_transact(&request, NULL, NULL); - vport_del_socksp(dpif, socksp); - goto exit; - } + /* Delete the port. */ + dpif_netlink_vport_init(&request); + request.cmd = OVS_VPORT_CMD_DEL; + request.dp_ifindex = dpif->dp_ifindex; + request.port_no = *port_nop; + dpif_netlink_vport_transact(&request, NULL, NULL); + close_nl_sock(socksp); + goto exit; } - free(socksp); exit: ofpbuf_delete(buf); - free(upcall_pids); return error; } @@ -1131,7 +1031,7 @@ static uint32_t dpif_netlink_port_get_pid__(const struct dpif_netlink *dpif, - odp_port_t port_no, uint32_t hash) + odp_port_t port_no) OVS_REQ_RDLOCK(dpif->upcall_lock) { uint32_t port_idx = odp_to_u32(port_no); @@ -1141,14 +1041,13 @@ /* The ODPP_NONE "reserved" port number uses the "ovs-system"'s * channel, since it is not heavily loaded. */ uint32_t idx = port_idx >= dpif->uc_array_size ? 0 : port_idx; - struct dpif_handler *h = &dpif->handlers[hash % dpif->n_handlers]; /* Needs to check in case the socket pointer is changed in between * the holding of upcall_lock. A known case happens when the main * thread deletes the vport while the handler thread is handling * the upcall from that port. */ - if (h->channels[idx].sock) { - pid = nl_sock_pid(h->channels[idx].sock); + if (dpif->channels[idx].sock) { + pid = nl_sock_pid(dpif->channels[idx].sock); } } @@ -1156,14 +1055,13 @@ } static uint32_t -dpif_netlink_port_get_pid(const struct dpif *dpif_, odp_port_t port_no, - uint32_t hash) +dpif_netlink_port_get_pid(const struct dpif *dpif_, odp_port_t port_no) { const struct dpif_netlink *dpif = dpif_netlink_cast(dpif_); uint32_t ret; fat_rwlock_rdlock(&dpif->upcall_lock); - ret = dpif_netlink_port_get_pid__(dpif, port_no, hash); + ret = dpif_netlink_port_get_pid__(dpif, port_no); fat_rwlock_unlock(&dpif->upcall_lock); return ret; @@ -2119,11 +2017,6 @@ return err; } - /* When we try to install a dummy flow from a probed feature. */ - if (match.flow.dl_type == htons(0x1234)) { - return EOPNOTSUPP; - } - in_port = match.flow.in_port.odp_port; dev = netdev_ports_get(in_port, dpif_class); if (!dev) { @@ -2382,42 +2275,41 @@ dpif_netlink_port_dump_start__(dpif, &dump); while (!dpif_netlink_port_dump_next__(dpif, &dump, &vport, &buf)) { uint32_t port_no = odp_to_u32(vport.port_no); - uint32_t *upcall_pids = NULL; + uint32_t upcall_pid; int error; if (port_no >= dpif->uc_array_size - || !vport_get_pids(dpif, port_no, &upcall_pids)) { - struct nl_sock **socksp = vport_create_socksp(dpif, &error); + || !vport_get_pid(dpif, port_no, &upcall_pid)) { + struct nl_sock *socksp; + error = create_nl_sock(dpif, &socksp); - if (!socksp) { + if (error) { goto error; } - error = vport_add_channels(dpif, vport.port_no, socksp); + error = vport_add_channel(dpif, vport.port_no, socksp); if (error) { VLOG_INFO("%s: could not add channels for port %s", dpif_name(&dpif->dpif), vport.name); - vport_del_socksp(dpif, socksp); + nl_sock_destroy(socksp); retval = error; goto error; } - upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers); - free(socksp); + upcall_pid = nl_sock_pid(socksp); } /* Configure the vport to deliver misses to 'sock'. */ if (vport.upcall_pids[0] == 0 - || vport.n_upcall_pids != dpif->n_handlers - || memcmp(upcall_pids, vport.upcall_pids, n_handlers * sizeof - *upcall_pids)) { + || vport.n_upcall_pids != 1 + || upcall_pid != vport.upcall_pids[0]) { struct dpif_netlink_vport vport_request; dpif_netlink_vport_init(&vport_request); vport_request.cmd = OVS_VPORT_CMD_SET; vport_request.dp_ifindex = dpif->dp_ifindex; vport_request.port_no = vport.port_no; - vport_request.n_upcall_pids = dpif->n_handlers; - vport_request.upcall_pids = upcall_pids; + vport_request.n_upcall_pids = 1; + vport_request.upcall_pids = &upcall_pid; error = dpif_netlink_vport_transact(&vport_request, NULL, NULL); if (error) { VLOG_WARN_RL(&error_rl, @@ -2438,11 +2330,9 @@ if (port_no < keep_channels_nbits) { bitmap_set1(keep_channels, port_no); } - free(upcall_pids); continue; error: - free(upcall_pids); vport_del_channels(dpif, vport.port_no); } nl_dump_done(&dump); @@ -2701,7 +2591,7 @@ while (handler->event_offset < handler->n_events) { int idx = handler->epoll_events[handler->event_offset].data.u32; - struct dpif_channel *ch = &dpif->handlers[handler_id].channels[idx]; + struct dpif_channel *ch = &dpif->channels[idx]; handler->event_offset++; @@ -2803,16 +2693,14 @@ OVS_REQ_WRLOCK(dpif->upcall_lock) { if (dpif->handlers) { - size_t i, j; + size_t i; + if (!dpif->channels[0].sock) { + return; + } for (i = 0; i < dpif->uc_array_size; i++ ) { - if (!dpif->handlers[0].channels[i].sock) { - continue; - } - for (j = 0; j < dpif->n_handlers; j++) { - nl_sock_drain(dpif->handlers[j].channels[i].sock); - } + nl_sock_drain(dpif->channels[i].sock); } } } @@ -2961,7 +2849,7 @@ nl_msg_end_nested(request, opt_offset); int err = nl_transact(NETLINK_GENERIC, request, NULL); - ofpbuf_uninit(request); + ofpbuf_delete(request); return err; } @@ -3061,8 +2949,8 @@ zone_limits_reply); out: - ofpbuf_uninit(request); - ofpbuf_uninit(reply); + ofpbuf_delete(request); + ofpbuf_delete(reply); return err; } @@ -3098,7 +2986,7 @@ int err = nl_transact(NETLINK_GENERIC, request, NULL); - ofpbuf_uninit(request); + ofpbuf_delete(request); return err; } @@ -4002,7 +3890,7 @@ ovs_be16 pt = pt_ns_type_be(nl_attr_get_be32(packet_type)); const struct nlattr *nla; - nla = nl_attr_find(buf, NLA_HDRLEN, OVS_KEY_ATTR_ETHERTYPE); + nla = nl_attr_find(buf, ofs + NLA_HDRLEN, OVS_KEY_ATTR_ETHERTYPE); if (nla) { ovs_be16 *ethertype; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-provider.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-provider.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dpif-provider.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dpif-provider.h 2020-03-11 16:15:44.000000000 +0000 @@ -191,16 +191,7 @@ /* Returns the Netlink PID value to supply in OVS_ACTION_ATTR_USERSPACE * actions as the OVS_USERSPACE_ATTR_PID attribute's value, for use in - * flows whose packets arrived on port 'port_no'. In the case where the - * provider allocates multiple Netlink PIDs to a single port, it may use - * 'hash' to spread load among them. The caller need not use a particular - * hash function; a 5-tuple hash is suitable. - * - * (The datapath implementation might use some different hash function for - * distributing packets received via flow misses among PIDs. This means - * that packets received via flow misses might be reordered relative to - * packets received via userspace actions. This is not ordinarily a - * problem.) + * flows whose packets arrived on port 'port_no'. * * A 'port_no' of UINT32_MAX should be treated as a special case. The * implementation should return a reserved PID, not allocated to any port, @@ -212,8 +203,7 @@ * * A dpif provider that doesn't have meaningful Netlink PIDs can use NULL * for this function. This is equivalent to always returning 0. */ - uint32_t (*port_get_pid)(const struct dpif *dpif, odp_port_t port_no, - uint32_t hash); + uint32_t (*port_get_pid)(const struct dpif *dpif, odp_port_t port_no); /* Attempts to begin dumping the ports in a dpif. On success, returns 0 * and initializes '*statep' with any data needed for iteration. On diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dp-packet.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dp-packet.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/dp-packet.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/dp-packet.h 2020-03-11 16:15:44.000000000 +0000 @@ -352,10 +352,23 @@ b->l4_ofs = l4 ? (char *) l4 - (char *) dp_packet_data(b) : UINT16_MAX; } +/* Returns the size of the packet from the beginning of the L3 header to the + * end of the L3 payload. Hence L2 padding is not included. */ +static inline size_t +dp_packet_l3_size(const struct dp_packet *b) +{ + return OVS_LIKELY(b->l3_ofs != UINT16_MAX) + ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l3(b) + - dp_packet_l2_pad_size(b) + : 0; +} + +/* Returns the size of the packet from the beginning of the L4 header to the + * end of the L4 payload. Hence L2 padding is not included. */ static inline size_t dp_packet_l4_size(const struct dp_packet *b) { - return b->l4_ofs != UINT16_MAX + return OVS_LIKELY(b->l4_ofs != UINT16_MAX) ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l4(b) - dp_packet_l2_pad_size(b) : 0; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/flow.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/flow.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/flow.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/flow.c 2020-03-11 16:15:44.000000000 +0000 @@ -681,7 +681,7 @@ return false; } /* Jumbo Payload option not supported yet. */ - if (OVS_UNLIKELY(size - plen > UINT8_MAX)) { + if (OVS_UNLIKELY(size - (plen + IPV6_HEADER_LEN) > UINT8_MAX)) { return false; } @@ -868,11 +868,6 @@ } tc_flow = get_16aligned_be32(&nh->ip6_flow); - { - ovs_be32 label = tc_flow & htonl(IPV6_LABEL_MASK); - miniflow_push_be32(mf, ipv6_label, label); - } - nw_tos = ntohl(tc_flow) >> 20; nw_ttl = nh->ip6_hlim; nw_proto = nh->ip6_nxt; @@ -880,6 +875,12 @@ if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag)) { goto out; } + + /* This needs to be after the parse_ipv6_ext_hdrs__() call because it + * leaves the nw_frag word uninitialized. */ + ASSERT_SEQUENTIAL(ipv6_label, nw_frag); + ovs_be32 label = tc_flow & htonl(IPV6_LABEL_MASK); + miniflow_push_be32(mf, ipv6_label, label); } else { if (dl_type == htons(ETH_TYPE_ARP) || dl_type == htons(ETH_TYPE_RARP)) { @@ -1008,15 +1009,14 @@ dst->map = mf.map; } -ovs_be16 -parse_dl_type(const struct eth_header *data_, size_t size) +static ovs_be16 +parse_dl_type(const void **datap, size_t *sizep) { - const void *data = data_; union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS]; - parse_vlan(&data, &size, vlans); + parse_vlan(datap, sizep, vlans); - return parse_ethertype(&data, &size); + return parse_ethertype(datap, sizep); } uint16_t @@ -1034,11 +1034,11 @@ dp_packet_reset_offsets(packet); - data_pull(&data, &size, ETH_ADDR_LEN * 2); - dl_type = parse_ethertype(&data, &size); + dl_type = parse_dl_type(&data, &size); if (OVS_UNLIKELY(eth_type_mpls(dl_type))) { packet->l2_5_ofs = (char *)data - frame; } + packet->l3_ofs = (char *)data - frame; if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) { const struct ip_header *nh = data; int ip_len; @@ -1048,7 +1048,6 @@ return 0; } dp_packet_set_l2_pad_size(packet, size - tot_len); - packet->l3_ofs = (uint16_t)((char *)nh - frame); nw_proto = nh->ip_proto; nw_frag = ipv4_get_nw_frag(nh); @@ -1061,7 +1060,6 @@ if (OVS_UNLIKELY(!ipv6_sanity_check(nh, size))) { return 0; } - packet->l3_ofs = (uint16_t)((char *)nh - frame); data_pull(&data, &size, sizeof *nh); plen = ntohs(nh->ip6_plen); /* Never pull padding. */ @@ -1251,6 +1249,7 @@ if (!bit) { ds_put_format(ds, "%s: unknown connection tracking state flag", cs); + free(state_s); return false; } state |= bit; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/flow.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/flow.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/flow.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/flow.h 2020-03-11 16:15:44.000000000 +0000 @@ -131,7 +131,6 @@ bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, uint8_t *nw_frag); -ovs_be16 parse_dl_type(const struct eth_header *data_, size_t size); bool parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key); uint16_t parse_tcp_flags(struct dp_packet *packet); @@ -1187,4 +1186,26 @@ && eth_addr_equals(flow->dl_dst, eth_addr_stp)); } +/* Returns true if flow->tp_dst equals 'port'. If 'wc' is nonnull, sets + * appropriate bits in wc->masks.tp_dst to account for the test. + * + * The caller must already have ensured that 'flow' is a protocol for which + * tp_dst is relevant. */ +static inline bool tp_dst_equals(const struct flow *flow, uint16_t port, + struct flow_wildcards *wc) +{ + uint16_t diff = port ^ ntohs(flow->tp_dst); + if (wc) { + if (diff) { + /* Set mask for the most significant mismatching bit. */ + int ofs = raw_clz64((uint64_t) diff << 48); /* range [0,15] */ + wc->masks.tp_dst |= htons(0x8000 >> ofs); + } else { + /* Must match all bits. */ + wc->masks.tp_dst = OVS_BE16_MAX; + } + } + return !diff; +} + #endif /* flow.h */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-bsd.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-bsd.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-bsd.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-bsd.c 2020-03-11 16:15:44.000000000 +0000 @@ -1479,94 +1479,45 @@ return error; } -/* Linux has also different GET_STATS, SET_STATS, - * GET_STATUS) - */ -#define NETDEV_BSD_CLASS(NAME, CONSTRUCT, \ - GET_FEATURES) \ -{ \ - NAME, \ - false, /* is_pmd */ \ - \ - NULL, /* init */ \ - netdev_bsd_run, \ - netdev_bsd_wait, \ - netdev_bsd_alloc, \ - CONSTRUCT, \ - netdev_bsd_destruct, \ - netdev_bsd_dealloc, \ - NULL, /* get_config */ \ - NULL, /* set_config */ \ - NULL, /* get_tunnel_config */ \ - NULL, /* build header */ \ - NULL, /* push header */ \ - NULL, /* pop header */ \ - NULL, /* get_numa_id */ \ - NULL, /* set_tx_multiq */ \ - \ - netdev_bsd_send, \ - netdev_bsd_send_wait, \ - \ - netdev_bsd_set_etheraddr, \ - netdev_bsd_get_etheraddr, \ - netdev_bsd_get_mtu, \ - NULL, /* set_mtu */ \ - netdev_bsd_get_ifindex, \ - netdev_bsd_get_carrier, \ - NULL, /* get_carrier_resets */ \ - NULL, /* set_miimon_interval */ \ - netdev_bsd_get_stats, \ - NULL, /* get_custom_stats */ \ - GET_FEATURES, \ - NULL, /* set_advertisement */ \ - NULL, /* get_pt_mode */ \ - NULL, /* set_policing */ \ - NULL, /* get_qos_type */ \ - NULL, /* get_qos_capabilities */ \ - NULL, /* get_qos */ \ - NULL, /* set_qos */ \ - NULL, /* get_queue */ \ - NULL, /* set_queue */ \ - NULL, /* delete_queue */ \ - NULL, /* get_queue_stats */ \ - NULL, /* queue_dump_start */ \ - NULL, /* queue_dump_next */ \ - NULL, /* queue_dump_done */ \ - NULL, /* dump_queue_stats */ \ - \ - netdev_bsd_set_in4, \ - netdev_bsd_get_addr_list, \ - NULL, /* add_router */ \ - netdev_bsd_get_next_hop, \ - NULL, /* get_status */ \ - netdev_bsd_arp_lookup, /* arp_lookup */ \ - \ - netdev_bsd_update_flags, \ - NULL, /* reconfigure */ \ - \ - netdev_bsd_rxq_alloc, \ - netdev_bsd_rxq_construct, \ - netdev_bsd_rxq_destruct, \ - netdev_bsd_rxq_dealloc, \ - netdev_bsd_rxq_recv, \ - netdev_bsd_rxq_wait, \ - netdev_bsd_rxq_drain, \ - \ - NO_OFFLOAD_API, \ - NULL /* get_block_id */ \ -} +#define NETDEV_BSD_CLASS_COMMON \ + .run = netdev_bsd_run, \ + .wait = netdev_bsd_wait, \ + .alloc = netdev_bsd_alloc, \ + .destruct = netdev_bsd_destruct, \ + .dealloc = netdev_bsd_dealloc, \ + .send = netdev_bsd_send, \ + .send_wait = netdev_bsd_send_wait, \ + .set_etheraddr = netdev_bsd_set_etheraddr, \ + .get_etheraddr = netdev_bsd_get_etheraddr, \ + .get_mtu = netdev_bsd_get_mtu, \ + .get_ifindex = netdev_bsd_get_ifindex, \ + .get_carrier = netdev_bsd_get_carrier, \ + .get_stats = netdev_bsd_get_stats, \ + .get_features = netdev_bsd_get_features, \ + .set_in4 = netdev_bsd_set_in4, \ + .get_addr_list = netdev_bsd_get_addr_list, \ + .get_next_hop = netdev_bsd_get_next_hop, \ + .arp_lookup = netdev_bsd_arp_lookup, \ + .update_flags = netdev_bsd_update_flags, \ + .rxq_alloc = netdev_bsd_rxq_alloc, \ + .rxq_construct = netdev_bsd_rxq_construct, \ + .rxq_destruct = netdev_bsd_rxq_destruct, \ + .rxq_dealloc = netdev_bsd_rxq_dealloc, \ + .rxq_recv = netdev_bsd_rxq_recv, \ + .rxq_wait = netdev_bsd_rxq_wait, \ + .rxq_drain = netdev_bsd_rxq_drain -const struct netdev_class netdev_bsd_class = - NETDEV_BSD_CLASS( - "system", - netdev_bsd_construct_system, - netdev_bsd_get_features); +const struct netdev_class netdev_bsd_class = { + NETDEV_BSD_CLASS_COMMON, + .type = "system", + .construct = netdev_bsd_construct_system, +}; -const struct netdev_class netdev_tap_class = - NETDEV_BSD_CLASS( - "tap", - netdev_bsd_construct_tap, - netdev_bsd_get_features); +const struct netdev_class netdev_tap_class = { + NETDEV_BSD_CLASS_COMMON, + .type = "tap", + .construct = netdev_bsd_construct_tap, +}; static void diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev.c 2020-03-11 16:15:44.000000000 +0000 @@ -1801,8 +1801,9 @@ netdev_queue_dump_next(struct netdev_queue_dump *dump, unsigned int *queue_id, struct smap *details) { - const struct netdev *netdev = dump->netdev; + smap_clear(details); + const struct netdev *netdev = dump->netdev; if (dump->error) { return false; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-dpdk.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-dpdk.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-dpdk.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-dpdk.c 2020-03-11 16:15:44.000000000 +0000 @@ -1678,6 +1678,7 @@ { struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); bool rx_fc_en, tx_fc_en, autoneg, lsc_interrupt_mode; + bool flow_control_requested = true; enum rte_eth_fc_mode fc_mode; static const enum rte_eth_fc_mode fc_mode_set[2][2] = { {RTE_FC_NONE, RTE_FC_TX_PAUSE}, @@ -1700,7 +1701,7 @@ new_devargs = smap_get(args, "dpdk-devargs"); - if (dev->devargs && strcmp(new_devargs, dev->devargs)) { + if (dev->devargs && new_devargs && strcmp(new_devargs, dev->devargs)) { /* The user requested a new device. If we return error, the caller * will delete this netdev and try to recreate it. */ err = EAGAIN; @@ -1765,15 +1766,34 @@ autoneg = smap_get_bool(args, "flow-ctrl-autoneg", false); fc_mode = fc_mode_set[tx_fc_en][rx_fc_en]; + + if (!smap_get(args, "rx-flow-ctrl") && !smap_get(args, "tx-flow-ctrl") + && !smap_get(args, "flow-ctrl-autoneg")) { + /* FIXME: User didn't ask for flow control configuration. + * For now we'll not print a warning if flow control is not + * supported by the DPDK port. */ + flow_control_requested = false; + } + + /* Get the Flow control configuration. */ + err = -rte_eth_dev_flow_ctrl_get(dev->port_id, &dev->fc_conf); + if (err) { + if (err == ENOTSUP) { + if (flow_control_requested) { + VLOG_WARN("%s: Flow control is not supported.", + netdev_get_name(netdev)); + } + err = 0; /* Not fatal. */ + } else { + VLOG_WARN("%s: Cannot get flow control parameters: %s", + netdev_get_name(netdev), rte_strerror(err)); + } + goto out; + } + if (dev->fc_conf.mode != fc_mode || autoneg != dev->fc_conf.autoneg) { dev->fc_conf.mode = fc_mode; dev->fc_conf.autoneg = autoneg; - /* Get the Flow control configuration for DPDK-ETH */ - err = rte_eth_dev_flow_ctrl_get(dev->port_id, &dev->fc_conf); - if (err) { - VLOG_WARN("Cannot get flow control parameters on port " - DPDK_PORT_ID_FMT", err=%d", dev->port_id, err); - } dpdk_eth_flow_ctrl_setup(dev); } @@ -2254,7 +2274,7 @@ /* No packets sent - do not retry.*/ break; } - } while (cnt && (retries++ <= VHOST_ENQ_RETRY_NUM)); + } while (cnt && (retries++ < VHOST_ENQ_RETRY_NUM)); rte_spinlock_unlock(&dev->tx_q[qid].tx_lock); @@ -2707,43 +2727,57 @@ { struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); struct rte_eth_link link; + uint32_t feature = 0; ovs_mutex_lock(&dev->mutex); link = dev->link; ovs_mutex_unlock(&dev->mutex); - if (link.link_duplex == ETH_LINK_HALF_DUPLEX) { - if (link.link_speed == ETH_SPEED_NUM_10M) { - *current = NETDEV_F_10MB_HD; - } - if (link.link_speed == ETH_SPEED_NUM_100M) { - *current = NETDEV_F_100MB_HD; - } - if (link.link_speed == ETH_SPEED_NUM_1G) { - *current = NETDEV_F_1GB_HD; - } - } else if (link.link_duplex == ETH_LINK_FULL_DUPLEX) { - if (link.link_speed == ETH_SPEED_NUM_10M) { - *current = NETDEV_F_10MB_FD; - } - if (link.link_speed == ETH_SPEED_NUM_100M) { - *current = NETDEV_F_100MB_FD; - } - if (link.link_speed == ETH_SPEED_NUM_1G) { - *current = NETDEV_F_1GB_FD; - } - if (link.link_speed == ETH_SPEED_NUM_10G) { - *current = NETDEV_F_10GB_FD; + /* Match against OpenFlow defined link speed values. */ + if (link.link_duplex == ETH_LINK_FULL_DUPLEX) { + switch (link.link_speed) { + case ETH_SPEED_NUM_10M: + feature |= NETDEV_F_10MB_FD; + break; + case ETH_SPEED_NUM_100M: + feature |= NETDEV_F_100MB_FD; + break; + case ETH_SPEED_NUM_1G: + feature |= NETDEV_F_1GB_FD; + break; + case ETH_SPEED_NUM_10G: + feature |= NETDEV_F_10GB_FD; + break; + case ETH_SPEED_NUM_40G: + feature |= NETDEV_F_40GB_FD; + break; + case ETH_SPEED_NUM_100G: + feature |= NETDEV_F_100GB_FD; + break; + default: + feature |= NETDEV_F_OTHER; } - if (link.link_speed == ETH_SPEED_NUM_40G) { - *current = NETDEV_F_40GB_FD; + } else if (link.link_duplex == ETH_LINK_HALF_DUPLEX) { + switch (link.link_speed) { + case ETH_SPEED_NUM_10M: + feature |= NETDEV_F_10MB_HD; + break; + case ETH_SPEED_NUM_100M: + feature |= NETDEV_F_100MB_HD; + break; + case ETH_SPEED_NUM_1G: + feature |= NETDEV_F_1GB_HD; + break; + default: + feature |= NETDEV_F_OTHER; } } if (link.link_autoneg) { - *current |= NETDEV_F_AUTONEG; + feature |= NETDEV_F_AUTONEG; } + *current = feature; *advertised = *supported = *peer = 0; return 0; @@ -2909,6 +2943,26 @@ } if (dev->type == DPDK_DEV_ETH) { + + if ((dev->flags ^ *old_flagsp) & NETDEV_UP) { + int err; + + if (dev->flags & NETDEV_UP) { + err = rte_eth_dev_set_link_up(dev->port_id); + } else { + err = rte_eth_dev_set_link_down(dev->port_id); + } + if (err == -ENOTSUP) { + VLOG_INFO("Interface %s does not support link state " + "configuration", netdev_get_name(&dev->up)); + } else if (err < 0) { + VLOG_ERR("Interface %s link change error: %s", + netdev_get_name(&dev->up), rte_strerror(-err)); + dev->flags = *old_flagsp; + return -err; + } + } + if (dev->flags & NETDEV_PROMISC) { rte_eth_promiscuous_enable(dev->port_id); } @@ -3253,9 +3307,17 @@ } } - VLOG_DBG("TX queue mapping for %s\n", dev->vhost_id); - for (i = 0; i < total_txqs; i++) { - VLOG_DBG("%2d --> %2d", i, dev->tx_q[i].map); + if (VLOG_IS_DBG_ENABLED()) { + struct ds mapping = DS_EMPTY_INITIALIZER; + + ds_put_format(&mapping, "TX queue mapping for port '%s':\n", + netdev_get_name(&dev->up)); + for (i = 0; i < total_txqs; i++) { + ds_put_format(&mapping, "%2d --> %2d\n", i, dev->tx_q[i].map); + } + + VLOG_DBG("%s", ds_cstr(&mapping)); + ds_destroy(&mapping); } free(enabled_queues); @@ -3423,7 +3485,7 @@ ovs_mutex_unlock(&dpdk_mutex); if (exists) { - VLOG_INFO("State of queue %d ( tx_qid %d ) of vhost device '%s'" + VLOG_INFO("State of queue %d ( tx_qid %d ) of vhost device '%s' " "changed to \'%s\'", queue_id, qid, ifname, (enable == 1) ? "enabled" : "disabled"); } else { @@ -4043,7 +4105,7 @@ if (ovs_u128_equals(*ufid, data->ufid)) { cmap_remove(&ufid_to_rte_flow, CONST_CAST(struct cmap_node *, &data->node), hash); - free(data); + ovsrcu_postpone(free, data); return; } } @@ -4072,28 +4134,38 @@ static void dump_flow_pattern(struct rte_flow_item *item) { + struct ds s; + + if (!VLOG_IS_DBG_ENABLED() || item->type == RTE_FLOW_ITEM_TYPE_END) { + return; + } + + ds_init(&s); + if (item->type == RTE_FLOW_ITEM_TYPE_ETH) { const struct rte_flow_item_eth *eth_spec = item->spec; const struct rte_flow_item_eth *eth_mask = item->mask; - VLOG_DBG("rte flow eth pattern:\n"); + ds_put_cstr(&s, "rte flow eth pattern:\n"); if (eth_spec) { - VLOG_DBG(" Spec: src="ETH_ADDR_FMT", dst="ETH_ADDR_FMT", " + ds_put_format(&s, + " Spec: src="ETH_ADDR_FMT", dst="ETH_ADDR_FMT", " "type=0x%04" PRIx16"\n", ETH_ADDR_BYTES_ARGS(eth_spec->src.addr_bytes), ETH_ADDR_BYTES_ARGS(eth_spec->dst.addr_bytes), ntohs(eth_spec->type)); } else { - VLOG_DBG(" Spec = null\n"); + ds_put_cstr(&s, " Spec = null\n"); } if (eth_mask) { - VLOG_DBG(" Mask: src="ETH_ADDR_FMT", dst="ETH_ADDR_FMT", " + ds_put_format(&s, + " Mask: src="ETH_ADDR_FMT", dst="ETH_ADDR_FMT", " "type=0x%04"PRIx16"\n", ETH_ADDR_BYTES_ARGS(eth_mask->src.addr_bytes), ETH_ADDR_BYTES_ARGS(eth_mask->dst.addr_bytes), - eth_mask->type); + ntohs(eth_mask->type)); } else { - VLOG_DBG(" Mask = null\n"); + ds_put_cstr(&s, " Mask = null\n"); } } @@ -4101,19 +4173,21 @@ const struct rte_flow_item_vlan *vlan_spec = item->spec; const struct rte_flow_item_vlan *vlan_mask = item->mask; - VLOG_DBG("rte flow vlan pattern:\n"); + ds_put_cstr(&s, "rte flow vlan pattern:\n"); if (vlan_spec) { - VLOG_DBG(" Spec: tpid=0x%"PRIx16", tci=0x%"PRIx16"\n", + ds_put_format(&s, + " Spec: tpid=0x%"PRIx16", tci=0x%"PRIx16"\n", ntohs(vlan_spec->tpid), ntohs(vlan_spec->tci)); } else { - VLOG_DBG(" Spec = null\n"); + ds_put_cstr(&s, " Spec = null\n"); } if (vlan_mask) { - VLOG_DBG(" Mask: tpid=0x%"PRIx16", tci=0x%"PRIx16"\n", + ds_put_format(&s, + " Mask: tpid=0x%"PRIx16", tci=0x%"PRIx16"\n", vlan_mask->tpid, vlan_mask->tci); } else { - VLOG_DBG(" Mask = null\n"); + ds_put_cstr(&s, " Mask = null\n"); } } @@ -4121,9 +4195,10 @@ const struct rte_flow_item_ipv4 *ipv4_spec = item->spec; const struct rte_flow_item_ipv4 *ipv4_mask = item->mask; - VLOG_DBG("rte flow ipv4 pattern:\n"); + ds_put_cstr(&s, "rte flow ipv4 pattern:\n"); if (ipv4_spec) { - VLOG_DBG(" Spec: tos=0x%"PRIx8", ttl=%"PRIx8", proto=0x%"PRIx8 + ds_put_format(&s, + " Spec: tos=0x%"PRIx8", ttl=%"PRIx8", proto=0x%"PRIx8 ", src="IP_FMT", dst="IP_FMT"\n", ipv4_spec->hdr.type_of_service, ipv4_spec->hdr.time_to_live, @@ -4131,10 +4206,11 @@ IP_ARGS(ipv4_spec->hdr.src_addr), IP_ARGS(ipv4_spec->hdr.dst_addr)); } else { - VLOG_DBG(" Spec = null\n"); + ds_put_cstr(&s, " Spec = null\n"); } if (ipv4_mask) { - VLOG_DBG(" Mask: tos=0x%"PRIx8", ttl=%"PRIx8", proto=0x%"PRIx8 + ds_put_format(&s, + " Mask: tos=0x%"PRIx8", ttl=%"PRIx8", proto=0x%"PRIx8 ", src="IP_FMT", dst="IP_FMT"\n", ipv4_mask->hdr.type_of_service, ipv4_mask->hdr.time_to_live, @@ -4142,7 +4218,7 @@ IP_ARGS(ipv4_mask->hdr.src_addr), IP_ARGS(ipv4_mask->hdr.dst_addr)); } else { - VLOG_DBG(" Mask = null\n"); + ds_put_cstr(&s, " Mask = null\n"); } } @@ -4150,20 +4226,22 @@ const struct rte_flow_item_udp *udp_spec = item->spec; const struct rte_flow_item_udp *udp_mask = item->mask; - VLOG_DBG("rte flow udp pattern:\n"); + ds_put_cstr(&s, "rte flow udp pattern:\n"); if (udp_spec) { - VLOG_DBG(" Spec: src_port=%"PRIu16", dst_port=%"PRIu16"\n", + ds_put_format(&s, + " Spec: src_port=%"PRIu16", dst_port=%"PRIu16"\n", ntohs(udp_spec->hdr.src_port), ntohs(udp_spec->hdr.dst_port)); } else { - VLOG_DBG(" Spec = null\n"); + ds_put_cstr(&s, " Spec = null\n"); } if (udp_mask) { - VLOG_DBG(" Mask: src_port=0x%"PRIx16", dst_port=0x%"PRIx16"\n", - udp_mask->hdr.src_port, - udp_mask->hdr.dst_port); + ds_put_format(&s, + " Mask: src_port=0x%"PRIx16", dst_port=0x%"PRIx16"\n", + ntohs(udp_mask->hdr.src_port), + ntohs(udp_mask->hdr.dst_port)); } else { - VLOG_DBG(" Mask = null\n"); + ds_put_cstr(&s, " Mask = null\n"); } } @@ -4171,20 +4249,22 @@ const struct rte_flow_item_sctp *sctp_spec = item->spec; const struct rte_flow_item_sctp *sctp_mask = item->mask; - VLOG_DBG("rte flow sctp pattern:\n"); + ds_put_cstr(&s, "rte flow sctp pattern:\n"); if (sctp_spec) { - VLOG_DBG(" Spec: src_port=%"PRIu16", dst_port=%"PRIu16"\n", + ds_put_format(&s, + " Spec: src_port=%"PRIu16", dst_port=%"PRIu16"\n", ntohs(sctp_spec->hdr.src_port), ntohs(sctp_spec->hdr.dst_port)); } else { - VLOG_DBG(" Spec = null\n"); + ds_put_cstr(&s, " Spec = null\n"); } if (sctp_mask) { - VLOG_DBG(" Mask: src_port=0x%"PRIx16", dst_port=0x%"PRIx16"\n", - sctp_mask->hdr.src_port, - sctp_mask->hdr.dst_port); + ds_put_format(&s, + " Mask: src_port=0x%"PRIx16", dst_port=0x%"PRIx16"\n", + ntohs(sctp_mask->hdr.src_port), + ntohs(sctp_mask->hdr.dst_port)); } else { - VLOG_DBG(" Mask = null\n"); + ds_put_cstr(&s, " Mask = null\n"); } } @@ -4192,20 +4272,22 @@ const struct rte_flow_item_icmp *icmp_spec = item->spec; const struct rte_flow_item_icmp *icmp_mask = item->mask; - VLOG_DBG("rte flow icmp pattern:\n"); + ds_put_cstr(&s, "rte flow icmp pattern:\n"); if (icmp_spec) { - VLOG_DBG(" Spec: icmp_type=%"PRIu8", icmp_code=%"PRIu8"\n", + ds_put_format(&s, + " Spec: icmp_type=%"PRIu8", icmp_code=%"PRIu8"\n", icmp_spec->hdr.icmp_type, icmp_spec->hdr.icmp_code); } else { - VLOG_DBG(" Spec = null\n"); + ds_put_cstr(&s, " Spec = null\n"); } if (icmp_mask) { - VLOG_DBG(" Mask: icmp_type=0x%"PRIx8", icmp_code=0x%"PRIx8"\n", + ds_put_format(&s, + " Mask: icmp_type=0x%"PRIx8", icmp_code=0x%"PRIx8"\n", icmp_spec->hdr.icmp_type, icmp_spec->hdr.icmp_code); } else { - VLOG_DBG(" Mask = null\n"); + ds_put_cstr(&s, " Mask = null\n"); } } @@ -4213,28 +4295,33 @@ const struct rte_flow_item_tcp *tcp_spec = item->spec; const struct rte_flow_item_tcp *tcp_mask = item->mask; - VLOG_DBG("rte flow tcp pattern:\n"); + ds_put_cstr(&s, "rte flow tcp pattern:\n"); if (tcp_spec) { - VLOG_DBG(" Spec: src_port=%"PRIu16", dst_port=%"PRIu16 + ds_put_format(&s, + " Spec: src_port=%"PRIu16", dst_port=%"PRIu16 ", data_off=0x%"PRIx8", tcp_flags=0x%"PRIx8"\n", ntohs(tcp_spec->hdr.src_port), ntohs(tcp_spec->hdr.dst_port), tcp_spec->hdr.data_off, tcp_spec->hdr.tcp_flags); } else { - VLOG_DBG(" Spec = null\n"); + ds_put_cstr(&s, " Spec = null\n"); } if (tcp_mask) { - VLOG_DBG(" Mask: src_port=%"PRIx16", dst_port=%"PRIx16 + ds_put_format(&s, + " Mask: src_port=%"PRIx16", dst_port=%"PRIx16 ", data_off=0x%"PRIx8", tcp_flags=0x%"PRIx8"\n", - tcp_mask->hdr.src_port, - tcp_mask->hdr.dst_port, + ntohs(tcp_mask->hdr.src_port), + ntohs(tcp_mask->hdr.dst_port), tcp_mask->hdr.data_off, tcp_mask->hdr.tcp_flags); } else { - VLOG_DBG(" Mask = null\n"); + ds_put_cstr(&s, " Mask = null\n"); } } + + VLOG_DBG("%s", ds_cstr(&s)); + ds_destroy(&s); } static void @@ -4511,25 +4598,31 @@ add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_END, NULL, NULL); struct rte_flow_action_mark mark; + struct rte_flow_action_rss *rss; + mark.id = info->flow_mark; add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_MARK, &mark); - struct rte_flow_action_rss *rss; + ovs_mutex_lock(&dev->mutex); + rss = add_flow_rss_action(&actions, netdev); add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_END, NULL); flow = rte_flow_create(dev->port_id, &flow_attr, patterns.items, actions.actions, &error); + + ovs_mutex_unlock(&dev->mutex); + free(rss); if (!flow) { - VLOG_ERR("rte flow creat error: %u : message : %s\n", - error.type, error.message); + VLOG_ERR("%s: rte flow creat error: %u : message : %s\n", + netdev_get_name(netdev), error.type, error.message); ret = -1; goto out; } ufid_to_rte_flow_associate(ufid, flow); - VLOG_DBG("installed flow %p by ufid "UUID_FMT"\n", - flow, UUID_ARGS((struct uuid *)ufid)); + VLOG_DBG("%s: installed flow %p by ufid "UUID_FMT"\n", + netdev_get_name(netdev), flow, UUID_ARGS((struct uuid *)ufid)); out: free(patterns.items); @@ -4633,22 +4726,27 @@ } static int -netdev_dpdk_destroy_rte_flow(struct netdev_dpdk *dev, +netdev_dpdk_destroy_rte_flow(struct netdev *netdev, const ovs_u128 *ufid, struct rte_flow *rte_flow) { + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); struct rte_flow_error error; int ret; + ovs_mutex_lock(&dev->mutex); + ret = rte_flow_destroy(dev->port_id, rte_flow, &error); if (ret == 0) { ufid_to_rte_flow_disassociate(ufid); - VLOG_DBG("removed rte flow %p associated with ufid " UUID_FMT "\n", - rte_flow, UUID_ARGS((struct uuid *)ufid)); + VLOG_DBG("%s: removed rte flow %p associated with ufid " UUID_FMT "\n", + netdev_get_name(netdev), rte_flow, + UUID_ARGS((struct uuid *)ufid)); } else { - VLOG_ERR("rte flow destroy error: %u : message : %s\n", - error.type, error.message); + VLOG_ERR("%s: rte flow destroy error: %u : message : %s\n", + netdev_get_name(netdev), error.type, error.message); } + ovs_mutex_unlock(&dev->mutex); return ret; } @@ -4666,8 +4764,7 @@ */ rte_flow = ufid_to_rte_flow_find(ufid); if (rte_flow) { - ret = netdev_dpdk_destroy_rte_flow(netdev_dpdk_cast(netdev), - ufid, rte_flow); + ret = netdev_dpdk_destroy_rte_flow(netdev, ufid, rte_flow); if (ret < 0) { return ret; } @@ -4692,165 +4789,92 @@ return -1; } - return netdev_dpdk_destroy_rte_flow(netdev_dpdk_cast(netdev), - ufid, rte_flow); + return netdev_dpdk_destroy_rte_flow(netdev, ufid, rte_flow); } -#define DPDK_FLOW_OFFLOAD_API \ - NULL, /* flow_flush */ \ - NULL, /* flow_dump_create */ \ - NULL, /* flow_dump_destroy */ \ - NULL, /* flow_dump_next */ \ - netdev_dpdk_flow_put, \ - NULL, /* flow_get */ \ - netdev_dpdk_flow_del, \ - NULL /* init_flow_api */ - - -#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, \ - SET_CONFIG, SET_TX_MULTIQ, SEND, \ - GET_CARRIER, GET_STATS, \ - GET_CUSTOM_STATS, \ - GET_FEATURES, GET_STATUS, \ - RECONFIGURE, RXQ_RECV) \ -{ \ - NAME, \ - true, /* is_pmd */ \ - INIT, /* init */ \ - NULL, /* netdev_dpdk_run */ \ - NULL, /* netdev_dpdk_wait */ \ - \ - netdev_dpdk_alloc, \ - CONSTRUCT, \ - DESTRUCT, \ - netdev_dpdk_dealloc, \ - netdev_dpdk_get_config, \ - SET_CONFIG, \ - NULL, /* get_tunnel_config */ \ - NULL, /* build header */ \ - NULL, /* push header */ \ - NULL, /* pop header */ \ - netdev_dpdk_get_numa_id, /* get_numa_id */ \ - SET_TX_MULTIQ, \ - \ - SEND, /* send */ \ - NULL, /* send_wait */ \ - \ - netdev_dpdk_set_etheraddr, \ - netdev_dpdk_get_etheraddr, \ - netdev_dpdk_get_mtu, \ - netdev_dpdk_set_mtu, \ - netdev_dpdk_get_ifindex, \ - GET_CARRIER, \ - netdev_dpdk_get_carrier_resets, \ - netdev_dpdk_set_miimon, \ - GET_STATS, \ - GET_CUSTOM_STATS, \ - GET_FEATURES, \ - NULL, /* set_advertisements */ \ - NULL, /* get_pt_mode */ \ - \ - netdev_dpdk_set_policing, \ - netdev_dpdk_get_qos_types, \ - NULL, /* get_qos_capabilities */ \ - netdev_dpdk_get_qos, \ - netdev_dpdk_set_qos, \ - NULL, /* get_queue */ \ - NULL, /* set_queue */ \ - NULL, /* delete_queue */ \ - NULL, /* get_queue_stats */ \ - NULL, /* queue_dump_start */ \ - NULL, /* queue_dump_next */ \ - NULL, /* queue_dump_done */ \ - NULL, /* dump_queue_stats */ \ - \ - NULL, /* set_in4 */ \ - NULL, /* get_addr_list */ \ - NULL, /* add_router */ \ - NULL, /* get_next_hop */ \ - GET_STATUS, \ - NULL, /* arp_lookup */ \ - \ - netdev_dpdk_update_flags, \ - RECONFIGURE, \ - \ - netdev_dpdk_rxq_alloc, \ - netdev_dpdk_rxq_construct, \ - netdev_dpdk_rxq_destruct, \ - netdev_dpdk_rxq_dealloc, \ - RXQ_RECV, \ - NULL, /* rx_wait */ \ - NULL, /* rxq_drain */ \ - DPDK_FLOW_OFFLOAD_API, \ - NULL /* get_block_id */ \ -} - -static const struct netdev_class dpdk_class = - NETDEV_DPDK_CLASS( - "dpdk", - netdev_dpdk_class_init, - netdev_dpdk_construct, - netdev_dpdk_destruct, - netdev_dpdk_set_config, - netdev_dpdk_set_tx_multiq, - netdev_dpdk_eth_send, - netdev_dpdk_get_carrier, - netdev_dpdk_get_stats, - netdev_dpdk_get_custom_stats, - netdev_dpdk_get_features, - netdev_dpdk_get_status, - netdev_dpdk_reconfigure, - netdev_dpdk_rxq_recv); - -static const struct netdev_class dpdk_ring_class = - NETDEV_DPDK_CLASS( - "dpdkr", - netdev_dpdk_class_init, - netdev_dpdk_ring_construct, - netdev_dpdk_destruct, - netdev_dpdk_ring_set_config, - netdev_dpdk_set_tx_multiq, - netdev_dpdk_ring_send, - netdev_dpdk_get_carrier, - netdev_dpdk_get_stats, - netdev_dpdk_get_custom_stats, - netdev_dpdk_get_features, - netdev_dpdk_get_status, - netdev_dpdk_reconfigure, - netdev_dpdk_rxq_recv); - -static const struct netdev_class dpdk_vhost_class = - NETDEV_DPDK_CLASS( - "dpdkvhostuser", - NULL, - netdev_dpdk_vhost_construct, - netdev_dpdk_vhost_destruct, - NULL, - NULL, - netdev_dpdk_vhost_send, - netdev_dpdk_vhost_get_carrier, - netdev_dpdk_vhost_get_stats, - NULL, - NULL, - netdev_dpdk_vhost_user_get_status, - netdev_dpdk_vhost_reconfigure, - netdev_dpdk_vhost_rxq_recv); -static const struct netdev_class dpdk_vhost_client_class = - NETDEV_DPDK_CLASS( - "dpdkvhostuserclient", - NULL, - netdev_dpdk_vhost_client_construct, - netdev_dpdk_vhost_destruct, - netdev_dpdk_vhost_client_set_config, - NULL, - netdev_dpdk_vhost_send, - netdev_dpdk_vhost_get_carrier, - netdev_dpdk_vhost_get_stats, - NULL, - NULL, - netdev_dpdk_vhost_user_get_status, - netdev_dpdk_vhost_client_reconfigure, - netdev_dpdk_vhost_rxq_recv); +#define DPDK_FLOW_OFFLOAD_API \ + .flow_put = netdev_dpdk_flow_put, \ + .flow_del = netdev_dpdk_flow_del + +#define NETDEV_DPDK_CLASS_COMMON \ + .is_pmd = true, \ + .alloc = netdev_dpdk_alloc, \ + .dealloc = netdev_dpdk_dealloc, \ + .get_config = netdev_dpdk_get_config, \ + .get_numa_id = netdev_dpdk_get_numa_id, \ + .set_etheraddr = netdev_dpdk_set_etheraddr, \ + .get_etheraddr = netdev_dpdk_get_etheraddr, \ + .get_mtu = netdev_dpdk_get_mtu, \ + .set_mtu = netdev_dpdk_set_mtu, \ + .get_ifindex = netdev_dpdk_get_ifindex, \ + .get_carrier_resets = netdev_dpdk_get_carrier_resets, \ + .set_miimon_interval = netdev_dpdk_set_miimon, \ + .set_policing = netdev_dpdk_set_policing, \ + .get_qos_types = netdev_dpdk_get_qos_types, \ + .get_qos = netdev_dpdk_get_qos, \ + .set_qos = netdev_dpdk_set_qos, \ + .update_flags = netdev_dpdk_update_flags, \ + .rxq_alloc = netdev_dpdk_rxq_alloc, \ + .rxq_construct = netdev_dpdk_rxq_construct, \ + .rxq_destruct = netdev_dpdk_rxq_destruct, \ + .rxq_dealloc = netdev_dpdk_rxq_dealloc + +#define NETDEV_DPDK_CLASS_BASE \ + NETDEV_DPDK_CLASS_COMMON, \ + .init = netdev_dpdk_class_init, \ + .destruct = netdev_dpdk_destruct, \ + .set_tx_multiq = netdev_dpdk_set_tx_multiq, \ + .get_carrier = netdev_dpdk_get_carrier, \ + .get_stats = netdev_dpdk_get_stats, \ + .get_custom_stats = netdev_dpdk_get_custom_stats, \ + .get_features = netdev_dpdk_get_features, \ + .get_status = netdev_dpdk_get_status, \ + .reconfigure = netdev_dpdk_reconfigure, \ + .rxq_recv = netdev_dpdk_rxq_recv, \ + DPDK_FLOW_OFFLOAD_API + +static const struct netdev_class dpdk_class = { + .type = "dpdk", + NETDEV_DPDK_CLASS_BASE, + .construct = netdev_dpdk_construct, + .set_config = netdev_dpdk_set_config, + .send = netdev_dpdk_eth_send, +}; + +static const struct netdev_class dpdk_ring_class = { + .type = "dpdkr", + NETDEV_DPDK_CLASS_BASE, + .construct = netdev_dpdk_ring_construct, + .set_config = netdev_dpdk_ring_set_config, + .send = netdev_dpdk_ring_send, +}; + +static const struct netdev_class dpdk_vhost_class = { + .type = "dpdkvhostuser", + NETDEV_DPDK_CLASS_COMMON, + .construct = netdev_dpdk_vhost_construct, + .destruct = netdev_dpdk_vhost_destruct, + .send = netdev_dpdk_vhost_send, + .get_carrier = netdev_dpdk_vhost_get_carrier, + .get_stats = netdev_dpdk_vhost_get_stats, + .get_status = netdev_dpdk_vhost_user_get_status, + .reconfigure = netdev_dpdk_vhost_reconfigure, + .rxq_recv = netdev_dpdk_vhost_rxq_recv +}; + +static const struct netdev_class dpdk_vhost_client_class = { + .type = "dpdkvhostuserclient", + NETDEV_DPDK_CLASS_COMMON, + .construct = netdev_dpdk_vhost_client_construct, + .destruct = netdev_dpdk_vhost_destruct, + .set_config = netdev_dpdk_vhost_client_set_config, + .send = netdev_dpdk_vhost_send, + .get_carrier = netdev_dpdk_vhost_get_carrier, + .get_stats = netdev_dpdk_vhost_get_stats, + .get_status = netdev_dpdk_vhost_user_get_status, + .reconfigure = netdev_dpdk_vhost_client_reconfigure, + .rxq_recv = netdev_dpdk_vhost_rxq_recv +}; void netdev_dpdk_register(void) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-dummy.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-dummy.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-dummy.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-dummy.c 2020-03-11 16:15:44.000000000 +0000 @@ -1393,90 +1393,56 @@ /* Helper functions. */ -#define NETDEV_DUMMY_CLASS(NAME, PMD, RECOFIGURE) \ -{ \ - NAME, \ - PMD, /* is_pmd */ \ - NULL, /* init */ \ - netdev_dummy_run, \ - netdev_dummy_wait, \ - \ - netdev_dummy_alloc, \ - netdev_dummy_construct, \ - netdev_dummy_destruct, \ - netdev_dummy_dealloc, \ - netdev_dummy_get_config, \ - netdev_dummy_set_config, \ - NULL, /* get_tunnel_config */ \ - NULL, /* build header */ \ - NULL, /* push header */ \ - NULL, /* pop header */ \ - netdev_dummy_get_numa_id, \ - NULL, /* set_tx_multiq */ \ - \ - netdev_dummy_send, /* send */ \ - NULL, /* send_wait */ \ - \ - netdev_dummy_set_etheraddr, \ - netdev_dummy_get_etheraddr, \ - netdev_dummy_get_mtu, \ - netdev_dummy_set_mtu, \ - netdev_dummy_get_ifindex, \ - NULL, /* get_carrier */ \ - NULL, /* get_carrier_resets */ \ - NULL, /* get_miimon */ \ - netdev_dummy_get_stats, \ - netdev_dummy_get_custom_stats, \ - \ - NULL, /* get_features */ \ - NULL, /* set_advertisements */ \ - NULL, /* get_pt_mode */ \ - \ - NULL, /* set_policing */ \ - NULL, /* get_qos_types */ \ - NULL, /* get_qos_capabilities */ \ - NULL, /* get_qos */ \ - NULL, /* set_qos */ \ - netdev_dummy_get_queue, \ - NULL, /* set_queue */ \ - NULL, /* delete_queue */ \ - netdev_dummy_get_queue_stats, \ - netdev_dummy_queue_dump_start, \ - netdev_dummy_queue_dump_next, \ - netdev_dummy_queue_dump_done, \ - netdev_dummy_dump_queue_stats, \ - \ - NULL, /* set_in4 */ \ - netdev_dummy_get_addr_list, \ - NULL, /* add_router */ \ - NULL, /* get_next_hop */ \ - NULL, /* get_status */ \ - NULL, /* arp_lookup */ \ - \ - netdev_dummy_update_flags, \ - RECOFIGURE, \ - \ - netdev_dummy_rxq_alloc, \ - netdev_dummy_rxq_construct, \ - netdev_dummy_rxq_destruct, \ - netdev_dummy_rxq_dealloc, \ - netdev_dummy_rxq_recv, \ - netdev_dummy_rxq_wait, \ - netdev_dummy_rxq_drain, \ - \ - NO_OFFLOAD_API, \ - NULL /* get_block_id */ \ -} +#define NETDEV_DUMMY_CLASS_COMMON \ + .run = netdev_dummy_run, \ + .wait = netdev_dummy_wait, \ + .alloc = netdev_dummy_alloc, \ + .construct = netdev_dummy_construct, \ + .destruct = netdev_dummy_destruct, \ + .dealloc = netdev_dummy_dealloc, \ + .get_config = netdev_dummy_get_config, \ + .set_config = netdev_dummy_set_config, \ + .get_numa_id = netdev_dummy_get_numa_id, \ + .send = netdev_dummy_send, \ + .set_etheraddr = netdev_dummy_set_etheraddr, \ + .get_etheraddr = netdev_dummy_get_etheraddr, \ + .get_mtu = netdev_dummy_get_mtu, \ + .set_mtu = netdev_dummy_set_mtu, \ + .get_ifindex = netdev_dummy_get_ifindex, \ + .get_stats = netdev_dummy_get_stats, \ + .get_custom_stats = netdev_dummy_get_custom_stats, \ + .get_queue = netdev_dummy_get_queue, \ + .get_queue_stats = netdev_dummy_get_queue_stats, \ + .queue_dump_start = netdev_dummy_queue_dump_start, \ + .queue_dump_next = netdev_dummy_queue_dump_next, \ + .queue_dump_done = netdev_dummy_queue_dump_done, \ + .dump_queue_stats = netdev_dummy_dump_queue_stats, \ + .get_addr_list = netdev_dummy_get_addr_list, \ + .update_flags = netdev_dummy_update_flags, \ + .rxq_alloc = netdev_dummy_rxq_alloc, \ + .rxq_construct = netdev_dummy_rxq_construct, \ + .rxq_destruct = netdev_dummy_rxq_destruct, \ + .rxq_dealloc = netdev_dummy_rxq_dealloc, \ + .rxq_recv = netdev_dummy_rxq_recv, \ + .rxq_wait = netdev_dummy_rxq_wait, \ + .rxq_drain = netdev_dummy_rxq_drain -static const struct netdev_class dummy_class = - NETDEV_DUMMY_CLASS("dummy", false, NULL); +static const struct netdev_class dummy_class = { + NETDEV_DUMMY_CLASS_COMMON, + .type = "dummy" +}; -static const struct netdev_class dummy_internal_class = - NETDEV_DUMMY_CLASS("dummy-internal", false, NULL); +static const struct netdev_class dummy_internal_class = { + NETDEV_DUMMY_CLASS_COMMON, + .type = "dummy-internal" +}; -static const struct netdev_class dummy_pmd_class = - NETDEV_DUMMY_CLASS("dummy-pmd", true, - netdev_dummy_reconfigure); +static const struct netdev_class dummy_pmd_class = { + NETDEV_DUMMY_CLASS_COMMON, + .type = "dummy-pmd", + .is_pmd = true, + .reconfigure = netdev_dummy_reconfigure +}; static void pkt_list_delete(struct ovs_list *l) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-linux.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-linux.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-linux.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-linux.c 2020-03-11 16:15:44.000000000 +0000 @@ -739,11 +739,14 @@ lag->block_id = block_id; lag->node = shash_add(&lag_shash, change->ifname, lag); + /* delete ingress block in case it exists */ + tc_add_del_ingress_qdisc(change->if_index, false, 0); /* LAG master is linux netdev so add slave to same block. */ error = tc_add_del_ingress_qdisc(change->if_index, true, block_id); if (error) { - VLOG_WARN("failed to bind LAG slave to master's block"); + VLOG_WARN("failed to bind LAG slave %s to master's block", + change->ifname); shash_delete(&lag_shash, lag->node); free(lag); } @@ -3158,113 +3161,77 @@ return error; } -#define NETDEV_LINUX_CLASS(NAME, CONSTRUCT, GET_STATS, \ - GET_FEATURES, GET_STATUS, \ - FLOW_OFFLOAD_API, GET_BLOCK_ID) \ -{ \ - NAME, \ - false, /* is_pmd */ \ - \ - NULL, \ - netdev_linux_run, \ - netdev_linux_wait, \ - \ - netdev_linux_alloc, \ - CONSTRUCT, \ - netdev_linux_destruct, \ - netdev_linux_dealloc, \ - NULL, /* get_config */ \ - NULL, /* set_config */ \ - NULL, /* get_tunnel_config */ \ - NULL, /* build header */ \ - NULL, /* push header */ \ - NULL, /* pop header */ \ - NULL, /* get_numa_id */ \ - NULL, /* set_tx_multiq */ \ - \ - netdev_linux_send, \ - netdev_linux_send_wait, \ - \ - netdev_linux_set_etheraddr, \ - netdev_linux_get_etheraddr, \ - netdev_linux_get_mtu, \ - netdev_linux_set_mtu, \ - netdev_linux_get_ifindex, \ - netdev_linux_get_carrier, \ - netdev_linux_get_carrier_resets, \ - netdev_linux_set_miimon_interval, \ - GET_STATS, \ - NULL, \ - \ - GET_FEATURES, \ - netdev_linux_set_advertisements, \ - NULL, /* get_pt_mode */ \ - \ - netdev_linux_set_policing, \ - netdev_linux_get_qos_types, \ - netdev_linux_get_qos_capabilities, \ - netdev_linux_get_qos, \ - netdev_linux_set_qos, \ - netdev_linux_get_queue, \ - netdev_linux_set_queue, \ - netdev_linux_delete_queue, \ - netdev_linux_get_queue_stats, \ - netdev_linux_queue_dump_start, \ - netdev_linux_queue_dump_next, \ - netdev_linux_queue_dump_done, \ - netdev_linux_dump_queue_stats, \ - \ - netdev_linux_set_in4, \ - netdev_linux_get_addr_list, \ - netdev_linux_add_router, \ - netdev_linux_get_next_hop, \ - GET_STATUS, \ - netdev_linux_arp_lookup, \ - \ - netdev_linux_update_flags, \ - NULL, /* reconfigure */ \ - \ - netdev_linux_rxq_alloc, \ - netdev_linux_rxq_construct, \ - netdev_linux_rxq_destruct, \ - netdev_linux_rxq_dealloc, \ - netdev_linux_rxq_recv, \ - netdev_linux_rxq_wait, \ - netdev_linux_rxq_drain, \ - \ - FLOW_OFFLOAD_API, \ - GET_BLOCK_ID \ -} - -const struct netdev_class netdev_linux_class = - NETDEV_LINUX_CLASS( - "system", - netdev_linux_construct, - netdev_linux_get_stats, - netdev_linux_get_features, - netdev_linux_get_status, - LINUX_FLOW_OFFLOAD_API, - netdev_linux_get_block_id); - -const struct netdev_class netdev_tap_class = - NETDEV_LINUX_CLASS( - "tap", - netdev_linux_construct_tap, - netdev_tap_get_stats, - netdev_linux_get_features, - netdev_linux_get_status, - NO_OFFLOAD_API, - NULL); - -const struct netdev_class netdev_internal_class = - NETDEV_LINUX_CLASS( - "internal", - netdev_linux_construct, - netdev_internal_get_stats, - NULL, /* get_features */ - netdev_internal_get_status, - NO_OFFLOAD_API, - NULL); +#define NETDEV_LINUX_CLASS_COMMON \ + .run = netdev_linux_run, \ + .wait = netdev_linux_wait, \ + .alloc = netdev_linux_alloc, \ + .destruct = netdev_linux_destruct, \ + .dealloc = netdev_linux_dealloc, \ + .send = netdev_linux_send, \ + .send_wait = netdev_linux_send_wait, \ + .set_etheraddr = netdev_linux_set_etheraddr, \ + .get_etheraddr = netdev_linux_get_etheraddr, \ + .get_mtu = netdev_linux_get_mtu, \ + .set_mtu = netdev_linux_set_mtu, \ + .get_ifindex = netdev_linux_get_ifindex, \ + .get_carrier = netdev_linux_get_carrier, \ + .get_carrier_resets = netdev_linux_get_carrier_resets, \ + .set_miimon_interval = netdev_linux_set_miimon_interval, \ + .set_advertisements = netdev_linux_set_advertisements, \ + .set_policing = netdev_linux_set_policing, \ + .get_qos_types = netdev_linux_get_qos_types, \ + .get_qos_capabilities = netdev_linux_get_qos_capabilities, \ + .get_qos = netdev_linux_get_qos, \ + .set_qos = netdev_linux_set_qos, \ + .get_queue = netdev_linux_get_queue, \ + .set_queue = netdev_linux_set_queue, \ + .delete_queue = netdev_linux_delete_queue, \ + .get_queue_stats = netdev_linux_get_queue_stats, \ + .queue_dump_start = netdev_linux_queue_dump_start, \ + .queue_dump_next = netdev_linux_queue_dump_next, \ + .queue_dump_done = netdev_linux_queue_dump_done, \ + .dump_queue_stats = netdev_linux_dump_queue_stats, \ + .set_in4 = netdev_linux_set_in4, \ + .get_addr_list = netdev_linux_get_addr_list, \ + .add_router = netdev_linux_add_router, \ + .get_next_hop = netdev_linux_get_next_hop, \ + .arp_lookup = netdev_linux_arp_lookup, \ + .update_flags = netdev_linux_update_flags, \ + .rxq_alloc = netdev_linux_rxq_alloc, \ + .rxq_construct = netdev_linux_rxq_construct, \ + .rxq_destruct = netdev_linux_rxq_destruct, \ + .rxq_dealloc = netdev_linux_rxq_dealloc, \ + .rxq_recv = netdev_linux_rxq_recv, \ + .rxq_wait = netdev_linux_rxq_wait, \ + .rxq_drain = netdev_linux_rxq_drain + +const struct netdev_class netdev_linux_class = { + NETDEV_LINUX_CLASS_COMMON, + LINUX_FLOW_OFFLOAD_API, + .type = "system", + .construct = netdev_linux_construct, + .get_stats = netdev_linux_get_stats, + .get_features = netdev_linux_get_features, + .get_status = netdev_linux_get_status, + .get_block_id = netdev_linux_get_block_id +}; + +const struct netdev_class netdev_tap_class = { + NETDEV_LINUX_CLASS_COMMON, + .type = "tap", + .construct = netdev_linux_construct_tap, + .get_stats = netdev_tap_get_stats, + .get_features = netdev_linux_get_features, + .get_status = netdev_linux_get_status, +}; + +const struct netdev_class netdev_internal_class = { + NETDEV_LINUX_CLASS_COMMON, + .type = "internal", + .construct = netdev_linux_construct, + .get_stats = netdev_internal_get_stats, + .get_status = netdev_internal_get_status, +}; #define CODEL_N_QUEUES 0x0000 @@ -3461,19 +3428,14 @@ } static const struct tc_ops tc_ops_codel = { - "codel", /* linux_name */ - "linux-codel", /* ovs_name */ - CODEL_N_QUEUES, /* n_queues */ - codel_tc_install, - codel_tc_load, - codel_tc_destroy, - codel_qdisc_get, - codel_qdisc_set, - NULL, - NULL, - NULL, - NULL, - NULL + .linux_name = "codel", + .ovs_name = "linux-codel", + .n_queues = CODEL_N_QUEUES, + .tc_install = codel_tc_install, + .tc_load = codel_tc_load, + .tc_destroy = codel_tc_destroy, + .qdisc_get = codel_qdisc_get, + .qdisc_set = codel_qdisc_set, }; /* FQ-CoDel traffic control class. */ @@ -3703,19 +3665,14 @@ } static const struct tc_ops tc_ops_fqcodel = { - "fq_codel", /* linux_name */ - "linux-fq_codel", /* ovs_name */ - FQCODEL_N_QUEUES, /* n_queues */ - fqcodel_tc_install, - fqcodel_tc_load, - fqcodel_tc_destroy, - fqcodel_qdisc_get, - fqcodel_qdisc_set, - NULL, - NULL, - NULL, - NULL, - NULL + .linux_name = "fq_codel", + .ovs_name = "linux-fq_codel", + .n_queues = FQCODEL_N_QUEUES, + .tc_install = fqcodel_tc_install, + .tc_load = fqcodel_tc_load, + .tc_destroy = fqcodel_tc_destroy, + .qdisc_get = fqcodel_qdisc_get, + .qdisc_set = fqcodel_qdisc_set, }; /* SFQ traffic control class. */ @@ -3845,7 +3802,7 @@ error = tc_parse_qdisc(nlmsg, &kind, &nlattr); if (error == 0) { sfq = nl_attr_get(nlattr); - sfq_install__(netdev, sfq->perturb_period, sfq->quantum); + sfq_install__(netdev, sfq->quantum, sfq->perturb_period); return 0; } @@ -3882,19 +3839,14 @@ } static const struct tc_ops tc_ops_sfq = { - "sfq", /* linux_name */ - "linux-sfq", /* ovs_name */ - SFQ_N_QUEUES, /* n_queues */ - sfq_tc_install, - sfq_tc_load, - sfq_tc_destroy, - sfq_qdisc_get, - sfq_qdisc_set, - NULL, - NULL, - NULL, - NULL, - NULL + .linux_name = "sfq", + .ovs_name = "linux-sfq", + .n_queues = SFQ_N_QUEUES, + .tc_install = sfq_tc_install, + .tc_load = sfq_tc_load, + .tc_destroy = sfq_tc_destroy, + .qdisc_get = sfq_qdisc_get, + .qdisc_set = sfq_qdisc_set, }; /* HTB traffic control class. */ @@ -4364,19 +4316,19 @@ } static const struct tc_ops tc_ops_htb = { - "htb", /* linux_name */ - "linux-htb", /* ovs_name */ - HTB_N_QUEUES, /* n_queues */ - htb_tc_install, - htb_tc_load, - htb_tc_destroy, - htb_qdisc_get, - htb_qdisc_set, - htb_class_get, - htb_class_set, - htb_class_delete, - htb_class_get_stats, - htb_class_dump_stats + .linux_name = "htb", + .ovs_name = "linux-htb", + .n_queues = HTB_N_QUEUES, + .tc_install = htb_tc_install, + .tc_load = htb_tc_load, + .tc_destroy = htb_tc_destroy, + .qdisc_get = htb_qdisc_get, + .qdisc_set = htb_qdisc_set, + .class_get = htb_class_get, + .class_set = htb_class_set, + .class_delete = htb_class_delete, + .class_get_stats = htb_class_get_stats, + .class_dump_stats = htb_class_dump_stats }; /* "linux-hfsc" traffic control class. */ @@ -4861,19 +4813,19 @@ } static const struct tc_ops tc_ops_hfsc = { - "hfsc", /* linux_name */ - "linux-hfsc", /* ovs_name */ - HFSC_N_QUEUES, /* n_queues */ - hfsc_tc_install, /* tc_install */ - hfsc_tc_load, /* tc_load */ - hfsc_tc_destroy, /* tc_destroy */ - hfsc_qdisc_get, /* qdisc_get */ - hfsc_qdisc_set, /* qdisc_set */ - hfsc_class_get, /* class_get */ - hfsc_class_set, /* class_set */ - hfsc_class_delete, /* class_delete */ - hfsc_class_get_stats, /* class_get_stats */ - hfsc_class_dump_stats /* class_dump_stats */ + .linux_name = "hfsc", + .ovs_name = "linux-hfsc", + .n_queues = HFSC_N_QUEUES, /* n_queues */ + .tc_install = hfsc_tc_install, + .tc_load = hfsc_tc_load, + .tc_destroy = hfsc_tc_destroy, + .qdisc_get = hfsc_qdisc_get, + .qdisc_set = hfsc_qdisc_set, + .class_get = hfsc_class_get, + .class_set = hfsc_class_set, + .class_delete = hfsc_class_delete, + .class_get_stats = hfsc_class_get_stats, + .class_dump_stats = hfsc_class_dump_stats, }; /* "linux-noop" traffic control class. */ @@ -4903,19 +4855,9 @@ } static const struct tc_ops tc_ops_noop = { - NULL, /* linux_name */ - "linux-noop", /* ovs_name */ - 0, /* n_queues */ - noop_tc_install, - noop_tc_load, - NULL, /* tc_destroy */ - NULL, /* qdisc_get */ - NULL, /* qdisc_set */ - NULL, /* class_get */ - NULL, /* class_set */ - NULL, /* class_delete */ - NULL, /* class_get_stats */ - NULL /* class_dump_stats */ + .ovs_name = "linux-noop", /* ovs_name */ + .tc_install = noop_tc_install, + .tc_load = noop_tc_load, }; /* "linux-default" traffic control class. @@ -4950,19 +4892,9 @@ } static const struct tc_ops tc_ops_default = { - NULL, /* linux_name */ - "", /* ovs_name */ - 0, /* n_queues */ - default_tc_install, - default_tc_load, - NULL, /* tc_destroy */ - NULL, /* qdisc_get */ - NULL, /* qdisc_set */ - NULL, /* class_get */ - NULL, /* class_set */ - NULL, /* class_delete */ - NULL, /* class_get_stats */ - NULL /* class_dump_stats */ + .ovs_name = "", /* ovs_name */ + .tc_install = default_tc_install, + .tc_load = default_tc_load, }; /* "linux-other" traffic control class. @@ -4982,19 +4914,8 @@ } static const struct tc_ops tc_ops_other = { - NULL, /* linux_name */ - "linux-other", /* ovs_name */ - 0, /* n_queues */ - NULL, /* tc_install */ - other_tc_load, - NULL, /* tc_destroy */ - NULL, /* qdisc_get */ - NULL, /* qdisc_set */ - NULL, /* class_get */ - NULL, /* class_set */ - NULL, /* class_delete */ - NULL, /* class_get_stats */ - NULL /* class_dump_stats */ + .ovs_name = "linux-other", + .tc_load = other_tc_load, }; /* Traffic control. */ @@ -5842,7 +5763,7 @@ * and the interface name statically stored in ovsdb. */ nl_msg_put_string(&request, IFLA_IFNAME, netdev_get_name(&netdev->up)); if (netdev_linux_netnsid_is_remote(netdev)) { - nl_msg_push_u32(&request, IFLA_IF_NETNSID, netdev->netnsid); + nl_msg_put_u32(&request, IFLA_IF_NETNSID, netdev->netnsid); } error = nl_transact(NETLINK_ROUTE, &request, &reply); ofpbuf_uninit(&request); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-linux.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-linux.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-linux.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-linux.h 2020-03-11 16:15:44.000000000 +0000 @@ -29,14 +29,14 @@ const char *flag_name, bool enable); int linux_get_ifindex(const char *netdev_name); -#define LINUX_FLOW_OFFLOAD_API \ - netdev_tc_flow_flush, \ - netdev_tc_flow_dump_create, \ - netdev_tc_flow_dump_destroy, \ - netdev_tc_flow_dump_next, \ - netdev_tc_flow_put, \ - netdev_tc_flow_get, \ - netdev_tc_flow_del, \ - netdev_tc_init_flow_api +#define LINUX_FLOW_OFFLOAD_API \ + .flow_flush = netdev_tc_flow_flush, \ + .flow_dump_create = netdev_tc_flow_dump_create, \ + .flow_dump_destroy = netdev_tc_flow_dump_destroy, \ + .flow_dump_next = netdev_tc_flow_dump_next, \ + .flow_put = netdev_tc_flow_put, \ + .flow_get = netdev_tc_flow_get, \ + .flow_del = netdev_tc_flow_del, \ + .init_flow_api = netdev_tc_init_flow_api #endif /* netdev-linux.h */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-provider.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-provider.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-provider.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-provider.h 2020-03-11 16:15:44.000000000 +0000 @@ -893,6 +893,4 @@ } #endif -#define NO_OFFLOAD_API NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL - #endif /* netdev.h */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-tc-offloads.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-tc-offloads.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-tc-offloads.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-tc-offloads.c 2020-03-11 16:15:44.000000000 +0000 @@ -163,8 +163,20 @@ ovs_mutex_unlock(&ufid_lock); } -/* Add ufid entry to ufid_tc hashmap. - * If entry exists already it will be replaced. */ +/* Wrapper function to delete filter and ufid tc mapping */ +static int +del_filter_and_ufid_mapping(int ifindex, int prio, int handle, + uint32_t block_id, const ovs_u128 *ufid) +{ + int err; + + err = tc_del_filter(ifindex, prio, handle, block_id); + del_ufid_tc_mapping(ufid); + + return err; +} + +/* Add ufid entry to ufid_tc hashmap. */ static void add_ufid_tc_mapping(const ovs_u128 *ufid, int prio, int handle, struct netdev *netdev, int ifindex) @@ -173,8 +185,6 @@ size_t tc_hash = hash_int(hash_int(prio, handle), ifindex); struct ufid_tc_data *new_data = xzalloc(sizeof *new_data); - del_ufid_tc_mapping(ufid); - new_data->ufid = *ufid; new_data->prio = prio; new_data->handle = handle; @@ -877,14 +887,18 @@ key->nw_proto == IPPROTO_ICMPV6) { if (mask->tp_src) { VLOG_DBG_RL(&rl, - "offloading attribute icmp_type isn't supported"); + "offloading attribute icmpv6_type isn't supported"); return EOPNOTSUPP; } if (mask->tp_dst) { VLOG_DBG_RL(&rl, - "offloading attribute icmp_code isn't supported"); + "offloading attribute icmpv6_code isn't supported"); return EOPNOTSUPP; } + } else if (key->dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE)) { + VLOG_DBG_RL(&rl, + "offloading of non-ethernet packets isn't supported"); + return EOPNOTSUPP; } if (!is_all_zeros(mask, sizeof *mask)) { @@ -956,10 +970,12 @@ && (vid_mask || pcp_mask)) { if (vid_mask) { flower.key.vlan_id = vlan_tci_to_vid(key->vlans[0].tci); + flower.mask.vlan_id = vlan_tci_to_vid(mask->vlans[0].tci); VLOG_DBG_RL(&rl, "vlan_id: %d\n", flower.key.vlan_id); } if (pcp_mask) { flower.key.vlan_prio = vlan_tci_to_pcp(key->vlans[0].tci); + flower.mask.vlan_prio = vlan_tci_to_pcp(mask->vlans[0].tci); VLOG_DBG_RL(&rl, "vlan_prio: %d\n", flower.key.vlan_prio); } flower.key.encap_eth_type = flower.key.eth_type; @@ -1057,14 +1073,19 @@ } } + /* ignore exact match on skb_mark of 0. */ + if (mask->pkt_mark == UINT32_MAX && !key->pkt_mark) { + mask->pkt_mark = 0; + } + err = test_key_and_mask(match); if (err) { return err; } NL_ATTR_FOR_EACH(nla, left, actions, actions_len) { - if (flower.action_count >= TCA_ACT_MAX_PRIO) { - VLOG_DBG_RL(&rl, "Can only support %d actions", flower.action_count); + if (flower.action_count >= TCA_ACT_MAX_NUM) { + VLOG_DBG_RL(&rl, "Can only support %d actions", TCA_ACT_MAX_NUM); return EOPNOTSUPP; } action = &flower.actions[flower.action_count]; @@ -1072,6 +1093,10 @@ odp_port_t port = nl_attr_get_odp_port(nla); struct netdev *outdev = netdev_ports_get(port, info->dpif_class); + if (!outdev) { + VLOG_DBG_RL(&rl, "Can't find netdev for output port %d", port); + return ENODEV; + } action->ifindex_out = netdev_get_ifindex(outdev); action->type = TC_ACT_OUTPUT; flower.action_count++; @@ -1117,7 +1142,7 @@ handle = get_ufid_tc_mapping(ufid, &prio, NULL); if (handle && prio) { VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", handle, prio); - tc_del_filter(ifindex, prio, handle, block_id); + del_filter_and_ufid_mapping(ifindex, prio, handle, block_id, ufid); } if (!prio) { @@ -1171,9 +1196,9 @@ return -ifindex; } - VLOG_DBG_RL(&rl, "flow get (dev %s prio %d handle %d)", - netdev_get_name(dev), prio, handle); - block_id = get_block_id_from_netdev(netdev); + block_id = get_block_id_from_netdev(dev); + VLOG_DBG_RL(&rl, "flow get (dev %s prio %d handle %d block_id %d)", + netdev_get_name(dev), prio, handle, block_id); err = tc_get_flower(ifindex, prio, handle, &flower, block_id); netdev_close(dev); if (err) { @@ -1217,7 +1242,7 @@ return -ifindex; } - block_id = get_block_id_from_netdev(netdev); + block_id = get_block_id_from_netdev(dev); if (stats) { memset(stats, 0, sizeof *stats); @@ -1228,8 +1253,7 @@ } } - error = tc_del_filter(ifindex, prio, handle, block_id); - del_ufid_tc_mapping(ufid); + error = del_filter_and_ufid_mapping(ifindex, prio, handle, block_id, ufid); netdev_close(dev); @@ -1282,6 +1306,7 @@ static void probe_tc_block_support(int ifindex) { + struct tc_flower flower; uint32_t block_id = 1; int error; @@ -1290,10 +1315,21 @@ return; } + memset(&flower, 0, sizeof flower); + + flower.key.eth_type = htons(ETH_P_IP); + flower.mask.eth_type = OVS_BE16_MAX; + memset(&flower.key.dst_mac, 0x11, sizeof flower.key.dst_mac); + memset(&flower.mask.dst_mac, 0xff, sizeof flower.mask.dst_mac); + + error = tc_replace_flower(ifindex, 1, 1, &flower, block_id); + tc_add_del_ingress_qdisc(ifindex, false, block_id); - block_support = true; - VLOG_INFO("probe tc: block offload is supported."); + if (!error) { + block_support = true; + VLOG_INFO("probe tc: block offload is supported."); + } } int @@ -1312,6 +1348,9 @@ return -ifindex; } + /* make sure there is no ingress qdisc */ + tc_add_del_ingress_qdisc(ifindex, false, 0); + if (ovsthread_once_start(&block_once)) { probe_tc_block_support(ifindex); ovsthread_once_done(&block_once); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-vport.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-vport.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netdev-vport.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netdev-vport.c 2020-03-11 16:15:44.000000000 +0000 @@ -936,7 +936,7 @@ } static int -get_stats(const struct netdev *netdev, struct netdev_stats *stats) +netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats) { struct netdev_vport *dev = netdev_vport_cast(netdev); @@ -952,7 +952,7 @@ } static enum netdev_pt_mode -get_pt_mode(const struct netdev *netdev) +netdev_vport_get_pt_mode(const struct netdev *netdev) { struct netdev_vport *dev = netdev_vport_cast(netdev); @@ -972,98 +972,32 @@ } #define NETDEV_VPORT_GET_IFINDEX netdev_vport_get_ifindex -#define NETDEV_FLOW_OFFLOAD_API LINUX_FLOW_OFFLOAD_API +#define NETDEV_FLOW_OFFLOAD_API , LINUX_FLOW_OFFLOAD_API #else /* !__linux__ */ #define NETDEV_VPORT_GET_IFINDEX NULL -#define NETDEV_FLOW_OFFLOAD_API NO_OFFLOAD_API +#define NETDEV_FLOW_OFFLOAD_API #endif /* __linux__ */ -#define VPORT_FUNCTIONS(GET_CONFIG, SET_CONFIG, \ - GET_TUNNEL_CONFIG, GET_STATUS, \ - BUILD_HEADER, \ - PUSH_HEADER, POP_HEADER, \ - GET_IFINDEX) \ - NULL, \ - netdev_vport_run, \ - netdev_vport_wait, \ - \ - netdev_vport_alloc, \ - netdev_vport_construct, \ - netdev_vport_destruct, \ - netdev_vport_dealloc, \ - GET_CONFIG, \ - SET_CONFIG, \ - GET_TUNNEL_CONFIG, \ - BUILD_HEADER, \ - PUSH_HEADER, \ - POP_HEADER, \ - NULL, /* get_numa_id */ \ - NULL, /* set_tx_multiq */ \ - \ - NULL, /* send */ \ - NULL, /* send_wait */ \ - \ - netdev_vport_set_etheraddr, \ - netdev_vport_get_etheraddr, \ - NULL, /* get_mtu */ \ - NULL, /* set_mtu */ \ - GET_IFINDEX, \ - NULL, /* get_carrier */ \ - NULL, /* get_carrier_resets */ \ - NULL, /* get_miimon */ \ - get_stats, \ - NULL, /* get_custom_stats */ \ - \ - NULL, /* get_features */ \ - NULL, /* set_advertisements */ \ - get_pt_mode, \ - \ - NULL, /* set_policing */ \ - NULL, /* get_qos_types */ \ - NULL, /* get_qos_capabilities */ \ - NULL, /* get_qos */ \ - NULL, /* set_qos */ \ - NULL, /* get_queue */ \ - NULL, /* set_queue */ \ - NULL, /* delete_queue */ \ - NULL, /* get_queue_stats */ \ - NULL, /* queue_dump_start */ \ - NULL, /* queue_dump_next */ \ - NULL, /* queue_dump_done */ \ - NULL, /* dump_queue_stats */ \ - \ - NULL, /* set_in4 */ \ - NULL, /* get_addr_list */ \ - NULL, /* add_router */ \ - NULL, /* get_next_hop */ \ - GET_STATUS, \ - NULL, /* arp_lookup */ \ - \ - netdev_vport_update_flags, \ - NULL, /* reconfigure */ \ - \ - NULL, /* rx_alloc */ \ - NULL, /* rx_construct */ \ - NULL, /* rx_destruct */ \ - NULL, /* rx_dealloc */ \ - NULL, /* rx_recv */ \ - NULL, /* rx_wait */ \ - NULL, /* rx_drain */ \ - \ - NETDEV_FLOW_OFFLOAD_API, \ - NULL /* get_block_id */ - - -#define TUNNEL_CLASS(NAME, DPIF_PORT, BUILD_HEADER, PUSH_HEADER, POP_HEADER, \ - GET_IFINDEX) \ - { DPIF_PORT, \ - { NAME, false, \ - VPORT_FUNCTIONS(get_tunnel_config, \ - set_tunnel_config, \ - get_netdev_tunnel_config, \ - tunnel_get_status, \ - BUILD_HEADER, PUSH_HEADER, POP_HEADER, \ - GET_IFINDEX) }} +#define VPORT_FUNCTIONS_COMMON \ + .run = netdev_vport_run, \ + .wait = netdev_vport_wait, \ + .alloc = netdev_vport_alloc, \ + .construct = netdev_vport_construct, \ + .destruct = netdev_vport_destruct, \ + .dealloc = netdev_vport_dealloc, \ + .set_etheraddr = netdev_vport_set_etheraddr, \ + .get_etheraddr = netdev_vport_get_etheraddr, \ + .get_stats = netdev_vport_get_stats, \ + .get_pt_mode = netdev_vport_get_pt_mode, \ + .update_flags = netdev_vport_update_flags \ + NETDEV_FLOW_OFFLOAD_API + +#define TUNNEL_FUNCTIONS_COMMON \ + VPORT_FUNCTIONS_COMMON, \ + .get_config = get_tunnel_config, \ + .set_config = set_tunnel_config, \ + .get_tunnel_config = get_netdev_tunnel_config, \ + .get_status = tunnel_get_status void netdev_vport_tunnel_register(void) @@ -1071,32 +1005,74 @@ /* The name of the dpif_port should be short enough to accomodate adding * a port number to the end if one is necessary. */ static const struct vport_class vport_classes[] = { - TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header, - netdev_tnl_push_udp_header, - netdev_geneve_pop_header, - NETDEV_VPORT_GET_IFINDEX), - TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header, - netdev_gre_push_header, - netdev_gre_pop_header, - NULL), - TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header, - netdev_tnl_push_udp_header, - netdev_vxlan_pop_header, - NETDEV_VPORT_GET_IFINDEX), - TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL, NULL), - TUNNEL_CLASS("stt", "stt_sys", NULL, NULL, NULL, NULL), - TUNNEL_CLASS("erspan", "erspan_sys", netdev_erspan_build_header, - netdev_erspan_push_header, - netdev_erspan_pop_header, - NULL), - TUNNEL_CLASS("ip6erspan", "ip6erspan_sys", netdev_erspan_build_header, - netdev_erspan_push_header, - netdev_erspan_pop_header, - NULL), - TUNNEL_CLASS("ip6gre", "ip6gre_sys", netdev_gre_build_header, - netdev_gre_push_header, - netdev_gre_pop_header, - NULL), + { "genev_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "geneve", + .build_header = netdev_geneve_build_header, + .push_header = netdev_tnl_push_udp_header, + .pop_header = netdev_geneve_pop_header, + .get_ifindex = NETDEV_VPORT_GET_IFINDEX, + } + }, + { "gre_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "gre", + .build_header = netdev_gre_build_header, + .push_header = netdev_gre_push_header, + .pop_header = netdev_gre_pop_header + } + }, + { "vxlan_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "vxlan", + .build_header = netdev_vxlan_build_header, + .push_header = netdev_tnl_push_udp_header, + .pop_header = netdev_vxlan_pop_header, + .get_ifindex = NETDEV_VPORT_GET_IFINDEX + } + }, + { "lisp_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "lisp" + } + }, + { "stt_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "stt" + } + }, + { "erspan_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "erspan", + .build_header = netdev_erspan_build_header, + .push_header = netdev_erspan_push_header, + .pop_header = netdev_erspan_pop_header + } + }, + { "ip6erspan_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "ip6erspan", + .build_header = netdev_erspan_build_header, + .push_header = netdev_erspan_push_header, + .pop_header = netdev_erspan_pop_header + } + }, + { "ip6gre_sys", + { + TUNNEL_FUNCTIONS_COMMON, + .type = "ip6gre", + .build_header = netdev_gre_build_header, + .push_header = netdev_gre_push_header, + .pop_header = netdev_gre_pop_header + } + }, }; static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; @@ -1117,12 +1093,13 @@ void netdev_vport_patch_register(void) { - static const struct vport_class patch_class = - { NULL, - { "patch", false, - VPORT_FUNCTIONS(get_patch_config, - set_patch_config, - NULL, - NULL, NULL, NULL, NULL, NULL) }}; + static const struct vport_class patch_class = { + NULL, + { VPORT_FUNCTIONS_COMMON, + .type = "patch", + .get_config = get_patch_config, + .set_config = set_patch_config, + } + }; netdev_register_provider(&patch_class.netdev_class); } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netlink-socket.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netlink-socket.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/netlink-socket.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/netlink-socket.c 2020-03-11 16:15:44.000000000 +0000 @@ -1571,6 +1571,11 @@ family_name = OVS_WIN_NETDEV_FAMILY; family_version = OVS_WIN_NETDEV_VERSION; family_attrmax = OVS_WIN_NETDEV_ATTR_MAX; + } else if (!strcmp(name, OVS_CT_LIMIT_FAMILY)) { + family_id = OVS_WIN_NL_CTLIMIT_FAMILY_ID; + family_name = OVS_CT_LIMIT_FAMILY; + family_version = OVS_CT_LIMIT_VERSION; + family_attrmax = OVS_CT_LIMIT_ATTR_MAX; } else { ofpbuf_delete(reply); return EINVAL; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/odp-util.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/odp-util.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/odp-util.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/odp-util.c 2020-03-11 16:15:44.000000000 +0000 @@ -1915,8 +1915,8 @@ s += n; retval = scan_u128(s, &ct_label.value, &ct_label.mask); - if (retval < 0) { - return retval; + if (retval == 0) { + return -EINVAL; } s += retval; continue; @@ -2104,14 +2104,14 @@ struct ofpbuf b; char buf[512]; size_t mdlen, padding; - if (ovs_scan_len(s, &n, "md2=0x%511[0-9a-fA-F]", buf)) { - ofpbuf_use_stub(&b, metadata, - NSH_CTX_HDRS_MAX_LEN); + if (ovs_scan_len(s, &n, "md2=0x%511[0-9a-fA-F]", buf) + && n/2 <= sizeof metadata) { + ofpbuf_use_stub(&b, metadata, sizeof metadata); ofpbuf_put_hex(&b, buf, &mdlen); /* Pad metadata to 4 bytes. */ padding = PAD_SIZE(mdlen, 4); if (padding > 0) { - ofpbuf_push_zeros(&b, padding); + ofpbuf_put_zeros(&b, padding); } md_size = mdlen + padding; ofpbuf_uninit(&b); @@ -2153,6 +2153,10 @@ n += retval; } + if (actions->size > UINT16_MAX) { + return -EFBIG; + } + return n; } @@ -2242,13 +2246,14 @@ key->nla_len += size; ofpbuf_put(actions, mask + 1, size); - /* Add new padding as needed */ - ofpbuf_put_zeros(actions, NLA_ALIGN(key->nla_len) - - key->nla_len); - /* 'actions' may have been reallocated by ofpbuf_put(). */ nested = ofpbuf_at_assert(actions, start_ofs, sizeof *nested); nested->nla_type = OVS_ACTION_ATTR_SET_MASKED; + + key = nested + 1; + /* Add new padding as needed */ + ofpbuf_put_zeros(actions, NLA_ALIGN(key->nla_len) - + key->nla_len); } } ofpbuf_uninit(&maskbuf); @@ -2558,6 +2563,8 @@ bool has_md1 = false; bool has_md2 = false; + memset(nsh_hdr, 0, size); + NL_NESTED_FOR_EACH (a, left, attr) { uint16_t type = nl_attr_type(a); size_t len = nl_attr_get_size(a); @@ -2695,7 +2702,7 @@ return ODP_FIT_TOO_MUCH; } - if (has_md1 && nsh->mdtype != NSH_M_TYPE1) { + if (has_md1 && nsh->mdtype != NSH_M_TYPE1 && !nsh_mask) { return ODP_FIT_ERROR; } @@ -4803,10 +4810,15 @@ const char *s_base = s; ovs_be16 id = 0, id_mask = 0; uint8_t flags = 0, flags_mask = 0; + int len; if (!strncmp(s, "id=", 3)) { s += 3; - s += scan_be16(s, &id, mask ? &id_mask : NULL); + len = scan_be16(s, &id, mask ? &id_mask : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; } if (s[0] == ',') { @@ -4814,7 +4826,11 @@ } if (!strncmp(s, "flags=", 6)) { s += 6; - s += scan_u8(s, &flags, mask ? &flags_mask : NULL); + len = scan_u8(s, &flags, mask ? &flags_mask : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; } if (!strncmp(s, "))", 2)) { @@ -4840,10 +4856,15 @@ uint32_t idx = 0, idx_mask = 0; uint8_t ver = 0, dir = 0, hwid = 0; uint8_t ver_mask = 0, dir_mask = 0, hwid_mask = 0; + int len; if (!strncmp(s, "ver=", 4)) { s += 4; - s += scan_u8(s, &ver, mask ? &ver_mask : NULL); + len = scan_u8(s, &ver, mask ? &ver_mask : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; } if (s[0] == ',') { @@ -4853,7 +4874,11 @@ if (ver == 1) { if (!strncmp(s, "idx=", 4)) { s += 4; - s += scan_u32(s, &idx, mask ? &idx_mask : NULL); + len = scan_u32(s, &idx, mask ? &idx_mask : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; } if (!strncmp(s, ")", 1)) { @@ -4869,14 +4894,22 @@ } else if (ver == 2) { if (!strncmp(s, "dir=", 4)) { s += 4; - s += scan_u8(s, &dir, mask ? &dir_mask : NULL); + len = scan_u8(s, &dir, mask ? &dir_mask : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; } if (s[0] == ',') { s++; } if (!strncmp(s, "hwid=", 5)) { s += 5; - s += scan_u8(s, &hwid, mask ? &hwid_mask : NULL); + len = scan_u8(s, &hwid, mask ? &hwid_mask : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; } if (!strncmp(s, ")", 1)) { @@ -4902,6 +4935,7 @@ struct geneve_opt *opt = key->d; struct geneve_opt *opt_mask = mask ? mask->d : NULL; int len_remain = sizeof key->d; + int len; while (s[0] == '{' && len_remain >= sizeof *opt) { int data_len = 0; @@ -4911,8 +4945,12 @@ if (!strncmp(s, "class=", 6)) { s += 6; - s += scan_be16(s, &opt->opt_class, - mask ? &opt_mask->opt_class : NULL); + len = scan_be16(s, &opt->opt_class, + mask ? &opt_mask->opt_class : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; } else if (mask) { memset(&opt_mask->opt_class, 0, sizeof opt_mask->opt_class); } @@ -4922,7 +4960,11 @@ } if (!strncmp(s, "type=", 5)) { s += 5; - s += scan_u8(s, &opt->type, mask ? &opt_mask->type : NULL); + len = scan_u8(s, &opt->type, mask ? &opt_mask->type : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; } else if (mask) { memset(&opt_mask->type, 0, sizeof opt_mask->type); } @@ -4933,7 +4975,11 @@ if (!strncmp(s, "len=", 4)) { uint8_t opt_len, opt_len_mask; s += 4; - s += scan_u8(s, &opt_len, mask ? &opt_len_mask : NULL); + len = scan_u8(s, &opt_len, mask ? &opt_len_mask : NULL); + if (len == 0) { + return -EINVAL; + } + s += len; if (opt_len > 124 || opt_len % 4 || opt_len > len_remain) { return 0; @@ -4978,7 +5024,7 @@ } if (s[0] == ')') { - int len = sizeof key->d - len_remain; + len = sizeof key->d - len_remain; s++; key->len = len; @@ -5363,13 +5409,6 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names, struct ofpbuf *key, struct ofpbuf *mask) { - /* Skip UFID. */ - ovs_u128 ufid; - int ufid_len = odp_ufid_from_string(s, &ufid); - if (ufid_len) { - return ufid_len; - } - SCAN_SINGLE("skb_priority(", uint32_t, u32, OVS_KEY_ATTR_PRIORITY); SCAN_SINGLE("skb_mark(", uint32_t, u32, OVS_KEY_ATTR_SKB_MARK); SCAN_SINGLE_FULLY_MASKED("recirc_id(", uint32_t, u32, @@ -5540,6 +5579,10 @@ if (retval < 0) { return retval; } + + if (nl_attr_oversized(key->size - encap - NLA_HDRLEN)) { + return -E2BIG; + } s += retval; } s++; @@ -5582,6 +5625,17 @@ return 0; } + /* Skip UFID. */ + ovs_u128 ufid; + retval = odp_ufid_from_string(s, &ufid); + if (retval < 0) { + key->size = old_size; + return -retval; + } else if (retval > 0) { + s += retval; + s += s[0] == ' ' ? 1 : 0; + } + retval = parse_odp_key_mask_attr(s, port_names, key, mask); if (retval < 0) { key->size = old_size; @@ -5675,26 +5729,28 @@ if (flow->ct_nw_proto) { if (parms->support.ct_orig_tuple && flow->dl_type == htons(ETH_TYPE_IP)) { - struct ovs_key_ct_tuple_ipv4 ct = { - data->ct_nw_src, - data->ct_nw_dst, - data->ct_tp_src, - data->ct_tp_dst, - data->ct_nw_proto, - }; - nl_msg_put_unspec(buf, OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4, &ct, - sizeof ct); + struct ovs_key_ct_tuple_ipv4 *ct; + + /* 'struct ovs_key_ct_tuple_ipv4' has padding, clear it. */ + ct = nl_msg_put_unspec_zero(buf, OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4, + sizeof *ct); + ct->ipv4_src = data->ct_nw_src; + ct->ipv4_dst = data->ct_nw_dst; + ct->src_port = data->ct_tp_src; + ct->dst_port = data->ct_tp_dst; + ct->ipv4_proto = data->ct_nw_proto; } else if (parms->support.ct_orig_tuple6 && flow->dl_type == htons(ETH_TYPE_IPV6)) { - struct ovs_key_ct_tuple_ipv6 ct = { - data->ct_ipv6_src, - data->ct_ipv6_dst, - data->ct_tp_src, - data->ct_tp_dst, - data->ct_nw_proto, - }; - nl_msg_put_unspec(buf, OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6, &ct, - sizeof ct); + struct ovs_key_ct_tuple_ipv6 *ct; + + /* 'struct ovs_key_ct_tuple_ipv6' has padding, clear it. */ + ct = nl_msg_put_unspec_zero(buf, OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6, + sizeof *ct); + ct->ipv6_src = data->ct_ipv6_src; + ct->ipv6_dst = data->ct_ipv6_dst; + ct->src_port = data->ct_tp_src; + ct->dst_port = data->ct_tp_dst; + ct->ipv6_proto = data->ct_nw_proto; } } if (parms->support.recirc) { @@ -6700,6 +6756,9 @@ flow->packet_type = nl_attr_get_be32(attrs[OVS_KEY_ATTR_PACKET_TYPE]); expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_PACKET_TYPE; + if (pt_ns(src_flow->packet_type) == OFPHTN_ETHERTYPE) { + flow->dl_type = pt_ns_type_be(flow->packet_type); + } } else if (!is_mask) { flow->packet_type = htonl(PT_ETH); } @@ -7260,6 +7319,7 @@ get_ipv6_key(&wc->masks, &mask, true); mask.ipv6_proto = 0; /* Not writeable. */ mask.ipv6_frag = 0; /* Not writable. */ + mask.ipv6_label &= htonl(IPV6_LABEL_MASK); /* Not writable. */ if (flow_tnl_dst_is_set(&base_flow->tunnel) && ((base_flow->nw_tos ^ flow->nw_tos) & IP_ECN_MASK) == 0) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-actions.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-actions.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-actions.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-actions.c 2020-03-11 16:15:44.000000000 +0000 @@ -824,7 +824,7 @@ } case NXAC2PT_USERDATA: - out->size = start_ofs + OFPACT_CONTROLLER_SIZE; + out->size = start_ofs + sizeof(struct ofpact_controller); ofpbuf_put(out, payload.msg, ofpbuf_msgsize(&payload)); oc = ofpbuf_at_assert(out, start_ofs, sizeof *oc); oc->userdata_len = ofpbuf_msgsize(&payload); @@ -8792,11 +8792,16 @@ ofpacts_parse(char *str, const struct ofpact_parse_params *pp, bool allow_instructions, enum ofpact_type outer_action) { + if (pp->depth >= MAX_OFPACT_PARSE_DEPTH) { + return xstrdup("Action nested too deeply"); + } + CONST_CAST(struct ofpact_parse_params *, pp)->depth++; uint32_t orig_size = pp->ofpacts->size; char *error = ofpacts_parse__(str, pp, allow_instructions, outer_action); if (error) { pp->ofpacts->size = orig_size; } + CONST_CAST(struct ofpact_parse_params *, pp)->depth--; return error; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofpbuf.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofpbuf.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofpbuf.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofpbuf.c 2020-03-11 16:15:44.000000000 +0000 @@ -469,9 +469,9 @@ ofpbuf_insert(struct ofpbuf *b, size_t offset, const void *data, size_t n) { if (offset < b->size) { - ofpbuf_put_uninit(b, n); + ofpbuf_put_uninit(b, n); /* b->size gets increased. */ memmove((char *) b->data + offset + n, (char *) b->data + offset, - b->size - offset); + b->size - offset - n); memcpy((char *) b->data + offset, data, n); } else { ovs_assert(offset == b->size); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-bundle.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-bundle.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-bundle.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-bundle.c 2020-03-11 16:15:44.000000000 +0000 @@ -65,7 +65,7 @@ request = ofputil_encode_flow_mod(&bms[i].fm, protocol); break; case OFPTYPE_GROUP_MOD: - request = ofputil_encode_group_mod(version, &bms[i].gm); + request = ofputil_encode_group_mod(version, &bms[i].gm, NULL, -1); break; case OFPTYPE_PACKET_OUT: request = ofputil_encode_packet_out(&bms[i].po, protocol); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-group.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-group.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-group.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-group.c 2020-03-11 16:15:44.000000000 +0000 @@ -1043,7 +1043,8 @@ } ovs_list_push_back(&gm->buckets, &bucket->list_node); - if (gm->type != OFPGT11_SELECT && bucket->weight) { + if (gm->command != OFPGC15_INSERT_BUCKET + && gm->type != OFPGT11_SELECT && bucket->weight) { error = xstrdup("Only select groups can have bucket weights."); goto out; } @@ -1189,7 +1190,7 @@ openflow, ofp_version); actions_len = openflow->size - actions_start; - if (group_type == OFPGT11_SELECT) { + if (group_type == OFPGT11_SELECT || bucket->weight) { ofpprop_put_u16(openflow, OFPGBPT15_WEIGHT, bucket->weight); } if (bucket->watch_port != OFPP_ANY) { @@ -1916,9 +1917,68 @@ ofputil_group_properties_destroy(&gm->props); } +static void +bad_group_cmd(enum ofp15_group_mod_command cmd) +{ + const char *opt_version; + const char *version; + const char *cmd_str; + + switch (cmd) { + case OFPGC15_ADD: + case OFPGC15_MODIFY: + case OFPGC15_ADD_OR_MOD: + case OFPGC15_DELETE: + version = "1.1"; + opt_version = "11"; + break; + + case OFPGC15_INSERT_BUCKET: + case OFPGC15_REMOVE_BUCKET: + version = "1.5"; + opt_version = "15"; + break; + + default: + OVS_NOT_REACHED(); + } + + switch (cmd) { + case OFPGC15_ADD: + cmd_str = "add-group"; + break; + + case OFPGC15_MODIFY: + case OFPGC15_ADD_OR_MOD: + cmd_str = "mod-group"; + break; + + case OFPGC15_DELETE: + cmd_str = "del-group"; + break; + + case OFPGC15_INSERT_BUCKET: + cmd_str = "insert-bucket"; + break; + + case OFPGC15_REMOVE_BUCKET: + cmd_str = "remove-bucket"; + break; + + default: + OVS_NOT_REACHED(); + } + + ovs_fatal(0, "%s needs OpenFlow %s or later (\'-O OpenFlow%s\')", + cmd_str, version, opt_version); + +} + static struct ofpbuf * ofputil_encode_ofp11_group_mod(enum ofp_version ofp_version, - const struct ofputil_group_mod *gm) + const struct ofputil_group_mod *gm, + const struct ovs_list *new_buckets, + int group_existed) { struct ofpbuf *b; struct ofp11_group_mod *ogm; @@ -1929,11 +1989,32 @@ start_ogm = b->size; ofpbuf_put_zeros(b, sizeof *ogm); - LIST_FOR_EACH (bucket, list_node, &gm->buckets) { + uint16_t command = gm->command; + const struct ovs_list *buckets = &gm->buckets; + switch (gm->command) { + case OFPGC15_INSERT_BUCKET: + case OFPGC15_REMOVE_BUCKET: + if (!new_buckets) { + bad_group_cmd(gm->command); + } + command = OFPGC11_MODIFY; + buckets = new_buckets; + break; + + case OFPGC11_ADD_OR_MOD: + if (group_existed >= 0) { + command = group_existed ? OFPGC11_MODIFY : OFPGC11_ADD; + } + break; + + default: + break; + } + LIST_FOR_EACH (bucket, list_node, buckets) { ofputil_put_ofp11_bucket(bucket, b, ofp_version); } ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm); - ogm->command = htons(gm->command); + ogm->command = htons(command); ogm->type = gm->type; ogm->group_id = htonl(gm->group_id); @@ -1942,7 +2023,8 @@ static struct ofpbuf * ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version, - const struct ofputil_group_mod *gm) + const struct ofputil_group_mod *gm, + int group_existed) { struct ofpbuf *b; struct ofp15_group_mod *ogm; @@ -1988,7 +2070,9 @@ ofputil_put_ofp15_bucket(bucket, bucket_id, gm->type, b, ofp_version); } ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm); - ogm->command = htons(gm->command); + ogm->command = htons(gm->command != OFPGC11_ADD_OR_MOD || group_existed < 0 + ? gm->command + : group_existed ? OFPGC11_MODIFY : OFPGC11_ADD); ogm->type = gm->type; ogm->group_id = htonl(gm->group_id); ogm->command_bucket_id = htonl(gm->command_bucket_id); @@ -2003,68 +2087,24 @@ return b; } -static void -bad_group_cmd(enum ofp15_group_mod_command cmd) -{ - const char *opt_version; - const char *version; - const char *cmd_str; - - switch (cmd) { - case OFPGC15_ADD: - case OFPGC15_MODIFY: - case OFPGC15_ADD_OR_MOD: - case OFPGC15_DELETE: - version = "1.1"; - opt_version = "11"; - break; - - case OFPGC15_INSERT_BUCKET: - case OFPGC15_REMOVE_BUCKET: - version = "1.5"; - opt_version = "15"; - break; - - default: - OVS_NOT_REACHED(); - } - - switch (cmd) { - case OFPGC15_ADD: - cmd_str = "add-group"; - break; - - case OFPGC15_MODIFY: - case OFPGC15_ADD_OR_MOD: - cmd_str = "mod-group"; - break; - - case OFPGC15_DELETE: - cmd_str = "del-group"; - break; - - case OFPGC15_INSERT_BUCKET: - cmd_str = "insert-bucket"; - break; - - case OFPGC15_REMOVE_BUCKET: - cmd_str = "remove-bucket"; - break; - - default: - OVS_NOT_REACHED(); - } - - ovs_fatal(0, "%s needs OpenFlow %s or later (\'-O OpenFlow%s\')", - cmd_str, version, opt_version); - -} - /* Converts abstract group mod 'gm' into a message for OpenFlow version - * 'ofp_version' and returns the message. */ + * 'ofp_version' and returns the message. + * + * If 'new_buckets' is nonnull, it should point to the full set of new buckets + * that resulted from a OFPGC15_INSERT_BUCKET or OFPGC15_REMOVE_BUCKET command. + * It is needed to translate such group_mods into OpenFlow 1.1-1.4 + * OFPGC11_MODIFY. If it is null but needed for translation, then encoding the + * group_mod will print an error on stderr and exit(). + * + * If 'group_existed' is nonnegative, it should specify whether the group + * existed before the command was executed. If it is nonnegative, then it is + * used to translate OVS's nonstandard OFPGC11_ADD_OR_MOD into a standard + * command. If it is negative, then OFPGC11_ADD_OR_MOD will be left as is. */ struct ofpbuf * ofputil_encode_group_mod(enum ofp_version ofp_version, - const struct ofputil_group_mod *gm) + const struct ofputil_group_mod *gm, + const struct ovs_list *new_buckets, + int group_existed) { switch (ofp_version) { @@ -2072,15 +2112,13 @@ case OFP12_VERSION: case OFP13_VERSION: case OFP14_VERSION: - if (gm->command > OFPGC11_DELETE && gm->command != OFPGC11_ADD_OR_MOD) { - bad_group_cmd(gm->command); - } - return ofputil_encode_ofp11_group_mod(ofp_version, gm); + return ofputil_encode_ofp11_group_mod(ofp_version, gm, + new_buckets, group_existed); case OFP10_VERSION: case OFP15_VERSION: case OFP16_VERSION: - return ofputil_encode_ofp15_group_mod(ofp_version, gm); + return ofputil_encode_ofp15_group_mod(ofp_version, gm, group_existed); default: OVS_NOT_REACHED(); @@ -2214,7 +2252,8 @@ struct ofputil_bucket *bucket; LIST_FOR_EACH (bucket, list_node, &gm->buckets) { - if (bucket->weight && gm->type != OFPGT11_SELECT) { + if (bucket->weight && gm->type != OFPGT11_SELECT + && gm->command != OFPGC15_INSERT_BUCKET) { return OFPERR_OFPGMFC_INVALID_GROUP; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-monitor.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-monitor.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-monitor.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-monitor.c 2020-03-11 16:15:44.000000000 +0000 @@ -796,7 +796,8 @@ switch (rf->reason) { case OFPRFR_GROUP_MOD: - inner = ofputil_encode_group_mod(ofp_version, rf->group_mod); + inner = ofputil_encode_group_mod(ofp_version, rf->group_mod, + rf->new_buckets, rf->group_existed); break; case OFPRFR_METER_MOD: @@ -829,6 +830,9 @@ ofputil_decode_requestforward(const struct ofp_header *outer, struct ofputil_requestforward *rf) { + rf->new_buckets = NULL; + rf->group_existed = -1; + struct ofpbuf b = ofpbuf_const_initializer(outer, ntohs(outer->length)); /* Skip past outer message. */ @@ -920,6 +924,7 @@ case OFPRFR_GROUP_MOD: ofputil_uninit_group_mod(rf->group_mod); free(rf->group_mod); + /* 'rf' does not own rf->new_buckets. */ break; case OFPRFR_METER_MOD: diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-packet.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-packet.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-packet.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-packet.c 2020-03-11 16:15:44.000000000 +0000 @@ -160,6 +160,7 @@ error = oxm_decode_match(payload.msg, ofpbuf_msgsize(&payload), loose, tun_table, vl_mff_map, &pin->flow_metadata); + pin->flow_metadata.flow.tunnel.metadata.tab = tun_table; break; case NXPINT_USERDATA: @@ -244,6 +245,7 @@ : NULL); enum ofperr error = oxm_pull_match_loose(&b, false, tun_table, &pin->flow_metadata); + pin->flow_metadata.flow.tunnel.metadata.tab = tun_table; if (error) { return error; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-port.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-port.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ofp-port.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ofp-port.c 2020-03-11 16:15:44.000000000 +0000 @@ -1698,6 +1698,7 @@ error = ofpprop_pull(&properties, &payload, &type); if (error) { + netdev_free_custom_stats_counters(&ops->custom_stats); return error; } switch (type) { @@ -1720,6 +1721,7 @@ } if (error) { + netdev_free_custom_stats_counters(&ops->custom_stats); return error; } } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ovsdb-data.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ovsdb-data.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ovsdb-data.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ovsdb-data.c 2020-03-11 16:15:44.000000000 +0000 @@ -1234,9 +1234,16 @@ n = inner->array.n; if (n < type->n_min || n > type->n_max) { - return ovsdb_syntax_error(json, NULL, "%s must have %u to " - "%u members but %"PRIuSIZE" are present", - class, type->n_min, type->n_max, n); + if (type->n_min == 1 && type->n_max == 1) { + return ovsdb_syntax_error(json, NULL, "%s must have exactly " + "one member but %"PRIuSIZE" " + "are present", class, n); + } else { + return ovsdb_syntax_error(json, NULL, "%s must have %u to " + "%u members but %"PRIuSIZE" are " + "present", + class, type->n_min, type->n_max, n); + } } datum->n = 0; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ovsdb-idl.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ovsdb-idl.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ovsdb-idl.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ovsdb-idl.c 2020-03-11 16:15:44.000000000 +0000 @@ -3806,6 +3806,13 @@ goto coverage_out; } + /* If we're still connecting or re-connecting, don't bother sending a + * transaction. */ + if (txn->db->idl->state != IDL_S_MONITORING) { + txn->status = TXN_TRY_AGAIN; + goto disassemble_out; + } + /* If we need a lock but don't have it, give up quickly. */ if (txn->db->lock_name && !txn->db->has_lock) { txn->status = TXN_NOT_LOCKED; @@ -4617,6 +4624,10 @@ if (error->type == JSON_STRING) { if (!strcmp(error->string, "timed out")) { soft_errors++; + } else if (!strcmp(error->string, + "unknown database")) { + ovsdb_idl_retry(db->idl); + soft_errors++; } else if (!strcmp(error->string, "not owner")) { lock_errors++; } else if (!strcmp(error->string, "not allowed")) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ovsdb-types.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ovsdb-types.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/ovsdb-types.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/ovsdb-types.h 2020-03-11 16:15:44.000000000 +0000 @@ -53,6 +53,27 @@ OVSDB_REF_WEAK /* Delete reference if target disappears. */ }; +struct ovsdb_integer_constraints { + int64_t min; /* minInteger or INT64_MIN. */ + int64_t max; /* maxInteger or INT64_MAX. */ +}; + +struct ovsdb_real_constraints { + double min; /* minReal or -DBL_MAX. */ + double max; /* minReal or DBL_MAX. */ +}; + +struct ovsdb_string_constraints { + unsigned int minLen; /* minLength or 0. */ + unsigned int maxLen; /* maxLength or UINT_MAX. */ +}; + +struct ovsdb_uuid_constraints { + char *refTableName; /* Name of referenced table, or NULL. */ + struct ovsdb_table *refTable; /* Referenced table, if available. */ + enum ovsdb_ref_type refType; /* Reference type. */ +}; + struct ovsdb_base_type { enum ovsdb_atomic_type type; @@ -61,28 +82,11 @@ struct ovsdb_datum *enum_; union { - struct ovsdb_integer_constraints { - int64_t min; /* minInteger or INT64_MIN. */ - int64_t max; /* maxInteger or INT64_MAX. */ - } integer; - - struct ovsdb_real_constraints { - double min; /* minReal or -DBL_MAX. */ - double max; /* minReal or DBL_MAX. */ - } real; - + struct ovsdb_integer_constraints integer; + struct ovsdb_real_constraints real; /* No constraints for Boolean types. */ - - struct ovsdb_string_constraints { - unsigned int minLen; /* minLength or 0. */ - unsigned int maxLen; /* maxLength or UINT_MAX. */ - } string; - - struct ovsdb_uuid_constraints { - char *refTableName; /* Name of referenced table, or NULL. */ - struct ovsdb_table *refTable; /* Referenced table, if available. */ - enum ovsdb_ref_type refType; /* Reference type. */ - } uuid; + struct ovsdb_string_constraints string; + struct ovsdb_uuid_constraints uuid; }; }; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/packets.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/packets.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/packets.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/packets.c 2020-03-11 16:15:44.000000000 +0000 @@ -1613,7 +1613,6 @@ struct ip6_hdr *nh = dp_packet_l3(b); nh->ip6_plen = htons(prev_l4_size + ND_PREFIX_OPT_LEN); - struct ovs_ra_msg *ra = dp_packet_l4(b); struct ovs_nd_prefix_opt *prefix_opt = dp_packet_put_uninit(b, sizeof *prefix_opt); prefix_opt->type = ND_OPT_PREFIX_INFORMATION; @@ -1625,6 +1624,7 @@ put_16aligned_be32(&prefix_opt->reserved, 0); memcpy(prefix_opt->prefix.be32, prefix.be32, sizeof(ovs_be32[4])); + struct ovs_ra_msg *ra = dp_packet_l4(b); ra->icmph.icmp6_cksum = 0; uint32_t icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b)); ra->icmph.icmp6_cksum = csum_finish(csum_continue( @@ -1662,7 +1662,7 @@ /* Calculate the IPv6 upper layer checksum according to RFC2460. We pass the ip6_nxt and ip6_plen values, so it will also work if extension headers are present. */ -uint16_t +ovs_be16 packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *ip6, const void *data, uint8_t l4_protocol, uint16_t l4_size) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/packets.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/packets.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/packets.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/packets.h 2020-03-11 16:15:44.000000000 +0000 @@ -744,6 +744,9 @@ }; BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header)); +/* ICMPV4 */ +#define ICMP_ERROR_DATA_L4_LEN 8 + #define IGMP_HEADER_LEN 8 struct igmp_header { uint8_t igmp_type; @@ -951,7 +954,7 @@ BUILD_ASSERT_DECL(ICMP6_ERROR_HEADER_LEN == sizeof(struct icmp6_error_header)); uint32_t packet_csum_pseudoheader6(const struct ovs_16aligned_ip6_hdr *); -uint16_t packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *, +ovs_be16 packet_csum_upperlayer6(const struct ovs_16aligned_ip6_hdr *, const void *, uint8_t, uint16_t); /* Neighbor Discovery option field. @@ -978,9 +981,6 @@ }; BUILD_ASSERT_DECL(ND_PREFIX_OPT_LEN == sizeof(struct ovs_nd_prefix_opt)); -#define ND_PREFIX_ON_LINK 0x80 -#define ND_PREFIX_AUTONOMOUS_ADDRESS 0x40 - /* Neighbor Discovery option: MTU. */ #define ND_MTU_OPT_LEN 8 #define ND_MTU_DEFAULT 0 diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/rconn.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/rconn.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/rconn.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/rconn.c 2020-03-11 16:15:44.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2019 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -502,7 +502,7 @@ timeout_CONNECTING(const struct rconn *rc) OVS_REQUIRES(rc->mutex) { - return MAX(1, rc->backoff); + return MAX(2, rc->backoff); } static void diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/reconnect.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/reconnect.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/reconnect.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/reconnect.c 2020-03-11 16:15:44.000000000 +0000 @@ -495,7 +495,7 @@ void reconnect_activity(struct reconnect *fsm, long long int now) { - if (fsm->state != S_ACTIVE) { + if (fsm->state == S_IDLE) { reconnect_transition__(fsm, now, S_ACTIVE); } fsm->last_activity = now; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/socket-util.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/socket-util.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/socket-util.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/socket-util.c 2020-03-11 16:15:44.000000000 +0000 @@ -285,7 +285,7 @@ } #endif if (retval == 1) { - if (pfd.revents & POLLERR) { + if (pfd.revents & (POLLERR | POLLHUP)) { ssize_t n = send(fd, "", 1, 0); if (n < 0) { return sock_errno(); @@ -518,12 +518,13 @@ * is optional and defaults to 'default_port' (use 0 to make the kernel choose * an available port, although this isn't usually appropriate for active * connections). If 'default_port' is negative, then is required. + * It resolves the host if 'resolve_host' is true. * * On success, returns true and stores the parsed remote address into '*ss'. * On failure, logs an error, stores zeros into '*ss', and returns false. */ bool inet_parse_active(const char *target_, int default_port, - struct sockaddr_storage *ss) + struct sockaddr_storage *ss, bool resolve_host) { char *target = xstrdup(target_); char *port, *host; @@ -538,7 +539,7 @@ ok = false; } else { ok = parse_sockaddr_components(ss, host, port, default_port, - target_, true); + target_, resolve_host); } if (!ok) { memset(ss, 0, sizeof *ss); @@ -575,7 +576,7 @@ int error; /* Parse. */ - if (!inet_parse_active(target, default_port, &ss)) { + if (!inet_parse_active(target, default_port, &ss, true)) { error = EAFNOSUPPORT; goto exit; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/socket-util.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/socket-util.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/socket-util.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/socket-util.h 2020-03-11 16:15:44.000000000 +0000 @@ -49,7 +49,7 @@ void inet_parse_host_port_tokens(char *s, char **hostp, char **portp); void inet_parse_port_host_tokens(char *s, char **portp, char **hostp); bool inet_parse_active(const char *target, int default_port, - struct sockaddr_storage *ssp); + struct sockaddr_storage *ssp, bool resolve_host); int inet_open_active(int style, const char *target, int default_port, struct sockaddr_storage *ssp, int *fdp, uint8_t dscp); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/stopwatch.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/stopwatch.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/stopwatch.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/stopwatch.c 2020-03-11 16:15:44.000000000 +0000 @@ -450,6 +450,7 @@ should_exit = true; break; } + free(pkt); } ovs_mutex_unlock(&stopwatches_lock); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/stream.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/stream.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/stream.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/stream.c 2020-03-11 16:15:44.000000000 +0000 @@ -751,7 +751,7 @@ struct sockaddr_storage *ss) { return ((!strncmp(target, "tcp:", 4) || !strncmp(target, "ssl:", 4)) - && inet_parse_active(target + 4, default_port, ss)); + && inet_parse_active(target + 4, default_port, ss, true)); } /* Attempts to guess the content type of a stream whose first few bytes were diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/stream-ssl.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/stream-ssl.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/stream-ssl.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/stream-ssl.c 2020-03-11 16:15:44.000000000 +0000 @@ -425,6 +425,7 @@ static char * get_peer_common_name(const struct ssl_stream *sslv) { + char *peer_name = NULL; X509 *peer_cert = SSL_get_peer_certificate(sslv->ssl); if (!peer_cert) { return NULL; @@ -433,18 +434,18 @@ int cn_index = X509_NAME_get_index_by_NID(X509_get_subject_name(peer_cert), NID_commonName, -1); if (cn_index < 0) { - return NULL; + goto error; } X509_NAME_ENTRY *cn_entry = X509_NAME_get_entry( X509_get_subject_name(peer_cert), cn_index); if (!cn_entry) { - return NULL; + goto error; } ASN1_STRING *cn_data = X509_NAME_ENTRY_get_data(cn_entry); if (!cn_data) { - return NULL; + goto error; } const char *cn; @@ -454,7 +455,11 @@ #else cn = (const char *)ASN1_STRING_get0_data(cn_data); #endif - return xstrdup(cn); + peer_name = xstrdup(cn); + +error: + X509_free(peer_cert); + return peer_name; } static int @@ -1157,7 +1162,7 @@ const char *certificate_file) { if (update_ssl_config(&private_key, private_key_file) - || update_ssl_config(&certificate, certificate_file)) { + && update_ssl_config(&certificate, certificate_file)) { stream_ssl_set_certificate_file__(certificate_file); stream_ssl_set_private_key_file__(private_key_file); } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/table.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/table.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/table.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/table.c 2020-03-11 16:15:44.000000000 +0000 @@ -236,15 +236,18 @@ } } +static bool first_table = true; + static void table_print_table__(const struct table *table, const struct table_style *style, struct ds *s) { - static int n = 0; int *widths; size_t x, y; - if (n++ > 0) { + if (first_table) { + first_table = false; + } else { ds_put_char(s, '\n'); } @@ -318,10 +321,11 @@ table_print_list__(const struct table *table, const struct table_style *style, struct ds *s) { - static int n = 0; size_t x, y; - if (n++ > 0) { + if (first_table) { + first_table = false; + } else { ds_put_char(s, '\n'); } @@ -469,10 +473,11 @@ table_print_csv__(const struct table *table, const struct table_style *style, struct ds *s) { - static int n = 0; size_t x, y; - if (n++ > 0) { + if (first_table) { + first_table = false; + } else { ds_put_char(s, '\n'); } @@ -614,6 +619,12 @@ } } +void +table_format_reset(void) +{ + first_table = true; +} + /* Outputs 'table' on stdout in the specified 'style'. */ void table_print(const struct table *table, const struct table_style *style) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/table.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/table.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/table.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/table.h 2020-03-11 16:15:44.000000000 +0000 @@ -133,6 +133,7 @@ void table_print(const struct table *, const struct table_style *); void table_format(const struct table *, const struct table_style *, struct ds *); +void table_format_reset(void); void table_usage(void); #endif /* table.h */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/tc.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/tc.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/tc.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/tc.c 2020-03-11 16:15:44.000000000 +0000 @@ -346,10 +346,12 @@ if (attrs[TCA_FLOWER_KEY_VLAN_ID]) { flower->key.vlan_id = nl_attr_get_u16(attrs[TCA_FLOWER_KEY_VLAN_ID]); + flower->mask.vlan_id = 0xffff; } if (attrs[TCA_FLOWER_KEY_VLAN_PRIO]) { flower->key.vlan_prio = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_VLAN_PRIO]); + flower->mask.vlan_prio = 0xff; } } @@ -932,7 +934,7 @@ nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower) { const struct nlattr *actions = attrs[TCA_FLOWER_ACT]; - static struct nl_policy actions_orders_policy[TCA_ACT_MAX_PRIO + 1] = {}; + static struct nl_policy actions_orders_policy[TCA_ACT_MAX_NUM + 1] = {}; struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)]; const int max_size = ARRAY_SIZE(actions_orders_policy); @@ -951,8 +953,8 @@ if (actions_orders[i]) { int err; - if (flower->action_count >= TCA_ACT_MAX_PRIO) { - VLOG_DBG_RL(&error_rl, "Can only support %d actions", flower->action_count); + if (flower->action_count >= TCA_ACT_MAX_NUM) { + VLOG_DBG_RL(&error_rl, "Can only support %d actions", TCA_ACT_MAX_NUM); return EOPNOTSUPP; } err = nl_parse_single_action(actions_orders[i], flower); @@ -1637,9 +1639,11 @@ nl_msg_put_be16(request, TCA_FLOWER_KEY_ETH_TYPE, flower->key.eth_type); if (is_vlan) { - if (flower->key.vlan_id || flower->key.vlan_prio) { + if (flower->key.vlan_id) { nl_msg_put_u16(request, TCA_FLOWER_KEY_VLAN_ID, flower->key.vlan_id); + } + if (flower->key.vlan_prio) { nl_msg_put_u8(request, TCA_FLOWER_KEY_VLAN_PRIO, flower->key.vlan_prio); } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/tc.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/tc.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/tc.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/tc.h 2020-03-11 16:15:44.000000000 +0000 @@ -148,6 +148,8 @@ TC_OFFLOADED_STATE_NOT_IN_HW, }; +#define TCA_ACT_MAX_NUM 16 + struct tc_flower { uint32_t handle; uint32_t prio; @@ -156,7 +158,7 @@ struct tc_flower_key mask; int action_count; - struct tc_action actions[TCA_ACT_MAX_PRIO]; + struct tc_action actions[TCA_ACT_MAX_NUM]; struct ovs_flow_stats stats; uint64_t lastused; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/wmi.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/wmi.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/lib/wmi.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/lib/wmi.c 2020-03-11 16:15:44.000000000 +0000 @@ -686,7 +686,7 @@ /* Check if the element already exists on the switch. */ wchar_t internal_port_query[WMI_QUERY_COUNT] = L"SELECT * FROM " - L"Msvm_InternalEthernetPort WHERE ElementName = \""; + L"CIM_EthernetPort WHERE ElementName = \""; wide_name = xmalloc((strlen(name) + 1) * sizeof(wchar_t)); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/NEWS openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/NEWS --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/NEWS 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/NEWS 2020-03-11 16:15:44.000000000 +0000 @@ -1,6 +1,23 @@ -v2.10.1 - xx xxx xxxx +v2.10.5 - xx xxx xxxx --------------------- + - DPDK + * OVS validated with DPDK 17.11.6 which is recommended to be used. +v2.10.4 - 06 Sep 2019 +--------------------- + - Fix compilation issue with Ubuntu kernel 4.15.60. + +v2.10.3 - 03 Sep 2019 +--------------------- + - Bug fixes + +v2.10.2 - 30 Mar 2019 +--------------------- + - Bug fixes + +v2.10.1 - 19 Oct 2018 +--------------------- + - Bug fixes v2.10.0 - 18 Aug 2018 --------------------- diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/bond.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/bond.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/bond.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/bond.c 2020-03-11 16:15:44.000000000 +0000 @@ -186,6 +186,7 @@ uint16_t vlan) OVS_REQ_RDLOCK(rwlock); static void update_recirc_rules__(struct bond *bond); +static bool bond_is_falling_back_to_ab(const struct bond *); /* Attempts to parse 's' as the name of a bond balancing mode. If successful, * stores the mode in '*balance' and returns true. Otherwise returns false @@ -648,6 +649,13 @@ if (bond->lacp_status != lacp_status) { bond->lacp_status = lacp_status; bond->bond_revalidate = true; + + /* Change in LACP status can affect whether the bond is falling back to + * active-backup. Make sure to create or destroy buckets if + * necessary. */ + if (bond_is_falling_back_to_ab(bond) || !bond->hash) { + bond_entry_reset(bond); + } } /* Enable slaves based on link status and LACP feedback. */ @@ -756,6 +764,15 @@ return packet; } + +static bool +bond_is_falling_back_to_ab(const struct bond *bond) +{ + return (bond->lacp_fallback_ab + && (bond->balance == BM_SLB || bond->balance == BM_TCP) + && bond->lacp_status == LACP_CONFIGURED); +} + /* Checks whether a packet that arrived on 'slave_' within 'bond', with an * Ethernet destination address of 'eth_dst', should be admitted. * @@ -927,7 +944,8 @@ static bool bond_may_recirc(const struct bond *bond) { - return bond->balance == BM_TCP && bond->recirc_id; + return (bond->balance == BM_TCP && bond->recirc_id + && !bond_is_falling_back_to_ab(bond)); } static void @@ -986,7 +1004,8 @@ bond_is_balanced(const struct bond *bond) OVS_REQ_RDLOCK(rwlock) { return bond->rebalance_interval - && (bond->balance == BM_SLB || bond->balance == BM_TCP); + && (bond->balance == BM_SLB || bond->balance == BM_TCP) + && !(bond->lacp_fallback_ab && bond->lacp_status == LACP_CONFIGURED); } /* Notifies 'bond' that 'n_bytes' bytes were sent in 'flow' within 'vlan'. */ @@ -1645,7 +1664,7 @@ static void bond_entry_reset(struct bond *bond) { - if (bond->balance != BM_AB) { + if (bond->balance != BM_AB && !bond_is_falling_back_to_ab(bond)) { size_t hash_len = BOND_BUCKETS * sizeof *bond->hash; if (!bond->hash) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/connmgr.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/connmgr.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/connmgr.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/connmgr.c 2020-03-11 16:15:44.000000000 +0000 @@ -1538,6 +1538,10 @@ ovs_assert(reason < 32); ovs_assert((unsigned int) type < OAM_N_TYPES); + if (!rconn_is_connected(ofconn->rconn)) { + return false; + } + /* Keep the following code in sync with the documentation in the * "Asynchronous Messages" section in 'topics/design' */ @@ -1965,7 +1969,7 @@ struct ofpbuf ofpacts; struct match match; - ofpbuf_init(&ofpacts, OFPACT_OUTPUT_SIZE); + ofpbuf_init(&ofpacts, sizeof(struct ofpact_output)); ofpact_put_OUTPUT(&ofpacts)->port = OFPP_NORMAL; match_init_catchall(&match); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/fail-open.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/fail-open.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/fail-open.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/fail-open.c 2020-03-11 16:15:44.000000000 +0000 @@ -163,7 +163,7 @@ /* Set up a flow that matches every packet and directs them to * OFPP_NORMAL. */ - ofpbuf_init(&ofpacts, OFPACT_OUTPUT_SIZE); + ofpbuf_init(&ofpacts, sizeof(struct ofpact_output)); ofpact_put_OUTPUT(&ofpacts)->port = OFPP_NORMAL; match_init_catchall(&match); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto.c 2020-03-11 16:15:44.000000000 +0000 @@ -2492,6 +2492,9 @@ { struct ofport *port = ofproto_get_port(ofproto, ofp_port); if (port) { + if (port->ofproto->ofproto_class->set_lldp) { + port->ofproto->ofproto_class->set_lldp(port, NULL); + } if (port->ofproto->ofproto_class->set_stp_port) { port->ofproto->ofproto_class->set_stp_port(port, NULL); } @@ -3548,9 +3551,20 @@ } static void +ofproto_packet_out_prepare(struct ofproto *ofproto, + struct ofproto_packet_out *opo) + OVS_REQUIRES(ofproto_mutex) +{ + ofproto->ofproto_class->packet_execute_prepare(ofproto, opo); +} + +/* Execution of packet_out action in datapath could end up in upcall with + * subsequent flow translations and possible rule modifications. + * So, the caller should not hold 'ofproto_mutex'. */ +static void ofproto_packet_out_finish(struct ofproto *ofproto, struct ofproto_packet_out *opo) - OVS_REQUIRES(ofproto_mutex) + OVS_EXCLUDED(ofproto_mutex) { ofproto->ofproto_class->packet_execute(ofproto, opo); } @@ -3593,10 +3607,13 @@ opo.version = p->tables_version; error = ofproto_packet_out_start(p, &opo); if (!error) { - ofproto_packet_out_finish(p, &opo); + ofproto_packet_out_prepare(p, &opo); } ovs_mutex_unlock(&ofproto_mutex); + if (!error) { + ofproto_packet_out_finish(p, &opo); + } ofproto_packet_out_uninit(&opo); return error; } @@ -7192,6 +7209,8 @@ *CONST_CAST(long long int *, &(new_group->created)) = old_group->created; *CONST_CAST(long long int *, &(new_group->modified)) = time_msec(); + *CONST_CAST(uint32_t *, &(new_group->n_buckets)) = + ovs_list_size(&(new_group->buckets)); group_collection_add(&ogm->old_groups, old_group); /* Mark the old group for deletion. */ @@ -7391,6 +7410,8 @@ rf.xid = req->request->xid; rf.reason = OFPRFR_GROUP_MOD; rf.group_mod = &ogm->gm; + rf.new_buckets = new_group ? &new_group->buckets : NULL; + rf.group_existed = group_collection_n(&ogm->old_groups) > 0; connmgr_send_requestforward(ofproto->connmgr, req->ofconn, &rf); } } @@ -7875,7 +7896,7 @@ } else if (be->type == OFPTYPE_GROUP_MOD) { ofproto_group_mod_finish(ofproto, &be->ogm, &req); } else if (be->type == OFPTYPE_PACKET_OUT) { - ofproto_packet_out_finish(ofproto, &be->opo); + ofproto_packet_out_prepare(ofproto, &be->opo); } } } @@ -7885,6 +7906,13 @@ ovs_mutex_unlock(&ofproto_mutex); } + /* Executing remaining datapath actions. */ + LIST_FOR_EACH (be, node, &bundle->msg_list) { + if (be->type == OFPTYPE_PACKET_OUT) { + ofproto_packet_out_finish(ofproto, &be->opo); + } + } + /* The bundle is discarded regardless the outcome. */ ofp_bundle_remove__(ofconn, bundle); return error; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif.c 2020-03-11 16:15:44.000000000 +0000 @@ -2239,24 +2239,24 @@ const struct smap *cfg) { struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto); int error = 0; if (cfg) { if (!ofport->lldp) { - struct ofproto_dpif *ofproto; - - ofproto = ofproto_dpif_cast(ofport->up.ofproto); ofproto->backer->need_revalidate = REV_RECONFIGURE; ofport->lldp = lldp_create(ofport->up.netdev, ofport_->mtu, cfg); } if (!lldp_configure(ofport->lldp, cfg)) { + lldp_unref(ofport->lldp); + ofport->lldp = NULL; error = EINVAL; } - } - if (error) { + } else if (ofport->lldp) { lldp_unref(ofport->lldp); ofport->lldp = NULL; + ofproto->backer->need_revalidate = REV_RECONFIGURE; } ofproto_dpif_monitor_port_update(ofport, @@ -3684,10 +3684,11 @@ } dp_port_name = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf); + if (!dpif_port_exists(ofproto->backer->dpif, dp_port_name)) { + odp_port_t port_no = ODPP_NONE; + int error; - odp_port_t port_no = ODPP_NONE; - int error = dpif_port_add(ofproto->backer->dpif, netdev, &port_no); - if (error != EEXIST && error != EBUSY) { + error = dpif_port_add(ofproto->backer->dpif, netdev, &port_no); if (error) { return error; } @@ -4676,12 +4677,13 @@ } static void -packet_execute(struct ofproto *ofproto_, struct ofproto_packet_out *opo) +packet_execute_prepare(struct ofproto *ofproto_, + struct ofproto_packet_out *opo) OVS_REQUIRES(ofproto_mutex) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); struct dpif_flow_stats stats; - struct dpif_execute execute; + struct dpif_execute *execute; struct ofproto_dpif_packet_out *aux = opo->aux; ovs_assert(aux); @@ -4690,22 +4692,40 @@ dpif_flow_stats_extract(opo->flow, opo->packet, time_msec(), &stats); ofproto_dpif_xcache_execute(ofproto, &aux->xcache, &stats); - execute.actions = aux->odp_actions.data; - execute.actions_len = aux->odp_actions.size; + execute = xzalloc(sizeof *execute); + execute->actions = xmemdup(aux->odp_actions.data, aux->odp_actions.size); + execute->actions_len = aux->odp_actions.size; pkt_metadata_from_flow(&opo->packet->md, opo->flow); - execute.packet = opo->packet; - execute.flow = opo->flow; - execute.needs_help = aux->needs_help; - execute.probe = false; - execute.mtu = 0; + execute->packet = opo->packet; + execute->flow = opo->flow; + execute->needs_help = aux->needs_help; + execute->probe = false; + execute->mtu = 0; /* Fix up in_port. */ ofproto_dpif_set_packet_odp_port(ofproto, opo->flow->in_port.ofp_port, opo->packet); - dpif_execute(ofproto->backer->dpif, &execute); ofproto_dpif_packet_out_delete(aux); + opo->aux = execute; +} + +static void +packet_execute(struct ofproto *ofproto_, struct ofproto_packet_out *opo) + OVS_EXCLUDED(ofproto_mutex) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + struct dpif_execute *execute = opo->aux; + + if (!execute) { + return; + } + + dpif_execute(ofproto->backer->dpif, execute); + + free(CONST_CAST(struct nlattr *, execute->actions)); + free(execute); opo->aux = NULL; } @@ -5051,18 +5071,29 @@ const struct ofputil_packet_in_private *pin) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + struct dpif_flow_stats stats; + struct xlate_cache xcache; + struct flow flow; + xlate_cache_init(&xcache); /* Translate pin into datapath actions. */ uint64_t odp_actions_stub[1024 / 8]; struct ofpbuf odp_actions = OFPBUF_STUB_INITIALIZER(odp_actions_stub); enum slow_path_reason slow; - enum ofperr error = xlate_resume(ofproto, pin, &odp_actions, &slow); + enum ofperr error = xlate_resume(ofproto, pin, &odp_actions, &slow, + &flow, &xcache); /* Steal 'pin->packet' and put it into a dp_packet. */ struct dp_packet packet; dp_packet_init(&packet, pin->base.packet_len); dp_packet_put(&packet, pin->base.packet, pin->base.packet_len); + /* Run the side effects from the xcache. */ + dpif_flow_stats_extract(&flow, &packet, time_msec(), &stats); + ovs_mutex_lock(&ofproto_mutex); + ofproto_dpif_xcache_execute(ofproto, &xcache, &stats); + ovs_mutex_unlock(&ofproto_mutex); + pkt_metadata_from_flow(&packet.md, &pin->base.flow_metadata.flow); /* Fix up in_port. */ @@ -5951,11 +5982,11 @@ /* Provider ID unknown. Use backer to allocate a new DP meter */ if (meter_id->uint32 == UINT32_MAX) { if (!ofproto->backer->meter_ids) { - return EFBIG; /* Datapath does not support meter. */ + return OFPERR_OFPMMFC_OUT_OF_METERS; /* Meters not supported. */ } if(!id_pool_alloc_id(ofproto->backer->meter_ids, &meter_id->uint32)) { - return ENOMEM; /* Can't allocate a DP meter. */ + return OFPERR_OFPMMFC_OUT_OF_METERS; /* Can't allocate meter. */ } } @@ -6069,6 +6100,7 @@ rule_get_stats, packet_xlate, packet_xlate_revert, + packet_execute_prepare, packet_execute, set_frag_handling, nxt_resume, diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-sflow.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-sflow.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-sflow.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-sflow.c 2020-03-11 16:15:44.000000000 +0000 @@ -468,15 +468,16 @@ const char *target; SSET_FOR_EACH (target, targets) { struct sockaddr_storage ss; - if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT, &ss)) { + if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT, &ss, true)) { /* sFlow only supports target in default routing table with * packet mark zero. */ - ip = ss_get_address(&ss); + struct in6_addr target_ip = ss_get_address(&ss); struct in6_addr gw, src = in6addr_any; char name[IFNAMSIZ]; - if (ovs_router_lookup(0, &ip, name, &src, &gw)) { + if (ovs_router_lookup(0, &target_ip, name, &src, &gw)) { + ip = src; goto success; } } @@ -1025,7 +1026,7 @@ sflow_actions->tunnel.ip_tos = key->ipv4_tos; } if (key->ipv4_ttl) { - sflow_actions->tunnel.ip_tos = key->ipv4_ttl; + sflow_actions->tunnel.ip_ttl = key->ipv4_ttl; } } break; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-trace.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-trace.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-trace.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-trace.c 2020-03-11 16:15:44.000000000 +0000 @@ -675,7 +675,7 @@ ds_put_format(output, "\nrecirc(%#"PRIx32")", recirc_node->recirc_id); - if (recirc_node->type == OFT_RECIRC_CONNTRACK) { + if (next_ct_states && recirc_node->type == OFT_RECIRC_CONNTRACK) { uint32_t ct_state; if (ovs_list_is_empty(next_ct_states)) { ct_state = CS_TRACKED | CS_NEW; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-upcall.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-upcall.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-upcall.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-upcall.c 2020-03-11 16:15:44.000000000 +0000 @@ -1021,7 +1021,6 @@ * initialized with at least 128 bytes of space. */ static void compose_slow_path(struct udpif *udpif, struct xlate_out *xout, - const struct flow *flow, odp_port_t odp_in_port, ofp_port_t ofp_in_port, struct ofpbuf *buf, uint32_t meter_id, struct uuid *ofproto_uuid) @@ -1030,6 +1029,7 @@ odp_port_t port; uint32_t pid; + memset(&cookie, 0, sizeof cookie); cookie.type = USER_ACTION_COOKIE_SLOW_PATH; cookie.ofp_in_port = ofp_in_port; cookie.ofproto_uuid = *ofproto_uuid; @@ -1038,7 +1038,7 @@ port = xout->slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP | SLOW_STP) ? ODPP_NONE : odp_in_port; - pid = dpif_port_get_pid(udpif->dpif, port, flow_hash_5tuple(flow, 0)); + pid = dpif_port_get_pid(udpif->dpif, port); size_t offset; size_t ac_offset; @@ -1196,7 +1196,7 @@ odp_actions->data, odp_actions->size); } else { /* upcall->put_actions already initialized by upcall_receive(). */ - compose_slow_path(udpif, &upcall->xout, upcall->flow, + compose_slow_path(udpif, &upcall->xout, upcall->flow->in_port.odp_port, upcall->ofp_in_port, &upcall->put_actions, upcall->ofproto->up.slowpath_meter_id, @@ -1757,7 +1757,7 @@ } reval_seq = seq_read(udpif->reval_seq) - 1; /* Ensure revalidation. */ - ofpbuf_use_const(&actions, &flow->actions, flow->actions_len); + ofpbuf_use_const(&actions, flow->actions, flow->actions_len); *ukey = ukey_create__(flow->key, flow->key_len, flow->mask, flow->mask_len, flow->ufid_present, &flow->ufid, flow->pmd_id, &actions, @@ -2155,7 +2155,7 @@ goto exit; } - compose_slow_path(udpif, xoutp, &ctx.flow, ctx.flow.in_port.odp_port, + compose_slow_path(udpif, xoutp, ctx.flow.in_port.odp_port, ofp_in_port, odp_actions, ofproto->up.slowpath_meter_id, &ofproto->uuid); } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-xlate.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-xlate.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-xlate.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-xlate.c 2020-03-11 16:15:44.000000000 +0000 @@ -534,6 +534,8 @@ static void clone_xlate_actions(const struct ofpact *, size_t ofpacts_len, struct xlate_ctx *, bool, bool); static void xlate_normal(struct xlate_ctx *); +static void xlate_normal_flood(struct xlate_ctx *ct, + struct xbundle *in_xbundle, struct xvlan *); static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port, uint8_t table_id, bool may_packet_in, bool honor_table_miss, bool with_ct_orig, @@ -2028,21 +2030,10 @@ return; } - if (ctx->xin->resubmit_stats) { - mirror_update_stats(xbridge->mbridge, mirrors, - ctx->xin->resubmit_stats->n_packets, - ctx->xin->resubmit_stats->n_bytes); - } - if (ctx->xin->xcache) { - struct xc_entry *entry; - - entry = xlate_cache_add_entry(ctx->xin->xcache, XC_MIRROR); - entry->mirror.mbridge = mbridge_ref(xbridge->mbridge); - entry->mirror.mirrors = mirrors; - } - - /* 'mirrors' is a bit-mask of candidates for mirroring. Iterate as long as - * some candidates remain. */ + /* 'mirrors' is a bit-mask of candidates for mirroring. Iterate through + * the candidates, adding the ones that really should be mirrored to + * 'used_mirrors', as long as some candidates remain. */ + mirror_mask_t used_mirrors = 0; while (mirrors) { const unsigned long *vlans; mirror_mask_t dup_mirrors; @@ -2066,6 +2057,9 @@ continue; } + /* We sent a packet to this mirror. */ + used_mirrors |= rightmost_1bit(mirrors); + /* Record the mirror, and the mirrors that output to the same * destination, so that we don't mirror to them again. This must be * done now to ensure that output_normal(), below, doesn't recursively @@ -2099,6 +2093,21 @@ mirrors &= ~ctx->mirrors; ctx->mirror_snaplen = 0; } + + if (used_mirrors) { + if (ctx->xin->resubmit_stats) { + mirror_update_stats(xbridge->mbridge, used_mirrors, + ctx->xin->resubmit_stats->n_packets, + ctx->xin->resubmit_stats->n_bytes); + } + if (ctx->xin->xcache) { + struct xc_entry *entry; + + entry = xlate_cache_add_entry(ctx->xin->xcache, XC_MIRROR); + entry->mirror.mbridge = mbridge_ref(xbridge->mbridge); + entry->mirror.mirrors = used_mirrors; + } + } } static void @@ -2662,6 +2671,53 @@ } ovs_rwlock_unlock(&ms->rwlock); } + +/* A list of multicast output ports. + * + * We accumulate output ports and then do all the outputs afterward. It would + * be more natural to do the outputs one at a time as we discover the need for + * each one, but this can cause a deadlock because we need to take the + * mcast_snooping's rwlock for reading to iterate through the port lists and + * doing an output, if it goes to a patch port, can eventually come back to the + * same mcast_snooping and attempt to take the write lock (see + * https://github.com/openvswitch/ovs-issues/issues/153). */ +struct mcast_output { + /* Discrete ports. */ + struct xbundle **xbundles; + size_t n, allocated; + + /* If set, flood to all ports. */ + bool flood; +}; +#define MCAST_OUTPUT_INIT { NULL, 0, 0, false } + +/* Add 'mcast_bundle' to 'out'. */ +static void +mcast_output_add(struct mcast_output *out, struct xbundle *mcast_xbundle) +{ + if (out->n >= out->allocated) { + out->xbundles = x2nrealloc(out->xbundles, &out->allocated, + sizeof *out->xbundles); + } + out->xbundles[out->n++] = mcast_xbundle; +} + +/* Outputs the packet in 'ctx' to all of the output ports in 'out', given input + * bundle 'in_xbundle' and the current 'xvlan'. */ +static void +mcast_output_finish(struct xlate_ctx *ctx, struct mcast_output *out, + struct xbundle *in_xbundle, struct xvlan *xvlan) +{ + if (out->flood) { + xlate_normal_flood(ctx, in_xbundle, xvlan); + } else { + for (size_t i = 0; i < out->n; i++) { + output_normal(ctx, out->xbundles[i], xvlan); + } + } + + free(out->xbundles); +} /* send the packet to ports having the multicast group learned */ static void @@ -2669,7 +2725,7 @@ struct mcast_snooping *ms OVS_UNUSED, struct mcast_group *grp, struct xbundle *in_xbundle, - const struct xvlan *xvlan) + struct mcast_output *out) OVS_REQ_RDLOCK(ms->rwlock) { struct mcast_group_bundle *b; @@ -2679,7 +2735,7 @@ mcast_xbundle = xbundle_lookup(ctx->xcfg, b->port); if (mcast_xbundle && mcast_xbundle != in_xbundle) { xlate_report(ctx, OFT_DETAIL, "forwarding to mcast group port"); - output_normal(ctx, mcast_xbundle, xvlan); + mcast_output_add(out, mcast_xbundle); } else if (!mcast_xbundle) { xlate_report(ctx, OFT_WARN, "mcast group port is unknown, dropping"); @@ -2695,7 +2751,8 @@ xlate_normal_mcast_send_mrouters(struct xlate_ctx *ctx, struct mcast_snooping *ms, struct xbundle *in_xbundle, - const struct xvlan *xvlan) + const struct xvlan *xvlan, + struct mcast_output *out) OVS_REQ_RDLOCK(ms->rwlock) { struct mcast_mrouter_bundle *mrouter; @@ -2706,7 +2763,7 @@ if (mcast_xbundle && mcast_xbundle != in_xbundle && mrouter->vlan == xvlan->v[0].vid) { xlate_report(ctx, OFT_DETAIL, "forwarding to mcast router port"); - output_normal(ctx, mcast_xbundle, xvlan); + mcast_output_add(out, mcast_xbundle); } else if (!mcast_xbundle) { xlate_report(ctx, OFT_WARN, "mcast router port is unknown, dropping"); @@ -2725,7 +2782,7 @@ xlate_normal_mcast_send_fports(struct xlate_ctx *ctx, struct mcast_snooping *ms, struct xbundle *in_xbundle, - const struct xvlan *xvlan) + struct mcast_output *out) OVS_REQ_RDLOCK(ms->rwlock) { struct mcast_port_bundle *fport; @@ -2735,7 +2792,7 @@ mcast_xbundle = xbundle_lookup(ctx->xcfg, fport->port); if (mcast_xbundle && mcast_xbundle != in_xbundle) { xlate_report(ctx, OFT_DETAIL, "forwarding to mcast flood port"); - output_normal(ctx, mcast_xbundle, xvlan); + mcast_output_add(out, mcast_xbundle); } else if (!mcast_xbundle) { xlate_report(ctx, OFT_WARN, "mcast flood port is unknown, dropping"); @@ -2751,7 +2808,7 @@ xlate_normal_mcast_send_rports(struct xlate_ctx *ctx, struct mcast_snooping *ms, struct xbundle *in_xbundle, - const struct xvlan *xvlan) + struct mcast_output *out) OVS_REQ_RDLOCK(ms->rwlock) { struct mcast_port_bundle *rport; @@ -2764,7 +2821,7 @@ && mcast_xbundle->ofbundle != in_xbundle->ofbundle) { xlate_report(ctx, OFT_DETAIL, "forwarding report to mcast flagged port"); - output_normal(ctx, mcast_xbundle, xvlan); + mcast_output_add(out, mcast_xbundle); } else if (!mcast_xbundle) { xlate_report(ctx, OFT_WARN, "mcast port is unknown, dropping the report"); @@ -2916,8 +2973,11 @@ } if (mcast_snooping_is_membership(flow->tp_src)) { + struct mcast_output out = MCAST_OUTPUT_INIT; + ovs_rwlock_rdlock(&ms->rwlock); - xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, &xvlan); + xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, &xvlan, + &out); /* RFC4541: section 2.1.1, item 1: A snooping switch should * forward IGMP Membership Reports only to those ports where * multicast routers are attached. Alternatively stated: a @@ -2926,8 +2986,10 @@ * An administrative control may be provided to override this * restriction, allowing the report messages to be flooded to * other ports. */ - xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, &xvlan); + xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, &out); ovs_rwlock_unlock(&ms->rwlock); + + mcast_output_finish(ctx, &out, in_xbundle, &xvlan); } else { xlate_report(ctx, OFT_DETAIL, "multicast traffic, flooding"); xlate_normal_flood(ctx, in_xbundle, &xvlan); @@ -2940,10 +3002,15 @@ in_xbundle, ctx->xin->packet); } if (is_mld_report(flow, wc)) { + struct mcast_output out = MCAST_OUTPUT_INIT; + ovs_rwlock_rdlock(&ms->rwlock); - xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, &xvlan); - xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, &xvlan); + xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, &xvlan, + &out); + xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, &out); ovs_rwlock_unlock(&ms->rwlock); + + mcast_output_finish(ctx, &out, in_xbundle, &xvlan); } else { xlate_report(ctx, OFT_DETAIL, "MLD query, flooding"); xlate_normal_flood(ctx, in_xbundle, &xvlan); @@ -2961,6 +3028,8 @@ } /* forwarding to group base ports */ + struct mcast_output out = MCAST_OUTPUT_INIT; + ovs_rwlock_rdlock(&ms->rwlock); if (flow->dl_type == htons(ETH_TYPE_IP)) { grp = mcast_snooping_lookup4(ms, flow->nw_dst, vlan); @@ -2968,20 +3037,24 @@ grp = mcast_snooping_lookup(ms, &flow->ipv6_dst, vlan); } if (grp) { - xlate_normal_mcast_send_group(ctx, ms, grp, in_xbundle, &xvlan); - xlate_normal_mcast_send_fports(ctx, ms, in_xbundle, &xvlan); - xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, &xvlan); + xlate_normal_mcast_send_group(ctx, ms, grp, in_xbundle, &out); + xlate_normal_mcast_send_fports(ctx, ms, in_xbundle, &out); + xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, &xvlan, + &out); } else { if (mcast_snooping_flood_unreg(ms)) { xlate_report(ctx, OFT_DETAIL, "unregistered multicast, flooding"); - xlate_normal_flood(ctx, in_xbundle, &xvlan); + out.flood = true; } else { - xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, &xvlan); - xlate_normal_mcast_send_fports(ctx, ms, in_xbundle, &xvlan); + xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, &xvlan, + &out); + xlate_normal_mcast_send_fports(ctx, ms, in_xbundle, &out); } } ovs_rwlock_unlock(&ms->rwlock); + + mcast_output_finish(ctx, &out, in_xbundle, &xvlan); } else { ovs_rwlock_rdlock(&ctx->xbridge->ml->rwlock); mac = mac_learning_lookup(ctx->xbridge->ml, flow->dl_dst, vlan); @@ -3040,7 +3113,7 @@ /* When meter action is not required, avoid generate sample action * for 100% sampling rate. */ bool is_sample = probability < UINT32_MAX || meter_id != UINT32_MAX; - size_t sample_offset, actions_offset; + size_t sample_offset = 0, actions_offset = 0; if (is_sample) { sample_offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_SAMPLE); @@ -3056,8 +3129,7 @@ odp_port_t odp_port = ofp_port_to_odp_port( ctx->xbridge, ctx->xin->flow.in_port.ofp_port); - uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port, - flow_hash_5tuple(&ctx->xin->flow, 0)); + uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port); size_t cookie_offset = odp_put_userspace_action(pid, cookie, sizeof *cookie, tunnel_out_port, @@ -3087,11 +3159,13 @@ return 0; } - struct user_action_cookie cookie = { - .type = USER_ACTION_COOKIE_SFLOW, - .ofp_in_port = ctx->xin->flow.in_port.ofp_port, - .ofproto_uuid = ctx->xbridge->ofproto->uuid - }; + struct user_action_cookie cookie; + + memset(&cookie, 0, sizeof cookie); + cookie.type = USER_ACTION_COOKIE_SFLOW; + cookie.ofp_in_port = ctx->xin->flow.in_port.ofp_port; + cookie.ofproto_uuid = ctx->xbridge->ofproto->uuid; + return compose_sample_action(ctx, dpif_sflow_get_probability(sflow), &cookie, ODPP_NONE, true); } @@ -3131,12 +3205,14 @@ } } - struct user_action_cookie cookie = { - .type = USER_ACTION_COOKIE_IPFIX, - .ofp_in_port = ctx->xin->flow.in_port.ofp_port, - .ofproto_uuid = ctx->xbridge->ofproto->uuid, - .ipfix.output_odp_port = output_odp_port - }; + struct user_action_cookie cookie; + + memset(&cookie, 0, sizeof cookie); + cookie.type = USER_ACTION_COOKIE_IPFIX; + cookie.ofp_in_port = ctx->xin->flow.in_port.ofp_port; + cookie.ofproto_uuid = ctx->xbridge->ofproto->uuid; + cookie.ipfix.output_odp_port = output_odp_port; + compose_sample_action(ctx, dpif_ipfix_get_bridge_exporter_probability(ipfix), &cookie, tunnel_out_port, false); @@ -3279,6 +3355,7 @@ struct dp_packet *packet) { struct xbridge *xbridge = out_dev->xbridge; + ovs_version_t version = ofproto_dpif_get_tables_version(xbridge->ofproto); struct ofpact_output output; struct flow flow; @@ -3288,8 +3365,7 @@ output.port = OFPP_TABLE; output.max_len = 0; - return ofproto_dpif_execute_actions__(xbridge->ofproto, - ctx->xin->tables_version, &flow, + return ofproto_dpif_execute_actions__(xbridge->ofproto, version, &flow, NULL, &output.ofpact, sizeof output, ctx->depth, ctx->resubmits, packet); } @@ -3553,13 +3629,6 @@ nl_msg_end_non_empty_nested(ctx->odp_actions, clone_ofs); } else { nl_msg_cancel_nested(ctx->odp_actions, clone_ofs); - /* XXX : There is no real use-case for a tunnel push without - * any post actions. However keeping it now - * as is to make the 'make check' happy. Should remove when all the - * make check tunnel test case does something meaningful on a - * tunnel encap packets. - */ - odp_put_tnl_push_action(ctx->odp_actions, &tnl_push_data); } /* Restore context status. */ @@ -4199,6 +4268,7 @@ !is_ip_any(&ctx->xin->flow)) { xlate_report_error(ctx, "resubmit(ct) with non-tracked or non-IP packet!"); + ctx->table_id = old_table_id; return; } tuple_swap(&ctx->xin->flow, ctx->wc); @@ -4460,7 +4530,7 @@ bool is_last_action) { if (group->up.type == OFPGT11_ALL || group->up.type == OFPGT11_INDIRECT) { - struct ovs_list *last_bucket = ovs_list_back(&group->up.buckets); + struct ovs_list *last_bucket = group->up.buckets.prev; struct ofputil_bucket *bucket; LIST_FOR_EACH (bucket, list_node, &group->up.buckets) { bool is_last_bucket = &bucket->list_node == last_bucket; @@ -4609,8 +4679,7 @@ odp_port_t odp_port = ofp_port_to_odp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port); - uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port, - flow_hash_5tuple(&ctx->xin->flow, 0)); + uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port); odp_put_userspace_action(pid, &cookie, sizeof cookie, ODPP_NONE, false, ctx->odp_actions); } @@ -5393,19 +5462,19 @@ } } - struct user_action_cookie cookie = { - .type = USER_ACTION_COOKIE_FLOW_SAMPLE, - .ofp_in_port = ctx->xin->flow.in_port.ofp_port, - .ofproto_uuid = ctx->xbridge->ofproto->uuid, - .flow_sample = { - .probability = os->probability, - .collector_set_id = os->collector_set_id, - .obs_domain_id = os->obs_domain_id, - .obs_point_id = os->obs_point_id, - .output_odp_port = output_odp_port, - .direction = os->direction, - } - }; + struct user_action_cookie cookie; + + memset(&cookie, 0, sizeof cookie); + cookie.type = USER_ACTION_COOKIE_FLOW_SAMPLE; + cookie.ofp_in_port = ctx->xin->flow.in_port.ofp_port; + cookie.ofproto_uuid = ctx->xbridge->ofproto->uuid; + cookie.flow_sample.probability = os->probability; + cookie.flow_sample.collector_set_id = os->collector_set_id; + cookie.flow_sample.obs_domain_id = os->obs_domain_id; + cookie.flow_sample.obs_point_id = os->obs_point_id; + cookie.flow_sample.output_odp_port = output_odp_port; + cookie.flow_sample.direction = os->direction; + compose_sample_action(ctx, probability, &cookie, tunnel_out_port, false); } @@ -6946,9 +7015,7 @@ /* Some fields we consider to always be examined. */ WC_MASK_FIELD(ctx->wc, packet_type); WC_MASK_FIELD(ctx->wc, in_port); - if (is_ethernet(&ctx->xin->flow, NULL)) { - WC_MASK_FIELD(ctx->wc, dl_type); - } + WC_MASK_FIELD(ctx->wc, dl_type); if (is_ip_any(&ctx->xin->flow)) { WC_MASK_FIELD_MASK(ctx->wc, nw_frag, FLOW_NW_FRAG_MASK); } @@ -6975,12 +7042,14 @@ * use non-header fields as part of the cache. */ flow_wildcards_clear_non_packet_fields(ctx->wc); - /* Wildcard ethernet fields if the original packet type was not - * Ethernet. */ + /* Wildcard Ethernet address fields if the original packet type was not + * Ethernet. + * + * (The Ethertype field is used even when the original packet type is not + * Ethernet.) */ if (ctx->xin->upcall_flow->packet_type != htonl(PT_ETH)) { ctx->wc->masks.dl_dst = eth_addr_zero; ctx->wc->masks.dl_src = eth_addr_zero; - ctx->wc->masks.dl_type = 0; } /* ICMPv4 and ICMPv6 have 8-bit "type" and "code" fields. struct flow @@ -7436,19 +7505,22 @@ xlate_resume(struct ofproto_dpif *ofproto, const struct ofputil_packet_in_private *pin, struct ofpbuf *odp_actions, - enum slow_path_reason *slow) + enum slow_path_reason *slow, + struct flow *flow, + struct xlate_cache *xcache) { struct dp_packet packet; dp_packet_use_const(&packet, pin->base.packet, pin->base.packet_len); - struct flow flow; - flow_extract(&packet, &flow); + pkt_metadata_from_flow(&packet.md, &pin->base.flow_metadata.flow); + flow_extract(&packet, flow); struct xlate_in xin; xlate_in_init(&xin, ofproto, ofproto_dpif_get_tables_version(ofproto), - &flow, 0, NULL, ntohs(flow.tcp_flags), + flow, 0, NULL, ntohs(flow->tcp_flags), &packet, NULL, odp_actions); + xin.xcache = xcache; struct ofpact_note noop; ofpact_init_NOTE(&noop); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-xlate.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-xlate.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-dpif-xlate.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-dpif-xlate.h 2020-03-11 16:15:44.000000000 +0000 @@ -230,8 +230,8 @@ enum ofperr xlate_resume(struct ofproto_dpif *, const struct ofputil_packet_in_private *, - struct ofpbuf *odp_actions, enum slow_path_reason *); - + struct ofpbuf *odp_actions, enum slow_path_reason *, + struct flow *, struct xlate_cache *); int xlate_send_packet(const struct ofport_dpif *, bool oam, struct dp_packet *); void xlate_mac_learning_update(const struct ofproto_dpif *ofproto, diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-provider.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-provider.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ofproto/ofproto-provider.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ofproto/ofproto-provider.h 2020-03-11 16:15:44.000000000 +0000 @@ -1336,9 +1336,15 @@ * packet_xlate_revert() calls have to be made in reverse order. */ void (*packet_xlate_revert)(struct ofproto *, struct ofproto_packet_out *); - /* Executes the datapath actions, translation side-effects, and stats as - * produced by ->packet_xlate(). The caller retains ownership of 'opo'. - */ + /* Translates side-effects, and stats as produced by ->packet_xlate(). + * Prepares to execute datapath actions. The caller retains ownership + * of 'opo'. */ + void (*packet_execute_prepare)(struct ofproto *, + struct ofproto_packet_out *opo); + + /* Executes the datapath actions. The caller retains ownership of 'opo'. + * Should be called after successful packet_execute_prepare(). + * No-op if called after packet_xlate_revert(). */ void (*packet_execute)(struct ofproto *, struct ofproto_packet_out *opo); /* Changes the OpenFlow IP fragment handling policy to 'frag_handling', diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/ofctrl.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/ofctrl.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/ofctrl.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/ofctrl.c 2020-03-11 16:15:44.000000000 +0000 @@ -630,9 +630,11 @@ * * The caller should initialize its own hmap to hold the flows. */ void -ofctrl_add_flow(struct hmap *desired_flows, - uint8_t table_id, uint16_t priority, uint64_t cookie, - const struct match *match, const struct ofpbuf *actions) +ofctrl_check_and_add_flow(struct hmap *desired_flows, + uint8_t table_id, uint16_t priority, uint64_t cookie, + const struct match *match, + const struct ofpbuf *actions, + bool log_duplicate_flow) { struct ovn_flow *f = xmalloc(sizeof *f); f->table_id = table_id; @@ -644,13 +646,14 @@ f->cookie = cookie; if (ovn_flow_lookup(desired_flows, f)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); - if (!VLOG_DROP_DBG(&rl)) { - char *s = ovn_flow_to_string(f); - VLOG_DBG("dropping duplicate flow: %s", s); - free(s); + if (log_duplicate_flow) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + if (!VLOG_DROP_DBG(&rl)) { + char *s = ovn_flow_to_string(f); + VLOG_DBG("dropping duplicate flow: %s", s); + free(s); + } } - ovn_flow_destroy(f); return; } @@ -658,6 +661,14 @@ hmap_insert(desired_flows, &f->hmap_node, f->hmap_node.hash); } +void +ofctrl_add_flow(struct hmap *desired_flows, + uint8_t table_id, uint16_t priority, uint64_t cookie, + const struct match *match, const struct ofpbuf *actions) +{ + ofctrl_check_and_add_flow(desired_flows, table_id, priority, cookie, + match, actions, true); +} /* ovn_flow. */ @@ -777,7 +788,7 @@ static struct ofpbuf * encode_group_mod(const struct ofputil_group_mod *gm) { - return ofputil_encode_group_mod(OFP13_VERSION, gm); + return ofputil_encode_group_mod(OFP13_VERSION, gm, NULL, -1); } static void diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/ofctrl.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/ofctrl.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/ofctrl.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/ofctrl.h 2020-03-11 16:15:44.000000000 +0000 @@ -55,4 +55,9 @@ uint16_t priority, uint64_t cookie, const struct match *, const struct ofpbuf *ofpacts); +void ofctrl_check_and_add_flow(struct hmap *desired_flows, uint8_t table_id, + uint16_t priority, uint64_t cookie, + const struct match *, + const struct ofpbuf *ofpacts, + bool log_duplicate_flow); #endif /* ovn/ofctrl.h */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/ovn-controller.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/ovn-controller.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/ovn-controller.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/ovn-controller.c 2020-03-11 16:15:44.000000000 +0000 @@ -801,7 +801,7 @@ if (pending_pkt.conn) { char *error = ofctrl_inject_pkt(br_int, pending_pkt.flow_s, - &port_groups, &addr_sets); + &addr_sets, &port_groups); if (error) { unixctl_command_reply_error(pending_pkt.conn, error); free(error); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/physical.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/physical.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/physical.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/physical.c 2020-03-11 16:15:44.000000000 +0000 @@ -189,7 +189,8 @@ static void put_local_common_flows(uint32_t dp_key, uint32_t port_key, - bool nested_container, const struct zone_ids *zone_ids, + uint32_t parent_port_key, + const struct zone_ids *zone_ids, struct ofpbuf *ofpacts_p, struct hmap *flow_table) { struct match match; @@ -244,11 +245,19 @@ /* Table 64, Priority 100. * ======================= * - * If the packet is supposed to hair-pin because the "loopback" - * flag is set (or if the destination is a nested container), + * If the packet is supposed to hair-pin because the + * - "loopback" flag is set + * - or if the destination is a nested container + * - or if "nested_container" flag is set and the destination is the + * parent port, * temporarily set the in_port to zero, resubmit to * table 65 for logical-to-physical translation, then restore - * the port number. */ + * the port number. + * + * If 'parent_port_key' is set, then the 'port_key' represents a nested + * container. */ + + bool nested_container = parent_port_key ? true: false; match_init_catchall(&match); ofpbuf_clear(ofpacts_p); match_set_metadata(&match, htonll(dp_key)); @@ -264,6 +273,38 @@ put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p)); ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0, &match, ofpacts_p); + + if (nested_container) { + /* It's a nested container and when the packet from the nested + * container is to be sent to the parent port, "nested_container" + * flag will be set. We need to temporarily set the in_port to zero + * as mentioned in the comment above. + * + * If a parent port has multiple child ports, then this if condition + * will be hit multiple times, but we want to add only one flow. + * ofctrl_add_flow() logs a warning message for duplicate flows. + * So use the function 'ofctrl_check_and_add_flow' which doesn't + * log a warning. + * + * Other option is to add this flow for all the ports which are not + * nested containers. In which case we will add this flow for all the + * ports even if they don't have any child ports which is + * unnecessary. + */ + match_init_catchall(&match); + ofpbuf_clear(ofpacts_p); + match_set_metadata(&match, htonll(dp_key)); + match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, parent_port_key); + match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0, + MLF_NESTED_CONTAINER, MLF_NESTED_CONTAINER); + + put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(ofpacts_p)); + put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p); + put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p); + put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p)); + ofctrl_check_and_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0, + &match, ofpacts_p, false); + } } static void @@ -328,7 +369,7 @@ } struct zone_ids binding_zones = get_zone_ids(binding, ct_zones); - put_local_common_flows(dp_key, port_key, false, &binding_zones, + put_local_common_flows(dp_key, port_key, 0, &binding_zones, ofpacts_p, flow_table); match_init_catchall(&match); @@ -452,6 +493,7 @@ int tag = 0; bool nested_container = false; + const struct sbrec_port_binding *parent_port = NULL; ofp_port_t ofport; bool is_remote = false; if (binding->parent_port && *binding->parent_port) { @@ -463,6 +505,8 @@ if (ofport) { tag = *binding->tag; nested_container = true; + parent_port = lport_lookup_by_name( + sbrec_port_binding_by_name, binding->parent_port); } } else { ofport = u16_to_ofp(simap_get(&localvif_to_ofport, @@ -523,7 +567,10 @@ */ struct zone_ids zone_ids = get_zone_ids(binding, ct_zones); - put_local_common_flows(dp_key, port_key, nested_container, &zone_ids, + uint32_t parent_port_key = parent_port ? parent_port->tunnel_key : 0; + /* Pass the parent port tunnel key if the port is a nested + * container. */ + put_local_common_flows(dp_key, port_key, parent_port_key, &zone_ids, ofpacts_p, flow_table); /* Table 0, Priority 150 and 100. @@ -553,8 +600,10 @@ if (nested_container) { /* When a packet comes from a container sitting behind a * parent_port, we should let it loopback to other containers - * or the parent_port itself. */ - put_load(MLF_ALLOW_LOOPBACK, MFF_LOG_FLAGS, 0, 1, ofpacts_p); + * or the parent_port itself. Indicate this by setting the + * MLF_NESTED_CONTAINER_BIT in MFF_LOG_FLAGS.*/ + put_load(1, MFF_LOG_FLAGS, MLF_NESTED_CONTAINER_BIT, 1, + ofpacts_p); } ofpact_put_STRIP_VLAN(ofpacts_p); } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/pinctrl.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/pinctrl.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/controller/pinctrl.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/controller/pinctrl.c 2020-03-11 16:15:44.000000000 +0000 @@ -432,7 +432,7 @@ if (dp_packet_l4_size(pkt_in) < (UDP_HEADER_LEN + sizeof (struct dhcp_header) + sizeof(uint32_t) + 3)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "Invalid or incomplete DHCP packet recieved"); + VLOG_WARN_RL(&rl, "Invalid or incomplete DHCP packet received"); goto exit; } @@ -609,6 +609,11 @@ return false; } + if (!iaid) { + /* If iaid is None, it means its an DHCPv6 information request. + * Don't put IA_NA option in the response. */ + break; + } /* IA Address option is used to specify IPv6 addresses associated * with an IA_NA or IA_TA. The IA Address option must be * encapsulated in the Options field of an IA_NA or IA_TA option. @@ -717,7 +722,8 @@ } uint8_t out_dhcpv6_msg_type; - switch(*in_dhcpv6_data) { + uint8_t in_dhcpv6_msg_type = *in_dhcpv6_data; + switch (in_dhcpv6_msg_type) { case DHCPV6_MSG_TYPE_SOLICIT: out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_ADVT; break; @@ -725,6 +731,7 @@ case DHCPV6_MSG_TYPE_REQUEST: case DHCPV6_MSG_TYPE_CONFIRM: case DHCPV6_MSG_TYPE_DECLINE: + case DHCPV6_MSG_TYPE_INFO_REQ: out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_REPLY; break; @@ -737,7 +744,10 @@ in_dhcpv6_data += 4; /* We need to extract IAID from the IA-NA option of the client's DHCPv6 * solicit/request/confirm packet and copy the same IAID in the Server's - * response. */ + * response. + * DHCPv6 information packet (for stateless request will not have IA-NA + * option. So we don't need to copy that in the Server's response. + * */ ovs_be32 iaid = 0; struct dhcpv6_opt_header const *in_opt_client_id = NULL; size_t udp_len = ntohs(in_udp->udp_len); @@ -771,7 +781,7 @@ goto exit; } - if (!iaid) { + if (!iaid && in_dhcpv6_msg_type != DHCPV6_MSG_TYPE_INFO_REQ) { VLOG_WARN_RL(&rl, "DHCPv6 option - IA NA not present in the " " DHCPv6 packet"); goto exit; @@ -898,6 +908,12 @@ goto exit; } + /* Check that the packet stores at least the minimal headers. */ + if (dp_packet_l4_size(pkt_in) < (UDP_HEADER_LEN + DNS_HEADER_LEN)) { + VLOG_WARN_RL(&rl, "truncated dns packet"); + goto exit; + } + /* Extract the DNS header */ struct dns_header const *in_dns_header = dp_packet_get_udp_payload(pkt_in); if (!in_dns_header) { @@ -922,7 +938,7 @@ uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len); uint8_t *in_dns_data = (uint8_t *)(in_dns_header + 1); uint8_t *in_queryname = in_dns_data; - uint8_t idx = 0; + uint16_t idx = 0; struct ds query_name; ds_init(&query_name); /* Extract the query_name. If the query name is - 'www.ovn.org' it would be @@ -1378,7 +1394,7 @@ config->min_interval = smap_get_int(&pb->options, "ipv6_ra_min_interval", nd_ra_min_interval_default(config->max_interval)); config->mtu = smap_get_int(&pb->options, "ipv6_ra_mtu", ND_MTU_DEFAULT); - config->la_flags = ND_PREFIX_ON_LINK; + config->la_flags = IPV6_ND_RA_OPT_PREFIX_ON_LINK; const char *address_mode = smap_get(&pb->options, "ipv6_ra_address_mode"); if (!address_mode) { @@ -1387,10 +1403,11 @@ } if (!strcmp(address_mode, "dhcpv6_stateless")) { config->mo_flags = IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG; + config->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS; } else if (!strcmp(address_mode, "dhcpv6_stateful")) { config->mo_flags = IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG; } else if (!strcmp(address_mode, "slaac")) { - config->la_flags |= ND_PREFIX_AUTONOMOUS_ADDRESS; + config->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS; } else { VLOG_WARN("Invalid address mode %s", address_mode); goto fail; @@ -1563,6 +1580,11 @@ ra->config->max_interval); shash_add(&ipv6_ras, pb->logical_port, ra); } else { + if (config->min_interval != ra->config->min_interval || + config->max_interval != ra->config->max_interval) + ra->next_announce = ipv6_ra_calc_next_announce( + config->min_interval, + config->max_interval); ipv6_ra_config_delete(ra->config); ra->config = config; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/actions.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/actions.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/actions.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/actions.c 2020-03-11 16:15:44.000000000 +0000 @@ -185,12 +185,15 @@ : ep->egress_ptable); } +#define MAX_NESTED_ACTION_DEPTH 32 + /* Context maintained during ovnacts_parse(). */ struct action_context { const struct ovnact_parse_params *pp; /* Parameters. */ struct lexer *lexer; /* Lexer for pulling more tokens. */ struct ofpbuf *ovnacts; /* Actions. */ struct expr *prereqs; /* Prerequisites to apply to match. */ + int depth; /* Current nested action depth. */ }; static void parse_actions(struct action_context *, enum lex_type sentinel); @@ -1092,6 +1095,11 @@ return; } + if (ctx->depth + 1 == MAX_NESTED_ACTION_DEPTH) { + lexer_error(ctx->lexer, "maximum depth of nested actions reached"); + return; + } + uint64_t stub[1024 / 8]; struct ofpbuf nested = OFPBUF_STUB_INITIALIZER(stub); @@ -1100,6 +1108,7 @@ .lexer = ctx->lexer, .ovnacts = &nested, .prereqs = NULL, + .depth = ctx->depth + 1, }; parse_actions(&inner_ctx, LEX_T_RCURLY); @@ -1945,12 +1954,6 @@ return; } - if (addr_mode_stateful && prefix_set) { - lexer_error(ctx->lexer, "prefix option can't be" - " set when address mode is dhcpv6_stateful."); - return; - } - if (!addr_mode_stateful && !prefix_set) { lexer_error(ctx->lexer, "prefix option needs " "to be set when address mode is slaac/dhcpv6_stateless."); @@ -1969,18 +1972,21 @@ static void encode_put_nd_ra_option(const struct ovnact_gen_option *o, - struct ofpbuf *ofpacts, struct ovs_ra_msg *ra) + struct ofpbuf *ofpacts, ptrdiff_t ra_offset) { const union expr_constant *c = o->value.values; switch (o->option->code) { case ND_RA_FLAG_ADDR_MODE: + { + struct ovs_ra_msg *ra = ofpbuf_at(ofpacts, ra_offset, sizeof *ra); if (!strcmp(c->string, "dhcpv6_stateful")) { ra->mo_flags = IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG; } else if (!strcmp(c->string, "dhcpv6_stateless")) { ra->mo_flags = IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG; } break; + } case ND_OPT_SOURCE_LINKADDR: { @@ -2008,10 +2014,14 @@ struct ovs_nd_prefix_opt *prefix_opt = ofpbuf_put_uninit(ofpacts, sizeof *prefix_opt); uint8_t prefix_len = ipv6_count_cidr_bits(&c->mask.ipv6); + struct ovs_ra_msg *ra = ofpbuf_at(ofpacts, ra_offset, sizeof *ra); prefix_opt->type = ND_OPT_PREFIX_INFORMATION; prefix_opt->len = 4; prefix_opt->prefix_len = prefix_len; - prefix_opt->la_flags = IPV6_ND_RA_OPT_PREFIX_FLAGS; + prefix_opt->la_flags = IPV6_ND_RA_OPT_PREFIX_ON_LINK; + if (!(ra->mo_flags & IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG)) { + prefix_opt->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS; + } put_16aligned_be32(&prefix_opt->valid_lifetime, htonl(IPV6_ND_RA_OPT_PREFIX_VALID_LIFETIME)); put_16aligned_be32(&prefix_opt->preferred_lifetime, @@ -2042,6 +2052,7 @@ * pinctrl module receives the ICMPv6 Router Solicitation packet * it can copy the userdata field AS IS and resume the packet. */ + size_t ra_offset = ofpacts->size; struct ovs_ra_msg *ra = ofpbuf_put_zeros(ofpacts, sizeof *ra); ra->icmph.icmp6_type = ND_ROUTER_ADVERT; ra->cur_hop_limit = IPV6_ND_RA_CUR_HOP_LIMIT; @@ -2050,7 +2061,7 @@ for (const struct ovnact_gen_option *o = po->options; o < &po->options[po->n_options]; o++) { - encode_put_nd_ra_option(o, ofpacts, ra); + encode_put_nd_ra_option(o, ofpacts, ra_offset); } encode_finish_controller_op(oc_offset, ofpacts); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/expr.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/expr.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/expr.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/expr.c 2020-03-11 16:15:44.000000000 +0000 @@ -459,6 +459,8 @@ /* Parsing. */ +#define MAX_PAREN_DEPTH 100 + /* Context maintained during expr_parse(). */ struct expr_context { struct lexer *lexer; /* Lexer for pulling more tokens. */ @@ -466,6 +468,7 @@ const struct shash *addr_sets; /* Address set table. */ const struct shash *port_groups; /* Port group table. */ bool not; /* True inside odd number of NOT operators. */ + unsigned int paren_depth; /* Depth of nested parentheses. */ }; struct expr *expr_parse__(struct expr_context *); @@ -578,6 +581,11 @@ f->symbol->name); goto exit; } + if (!cs->n_values) { + lexer_error(ctx->lexer, "Only == and != operators may be used " + "to compare a field against an empty value set."); + goto exit; + } if (cs->values[0].masked) { lexer_error(ctx->lexer, "Only == and != operators may be used " "with masked constants. Consider using subfields " @@ -1077,7 +1085,15 @@ { *atomic = false; if (lexer_match(ctx->lexer, LEX_T_LPAREN)) { + if (ctx->paren_depth >= MAX_PAREN_DEPTH) { + lexer_error(ctx->lexer, "Parentheses nested too deeply."); + return NULL; + } + + ctx->paren_depth++; struct expr *e = expr_parse__(ctx); + ctx->paren_depth--; + if (!lexer_force_match(ctx->lexer, LEX_T_RPAREN)) { expr_destroy(e); return NULL; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/extend-table.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/extend-table.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/extend-table.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/extend-table.c 2020-03-11 16:15:44.000000000 +0000 @@ -33,26 +33,25 @@ hmap_init(&table->existing); } +static void +ovn_extend_table_info_destroy(struct hmap *target) +{ + struct ovn_extend_table_info *e, *next; + HMAP_FOR_EACH_SAFE (e, next, hmap_node, target) { + hmap_remove(target, &e->hmap_node); + free(e->name); + free(e); + } + hmap_destroy(target); +} + void ovn_extend_table_destroy(struct ovn_extend_table *table) { bitmap_free(table->table_ids); - struct ovn_extend_table_info *desired, *d_next; - HMAP_FOR_EACH_SAFE (desired, d_next, hmap_node, &table->existing) { - hmap_remove(&table->existing, &desired->hmap_node); - free(desired->name); - free(desired); - } - hmap_destroy(&table->desired); - - struct ovn_extend_table_info *existing, *e_next; - HMAP_FOR_EACH_SAFE (existing, e_next, hmap_node, &table->existing) { - hmap_remove(&table->existing, &existing->hmap_node); - free(existing->name); - free(existing); - } - hmap_destroy(&table->existing); + ovn_extend_table_info_destroy(&table->desired); + ovn_extend_table_info_destroy(&table->existing); } /* Finds and returns a group_info in 'existing' whose key is identical diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/lex.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/lex.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/lex.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/lex.c 2020-03-11 16:15:44.000000000 +0000 @@ -332,13 +332,15 @@ if (hexit < 0) { lex_error(token, "Invalid syntax in hexadecimal constant."); return; + } else if (hexit) { + /* Check within loop to ignore any number of leading zeros. */ + if (i / 2 >= sizeof token->value.u8) { + lex_error(token, "Hexadecimal constant requires more than " + "%"PRIuSIZE" bits.", 8 * sizeof token->value.u8); + return; + } + out[-(i / 2)] |= i % 2 ? hexit << 4 : hexit; } - if (hexit && i / 2 >= sizeof token->value.u8) { - lex_error(token, "Hexadecimal constant requires more than " - "%"PRIuSIZE" bits.", 8 * sizeof token->value.u8); - return; - } - out[-(i / 2)] |= i % 2 ? hexit << 4 : hexit; } token->format = LEX_F_HEXADECIMAL; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/logical-fields.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/logical-fields.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/logical-fields.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/logical-fields.h 2020-03-11 16:15:44.000000000 +0000 @@ -50,6 +50,7 @@ MLF_FORCE_SNAT_FOR_DNAT_BIT = 2, MLF_FORCE_SNAT_FOR_LB_BIT = 3, MLF_LOCAL_ONLY_BIT = 4, + MLF_NESTED_CONTAINER_BIT = 5, }; /* MFF_LOG_FLAGS_REG flag assignments */ @@ -75,6 +76,9 @@ * hypervisors should instead only be output to local targets */ MLF_LOCAL_ONLY = (1 << MLF_LOCAL_ONLY_BIT), + + /* Indicate that a packet was received from a nested container. */ + MLF_NESTED_CONTAINER = (1 << MLF_NESTED_CONTAINER_BIT), }; #endif /* ovn/lib/logical-fields.h */ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/ovn-l7.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/ovn-l7.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/lib/ovn-l7.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/lib/ovn-l7.h 2020-03-11 16:15:44.000000000 +0000 @@ -70,6 +70,8 @@ #define DHCP_OPT_T1 DHCP_OPTION("T1", 58, "uint32") #define DHCP_OPT_T2 DHCP_OPTION("T2", 59, "uint32") +#define DHCP_OPT_WPAD DHCP_OPTION("wpad", 252, "str") + static inline uint32_t gen_opt_hash(char *opt_name) { @@ -149,6 +151,7 @@ #define DHCPV6_MSG_TYPE_CONFIRM 4 #define DHCPV6_MSG_TYPE_REPLY 7 #define DHCPV6_MSG_TYPE_DECLINE 9 +#define DHCPV6_MSG_TYPE_INFO_REQ 11 /* DHCPv6 Option codes */ @@ -242,7 +245,8 @@ #define IPV6_ND_RA_REACHABLE_TIME 0 #define IPV6_ND_RA_RETRANSMIT_TIMER 0 -#define IPV6_ND_RA_OPT_PREFIX_FLAGS 0xc0 +#define IPV6_ND_RA_OPT_PREFIX_ON_LINK 0x80 +#define IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS 0x40 #define IPV6_ND_RA_OPT_PREFIX_VALID_LIFETIME 0xffffffff #define IPV6_ND_RA_OPT_PREFIX_PREFERRED_LIFETIME 0xffffffff diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/northd/ovn-northd.8.xml openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/northd/ovn-northd.8.xml --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/northd/ovn-northd.8.xml 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/northd/ovn-northd.8.xml 2020-03-11 16:15:44.000000000 +0000 @@ -2055,6 +2055,30 @@

+ Unknown MAC address. For each IPv6 static route associated with the + router with the nexthop IP: G, a priority-200 flow + for IPv6 packets with match + eth.dst == 00:00:00:00:00:00 && + xxreg0 == G + with the following actions is added: +

+ +
+nd_ns {
+    eth.dst = E;
+    ip6.dst = I
+    nd.target = G;
+    output;
+};
+        
+ +

+ Where E is the multicast mac derived from the Gateway IP, + I is the solicited-node multicast address corresponding + to the target address G. +

+ +

Unknown MAC address. A priority-100 flow for IPv6 packets with match eth.dst == 00:00:00:00:00:00 has the following actions:

diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/northd/ovn-northd.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/northd/ovn-northd.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/northd/ovn-northd.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/northd/ovn-northd.c 2020-03-11 16:15:44.000000000 +0000 @@ -385,6 +385,7 @@ if (uuid_equals(&chassis->header_.uuid, &node->chassis_uuid) && node->queue_id == queue_id) { hmap_remove(set, &node->key_node); + free(node); break; } } @@ -1400,7 +1401,7 @@ } } - if (!nbsp->n_addresses && nbsp->dynamic_addresses) { + if (!num_dynamic_addresses && nbsp->dynamic_addresses) { nbrec_logical_switch_port_set_dynamic_addresses(nbsp, NULL); } } @@ -1613,7 +1614,6 @@ } op->od = od; - ipam_add_port_addresses(od, op); tag_alloc_add_existing_tags(tag_alloc_table, nbsp); } } else { @@ -1657,7 +1657,6 @@ op->lrp_networks = lrp_networks; op->od = od; - ipam_add_port_addresses(op->od, op); const char *redirect_chassis = smap_get(&op->nbrp->options, "redirect-chassis"); @@ -1759,6 +1758,8 @@ } } } + + ipam_add_port_addresses(op->od, op); } } @@ -3203,7 +3204,7 @@ uint16_t *port, int *addr_family) { struct sockaddr_storage ss; - if (!inet_parse_active(key, 0, &ss)) { + if (!inet_parse_active(key, 0, &ss, false)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); VLOG_WARN_RL(&rl, "bad ip address or port for load balancer key %s", key); @@ -6206,13 +6207,10 @@ continue; } - /* Add the prefix option if the address mode is slaac or - * dhcpv6_stateless. */ - if (strcmp(address_mode, "dhcpv6_stateful")) { - ds_put_format(&actions, ", prefix = %s/%u", - op->lrp_networks.ipv6_addrs[i].network_s, - op->lrp_networks.ipv6_addrs[i].plen); - } + ds_put_format(&actions, ", prefix = %s/%u", + op->lrp_networks.ipv6_addrs[i].network_s, + op->lrp_networks.ipv6_addrs[i].plen); + add_rs_response_flow = true; } @@ -6542,6 +6540,42 @@ continue; } + for (int i = 0; i < od->nbr->n_static_routes; i++) { + const struct nbrec_logical_router_static_route *route; + + route = od->nbr->static_routes[i]; + struct in6_addr gw_ip6; + unsigned int plen; + char *error = ipv6_parse_cidr(route->nexthop, &gw_ip6, &plen); + if (error || plen != 128) { + free(error); + continue; + } + + ds_clear(&match); + ds_put_format(&match, "eth.dst == 00:00:00:00:00:00 && " + "ip6 && xxreg0 == %s", route->nexthop); + struct in6_addr sn_addr; + struct eth_addr eth_dst; + in6_addr_solicited_node(&sn_addr, &gw_ip6); + ipv6_multicast_to_ethernet(ð_dst, &sn_addr); + + char sn_addr_s[INET6_ADDRSTRLEN + 1]; + ipv6_string_mapped(sn_addr_s, &sn_addr); + + ds_clear(&actions); + ds_put_format(&actions, + "nd_ns { " + "eth.dst = "ETH_ADDR_FMT"; " + "ip6.dst = %s; " + "nd.target = %s; " + "output; " + "};", ETH_ADDR_ARGS(eth_dst), sn_addr_s, + route->nexthop); + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, + ds_cstr(&match), ds_cstr(&actions)); + } + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, "eth.dst == 00:00:00:00:00:00", "arp { " @@ -6913,7 +6947,7 @@ for (size_t i = 0; i < nb_meter->n_bands; i++) { if (nb_bands[i].rate != sb_bands[i].rate || nb_bands[i].burst_size != sb_bands[i].burst_size - || strcmp(nb_bands[i].action, nb_bands[i].action)) { + || strcmp(nb_bands[i].action, sb_bands[i].action)) { need_update = true; goto done; } @@ -7214,7 +7248,8 @@ DHCP_OPT_MTU, DHCP_OPT_LEASE_TIME, DHCP_OPT_T1, - DHCP_OPT_T2 + DHCP_OPT_T2, + DHCP_OPT_WPAD, }; static struct gen_opts_map supported_dhcpv6_opts[] = { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/ovn-nb.xml openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/ovn-nb.xml --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/ovn-nb.xml 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/ovn-nb.xml 2020-03-11 16:15:44.000000000 +0000 @@ -1991,6 +1991,7 @@ Microsoft Windows DHCPv4 clients.

+ @@ -2055,6 +2056,20 @@ for this option is 59. + + +

+ These options accept a string value. +

+ + +

+ The DHCPv4 option code for this option is 252. This option is used + as part of web proxy auto discovery to provide a URL for a web + proxy. +

+
+
diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/utilities/ovn-ctl openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/utilities/ovn-ctl --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/utilities/ovn-ctl 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/utilities/ovn-ctl 2020-03-11 16:15:44.000000000 +0000 @@ -95,7 +95,7 @@ start_ovsdb__() { local DB=$1 db=$2 schema_name=$3 table_name=$4 - local pid + local db_pid_file local cluster_local_addr local cluster_local_port local cluster_local_proto @@ -116,7 +116,10 @@ local addr local active_conf_file local use_remote_in_db - eval pid=\$DB_${DB}_PID + local ovn_db_ssl_key + local ovn_db_ssl_cert + local ovn_db_ssl_cacert + eval db_pid_file=\$DB_${DB}_PID eval cluster_local_addr=\$DB_${DB}_CLUSTER_LOCAL_ADDR eval cluster_local_port=\$DB_${DB}_CLUSTER_LOCAL_PORT eval cluster_local_proto=\$DB_${DB}_CLUSTER_LOCAL_PROTO @@ -137,9 +140,12 @@ eval addr=\$DB_${DB}_ADDR eval active_conf_file=\$ovn${db}_active_conf_file eval use_remote_in_db=\$DB_${DB}_USE_REMOTE_IN_DB + eval ovn_db_ssl_key=\$OVN_${DB}_DB_SSL_KEY + eval ovn_db_ssl_cert=\$OVN_${DB}_DB_SSL_CERT + eval ovn_db_ssl_cacert=\$OVN_${DB}_DB_SSL_CA_CERT # Check and eventually start ovsdb-server for DB - if pidfile_is_running $pid; then + if pidfile_is_running $db_pid_file; then return fi @@ -169,7 +175,7 @@ set ovsdb-server set "$@" $log --log-file=$logfile - set "$@" --remote=punix:$sock --pidfile=$pid + set "$@" --remote=punix:$sock --pidfile=$db_pid_file set "$@" --unixctl=ovn${db}_db.ctl if test X"$detach" != Xno; then @@ -181,9 +187,23 @@ if test X"$use_remote_in_db" != Xno; then set "$@" --remote=db:$schema_name,$table_name,connections fi - set "$@" --private-key=db:$schema_name,SSL,private_key - set "$@" --certificate=db:$schema_name,SSL,certificate - set "$@" --ca-cert=db:$schema_name,SSL,ca_cert + + if test X"$ovn_db_ssl_key" != X; then + set "$@" --private-key=$ovn_db_ssl_key + else + set "$@" --private-key=db:$schema_name,SSL,private_key + fi + if test X"$ovn_db_ssl_cert" != X; then + set "$@" --certificate=$ovn_db_ssl_cert + else + set "$@" --certificate=db:$schema_name,SSL,certificate + fi + if test X"$ovn_db_ssl_cacert" != X; then + set "$@" --ca-cert=$ovn_db_ssl_cacert + else + set "$@" --ca-cert=db:$schema_name,SSL,ca_cert + fi + set "$@" --ssl-protocols=db:$schema_name,SSL,ssl_protocols set "$@" --ssl-ciphers=db:$schema_name,SSL,ssl_ciphers @@ -200,7 +220,7 @@ # Initialize the database if it's running standalone, # active-passive, or is the first server in a cluster. if test -z "$cluster_remote_addr"; then - ovn-nbctl init + ovn-${db}ctl init fi if test $mode = cluster; then @@ -469,6 +489,15 @@ OVN_NORTHD_SB_DB="unix:$DB_SB_SOCK" DB_NB_USE_REMOTE_IN_DB="yes" DB_SB_USE_REMOTE_IN_DB="yes" + + OVN_NB_DB_SSL_KEY="" + OVN_NB_DB_SSL_CERT="" + OVN_NB_DB_SSL_CA_CERT="" + + OVN_SB_DB_SSL_KEY="" + OVN_SB_DB_SSL_CERT="" + OVN_SB_DB_SSL_CA_CERT="" + } set_option () { @@ -524,6 +553,12 @@ --ovn-controller-ssl-cert=CERT OVN Southbound SSL certificate file --ovn-controller-ssl-ca-cert=CERT OVN Southbound SSL CA certificate file --ovn-controller-ssl-bootstrap-ca-cert=CERT Bootstrapped OVN Southbound SSL CA certificate file + --ovn-nb-db-ssl-key=KEY OVN Northbound DB SSL private key file + --ovn-nb-db-ssl-cert=CERT OVN Northbound DB SSL certificate file + --ovn-nb-db-ssl-ca-cert=CERT OVN Northbound DB SSL CA certificate file + --ovn-sb-db-ssl-key=KEY OVN Southbound DB SSL private key file + --ovn-sb-db-ssl-cert=CERT OVN Southbound DB SSL certificate file + --ovn-sb-db-ssl-ca-cert=CERT OVN Southbound DB SSL CA certificate file --ovn-manage-ovsdb=yes|no Whether or not the OVN databases should be automatically started and stopped along with ovn-northd. The default is "yes". If diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/utilities/ovn-ctl.8.xml openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/utilities/ovn-ctl.8.xml --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/utilities/ovn-ctl.8.xml 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/utilities/ovn-ctl.8.xml 2020-03-11 16:15:44.000000000 +0000 @@ -196,4 +196,18 @@ start_northd

+ +

Passing ssl keys when starting OVN dbs will supercede the default ssl values in db

+

Starting standalone ovn db server passing SSL certificates

+

+ + # ovn-ctl --ovn-nb-db-ssl-key=/etc/openvswitch/ovnnb-privkey.pem + --ovn-nb-db-ssl-cert=/etc/openvswitch/ovnnb-cert.pem + --ovn-nb-db-ssl-ca-cert=/etc/openvswitch/cacert.pem + --ovn-sb-db-ssl-key=/etc/openvswitch/ovnsb-privkey.pem + --ovn-sb-db-ssl-cert=/etc/openvswitch/ovnsb-cert.pem + --ovn-sb-db-ssl-ca-cert=/etc/openvswitch/cacert.pem + start_northd + +

diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/utilities/ovndb-servers.ocf openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/utilities/ovndb-servers.ocf --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/utilities/ovndb-servers.ocf 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/utilities/ovndb-servers.ocf 2020-03-11 16:15:44.000000000 +0000 @@ -10,6 +10,12 @@ : ${MANAGE_NORTHD_DEFAULT="no"} : ${INACTIVE_PROBE_DEFAULT="5000"} : ${LISTEN_ON_MASTER_IP_ONLY_DEFAULT="yes"} +: ${NB_SSL_KEY_DEFAULT="/etc/openvswitch/ovnnb-privkey.pem"} +: ${NB_SSL_CERT_DEFAULT="/etc/openvswitch/ovnnb-cert.pem"} +: ${NB_SSL_CACERT_DEFAULT="/etc/openvswitch/cacert.pem"} +: ${SB_SSL_KEY_DEFAULT="/etc/openvswitch/ovnsb-privkey.pem"} +: ${SB_SSL_CERT_DEFAULT="/etc/openvswitch/ovnsb-cert.pem"} +: ${SB_SSL_CACERT_DEFAULT="/etc/openvswitch/cacert.pem"} CRM_MASTER="${HA_SBIN_DIR}/crm_master -l reboot" CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name OVN_REPL_INFO -s ovn_ovsdb_master_server" @@ -21,6 +27,13 @@ SB_MASTER_PROTO=${OCF_RESKEY_sb_master_protocol:-${SB_MASTER_PROTO_DEFAULT}} MANAGE_NORTHD=${OCF_RESKEY_manage_northd:-${MANAGE_NORTHD_DEFAULT}} INACTIVE_PROBE=${OCF_RESKEY_inactive_probe_interval:-${INACTIVE_PROBE_DEFAULT}} +NB_PRIVKEY=${OCF_RESKEY_ovn_nb_db_privkey:-${NB_SSL_KEY_DEFAULT}} +NB_CERT=${OCF_RESKEY_ovn_nb_db_cert:-${NB_SSL_CERT_DEFAULT}} +NB_CACERT=${OCF_RESKEY_ovn_nb_db_cacert:-${NB_SSL_CACERT_DEFAULT}} +SB_PRIVKEY=${OCF_RESKEY_ovn_sb_db_privkey:-${SB_SSL_KEY_DEFAULT}} +SB_CERT=${OCF_RESKEY_ovn_sb_db_cert:-${SB_SSL_CERT_DEFAULT}} +SB_CACERT=${OCF_RESKEY_ovn_sb_db_cacert:-${SB_SSL_CACERT_DEFAULT}} + # In order for pacemaker to work with LB, we can set LISTEN_ON_MASTER_IP_ONLY # to false and pass LB vip IP while creating pcs resource. @@ -132,6 +145,54 @@ + + + OVN NB DB private key absolute path for ssl setup. + + OVN NB DB private key file + + + + + + OVN NB DB certificate absolute path for ssl setup. + + OVN NB DB cert file + + + + + + OVN NB DB CA certificate absolute path for ssl setup. + + OVN NB DB cacert file + + + + + + OVN SB DB private key absolute path for ssl setup. + + OVN SB DB private key file + + + + + + OVN SB DB certificate absolute path for ssl setup. + + OVN SB DB cert file + + + + + + OVN SB DB CA certificate absolute path for ssl setup. + + OVN SB DB cacert file + + + @@ -326,6 +387,16 @@ set $@ --db-sb-addr=${MASTER_IP} --db-sb-port=${SB_MASTER_PORT} fi + if [ "x${NB_MASTER_PROTO}" = xssl ]; then + set $@ --ovn-nb-db-ssl-key=${NB_PRIVKEY} + set $@ --ovn-nb-db-ssl-cert=${NB_CERT} + set $@ --ovn-nb-db-ssl-ca-cert=${NB_CACERT} + fi + if [ "x${SB_MASTER_PROTO}" = xssl ]; then + set $@ --ovn-sb-db-ssl-key=${SB_PRIVKEY} + set $@ --ovn-sb-db-ssl-cert=${SB_CERT} + set $@ --ovn-sb-db-ssl-ca-cert=${SB_CACERT} + fi if [ "x${present_master}" = x ]; then # No master detected, or the previous master is not among the # set starting. @@ -343,7 +414,6 @@ set $@ --db-nb-sync-from-addr=${INVALID_IP_ADDRESS} --db-sb-sync-from-addr=${INVALID_IP_ADDRESS} elif [ ${present_master} != ${host_name} ]; then - # TODO: for using LB vip, need to test for ssl. if [ "x${LISTEN_ON_MASTER_IP_ONLY}" = xyes ]; then if [ "x${NB_MASTER_PROTO}" = xtcp ]; then set $@ --db-nb-create-insecure-remote=yes diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/utilities/ovn-nbctl.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/utilities/ovn-nbctl.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovn/utilities/ovn-nbctl.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovn/utilities/ovn-nbctl.c 2020-03-11 16:15:44.000000000 +0000 @@ -117,7 +117,7 @@ size_t n_commands, struct ovsdb_idl *idl, const struct timer *); -static void server_loop(struct ovsdb_idl *idl); +static void server_loop(struct ovsdb_idl *idl, int argc, char *argv[]); int main(int argc, char *argv[]) @@ -173,26 +173,24 @@ shash_init(&local_options); apply_options_direct(parsed_options, n_parsed_options, &local_options); free(parsed_options); - argc -= optind; - argv += optind; /* Initialize IDL. */ idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false); ovsdb_idl_set_leader_only(idl, leader_only); if (get_detach()) { - if (argc != 0) { + if (argc != optind) { ctl_fatal("non-option arguments not supported with --detach " "(use --help for help)"); } - server_loop(idl); + server_loop(idl, argc, argv); } else { struct ctl_command *commands; size_t n_commands; char *error; - error = ctl_parse_commands(argc, argv, &local_options, &commands, - &n_commands); + error = ctl_parse_commands(argc - optind, argv + optind, + &local_options, &commands, &n_commands); if (error) { ctl_fatal("%s", error); } @@ -2555,7 +2553,7 @@ } struct sockaddr_storage ss_vip; - if (!inet_parse_active(lb_vip, 0, &ss_vip)) { + if (!inet_parse_active(lb_vip, 0, &ss_vip, false)) { ctl_error(ctx, "%s: should be an IP address (or an IP address " "and a port number with : as a separator).", lb_vip); return; @@ -2585,7 +2583,7 @@ struct sockaddr_storage ss_dst; if (lb_vip_port) { - if (!inet_parse_active(token, -1, &ss_dst)) { + if (!inet_parse_active(token, -1, &ss_dst, false)) { ctl_error(ctx, "%s: should be an IP address and a port " "number with : as a separator.", token); goto out; @@ -2704,7 +2702,7 @@ const struct smap_node *node = nodes[i]; struct sockaddr_storage ss; - if (!inet_parse_active(node->key, 0, &ss)) { + if (!inet_parse_active(node->key, 0, &ss, false)) { continue; } @@ -5233,6 +5231,7 @@ } struct ds output = DS_EMPTY_INITIALIZER; + table_format_reset(); for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) { if (c->table) { table_format(c->table, &table_style, &output); @@ -5271,11 +5270,12 @@ } static void -server_loop(struct ovsdb_idl *idl) +server_loop(struct ovsdb_idl *idl, int argc, char *argv[]) { struct unixctl_server *server = NULL; bool exiting = false; + service_start(&argc, &argv); daemonize_start(false); int error = unixctl_server_create(unixctl_path, &server); if (error) { @@ -5365,7 +5365,6 @@ break; VLOG_OPTION_HANDLERS - TABLE_OPTION_HANDLERS(&table_style) case OPT_LOCAL: default: diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/condition.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/condition.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/condition.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/condition.c 2020-03-11 16:15:44.000000000 +0000 @@ -125,7 +125,12 @@ free(s); return error; } + + /* Force the argument to be a scalar. */ + type.n_min = 1; + break; + case OVSDB_F_EQ: case OVSDB_F_NE: break; @@ -338,24 +343,17 @@ c->function == OVSDB_F_FALSE) { return c->function == OVSDB_F_TRUE; } - if (ovsdb_type_is_optional_scalar(type) && field->n == 0) { - switch (c->function) { - case OVSDB_F_LT: - case OVSDB_F_LE: - case OVSDB_F_EQ: - case OVSDB_F_GE: - case OVSDB_F_GT: - case OVSDB_F_INCLUDES: - return false; - case OVSDB_F_NE: - case OVSDB_F_EXCLUDES: - return true; - case OVSDB_F_TRUE: - case OVSDB_F_FALSE: - OVS_NOT_REACHED(); - } - } else if (ovsdb_type_is_scalar(type) - || ovsdb_type_is_optional_scalar(type)) { + if (ovsdb_type_is_optional_scalar(type) + && field->n == 0 + && (c->function == OVSDB_F_LT || + c->function == OVSDB_F_LE || + c->function == OVSDB_F_GT || + c->function == OVSDB_F_GE)) { + return false; + } else if ((ovsdb_type_is_scalar(type) + || ovsdb_type_is_optional_scalar(type)) + && field->n == 1 + && arg->n == 1) { int cmp = ovsdb_atom_compare_3way(&field->keys[0], &arg->keys[0], type->key.type); switch (c->function) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/file.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/file.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/file.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/file.c 2020-03-11 16:15:44.000000000 +0000 @@ -235,10 +235,14 @@ continue; } + ovsdb_datum_destroy(&dst_row->fields[dst_column->index], + &dst_column->type); + struct ovsdb_error *error = ovsdb_datum_convert( &dst_row->fields[dst_column->index], &dst_column->type, &src_row->fields[src_column->index], &src_column->type); if (error) { + ovsdb_datum_init_empty(&dst_row->fields[dst_column->index]); ovsdb_row_destroy(dst_row); return error; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/monitor.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/monitor.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/monitor.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/monitor.c 2020-03-11 16:15:44.000000000 +0000 @@ -120,6 +120,12 @@ struct hmap rows; int n_refs; uint64_t transaction; + + /* Save the mt->n_columns that is used when creating the changes. + * It can be different from the current mt->n_columns because + * mt->n_columns can be increased when there are condition changes + * from any of the clients sharing the dbmon. */ + size_t n_columns; }; /* A particular table being monitored. */ @@ -156,7 +162,8 @@ const struct ovsdb_monitor_session_condition * condition, enum ovsdb_monitor_row_type row_type, const void *, - bool initial, unsigned long int *changed); + bool initial, unsigned long int *changed, + size_t n_columns); static void ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon); static struct ovsdb_monitor_changes * ovsdb_monitor_table_add_changes( @@ -255,14 +262,15 @@ return NULL; } -/* Allocates an array of 'mt->n_columns' ovsdb_datums and initializes them as +/* Allocates an array of 'n_columns' ovsdb_datums and initializes them as * copies of the data in 'row' drawn from the columns represented by * mt->columns[]. Returns the array. * * If 'row' is NULL, returns NULL. */ static struct ovsdb_datum * clone_monitor_row_data(const struct ovsdb_monitor_table *mt, - const struct ovsdb_row *row) + const struct ovsdb_row *row, + size_t n_columns) { struct ovsdb_datum *data; size_t i; @@ -271,8 +279,8 @@ return NULL; } - data = xmalloc(mt->n_columns * sizeof *data); - for (i = 0; i < mt->n_columns; i++) { + data = xmalloc(n_columns * sizeof *data); + for (i = 0; i < n_columns; i++) { const struct ovsdb_column *c = mt->columns[i].column; const struct ovsdb_datum *src = &row->fields[c->index]; struct ovsdb_datum *dst = &data[i]; @@ -283,16 +291,17 @@ return data; } -/* Replaces the mt->n_columns ovsdb_datums in row[] by copies of the data from +/* Replaces the n_columns ovsdb_datums in row[] by copies of the data from * in 'row' drawn from the columns represented by mt->columns[]. */ static void update_monitor_row_data(const struct ovsdb_monitor_table *mt, const struct ovsdb_row *row, - struct ovsdb_datum *data) + struct ovsdb_datum *data, + size_t n_columns) { size_t i; - for (i = 0; i < mt->n_columns; i++) { + for (i = 0; i < n_columns; i++) { const struct ovsdb_column *c = mt->columns[i].column; const struct ovsdb_datum *src = &row->fields[c->index]; struct ovsdb_datum *dst = &data[i]; @@ -305,16 +314,17 @@ } } -/* Frees all of the mt->n_columns ovsdb_datums in data[], using the types taken +/* Frees all of the n_columns ovsdb_datums in data[], using the types taken * from mt->columns[], plus 'data' itself. */ static void free_monitor_row_data(const struct ovsdb_monitor_table *mt, - struct ovsdb_datum *data) + struct ovsdb_datum *data, + size_t n_columns) { if (data) { size_t i; - for (i = 0; i < mt->n_columns; i++) { + for (i = 0; i < n_columns; i++) { const struct ovsdb_column *c = mt->columns[i].column; ovsdb_datum_destroy(&data[i], &c->type); @@ -326,11 +336,12 @@ /* Frees 'row', which must have been created from 'mt'. */ static void ovsdb_monitor_row_destroy(const struct ovsdb_monitor_table *mt, - struct ovsdb_monitor_row *row) + struct ovsdb_monitor_row *row, + size_t n_columns) { if (row) { - free_monitor_row_data(mt, row->old); - free_monitor_row_data(mt, row->new); + free_monitor_row_data(mt, row->old, n_columns); + free_monitor_row_data(mt, row->new, n_columns); free(row); } } @@ -492,6 +503,7 @@ changes->transaction = next_txn; changes->mt = mt; changes->n_refs = 1; + changes->n_columns = mt->n_columns; hmap_init(&changes->rows); hmap_insert(&mt->changes, &changes->hmap_node, hash_uint64(next_txn)); @@ -552,7 +564,7 @@ HMAP_FOR_EACH_SAFE (row, next, hmap_node, &changes->rows) { hmap_remove(&changes->rows, &row->hmap_node); - ovsdb_monitor_row_destroy(changes->mt, row); + ovsdb_monitor_row_destroy(changes->mt, row, changes->n_columns); } hmap_destroy(&changes->rows); free(changes); @@ -788,7 +800,8 @@ const struct ovsdb_datum *old, const struct ovsdb_datum *new, enum ovsdb_monitor_selection type, - unsigned long int *changed) + unsigned long int *changed, + size_t n_columns) { if (!(mt->select & type)) { return true; @@ -798,8 +811,8 @@ size_t i, n_changes; n_changes = 0; - memset(changed, 0, bitmap_n_bytes(mt->n_columns)); - for (i = 0; i < mt->n_columns; i++) { + memset(changed, 0, bitmap_n_bytes(n_columns)); + for (i = 0; i < n_columns; i++) { const struct ovsdb_column *c = mt->columns[i].column; size_t index = row_type == OVSDB_ROW ? c->index : i; if (!ovsdb_datum_equals(&old[index], &new[index], &c->type)) { @@ -825,14 +838,15 @@ * going to be used as part of an "update" notification. * * 'changed' must be a scratch buffer for internal use that is at least - * bitmap_n_bytes(mt->n_columns) bytes long. */ + * bitmap_n_bytes(n_columns) bytes long. */ static struct json * ovsdb_monitor_compose_row_update( const struct ovsdb_monitor_table *mt, const struct ovsdb_monitor_session_condition *condition OVS_UNUSED, enum ovsdb_monitor_row_type row_type OVS_UNUSED, const void *_row, - bool initial, unsigned long int *changed) + bool initial, unsigned long int *changed, + size_t n_columns OVS_UNUSED) { const struct ovsdb_monitor_row *row = _row; enum ovsdb_monitor_selection type; @@ -843,7 +857,8 @@ ovs_assert(row_type == OVSDB_MONITOR_ROW); type = ovsdb_monitor_row_update_type(initial, row->old, row->new); if (ovsdb_monitor_row_skip_update(mt, row_type, row->old, - row->new, type, changed)) { + row->new, type, changed, + mt->n_columns)) { return NULL; } @@ -891,14 +906,15 @@ * false if it is going to be used as part of an "update2" notification. * * 'changed' must be a scratch buffer for internal use that is at least - * bitmap_n_bytes(mt->n_columns) bytes long. */ + * bitmap_n_bytes(n_columns) bytes long. */ static struct json * ovsdb_monitor_compose_row_update2( const struct ovsdb_monitor_table *mt, const struct ovsdb_monitor_session_condition *condition, enum ovsdb_monitor_row_type row_type, const void *_row, - bool initial, unsigned long int *changed) + bool initial, unsigned long int *changed, + size_t n_columns) { enum ovsdb_monitor_selection type; struct json *row_update2, *diff_json; @@ -914,7 +930,8 @@ type = ovsdb_monitor_row_update_type_condition(mt, condition, initial, row_type, old, new); - if (ovsdb_monitor_row_skip_update(mt, row_type, old, new, type, changed)) { + if (ovsdb_monitor_row_skip_update(mt, row_type, old, new, type, changed, + n_columns)) { return NULL; } @@ -1032,7 +1049,7 @@ HMAP_FOR_EACH_SAFE (row, next, hmap_node, &changes->rows) { struct json *row_json; row_json = (*row_update)(mt, condition, OVSDB_MONITOR_ROW, row, - initial, changed); + initial, changed, changes->n_columns); if (row_json) { ovsdb_monitor_add_json_row(&json, mt->table->schema->name, &table_json, row_json, @@ -1076,7 +1093,8 @@ row_json = ovsdb_monitor_compose_row_update2(mt, condition, OVSDB_ROW, row, - false, changed); + false, changed, + mt->n_columns); if (row_json) { ovsdb_monitor_add_json_row(&json, mt->table->schema->name, &table_json, row_json, @@ -1235,8 +1253,8 @@ change = xzalloc(sizeof *change); hmap_insert(&changes->rows, &change->hmap_node, uuid_hash(uuid)); change->uuid = *uuid; - change->old = clone_monitor_row_data(mt, old); - change->new = clone_monitor_row_data(mt, new); + change->old = clone_monitor_row_data(mt, old, changes->n_columns); + change->new = clone_monitor_row_data(mt, new, changes->n_columns); } else { if (new) { if (!change->new) { @@ -1275,12 +1293,14 @@ * replication, the row carries the same UUID as the row * just deleted. */ - change->new = clone_monitor_row_data(mt, new); + change->new = clone_monitor_row_data(mt, new, + changes->n_columns); } else { - update_monitor_row_data(mt, new, change->new); + update_monitor_row_data(mt, new, change->new, + changes->n_columns); } } else { - free_monitor_row_data(mt, change->new); + free_monitor_row_data(mt, change->new, changes->n_columns); change->new = NULL; if (!change->old) { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/mutation.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/mutation.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/mutation.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/mutation.c 2020-03-11 16:15:44.000000000 +0000 @@ -147,6 +147,8 @@ if (error && ovsdb_type_is_map(&m->type) && m->mutator == OVSDB_M_DELETE) { ovsdb_error_destroy(error); + ovsdb_base_type_destroy(&m->type.value); + m->type.value.enum_ = NULL; m->type.value.type = OVSDB_TYPE_VOID; error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2], symtab); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/ovsdb-client.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/ovsdb-client.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/ovsdb-client.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/ovsdb-client.c 2020-03-11 16:15:44.000000000 +0000 @@ -1269,7 +1269,7 @@ jsonrpc_send(rpc, request); VLOG_DBG("cond change %s %s", argv[1], argv[2]); - unixctl_command_reply(conn, "condiiton changed"); + unixctl_command_reply(conn, "condition changed"); } static void @@ -1763,9 +1763,9 @@ for (i = 1; i < argc; i++) { node = shash_find(&tschema->columns, argv[i]); if (!node) { - ovs_fatal(0, "Table \"%s\" has no column %s.", argv[0], argv[1]); + ovs_fatal(0, "Table \"%s\" has no column %s.", argv[0], argv[i]); } - shash_add(&custom_columns, argv[1], node->data); + shash_add(&custom_columns, argv[i], node->data); } } else { tables = shash_sort(&schema->tables); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/ovsdb-idlc.in openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/ovsdb-idlc.in --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/ovsdb-idlc.in 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/ovsdb-idlc.in 2020-03-11 16:15:44.000000000 +0000 @@ -1192,7 +1192,7 @@ %(s)s_index_init_row(struct ovsdb_idl_index *index) { ovs_assert(index->table->class_ == &%(p)stable_%(tl)s); - return (struct %(s)s *) ovsdb_idl_index_init_row(index); + return ALIGNED_CAST(struct %(s)s *, ovsdb_idl_index_init_row(index)); } struct %(s)s * diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/raft.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/raft.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/raft.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/raft.c 2020-03-11 16:15:44.000000000 +0000 @@ -296,6 +296,7 @@ struct raft *, const struct uuid *target_sid, const struct uuid *requester_sid, struct unixctl_conn *requester_conn, bool success, const char *comment); +static void raft_finished_leaving_cluster(struct raft *); static void raft_server_init_leader(struct raft *, struct raft_server *); @@ -303,9 +304,16 @@ static bool raft_is_rpc_synced(const struct raft *, const union raft_rpc *); static void raft_handle_rpc(struct raft *, const union raft_rpc *); -static bool raft_send(struct raft *, const union raft_rpc *); -static bool raft_send__(struct raft *, const union raft_rpc *, - struct raft_conn *); + +static bool raft_send_at(struct raft *, const union raft_rpc *, + int line_number); +#define raft_send(raft, rpc) raft_send_at(raft, rpc, __LINE__) + +static bool raft_send_to_conn_at(struct raft *, const union raft_rpc *, + struct raft_conn *, int line_number); +#define raft_send_to_conn(raft, rpc, conn) \ + raft_send_to_conn_at(raft, rpc, conn, __LINE__) + static void raft_send_append_request(struct raft *, struct raft_server *, unsigned int n, const char *comment); @@ -1055,7 +1063,7 @@ .term = raft->term, } }; - raft_send__(raft, &rpc, conn); + raft_send_to_conn(raft, &rpc, conn); raft_record_note(raft, "transfer leadership", "transferring leadership to %s because %s", @@ -1295,14 +1303,18 @@ } static void -log_rpc(const union raft_rpc *rpc, - const char *direction, const struct raft_conn *conn) +log_rpc(const union raft_rpc *rpc, const char *direction, + const struct raft_conn *conn, int line_number) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(600, 600); if (!raft_rpc_is_heartbeat(rpc) && !VLOG_DROP_DBG(&rl)) { struct ds s = DS_EMPTY_INITIALIZER; + if (line_number) { + ds_put_format(&s, "raft.c:%d ", line_number); + } + ds_put_format(&s, "%s%s ", direction, conn->nickname); raft_rpc_format(rpc, &s); - VLOG_DBG("%s%s %s", direction, conn->nickname, ds_cstr(&s)); + VLOG_DBG("%s", ds_cstr(&s)); ds_destroy(&s); } } @@ -1320,7 +1332,7 @@ .address = raft->local_address, }, }; - raft_send__(raft, &rq, conn); + raft_send_to_conn(raft, &rq, conn); } static void @@ -1345,7 +1357,7 @@ .sid = raft->sid, }, }; - raft_send__(raft, &rq, conn); + raft_send_to_conn(raft, &rq, conn); } else { union raft_rpc rq = (union raft_rpc) { .hello_request = { @@ -1356,7 +1368,7 @@ .address = raft->local_address, }, }; - raft_send__(raft, &rq, conn); + raft_send_to_conn(raft, &rq, conn); } } @@ -1366,7 +1378,7 @@ break; } - log_rpc(&rpc, "<--", conn); + log_rpc(&rpc, "<--", conn, 0); raft_handle_rpc(raft, &rpc); raft_rpc_uninit(&rpc); } @@ -1434,7 +1446,7 @@ struct raft_conn *dst = raft_find_conn_by_sid(raft, &rpc->common.sid); if (dst) { - raft_send__(raft, rpc, dst); + raft_send_to_conn(raft, rpc, dst); } } @@ -2186,16 +2198,28 @@ } static void -raft_send_remove_server_reply_rpc(struct raft *raft, const struct uuid *sid, +raft_send_remove_server_reply_rpc(struct raft *raft, + const struct uuid *dst_sid, + const struct uuid *target_sid, bool success, const char *comment) { + if (uuid_equals(&raft->sid, dst_sid)) { + if (success && uuid_equals(&raft->sid, target_sid)) { + raft_finished_leaving_cluster(raft); + } + return; + } + const union raft_rpc rpy = { .remove_server_reply = { .common = { .type = RAFT_RPC_REMOVE_SERVER_REPLY, - .sid = *sid, + .sid = *dst_sid, .comment = CONST_CAST(char *, comment), }, + .target_sid = (uuid_equals(dst_sid, target_sid) + ? UUID_ZERO + : *target_sid), .success = success, } }; @@ -2224,6 +2248,9 @@ } else { char buf[SID_LEN + 1]; ds_put_cstr(&s, raft_get_nickname(raft, target_sid, buf, sizeof buf)); + if (uuid_equals(target_sid, &raft->sid)) { + ds_put_cstr(&s, " (ourselves)"); + } } ds_put_format(&s, " from cluster "CID_FMT" %s", CID_ARGS(&raft->cid), @@ -2240,11 +2267,12 @@ * allows it to be sure that it's really removed and update its log and * disconnect permanently. */ if (!uuid_is_zero(requester_sid)) { - raft_send_remove_server_reply_rpc(raft, requester_sid, + raft_send_remove_server_reply_rpc(raft, requester_sid, target_sid, success, comment); } if (!uuid_equals(requester_sid, target_sid)) { - raft_send_remove_server_reply_rpc(raft, target_sid, success, comment); + raft_send_remove_server_reply_rpc(raft, target_sid, target_sid, + success, comment); } if (requester_conn) { if (success) { @@ -2556,9 +2584,6 @@ while (raft->commit_index < new_commit_index) { uint64_t index = ++raft->commit_index; const struct raft_entry *e = raft_get_entry(raft, index); - if (e->servers) { - raft_run_reconfigure(raft); - } if (e->data) { struct raft_command *cmd = raft_find_command_by_index(raft, index); @@ -2566,6 +2591,12 @@ raft_command_complete(raft, cmd, RAFT_CMD_SUCCESS); } } + if (e->servers) { + /* raft_run_reconfigure() can write a new Raft entry, which can + * reallocate raft->entries, which would invalidate 'e', so + * this case must be last, after the one for 'e->data'. */ + raft_run_reconfigure(raft); + } } } else { raft->commit_index = new_commit_index; @@ -3031,8 +3062,10 @@ static void raft_update_our_match_index(struct raft *raft, uint64_t min_index) { - raft_update_match_index(raft, raft_find_server(raft, &raft->sid), - min_index); + struct raft_server *server = raft_find_server(raft, &raft->sid); + if (server) { + raft_update_match_index(raft, server, min_index); + } } static void @@ -3543,17 +3576,25 @@ } static void -raft_handle_remove_server_reply(struct raft *raft, - const struct raft_remove_server_reply *rpc) +raft_finished_leaving_cluster(struct raft *raft) { - if (rpc->success) { - VLOG_INFO(SID_FMT": finished leaving cluster "CID_FMT, - SID_ARGS(&raft->sid), CID_ARGS(&raft->cid)); + VLOG_INFO(SID_FMT": finished leaving cluster "CID_FMT, + SID_ARGS(&raft->sid), CID_ARGS(&raft->cid)); - raft_record_note(raft, "left", "this server left the cluster"); + raft_record_note(raft, "left", "this server left the cluster"); - raft->leaving = false; - raft->left = true; + raft->leaving = false; + raft->left = true; +} + +static void +raft_handle_remove_server_reply(struct raft *raft, + const struct raft_remove_server_reply *rpc) +{ + if (rpc->success + && (uuid_is_zero(&rpc->target_sid) + || uuid_equals(&rpc->target_sid, &raft->sid))) { + raft_finished_leaving_cluster(raft); } } @@ -4001,10 +4042,10 @@ static bool -raft_send__(struct raft *raft, const union raft_rpc *rpc, - struct raft_conn *conn) +raft_send_to_conn_at(struct raft *raft, const union raft_rpc *rpc, + struct raft_conn *conn, int line_number) { - log_rpc(rpc, "-->", conn); + log_rpc(rpc, "-->", conn, line_number); return !jsonrpc_session_send( conn->js, raft_rpc_to_jsonrpc(&raft->cid, &raft->sid, rpc)); } @@ -4022,12 +4063,13 @@ } static bool -raft_send(struct raft *raft, const union raft_rpc *rpc) +raft_send_at(struct raft *raft, const union raft_rpc *rpc, int line_number) { const struct uuid *dst = &rpc->common.sid; if (uuid_equals(dst, &raft->sid)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_WARN_RL(&rl, "attempting to send RPC to self"); + VLOG_WARN_RL(&rl, "attempted to send RPC to self from raft.c:%d", + line_number); return false; } @@ -4035,9 +4077,10 @@ if (!conn) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); char buf[SID_LEN + 1]; - VLOG_DBG_RL(&rl, "%s: no connection to %s, cannot send RPC", - raft->local_nickname, - raft_get_nickname(raft, dst, buf, sizeof buf)); + VLOG_DBG_RL(&rl, "%s: no connection to %s, cannot send RPC " + "from raft.c:%d", raft->local_nickname, + raft_get_nickname(raft, dst, buf, sizeof buf), + line_number); return false; } @@ -4046,7 +4089,7 @@ return true; } - return raft_send__(raft, rpc, conn); + return raft_send_to_conn_at(raft, rpc, conn, line_number); } static struct raft * diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/raft-private.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/raft-private.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/raft-private.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/raft-private.c 2020-03-11 16:15:44.000000000 +0000 @@ -33,7 +33,7 @@ return NULL; } else if (!strncmp(address, "ssl:", 4) || !strncmp(address, "tcp:", 4)) { struct sockaddr_storage ss; - if (!inet_parse_active(address + 4, -1, &ss)) { + if (!inet_parse_active(address + 4, -1, &ss, true)) { return ovsdb_error(NULL, "%s: syntax error in address", address); } return NULL; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/raft-rpc.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/raft-rpc.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/raft-rpc.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/raft-rpc.c 2020-03-11 16:15:44.000000000 +0000 @@ -460,6 +460,10 @@ raft_remove_server_reply_to_jsonrpc(const struct raft_remove_server_reply *rpy, struct json *args) { + if (!uuid_is_zero(&rpy->target_sid)) { + json_object_put_format(args, "target_server", + UUID_FMT, UUID_ARGS(&rpy->target_sid)); + } json_object_put(args, "success", json_boolean_create(rpy->success)); } @@ -468,6 +472,7 @@ struct raft_remove_server_reply *rpy) { rpy->success = raft_parse_required_boolean(p, "success"); + raft_parse_optional_uuid(p, "target_server", &rpy->target_sid); } static void diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/raft-rpc.h openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/raft-rpc.h --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/raft-rpc.h 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/raft-rpc.h 2020-03-11 16:15:44.000000000 +0000 @@ -205,6 +205,13 @@ struct raft_remove_server_reply { struct raft_rpc_common common; bool success; + + /* SID of the removed server, but all-zeros if it is the same as the + * destination of the RPC. (Older ovsdb-server did not have 'target_sid' + * and assumed that the destination was always the target, so by omitting + * 'target_sid' when this is the case we can preserve a small amount of + * inter-version compatibility.) */ + struct uuid target_sid; }; struct raft_install_snapshot_request { diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/replication.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/replication.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/ovsdb/replication.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/ovsdb/replication.c 2020-03-11 16:15:44.000000000 +0000 @@ -299,19 +299,7 @@ /* After receiving schemas, reset the local databases that * will be monitored and send out monitor requests for them. */ if (hmap_is_empty(&request_ids)) { - struct shash_node *node, *next; - - SHASH_FOR_EACH_SAFE (node, next, replication_dbs) { - db = node->data; - error = reset_database(db); - if (error) { - const char *db_name = db->schema->name; - shash_find_and_delete(replication_dbs, db_name); - ovsdb_error_assert(error); - VLOG_WARN("Failed to reset database, " - "%s not replicated.", db_name); - } - } + struct shash_node *node; if (shash_is_empty(replication_dbs)) { VLOG_WARN("Nothing to replicate."); @@ -335,7 +323,16 @@ case RPL_S_MONITOR_REQUESTED: { /* Reply to monitor requests. */ struct ovsdb_error *error; - error = process_notification(msg->result, db); + VLOG_INFO("Monitor request received. Resetting the database"); + /* Resetting the database here has few risks. If the + * process_notification() fails, the database is completely + * lost locally. In case that node becomes active, then + * there is a chance of complete data loss in the active/standy + * cluster. */ + error = reset_database(db); + if (!error) { + error = process_notification(msg->result, db); + } if (error) { ovsdb_error_assert(error); state = RPL_S_ERR; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/db/idl.py openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/db/idl.py --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/db/idl.py 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/db/idl.py 2020-03-11 16:15:44.000000000 +0000 @@ -855,7 +855,7 @@ if removes is not None: for key in removes: if key not in (inserts or {}): - del dmap[key] + dmap.pop(key, None) datum = data.Datum.from_python(column.type, dmap, _row_to_uuid) else: diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/_json.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/_json.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/_json.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/_json.c 2020-03-11 16:15:44.000000000 +0000 @@ -170,6 +170,7 @@ json = json_parser_finish(self->_parser); self->_parser = NULL; obj = json_to_python(json); + json_destroy(json); return obj; } diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/json.py openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/json.py --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/json.py 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/json.py 2020-03-11 16:15:44.000000000 +0000 @@ -21,10 +21,13 @@ import six +PARSER_C = 'C' +PARSER_PY = 'PYTHON' try: import ovs._json + PARSER = PARSER_C except ImportError: - pass + PARSER = PARSER_PY __pychecker__ = 'no-stringiter' @@ -91,10 +94,9 @@ MAX_HEIGHT = 1000 def __new__(cls, *args, **kwargs): - try: + if PARSER == PARSER_C: return ovs._json.Parser(*args, **kwargs) - except NameError: - return super(Parser, cls).__new__(cls) + return super(Parser, cls).__new__(cls) def __init__(self, check_trailer=False): self.check_trailer = check_trailer diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/jsonrpc.py openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/jsonrpc.py --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/jsonrpc.py 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/jsonrpc.py 2020-03-11 16:15:44.000000000 +0000 @@ -272,7 +272,8 @@ # data, so we convert it here as soon as possible. if data and not error: try: - data = decoder.decode(data) + if six.PY3 or ovs.json.PARSER == ovs.json.PARSER_PY: + data = decoder.decode(data) except UnicodeError: error = errno.EILSEQ if error: @@ -298,7 +299,11 @@ else: if self.parser is None: self.parser = ovs.json.Parser() - self.input = self.input[self.parser.feed(self.input):] + if six.PY3 and ovs.json.PARSER == ovs.json.PARSER_C: + self.input = self.input.encode('utf-8')[ + self.parser.feed(self.input):].decode() + else: + self.input = self.input[self.parser.feed(self.input):] if self.parser.is_done(): msg = self.__process_msg() if msg: diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/socket_util.py openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/socket_util.py --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/socket_util.py 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/socket_util.py 2020-03-11 16:15:44.000000000 +0000 @@ -178,7 +178,7 @@ pfds = p.poll(0) if len(pfds) == 1: revents = pfds[0][1] - if revents & ovs.poller.POLLERR: + if revents & ovs.poller.POLLERR or revents & ovs.poller.POLLHUP: try: # The following should raise an exception. sock.send("\0".encode(), socket.MSG_DONTWAIT) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/stream.py openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/stream.py --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/stream.py 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/stream.py 2020-03-11 16:15:44.000000000 +0000 @@ -741,7 +741,11 @@ error, sock = ovs.socket_util.inet_open_active(socket.SOCK_STREAM, suffix, 0, dscp) if not error: - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + try: + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + except socket.error as e: + sock.close() + return ovs.socket_util.get_exception_errno(e), None return error, sock diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/vlog.py openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/vlog.py --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/python/ovs/vlog.py 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/python/ovs/vlog.py 2020-03-11 16:15:44.000000000 +0000 @@ -139,7 +139,7 @@ min_width = int(matches.group(2)) if len(replace) < min_width: replace = replace.center(min_width) - return re.sub(match, replace, tmp) + return re.sub(match, replace.replace('\\', r'\\'), tmp) def _format_time(self, tmp): date_regex = re.compile('(%(0?[1-9]?[dD])(\{(.*)\})?)') @@ -237,7 +237,7 @@ Vlog.__file_handler = logging.FileHandler(Vlog.__log_file) logger.addHandler(Vlog.__file_handler) except (IOError, socket.error): - logger.setLevel(logging.CRITICAL) + logger.disabled = True ovs.unixctl.command_register("vlog/reopen", "", 0, 0, Vlog._unixctl_vlog_reopen, None) @@ -305,20 +305,19 @@ return logger = logging.getLogger('syslog') - # If there is no infrastructure to support python syslog, disable - # the logger to avoid repeated errors. - if not os.path.exists("/dev/log"): - logger.disabled = True - return + + if facility is None: + facility = syslog_facility + + new_handler = logging.handlers.SysLogHandler(address="/dev/log", + facility=facility) if syslog_handler: logger.removeHandler(syslog_handler) - if facility: - syslog_facility = facility + syslog_handler = new_handler + syslog_facility = facility - syslog_handler = logging.handlers.SysLogHandler(address="/dev/log", - facility=syslog_facility) logger.addHandler(syslog_handler) return @@ -342,7 +341,11 @@ return "Please supply a valid pattern and destination" elif words[0] == "FACILITY": if words[1] in FACILITIES: - Vlog.add_syslog_handler(words[1]) + try: + Vlog.add_syslog_handler(words[1]) + except (IOError, socket.error): + logger = logging.getLogger('syslog') + logger.disabled = True return else: return "Facility %s is invalid" % words[1] diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/README.rst openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/README.rst --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/README.rst 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/README.rst 2020-03-11 16:15:44.000000000 +0000 @@ -1,5 +1,6 @@ -.. NOTE(stephenfin): If making changes to this file, ensure that the line - numbers found in 'Documentation/intro/what-is-ovs' are kept up-to-date. +.. NOTE(stephenfin): If making changes to this file, ensure that the + start-after/end-before lines found in 'Documentation/intro/what-is-ovs' + are kept up-to-date. ============ Open vSwitch diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/etc_init.d_openvswitch openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/etc_init.d_openvswitch --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/etc_init.d_openvswitch 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/etc_init.d_openvswitch 2020-03-11 16:15:44.000000000 +0000 @@ -28,6 +28,7 @@ ### END INIT INFO SYSTEMCTL_SKIP_REDIRECT=yes +SYSTEMD_NO_WRAP=yes . /usr/share/openvswitch/scripts/ovs-lib || exit 1 test -e /etc/sysconfig/openvswitch && . /etc/sysconfig/openvswitch diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/openvswitch-fedora.spec.in openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/openvswitch-fedora.spec.in --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/openvswitch-fedora.spec.in 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/openvswitch-fedora.spec.in 2020-03-11 16:15:44.000000000 +0000 @@ -223,6 +223,7 @@ --with-dpdk=$(dirname %{_datadir}/dpdk/*/.config) \ %endif --enable-ssl \ + --enable-shared \ --with-pkidir=%{_sharedstatedir}/openvswitch/pki \ %if 0%{?fedora} > 22 || %{with build_python3} PYTHON3=%{__python3} \ @@ -396,7 +397,7 @@ -c "Open vSwitch Daemons" openvswitch %if %{with dpdk} - getent group hugetlbfs >/dev/null || groupadd hugetlbfs + getent group hugetlbfs >/dev/null || groupadd -r hugetlbfs usermod -a -G hugetlbfs openvswitch %endif exit 0 @@ -422,7 +423,7 @@ %else # Package install, not upgrade if [ $1 -eq 1 ]; then - /bin/systemctl daemon-reload >dev/null || : + /bin/systemctl daemon-reload >/dev/null || : fi %endif @@ -523,6 +524,7 @@ %{python2_sitelib}/ovstest %files devel +%{_libdir}/lib*.so %{_libdir}/*.a %{_libdir}/*.la %{_libdir}/pkgconfig/*.pc @@ -571,6 +573,7 @@ %{_bindir}/ovs-testcontroller %{_bindir}/ovs-pki %{_bindir}/vtep-ctl +%{_libdir}/lib*.so.* %{_sbindir}/ovs-bugtool %{_sbindir}/ovs-vswitchd %{_sbindir}/ovsdb-server diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/openvswitch-kmod-fedora.spec.in openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/openvswitch-kmod-fedora.spec.in --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/openvswitch-kmod-fedora.spec.in 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/openvswitch-kmod-fedora.spec.in 2020-03-11 16:15:44.000000000 +0000 @@ -80,6 +80,15 @@ fi fi +%posttrans +# The upgrade path from the older kmod-openvswitch SysV package to +# the newer openvswitch-kmod systemd package will end up removing +# the symlinks to the weak-updates/openvswitch drivers because of +# it's %postun section. We add this section to handle that case. +if [ -x "%{_datadir}/openvswitch/scripts/ovs-kmod-manage.sh" ]; then + %{_datadir}/openvswitch/scripts/ovs-kmod-manage.sh +fi + %files %defattr(0644,root,root) /lib/modules/%{kernel}/extra/*.ko diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/usr_lib_systemd_system_ovn-controller.service openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/usr_lib_systemd_system_ovn-controller.service --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/usr_lib_systemd_system_ovn-controller.service 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/usr_lib_systemd_system_ovn-controller.service 2020-03-11 16:15:44.000000000 +0000 @@ -21,6 +21,7 @@ [Service] Type=forking +PIDFile=/var/run/openvswitch/ovn-controller.pid Restart=on-failure EnvironmentFile=-/etc/sysconfig/ovn-controller ExecStart=/usr/share/openvswitch/scripts/ovn-ctl --no-monitor \ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/usr_lib_systemd_system_ovsdb-server.service openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/usr_lib_systemd_system_ovsdb-server.service --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/usr_lib_systemd_system_ovsdb-server.service 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/usr_lib_systemd_system_ovsdb-server.service 2020-03-11 16:15:44.000000000 +0000 @@ -7,6 +7,7 @@ [Service] Type=forking +PIDFile=/var/run/openvswitch/ovsdb-server.pid Restart=on-failure EnvironmentFile=/etc/openvswitch/default.conf EnvironmentFile=-/etc/sysconfig/openvswitch diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/usr_lib_systemd_system_ovs-vswitchd.service.in openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/usr_lib_systemd_system_ovs-vswitchd.service.in --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/rhel/usr_lib_systemd_system_ovs-vswitchd.service.in 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/rhel/usr_lib_systemd_system_ovs-vswitchd.service.in 2020-03-11 16:15:44.000000000 +0000 @@ -9,6 +9,7 @@ [Service] Type=forking +PIDFile=/var/run/openvswitch/ovs-vswitchd.pid Restart=on-failure Environment=HOME=/var/run/openvswitch EnvironmentFile=/etc/openvswitch/default.conf diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/selinux/openvswitch-custom.te.in openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/selinux/openvswitch-custom.te.in --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/selinux/openvswitch-custom.te.in 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/selinux/openvswitch-custom.te.in 2020-03-11 16:15:44.000000000 +0000 @@ -16,6 +16,7 @@ type init_t; type init_var_run_t; type insmod_exec_t; + type kernel_t; type hostname_exec_t; type modules_conf_t; type modules_object_t; @@ -32,7 +33,6 @@ @begin_dpdk@ type hugetlbfs_t; - type kernel_t; type svirt_t; type svirt_image_t; type svirt_tmpfs_t; @@ -50,7 +50,7 @@ class netlink_audit_socket { create nlmsg_relay audit_write read write }; class netlink_socket { setopt getopt create connect getattr write read }; class sock_file { write }; - class system module_load; + class system { module_load module_request }; class process { sigchld signull transition noatsecure siginh rlimitinh }; class unix_stream_socket { write getattr read connectto connect setopt getopt sendto accept bind recvfrom acceptfrom ioctl }; @@ -107,6 +107,7 @@ allow openvswitch_load_module_t init_t:unix_stream_socket { getattr ioctl read write }; allow openvswitch_load_module_t init_var_run_t:dir { getattr read open search }; allow openvswitch_load_module_t insmod_exec_t:file { execute execute_no_trans getattr map open read }; +allow openvswitch_load_module_t kernel_t:system module_request; allow openvswitch_load_module_t modules_conf_t:dir { getattr open read search }; allow openvswitch_load_module_t modules_conf_t:file { getattr open read }; allow openvswitch_load_module_t modules_object_t:file { map getattr open read }; @@ -117,7 +118,7 @@ allow openvswitch_load_module_t proc_t:file { getattr open read }; allow openvswitch_load_module_t self:system module_load; allow openvswitch_load_module_t self:process { siginh noatsecure rlimitinh siginh }; -allow openvswitch_load_module_t shell_exec_t:file { map execute read open getattr }; +allow openvswitch_load_module_t shell_exec_t:file { map execute execute_no_trans read open getattr }; allow openvswitch_load_module_t sssd_public_t:dir { getattr open read search }; allow openvswitch_load_module_t sssd_public_t:file { getattr map open read }; allow openvswitch_load_module_t sssd_t:unix_stream_socket connectto; diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/atlocal.in openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/atlocal.in --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/atlocal.in 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/atlocal.in 2020-03-11 16:15:44.000000000 +0000 @@ -190,6 +190,9 @@ # Set HAVE_TCPDUMP find_command tcpdump +# Set HAVE_LFTP +find_command lftp + CURL_OPT="-g -v --max-time 1 --retry 2 --retry-delay 1 --connect-timeout 1" # Determine whether "diff" supports "normal" diffs. (busybox diff does not.) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/automake.mk openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/automake.mk --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/automake.mk 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/automake.mk 2020-03-11 16:15:44.000000000 +0000 @@ -404,6 +404,10 @@ tests_ovstest_LDADD = lib/libopenvswitch.la ovn/lib/libovn.la +noinst_PROGRAMS += tests/test-stream +tests_test_stream_SOURCES = tests/test-stream.c +tests_test_stream_LDADD = lib/libopenvswitch.la + noinst_PROGRAMS += tests/test-strtok_r tests_test_strtok_r_SOURCES = tests/test-strtok_r.c diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/bridge.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/bridge.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/bridge.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/bridge.at 2020-03-11 16:15:44.000000000 +0000 @@ -79,3 +79,27 @@ OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) OVS_APP_EXIT_AND_WAIT([ovsdb-server]) AT_CLEANUP + +AT_SETUP([bridge - add port after stopping controller]) +OVS_VSWITCHD_START + +dnl Start ovs-testcontroller +AT_CHECK([ovs-testcontroller --detach punix:controller --pidfile], [0], [ignore]) +OVS_WAIT_UNTIL([test -e controller]) + +AT_CHECK([ovs-vsctl set-controller br0 unix:controller]) +AT_CHECK([ovs-vsctl add-port br0 p1 -- set Interface p1 type=internal], [0], [ignore]) +AT_CHECK([ovs-appctl -t ovs-vswitchd version], [0], [ignore]) + +# Now kill the ovs-testcontroller +kill `cat ovs-testcontroller.pid` +if test "$IS_WIN32" = "yes"; then + AT_CHECK([rm controller], [0], [ignore]) +fi +OVS_WAIT_UNTIL([! test -e controller]) +AT_CHECK([ovs-vsctl --no-wait add-port br0 p2 -- set Interface p2 type=internal], [0], [ignore]) +AT_CHECK([ovs-appctl -t ovs-vswitchd version], [0], [ignore]) + +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) +AT_CLEANUP diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/dpif-netdev.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/dpif-netdev.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/dpif-netdev.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/dpif-netdev.at 2020-03-11 16:15:44.000000000 +0000 @@ -110,8 +110,10 @@ m4_define([DPIF_NETDEV_MISS_FLOW_INSTALL], [AT_SETUP([dpif-netdev - miss upcall key matches flow_install - $1]) OVS_VSWITCHD_START( - [add-port br0 p1 -- set interface p1 type=$1 options:pstream=punix:$OVS_RUNDIR/p0.sock - set bridge br0 datapath-type=dummy other-config:datapath-id=1234 fail-mode=secure], [], [], + [add-port br0 p1 \ + -- set interface p1 type=$1 options:pstream=punix:$OVS_RUNDIR/p0.sock \ + -- set bridge br0 datapath-type=dummy \ + other-config:datapath-id=1234 fail-mode=secure], [], [], [m4_if([$1], [dummy-pmd], [--dummy-numa="0,0,0,0,1,1,1,1"], [])]) AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg]) @@ -150,8 +152,10 @@ m4_define([DPIF_NETDEV_MISS_FLOW_DUMP], [AT_SETUP([dpif-netdev - miss upcall key matches flow_dump - $1]) OVS_VSWITCHD_START( - [add-port br0 p1 -- set interface p1 type=$1 options:pstream=punix:$OVS_RUNDIR/p0.sock - set bridge br0 datapath-type=dummy other-config:datapath-id=1234 fail-mode=secure], [], [], + [add-port br0 p1 \ + -- set interface p1 type=$1 options:pstream=punix:$OVS_RUNDIR/p0.sock \ + -- set bridge br0 datapath-type=dummy \ + other-config:datapath-id=1234 fail-mode=secure], [], [], [m4_if([$1], [dummy-pmd], [--dummy-numa="0,0,0,0,1,1,1,1"], [])]) AT_CHECK([ovs-appctl upcall/disable-ufid], [0], [Datapath dumping tersely using UFID disabled ], []) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/.gitignore openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/.gitignore --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/.gitignore 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/.gitignore 2020-03-11 16:15:44.000000000 +0000 @@ -51,6 +51,7 @@ /test-sha1 /test-skiplist /test-stp +/test-stream /test-strtok_r /test-timeval /test-type-props diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/nsh.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/nsh.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/nsh.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/nsh.at 2020-03-11 16:15:44.000000000 +0000 @@ -374,7 +374,7 @@ decap() Final flow: recirc_id=0x1,eth,in_port=4,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000 -Megaflow: recirc_id=0x1,packet_type=(1,0x894f),in_port=4,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_c1=0x11223344 +Megaflow: recirc_id=0x1,packet_type=(1,0x894f),in_port=4,dl_type=0x894f,nsh_mdtype=1,nsh_np=3,nsh_spi=0x1234,nsh_c1=0x11223344 Datapath actions: pop_nsh(),recirc(0x2) ]) @@ -413,7 +413,7 @@ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:push_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_nsh(flags=0,ttl=63,mdtype=1,np=4,spi=0x5678,si=255,c1=0x55667788,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),recirc(0x3) -recirc_id(0x3),in_port(1),packet_type(ns=1,id=0x894f),nsh(mdtype=1,np=3,spi=0x1234,c1=0x11223344), packets:1, bytes:122, used:0.0s, actions:pop_nsh(),recirc(0x4) +recirc_id(0x3),in_port(1),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(mdtype=1,np=3,spi=0x1234,c1=0x11223344), packets:1, bytes:122, used:0.0s, actions:pop_nsh(),recirc(0x4) recirc_id(0x4),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:2 ]) @@ -725,8 +725,8 @@ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789)) -tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(np=1,spi=0x3000,si=255), packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x1) -tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x1),in_port(4789),packet_type(ns=1,id=0x800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6 +tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3000,si=255), packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x1) +tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x1),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6 ]) AT_CHECK([ @@ -779,9 +779,9 @@ ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789)) -tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(spi=0x3020,si=255), packets:1, bytes:108, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)) -tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),nsh(np=1,spi=0x3020,si=254), packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x2) -tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x2),in_port(4789),packet_type(ns=1,id=0x800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6 +tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(spi=0x3020,si=255), packets:1, bytes:108, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)) +tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3020,si=254), packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x2) +tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x2),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6 ]) AT_CHECK([ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ofproto.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ofproto.at 2020-03-11 16:15:44.000000000 +0000 @@ -678,6 +678,20 @@ AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=first,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1], [1], [], [ovs-ofctl: insert-bucket needs OpenFlow 1.5 or later ('-O OpenFlow15') ]) + +# Verify insert-buckets command to insert bucket with weight value for select group. +AT_CHECK([ovs-ofctl -O OpenFlow15 --strict del-groups br0 group_id=1234]) +AT_DATA([groups.txt], [dnl +group_id=1234,type=select,selection_method=hash,bucket=bucket_id=1,weight:100,output:11 +]) +AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt]) +AT_CHECK([ovs-ofctl -O OpenFlow15 insert-buckets br0 group_id=1234,command_bucket_id=last,bucket=bucket_id=2,weight=100,actions=output:11]) +AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout]) +AT_CHECK([strip_xids < stdout], [0], [dnl +OFPST_GROUP_DESC reply (OF1.5): + group_id=1234,type=select,selection_method=hash,bucket=bucket_id:1,weight:100,actions=output:11,bucket=bucket_id:2,weight:100,actions=output:11 +]) + OVS_VSWITCHD_STOP AT_CLEANUP @@ -1241,6 +1255,22 @@ OFPST_GROUP reply (OF1.5): ]) OVS_VSWITCHD_STOP +AT_CLEANUP + +dnl This is used to find that the bucket counter is not updated. +AT_SETUP([ofproto - group stats after insert a new bucket (OpenFlow 1.5)]) +OVS_VSWITCHD_START +AT_DATA([groups.txt], [dnl +group_id=1234,type=select,selection_method=hash bucket=bucket_id=1,weight:100,actions=output:10 +]) +AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt]) +AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 'group_id=1234, command_bucket_id=last, bucket=bucket_id=2,weight:100,actions=output:10']) +AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-group-stats br0 group_id=1234], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl + group_id=1234,duration=?s,ref_count=0,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0,bucket1:packet_count=0,byte_count=0 +OFPST_GROUP reply (OF1.5): +]) +OVS_VSWITCHD_STOP AT_CLEANUP dnl This found a use-after-free error in bridge destruction in the diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto-dpif.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ofproto-dpif.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ofproto-dpif.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ofproto-dpif.at 2020-03-11 16:15:44.000000000 +0000 @@ -4337,11 +4337,11 @@ OVS_VSWITCHD_START add_of_ports br0 1 2 3 4 5 6 90 AT_DATA([flows.txt], [dnl -priority=75 tcp ip_frag=no tp_dst=80 actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:1 -priority=75 tcp ip_frag=first tp_dst=80 actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:2 -priority=50 tcp ip_frag=no actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:4 -priority=50 tcp ip_frag=first actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:5 -priority=50 tcp ip_frag=later actions=output:6 +priority=75 tcp nw_frag=no tp_dst=80 actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:1 +priority=75 tcp nw_frag=first tp_dst=80 actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:2 +priority=50 tcp nw_frag=no actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:4 +priority=50 tcp nw_frag=first actions=move:OXM_OF_TCP_DST[[]]->OXM_OF_TCP_SRC[[]],output:5 +priority=50 tcp nw_frag=later actions=output:6 ]) AT_CHECK([ovs-ofctl replace-flows br0 flows.txt]) @@ -5393,6 +5393,74 @@ -- set interface patch11 type=patch options:peer=patch10 \ ofport_request=11]) +AT_SETUP([ofproto-dpif - continuation flow stats]) +AT_KEYWORDS([continuations pause resume]) +OVS_VSWITCHD_START + +add_of_ports --pcap br0 `seq 1 2` + +flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)" + +AT_DATA([flows.txt], [dnl +table=0 in_port=1 actions=set_field:1->reg1 controller(pause) resubmit(,2) +table=2 reg1=0x1 actions=2 +]) + +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br0 flows.txt]) + +AT_CAPTURE_FILE([ofctl_monitor0.log]) +ovs-ofctl monitor br0 resume --detach --no-chdir \ +--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log + +# Run a packet through the switch. +AT_CHECK([ovs-appctl netdev-dummy/receive p1 "$flow"], [0], [stdout]) + +# Check flow stats +AT_CHECK([ovs-ofctl dump-flows br0], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sed -n 's/duration=[[0-9]]*\.[[0-9]]*s/duration=0.0s/p' | sed -n 's/idle_age=[[0-9]]*/idle_age=0/p' | grep 'table=2'], [0], [dnl + cookie=0x0, duration=0.0s, table=2, n_packets=1, n_bytes=106, idle_age=0, reg1=0x1 actions=output:2 +]) + +# The packet should be received by port 2 +AT_CHECK([test 1 = `$PYTHON "$top_srcdir/utilities/ovs-pcap.in" p2-tx.pcap | wc -l`]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto-dpif - continuation with conntrack]) +AT_KEYWORDS([continuations pause resume]) +OVS_VSWITCHD_START + +add_of_ports --pcap br0 `seq 1 2` + +flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)" + +AT_DATA([flows.txt], [dnl +table=0, in_port=1 icmp action=ct(table=1) +table=1, icmp action=controller(pause) resubmit(,2) +table=2, in_port=1 icmp ct_state=+trk+new action=output:2 +]) + +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br0 flows.txt]) + +AT_CAPTURE_FILE([ofctl_monitor0.log]) +ovs-ofctl monitor br0 resume --detach --no-chdir \ +--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log + +# Run a packet through the switch. +AT_CHECK([ovs-appctl netdev-dummy/receive p1 "$flow"], [0], [stdout]) + +# Check flow stats +AT_CHECK([ovs-ofctl dump-flows br0], [0], [stdout]) +AT_CHECK([strip_xids < stdout | sed -n 's/duration=[[0-9]]*\.[[0-9]]*s/duration=0.0s/p' | sed -n 's/idle_age=[[0-9]]*/idle_age=0/p' | grep 'table=2'], [0], [dnl + cookie=0x0, duration=0.0s, table=2, n_packets=1, n_bytes=106, idle_age=0, ct_state=+new+trk,icmp,in_port=1 actions=output:2 +]) + +# The packet should be received by port 2 +AT_CHECK([test 1 = `$PYTHON "$top_srcdir/utilities/ovs-pcap.in" p2-tx.pcap | wc -l`]) + +OVS_VSWITCHD_STOP +AT_CLEANUP # Check that pause works after the packet is cloned. AT_SETUP([ofproto-dpif - continuation after clone]) @@ -5424,7 +5492,7 @@ ovs-vsctl show ovs-ofctl dump-flows br0 -# The packet should be recieved by port 2 and not port 3 +# The packet should be received by port 2 and not port 3 AT_CHECK([test 1 = `$PYTHON "$top_srcdir/utilities/ovs-pcap.in" p2-tx.pcap | wc -l`]) AT_CHECK([test 0 = `$PYTHON "$top_srcdir/utilities/ovs-pcap.in" p3-tx.pcap | wc -l`]) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovn.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovn.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovn.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovn.at 2020-03-11 16:15:44.000000000 +0000 @@ -287,6 +287,8 @@ inport == "eth0" !(inport != "eth0") => inport == "eth0" +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) => 0 + ip4.src == "eth0" => Integer field ip4.src is not compatible with string constant. inport == 1 => String field inport is not compatible with integer constant. ip4.src = 1.2.3.4 => Syntax error at `=' expecting relational operator. @@ -353,6 +355,10 @@ ip4.src == {1.2.3.4, $set1, $unknownset} => Syntax error at `$unknownset' expecting address set name. eth.src == {$set3, badmac, 00:00:00:00:00:01} => Syntax error at `badmac' expecting constant. + +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) => Parentheses nested too deeply. + +ct_label > $set4 => Only == and != operators may be used to compare a field against an empty value set. ]]) sed 's/ =>.*//' test-cases.txt > input.txt sed 's/.* => //' test-cases.txt > expout @@ -1100,9 +1106,9 @@ # put_dhcp_opts reg1[0] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1); encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.04.0a.00.00.01,pause) -reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain="ovn.org"); - formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain = "ovn.org"); - encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67,pause) +reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain="ovn.org",wpad="https://example.org"); + formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain = "ovn.org", wpad = "https://example.org"); + encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67,pause) reg0[15] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.255.0,mtu=1400,ip_forward_enable=1,default_ttl=121,dns_server={8.8.8.8,7.7.7.7},classless_static_route={30.0.0.0/24,10.0.0.4,40.0.0.0/16,10.0.0.6,0.0.0.0/0,10.0.0.1},ethernet_encap=1,router_discovery=0); formats as reg0[15] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.255.0, mtu = 1400, ip_forward_enable = 1, default_ttl = 121, dns_server = {8.8.8.8, 7.7.7.7}, classless_static_route = {30.0.0.0/24, 10.0.0.4, 40.0.0.0/16, 10.0.0.6, 0.0.0.0/0, 10.0.0.1}, ethernet_encap = 1, router_discovery = 0); encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.ff.00.1a.02.05.78.13.01.01.17.01.79.06.08.08.08.08.08.07.07.07.07.79.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.01.01.1f.01.00,pause) @@ -1256,9 +1262,11 @@ reg1[0] = put_nd_ra_opts(addr_mode = "slaac", mtu = 1500, prefix = aef0::/64); slla option not present reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateful", mtu = 1450, prefix = aef0::/64, prefix = bef0::/64, slla = ae:01:02:03:04:10); - prefix option can't be set when address mode is dhcpv6_stateful. + encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.80.ff.ff.00.00.00.00.00.00.00.00.05.01.00.00.00.00.05.aa.03.04.40.80.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.03.04.40.80.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.be.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.10,pause) + has prereqs ip6 reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateful", mtu = 1450, prefix = aef0::/64, prefix = bef0::/64, slla = ae:01:02:03:04:10); - prefix option can't be set when address mode is dhcpv6_stateful. + encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.80.ff.ff.00.00.00.00.00.00.00.00.05.01.00.00.00.00.05.aa.03.04.40.80.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.03.04.40.80.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.be.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.10,pause) + has prereqs ip6 reg1[0] = put_nd_ra_opts(addr_mode = "slaac", slla = ae:01:02:03:04:10); prefix option needs to be set when address mode is slaac/dhcpv6_stateless. reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateless", slla = ae:01:02:03:04:10); @@ -4613,15 +4621,23 @@ # from the "ovs-ofctl monitor br-int resume" test_dhcpv6() { local inport=$1 src_mac=$2 src_lla=$3 msg_code=$4 offer_ip=$5 - local request=ffffffffffff${src_mac}86dd00000000002a1101${src_lla} + if test $msg_code != 0b; then + req_len=2a + else + req_len=1a + fi + local request=ffffffffffff${src_mac}86dd0000000000${req_len}1101${src_lla} # dst ip ff02::1:2 request=${request}ff020000000000000000000000010002 # udp header and dhcpv6 header - request=${request}02220223002affff${msg_code}010203 + request=${request}0222022300${req_len}ffff${msg_code}010203 # Client identifier request=${request}0001000a00030001${src_mac} - # IA-NA (Identity Association for Non Temporary Address) - request=${request}0003000c0102030400000e1000001518 + # Add IA-NA (Identity Association for Non Temporary Address) if msg_code + # is not 11 (information request packet) + if test $msg_code != 0b; then + request=${request}0003000c0102030400000e1000001518 + fi shift; shift; shift; shift; shift; if test $offer_ip != 0; then local server_mac=000000100001 @@ -4752,7 +4768,7 @@ AT_CHECK([cat 4.packets], [0], [expout]) # Send DHCPv6 packet on ls1-lp3. native DHCPv6 works as stateless mode for this port. -# The DHCPv6 reply should doesn't contian offer_ip. +# The DHCPv6 reply shouldn't contain offer_ip. src_mac=f00000000022 src_lla=fe80000000000000f20000fffe000022 reset_pcap_file hv1-vif5 hv1/vif5 @@ -4766,6 +4782,23 @@ cat 5.expected | cut -c 1-120,125- > expout AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout]) +# Send DHCPv6 information request (code 11) on ls1-lp3. The DHCPv6 reply +# shouldn't contain offer_ip +src_mac=f00000000022 +src_lla=fe80000000000000f20000fffe000022 +reset_pcap_file hv1-vif5 hv1/vif5 +rm -f 5.expected +test_dhcpv6 5 $src_mac $src_lla 0b 1 5 + +# NXT_RESUMEs should be 4. +OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif5-tx.pcap | +trim_zeros > 5.packets +# Skipping the UDP checksum +cat 5.expected | cut -c 1-120,125- > expout +AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout]) + as hv1 OVS_APP_EXIT_AND_WAIT([ovn-controller]) OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) @@ -6500,15 +6533,25 @@ ovs-appctl netdev-dummy/receive lp1 'in_port(1),eth(src=f0:00:00:00:00:01,dst=f0:00:00:00:00:02),eth_type(0x0800),ipv4(src=192.168.1.2,dst=192.168.1.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=7777,dst=82)' done +# The rate at which packets are sent is highly system-dependent, so we +# can't count on precise drop counts. To work around that, we just +# check that exactly 100 "http-acl3" actions were logged and that there +# were more "http-acl1" actions than "http-acl2" ones. +OVS_WAIT_UNTIL([ test 100 = $(grep -c 'http-acl3' hv/ovn-controller.log) ]) + +# On particularly slow or overloaded systems, the transmission rate may +# be lower than the configured meter rate. To prevent false test +# failures, we check the duration count of the meter, and if it's +# greater than nine seconds, just skip the test. +d_secs=$(as hv ovs-ofctl -O OpenFlow13 meter-stats br-int | grep "meter:1" | sed 's/.* duration:\([[0-9]]\{1,\}\)\.[[0-9]]\+s .*/\1/') + +echo "Meter duration: $d_secs" +AT_SKIP_IF([test $d_secs -gt 9]) + # Print some information that may help debugging. as hv ovs-appctl -t ovn-controller meter-table-list as hv ovs-ofctl -O OpenFlow13 meter-stats br-int -# The userspace meter implementation doesn't precisely enforce counts, -# so we just check that exactly 100 "http-acl3" actions were logged and -# that there were more "http-acl1" actions than "http-acl2" ones. -OVS_WAIT_UNTIL([ test 100 = $(grep -c 'http-acl3' hv/ovn-controller.log) ]) - n_acl1=$(grep -c 'http-acl1' hv/ovn-controller.log) n_acl2=$(grep -c 'http-acl2' hv/ovn-controller.log) n_acl3=$(grep -c 'http-acl3' hv/ovn-controller.log) @@ -6516,7 +6559,6 @@ AT_CHECK([ test $n_acl3 -gt $n_acl1 ], [0], []) AT_CHECK([ test $n_acl1 -gt $n_acl2 ], [0], []) - OVN_CLEANUP([hv]) AT_CLEANUP @@ -7035,6 +7077,17 @@ echo $packet >> expected1 OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1]) +# Send broadcast packet from foo1. foo1 should not receive the same packet. +src_mac="f00000010205" +dst_mac="ffffffffffff" +src_ip=`ip_to_hex 192 168 1 2` +dst_ip=`ip_to_hex 255 255 255 255` +packet=${dst_mac}${src_mac}8100000108004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 +as hv1 ovs-appctl netdev-dummy/receive vm1 $packet + +# expected packet at VM1 +OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1]) + OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP @@ -8707,7 +8760,7 @@ OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) addr_mode=80 -default_prefix_option_config="" +default_prefix_option_config=03044080ffffffffffffffff00000000 src_mac=fa163e000004 src_lla=fe80000000000000f8163efffe000004 mtu=000005dc @@ -9544,6 +9597,10 @@ 2001:db8:1:0:200:02ff:fe01:0204/64 \ -- set Logical_Router_port ip6_public options:redirect-chassis="hv1" +#install static route +ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \ +ip_prefix="\:\:/0" nexthop="2001\:db8\:1\:0\:200\:02ff\:fe01\:1305" \ +-- add Logical_Router lr0_ip6 static_routes @lrt ovn-nbctl lsp-add public rp-ip6_public -- set Logical_Switch_Port \ rp-ip6_public type=router options:router-port=ip6_public \ @@ -9586,36 +9643,82 @@ sed 's/\(00\)\{1,\}$//' } +reset_pcap_file() { + local iface=$1 + local pcap_file=$2 + ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \ +options:rxq_pcap=dummy-rx.pcap + rm -f ${pcap_file}*.pcap + ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \ +options:rxq_pcap=${pcap_file}-rx.pcap +} + # Test the IPv6 Neighbor Solicitation (NS) - nd_ns action for unknown MAC # addresses. ovn-controller should generate an IPv6 NS request for IPv6 # packets whose MAC is unknown (in the ARP_REQUEST router pipeline stage. # test_ipv6 INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT... # This function sends ipv6 packet test_ipv6() { - local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 - dst_ip=20010db800010000020002fffe010205 + local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 + local dst_mcast_mac=$6 mcast_node_ip=$7 nd_target=$8 local packet=${dst_mac}${src_mac}86dd6000000000083aff${src_ip}${dst_ip} packet=${packet}8000000000000000 - shift; shift; shift; shift - dst_mac=3333ff010205 src_mac=000002010204 - mcast_node_ip=ff0200000000000000000001ff010205 - expected_packet=${dst_mac}${src_mac}86dd6000000000203aff${src_ip} - expected_packet=${expected_packet}${mcast_node_ip}8700XXXX00000000${dst_ip} - expected_packet=${expected_packet}0101${src_mac} + expected_packet=${dst_mcast_mac}${src_mac}86dd6000000000203aff${src_ip} + expected_packet=${expected_packet}${mcast_node_ip}8700XXXX00000000 + expected_packet=${expected_packet}${nd_target}0101${src_mac} as hv1 ovs-appctl netdev-dummy/receive hv1-vif${inport} $packet + rm -f ipv6_ns.expected echo $expected_packet >> ipv6_ns.expected } src_mac=506400000002 dst_mac=00000000af01 src_ip=aef0000000000000526400fffe000002 +dst_ip=20010db800010000020002fffe010205 +dst_mcast_mac=3333ff010205 +mcast_node_ip=ff0200000000000000000001ff010205 +nd_target=20010db800010000020002fffe010205 # Send an IPv6 packet. Generated IPv6 Neighbor solicitation packet # should be received by the ports attached to br-phys. -test_ipv6 1 $src_mac $dst_mac $src_ip 2 +test_ipv6 1 $src_mac $dst_mac $src_ip $dst_ip $dst_mcast_mac \ +$mcast_node_ip $nd_target + +OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys_n1-tx.pcap | cut -d " " -f1)]) +OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys-tx.pcap | cut -d " " -f1)]) + +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys_n1-tx.pcap | \ +trim_zeros > 1.packets +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys-tx.pcap | \ +trim_zeros > 2.packets + +cat ipv6_ns.expected | cut -c -112 > expout +AT_CHECK([cat 1.packets | cut -c -112], [0], [expout]) +AT_CHECK([cat 2.packets | cut -c -112], [0], [expout]) + +# Skipping the ICMPv6 checksum +cat ipv6_ns.expected | cut -c 117- > expout +AT_CHECK([cat 1.packets | cut -c 117-], [0], [expout]) +AT_CHECK([cat 2.packets | cut -c 117-], [0], [expout]) + +# Now send a packet with destination ip other than +# 2001:db8:1:0:200:02ff:fe01:0204/64 prefix. +reset_pcap_file br-phys_n1 hv1/br-phys_n1 +reset_pcap_file br-phys hv1/br-phys + +src_mac=506400000002 +dst_mac=00000000af01 +src_ip=aef0000000000000526400fffe000002 +dst_ip=20020ab8000100000200020000020306 +# multicast mac of the nexthop IP - 2001:db8:1:0:200:02ff:fe01:1305 +dst_mcast_mac=3333ff011305 +mcast_node_ip=ff0200000000000000000001ff011305 +nd_target=20010db800010000020002fffe011305 +test_ipv6 1 $src_mac $dst_mac $src_ip $dst_ip $dst_mcast_mac \ +$mcast_node_ip $nd_target OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys_n1-tx.pcap | cut -d " " -f1)]) OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys-tx.pcap | cut -d " " -f1)]) @@ -9900,7 +10003,7 @@ # And the other address mode ovn-nbctl --wait=hv set Logical_Router_Port ro-sw ipv6_ra_configs:address_mode=dhcpv6_stateless -ra_test 000005dc 40 80 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000 +ra_test 000005dc 40 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000 OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP @@ -11194,3 +11297,43 @@ OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP + +AT_SETUP([ovn -- ipam to non-ipam]) +ovn_start + +ovn-nbctl ls-add sw0 +ovn-nbctl lsp-add sw0 p0 -- lsp-set-addresses p0 dynamic +ovn-nbctl --wait=sb add Logical-Switch sw0 other_config subnet=192.168.1.0/24 + +AT_CHECK([ovn-nbctl get Logical-Switch-Port p0 dynamic_addresses], [0], + ["0a:00:00:00:00:01 192.168.1.2" +]) + +ovn-nbctl lsp-set-addresses p0 router + +ovn-nbctl get Logical-Switch-Port p0 dynamic_addresses + +AT_CHECK([ovn-nbctl get Logical-Switch-Port p0 dynamic_addresses], [0], [[[]] +]) +AT_CLEANUP + +AT_SETUP([ovn -- ipam router ports]) +ovn_start + +ovn-nbctl ls-add sw +ovn-nbctl set logical_switch sw other-config:subnet=192.168.1.0/24 + +for i in 2 3 4; do + ovn-nbctl lr-add ro$i + ovn-nbctl lsp-add sw swp$i + ovn-nbctl --wait=sb lsp-set-addresses swp$i "02:00:00:00:00:0$i dynamic" + cidr=$(ovn-nbctl get logical_switch_port swp$i dynamic_addresses |cut -f2 -d' '|cut -f1 -d\") + ovn-nbctl lrp-add ro$i rop$i 02:00:00:00:00:0$i $cidr/24 -- set logical_switch_port swp$i type=router options:router-port=rop$i addresses=router; + AT_CHECK_UNQUOTED([ovn-nbctl get logical_router_port rop$i networks], [0], [[["192.168.1.$i/24"]] +]) +done + +ovn-nbctl list logical_switch_port +ovn-nbctl list logical_router_port + +AT_CLEANUP diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovn-nbctl.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovn-nbctl.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovn-nbctl.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovn-nbctl.at 2020-03-11 16:15:44.000000000 +0000 @@ -1517,3 +1517,25 @@ AT_CHECK([ovn-nbctl get Port_Group pg0 name], [0], [dnl "pg0" ])]) + + +OVN_NBCTL_TEST([ovn_nbctl_extra_newlines], [extra newlines], [ +dnl This test addresses a specific issue seen when running ovn-nbctl in +dnl daemon mode. All we have to do is ensure that each time we list database +dnl information, there is not an extra newline at the beginning of the output. +AT_CHECK([ovn-nbctl ls-add sw1], [0], [ignore]) +AT_CHECK([ovn-nbctl --columns=name list logical_switch sw1], [0], [dnl +name : "sw1" +]) +AT_CHECK([ovn-nbctl --columns=name list logical_switch sw1], [0], [dnl +name : "sw1" +])]) + +OVN_NBCTL_TEST([ovn_nbctl_table_formatting], [table formatting], [ +dnl This test addresses a specific issue seen when running ovn-nbctl in +dnl daemon mode. We need to ensure that table formatting options are honored +dnl when listing database information. +AT_CHECK([ovn-nbctl ls-add sw1], [0], [ignore]) +AT_CHECK([ovn-nbctl --bare --columns=name list logical_switch sw1], [0], [dnl +sw1 +])]) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovsdb-condition.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovsdb-condition.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovsdb-condition.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovsdb-condition.at 2020-03-11 16:15:44.000000000 +0000 @@ -92,7 +92,58 @@ '[["u", ">", ["uuid", "b10d28f7-af18-4a67-9e78-2a6394516c59"]]]' \ '[["u", ">=", ["uuid", "9179ca6d-6d65-400a-b455-3ad92783a099"]]]' \ '[["u", "<", ["uuid", "ad0fa355-8b84-4a36-a4b5-b2c1bfd91758"]]]' \ - '[["u", "<=", ["uuid", "62315898-64e0-40b9-b26f-ff74225303e6"]]]']], + '[["u", "<=", ["uuid", "62315898-64e0-40b9-b26f-ff74225303e6"]]]' \ + '[["i", "==", ["set", []]]]' \ + '[["i", "!=", ["set", []]]]' \ + '[["i", ">", ["set", []]]]' \ + '[["i", ">=", ["set", []]]]' \ + '[["i", "<", ["set", []]]]' \ + '[["i", "<=", ["set", []]]]' \ + '[["i", "includes", ["set", []]]]' \ + '[["i", "excludes", ["set", []]]]' \ + '[["i", ">", ["set", []]]]' \ + '[["i", "==", ["set", []]]]' \ + '[["r", "==", ["set", []]]]' \ + '[["r", "!=", ["set", []]]]' \ + '[["r", ">", ["set", []]]]' \ + '[["r", ">=", ["set", []]]]' \ + '[["r", "<", ["set", []]]]' \ + '[["r", "<=", ["set", []]]]' \ + '[["r", "includes", ["set", []]]]' \ + '[["r", "excludes", ["set", []]]]' \ + '[["r", ">", ["set", []]]]' \ + '[["r", "==", ["set", []]]]' \ + '[["b", "==", ["set", []]]]' \ + '[["b", "!=", ["set", []]]]' \ + '[["b", ">", ["set", []]]]' \ + '[["b", ">=", ["set", []]]]' \ + '[["b", "<", ["set", []]]]' \ + '[["b", "<=", ["set", []]]]' \ + '[["b", "includes", ["set", []]]]' \ + '[["b", "excludes", ["set", []]]]' \ + '[["b", ">", ["set", []]]]' \ + '[["b", "==", ["set", []]]]' \ + '[["s", "==", ["set", []]]]' \ + '[["s", "!=", ["set", []]]]' \ + '[["s", ">", ["set", []]]]' \ + '[["s", ">=", ["set", []]]]' \ + '[["s", "<", ["set", []]]]' \ + '[["s", "<=", ["set", []]]]' \ + '[["s", "includes", ["set", []]]]' \ + '[["s", "excludes", ["set", []]]]' \ + '[["s", ">", ["set", []]]]' \ + '[["s", "==", ["set", []]]]' \ + '[["u", "==", ["set", []]]]' \ + '[["u", "!=", ["set", []]]]' \ + '[["u", ">", ["set", []]]]' \ + '[["u", ">=", ["set", []]]]' \ + '[["u", "<", ["set", []]]]' \ + '[["u", "<=", ["set", []]]]' \ + '[["u", "includes", ["set", []]]]' \ + '[["u", "excludes", ["set", []]]]' \ + '[["u", ">", ["set", []]]]' \ + '[["u", "==", ["set", []]]]' \ +]], [1], [], [[test-ovsdb: syntax "["b",">",true]": syntax error: Type mismatch: ">" operator may not be applied to column b of type boolean. test-ovsdb: syntax "["b",">=",false]": syntax error: Type mismatch: ">=" operator may not be applied to column b of type boolean. @@ -106,6 +157,209 @@ test-ovsdb: syntax "["u",">=",["uuid","9179ca6d-6d65-400a-b455-3ad92783a099"]]": syntax error: Type mismatch: ">=" operator may not be applied to column u of type uuid. test-ovsdb: syntax "["u","<",["uuid","ad0fa355-8b84-4a36-a4b5-b2c1bfd91758"]]": syntax error: Type mismatch: "<" operator may not be applied to column u of type uuid. test-ovsdb: syntax "["u","<=",["uuid","62315898-64e0-40b9-b26f-ff74225303e6"]]": syntax error: Type mismatch: "<=" operator may not be applied to column u of type uuid. +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["b",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column b of type boolean. +test-ovsdb: syntax "["b",">=",["set",[]]]": syntax error: Type mismatch: ">=" operator may not be applied to column b of type boolean. +test-ovsdb: syntax "["b","<",["set",[]]]": syntax error: Type mismatch: "<" operator may not be applied to column b of type boolean. +test-ovsdb: syntax "["b","<=",["set",[]]]": syntax error: Type mismatch: "<=" operator may not be applied to column b of type boolean. +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["b",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column b of type boolean. +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["s",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column s of type string. +test-ovsdb: syntax "["s",">=",["set",[]]]": syntax error: Type mismatch: ">=" operator may not be applied to column s of type string. +test-ovsdb: syntax "["s","<",["set",[]]]": syntax error: Type mismatch: "<" operator may not be applied to column s of type string. +test-ovsdb: syntax "["s","<=",["set",[]]]": syntax error: Type mismatch: "<=" operator may not be applied to column s of type string. +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["s",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column s of type string. +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["u",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column u of type uuid. +test-ovsdb: syntax "["u",">=",["set",[]]]": syntax error: Type mismatch: ">=" operator may not be applied to column u of type uuid. +test-ovsdb: syntax "["u","<",["set",[]]]": syntax error: Type mismatch: "<" operator may not be applied to column u of type uuid. +test-ovsdb: syntax "["u","<=",["set",[]]]": syntax error: Type mismatch: "<=" operator may not be applied to column u of type uuid. +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["u",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column u of type uuid. +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +]]) +AT_CLEANUP + +OVSDB_CHECK_POSITIVE([conditions on optional scalars], + [[parse-conditions \ + '{"columns": + {"i": {"type": {"key": "integer", "min": 0, "max": 1}}, + "r": {"type": {"key": "real", "min": 0, "max": 1}}, + "b": {"type": {"key": "boolean", "min": 0, "max": 1}}, + "s": {"type": {"key": "string", "min": 0, "max": 1}}, + "u": {"type": {"key": "uuid", "min": 0, "max": 1}}}}' \ + '[["i", "==", 0]]' \ + '[["i", "!=", 1]]' \ + '[["i", "<", 2]]' \ + '[["i", "<=", 3]]' \ + '[["i", ">", 4]]' \ + '[["i", ">=", 5]]' \ + '[["i", "includes", 6]]' \ + '[["i", "excludes", 7]]' \ + '[["r", "==", 0.5]]' \ + '[["r", "!=", 1.5]]' \ + '[["r", "<", 2.5]]' \ + '[["r", "<=", 3.5]]' \ + '[["r", ">", 4.5]]' \ + '[["r", ">=", 5.5]]' \ + '[["r", "includes", 6.5]]' \ + '[["r", "excludes", 7.5]]' \ + '[["b", "==", true]]' \ + '[["b", "!=", false]]' \ + '[["b", "includes", false]]' \ + '[["b", "excludes", true]]' \ + '[["s", "==", "a"]]' \ + '[["s", "!=", "b"]]' \ + '[["s", "includes", "c"]]' \ + '[["s", "excludes", "d"]]' \ + '[["u", "==", ["uuid", "b10d28f7-af18-4a67-9e78-2a6394516c59"]]]' \ + '[["u", "!=", ["uuid", "9179ca6d-6d65-400a-b455-3ad92783a099"]]]' \ + '[["u", "includes", ["uuid", "ad0fa355-8b84-4a36-a4b5-b2c1bfd91758"]]]' \ + '[["u", "excludes", ["uuid", "62315898-64e0-40b9-b26f-ff74225303e6"]]]']], + [[[["i","==",0]] +[["i","!=",1]] +[["i","<",2]] +[["i","<=",3]] +[["i",">",4]] +[["i",">=",5]] +[["i","includes",6]] +[["i","excludes",7]] +[["r","==",0.5]] +[["r","!=",1.5]] +[["r","<",2.5]] +[["r","<=",3.5]] +[["r",">",4.5]] +[["r",">=",5.5]] +[["r","includes",6.5]] +[["r","excludes",7.5]] +[["b","==",true]] +[["b","!=",false]] +[["b","includes",false]] +[["b","excludes",true]] +[["s","==","a"]] +[["s","!=","b"]] +[["s","includes","c"]] +[["s","excludes","d"]] +[["u","==",["uuid","b10d28f7-af18-4a67-9e78-2a6394516c59"]]] +[["u","!=",["uuid","9179ca6d-6d65-400a-b455-3ad92783a099"]]] +[["u","includes",["uuid","ad0fa355-8b84-4a36-a4b5-b2c1bfd91758"]]] +[["u","excludes",["uuid","62315898-64e0-40b9-b26f-ff74225303e6"]]]]], + [condition]) + +AT_SETUP([disallowed conditions on optional scalars]) +AT_KEYWORDS([ovsdb negative condition]) +AT_CHECK([[test-ovsdb parse-conditions \ + '{"columns": + {"i": {"type": {"key": "integer", "min": 0, "max": 1}}, + "r": {"type": {"key": "real", "min": 0, "max": 1}}, + "b": {"type": {"key": "boolean", "min": 0, "max": 1}}, + "s": {"type": {"key": "string", "min": 0, "max": 1}}, + "u": {"type": {"key": "uuid", "min": 0, "max": 1}}}}' \ + '[["b", ">", true]]' \ + '[["b", ">=", false]]' \ + '[["b", "<", false]]' \ + '[["b", "<=", false]]' \ + '[["s", ">", "a"]]' \ + '[["s", ">=", "b"]]' \ + '[["s", "<", "c"]]' \ + '[["s", "<=", "d"]]' \ + '[["u", ">", ["uuid", "b10d28f7-af18-4a67-9e78-2a6394516c59"]]]' \ + '[["u", ">=", ["uuid", "9179ca6d-6d65-400a-b455-3ad92783a099"]]]' \ + '[["u", "<", ["uuid", "ad0fa355-8b84-4a36-a4b5-b2c1bfd91758"]]]' \ + '[["u", "<=", ["uuid", "62315898-64e0-40b9-b26f-ff74225303e6"]]]' \ + '[["i", ">", ["set", []]]]' \ + '[["i", ">=", ["set", []]]]' \ + '[["i", "<", ["set", []]]]' \ + '[["i", "<=", ["set", []]]]' \ + '[["i", ">", ["set", []]]]' \ + '[["r", ">", ["set", []]]]' \ + '[["r", ">=", ["set", []]]]' \ + '[["r", "<", ["set", []]]]' \ + '[["r", "<=", ["set", []]]]' \ + '[["r", ">", ["set", []]]]' \ + '[["b", ">", ["set", []]]]' \ + '[["b", ">=", ["set", []]]]' \ + '[["b", "<", ["set", []]]]' \ + '[["b", "<=", ["set", []]]]' \ + '[["b", ">", ["set", []]]]' \ + '[["s", ">", ["set", []]]]' \ + '[["s", ">=", ["set", []]]]' \ + '[["s", "<", ["set", []]]]' \ + '[["s", "<=", ["set", []]]]' \ + '[["s", ">", ["set", []]]]' \ + '[["u", ">", ["set", []]]]' \ + '[["u", ">=", ["set", []]]]' \ + '[["u", "<", ["set", []]]]' \ + '[["u", "<=", ["set", []]]]' \ + '[["u", ">", ["set", []]]]' \ +]], + [1], [], [[test-ovsdb: syntax "["b",">",true]": syntax error: Type mismatch: ">" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["b",">=",false]": syntax error: Type mismatch: ">=" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["b","<",false]": syntax error: Type mismatch: "<" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["b","<=",false]": syntax error: Type mismatch: "<=" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["s",">","a"]": syntax error: Type mismatch: ">" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["s",">=","b"]": syntax error: Type mismatch: ">=" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["s","<","c"]": syntax error: Type mismatch: "<" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["s","<=","d"]": syntax error: Type mismatch: "<=" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["u",">",["uuid","b10d28f7-af18-4a67-9e78-2a6394516c59"]]": syntax error: Type mismatch: ">" operator may not be applied to column u of type set of up to 1 uuids. +test-ovsdb: syntax "["u",">=",["uuid","9179ca6d-6d65-400a-b455-3ad92783a099"]]": syntax error: Type mismatch: ">=" operator may not be applied to column u of type set of up to 1 uuids. +test-ovsdb: syntax "["u","<",["uuid","ad0fa355-8b84-4a36-a4b5-b2c1bfd91758"]]": syntax error: Type mismatch: "<" operator may not be applied to column u of type set of up to 1 uuids. +test-ovsdb: syntax "["u","<=",["uuid","62315898-64e0-40b9-b26f-ff74225303e6"]]": syntax error: Type mismatch: "<=" operator may not be applied to column u of type set of up to 1 uuids. +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["set",[]]": syntax error: set must have exactly one member but 0 are present +test-ovsdb: syntax "["b",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["b",">=",["set",[]]]": syntax error: Type mismatch: ">=" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["b","<",["set",[]]]": syntax error: Type mismatch: "<" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["b","<=",["set",[]]]": syntax error: Type mismatch: "<=" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["b",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column b of type set of up to 1 booleans. +test-ovsdb: syntax "["s",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["s",">=",["set",[]]]": syntax error: Type mismatch: ">=" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["s","<",["set",[]]]": syntax error: Type mismatch: "<" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["s","<=",["set",[]]]": syntax error: Type mismatch: "<=" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["s",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column s of type set of up to 1 strings. +test-ovsdb: syntax "["u",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column u of type set of up to 1 uuids. +test-ovsdb: syntax "["u",">=",["set",[]]]": syntax error: Type mismatch: ">=" operator may not be applied to column u of type set of up to 1 uuids. +test-ovsdb: syntax "["u","<",["set",[]]]": syntax error: Type mismatch: "<" operator may not be applied to column u of type set of up to 1 uuids. +test-ovsdb: syntax "["u","<=",["set",[]]]": syntax error: Type mismatch: "<=" operator may not be applied to column u of type set of up to 1 uuids. +test-ovsdb: syntax "["u",">",["set",[]]]": syntax error: Type mismatch: ">" operator may not be applied to column u of type set of up to 1 uuids. ]]) AT_CLEANUP @@ -600,7 +854,11 @@ [["i", ">", 1]], [["i", "includes", 1]], [["i", "excludes", 1]], - [["i", ">", 0], ["i", "<", 2]]]' \ + [["i", ">", 0], ["i", "<", 2]], + [["i", "==", ["set", []]]], + [["i", "!=", ["set", []]]], + [["i", "includes", ["set", []]]], + [["i", "excludes", ["set", []]]]]' \ '[{"i": ["set", []]}, {"i": ["set", [0]]}, {"i": ["set", [1]]}, @@ -614,7 +872,11 @@ condition 5: ---T condition 6: --T- condition 7: TT-T -condition 8: --T-], [condition]) +condition 8: --T- +condition 9: T--- +condition 10: -TTT +condition 11: TTTT +condition 12: TTTT], [condition]) OVSDB_CHECK_POSITIVE([evaluating conditions on optional strings], [[evaluate-conditions \ @@ -654,7 +916,11 @@ [["r", ">", 5.0]], [["r", "includes", 5.0]], [["r", "excludes", 5.0]], - [["r", "!=", 0], ["r", "!=", 5.1]]]' \ + [["r", "!=", 0], ["r", "!=", 5.1]], + [["r", "==", ["set", []]]], + [["r", "!=", ["set", []]]], + [["r", "includes", ["set", []]]], + [["r", "excludes", ["set", []]]]]' \ '[{"r": ["set", [0]]}, {"r": ["set", [5.0]]}, {"r": ["set", [5.1]]}, @@ -668,7 +934,11 @@ condition 5: --T- condition 6: -T-- condition 7: T-TT -condition 8: -T-T], [condition]) +condition 8: -T-T +condition 9: ---T +condition 10: TTT- +condition 11: TTTT +condition 12: TTTT], [condition]) OVSDB_CHECK_POSITIVE([evaluating false boolean condition], [[evaluate-conditions-any \ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovsdb-idl.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovsdb-idl.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovsdb-idl.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovsdb-idl.at 2020-03-11 16:15:44.000000000 +0000 @@ -1785,6 +1785,23 @@ 008: End test ]]) +m4_define([CHECK_STREAM_OPEN_BLOCK], + [AT_SETUP([Check Stream open block - C - $1]) + AT_SKIP_IF([test "$1" = "tcp6" && test "$IS_WIN32" = "yes"]) + AT_SKIP_IF([test "$1" = "tcp6" && test "$HAVE_IPV6" = "no"]) + AT_KEYWORDS([Check Stream open block $1]) + AT_CHECK([ovsdb_start_idltest "ptcp:0:$2"]) + PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT]) + WRONG_PORT=$(($TCP_PORT+1)) + AT_CHECK([test-stream tcp:$2:$TCP_PORT], [0], [ignore]) + AT_CHECK([test-stream tcp:$2:$WRONG_PORT], [1], [ignore], [ignore]) + OVSDB_SERVER_SHUTDOWN + AT_CHECK([test-stream tcp:$2:$TCP_PORT], [1], [ignore], [ignore]) + AT_CLEANUP]) + +CHECK_STREAM_OPEN_BLOCK([tcp], [127.0.0.1]) +CHECK_STREAM_OPEN_BLOCK([tcp6], [[[::1]]]) + m4_define([CHECK_STREAM_OPEN_BLOCK_PY], [AT_SETUP([$1]) AT_SKIP_IF([test $2 = no]) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovsdb-monitor.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovsdb-monitor.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/ovsdb-monitor.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/ovsdb-monitor.at 2020-03-11 16:15:44.000000000 +0000 @@ -589,3 +589,71 @@ [[[["name","==","one"]]]], [[[false]]], [[[true]]]]) + + +AT_SETUP(monitor-cond-change with many sessions pending) +AT_KEYWORDS([ovsdb server monitor monitor-cond negative]) +ordinal_schema > schema +AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore]) + +AT_CAPTURE_FILE([ovsdb-server-log]) +AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket --log-file="`pwd`"/ovsdb-server-log db >/dev/null 2>&1]) +on_exit 'kill `cat ovsdb-server.pid`' +for txn in m4_foreach([txn], [[[["ordinals", + {"op": "insert", + "table": "ordinals", + "row": {"number": 0, "name": "zero"}}, + {"op": "insert", + "table": "ordinals", + "row": {"number": 1, "name": "one"}}, + {"op": "insert", + "table": "ordinals", + "row": {"number": 2, "name": "two"}}]]]], ['txn' ]); do + AT_CHECK([ovsdb-client transact unix:socket "$txn"], [0], [ignore], [ignore]) +done + +# 1001 clients monitoring column "name" and with condition for "name" only. +# The clients are created in a way that the 991th client will request condition +# change, so that the chance is high that the condition change will be handled +# before some pending changes are freed. + +cond='[[["name","==","ten"]]]' +for i in `seq 1 990`; do + AT_CHECK([ovsdb-client -vjsonrpc --pidfile=ovsdb-client$i.pid --detach --no-chdir -d json monitor-cond --format=csv unix:socket ordinals $cond ordinals ["name"]], [0], [ignore], [ignore]) +done + +AT_CHECK([ovsdb-client -vjsonrpc --pidfile --detach --no-chdir -d json monitor-cond --format=csv unix:socket ordinals $cond ordinals ["name"] > output], + [0], [ignore], [ignore]) + +for i in `seq 991 1000`; do + AT_CHECK([ovsdb-client -vjsonrpc --pidfile=ovsdb-client$i.pid --detach --no-chdir -d json monitor-cond --format=csv unix:socket ordinals $cond ordinals ["name"]], [0], [ignore], [ignore]) +done + +for txn in m4_foreach([txn], [[[["ordinals", + {"op": "insert", + "table": "ordinals", + "row": {"number": 10, "name": "ten"}}]]]], ['txn' ]); do + AT_CHECK([ovsdb-client transact unix:socket "$txn"], [0], + [ignore], [ignore], [kill `cat server-pid client-pid`]) +done + +# Change the condition so that a new column "number" is added to monitor table. +cond='[[["number","==",1]]]' +AT_CHECK([ovs-appctl -t ovsdb-client ovsdb-client/cond_change ordinals $cond], [0], [ignore], [ignore]) + +# Give some time for the server to flush and free pending changes +# (to crash, when n_columns is not handled properly) +sleep 1 + +AT_CHECK([ovsdb-client transact unix:socket '[["ordinals"]]'], [0], + [ignore], [ignore]) +AT_CHECK([ovs-appctl -t ovsdb-server -e exit], [0], [ignore], [ignore]) +OVS_WAIT_UNTIL([test ! -e ovsdb-server.pid && test ! -e ovsdb-client.pid]) +AT_CHECK([$PYTHON $srcdir/ovsdb-monitor-sort.py < output | uuidfilt], [0], [[row,action,name +<0>,insert,"""ten""" + +row,action,name +<0>,delete, +<1>,insert,"""one""" +]], [ignore]) +AT_CLEANUP diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/packet-type-aware.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/packet-type-aware.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/packet-type-aware.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/packet-type-aware.at 2020-03-11 16:15:44.000000000 +0000 @@ -400,8 +400,8 @@ ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)) -tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.10,frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:01),n1 -tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:84, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)) +tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:01),n1 +tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:84, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)) ]) # Clear up megaflow cache @@ -505,7 +505,7 @@ ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)) -tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop +tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop ]) OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"]) @@ -1020,7 +1020,7 @@ ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort ], [0], [flow-dump from non-dpdk interfaces: recirc_id(0),in_port(p0),packet_type(ns=0,id=0),eth(src=aa:bb:cc:00:00:02,dst=aa:bb:cc:00:00:01),eth_type(0x0800),ipv4(dst=20.0.0.1,proto=47,frag=no), packets:3, bytes:378, used:0.0s, actions:tnl_pop(gre_sys) -tunnel(src=20.0.0.2,dst=20.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x8847),mpls(label=999/0x0,tc=0/0,ttl=64/0x0,bos=1/1), packets:3, bytes:264, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),pop_mpls(eth_type=0x800),recirc(0x1) +tunnel(src=20.0.0.2,dst=20.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x8847),eth_type(0x8847),mpls(label=999/0x0,tc=0/0,ttl=64/0x0,bos=1/1), packets:3, bytes:264, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),pop_mpls(eth_type=0x800),recirc(0x1) tunnel(src=20.0.0.2,dst=20.0.0.1,flags(-df-csum)),recirc_id(0x1),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=00:00:00:00:00:00),eth_type(0x0800),ipv4(ttl=64,frag=no), packets:3, bytes:294, used:0.0s, actions:set(ipv4(ttl=63)),int-br ]) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/system-kmod-macros.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/system-kmod-macros.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/system-kmod-macros.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/system-kmod-macros.at 2020-03-11 16:15:44.000000000 +0000 @@ -114,6 +114,13 @@ # m4_define([CHECK_CONNTRACK_NAT]) +# CHECK_CT_DPIF_PER_ZONE_LIMIT() +# +# Perform requirements checks for running ovs-dpctl ct-[set|get|del]-limits per +# zone. The kernel datapath does support this feature. Will remove this check +# after both kernel and userspace datapath support it. +m4_define([CHECK_CT_DPIF_PER_ZONE_LIMIT]) + # CHECK_CT_DPIF_SET_GET_MAXCONNS() # # Perform requirements checks for running ovs-dpctl ct-set-maxconns or diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/system-traffic.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/system-traffic.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/system-traffic.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/system-traffic.at 2020-03-11 16:15:44.000000000 +0000 @@ -527,6 +527,46 @@ OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([datapath - flow resume with geneve tun_metadata]) +OVS_CHECK_GENEVE() + +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-underlay]) + +ADD_NAMESPACES(at_ns0) + +dnl Set up underlay link from host into the namespace using veth pair. +ADD_VETH(p0, at_ns0, br-underlay, "172.31.1.1/24") +AT_CHECK([ip addr add dev br-underlay "172.31.1.100/24"]) +AT_CHECK([ip link set dev br-underlay up]) + +dnl Set up tunnel endpoints on OVS outside the namespace and with a native +dnl linux device inside the namespace. +ADD_OVS_TUNNEL([geneve], [br0], [at_gnv0], [172.31.1.1], [10.1.1.100/24]) +ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24], + [vni 0]) + +dnl Set up flows +AT_DATA([flows.txt], [dnl +table=0, arp action=NORMAL +table=0, in_port=LOCAL icmp action=output:at_gnv0 +table=0, in_port=at_gnv0 icmp action=set_field:0xa->tun_metadata0,resubmit(,1) +table=1, icmp action=controller(pause), resubmit(,2) +table=2, tun_metadata0=0xa, icmp action=output:LOCAL +]) +AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0"]) +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) +AT_CHECK([ovs-ofctl add-flow br-underlay "actions=normal"]) + +AT_CHECK([ovs-ofctl monitor br0 resume --detach --no-chdir --pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log]) + +NS_CHECK_EXEC([at_ns0], [ping -q -c 3 10.1.1.100 | FORMAT_PING], [0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([datapath - ping over geneve6 tunnel]) OVS_CHECK_GENEVE_UDP6ZEROCSUM() @@ -2920,7 +2960,7 @@ AT_SETUP([conntrack - limit by zone]) CHECK_CONNTRACK() -CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE() +CHECK_CT_DPIF_PER_ZONE_LIMIT() OVS_TRAFFIC_VSWITCHD_START() ADD_NAMESPACES(at_ns0, at_ns1) @@ -3776,8 +3816,9 @@ dnl Checks the implementation of conntrack with FTP ALGs in combination with dnl NAT, using the provided flow table. m4_define([CHECK_FTP_NAT], - [AT_SETUP([conntrack - FTP NAT $1]) + [AT_SETUP([conntrack - FTP $1]) AT_SKIP_IF([test $HAVE_FTP = no]) + AT_SKIP_IF([test $HAVE_LFTP = no]) CHECK_CONNTRACK() CHECK_CONNTRACK_NAT() CHECK_CONNTRACK_ALG() @@ -3798,7 +3839,18 @@ OVS_START_L7([at_ns1], [ftp]) dnl FTP requests from p0->p1 should work fine. - NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 -4 --no-passive-ftp -t 3 -T 1 --retry-connrefused -v --server-response --no-remove-listing -o wget0.log -d]) + AT_DATA([ftp.cmd], [dnl +set net:max-retries 1 +set net:timeout 1 +set ftp:passive-mode off +cache off +connect ftp://anonymous:@10.1.1.2 +ls +ls +ls +ls +]) + NS_CHECK_EXEC([at_ns0], [lftp -f ftp.cmd > lftp.log]) dnl Discards CLOSE_WAIT and CLOSING AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [$4]) @@ -3806,7 +3858,7 @@ OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP]) -dnl CHECK_FTP_NAT_PRE_RECIRC(TITLE, IP_ADDR, IP_ADDR_AS_HEX) +dnl CHECK_FTP_SNAT_PRE_RECIRC(TITLE, IP_ADDR, IP_ADDR_AS_HEX) dnl dnl Checks the implementation of conntrack with FTP ALGs in combination with dnl NAT, with flow tables that implement the NATing as part of handling of @@ -3814,8 +3866,8 @@ dnl dnl IP_ADDR must specify the NAT address in standard "10.1.1.x" format, dnl and IP_ADDR_AS_HEX must specify the same address as hex, eg 0x0a0101xx. -m4_define([CHECK_FTP_NAT_PRE_RECIRC], [dnl - CHECK_FTP_NAT([prerecirc $1], [$2], [dnl +m4_define([CHECK_FTP_SNAT_PRE_RECIRC], [dnl + CHECK_FTP_NAT([SNAT prerecirc $1], [$2], [dnl dnl track all IP traffic, de-mangle non-NEW connections table=0 in_port=1, ip, action=ct(table=1,nat) table=0 in_port=2, ip, action=ct(table=2,nat) @@ -3869,7 +3921,7 @@ ]) dnl Check that ct(nat,table=foo) works without TCP sequence adjustment. -CHECK_FTP_NAT_PRE_RECIRC([], [10.1.1.9], [0x0a010109]) +CHECK_FTP_SNAT_PRE_RECIRC([], [10.1.1.9], [0x0a010109]) dnl Check that ct(nat,table=foo) works with TCP sequence adjustment. dnl @@ -3880,9 +3932,9 @@ dnl resize the packet and adjust TCP sequence numbers. This test is kept dnl separate from the above to easier identify issues in this code on different dnl kernels. -CHECK_FTP_NAT_PRE_RECIRC([seqadj], [10.1.1.240], [0x0a0101f0]) +CHECK_FTP_SNAT_PRE_RECIRC([seqadj], [10.1.1.240], [0x0a0101f0]) -dnl CHECK_FTP_NAT_POST_RECIRC(TITLE, IP_ADDR, IP_ADDR_AS_HEX) +dnl CHECK_FTP_SNAT_POST_RECIRC(TITLE, IP_ADDR, IP_ADDR_AS_HEX) dnl dnl Checks the implementation of conntrack with FTP ALGs in combination with dnl NAT, with flow tables that implement the NATing after the first round @@ -3891,8 +3943,8 @@ dnl dnl IP_ADDR must specify the NAT address in standard "10.1.1.x" format, dnl and IP_ADDR_AS_HEX must specify the same address as hex, eg 0x0a0101xx. -m4_define([CHECK_FTP_NAT_POST_RECIRC], [dnl - CHECK_FTP_NAT([postrecirc $1], [$2], [dnl +m4_define([CHECK_FTP_SNAT_POST_RECIRC], [dnl + CHECK_FTP_NAT([SNAT postrecirc $1], [$2], [dnl dnl track all IP traffic (this includes a helper call to non-NEW packets.) table=0 ip, action=ct(table=1) dnl @@ -3935,7 +3987,7 @@ ]) dnl Check that ct(nat,table=foo) works without TCP sequence adjustment. -CHECK_FTP_NAT_POST_RECIRC([], [10.1.1.9], [0x0a010109]) +CHECK_FTP_SNAT_POST_RECIRC([], [10.1.1.9], [0x0a010109]) dnl Check that ct(nat,table=foo) works with TCP sequence adjustment. dnl @@ -3946,10 +3998,10 @@ dnl resize the packet and adjust TCP sequence numbers. This test is kept dnl separate from the above to easier identify issues in this code on different dnl kernels. -CHECK_FTP_NAT_POST_RECIRC([seqadj], [10.1.1.240], [0x0a0101f0]) +CHECK_FTP_SNAT_POST_RECIRC([seqadj], [10.1.1.240], [0x0a0101f0]) -dnl CHECK_FTP_NAT_ORIG_TUPLE(TITLE, IP_ADDR, IP_ADDR_AS_HEX) +dnl CHECK_FTP_SNAT_ORIG_TUPLE(TITLE, IP_ADDR, IP_ADDR_AS_HEX) dnl dnl Checks the implementation of conntrack original direction tuple matching dnl with FTP ALGs in combination with NAT, with flow tables that implement @@ -3959,8 +4011,8 @@ dnl dnl IP_ADDR must specify the NAT address in standard "10.1.1.x" format, dnl and IP_ADDR_AS_HEX must specify the same address as hex, eg 0x0a0101xx. -m4_define([CHECK_FTP_NAT_ORIG_TUPLE], [dnl - CHECK_FTP_NAT([orig tuple $1], [$2], [dnl +m4_define([CHECK_FTP_SNAT_ORIG_TUPLE], [dnl + CHECK_FTP_NAT([SNAT orig tuple $1], [$2], [dnl dnl Store zone in reg4 and packet direction in reg3 (IN=1, OUT=2). dnl NAT is only applied to OUT-direction packets, so that ACL dnl processing can be done with non-NATted headers. @@ -4066,13 +4118,13 @@ dnl Check that ct(nat,table=foo) works without TCP sequence adjustment with dnl an ACL table based on matching on conntrack original direction tuple only. -CHECK_FTP_NAT_ORIG_TUPLE([], [10.1.1.9], [0x0a010109]) +CHECK_FTP_SNAT_ORIG_TUPLE([], [10.1.1.9], [0x0a010109]) dnl Check that ct(nat,table=foo) works with TCP sequence adjustment with dnl an ACL table based on matching on conntrack original direction tuple only. -CHECK_FTP_NAT_ORIG_TUPLE([seqadj], [10.1.1.240], [0x0a0101f0]) +CHECK_FTP_SNAT_ORIG_TUPLE([seqadj], [10.1.1.240], [0x0a0101f0]) -AT_SETUP([conntrack - IPv4 FTP Passive with NAT]) +AT_SETUP([conntrack - IPv4 FTP Passive with SNAT]) AT_SKIP_IF([test $HAVE_FTP = no]) CHECK_CONNTRACK() CHECK_CONNTRACK_NAT() @@ -4132,6 +4184,246 @@ OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([conntrack - IPv4 FTP Passive with DNAT]) +AT_SKIP_IF([test $HAVE_FTP = no]) +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +CHECK_CONNTRACK_ALG() + +OVS_TRAFFIC_VSWITCHD_START() + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") +NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11]) +NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22]) +NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.240 e6:66:c1:22:22:22]) + +ADD_VETH(p1, at_ns1, br0, "10.1.1.240/24") +NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22]) +NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11]) + +dnl Allow any traffic from ns0->ns1. +AT_DATA([flows.txt], [dnl +dnl track all IPv4 traffic and NAT any established traffic. +table=0 priority=10 ip, action=ct(nat,table=1) +table=0 priority=0 action=drop +dnl +dnl Table 1 +dnl +dnl Allow new FTP control connections. +table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21 action=ct(alg=ftp,commit,nat(dst=10.1.1.240)),2 +dnl Allow related TCP connections from port 1. +table=1 in_port=1 ct_state=+new+rel tcp nw_src=10.1.1.1 action=ct(commit,nat),2 +dnl Allow established TCP connections both ways, post-NAT match. +table=1 in_port=1 ct_state=+est tcp nw_dst=10.1.1.240 action=2 +table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1 + +dnl Allow ICMP both ways. +table=1 priority=100 in_port=1 icmp, action=2 +table=1 priority=100 in_port=2 icmp, action=1 +table=1 priority=0, action=drop +]) + +AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) + +dnl Check that the stacks working to avoid races. +OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.240 >/dev/null]) + +OVS_START_L7([at_ns1], [ftp]) + +dnl FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o wget0.log]) + +dnl Discards CLOSE_WAIT and CLOSING +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl +tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src=10.1.1.240,dst=10.1.1.1,sport=,dport=),protoinfo=(state=) +tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src=10.1.1.240,dst=10.1.1.1,sport=,dport=),protoinfo=(state=),helper=ftp +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([conntrack - IPv4 FTP Passive with DNAT 2]) +AT_SKIP_IF([test $HAVE_FTP = no]) +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +CHECK_CONNTRACK_ALG() + +OVS_TRAFFIC_VSWITCHD_START() + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/16") +NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11]) +NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.200 e6:66:c1:22:22:22]) +NS_CHECK_EXEC([at_ns0], [arp -s 10.1.100.1 e6:66:c1:22:22:22]) + +ADD_VETH(p1, at_ns1, br0, "10.1.100.1/16") +NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22]) +NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11]) + +dnl Allow any traffic from ns0->ns1. +AT_DATA([flows.txt], [dnl +dnl track all IPv4 traffic and NAT any established traffic. +table=0 priority=10 ip, action=ct(nat,table=1) +table=0 priority=0 action=drop +dnl +dnl Table 1 +dnl +dnl Allow new FTP control connections. +table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21 action=ct(alg=ftp,commit,nat(dst=10.1.100.1)),2 +dnl Allow related TCP connections from port 1. +table=1 in_port=1 ct_state=+new+rel tcp nw_src=10.1.1.1 action=ct(commit,nat),2 +dnl Allow established TCP connections both ways, post-NAT match. +table=1 in_port=1 ct_state=+est tcp nw_dst=10.1.100.1 action=2 +table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1 + +dnl Allow ICMP both ways. +table=1 priority=100 in_port=1 icmp, action=2 +table=1 priority=100 in_port=2 icmp, action=1 +table=1 priority=0, action=drop +]) + +AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) + +dnl Check that the stacks working to avoid races. +OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.100.1 >/dev/null]) + +OVS_START_L7([at_ns1], [ftp]) + +dnl FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.200 -t 3 -T 1 --retry-connrefused -v -o wget0.log]) + +dnl Discards CLOSE_WAIT and CLOSING +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.200)], [0], [dnl +tcp,orig=(src=10.1.1.1,dst=10.1.1.200,sport=,dport=),reply=(src=10.1.100.1,dst=10.1.1.1,sport=,dport=),protoinfo=(state=) +tcp,orig=(src=10.1.1.1,dst=10.1.1.200,sport=,dport=),reply=(src=10.1.100.1,dst=10.1.1.1,sport=,dport=),protoinfo=(state=),helper=ftp +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([conntrack - IPv4 FTP Active with DNAT]) +AT_SKIP_IF([test $HAVE_FTP = no]) +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +CHECK_CONNTRACK_ALG() + +OVS_TRAFFIC_VSWITCHD_START() + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") +NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11]) +NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22]) +NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.240 e6:66:c1:22:22:22]) + +ADD_VETH(p1, at_ns1, br0, "10.1.1.240/24") +NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22]) +NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11]) + +dnl Allow any traffic from ns0->ns1. +AT_DATA([flows.txt], [dnl +dnl track all IPv4 traffic and NAT any established traffic. +table=0 priority=10 ip, action=ct(nat,table=1) +table=0 priority=0 action=drop +dnl +dnl Table 1 +dnl +dnl Allow new FTP control connections. +table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21 action=ct(alg=ftp,commit,nat(dst=10.1.1.240)),2 +dnl Allow related TCP connections from port 1. +table=1 in_port=2 ct_state=+new+rel tcp nw_src=10.1.1.240 action=ct(commit,nat),1 +dnl Allow established TCP connections both ways, post-NAT match. +table=1 in_port=1 ct_state=+est tcp nw_dst=10.1.1.240 action=2 +table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1 + +dnl Allow ICMP both ways. +table=1 priority=100 in_port=1 icmp, action=2 +table=1 priority=100 in_port=2 icmp, action=1 +table=1 priority=0, action=drop +]) + +AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) + +dnl Check that the stacks working to avoid races. +OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.240 >/dev/null]) + +OVS_START_L7([at_ns1], [ftp]) + +dnl FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 --retry-connrefused -v -o wget0.log]) + +dnl Discards CLOSE_WAIT and CLOSING +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl +tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src=10.1.1.240,dst=10.1.1.1,sport=,dport=),protoinfo=(state=),helper=ftp +tcp,orig=(src=10.1.1.240,dst=10.1.1.1,sport=,dport=),reply=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),protoinfo=(state=) +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([conntrack - IPv4 FTP Active with DNAT with reverse skew]) +AT_SKIP_IF([test $HAVE_FTP = no]) +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +CHECK_CONNTRACK_ALG() + +OVS_TRAFFIC_VSWITCHD_START() + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/16") +NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address e6:66:c1:11:11:11]) +NS_CHECK_EXEC([at_ns0], [arp -s 10.1.1.2 e6:66:c1:22:22:22]) +NS_CHECK_EXEC([at_ns0], [arp -s 10.1.120.240 e6:66:c1:22:22:22]) + +ADD_VETH(p1, at_ns1, br0, "10.1.1.2/16") +NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address e6:66:c1:22:22:22]) +NS_CHECK_EXEC([at_ns1], [arp -s 10.1.1.1 e6:66:c1:11:11:11]) + +dnl Allow any traffic from ns0->ns1. +AT_DATA([flows.txt], [dnl +dnl track all IPv4 traffic and NAT any established traffic. +table=0 priority=10 ip, action=ct(nat,table=1) +table=0 priority=0 action=drop +dnl +dnl Table 1 +dnl +dnl Allow new FTP control connections. +table=1 in_port=1 ct_state=+new tcp nw_src=10.1.1.1 tp_dst=21 action=ct(alg=ftp,commit,nat(dst=10.1.1.2)),2 +dnl Allow related TCP connections from port 1. +table=1 in_port=2 ct_state=+new+rel tcp nw_src=10.1.1.2 action=ct(commit,nat),1 +dnl Allow established TCP connections both ways, post-NAT match. +table=1 in_port=1 ct_state=+est tcp nw_dst=10.1.1.2 action=2 +table=1 in_port=2 ct_state=+est tcp nw_dst=10.1.1.1 action=1 + +dnl Allow ICMP both ways. +table=1 priority=100 in_port=1 icmp, action=2 +table=1 priority=100 in_port=2 icmp, action=1 +table=1 priority=0, action=drop +]) + +AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) + +dnl Check that the stacks working to avoid races. +OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.1.1.2 >/dev/null]) + +OVS_START_L7([at_ns1], [ftp]) + +dnl FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.120.240 --no-passive-ftp -t 3 -T 1 --retry-connrefused -v -o wget0.log]) + +dnl Discards CLOSE_WAIT and CLOSING +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.120.240)], [0], [dnl +tcp,orig=(src=10.1.1.1,dst=10.1.120.240,sport=,dport=),reply=(src=10.1.1.2,dst=10.1.1.1,sport=,dport=),protoinfo=(state=),helper=ftp +tcp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=,dport=),reply=(src=10.1.1.1,dst=10.1.120.240,sport=,dport=),protoinfo=(state=) +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([conntrack - IPv6 HTTP with SNAT]) CHECK_CONNTRACK() CHECK_CONNTRACK_NAT() @@ -4273,7 +4565,7 @@ OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP -AT_SETUP([conntrack - IPv6 FTP with NAT]) +AT_SETUP([conntrack - IPv6 FTP with SNAT]) AT_SKIP_IF([test $HAVE_FTP = no]) CHECK_CONNTRACK() CHECK_CONNTRACK_NAT() @@ -4333,7 +4625,7 @@ OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP -AT_SETUP([conntrack - IPv6 FTP Passive with NAT]) +AT_SETUP([conntrack - IPv6 FTP Passive with SNAT]) AT_SKIP_IF([test $HAVE_FTP = no]) CHECK_CONNTRACK() CHECK_CONNTRACK_NAT() @@ -4394,7 +4686,7 @@ OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP -AT_SETUP([conntrack - IPv6 FTP with NAT - orig tuple]) +AT_SETUP([conntrack - IPv6 FTP with SNAT - orig tuple]) AT_SKIP_IF([test $HAVE_FTP = no]) CHECK_CONNTRACK() CHECK_CONNTRACK_NAT() @@ -4454,7 +4746,7 @@ OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP -AT_SETUP([conntrack - IPv4 TFTP with NAT]) +AT_SETUP([conntrack - IPv4 TFTP with SNAT]) AT_SKIP_IF([test $HAVE_TFTP = no]) CHECK_CONNTRACK() CHECK_CONNTRACK_NAT() diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/system-userspace-macros.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/system-userspace-macros.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/system-userspace-macros.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/system-userspace-macros.at 2020-03-11 16:15:44.000000000 +0000 @@ -116,6 +116,15 @@ # m4_define([CHECK_CONNTRACK_NAT]) +# CHECK_CT_DPIF_PER_ZONE_LIMIT() +# +# Perform requirements checks for running ovs-dpctl ct-[set|get|del]-limits per +# zone. The userspace datapath does not support this feature yet. +m4_define([CHECK_CT_DPIF_PER_ZONE_LIMIT], +[ + AT_SKIP_IF([:]) +]) + # CHECK_CT_DPIF_SET_GET_MAXCONNS() # # Perform requirements checks for running ovs-dpctl ct-set-maxconns or diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/system-userspace-packet-type-aware.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/system-userspace-packet-type-aware.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/system-userspace-packet-type-aware.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/system-userspace-packet-type-aware.at 2020-03-11 16:15:44.000000000 +0000 @@ -252,39 +252,39 @@ ### Verify datapath configuration AT_CHECK([ - ovs-appctl dpif/show | grep -v hit | sed 's/\t/ /g' + ovs-appctl dpif/show | grep -v hit ], [0], [dnl - br-in1: - br-in1 65534/2: (tap) - gre12 1020/14: (gre: remote_ip=10.0.0.2) - gre12_l3 1021/14: (gre: packet_type=legacy_l3, remote_ip=10.0.0.2) - gre13 1030/14: (gre: remote_ip=10.0.0.3) - ovs-n1 10/15: (system) - br-in2: - br-in2 65534/3: (tap) - gre21 2010/14: (gre: packet_type=ptap, remote_ip=20.0.0.1) - gre23 2030/14: (gre: packet_type=ptap, remote_ip=20.0.0.3) - ovs-n2 20/16: (system) - br-in3: - br-in3 65534/4: (tap) - gre31 3010/14: (gre: remote_ip=30.0.0.1) - gre32 3020/14: (gre: remote_ip=30.0.0.2) - gre32_l3 3021/14: (gre: packet_type=legacy_l3, remote_ip=30.0.0.2) - ovs-n3 30/17: (system) - br-p1: - br-p1 65534/5: (tap) - p1-0 2/8: (system) - br-p2: - br-p2 65534/6: (tap) - p2-0 2/9: (system) - br-p3: - br-p3 65534/7: (tap) - p3-0 2/10: (system) - br0: - br0 65534/1: (tap) - p0-1 10/11: (system) - p0-2 20/12: (system) - p0-3 30/13: (system) + br-in1: + br-in1 65534/2: (tap) + gre12 1020/14: (gre: remote_ip=10.0.0.2) + gre12_l3 1021/14: (gre: packet_type=legacy_l3, remote_ip=10.0.0.2) + gre13 1030/14: (gre: remote_ip=10.0.0.3) + ovs-n1 10/15: (system) + br-in2: + br-in2 65534/3: (tap) + gre21 2010/14: (gre: packet_type=ptap, remote_ip=20.0.0.1) + gre23 2030/14: (gre: packet_type=ptap, remote_ip=20.0.0.3) + ovs-n2 20/16: (system) + br-in3: + br-in3 65534/4: (tap) + gre31 3010/14: (gre: remote_ip=30.0.0.1) + gre32 3020/14: (gre: remote_ip=30.0.0.2) + gre32_l3 3021/14: (gre: packet_type=legacy_l3, remote_ip=30.0.0.2) + ovs-n3 30/17: (system) + br-p1: + br-p1 65534/5: (tap) + p1-0 2/8: (system) + br-p2: + br-p2 65534/6: (tap) + p2-0 2/9: (system) + br-p3: + br-p3 65534/7: (tap) + p3-0 2/10: (system) + br0: + br0 65534/1: (tap) + p0-1 10/11: (system) + p0-2 20/12: (system) + p0-3 30/13: (system) ]) ### Test L3 forwarding flows diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/test-ovn.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/test-ovn.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/test-ovn.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/test-ovn.c 2020-03-11 16:15:44.000000000 +0000 @@ -182,6 +182,7 @@ dhcp_opt_add(dhcp_opts, "tcp_ttl", 37, "uint8"); dhcp_opt_add(dhcp_opts, "mtu", 26, "uint16"); dhcp_opt_add(dhcp_opts, "lease_time", 51, "uint32"); + dhcp_opt_add(dhcp_opts, "wpad", 252, "str"); /* DHCPv6 options. */ hmap_init(dhcpv6_opts); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/test-stream.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/test-stream.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/test-stream.c 1970-01-01 00:00:00.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/test-stream.c 2020-03-11 16:15:44.000000000 +0000 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 Ilya Maximets + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "fatal-signal.h" +#include "openvswitch/vlog.h" +#include "stream.h" +#include "util.h" + +VLOG_DEFINE_THIS_MODULE(test_stream); + +int +main(int argc, char *argv[]) +{ + int error; + struct stream *stream; + + fatal_ignore_sigpipe(); + set_program_name(argv[0]); + + if (argc < 2) { + ovs_fatal(0, "usage: %s REMOTE", argv[0]); + } + + error = stream_open_block(stream_open(argv[1], &stream, DSCP_DEFAULT), + &stream); + if (error) { + VLOG_ERR("stream_open_block(%s) failure: %s", + argv[1], ovs_strerror(error)); + } + return (error || !stream) ? 1 : 0; +} diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/tunnel.at openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/tunnel.at --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/tests/tunnel.at 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/tests/tunnel.at 2020-03-11 16:15:44.000000000 +0000 @@ -394,6 +394,68 @@ OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([tunnel - table version]) +dnl check if changes in the egress bridge flow table affects +dnl discovering the link layer address of tunnel endpoints. +OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00]) +AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0]) +AT_CHECK([ovs-vsctl add-port int-br v1 -- set Interface v1 type=vxlan \ + options:remote_ip=172.31.1.2 options:key=123 \ + ofport_request=2 \ + -- add-port int-br v2 -- set Interface v2 type=internal \ + ofport_request=3 \ + ], [0]) + +AT_CHECK([ovs-appctl dpif/show], [0], [dnl +dummy@ovs-dummy: hit:0 missed:0 + br0: + br0 65534/100: (dummy-internal) + p0 1/1: (dummy) + int-br: + int-br 65534/2: (dummy-internal) + v1 2/4789: (vxlan: key=123, remote_ip=172.31.1.2) + v2 3/3: (dummy-internal) +]) + +dnl First setup dummy interface IP address, then add the route +dnl so that tnl-port table can get valid IP address for the device. +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 172.31.1.1/24], [0], [OK +]) +AT_CHECK([ovs-appctl ovs/route/add 172.31.1.0/24 br0], [0], [OK +]) + +dnl change the flow table to bump the internal table version +AT_CHECK([ovs-ofctl add-flow int-br action=normal]) +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl del-flows br0]) +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl del-flows br0]) +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl del-flows br0]) +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl del-flows br0]) +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl del-flows br0]) +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl del-flows br0]) +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) +AT_CHECK([ovs-ofctl del-flows br0]) +AT_CHECK([ovs-ofctl add-flow br0 action=normal]) + +dnl Check Neighbour discovery. +AT_CHECK([ovs-vsctl -- set Interface p0 options:pcap=p0.pcap]) + +AT_CHECK([ovs-appctl netdev-dummy/receive int-br 'in_port(2),eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)']) +AT_CHECK([ovs-pcap p0.pcap > p0.pcap.txt 2>&1]) + +dnl When the wrong version is used, the flow is not visible and the +dnl packet is dropped. +AT_CHECK([cat p0.pcap.txt | grep ffffffffffffaa55aa55000008060001080006040001aa55aa550000ac1f0101000000000000ac1f0102 | uniq], [0], [dnl +ffffffffffffaa55aa55000008060001080006040001aa55aa550000ac1f0101000000000000ac1f0102 +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([tunnel - LISP]) OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=lisp \ options:remote_ip=1.1.1.1 ofport_request=1]) diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/.travis/linux-build.sh openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/.travis/linux-build.sh --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/.travis/linux-build.sh 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/.travis/linux-build.sh 2020-03-11 16:15:44.000000000 +0000 @@ -83,7 +83,7 @@ if [ "$DPDK" ]; then if [ -z "$DPDK_VER" ]; then - DPDK_VER="17.11.3" + DPDK_VER="17.11.6" fi install_dpdk $DPDK_VER if [ "$CC" = "clang" ]; then diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/.travis/linux-prepare.sh openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/.travis/linux-prepare.sh --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/.travis/linux-prepare.sh 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/.travis/linux-prepare.sh 2020-03-11 16:15:44.000000000 +0000 @@ -2,6 +2,10 @@ set -ev +# Logging to syslog could be way too slow on Travis. +# Stopping the rsyslog daemon to allow tests to fit the time limit. +sudo service rsyslog stop + # Build and install sparse. # # Explicitly disable sparse support for llvm because some travis diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/.travis.yml openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/.travis.yml --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/.travis.yml 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/.travis.yml 2020-03-11 16:15:44.000000000 +0000 @@ -26,8 +26,6 @@ before_script: export PATH=$PATH:$HOME/bin -sudo: false - env: - OPTS="--disable-ssl" - TESTSUITE=1 KERNEL=3.16.54 @@ -36,8 +34,8 @@ - KERNEL=3.16.54 DPDK=1 - KERNEL=3.16.54 DPDK=1 OPTS="--enable-shared" - KERNEL=4.15.18 - - KERNEL=4.14.63 - - KERNEL=4.9.120 + - KERNEL=4.14.111 + - KERNEL=4.9.149 - KERNEL=4.4.148 - KERNEL=3.16.57 - TESTSUITE=1 LIBS=-ljemalloc diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/utilities/ovs-ctl.in openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/utilities/ovs-ctl.in --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/utilities/ovs-ctl.in 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/utilities/ovs-ctl.in 2020-03-11 16:15:44.000000000 +0000 @@ -164,16 +164,14 @@ } add_managers () { - # Now that ovs-vswitchd has started and completed its initial - # configuration, tell ovsdb-server to connect to the remote managers. We - # used to do this at ovsdb-server startup time, but waiting for - # ovs-vswitchd to finish configuring means that remote managers see less - # churn in the database at startup or restart. (For example, managers - # won't briefly see empty datapath-id or ofport columns for records that - # exist at startup.) + # Tell ovsdb-server to connect to the remote managers. If ovs-vswitchd + # is not finished configuring, it may mean that remote managers will + # see more churn in the database at startup or restart. (For example, + # managers may briefly see empty datapath-id or ofport columns for + # records that exist at startup.). However, the alternative is a + # 'bricked' system, so we allow database connectivity regardless. if test X"$OVSDB_SERVER" = Xyes || test X"$OVS_VSWITCHD" = Xyes; then - if daemon_is_running ovsdb-server \ - && daemon_is_running ovs-vswitchd; then + if daemon_is_running ovsdb-server; then action "Enabling remote OVSDB managers" \ ovs-appctl -t ovsdb-server ovsdb-server/add-remote \ db:Open_vSwitch,Open_vSwitch,manager_options diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/utilities/ovs-lib.in openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/utilities/ovs-lib.in --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/utilities/ovs-lib.in 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/utilities/ovs-lib.in 2020-03-11 16:15:44.000000000 +0000 @@ -127,7 +127,7 @@ pid_exists () { # This is better than "kill -0" because it doesn't require permission to # send a signal (so daemon_status in particular works as non-root). - test -d /proc/"$1" + test -n "$1" && test -d /proc/"$1" } pid_comm_check () { @@ -477,6 +477,7 @@ elif ovsdb_tool db-is-standalone "$DB_FILE"; then # Convert standalone database to clustered. backup_db || return 1 + rm -f "$DB_FILE" action "Creating cluster database $DB_FILE from existing one" \ ovsdb_tool create-cluster "$DB_FILE" "$backup" "$LOCAL_ADDR" fi @@ -608,9 +609,6 @@ stop_ovsdb start_ovsdb || return 1 - if [ -n "$(ovs-dpctl show)" ]; then - action "Flush old conntrack entries" ovs-appctl dpctl/flush-conntrack - fi stop_forwarding if action "Saving interface configuration" save_interfaces; then @@ -627,6 +625,14 @@ action "Removing datapath: $dp" ovs-dpctl del-dp "$dp" done + if test -e /sys/module/ip_gre; then + action "Forcing removal of ip_gre module" rmmod ip_gre + fi + + if test -e /sys/module/gre; then + action "Forcing removal of gre module" rmmod gre + fi + ovs_kmod_ctl remove # Start vswitchd by asking it to wait till flow restore is finished. diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/utilities/ovs-ofctl.c openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/utilities/ovs-ofctl.c --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/utilities/ovs-ofctl.c 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/utilities/ovs-ofctl.c 2020-03-11 16:15:44.000000000 +0000 @@ -2958,7 +2958,8 @@ for (i = 0; i < n_gms; i++) { struct ofputil_group_mod *gm = &gms[i]; - struct ofpbuf *request = ofputil_encode_group_mod(version, gm); + struct ofpbuf *request = ofputil_encode_group_mod(version, gm, + NULL, -1); ovs_list_push_back(&requests, &request->list_node); ofputil_uninit_group_mod(gm); @@ -2991,7 +2992,7 @@ for (i = 0; i < n_gms; i++) { gm = &gms[i]; - request = ofputil_encode_group_mod(version, gm); + request = ofputil_encode_group_mod(version, gm, NULL, -1); transact_noreply(vconn, request); ofputil_uninit_group_mod(gm); } @@ -4474,6 +4475,7 @@ } else if (retval) { error = retval; ovs_error(error, "%s: read failed", filename); + break; } pkt_metadata_init(&packet->md, u32_to_odp(ofp_to_u16(OFPP_ANY))); diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/utilities/ovs-save openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/utilities/ovs-save --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/utilities/ovs-save 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/utilities/ovs-save 2020-03-11 16:15:44.000000000 +0000 @@ -110,6 +110,17 @@ exit 1 fi + # OVS 2.7 and earlier do not enable OpenFlow 1.4 (by default) and lack + # other features needed to save and restore flows. Don't try. + case `ovs-appctl version | sed 1q` in + "ovs-vswitchd (Open vSwitch) 1."*.*) + return + ;; + "ovs-vswitchd (Open vSwitch) 2."[0-7].*) + return + ;; + esac + workdir=$(mktemp -d "${TMPDIR:-/tmp}/ovs-save.XXXXXXXXXX") for bridge in "$@"; do # Get the highest enabled OpenFlow version @@ -117,15 +128,23 @@ printf "%s" "ovs-ofctl add-tlv-map ${bridge} '" ovs-ofctl dump-tlv-map ${bridge} | \ - awk '/^ 0x/ {if (cnt != 0) printf ","; \ + awk '/^ *0x/ {if (cnt != 0) printf ","; \ cnt++;printf "{class="$1",type="$2",len="$3"}->"$4}' echo "'" - printf "%s" "ovs-ofctl -O $ofp_version add-flows ${bridge} " \ - "\"$workdir/$bridge.flows.dump\"" + # If possible use OpenFlow 1.4 atomic bundle txn for flows and groups + [ ${ofp_version#OpenFlow} -ge 14 ] && bundle=" --bundle" || bundle="" + + echo "ovs-ofctl -O $ofp_version add-groups ${bridge} \ + \"$workdir/$bridge.groups.dump\" ${bundle}" + + echo "ovs-ofctl -O $ofp_version replace-flows ${bridge} \ + \"$workdir/$bridge.flows.dump\" ${bundle}" - # If possible, use OpenFlow 1.4 atomic bundle transaction to add flows - [ ${ofp_version#OpenFlow} -ge 14 ] && echo " --bundle" || echo + ovs-ofctl -O $ofp_version dump-groups "$bridge" | \ + sed -e '/^OFPST_GROUP_DESC/d' \ + -e '/^NXST_GROUP_DESC/d' > \ + "$workdir/$bridge.groups.dump" ovs-ofctl -O $ofp_version dump-flows --no-names --no-stats "$bridge" | \ sed -e '/NXST_FLOW/d' \ diff -Nru openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Vagrantfile openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Vagrantfile --- openvswitch-2.10.0+2018.08.28+git.8ca7c82b7d+ds1/Vagrantfile 2018-09-01 17:30:24.000000000 +0000 +++ openvswitch-2.10.4+2020.01.14.b2ccc307f1+dfsg1/Vagrantfile 2020-03-11 16:15:44.000000000 +0000 @@ -12,7 +12,8 @@ python-twisted python-zope-interface \ desktop-file-utils groff graphviz rpmdevtools nc curl \ wget python-six pyftpdlib checkpolicy selinux-policy-devel \ - libcap-ng-devel kernel-devel-`uname -r` ethtool python-tftpy + libcap-ng-devel kernel-devel-`uname -r` ethtool python-tftpy \ + lftp echo "search extra update built-in" >/etc/depmod.d/search_path.conf SCRIPT @@ -28,7 +29,8 @@ wget python-six ethtool \ libcap-ng-dev libssl-dev python-dev openssl \ python-pyftpdlib python-flake8 python-tftpy \ - linux-headers-`uname -r` + linux-headers-`uname -r` \ + lftp SCRIPT $bootstrap_centos = <