dpif-netlink: Remove netlink-offload integration

This patch removes the legacy integration between dpif-netlink and
netlink-offload. All netdev flow dump structures, flow dump APIs, and
supporting code related to offloaded flows in dpif-netlink and
netdev-offload have been removed, as (tc) flow offload is now handled
entirely through dpif-offload.

This simplifies dpif-netlink by decoupling it from all it's offload
logic.

Signed-off-by: Eelco Chaudron <echau...@redhat.com>
---
 lib/dpif-netlink.c            | 169 +++-------------------------------
 lib/dpif-offload-tc.c         |   8 +-
 lib/netdev-offload-provider.h |  23 -----
 lib/netdev-offload-tc.c       |  12 +--
 lib/netdev-offload-tc.h       |  15 ++-
 lib/netdev-offload.c          |  77 ----------------
 lib/netdev-offload.h          |  18 ----
 7 files changed, 33 insertions(+), 289 deletions(-)

diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index ff29f9427..2df91a98e 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -79,7 +79,6 @@ enum { MAX_PORTS = USHRT_MAX };
  * missing if we have old headers. */
 #define ETH_FLAG_LRO      (1 << 15)    /* LRO is enabled */
 
-#define FLOW_DUMP_MAX_BATCH 50
 #define OPERATE_MAX_OPS 50
 
 #ifndef EPOLLEXCLUSIVE
@@ -1599,11 +1598,6 @@ struct dpif_netlink_flow_dump {
     struct dpif_flow_dump up;
     struct nl_dump nl_dump;
     atomic_int status;
-    struct netdev_flow_dump **netdev_dumps;
-    int netdev_dumps_num;                    /* Number of netdev_flow_dumps */
-    struct ovs_mutex netdev_lock;            /* Guards the following. */
-    int netdev_current_dump OVS_GUARDED;     /* Shared current dump */
-    struct dpif_flow_dump_types types;       /* Type of dump */
 };
 
 static struct dpif_netlink_flow_dump *
@@ -1612,39 +1606,6 @@ dpif_netlink_flow_dump_cast(struct dpif_flow_dump *dump)
     return CONTAINER_OF(dump, struct dpif_netlink_flow_dump, up);
 }
 
-static void
-start_netdev_dump(const struct dpif *dpif_,
-                  struct dpif_netlink_flow_dump *dump)
-{
-    ovs_mutex_init(&dump->netdev_lock);
-
-    if (!(dump->types.offloaded_flows)) {
-        dump->netdev_dumps_num = 0;
-        dump->netdev_dumps = NULL;
-        return;
-    }
-
-    ovs_mutex_lock(&dump->netdev_lock);
-    dump->netdev_current_dump = 0;
-    dump->netdev_dumps
-        = netdev_ports_flow_dump_create(dpif_normalize_type(dpif_type(dpif_)),
-                                        &dump->netdev_dumps_num,
-                                        dump->up.terse);
-    ovs_mutex_unlock(&dump->netdev_lock);
-}
-
-static void
-dpif_netlink_populate_flow_dump_types(struct dpif_netlink_flow_dump *dump,
-                                      struct dpif_flow_dump_types *types)
-{
-    if (!types) {
-        dump->types.ovs_flows = true;
-        dump->types.offloaded_flows = true;
-    } else {
-        memcpy(&dump->types, types, sizeof *types);
-    }
-}
-
 static struct dpif_flow_dump *
 dpif_netlink_flow_dump_create(const struct dpif *dpif_, bool terse,
                               struct dpif_flow_dump_types *types)
@@ -1657,24 +1618,18 @@ dpif_netlink_flow_dump_create(const struct dpif *dpif_, 
bool terse,
     dump = xmalloc(sizeof *dump);
     dpif_flow_dump_init(&dump->up, dpif_, terse, types);
 
-    dpif_netlink_populate_flow_dump_types(dump, types);
-
-    if (dump->types.ovs_flows) {
-        dpif_netlink_flow_init(&request);
-        request.cmd = OVS_FLOW_CMD_GET;
-        request.dp_ifindex = dpif->dp_ifindex;
-        request.ufid_present = false;
-        request.ufid_terse = terse;
+    dpif_netlink_flow_init(&request);
+    request.cmd = OVS_FLOW_CMD_GET;
+    request.dp_ifindex = dpif->dp_ifindex;
+    request.ufid_present = false;
+    request.ufid_terse = terse;
 
-        buf = ofpbuf_new(1024);
-        dpif_netlink_flow_to_ofpbuf(&request, buf);
-        nl_dump_start(&dump->nl_dump, NETLINK_GENERIC, buf);
-        ofpbuf_delete(buf);
-    }
+    buf = ofpbuf_new(1024);
+    dpif_netlink_flow_to_ofpbuf(&request, buf);
+    nl_dump_start(&dump->nl_dump, NETLINK_GENERIC, buf);
+    ofpbuf_delete(buf);
     atomic_init(&dump->status, 0);
 
-    start_netdev_dump(dpif_, dump);
-
     return &dump->up;
 }
 
@@ -1682,24 +1637,9 @@ static int
 dpif_netlink_flow_dump_destroy(struct dpif_flow_dump *dump_)
 {
     struct dpif_netlink_flow_dump *dump = dpif_netlink_flow_dump_cast(dump_);
-    unsigned int nl_status = 0;
+    unsigned int nl_status = nl_dump_done(&dump->nl_dump);
     int dump_status;
 
-    if (dump->types.ovs_flows) {
-        nl_status = nl_dump_done(&dump->nl_dump);
-    }
-
-    for (int i = 0; i < dump->netdev_dumps_num; i++) {
-        int err = netdev_flow_dump_destroy(dump->netdev_dumps[i]);
-
-        if (err != 0 && err != EOPNOTSUPP) {
-            VLOG_ERR("failed dumping netdev: %s", ovs_strerror(err));
-        }
-    }
-
-    free(dump->netdev_dumps);
-    ovs_mutex_destroy(&dump->netdev_lock);
-
     /* No other thread has access to 'dump' at this point. */
     atomic_read_relaxed(&dump->status, &dump_status);
     free(dump);
@@ -1713,13 +1653,6 @@ struct dpif_netlink_flow_dump_thread {
     struct dpif_flow_stats stats;
     struct ofpbuf nl_flows;     /* Always used to store flows. */
     struct ofpbuf *nl_actions;  /* Used if kernel does not supply actions. */
-    int netdev_dump_idx;        /* This thread current netdev dump index */
-    bool netdev_done;           /* If we are finished dumping netdevs */
-
-    /* (Key/Mask/Actions) Buffers for netdev dumping */
-    struct odputil_keybuf keybuf[FLOW_DUMP_MAX_BATCH];
-    struct odputil_keybuf maskbuf[FLOW_DUMP_MAX_BATCH];
-    struct odputil_keybuf actbuf[FLOW_DUMP_MAX_BATCH];
 };
 
 static struct dpif_netlink_flow_dump_thread *
@@ -1739,8 +1672,6 @@ dpif_netlink_flow_dump_thread_create(struct 
dpif_flow_dump *dump_)
     thread->dump = dump;
     ofpbuf_init(&thread->nl_flows, NL_DUMP_BUFSIZE);
     thread->nl_actions = NULL;
-    thread->netdev_dump_idx = 0;
-    thread->netdev_done = !(thread->netdev_dump_idx < dump->netdev_dumps_num);
 
     return &thread->up;
 }
@@ -1781,39 +1712,6 @@ dpif_netlink_flow_to_dpif_flow(struct dpif_flow 
*dpif_flow,
     dpif_flow->attrs.dp_extra_info = NULL;
 }
 
-/* The design is such that all threads are working together on the first dump
- * to the last, in order (at first they all on dump 0).
- * When the first thread finds that the given dump is finished,
- * they all move to the next. If two or more threads find the same dump
- * is finished at the same time, the first one will advance the shared
- * netdev_current_dump and the others will catch up. */
-static void
-dpif_netlink_advance_netdev_dump(struct dpif_netlink_flow_dump_thread *thread)
-{
-    struct dpif_netlink_flow_dump *dump = thread->dump;
-
-    ovs_mutex_lock(&dump->netdev_lock);
-    /* if we haven't finished (dumped everything) */
-    if (dump->netdev_current_dump < dump->netdev_dumps_num) {
-        /* if we are the first to find that current dump is finished
-         * advance it. */
-        if (thread->netdev_dump_idx == dump->netdev_current_dump) {
-            thread->netdev_dump_idx = ++dump->netdev_current_dump;
-            /* did we just finish the last dump? done. */
-            if (dump->netdev_current_dump == dump->netdev_dumps_num) {
-                thread->netdev_done = true;
-            }
-        } else {
-            /* otherwise, we are behind, catch up */
-            thread->netdev_dump_idx = dump->netdev_current_dump;
-        }
-    } else {
-        /* some other thread finished */
-        thread->netdev_done = true;
-    }
-    ovs_mutex_unlock(&dump->netdev_lock);
-}
-
 static int
 dpif_netlink_netdev_match_to_dpif_flow(struct match *match,
                                        struct ofpbuf *key_buf,
@@ -1882,56 +1780,11 @@ dpif_netlink_flow_dump_next(struct 
dpif_flow_dump_thread *thread_,
         = dpif_netlink_flow_dump_thread_cast(thread_);
     struct dpif_netlink_flow_dump *dump = thread->dump;
     struct dpif_netlink *dpif = dpif_netlink_cast(thread->up.dump->dpif);
-    int n_flows;
+    int n_flows = 0;
 
     ofpbuf_delete(thread->nl_actions);
     thread->nl_actions = NULL;
 
-    n_flows = 0;
-    max_flows = MIN(max_flows, FLOW_DUMP_MAX_BATCH);
-
-    while (!thread->netdev_done && n_flows < max_flows) {
-        struct odputil_keybuf *maskbuf = &thread->maskbuf[n_flows];
-        struct odputil_keybuf *keybuf = &thread->keybuf[n_flows];
-        struct odputil_keybuf *actbuf = &thread->actbuf[n_flows];
-        struct ofpbuf key, mask, act;
-        struct dpif_flow *f = &flows[n_flows];
-        int cur = thread->netdev_dump_idx;
-        struct netdev_flow_dump *netdev_dump = dump->netdev_dumps[cur];
-        struct match match;
-        struct nlattr *actions;
-        struct dpif_flow_stats stats;
-        struct dpif_flow_attrs attrs;
-        ovs_u128 ufid;
-        bool has_next;
-
-        ofpbuf_use_stack(&key, keybuf, sizeof *keybuf);
-        ofpbuf_use_stack(&act, actbuf, sizeof *actbuf);
-        ofpbuf_use_stack(&mask, maskbuf, sizeof *maskbuf);
-        has_next = netdev_flow_dump_next(netdev_dump, &match,
-                                        &actions, &stats, &attrs,
-                                        &ufid,
-                                        &thread->nl_flows,
-                                        &act);
-        if (has_next) {
-            dpif_netlink_netdev_match_to_dpif_flow(&match,
-                                                   &key, &mask,
-                                                   actions,
-                                                   &stats,
-                                                   &attrs,
-                                                   &ufid,
-                                                   f,
-                                                   dump->up.terse);
-            n_flows++;
-        } else {
-            dpif_netlink_advance_netdev_dump(thread);
-        }
-    }
-
-    if (!(dump->types.ovs_flows)) {
-        return n_flows;
-    }
-
     while (!n_flows
            || (n_flows < max_flows && thread->nl_flows.size)) {
         struct dpif_netlink_flow datapath_flow;
diff --git a/lib/dpif-offload-tc.c b/lib/dpif-offload-tc.c
index c74bfb52e..e2e18b5b1 100644
--- a/lib/dpif-offload-tc.c
+++ b/lib/dpif-offload-tc.c
@@ -48,7 +48,7 @@ struct dpif_offload_tc_flow_dump {
     struct ovs_mutex netdev_dump_mutex;
     size_t netdev_dump_index;
     size_t netdev_dump_count;
-    struct netdev_flow_dump *netdev_dumps[];
+    struct netdev_tc_flow_dump *netdev_dumps[];
 };
 
 #define FLOW_DUMP_MAX_BATCH 50
@@ -333,7 +333,7 @@ dpif_offload_tc_flow_dump_create(const struct dpif_offload 
*offload_,
     port_count = dpif_offload_port_mgr_port_count(offload->port_mgr);
 
     dump = xmalloc(sizeof *dump +
-                   (port_count * sizeof(struct netdev_flow_dump)));
+                   (port_count * sizeof(struct netdev_tc_flow_dump)));
 
     dpif_offload_flow_dump_init(&dump->dump, offload_, terse);
 
@@ -458,8 +458,8 @@ dpif_offload_tc_flow_dump_next(struct 
dpif_offload_flow_dump_thread *thread_,
         struct odputil_keybuf *maskbuf = &thread->maskbuf[n_flows];
         struct odputil_keybuf *keybuf = &thread->keybuf[n_flows];
         struct odputil_keybuf *actbuf = &thread->actbuf[n_flows];
+        struct netdev_tc_flow_dump *netdev_dump;
         struct dpif_flow *f = &flows[n_flows];
-        struct netdev_flow_dump *netdev_dump;
         int cur = thread->netdev_dump_index;
         struct ofpbuf key, mask, act;
         struct dpif_flow_stats stats;
@@ -505,7 +505,7 @@ dpif_offload_tc_flow_dump_destroy(struct 
dpif_offload_flow_dump *dump_)
 
     dump = dpif_offload_tc_flow_dump_cast(dump_);
     for (int i = 0; i < dump->netdev_dump_count; i++) {
-        struct netdev_flow_dump *dump_netdev = dump->netdev_dumps[i];
+        struct netdev_tc_flow_dump *dump_netdev = dump->netdev_dumps[i];
         int rc = netdev_offload_tc_flow_dump_destroy(dump_netdev);
 
         if (rc && !error) {
diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h
index f762af19a..6af97a723 100644
--- a/lib/netdev-offload-provider.h
+++ b/lib/netdev-offload-provider.h
@@ -31,29 +31,6 @@ extern "C" {
 struct netdev_flow_api {
     char *type;
 
-    /* Flow dumping interface.
-     *
-     * This is the back-end for the flow dumping interface described in
-     * dpif.h.  Please read the comments there first, because this code
-     * closely follows it.
-     *
-     * On success returns 0 and allocates data, on failure returns
-     * positive errno. */
-    int (*flow_dump_create)(struct netdev *, struct netdev_flow_dump **dump,
-                            bool terse);
-    int (*flow_dump_destroy)(struct netdev_flow_dump *);
-
-    /* Returns true if there are more flows to dump.
-     * 'rbuffer' is used as a temporary buffer and needs to be pre allocated
-     * by the caller.  While there are more flows the same 'rbuffer'
-     * should be provided. 'wbuffer' is used to store dumped actions and needs
-     * to be pre allocated by the caller. */
-    bool (*flow_dump_next)(struct netdev_flow_dump *, struct match *,
-                           struct nlattr **actions,
-                           struct dpif_flow_stats *stats,
-                           struct dpif_flow_attrs *attrs, ovs_u128 *ufid,
-                           struct ofpbuf *rbuffer, struct ofpbuf *wbuffer);
-
     /* Offload the given flow on netdev.
      * To modify a flow, use the same ufid.
      * 'actions' are in netlink format, as with struct dpif_flow_put.
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index 44518b3c1..ced017e98 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -501,7 +501,7 @@ static int
 get_chains_from_netdev(struct netdev *netdev, struct tcf_id *id,
                        struct hmap *map)
 {
-    struct netdev_flow_dump *dump;
+    struct netdev_tc_flow_dump *dump;
     struct chain_node *chain_node;
     struct ofpbuf rbuffer, reply;
     uint32_t chain;
@@ -588,11 +588,11 @@ netdev_offload_tc_flow_flush(struct netdev *netdev)
 
 int
 netdev_offload_tc_flow_dump_create(struct netdev *netdev,
-                                   struct netdev_flow_dump **dump_out,
+                                   struct netdev_tc_flow_dump **dump_out,
                                    bool terse)
 {
     enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev);
-    struct netdev_flow_dump *dump;
+    struct netdev_tc_flow_dump *dump;
     uint32_t block_id = 0;
     struct tcf_id id;
     int prio = 0;
@@ -619,7 +619,7 @@ netdev_offload_tc_flow_dump_create(struct netdev *netdev,
     return 0;
 }
 int
-netdev_offload_tc_flow_dump_destroy(struct netdev_flow_dump *dump)
+netdev_offload_tc_flow_dump_destroy(struct netdev_tc_flow_dump *dump)
 {
     nl_dump_done(dump->nl_dump);
     netdev_close(dump->netdev);
@@ -1351,7 +1351,7 @@ parse_tc_flower_to_match(const struct netdev *netdev,
 }
 
 bool
-netdev_offload_tc_flow_dump_next(struct netdev_flow_dump *dump,
+netdev_offload_tc_flow_dump_next(struct netdev_tc_flow_dump *dump,
                                  struct match *match,
                                  struct nlattr **actions,
                                  struct dpif_flow_stats *stats,
@@ -3070,7 +3070,7 @@ tc_get_policer_action_ids(struct hmap *map)
 {
     uint32_t police_idx[TCA_ACT_MAX_PRIO];
     struct policer_node *policer_node;
-    struct netdev_flow_dump *dump;
+    struct netdev_tc_flow_dump *dump;
     struct ofpbuf rbuffer, reply;
     size_t hash;
     int i, err;
diff --git a/lib/netdev-offload-tc.h b/lib/netdev-offload-tc.h
index d628e42ba..e4740c799 100644
--- a/lib/netdev-offload-tc.h
+++ b/lib/netdev-offload-tc.h
@@ -21,13 +21,22 @@
 struct dpif_offload;
 struct netdev;
 
+/* Per Netdev flow dump structure. */
+struct netdev_tc_flow_dump {
+    struct nl_dump *nl_dump;
+    struct netdev *netdev;
+    odp_port_t port;
+    bool terse;
+};
+
 /* Netdev-specific offload functions.  These should only be used by the
  * associated dpif offload provider. */
 int netdev_offload_tc_flow_flush(struct netdev *);
 int netdev_offload_tc_flow_dump_create(struct netdev *,
-                                       struct netdev_flow_dump **, bool terse);
-int netdev_offload_tc_flow_dump_destroy(struct netdev_flow_dump *);
-bool netdev_offload_tc_flow_dump_next(struct netdev_flow_dump *,
+                                       struct netdev_tc_flow_dump **,
+                                       bool terse);
+int netdev_offload_tc_flow_dump_destroy(struct netdev_tc_flow_dump *);
+bool netdev_offload_tc_flow_dump_next(struct netdev_tc_flow_dump *,
                                       struct match *, struct nlattr **actions,
                                       struct dpif_flow_stats *,
                                       struct dpif_flow_attrs *, ovs_u128 *ufid,
diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c
index bdc50da5d..3fec58b4f 100644
--- a/lib/netdev-offload.c
+++ b/lib/netdev-offload.c
@@ -200,44 +200,6 @@ netdev_assign_flow_api(struct netdev *netdev)
     return -1;
 }
 
-int
-netdev_flow_dump_create(struct netdev *netdev, struct netdev_flow_dump **dump,
-                        bool terse)
-{
-    const struct netdev_flow_api *flow_api =
-        ovsrcu_get(const struct netdev_flow_api *, &netdev->flow_api);
-
-    return (flow_api && flow_api->flow_dump_create)
-           ? flow_api->flow_dump_create(netdev, dump, terse)
-           : EOPNOTSUPP;
-}
-
-int
-netdev_flow_dump_destroy(struct netdev_flow_dump *dump)
-{
-    const struct netdev_flow_api *flow_api =
-        ovsrcu_get(const struct netdev_flow_api *, &dump->netdev->flow_api);
-
-    return (flow_api && flow_api->flow_dump_destroy)
-           ? flow_api->flow_dump_destroy(dump)
-           : EOPNOTSUPP;
-}
-
-bool
-netdev_flow_dump_next(struct netdev_flow_dump *dump, struct match *match,
-                      struct nlattr **actions, struct dpif_flow_stats *stats,
-                      struct dpif_flow_attrs *attrs, ovs_u128 *ufid,
-                      struct ofpbuf *rbuffer, struct ofpbuf *wbuffer)
-{
-    const struct netdev_flow_api *flow_api =
-        ovsrcu_get(const struct netdev_flow_api *, &dump->netdev->flow_api);
-
-    return (flow_api && flow_api->flow_dump_next)
-           ? flow_api->flow_dump_next(dump, match, actions, stats, attrs,
-                                      ufid, rbuffer, wbuffer)
-           : false;
-}
-
 int
 netdev_flow_put(struct netdev *netdev, struct match *match,
                 struct nlattr *actions, size_t act_len,
@@ -497,45 +459,6 @@ netdev_ports_traverse(const char *dpif_type,
     ovs_rwlock_unlock(&port_to_netdev_rwlock);
 }
 
-struct netdev_flow_dump **
-netdev_ports_flow_dump_create(const char *dpif_type, int *ports, bool terse)
-{
-    struct netdev_flow_dump **dumps = NULL;
-    struct port_to_netdev_data *data;
-    int count = 0;
-    int i = 0;
-
-    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
-    HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
-        if (netdev_get_dpif_type(data->netdev) == dpif_type) {
-            count++;
-        }
-    }
-
-    if (!count) {
-        goto unlock;
-    }
-
-    dumps = xzalloc(sizeof *dumps * count);
-
-    HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
-        if (netdev_get_dpif_type(data->netdev) == dpif_type) {
-            if (netdev_flow_dump_create(data->netdev, &dumps[i], terse)) {
-                continue;
-            }
-
-            dumps[i]->port = data->dpif_port.port_no;
-            i++;
-        }
-    }
-
-unlock:
-    ovs_rwlock_unlock(&port_to_netdev_rwlock);
-
-    *ports = i;
-    return dumps;
-}
-
 int
 netdev_ports_flow_del(const char *dpif_type, const ovs_u128 *ufid,
                       struct dpif_flow_stats *stats)
diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h
index 111de378b..39d11904e 100644
--- a/lib/netdev-offload.h
+++ b/lib/netdev-offload.h
@@ -59,13 +59,6 @@ enum hw_info_type {
     HW_INFO_TYPE_OFFL_COUNT = 3                /* Offloaded flow count */
 };
 
-struct netdev_flow_dump {
-    struct netdev *netdev;
-    odp_port_t port;
-    bool terse;
-    struct nl_dump *nl_dump;
-};
-
 /* Flow offloading. */
 struct offload_info {
     bool recirc_id_shared_with_tc;  /* Indicates whever tc chains will be in
@@ -100,13 +93,6 @@ netdev_offload_thread_id(void)
     return id;
 }
 
-int netdev_flow_dump_create(struct netdev *, struct netdev_flow_dump **dump,
-                            bool terse);
-int netdev_flow_dump_destroy(struct netdev_flow_dump *);
-bool netdev_flow_dump_next(struct netdev_flow_dump *, struct match *,
-                          struct nlattr **actions, struct dpif_flow_stats *,
-                          struct dpif_flow_attrs *, ovs_u128 *ufid,
-                          struct ofpbuf *rbuffer, struct ofpbuf *wbuffer);
 int netdev_flow_put(struct netdev *, struct match *, struct nlattr *actions,
                     size_t actions_len, const ovs_u128 *,
                     struct offload_info *, struct dpif_flow_stats *);
@@ -137,10 +123,6 @@ odp_port_t netdev_ifindex_to_odp_port(int ifindex);
 void netdev_ports_traverse(const char *dpif_type,
                            bool (*cb)(struct netdev *, odp_port_t, void *),
                            void *aux);
-struct netdev_flow_dump **netdev_ports_flow_dump_create(
-                                        const char *dpif_type,
-                                        int *ports,
-                                        bool terse);
 int netdev_ports_flow_del(const char *dpif_type, const ovs_u128 *ufid,
                           struct dpif_flow_stats *stats);
 int netdev_ports_flow_get(const char *dpif_type, struct match *match,
-- 
2.50.1

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to