diff --git a/SOURCES/openvswitch-2.16.0.patch b/SOURCES/openvswitch-2.16.0.patch index aef4484..7e073c5 100644 --- a/SOURCES/openvswitch-2.16.0.patch +++ b/SOURCES/openvswitch-2.16.0.patch @@ -1,7 +1,16 @@ diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh -index 863f023888..1e7565b8bb 100755 +index 863f023888..c06e88c577 100755 --- a/.ci/linux-build.sh +++ b/.ci/linux-build.sh +@@ -216,7 +216,7 @@ fi + + if [ "$DPDK" ] || [ "$DPDK_SHARED" ]; then + if [ -z "$DPDK_VER" ]; then +- DPDK_VER="20.11.1" ++ DPDK_VER="20.11.4" + fi + install_dpdk $DPDK_VER + if [ "$CC" = "clang" ]; then @@ -246,8 +246,8 @@ if [ "$ASAN" ]; then export ASAN_OPTIONS='detect_leaks=1' # -O2 generates few false-positive memory leak reports in test-ovsdb @@ -86,24 +95,50 @@ index 51d0511080..c7aeede06e 100644 - python3-sphinx - libelf-dev diff --git a/Documentation/faq/releases.rst b/Documentation/faq/releases.rst -index 68c9867b19..64bc577e0b 100644 +index 68c9867b19..d62d575eba 100644 --- a/Documentation/faq/releases.rst +++ b/Documentation/faq/releases.rst -@@ -205,8 +205,8 @@ Q: What DPDK version does each Open vSwitch release work with? +@@ -205,10 +205,10 @@ Q: What DPDK version does each Open vSwitch release work with? 2.10.x 17.11.10 2.11.x 18.11.9 2.12.x 18.11.9 - 2.13.x 19.11.8 - 2.14.x 19.11.8 +- 2.15.x 20.11.1 +- 2.16.x 20.11.1 + 2.13.x 19.11.10 + 2.14.x 19.11.10 - 2.15.x 20.11.1 - 2.16.x 20.11.1 ++ 2.15.x 20.11.4 ++ 2.16.x 20.11.4 ============ ======== + + Q: Are all the DPDK releases that OVS versions work with maintained? diff --git a/Documentation/intro/install/dpdk.rst b/Documentation/intro/install/dpdk.rst -index d8fa931fab..1dbead3276 100644 +index d8fa931fab..9ce5285c58 100644 --- a/Documentation/intro/install/dpdk.rst +++ b/Documentation/intro/install/dpdk.rst +@@ -42,7 +42,7 @@ Build requirements + In addition to the requirements described in :doc:`general`, building Open + vSwitch with DPDK will require the following: + +-- DPDK 20.11.1 ++- DPDK 20.11.4 + + - A `DPDK supported NIC`_ + +@@ -73,9 +73,9 @@ Install DPDK + #. Download the `DPDK sources`_, extract the file and set ``DPDK_DIR``:: + + $ cd /usr/src/ +- $ wget https://fast.dpdk.org/rel/dpdk-20.11.1.tar.xz +- $ tar xf dpdk-20.11.1.tar.xz +- $ export DPDK_DIR=/usr/src/dpdk-stable-20.11.1 ++ $ wget https://fast.dpdk.org/rel/dpdk-20.11.4.tar.xz ++ $ tar xf dpdk-20.11.4.tar.xz ++ $ export DPDK_DIR=/usr/src/dpdk-stable-20.11.4 + $ cd $DPDK_DIR + + #. Configure and install DPDK using Meson @@ -219,7 +219,7 @@ To verify hugepage configuration:: Mount the hugepages, if not already mounted by default:: @@ -146,15 +181,18 @@ index 95fa7af128..c1a35eb13a 100644 is discussed here. diff --git a/NEWS b/NEWS -index 559a51ba3f..ecaf9ffd78 100644 +index 559a51ba3f..80720f2607 100644 --- a/NEWS +++ b/NEWS -@@ -1,3 +1,17 @@ +@@ -1,3 +1,20 @@ +v2.16.3 - xx xxx xxxx +--------------------- + - Python: + * For SSL support, the use of the pyOpenSSL library has been replaced + with the native 'ssl' module. ++ - DPDK: ++ * OVS validated with DPDK 20.11.4. It is recommended to use this version ++ until further releases. + +v2.16.2 - 17 Dec 2021 +--------------------- @@ -1354,6 +1392,18 @@ index 7c4a840cb1..0d5da73c7a 100644 /* Caches the masks to match a packet to, reducing runtime calculations. */ uint64_t *mf_masks; +diff --git a/lib/dpif-netdev-private-flow.h b/lib/dpif-netdev-private-flow.h +index 3030660675..32ad020d90 100644 +--- a/lib/dpif-netdev-private-flow.h ++++ b/lib/dpif-netdev-private-flow.h +@@ -101,6 +101,7 @@ struct dp_netdev_flow { + + bool dead; + uint32_t mark; /* Unique flow mark assigned to a flow */ ++ odp_port_t orig_in_port; + + /* Statistics. */ + struct dp_netdev_flow_stats stats; diff --git a/lib/dpif-netdev-private-thread.h b/lib/dpif-netdev-private-thread.h index a782d9678a..ac4885538c 100644 --- a/lib/dpif-netdev-private-thread.h @@ -1374,7 +1424,7 @@ index a782d9678a..ac4885538c 100644 /* Flow-Table and classifiers diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index bddce75b63..221d10aa52 100644 +index bddce75b63..c56eb184d7 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -984,7 +984,9 @@ dpif_netdev_subtable_lookup_set(struct unixctl_conn *conn, int argc OVS_UNUSED, @@ -1425,6 +1475,24 @@ index bddce75b63..221d10aa52 100644 offload = dp_netdev_alloc_flow_offload(pmd, flow, DP_NETDEV_FLOW_OFFLOAD_OP_DEL); dp_netdev_append_flow_offload(offload); +@@ -2720,7 +2737,7 @@ static void + queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow, struct match *match, + const struct nlattr *actions, size_t actions_len, +- odp_port_t orig_in_port, int op) ++ int op) + { + struct dp_flow_offload_item *offload; + +@@ -2740,7 +2757,7 @@ queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, + offload->actions = xmalloc(actions_len); + memcpy(offload->actions, actions, actions_len); + offload->actions_len = actions_len; +- offload->orig_in_port = orig_in_port; ++ offload->orig_in_port = flow->orig_in_port; + + dp_netdev_append_flow_offload(offload); + } @@ -2758,9 +2775,7 @@ dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, ovs_assert(cls != NULL); dpcls_remove(cls, &flow->cr); @@ -1436,7 +1504,33 @@ index bddce75b63..221d10aa52 100644 flow->dead = true; dp_netdev_flow_unref(flow); -@@ -4061,7 +4076,10 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) +@@ -3555,6 +3570,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, + flow->dead = false; + flow->batch = NULL; + flow->mark = INVALID_FLOW_MARK; ++ flow->orig_in_port = orig_in_port; + *CONST_CAST(unsigned *, &flow->pmd_id) = pmd->core_id; + *CONST_CAST(struct flow *, &flow->flow) = match->flow; + *CONST_CAST(ovs_u128 *, &flow->ufid) = *ufid; +@@ -3584,7 +3600,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, + dp_netdev_flow_hash(&flow->ufid)); + + queue_netdev_flow_put(pmd, flow, match, actions, actions_len, +- orig_in_port, DP_NETDEV_FLOW_OFFLOAD_OP_ADD); ++ DP_NETDEV_FLOW_OFFLOAD_OP_ADD); + + if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) { + struct ds ds = DS_EMPTY_INITIALIZER; +@@ -3671,7 +3687,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, + ovsrcu_set(&netdev_flow->actions, new_actions); + + queue_netdev_flow_put(pmd, netdev_flow, match, +- put->actions, put->actions_len, ODPP_NONE, ++ put->actions, put->actions_len, + DP_NETDEV_FLOW_OFFLOAD_OP_MOD); + + if (stats) { +@@ -4061,7 +4077,10 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) flow_hash_5tuple(execute->flow, 0)); } @@ -1448,7 +1542,7 @@ index bddce75b63..221d10aa52 100644 dp_netdev_execute_actions(pmd, &pp, false, execute->flow, execute->actions, execute->actions_len); dp_netdev_pmd_flush_output_packets(pmd, true); -@@ -4071,6 +4089,24 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) +@@ -4071,6 +4090,24 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) dp_netdev_pmd_unref(pmd); } @@ -1473,7 +1567,7 @@ index bddce75b63..221d10aa52 100644 return 0; } -@@ -8942,9 +8978,12 @@ dpcls_create_subtable(struct dpcls *cls, const struct netdev_flow_key *mask) +@@ -8942,9 +8979,12 @@ dpcls_create_subtable(struct dpcls *cls, const struct netdev_flow_key *mask) /* Get the preferred subtable search function for this (u0,u1) subtable. * The function is guaranteed to always return a valid implementation, and @@ -1488,7 +1582,7 @@ index bddce75b63..221d10aa52 100644 cmap_insert(&cls->subtables_map, &subtable->cmap_node, mask->hash); /* Add the new subtable at the end of the pvector (with no hits yet) */ -@@ -8973,6 +9012,10 @@ dpcls_find_subtable(struct dpcls *cls, const struct netdev_flow_key *mask) +@@ -8973,6 +9013,10 @@ dpcls_find_subtable(struct dpcls *cls, const struct netdev_flow_key *mask) /* Checks for the best available implementation for each subtable lookup * function, and assigns it as the lookup function pointer for each subtable. * Returns the number of subtables that have changed lookup implementation. @@ -1499,7 +1593,7 @@ index bddce75b63..221d10aa52 100644 */ static uint32_t dpcls_subtable_lookup_reprobe(struct dpcls *cls) -@@ -8985,10 +9028,13 @@ dpcls_subtable_lookup_reprobe(struct dpcls *cls) +@@ -8985,10 +9029,13 @@ dpcls_subtable_lookup_reprobe(struct dpcls *cls) uint32_t u0_bits = subtable->mf_bits_set_unit0; uint32_t u1_bits = subtable->mf_bits_set_unit1; void *old_func = subtable->lookup_func; @@ -1978,9 +2072,23 @@ index 60dd138914..97bd21be4a 100644 } diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c -index 9845e8d3fe..3f7068c8e0 100644 +index 9845e8d3fe..12d0a9af3b 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c +@@ -481,10 +481,10 @@ netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump) + + static void + parse_flower_rewrite_to_netlink_action(struct ofpbuf *buf, +- struct tc_flower *flower) ++ struct tc_action *action) + { +- char *mask = (char *) &flower->rewrite.mask; +- char *data = (char *) &flower->rewrite.key; ++ char *mask = (char *) &action->rewrite.mask; ++ char *data = (char *) &action->rewrite.key; + + for (int type = 0; type < ARRAY_SIZE(set_flower_map); type++) { + char *put = NULL; @@ -585,8 +585,10 @@ parse_tc_flower_to_stats(struct tc_flower *flower, } @@ -1994,7 +2102,77 @@ index 9845e8d3fe..3f7068c8e0 100644 stats->used = flower->lastused; } -@@ -2015,9 +2017,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, +@@ -877,7 +879,7 @@ parse_tc_flower_to_match(struct tc_flower *flower, + } + break; + case TC_ACT_PEDIT: { +- parse_flower_rewrite_to_netlink_action(buf, flower); ++ parse_flower_rewrite_to_netlink_action(buf, action); + } + break; + case TC_ACT_ENCAP: { +@@ -1222,8 +1224,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, + uint64_t set_stub[1024 / 8]; + struct ofpbuf set_buf = OFPBUF_STUB_INITIALIZER(set_stub); + char *set_data, *set_mask; +- char *key = (char *) &flower->rewrite.key; +- char *mask = (char *) &flower->rewrite.mask; ++ char *key = (char *) &action->rewrite.key; ++ char *mask = (char *) &action->rewrite.mask; + const struct nlattr *attr; + int i, j, type; + size_t size; +@@ -1265,14 +1267,6 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, + } + } + +- if (!is_all_zeros(&flower->rewrite, sizeof flower->rewrite)) { +- if (flower->rewrite.rewrite == false) { +- flower->rewrite.rewrite = true; +- action->type = TC_ACT_PEDIT; +- flower->action_count++; +- } +- } +- + if (hasmask && !is_all_zeros(set_mask, size)) { + VLOG_DBG_RL(&rl, "unsupported sub attribute of set action type %d", + type); +@@ -1281,6 +1275,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, + } + + ofpbuf_uninit(&set_buf); ++ action->type = TC_ACT_PEDIT; ++ flower->action_count++; + return 0; + } + +@@ -1841,7 +1837,25 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, + VLOG_DBG_RL(&rl, "Can't find netdev for output port %d", port); + return ENODEV; + } ++ ++ if (!netdev_flow_api_equals(netdev, outdev)) { ++ VLOG_DBG_RL(&rl, ++ "Flow API provider mismatch between ingress (%s) " ++ "and egress (%s) ports", ++ netdev_get_name(netdev), netdev_get_name(outdev)); ++ netdev_close(outdev); ++ return EOPNOTSUPP; ++ } ++ + action->out.ifindex_out = netdev_get_ifindex(outdev); ++ if (action->out.ifindex_out < 0) { ++ VLOG_DBG_RL(&rl, ++ "Can't find ifindex for output port %s, error %d", ++ netdev_get_name(outdev), action->out.ifindex_out); ++ netdev_close(outdev); ++ return -action->out.ifindex_out; ++ } ++ + action->out.ingress = is_internal_port(netdev_get_type(outdev)); + action->type = TC_ACT_OUTPUT; + flower.action_count++; +@@ -2015,9 +2029,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, if (stats) { memset(stats, 0, sizeof *stats); if (!tc_get_flower(&id, &flower)) { @@ -2006,7 +2184,7 @@ index 9845e8d3fe..3f7068c8e0 100644 } diff --git a/lib/odp-util.c b/lib/odp-util.c -index 7729a90608..65f028ba02 100644 +index 7729a90608..20d663153b 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -2941,7 +2941,7 @@ odp_nsh_key_from_attr__(const struct nlattr *attr, bool is_mask, @@ -2027,7 +2205,19 @@ index 7729a90608..65f028ba02 100644 &opts, sizeof(opts)); } nl_msg_end_nested(a, tun_key_ofs); -@@ -4618,7 +4618,7 @@ odp_flow_format(const struct nlattr *key, size_t key_len, +@@ -4601,6 +4601,11 @@ odp_flow_format(const struct nlattr *key, size_t key_len, + ds_put_char(ds, ','); + } + ds_put_cstr(ds, "eth()"); ++ } else if (attr_type == OVS_KEY_ATTR_PACKET_TYPE && is_wildcard) { ++ /* See the above help text, however in the case where the ++ * packet type is not shown, we still need to display the ++ * eth() header if the packets type is wildcarded. */ ++ has_packet_type_key = false; + } + ofpbuf_clear(&ofp); + } +@@ -4618,7 +4623,7 @@ odp_flow_format(const struct nlattr *key, size_t key_len, } ds_put_char(ds, ')'); } @@ -3067,10 +3257,140 @@ index 809b405a52..a869b5f390 100644 goto out; } diff --git a/lib/tc.c b/lib/tc.c -index 38a1dfc0eb..a52cd46d99 100644 +index 38a1dfc0eb..df73a43d4c 100644 --- a/lib/tc.c +++ b/lib/tc.c -@@ -1702,6 +1702,9 @@ static const struct nl_policy stats_policy[] = { +@@ -568,16 +568,17 @@ nl_parse_flower_vlan(struct nlattr **attrs, struct tc_flower *flower) + + flower->key.encap_eth_type[0] = + nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ETH_TYPE]); ++ flower->mask.encap_eth_type[0] = CONSTANT_HTONS(0xffff); + + if (attrs[TCA_FLOWER_KEY_VLAN_ID]) { + flower->key.vlan_id[0] = + nl_attr_get_u16(attrs[TCA_FLOWER_KEY_VLAN_ID]); +- flower->mask.vlan_id[0] = 0xffff; ++ flower->mask.vlan_id[0] = VLAN_VID_MASK >> VLAN_VID_SHIFT; + } + if (attrs[TCA_FLOWER_KEY_VLAN_PRIO]) { + flower->key.vlan_prio[0] = + nl_attr_get_u8(attrs[TCA_FLOWER_KEY_VLAN_PRIO]); +- flower->mask.vlan_prio[0] = 0xff; ++ flower->mask.vlan_prio[0] = VLAN_PCP_MASK >> VLAN_PCP_SHIFT; + } + + if (!attrs[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) { +@@ -590,17 +591,18 @@ nl_parse_flower_vlan(struct nlattr **attrs, struct tc_flower *flower) + } + + flower->key.encap_eth_type[1] = flower->key.encap_eth_type[0]; ++ flower->mask.encap_eth_type[1] = CONSTANT_HTONS(0xffff); + flower->key.encap_eth_type[0] = encap_ethtype; + + if (attrs[TCA_FLOWER_KEY_CVLAN_ID]) { + flower->key.vlan_id[1] = + nl_attr_get_u16(attrs[TCA_FLOWER_KEY_CVLAN_ID]); +- flower->mask.vlan_id[1] = 0xffff; ++ flower->mask.vlan_id[1] = VLAN_VID_MASK >> VLAN_VID_SHIFT; + } + if (attrs[TCA_FLOWER_KEY_CVLAN_PRIO]) { + flower->key.vlan_prio[1] = + nl_attr_get_u8(attrs[TCA_FLOWER_KEY_CVLAN_PRIO]); +- flower->mask.vlan_prio[1] = 0xff; ++ flower->mask.vlan_prio[1] = VLAN_PCP_MASK >> VLAN_PCP_SHIFT; + } + } + +@@ -937,24 +939,21 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) { + key->icmp_code = + nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_CODE]); + mask->icmp_code = +- nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_CODE]); ++ nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_CODE_MASK]); + } + if (attrs[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK]) { +- key->icmp_type = +- nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK]); ++ key->icmp_type = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_TYPE]); + mask->icmp_type = + nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK]); + } + } else if (ip_proto == IPPROTO_ICMPV6) { + if (attrs[TCA_FLOWER_KEY_ICMPV6_CODE_MASK]) { +- key->icmp_code = +- nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_CODE]); ++ key->icmp_code = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_CODE]); + mask->icmp_code = +- nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_CODE]); ++ nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_CODE_MASK]); + } + if (attrs[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK]) { +- key->icmp_type = +- nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK]); ++ key->icmp_type = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_TYPE]); + mask->icmp_type = + nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK]); + } +@@ -1006,14 +1005,14 @@ static const struct nl_policy pedit_policy[] = { + static int + nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower) + { +- struct tc_action *action; ++ struct tc_action *action = &flower->actions[flower->action_count++]; + struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)]; + const struct tc_pedit *pe; + const struct tc_pedit_key *keys; + const struct nlattr *nla, *keys_ex, *ex_type; + const void *keys_attr; +- char *rewrite_key = (void *) &flower->rewrite.key; +- char *rewrite_mask = (void *) &flower->rewrite.mask; ++ char *rewrite_key = (void *) &action->rewrite.key; ++ char *rewrite_mask = (void *) &action->rewrite.mask; + size_t keys_ex_size, left; + int type, i = 0, err; + +@@ -1092,7 +1091,6 @@ nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower) + i++; + } + +- action = &flower->actions[flower->action_count++]; + action->type = TC_ACT_PEDIT; + + return 0; +@@ -1487,7 +1485,9 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower) + if (ipv4_max) { + ovs_be32 addr = nl_attr_get_be32(ipv4_max); + +- action->ct.range.ipv4.max = addr; ++ if (action->ct.range.ipv4.min != addr) { ++ action->ct.range.ipv4.max = addr; ++ } + } + } else if (ipv6_min) { + action->ct.range.ip_family = AF_INET6; +@@ -1496,7 +1496,9 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower) + if (ipv6_max) { + struct in6_addr addr = nl_attr_get_in6_addr(ipv6_max); + +- action->ct.range.ipv6.max = addr; ++ if (!ipv6_addr_equals(&action->ct.range.ipv6.min, &addr)) { ++ action->ct.range.ipv6.max = addr; ++ } + } + } + +@@ -1504,6 +1506,10 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower) + action->ct.range.port.min = nl_attr_get_be16(port_min); + if (port_max) { + action->ct.range.port.max = nl_attr_get_be16(port_max); ++ if (action->ct.range.port.min == ++ action->ct.range.port.max) { ++ action->ct.range.port.max = 0; ++ } + } + } + } +@@ -1702,6 +1708,9 @@ static const struct nl_policy stats_policy[] = { [TCA_STATS_BASIC] = { .type = NL_A_UNSPEC, .min_len = sizeof(struct gnet_stats_basic), .optional = false, }, @@ -3080,7 +3400,7 @@ index 38a1dfc0eb..a52cd46d99 100644 }; static int -@@ -1714,8 +1717,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower, +@@ -1714,8 +1723,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower, const char *act_kind; struct nlattr *action_attrs[ARRAY_SIZE(act_policy)]; struct nlattr *stats_attrs[ARRAY_SIZE(stats_policy)]; @@ -3094,7 +3414,7 @@ index 38a1dfc0eb..a52cd46d99 100644 int err = 0; if (!nl_parse_nested(action, act_policy, action_attrs, -@@ -1771,10 +1777,26 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower, +@@ -1771,10 +1783,26 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower, return EPROTO; } @@ -3125,7 +3445,44 @@ index 38a1dfc0eb..a52cd46d99 100644 } return 0; -@@ -2545,6 +2567,17 @@ nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request, +@@ -2399,14 +2427,14 @@ nl_msg_put_act_flags(struct ofpbuf *request) { + * first_word_mask/last_word_mask - the mask to use for the first/last read + * (as we read entire words). */ + static void +-calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m, ++calc_offsets(struct tc_action *action, struct flower_key_to_pedit *m, + int *cur_offset, int *cnt, ovs_be32 *last_word_mask, + ovs_be32 *first_word_mask, ovs_be32 **mask, ovs_be32 **data) + { + int start_offset, max_offset, total_size; + int diff, right_zero_bits, left_zero_bits; +- char *rewrite_key = (void *) &flower->rewrite.key; +- char *rewrite_mask = (void *) &flower->rewrite.mask; ++ char *rewrite_key = (void *) &action->rewrite.key; ++ char *rewrite_mask = (void *) &action->rewrite.mask; + + max_offset = m->offset + m->size; + start_offset = ROUND_DOWN(m->offset, 4); +@@ -2473,7 +2501,8 @@ csum_update_flag(struct tc_flower *flower, + + static int + nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request, +- struct tc_flower *flower) ++ struct tc_flower *flower, ++ struct tc_action *action) + { + struct { + struct tc_pedit sel; +@@ -2497,7 +2526,7 @@ nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request, + continue; + } + +- calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask, ++ calc_offsets(action, m, &cur_offset, &cnt, &last_word_mask, + &first_word_mask, &mask, &data); + + for (j = 0; j < cnt; j++, mask++, data++, cur_offset += 4) { +@@ -2545,6 +2574,40 @@ nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request, return 0; } @@ -3140,10 +3497,59 @@ index 38a1dfc0eb..a52cd46d99 100644 + nl_msg_end_nested(request, act_offset); +} + ++/* Aggregates all previous successive pedit actions csum_update_flags ++ * to flower->csum_update_flags. Only append one csum action to the ++ * last pedit action. */ ++static void ++nl_msg_put_csum_act(struct ofpbuf *request, struct tc_flower *flower, ++ uint16_t *act_index) ++{ ++ size_t act_offset; ++ ++ /* No pedit actions or processed already. */ ++ if (!flower->csum_update_flags) { ++ return; ++ } ++ ++ act_offset = nl_msg_start_nested(request, (*act_index)++); ++ nl_msg_put_act_csum(request, flower->csum_update_flags); ++ nl_msg_put_act_flags(request); ++ nl_msg_end_nested(request, act_offset); ++ ++ /* Clear it. So we can have another series of pedit actions. */ ++ flower->csum_update_flags = 0; ++} ++ static int nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) { -@@ -2579,6 +2612,11 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) +@@ -2561,24 +2624,31 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) + + action = flower->actions; + for (i = 0; i < flower->action_count; i++, action++) { ++ if (action->type != TC_ACT_PEDIT) { ++ nl_msg_put_csum_act(request, flower, &act_index); ++ } + switch (action->type) { + case TC_ACT_PEDIT: { + act_offset = nl_msg_start_nested(request, act_index++); +- error = nl_msg_put_flower_rewrite_pedits(request, flower); ++ error = nl_msg_put_flower_rewrite_pedits(request, flower, ++ action); + if (error) { + return error; + } + nl_msg_end_nested(request, act_offset); + +- if (flower->csum_update_flags) { +- act_offset = nl_msg_start_nested(request, act_index++); +- nl_msg_put_act_csum(request, flower->csum_update_flags); +- nl_msg_put_act_flags(request); +- nl_msg_end_nested(request, act_offset); ++ if (i == flower->action_count - 1) { ++ /* If this is the last action check csum calc again. */ ++ nl_msg_put_csum_act(request, flower, &act_index); + } } break; case TC_ACT_ENCAP: { @@ -3155,7 +3561,7 @@ index 38a1dfc0eb..a52cd46d99 100644 act_offset = nl_msg_start_nested(request, act_index++); nl_msg_put_act_tunnel_key_set(request, action->encap.id_present, action->encap.id, -@@ -2636,10 +2674,7 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) +@@ -2636,10 +2706,7 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) break; case TC_ACT_OUTPUT: { if (!released && flower->tunnel) { @@ -3167,11 +3573,165 @@ index 38a1dfc0eb..a52cd46d99 100644 released = true; } +@@ -2901,13 +2968,13 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower) + FLOWER_PUT_MASKED_VALUE(icmp_code, TCA_FLOWER_KEY_ICMPV6_CODE); + FLOWER_PUT_MASKED_VALUE(icmp_type, TCA_FLOWER_KEY_ICMPV6_TYPE); + } +- +- FLOWER_PUT_MASKED_VALUE(ct_state, TCA_FLOWER_KEY_CT_STATE); +- FLOWER_PUT_MASKED_VALUE(ct_zone, TCA_FLOWER_KEY_CT_ZONE); +- FLOWER_PUT_MASKED_VALUE(ct_mark, TCA_FLOWER_KEY_CT_MARK); +- FLOWER_PUT_MASKED_VALUE(ct_label, TCA_FLOWER_KEY_CT_LABELS); + } + ++ FLOWER_PUT_MASKED_VALUE(ct_state, TCA_FLOWER_KEY_CT_STATE); ++ FLOWER_PUT_MASKED_VALUE(ct_zone, TCA_FLOWER_KEY_CT_ZONE); ++ FLOWER_PUT_MASKED_VALUE(ct_mark, TCA_FLOWER_KEY_CT_MARK); ++ FLOWER_PUT_MASKED_VALUE(ct_label, TCA_FLOWER_KEY_CT_LABELS); ++ + if (host_eth_type == ETH_P_IP) { + FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_src, TCA_FLOWER_KEY_IPV4_SRC); + FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_dst, TCA_FLOWER_KEY_IPV4_DST); +@@ -2980,12 +3047,79 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower) + return 0; + } + ++static void ++log_tc_flower_match(const char *msg, ++ const struct tc_flower *a, ++ const struct tc_flower *b) ++{ ++ uint8_t key_a[sizeof(struct tc_flower_key)]; ++ uint8_t key_b[sizeof(struct tc_flower_key)]; ++ struct ds s = DS_EMPTY_INITIALIZER; ++ ++ for (int i = 0; i < sizeof a->key; i++) { ++ uint8_t mask_a = ((uint8_t *) &a->mask)[i]; ++ uint8_t mask_b = ((uint8_t *) &b->mask)[i]; ++ ++ key_a[i] = ((uint8_t *) &a->key)[i] & mask_a; ++ key_b[i] = ((uint8_t *) &b->key)[i] & mask_b; ++ } ++ ds_put_cstr(&s, "\nExpected Mask:\n"); ++ ds_put_hex(&s, &a->mask, sizeof a->mask); ++ ds_put_cstr(&s, "\nReceived Mask:\n"); ++ ds_put_hex(&s, &b->mask, sizeof b->mask); ++ ds_put_cstr(&s, "\nExpected Key:\n"); ++ ds_put_hex(&s, &a->key, sizeof a->key); ++ ds_put_cstr(&s, "\nReceived Key:\n"); ++ ds_put_hex(&s, &b->key, sizeof b->key); ++ ds_put_cstr(&s, "\nExpected Masked Key:\n"); ++ ds_put_hex(&s, key_a, sizeof key_a); ++ ds_put_cstr(&s, "\nReceived Masked Key:\n"); ++ ds_put_hex(&s, key_b, sizeof key_b); ++ ++ if (a->action_count != b->action_count) { ++ /* If action count is not equal, we print all actions to see which ++ * ones are missing. */ ++ const struct tc_action *action; ++ int i; ++ ++ ds_put_cstr(&s, "\nExpected Actions:\n"); ++ for (i = 0, action = a->actions; i < a->action_count; i++, action++) { ++ ds_put_cstr(&s, " - "); ++ ds_put_hex(&s, action, sizeof *action); ++ ds_put_cstr(&s, "\n"); ++ } ++ ds_put_cstr(&s, "Received Actions:\n"); ++ for (i = 0, action = b->actions; i < b->action_count; i++, action++) { ++ ds_put_cstr(&s, " - "); ++ ds_put_hex(&s, action, sizeof *action); ++ ds_put_cstr(&s, "\n"); ++ } ++ } else { ++ /* Only dump the delta in actions. */ ++ const struct tc_action *action_a = a->actions; ++ const struct tc_action *action_b = b->actions; ++ ++ for (int i = 0; i < a->action_count; i++, action_a++, action_b++) { ++ if (memcmp(action_a, action_b, sizeof *action_a)) { ++ ds_put_format(&s, ++ "\nAction %d mismatch:\n - Expected Action: ", ++ i); ++ ds_put_hex(&s, action_a, sizeof *action_a); ++ ds_put_cstr(&s, "\n - Received Action: "); ++ ds_put_hex(&s, action_b, sizeof *action_b); ++ } ++ } ++ } ++ VLOG_DBG_RL(&error_rl, "%s%s", msg, ds_cstr(&s)); ++ ds_destroy(&s); ++} ++ + static bool + cmp_tc_flower_match_action(const struct tc_flower *a, + const struct tc_flower *b) + { + if (memcmp(&a->mask, &b->mask, sizeof a->mask)) { +- VLOG_DBG_RL(&error_rl, "tc flower compare failed mask compare"); ++ log_tc_flower_match("tc flower compare failed mask compare:", a, b); + return false; + } + +@@ -2998,8 +3132,8 @@ cmp_tc_flower_match_action(const struct tc_flower *a, + uint8_t key_b = ((uint8_t *)&b->key)[i] & mask; + + if (key_a != key_b) { +- VLOG_DBG_RL(&error_rl, "tc flower compare failed key compare at " +- "%d", i); ++ log_tc_flower_match("tc flower compare failed masked key compare:", ++ a, b); + return false; + } + } +@@ -3009,14 +3143,15 @@ cmp_tc_flower_match_action(const struct tc_flower *a, + const struct tc_action *action_b = b->actions; + + if (a->action_count != b->action_count) { +- VLOG_DBG_RL(&error_rl, "tc flower compare failed action length check"); ++ log_tc_flower_match("tc flower compare failed action length check", ++ a, b); + return false; + } + + for (int i = 0; i < a->action_count; i++, action_a++, action_b++) { + if (memcmp(action_a, action_b, sizeof *action_a)) { +- VLOG_DBG_RL(&error_rl, "tc flower compare failed action compare " +- "for %d", i); ++ log_tc_flower_match("tc flower compare failed action compare", ++ a, b); + return false; + } + } diff --git a/lib/tc.h b/lib/tc.h -index a147ca461d..fb0534a084 100644 +index a147ca461d..d6cdddd169 100644 --- a/lib/tc.h +++ b/lib/tc.h -@@ -330,7 +330,8 @@ struct tc_flower { +@@ -256,11 +256,23 @@ struct tc_action { + bool force; + bool commit; + } ct; ++ ++ struct { ++ struct tc_flower_key key; ++ struct tc_flower_key mask; ++ } rewrite; + }; + + enum tc_action_type type; + }; + ++/* assert that if we overflow with a masked write of uint32_t to the last byte ++ * of action.rewrite we overflow inside struct tc_action. ++ * shouldn't happen unless someone moves rewrite to the end of action */ ++BUILD_ASSERT_DECL(offsetof(struct tc_action, rewrite) ++ + MEMBER_SIZEOF(struct tc_action, rewrite) ++ + sizeof(uint32_t) - 2 < sizeof(struct tc_action)); ++ + enum tc_offloaded_state { + TC_OFFLOADED_STATE_UNDEFINED, + TC_OFFLOADED_STATE_IN_HW, +@@ -330,15 +342,10 @@ struct tc_flower { int action_count; struct tc_action actions[TCA_ACT_MAX_NUM]; @@ -3180,7 +3740,29 @@ index a147ca461d..fb0534a084 100644 + struct ovs_flow_stats stats_hw; uint64_t lastused; - struct { +- struct { +- bool rewrite; +- struct tc_flower_key key; +- struct tc_flower_key mask; +- } rewrite; +- + uint32_t csum_update_flags; + + bool tunnel; +@@ -352,13 +359,6 @@ struct tc_flower { + enum tc_offload_policy tc_policy; + }; + +-/* assert that if we overflow with a masked write of uint32_t to the last byte +- * of flower.rewrite we overflow inside struct flower. +- * shouldn't happen unless someone moves rewrite to the end of flower */ +-BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite) +- + MEMBER_SIZEOF(struct tc_flower, rewrite) +- + sizeof(uint32_t) - 2 < sizeof(struct tc_flower)); +- + int tc_replace_flower(struct tcf_id *id, struct tc_flower *flower); + int tc_del_filter(struct tcf_id *id); + int tc_get_flower(struct tcf_id *id, struct tc_flower *flower); diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c index 5bda4af7e0..995c88bf17 100644 --- a/lib/tnl-neigh-cache.c @@ -6697,9 +7279,133 @@ index 7ef32d13cb..cb0e9df388 100755 flows.write(struct.pack('>LH', diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at -index 956a69e1fa..df62bb9e8a 100644 +index 956a69e1fa..325723af19 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at +@@ -81,11 +81,12 @@ recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=ff: + + ovs-appctl netdev-dummy/set-admin-state p1 up + ovs-appctl time/warp 100 +-OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl + ---- bond0 ---- + bond_mode: active-backup + bond may use recirculation: no, + bond-hash-basis: 0 ++lb_output action: disabled, bond-id: -1 + updelay: 0 ms + downdelay: 0 ms + lacp_status: off +@@ -99,7 +100,6 @@ member p1: enabled + + member p2: enabled + may_enable: true +- + ]) + + OVS_VSWITCHD_STOP +@@ -129,11 +129,12 @@ ovs-appctl time/warp 100 + OVS_WAIT_UNTIL([test -n "`ovs-appctl bond/show | fgrep 'member p1: disabled'`"]) + ovs-appctl netdev-dummy/set-admin-state p1 up + ovs-appctl time/warp 100 +-OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl + ---- bond0 ---- + bond_mode: active-backup + bond may use recirculation: no, + bond-hash-basis: 0 ++lb_output action: disabled, bond-id: -1 + updelay: 0 ms + downdelay: 0 ms + lacp_status: off +@@ -150,7 +151,6 @@ member p2: enabled + + member p3: enabled + may_enable: true +- + ]) + + dnl Now delete the primary and verify that the output shows that the +@@ -171,11 +171,12 @@ ovs-vsctl \ + --id=@p1 create Interface name=p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p1.sock ofport_request=1 -- \ + set Port bond0 interfaces="$uuids, @p1]" + ovs-appctl time/warp 100 +-OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl + ---- bond0 ---- + bond_mode: active-backup + bond may use recirculation: no, + bond-hash-basis: 0 ++lb_output action: disabled, bond-id: -1 + updelay: 0 ms + downdelay: 0 ms + lacp_status: off +@@ -192,17 +193,17 @@ member p2: enabled + + member p3: enabled + may_enable: true +- + ]) + + dnl Switch to another primary + ovs-vsctl set port bond0 other_config:bond-primary=p2 + ovs-appctl time/warp 100 +-OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl + ---- bond0 ---- + bond_mode: active-backup + bond may use recirculation: no, + bond-hash-basis: 0 ++lb_output action: disabled, bond-id: -1 + updelay: 0 ms + downdelay: 0 ms + lacp_status: off +@@ -211,25 +212,25 @@ active-backup primary: p2 + + + member p1: enabled +- active member + may_enable: true + + member p2: enabled ++ active member + may_enable: true + + member p3: enabled + may_enable: true +- + ]) + + dnl Remove the "bond-primary" config directive from the bond. + AT_CHECK([ovs-vsctl remove Port bond0 other_config bond-primary]) + ovs-appctl time/warp 100 +-OVS_WAIT_UNTIL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [0], [dnl ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl + ---- bond0 ---- + bond_mode: active-backup + bond may use recirculation: no, + bond-hash-basis: 0 ++lb_output action: disabled, bond-id: -1 + updelay: 0 ms + downdelay: 0 ms + lacp_status: off +@@ -238,15 +239,14 @@ active-backup primary: + + + member p1: enabled +- active member + may_enable: true + + member p2: enabled ++ active member + may_enable: true + + member p3: enabled + may_enable: true +- + ]) + + OVS_VSWITCHD_STOP @@ -4862,6 +4862,54 @@ recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,fr OVS_VSWITCHD_STOP AT_CLEANUP @@ -6879,6 +7585,44 @@ index 956a69e1fa..df62bb9e8a 100644 OVS_VSWITCHD_STOP AT_CLEANUP +diff --git a/tests/ovs-macros.at b/tests/ovs-macros.at +index 66545da572..e6c5bc6e94 100644 +--- a/tests/ovs-macros.at ++++ b/tests/ovs-macros.at +@@ -259,7 +259,20 @@ dnl Executes shell COMMAND in a loop until it returns zero. If COMMAND does + dnl not return zero within a reasonable time limit, executes the commands + dnl in IF-FAILED (if provided) and fails the test. + m4_define([OVS_WAIT_UNTIL], +- [OVS_WAIT([$1], [$2], [AT_LINE], [until $1])]) ++ [AT_FAIL_IF([test "$#" -ge 3]) ++ dnl The second argument should not be a number (confused with AT_CHECK ?). ++ AT_FAIL_IF([test "$#" -eq 2 && test "$2" -eq "$2" 2>/dev/null]) ++ OVS_WAIT([$1], [$2], [AT_LINE], [until $1])]) ++ ++dnl OVS_WAIT_UNTIL_EQUAL(COMMAND, OUTPUT) ++dnl ++dnl Executes shell COMMAND in a loop until it returns zero and the output ++dnl equals OUTPUT. If COMMAND does not return zero or a desired output within ++dnl a reasonable time limit, fails the test. ++m4_define([OVS_WAIT_UNTIL_EQUAL], ++ [AT_FAIL_IF([test "$#" -ge 3]) ++ echo "$2" > wait_until_expected ++ OVS_WAIT_UNTIL([$1 | diff -u wait_until_expected - ])]) + + dnl OVS_WAIT_WHILE(COMMAND, [IF-FAILED]) + dnl +@@ -267,7 +280,10 @@ dnl Executes shell COMMAND in a loop until it returns nonzero. If COMMAND does + dnl not return nonzero within a reasonable time limit, executes the commands + dnl in IF-FAILED (if provided) and fails the test. + m4_define([OVS_WAIT_WHILE], +- [OVS_WAIT([if $1; then return 1; else return 0; fi], [$2], ++ [AT_FAIL_IF([test "$#" -ge 3]) ++ dnl The second argument should not be a number (confused with AT_CHECK ?). ++ AT_FAIL_IF([test "$#" -eq 2 && test "$2" -eq "$2" 2>/dev/null]) ++ OVS_WAIT([if $1; then return 1; else return 0; fi], [$2], + [AT_LINE], [while $1])]) + + dnl OVS_APP_EXIT_AND_WAIT(DAEMON) diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 604f15c2d1..c93cb9f16c 100644 --- a/tests/ovs-ofctl.at @@ -7406,8 +8150,26 @@ index e0e750fde5..512aa87d4c 100644 AT_CHECK([ovs-appctl dpif-netdev/miniflow-parser-set autovalidator], [0], [dnl Miniflow extract implementation set to autovalidator. ]) +diff --git a/tests/system-route.at b/tests/system-route.at +index 1714273e35..270956d13f 100644 +--- a/tests/system-route.at ++++ b/tests/system-route.at +@@ -14,10 +14,9 @@ dnl Add ip address. + AT_CHECK([ip addr add 10.0.0.17/24 dev p1-route], [0], [stdout]) + + dnl Check that OVS catches route updates. +-OVS_WAIT_UNTIL([ovs-appctl ovs/route/show | grep 'p1-route' | sort], [0], [dnl +-Cached: 10.0.0.17/24 dev p1-route SRC 10.0.0.17 +-Cached: 10.0.0.17/32 dev p1-route SRC 10.0.0.17 local +-]) ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep 'p1-route' | sort], [dnl ++Cached: 10.0.0.0/24 dev p1-route SRC 10.0.0.17 ++Cached: 10.0.0.17/32 dev p1-route SRC 10.0.0.17 local]) + + dnl Delete ip address. + AT_CHECK([ip addr del 10.0.0.17/24 dev p1-route], [0], [stdout]) diff --git a/tests/system-traffic.at b/tests/system-traffic.at -index f400cfabc9..852e2520b4 100644 +index f400cfabc9..5df4ec9166 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -218,6 +218,7 @@ OVS_TRAFFIC_VSWITCHD_STOP @@ -7705,6 +8467,15 @@ index f400cfabc9..852e2520b4 100644 AT_SETUP([conntrack - resubmit to ct multiple times]) CHECK_CONNTRACK() +@@ -5817,7 +5979,7 @@ on_exit 'ovs-appctl revalidator/purge' + on_exit 'ovs-appctl dpif/dump-flows br0' + + dnl Should work with the virtual IP address through NAT +-for i in 1 2 3 4 5 6 7 8 9 10 11 12; do ++for i in $(seq 1 50); do + echo Request $i + NS_CHECK_EXEC([at_ns1], [wget 10.1.1.64 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) + done diff --git a/tests/system-tso-macros.at b/tests/system-tso-macros.at index 406334f3e0..1a80047619 100644 --- a/tests/system-tso-macros.at @@ -8442,6 +9213,19 @@ index 48c5de9d19..6a597488e6 100644 AT_SETUP([tunnel_push_pop - underlay bridge match]) OVS_VSWITCHD_START([add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 other-config:hwaddr=aa:55:aa:55:00:00]) +diff --git a/tests/tunnel.at b/tests/tunnel.at +index b8ae7caa9b..fd482aa872 100644 +--- a/tests/tunnel.at ++++ b/tests/tunnel.at +@@ -126,7 +126,7 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl + AT_CHECK([ovs-appctl dpctl/add-flow "tunnel(dst=1.1.1.1,src=3.3.3.200/255.255.255.0,tp_dst=123,tp_src=1,ttl=64),recirc_id(0),in_port(1),eth(),eth_type(0x0800),ipv4()" "2"]) + + AT_CHECK([ovs-appctl dpctl/dump-flows | tail -1], [0], [dnl +-tunnel(src=3.3.3.200/255.255.255.0,dst=1.1.1.1,ttl=64,tp_src=1,tp_dst=123),recirc_id(0),in_port(1),eth_type(0x0800), packets:0, bytes:0, used:never, actions:2 ++tunnel(src=3.3.3.200/255.255.255.0,dst=1.1.1.1,ttl=64,tp_src=1,tp_dst=123),recirc_id(0),in_port(1),eth(),eth_type(0x0800), packets:0, bytes:0, used:never, actions:2 + ]) + + OVS_VSWITCHD_STOP diff --git a/utilities/ovs-ctl.in b/utilities/ovs-ctl.in index 71800795c0..e6e07f4763 100644 --- a/utilities/ovs-ctl.in diff --git a/SPECS/openvswitch2.16.spec b/SPECS/openvswitch2.16.spec index 92308ec..0e9c491 100644 --- a/SPECS/openvswitch2.16.spec +++ b/SPECS/openvswitch2.16.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.16.0 -Release: 62%{?dist} +Release: 63%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -699,6 +699,23 @@ exit 0 %endif %changelog +* Mon Mar 28 2022 Open vSwitch CI - 2.16.0-63 +- Merging upstream branch-2.16 [RH git: a3c48a5aeb] + Commit list: + c50a0f080d system-traffic.at: Fix flaky DNAT load balancing test. + 9928344ea7 dpif-netdev: Keep orig_in_port as a field of the flow. + aee2e66287 tests: Fix incorrect usage of OVS_WAIT_UNTIL. + 5881545bd0 odp-util: Fix output for tc to be equal to kernel. + 4a80c322f9 netdev-offload-tc: Fix IP and port ranges in flower returns. + 49e0bb72bc netdev-offload-tc: Fix use of ICMP values instead of masks defines. + 0fb545c7d9 netdev-offload-tc: Always include conntrack information to tc. + 13a3f57976 netdev-offload-tc: Check for valid netdev ifindex in flow_put. + 6e72fd96d3 netdev-offload-tc: Set the correct VLAN_VID and VLAN_PCP masks. + e43157f303 netdev-offload-tc: Add debug logs on tc rule verify failures. + 37297e7ee6 tc: Keep header rewrite actions order. + 823be413ec dpdk: Use DPDK 20.11.4 release + + * Fri Mar 11 2022 Open vSwitch CI - 2.16.0-62 - Merging upstream branch-2.16 [RH git: 561b178a3d] Commit list: