On 1/12/26 12:20 PM, Eelco Chaudron wrote:
> This patch adds a new API that allows offload providers
> to expose free-form debug information. The information
> can be used for troubleshooting the offload providers state.
>
> The new API is integrated into the existing
> 'ovs-appctl dpif/offload/show' command, which now
> displays this debug output when available.
>
> Support for this API has been implemented for all
> currently supported offload providers.
>
> Acked-by: Eli Britstein <elibr.nvidia.com>
> Signed-off-by: Eelco Chaudron <[email protected]>
> ---
>
> v3 changes:
> - Fixed some newline issues.
> ---
> include/openvswitch/json.h | 1 +
> lib/dpif-offload-dpdk.c | 52 ++++++++++++++++
> lib/dpif-offload-dummy.c | 55 ++++++++++++++++
> lib/dpif-offload-provider.h | 9 +++
> lib/dpif-offload-tc.c | 54 ++++++++++++++++
> lib/dpif-offload.c | 12 ++++
> lib/dpif-offload.h | 2 +
> lib/json.c | 7 +++
> ofproto/ofproto-dpif.c | 18 +++++-
> tests/ofproto-dpif.at | 104 +++++++++++++++++++++++++++++--
> tests/system-dpdk.at | 13 +++-
> tests/system-offloads-traffic.at | 33 ++++++++--
> 12 files changed, 345 insertions(+), 15 deletions(-)
>
> diff --git a/include/openvswitch/json.h b/include/openvswitch/json.h
> index 134890553..ea2c4da04 100644
> --- a/include/openvswitch/json.h
> +++ b/include/openvswitch/json.h
> @@ -123,6 +123,7 @@ struct json *json_array_create_3(struct json *, struct
> json *, struct json *);
> bool json_array_contains_string(const struct json *, const char *);
>
> struct json *json_object_create(void);
> +bool json_object_is_empty(struct json *);
> void json_object_put(struct json *, const char *name, struct json *value);
> void json_object_put_nocopy(struct json *, char *name, struct json *value);
> void json_object_put_string(struct json *,
> diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c
> index 2a9743d74..e54b41f25 100644
> --- a/lib/dpif-offload-dpdk.c
> +++ b/lib/dpif-offload-dpdk.c
> @@ -23,6 +23,7 @@
> #include "netdev-vport.h"
> #include "util.h"
>
> +#include "openvswitch/json.h"
> #include "openvswitch/vlog.h"
>
> VLOG_DEFINE_THIS_MODULE(dpif_offload_dpdk);
> @@ -189,6 +190,56 @@ dpif_offload_dpdk_set_config(struct dpif_offload
> *offload_,
> }
> }
>
> +static bool
> +dpif_offload_dpdk_get_port_debug_ds(struct dpif_offload_port_mgr_port *port,
> + void *aux)
> +{
> + struct ds *ds = aux;
> +
> + ds_put_format(ds, " - %s: port_no: %u\n",
> + netdev_get_name(port->netdev), port->port_no);
> +
Empty line may be unnecessary.
> + return false;
> +}
> +
> +static bool
> +dpif_offload_dpdk_get_port_debug_json(struct dpif_offload_port_mgr_port
> *port,
> + void *aux)
> +{
> + struct json *json_port = json_object_create();
> + struct json *json = aux;
> +
> + json_object_put(json_port, "port_no",
> + json_integer_create(odp_to_u32(port->port_no)));
> +
> + json_object_put(json, netdev_get_name(port->netdev), json_port);
> + return false;
> +}
> +
> +static void
> +dpif_offload_dpdk_get_debug(const struct dpif_offload *offload_, struct ds
> *ds,
> + struct json *json)
> +{
> + struct dpif_offload_dpdk *offload = dpif_offload_dpdk_cast(offload_);
> +
> + if (json) {
> + struct json *json_ports = json_object_create();
> +
> + dpif_offload_port_mgr_traverse_ports(
> + offload->port_mgr, dpif_offload_dpdk_get_port_debug_json,
> + json_ports);
> +
> + if (!json_object_is_empty(json_ports)) {
> + json_object_put(json, "ports", json_ports);
> + } else {
> + json_destroy(json_ports);
> + }
> + } else if (ds) {
> + dpif_offload_port_mgr_traverse_ports(
> + offload->port_mgr, dpif_offload_dpdk_get_port_debug_ds, ds);
> + }
> +}
> +
> static bool
> dpif_offload_dpdk_can_offload(struct dpif_offload *offload OVS_UNUSED,
> struct netdev *netdev)
> @@ -211,6 +262,7 @@ struct dpif_offload_class dpif_offload_dpdk_class = {
> .open = dpif_offload_dpdk_open,
> .close = dpif_offload_dpdk_close,
> .set_config = dpif_offload_dpdk_set_config,
> + .get_debug = dpif_offload_dpdk_get_debug,
> .can_offload = dpif_offload_dpdk_can_offload,
> .port_add = dpif_offload_dpdk_port_add,
> .port_del = dpif_offload_dpdk_port_del,
> diff --git a/lib/dpif-offload-dummy.c b/lib/dpif-offload-dummy.c
> index 795c82a6c..33f89599a 100644
> --- a/lib/dpif-offload-dummy.c
> +++ b/lib/dpif-offload-dummy.c
> @@ -24,6 +24,8 @@
> #include "netdev-provider.h"
> #include "util.h"
>
> +#include "openvswitch/json.h"
> +
> struct dpif_offload_dummy {
> struct dpif_offload offload;
> struct dpif_offload_port_mgr *port_mgr;
> @@ -174,6 +176,58 @@ dpif_offload_dummy_set_config(struct dpif_offload
> *dpif_offload,
> }
> }
>
> +static bool
> +dpif_offload_dummy_get_port_debug_ds(struct dpif_offload_port_mgr_port *port,
> + void *aux)
> +{
> + struct ds *ds = aux;
> +
> + ds_put_format(ds, " - %s: port_no: %u\n", netdev_get_name(port->netdev),
> + port->port_no);
> +
Smae here.
> + return false;
> +}
> +
> +static bool
> +dpif_offload_dummy_get_port_debug_json(struct dpif_offload_port_mgr_port
> *port,
> + void *aux)
> +{
> + struct json *json_port = json_object_create();
> + struct json *json = aux;
> +
> + json_object_put(json_port, "port_no",
> + json_integer_create(odp_to_u32(port->port_no)));
> +
> + json_object_put(json, netdev_get_name(port->netdev), json_port);
> + return false;
> +}
> +
> +static void
> +dpif_offload_dummy_get_debug(const struct dpif_offload *offload, struct ds
> *ds,
> + struct json *json)
> +{
> + struct dpif_offload_dummy *offload_dummy;
> +
> + offload_dummy = dpif_offload_dummy_cast(offload);
> +
> + if (json) {
> + struct json *json_ports = json_object_create();
> +
> + dpif_offload_port_mgr_traverse_ports(
> + offload_dummy->port_mgr, dpif_offload_dummy_get_port_debug_json,
> + json_ports);
> +
> + if (!json_object_is_empty(json_ports)) {
> + json_object_put(json, "ports", json_ports);
> + } else {
> + json_destroy(json_ports);
> + }
> + } else if (ds) {
> + dpif_offload_port_mgr_traverse_ports(
> + offload_dummy->port_mgr, dpif_offload_dummy_get_port_debug_ds,
> ds);
> + }
> +}
> +
> static bool
> dpif_offload_dummy_can_offload(struct dpif_offload *dpif_offload OVS_UNUSED,
> struct netdev *netdev)
> @@ -190,6 +244,7 @@ dpif_offload_dummy_can_offload(struct dpif_offload
> *dpif_offload OVS_UNUSED,
> .open = dpif_offload_dummy_open, \
> .close = dpif_offload_dummy_close, \
> .set_config = dpif_offload_dummy_set_config, \
> + .get_debug = dpif_offload_dummy_get_debug, \
> .can_offload = dpif_offload_dummy_can_offload, \
> .port_add = dpif_offload_dummy_port_add, \
> .port_del = dpif_offload_dummy_port_del, \
> diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
> index d53cc9f18..50d2da19e 100644
> --- a/lib/dpif-offload-provider.h
> +++ b/lib/dpif-offload-provider.h
> @@ -94,6 +94,15 @@ struct dpif_offload_class {
> void (*set_config)(struct dpif_offload *,
> const struct smap *other_config);
>
> + /* Retrieve debug information from the offload provider in either string
> + * (ds) or JSON format. If both formats are requested, the provider may
> + * choose which one to return. Note that the actual format is
> unspecified,
> + * it's up to the provider to decide what to return. If 'ds' is supplied,
nit: double space.
> + * it should be initialized, and might already contain data. The caller
> is
> + * responsible for freeing any returned 'ds' or 'json' pointers. */
> + void (*get_debug)(const struct dpif_offload *offload, struct ds *ds,
> + struct json *json);
> +
> /* Verifies whether the offload provider supports offloading flows for
> the
> * given 'netdev'. Returns 'false' if the provider lacks the
> capabilities
> * to offload on this port, otherwise returns 'true'. */
> diff --git a/lib/dpif-offload-tc.c b/lib/dpif-offload-tc.c
> index 606f6d552..fb9db9433 100644
> --- a/lib/dpif-offload-tc.c
> +++ b/lib/dpif-offload-tc.c
> @@ -24,6 +24,7 @@
> #include "tc.h"
> #include "util.h"
>
> +#include "openvswitch/json.h"
> #include "openvswitch/vlog.h"
>
> VLOG_DEFINE_THIS_MODULE(dpif_offload_tc);
> @@ -172,6 +173,58 @@ dpif_offload_tc_set_config(struct dpif_offload *offload,
> }
> }
>
> +static bool
> +dpif_offload_tc_get_port_debug_ds(struct dpif_offload_port_mgr_port *port,
> + void *aux)
> +{
> + struct ds *ds = aux;
> +
> + ds_put_format(ds, " - %s: port_no: %u, ifindex: %d\n",
> + netdev_get_name(port->netdev), port->port_no,
> port->ifindex);
> +
ditto
> + return false;
> +}
> +
> +static bool
> +dpif_offload_tc_get_port_debug_json(struct dpif_offload_port_mgr_port *port,
> + void *aux)
> +{
> + struct json *json_port = json_object_create();
> + struct json *json = aux;
> +
> + json_object_put(json_port, "port_no",
> + json_integer_create(odp_to_u32(port->port_no)));
> + json_object_put(json_port, "ifindex",
> json_integer_create(port->ifindex));
> +
> + json_object_put(json, netdev_get_name(port->netdev), json_port);
> + return false;
> +}
> +
> +static void
> +dpif_offload_tc_get_debug(const struct dpif_offload *offload, struct ds *ds,
> + struct json *json)
> +{
> + struct dpif_offload_tc *offload_tc = dpif_offload_tc_cast(offload);
> +
> + if (json) {
> + struct json *json_ports = json_object_create();
> +
> + dpif_offload_port_mgr_traverse_ports(
> + offload_tc->port_mgr, dpif_offload_tc_get_port_debug_json,
> + json_ports);
> +
> + if (!json_object_is_empty(json_ports)) {
> + json_object_put(json, "ports", json_ports);
> + } else {
> + json_destroy(json_ports);
> + }
> + } else if (ds) {
> + dpif_offload_port_mgr_traverse_ports(offload_tc->port_mgr,
> +
> dpif_offload_tc_get_port_debug_ds,
> + ds);
> + }
> +}
> +
> static bool
> dpif_offload_tc_can_offload(struct dpif_offload *dpif_offload OVS_UNUSED,
> struct netdev *netdev)
> @@ -193,6 +246,7 @@ struct dpif_offload_class dpif_offload_tc_class = {
> .open = dpif_offload_tc_open,
> .close = dpif_offload_tc_close,
> .set_config = dpif_offload_tc_set_config,
> + .get_debug = dpif_offload_tc_get_debug,
> .can_offload = dpif_offload_tc_can_offload,
> .port_add = dpif_offload_tc_port_add,
> .port_del = dpif_offload_tc_port_del,
> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
> index 1dbec5d33..b6d057ec1 100644
> --- a/lib/dpif-offload.c
> +++ b/lib/dpif-offload.c
> @@ -409,6 +409,18 @@ dpif_offload_class_type(const struct dpif_offload
> *offload)
> return offload->class->type;
> }
>
> +bool
> +dpif_offload_get_debug(const struct dpif_offload *offload, struct ds *ds,
> + struct json *json)
> +{
> + if (!offload->class->get_debug) {
> + return false;
> + }
> +
> + offload->class->get_debug(offload, ds, json);
> + return true;
> +}
> +
> bool
> dpif_offload_is_offload_enabled(void)
> {
> diff --git a/lib/dpif-offload.h b/lib/dpif-offload.h
> index 9cee3a8f4..5b6c3038e 100644
> --- a/lib/dpif-offload.h
> +++ b/lib/dpif-offload.h
> @@ -44,6 +44,8 @@ int dpif_offload_attach_providers(struct dpif *);
> void dpif_offload_detach_providers(struct dpif *);
> const char *dpif_offload_name(const struct dpif_offload *);
> const char *dpif_offload_class_type(const struct dpif_offload *);
> +bool dpif_offload_get_debug(const struct dpif_offload *, struct ds *,
> + struct json *);
> void dpif_offload_dump_start(struct dpif_offload_dump *, const struct dpif
> *);
> bool dpif_offload_dump_next(struct dpif_offload_dump *,
> struct dpif_offload **);
> diff --git a/lib/json.c b/lib/json.c
> index 23622ab36..23000f195 100644
> --- a/lib/json.c
> +++ b/lib/json.c
> @@ -397,6 +397,13 @@ json_object_create(void)
> return json;
> }
>
> +bool
> +json_object_is_empty(struct json *json)
> +{
> + return json && json->type == JSON_OBJECT
> + && shash_is_empty(json->object);
> +}
> +
> struct json *
> json_integer_create(long long int integer)
> {
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 7f76c7864..de7657db3 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -6719,6 +6719,7 @@ dpif_offload_show_backer_text(const struct dpif_backer
> *backer, struct ds *ds)
>
> DPIF_OFFLOAD_FOR_EACH (offload, &dump, backer->dpif) {
> ds_put_format(ds, " %s\n", dpif_offload_class_type(offload));
> + dpif_offload_get_debug(offload, ds, NULL);
> }
> }
>
> @@ -6733,15 +6734,26 @@ dpif_offload_show_backer_json(struct json *backers,
> /* Add datapath as new JSON object using its name as key. */
> json_object_put(backers, dpif_name(backer->dpif), json_backer);
>
> - /* Add provider to "providers" array using its name as key. */
> - struct json *json_providers = json_array_create_empty();
> + /* Add provider to "providers" object using its name as key. */
> + struct json *json_providers = json_object_create();
> +
> + /* Add provider to "priority" array using its name as key. */
> + struct json *json_priority = json_array_create_empty();
>
> /* Add offload provides as new JSON objects using its type as key. */
> DPIF_OFFLOAD_FOR_EACH (offload, &dump, backer->dpif) {
> - json_array_add(json_providers,
> + struct json *debug_data = json_object_create();
> +
> + json_array_add(json_priority,
> json_string_create(dpif_offload_class_type(offload)));
> +
> + dpif_offload_get_debug(offload, NULL, debug_data);
> +
> + json_object_put(json_providers, dpif_offload_class_type(offload),
> + debug_data);
> }
>
> + json_object_put(json_backer, "priority", json_priority);
> json_object_put(json_backer, "providers", json_providers);
> return json_backer;
> }
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index fb14d23a3..06c57185c 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -20,6 +20,28 @@ check_dpflow_stats () {
> echo "n_flows=$flows n_buckets=$buckets"
> }
>
> +sort_dpif_offload_show () {
> + awk '
> + /^ -/ { dashlines[[++n]] = $0; next }
> + { print }
> + END {
> + # asort(dashlines) is a GNU extension, so we need to do it
> + # manually here as ofproto-dpif is also executed on FreeBSD.
> + for (i = 1; i <= n; i++) {
> + for (j = i + 1; j <= n; j++) {
> + if (dashlines[[i]] > dashlines[[j]]) {
> + tmp = dashlines[[i]]
> + dashlines[[i]] = dashlines[[j]]
> + dashlines[[j]] = tmp
> + }
> + }
> + }
> +
> + for (i=1; i<=n; i++) print dashlines[[i]]
> + }
> + '
> +}
> +
> m4_divert_pop([PREPARE_TESTS])
>
>
> @@ -10108,20 +10130,34 @@ AT_SETUP([ofproto-dpif - offload - ovs-appctl
> dpif/offload/])
> AT_KEYWORDS([dpif-offload])
> OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy])
>
> -AT_CHECK([ovs-appctl dpif/offload/show], [0], [dnl
> +AT_CHECK([ovs-appctl dpif/offload/show | sort_dpif_offload_show], [0], [dnl
> Globally enabled: false
> Datapaths:
> dummy@ovs-dummy:
> dummy
> dummy_x
> + - br0: port_no: 100
> + - br1: port_no: 101
> + - ovs-dummy: port_no: 0
> ])
>
> AT_CHECK([ovs-appctl --format json --pretty dpif/offload/show], [0], [dnl
> {
> "dummy@ovs-dummy": {
> - "providers": [[
> + "priority": [[
> "dummy",
> - "dummy_x"]]},
> + "dummy_x"]],
> + "providers": {
> + "dummy": {
> + "ports": {
> + "br0": {
> + "port_no": 100},
> + "br1": {
> + "port_no": 101},
> + "ovs-dummy": {
> + "port_no": 0}}},
> + "dummy_x": {
> + }}},
> "enabled": false}
> ])
>
> @@ -10146,26 +10182,82 @@ AT_KEYWORDS([dpif-offload])
> OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy], [],
> [],
> [], [-- set Open_vSwitch . other_config:hw-offload-priority=dummy_x,dummy])
>
> -AT_CHECK([ovs-appctl dpif/offload/show], [0], [dnl
> +AT_CHECK([ovs-appctl dpif/offload/show | sort_dpif_offload_show], [0], [dnl
> Globally enabled: false
> Datapaths:
> dummy@ovs-dummy:
> dummy_x
> dummy
> + - br0: port_no: 100
> + - br1: port_no: 101
> + - ovs-dummy: port_no: 0
> ])
>
> AT_CHECK([ovs-appctl --format json --pretty dpif/offload/show], [0], [dnl
> {
> "dummy@ovs-dummy": {
> - "providers": [[
> + "priority": [[
> "dummy_x",
> - "dummy"]]},
> + "dummy"]],
> + "providers": {
> + "dummy": {
> + },
> + "dummy_x": {
> + "ports": {
> + "br0": {
> + "port_no": 100},
> + "br1": {
> + "port_no": 101},
> + "ovs-dummy": {
> + "port_no": 0}}}}},
> "enabled": false}
> ])
>
> OVS_TRAFFIC_VSWITCHD_STOP
> AT_CLEANUP
>
> +AT_SETUP([ofproto-dpif - offload - port priority order])
> +AT_KEYWORDS([dpif-offload])
> +OVS_VSWITCHD_START([add-port br0 p1 -- \
> + set Interface p1 type=dummy ofport_request=1 -- \
> + set port p1 other_config:hw-offload-priority=dummy_x,dummy -- \
> + add-port br0 p2 -- \
> + set Interface p2 type=dummy ofport_request=2 -- \
> + set port p2 other_config:hw-offload-priority=none -- \
> + add-port br0 p3 -- \
> + set Interface p3 type=dummy ofport_request=3 -- \
> + set port p3 other_config:hw-offload-priority=dummy_x -- \
> + add-port br0 p4 -- \
> + set Interface p4 type=dummy ofport_request=4 -- \
> + set port p4 other_config:hw-offload-priority=dummy])
> +
> +AT_CHECK([ovs-appctl --format json --pretty dpif/offload/show], [0], [dnl
> +{
> + "dummy@ovs-dummy": {
> + "priority": [[
> + "dummy",
> + "dummy_x"]],
> + "providers": {
> + "dummy": {
> + "ports": {
> + "br0": {
> + "port_no": 100},
> + "ovs-dummy": {
> + "port_no": 0},
> + "p4": {
> + "port_no": 4}}},
> + "dummy_x": {
> + "ports": {
> + "p1": {
> + "port_no": 1},
> + "p3": {
> + "port_no": 3}}}}},
> + "enabled": false}
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> dnl ----------------------------------------------------------------------
> AT_BANNER([ofproto-dpif -- megaflows])
>
> diff --git a/tests/system-dpdk.at b/tests/system-dpdk.at
> index c1910b756..17d3d2595 100644
> --- a/tests/system-dpdk.at
> +++ b/tests/system-dpdk.at
> @@ -948,20 +948,29 @@ AT_KEYWORDS([dpdk dpif-offload])
> OVS_DPDK_PRE_CHECK()
> OVS_DPDK_START([--no-pci])
> AT_CHECK([ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev])
> +AT_CHECK([ovs-vsctl add-port br0 p1 \
> + -- set Interface p1 type=dpdk options:dpdk-devargs=net_null0,no-rx=1],
> + [], [stdout], [stderr])
>
> AT_CHECK([ovs-appctl dpif/offload/show], [0], [dnl
> Globally enabled: false
> Datapaths:
> netdev@ovs-netdev:
> dpdk
> + - p1: port_no: 2
> ])
>
> AT_CHECK([ovs-appctl --format json --pretty dpif/offload/show], [0], [dnl
> {
> "enabled": false,
> "netdev@ovs-netdev": {
> - "providers": [[
> - "dpdk"]]}}
> + "priority": [[
> + "dpdk"]],
> + "providers": {
> + "dpdk": {
> + "ports": {
> + "p1": {
> + "port_no": 2}}}}}}
> ])
>
> OVS_DPDK_STOP_VSWITCHD
> diff --git a/tests/system-offloads-traffic.at
> b/tests/system-offloads-traffic.at
> index 92d3523dc..8cea007ce 100644
> --- a/tests/system-offloads-traffic.at
> +++ b/tests/system-offloads-traffic.at
> @@ -1172,19 +1172,44 @@ AT_KEYWORDS([dpif-offload])
> OVS_TRAFFIC_VSWITCHD_START([], [],
> [-- set Open_vSwitch . other_config:hw-offload=true])
>
> -AT_CHECK([ovs-appctl dpif/offload/show], [0], [dnl
> +sort_dpif_offload_show () {
> + dnl Note: We do not use an m4 macro as it does not like the $0, or
> escaped
> + dnl variants and loops until it runs out of memory.
Note: I think, the $[0] should work as the m4 pass will remove the brackets
and should not evaluate further. But it's OK to use a shell function for
filtering. Just the comment may be a bit inaccurate.
> + awk '
> + /^ -/ { dashlines[[++n]] = $0; next }
> + { print }
> + END {
> + asort(dashlines)
> + for (i=1; i<=n; i++) print dashlines[[i]]
> + }
> + ' | sed -E 's/ifindex: [[0-9]]+/ifindex: 0/g'
> +}
> +
> +AT_CHECK([ovs-appctl dpif/offload/show | sort_dpif_offload_show], [0], [dnl
> Globally enabled: true
> Datapaths:
> system@ovs-system:
> tc
> + - br0: port_no: 1, ifindex: 0
> + - ovs-system: port_no: 0, ifindex: 0
> ])
>
> -AT_CHECK([ovs-appctl --format json --pretty dpif/offload/show], [0], [dnl
> +AT_CHECK([ovs-appctl --format json --pretty dpif/offload/show \
> + | sed -E 's/"ifindex": [[0-9]]+/"ifindex": 0/g'], [0], [dnl
> {
> "enabled": true,
> "system@ovs-system": {
> - "providers": [[
> - "tc"]]}}
> + "priority": [[
> + "tc"]],
> + "providers": {
> + "tc": {
> + "ports": {
> + "br0": {
> + "ifindex": 0,
> + "port_no": 1},
> + "ovs-system": {
> + "ifindex": 0,
> + "port_no": 0}}}}}}
> ])
>
> OVS_TRAFFIC_VSWITCHD_STOP
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev