diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch index c5bcbb1..9dcb483 100644 --- a/SOURCES/openvswitch-2.17.0.patch +++ b/SOURCES/openvswitch-2.17.0.patch @@ -52191,7 +52191,7 @@ index 66016eb099..7425dd44e7 100644 /* Statistics. */ struct dp_netdev_flow_stats stats; diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c -index 9f35713ef5..b9cafc2737 100644 +index 9f35713ef5..0b543cf222 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -93,7 +93,8 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev); @@ -52563,8 +52563,16 @@ index 9f35713ef5..b9cafc2737 100644 } } #endif +@@ -9495,6 +9527,7 @@ dpif_netdev_bond_stats_get(struct dpif *dpif, uint32_t bond_id, + const struct dpif_class dpif_netdev_class = { + "netdev", + true, /* cleanup_required */ ++ true, /* synced_dp_layers */ + dpif_netdev_init, + dpif_netdev_enumerate, + dpif_netdev_port_open_type, diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c -index 71e35ccdda..484545cfb8 100644 +index 71e35ccdda..6977888bb4 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -85,7 +85,7 @@ enum { MAX_PORTS = USHRT_MAX }; @@ -52782,8 +52790,35 @@ index 71e35ccdda..484545cfb8 100644 return true; } +@@ -4416,6 +4495,7 @@ dpif_netlink_cache_set_size(struct dpif *dpif_, uint32_t level, uint32_t size) + const struct dpif_class dpif_netlink_class = { + "system", + false, /* cleanup_required */ ++ false, /* synced_dp_layers */ + NULL, /* init */ + dpif_netlink_enumerate, + NULL, +diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h +index 12477a24fe..b8ead8a02a 100644 +--- a/lib/dpif-provider.h ++++ b/lib/dpif-provider.h +@@ -127,6 +127,14 @@ struct dpif_class { + * datapaths that can not exist without it (e.g. netdev datapath). */ + bool cleanup_required; + ++ /* If 'true' the specific dpif implementation synchronizes the various ++ * datapath implementation layers, i.e., the dpif's layer in combination ++ * with the underlying netdev offload layers. For example, dpif-netlink ++ * does not sync its kernel flows with the tc ones, i.e., only one gets ++ * installed. On the other hand, dpif-netdev installs both flows, ++ * internally keeps track of both, and represents them as one. */ ++ bool synced_dp_layers; ++ + /* Called when the dpif provider is registered, typically at program + * startup. Returning an error from this function will prevent any + * datapath with this class from being created. diff --git a/lib/dpif.c b/lib/dpif.c -index 40f5fe4460..fe4db83fbf 100644 +index 40f5fe4460..3305401fe0 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1213,7 +1213,7 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_, @@ -52795,6 +52830,28 @@ index 40f5fe4460..fe4db83fbf 100644 odp_put_tunnel_action(&md->tunnel, &execute_actions, NULL); } ofpbuf_put(&execute_actions, action, NLA_ALIGN(action->nla_len)); +@@ -2109,3 +2109,9 @@ dpif_cache_set_size(struct dpif *dpif, uint32_t level, uint32_t size) + ? dpif->dpif_class->cache_set_size(dpif, level, size) + : EOPNOTSUPP; + } ++ ++bool ++dpif_synced_dp_layers(struct dpif *dpif) ++{ ++ return dpif->dpif_class->synced_dp_layers; ++} +diff --git a/lib/dpif.h b/lib/dpif.h +index 6cb4dae6d8..129cbf6a1d 100644 +--- a/lib/dpif.h ++++ b/lib/dpif.h +@@ -939,6 +939,7 @@ int dpif_get_pmds_for_port(const struct dpif * dpif, odp_port_t port_no, + char *dpif_get_dp_version(const struct dpif *); + bool dpif_supports_tnl_push_pop(const struct dpif *); + bool dpif_supports_explicit_drop_action(const struct dpif *); ++bool dpif_synced_dp_layers(struct dpif *); + + /* Log functions. */ + struct vlog_module; diff --git a/lib/dynamic-string.c b/lib/dynamic-string.c index fd0127ed17..8e9555a630 100644 --- a/lib/dynamic-string.c @@ -55193,6 +55250,35 @@ index 8237a85ddb..13ab06d116 100644 bool recirc_id_shared_with_tc; /* Indicates whever tc chains will be in * sync with datapath recirc ids. */ +diff --git a/lib/netdev-windows.c b/lib/netdev-windows.c +index 4ad45ffa1b..3fad501e3e 100644 +--- a/lib/netdev-windows.c ++++ b/lib/netdev-windows.c +@@ -156,6 +156,7 @@ netdev_windows_system_construct(struct netdev *netdev_) + struct netdev_windows_netdev_info info; + struct ofpbuf *buf; + int ret; ++ const char *type = NULL; + + /* Query the attributes and runtime status of the netdev. */ + ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf); +@@ -167,6 +168,16 @@ netdev_windows_system_construct(struct netdev *netdev_) + } + ofpbuf_delete(buf); + ++ /* Don't create netdev if ovs-type is "internal" ++ * but the type of netdev->up is "system". */ ++ type = netdev_get_type(&netdev->up); ++ if (type && !strcmp(type, "system") && ++ (info.ovs_type == OVS_VPORT_TYPE_INTERNAL)) { ++ VLOG_DBG("construct device %s, ovs_type: %u failed", ++ netdev_get_name(&netdev->up), info.ovs_type); ++ return 1; ++ } ++ + netdev->change_seq = 1; + netdev->dev_type = info.ovs_type; + netdev->port_no = info.port_no; diff --git a/lib/netdev.c b/lib/netdev.c index 8305f6c427..c797783782 100644 --- a/lib/netdev.c @@ -58954,10 +59040,41 @@ index 78a54c715d..109940ad2a 100644 oftrace_node_destroy(node); } diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c -index 57f94df544..59126b9014 100644 +index 57f94df544..308876d38c 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c -@@ -362,6 +362,10 @@ static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc, +@@ -47,17 +47,20 @@ + + #define UPCALL_MAX_BATCH 64 + #define REVALIDATE_MAX_BATCH 50 ++#define UINT64_THREE_QUARTERS (UINT64_MAX / 4 * 3) + + VLOG_DEFINE_THIS_MODULE(ofproto_dpif_upcall); + + COVERAGE_DEFINE(dumped_duplicate_flow); + COVERAGE_DEFINE(dumped_new_flow); + COVERAGE_DEFINE(handler_duplicate_upcall); +-COVERAGE_DEFINE(upcall_ukey_contention); +-COVERAGE_DEFINE(upcall_ukey_replace); + COVERAGE_DEFINE(revalidate_missed_dp_flow); ++COVERAGE_DEFINE(ukey_dp_change); ++COVERAGE_DEFINE(ukey_invalid_stat_reset); + COVERAGE_DEFINE(upcall_flow_limit_hit); + COVERAGE_DEFINE(upcall_flow_limit_kill); ++COVERAGE_DEFINE(upcall_ukey_contention); ++COVERAGE_DEFINE(upcall_ukey_replace); + + /* A thread that reads upcalls from dpif, forwards each upcall's packet, + * and possibly sets up a kernel flow as a cache. */ +@@ -287,6 +290,7 @@ struct udpif_key { + + struct ovs_mutex mutex; /* Guards the following. */ + struct dpif_flow_stats stats OVS_GUARDED; /* Last known stats.*/ ++ const char *dp_layer OVS_GUARDED; /* Last known dp_layer. */ + long long int created OVS_GUARDED; /* Estimate of creation time. */ + uint64_t dump_seq OVS_GUARDED; /* Tracks udpif->dump_seq. */ + uint64_t reval_seq OVS_GUARDED; /* Tracks udpif->reval_seq. */ +@@ -362,6 +366,10 @@ static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc, const char *argv[], void *aux); static void upcall_unixctl_purge(struct unixctl_conn *conn, int argc, const char *argv[], void *aux); @@ -58968,7 +59085,7 @@ index 57f94df544..59126b9014 100644 static struct udpif_key *ukey_create_from_upcall(struct upcall *, struct flow_wildcards *); -@@ -434,6 +438,10 @@ udpif_init(void) +@@ -434,6 +442,10 @@ udpif_init(void) upcall_unixctl_dump_wait, NULL); unixctl_command_register("revalidator/purge", "", 0, 0, upcall_unixctl_purge, NULL); @@ -58979,7 +59096,33 @@ index 57f94df544..59126b9014 100644 ovsthread_once_done(&once); } } -@@ -1868,6 +1876,7 @@ try_ukey_replace(struct umap *umap, struct udpif_key *old_ukey, +@@ -771,6 +783,17 @@ udpif_get_n_flows(struct udpif *udpif) + atomic_store_relaxed(&udpif->n_flows_timestamp, now); + dpif_get_dp_stats(udpif->dpif, &stats); + flow_count = stats.n_flows; ++ ++ if (!dpif_synced_dp_layers(udpif->dpif)) { ++ /* If the dpif layer does not sync the flows, we need to include ++ * the hardware offloaded flows separately. */ ++ uint64_t hw_flows; ++ ++ if (!dpif_get_n_offloaded_flows(udpif->dpif, &hw_flows)) { ++ flow_count += hw_flows; ++ } ++ } ++ + atomic_store_relaxed(&udpif->n_flows, flow_count); + ovs_mutex_unlock(&udpif->n_flows_mutex); + } else { +@@ -1746,6 +1769,7 @@ ukey_create__(const struct nlattr *key, size_t key_len, + ukey->created = ukey->flow_time = time_msec(); + memset(&ukey->stats, 0, sizeof ukey->stats); + ukey->stats.used = used; ++ ukey->dp_layer = NULL; + ukey->xcache = NULL; + + ukey->offloaded = false; +@@ -1868,6 +1892,7 @@ try_ukey_replace(struct umap *umap, struct udpif_key *old_ukey, ovs_mutex_lock(&new_ukey->mutex); cmap_replace(&umap->cmap, &old_ukey->cmap_node, &new_ukey->cmap_node, new_ukey->hash); @@ -58987,7 +59130,60 @@ index 57f94df544..59126b9014 100644 ovsrcu_postpone(ukey_delete__, old_ukey); transition_ukey(old_ukey, UKEY_DELETED); transition_ukey(new_ukey, UKEY_VISIBLE); -@@ -2853,7 +2862,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge) +@@ -2321,6 +2346,13 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey, + ? stats->n_bytes - ukey->stats.n_bytes + : 0); + ++ if (stats->n_packets < ukey->stats.n_packets && ++ ukey->stats.n_packets < UINT64_THREE_QUARTERS) { ++ /* Report cases where the packet counter is lower than the previous ++ * instance, but exclude the potential wrapping of an uint64_t. */ ++ COVERAGE_INC(ukey_invalid_stat_reset); ++ } ++ + if (need_revalidate) { + if (should_revalidate(udpif, push.n_packets, ukey->stats.used)) { + if (!ukey->xcache) { +@@ -2434,6 +2466,15 @@ push_dp_ops(struct udpif *udpif, struct ukey_op *ops, size_t n_ops) + push->tcp_flags = stats->tcp_flags | op->ukey->stats.tcp_flags; + push->n_packets = stats->n_packets - op->ukey->stats.n_packets; + push->n_bytes = stats->n_bytes - op->ukey->stats.n_bytes; ++ ++ if (stats->n_packets < op->ukey->stats.n_packets && ++ op->ukey->stats.n_packets < UINT64_THREE_QUARTERS) { ++ /* Report cases where the packet counter is lower than the ++ * previous instance, but exclude the potential wrapping of an ++ * uint64_t. */ ++ COVERAGE_INC(ukey_invalid_stat_reset); ++ } ++ + ovs_mutex_unlock(&op->ukey->mutex); + } else { + push = stats; +@@ -2738,6 +2779,22 @@ revalidate(struct revalidator *revalidator) + continue; + } + ++ ukey->offloaded = f->attrs.offloaded; ++ if (!ukey->dp_layer ++ || (!dpif_synced_dp_layers(udpif->dpif) ++ && strcmp(ukey->dp_layer, f->attrs.dp_layer))) { ++ ++ if (ukey->dp_layer) { ++ /* The dp_layer has changed this is probably due to an ++ * earlier revalidate cycle moving it to/from hw offload. ++ * In this case we should reset the ukey stored statistics, ++ * as they are from the deleted DP flow. */ ++ COVERAGE_INC(ukey_dp_change); ++ memset(&ukey->stats, 0, sizeof ukey->stats); ++ } ++ ukey->dp_layer = f->attrs.dp_layer; ++ } ++ + already_dumped = ukey->dump_seq == dump_seq; + if (already_dumped) { + /* The flow has already been handled during this flow dump +@@ -2853,7 +2910,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge) } else { struct dpif_flow_stats stats; COVERAGE_INC(revalidate_missed_dp_flow); @@ -58996,7 +59192,7 @@ index 57f94df544..59126b9014 100644 result = revalidate_ukey(udpif, ukey, &stats, &odp_actions, reval_seq, &recircs, false); } -@@ -3099,6 +3108,31 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED, +@@ -3099,6 +3156,31 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED, unixctl_command_reply(conn, ""); } @@ -66955,7 +67151,7 @@ index d21fd777dd..c37852b216 100644 OVS_VSWITCHD_STOP diff --git a/tests/system-offloads-traffic.at b/tests/system-offloads-traffic.at -index 80bc1dd5c3..9f50f3b01d 100644 +index 80bc1dd5c3..84bab88be2 100644 --- a/tests/system-offloads-traffic.at +++ b/tests/system-offloads-traffic.at @@ -90,7 +90,7 @@ AT_CHECK([tc -o -s -d filter show dev ovs-p0 ingress | @@ -66976,14 +67172,16 @@ index 80bc1dd5c3..9f50f3b01d 100644 OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP -@@ -168,3 +168,67 @@ matchall +@@ -168,3 +168,131 @@ matchall ]) OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP + + +AT_SETUP([offloads - simulated flow action update]) -+OVS_TRAFFIC_VSWITCHD_START([], [], [-- set Open_vSwitch . other_config:hw-offload=true]) ++OVS_TRAFFIC_VSWITCHD_START() ++ ++AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true]) + +ADD_NAMESPACES(at_ns0, at_ns1) + @@ -67044,6 +67242,68 @@ index 80bc1dd5c3..9f50f3b01d 100644 + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP ++ ++ ++AT_SETUP([offloads - offload flow to none-offload]) ++OVS_TRAFFIC_VSWITCHD_START() ++ ++AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true]) ++ ++ADD_NAMESPACES(at_ns0, at_ns1) ++ ++ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") ++ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") ++ ++AT_DATA([flows.txt], [dnl ++add in_port=ovs-p0,actions=ovs-p1 ++add in_port=ovs-p1,actions=ovs-p0 ++]) ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++ ++NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl ++10 packets transmitted, 10 received, 0% packet loss, time 0ms ++]) ++ ++AT_CHECK([ovs-appctl dpctl/dump-flows type=tc | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl ++recirc_id(),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:756, used:0.0s, actions:3 ++recirc_id(),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:756, used:0.0s, actions:2 ++]) ++ ++dnl Here we use an output action with truncate, which will force a kernel flow. ++AT_DATA([flows2.txt], [dnl ++modify in_port=ovs-p0,actions=output(port=ovs-p1, max_len=128) ++modify in_port=ovs-p1,actions=output(port=ovs-p0, max_len=128) ++]) ++AT_CHECK([ovs-ofctl add-flows br0 flows2.txt]) ++AT_CHECK([ovs-appctl revalidator/wait], [0]) ++ ++NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl ++10 packets transmitted, 10 received, 0% packet loss, time 0ms ++]) ++ ++AT_CHECK([ovs-appctl dpctl/dump-flows type=ovs | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl ++recirc_id(),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:980, used:0.0s, actions:trunc(128),3 ++recirc_id(),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:980, used:0.0s, actions:trunc(128),2 ++]) ++ ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++AT_CHECK([ovs-appctl revalidator/wait], [0]) ++ ++NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl ++10 packets transmitted, 10 received, 0% packet loss, time 0ms ++]) ++ ++AT_CHECK([ovs-appctl dpctl/dump-flows type=tc | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl ++recirc_id(),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:840, used:0.0s, actions:3 ++recirc_id(),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:840, used:0.0s, actions:2 ++]) ++ ++AT_CHECK([ovs-appctl coverage/read-counter ukey_invalid_stat_reset], [0], [dnl ++0 ++]) ++ ++OVS_TRAFFIC_VSWITCHD_STOP ++AT_CLEANUP diff --git a/tests/system-route.at b/tests/system-route.at index 1714273e35..270956d13f 100644 --- a/tests/system-route.at diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec index 06d7931..61059eb 100644 --- a/SPECS/openvswitch2.17.spec +++ b/SPECS/openvswitch2.17.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.17.0 -Release: 69%{?dist} +Release: 70%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -748,6 +748,14 @@ exit 0 %endif %changelog +* Tue Mar 07 2023 Open vSwitch CI - 2.17.0-70 +- Merging upstream branch-2.17 [RH git: 0b8ab7fa79] + Commit list: + 7aa314c9c2 netdev-windows: Add checking when creating netdev with system type on Windows + 215278bded ofproto-dpif-upcall: Include hardware offloaded flows in total flows. + 4a3f8845e9 ofproto-dpif-upcall: Reset ukey's last stats value if the datapath changed. + + * Thu Mar 02 2023 Open vSwitch CI - 2.17.0-69 - Merging upstream branch-2.17 [RH git: 887978485c] Commit list: