Relocate the tc flow dump functionality from netdev-offload
to dpif-offload, centralizing flow dump handling in the
dpif-offload layer.

Signed-off-by: Eelco Chaudron <echau...@redhat.com>
---
 lib/dpif-offload-provider.h |   3 +
 lib/dpif-offload-tc.c       | 248 ++++++++++++++++++++++++++++++++++--
 lib/dpif-offload.c          |   6 +
 lib/netdev-offload-tc.c     |  34 +++--
 lib/netdev-offload-tc.h     |  11 +-
 5 files changed, 268 insertions(+), 34 deletions(-)

diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
index 8d4d8eaaf..cce815ae2 100644
--- a/lib/dpif-offload-provider.h
+++ b/lib/dpif-offload-provider.h
@@ -275,6 +275,7 @@ bool dpif_offload_port_mgr_add(struct dpif_offload_port_mgr 
*,
 struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_remove(
     struct dpif_offload_port_mgr *, odp_port_t, bool keep_netdev_ref);
 void dpif_offload_port_mgr_uninit(struct dpif_offload_port_mgr *);
+size_t dpif_offload_port_mgr_port_count(struct dpif_offload_port_mgr *);
 struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_find_by_ifindex(
     struct dpif_offload_port_mgr *, int ifindex);
 struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_find_by_netdev(
@@ -286,6 +287,8 @@ void dpif_offload_port_mgr_traverse_ports(
     bool (*cb)(struct dpif_offload_port_mgr_port *, void *),
     void *aux);
 
+#define DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH(PORT, PORT_MGR) \
+    CMAP_FOR_EACH (PORT, odp_port_node, &(PORT_MGR)->odp_port_to_port)
 
 /* Global functions, called by the dpif layer or offload providers. */
 void dp_offload_initialize(void);
diff --git a/lib/dpif-offload-tc.c b/lib/dpif-offload-tc.c
index a0e6194a9..c74bfb52e 100644
--- a/lib/dpif-offload-tc.c
+++ b/lib/dpif-offload-tc.c
@@ -19,13 +19,16 @@
 
 #include "dpif-offload.h"
 #include "dpif-offload-provider.h"
+#include "netdev-offload.h"
 #include "netdev-offload-tc.h"
 #include "netdev-provider.h"
 #include "netdev-vport.h"
+#include "odp-util.h"
 #include "util.h"
 #include "tc.h"
 
 #include "openvswitch/json.h"
+#include "openvswitch/match.h"
 #include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(dpif_offload_tc);
@@ -39,6 +42,30 @@ struct dpif_offload_tc {
     struct ovsthread_once once_enable; /* Track first-time enablement. */
 };
 
+/* tc's flow dump specific data structures. */
+struct dpif_offload_tc_flow_dump {
+    struct dpif_offload_flow_dump dump;
+    struct ovs_mutex netdev_dump_mutex;
+    size_t netdev_dump_index;
+    size_t netdev_dump_count;
+    struct netdev_flow_dump *netdev_dumps[];
+};
+
+#define FLOW_DUMP_MAX_BATCH 50
+
+struct dpif_offload_tc_flow_dump_thread {
+    struct dpif_offload_flow_dump_thread thread;
+    struct dpif_offload_tc_flow_dump *dump;
+    bool netdev_dump_done;
+    size_t netdev_dump_index;
+
+    /* (Flows/Key/Mask/Actions) Buffers for netdev dumping */
+    struct ofpbuf nl_flows;
+    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_offload_tc *
 dpif_offload_tc_cast(const struct dpif_offload *offload)
 {
@@ -279,46 +306,239 @@ dpif_offload_tc_flow_flush(const struct dpif_offload 
*offload)
     return err;
 }
 
+static struct dpif_offload_tc_flow_dump *
+dpif_offload_tc_flow_dump_cast(struct dpif_offload_flow_dump *dump)
+{
+    return CONTAINER_OF(dump, struct dpif_offload_tc_flow_dump, dump);
+}
+
+static struct dpif_offload_tc_flow_dump_thread *
+dpif_offload_tc_flow_dump_thread_cast(
+    struct dpif_offload_flow_dump_thread *thread)
+{
+    return CONTAINER_OF(thread, struct dpif_offload_tc_flow_dump_thread,
+                        thread);
+}
+
 static struct dpif_offload_flow_dump *
-dpif_offload_tc_flow_dump_create(const struct dpif_offload *offload,
+dpif_offload_tc_flow_dump_create(const struct dpif_offload *offload_,
                                  bool terse)
 {
-    struct dpif_offload_flow_dump *dump;
+    struct dpif_offload_tc *offload = dpif_offload_tc_cast(offload_);
+    struct dpif_offload_port_mgr_port *port;
+    struct dpif_offload_tc_flow_dump *dump;
+    size_t added_port_count = 0;
+    size_t port_count;
+
+    port_count = dpif_offload_port_mgr_port_count(offload->port_mgr);
+
+    dump = xmalloc(sizeof *dump +
+                   (port_count * sizeof(struct netdev_flow_dump)));
 
-    dump = xmalloc(sizeof *dump);
-    dpif_offload_flow_dump_init(dump, offload, terse);
-    return dump;
+    dpif_offload_flow_dump_init(&dump->dump, offload_, terse);
+
+    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
+        if (added_port_count >= port_count) {
+            break;
+        }
+        if (netdev_offload_tc_flow_dump_create(
+            port->netdev, &dump->netdev_dumps[added_port_count], terse)) {
+            continue;
+        }
+        dump->netdev_dumps[added_port_count]->port = port->port_no;
+        added_port_count++;
+    }
+    dump->netdev_dump_count = added_port_count;
+    dump->netdev_dump_index = 0;
+    ovs_mutex_init(&dump->netdev_dump_mutex);
+    return &dump->dump;
 }
 
 static int
-dpif_offload_tc_flow_dump_next(struct dpif_offload_flow_dump_thread *thread,
-                               struct dpif_flow *flows, int max_flows)
+dpif_offload_tc_netdev_match_to_dpif_flow(struct match *match,
+                                          struct ofpbuf *key_buf,
+                                          struct ofpbuf *mask_buf,
+                                          struct nlattr *actions,
+                                          struct dpif_flow_stats *stats,
+                                          struct dpif_flow_attrs *attrs,
+                                          ovs_u128 *ufid,
+                                          struct dpif_flow *flow,
+                                          bool terse)
 {
-    ovs_assert(thread && flows && max_flows);
+    memset(flow, 0, sizeof *flow);
+
+    if (!terse) {
+        struct odp_flow_key_parms odp_parms = {
+            .flow = &match->flow,
+            .mask = &match->wc.masks,
+            .support = {
+                .max_vlan_headers = 2,
+                .recirc = true,
+                .ct_state = true,
+                .ct_zone = true,
+                .ct_mark = true,
+                .ct_label = true,
+            },
+        };
+        size_t offset;
+
+        /* Key */
+        offset = key_buf->size;
+        flow->key = ofpbuf_tail(key_buf);
+        odp_flow_key_from_flow(&odp_parms, key_buf);
+        flow->key_len = key_buf->size - offset;
+
+        /* Mask */
+        offset = mask_buf->size;
+        flow->mask = ofpbuf_tail(mask_buf);
+        odp_parms.key_buf = key_buf;
+        odp_flow_key_from_mask(&odp_parms, mask_buf);
+        flow->mask_len = mask_buf->size - offset;
+
+        /* Actions */
+        flow->actions = nl_attr_get(actions);
+        flow->actions_len = nl_attr_get_size(actions);
+    }
+
+    /* Stats */
+    memcpy(&flow->stats, stats, sizeof *stats);
+
+    /* UFID */
+    flow->ufid_present = true;
+    flow->ufid = *ufid;
+
+    flow->pmd_id = PMD_ID_NULL;
+
+    memcpy(&flow->attrs, attrs, sizeof *attrs);
+
     return 0;
 }
 
+static void
+dpif_offload_tc_advance_provider_dump(
+    struct dpif_offload_tc_flow_dump_thread *thread)
+{
+    struct dpif_offload_tc_flow_dump *dump = thread->dump;
+
+    ovs_mutex_lock(&dump->netdev_dump_mutex);
+
+    /* If we haven't finished (dumped all providers). */
+    if (dump->netdev_dump_index < dump->netdev_dump_count) {
+        /* If we are the first to find that current dump is finished
+         * advance it. */
+        if (thread->netdev_dump_index == dump->netdev_dump_index) {
+            thread->netdev_dump_index = ++dump->netdev_dump_index;
+            /* Did we just finish the last dump? If so we are done. */
+            if (dump->netdev_dump_index == dump->netdev_dump_count) {
+                thread->netdev_dump_done = true;
+            }
+        } else {
+            /* Otherwise, we are behind, catch up. */
+            thread->netdev_dump_index = dump->netdev_dump_index;
+        }
+    } else {
+        /* Some other thread finished. */
+        thread->netdev_dump_done = true;
+    }
+
+    ovs_mutex_unlock(&dump->netdev_dump_mutex);
+}
+
 static int
-dpif_offload_tc_flow_dump_destroy(struct dpif_offload_flow_dump *dump)
+dpif_offload_tc_flow_dump_next(struct dpif_offload_flow_dump_thread *thread_,
+                               struct dpif_flow *flows, int max_flows)
 {
+    struct dpif_offload_tc_flow_dump_thread *thread;
+    int n_flows = 0;
+
+    thread = dpif_offload_tc_flow_dump_thread_cast(thread_);
+    max_flows = MIN(max_flows, FLOW_DUMP_MAX_BATCH);
+
+    while (!thread->netdev_dump_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 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;
+        struct dpif_flow_attrs attrs;
+        struct nlattr *actions;
+        struct match match;
+        ovs_u128 ufid;
+        bool has_next;
+
+        netdev_dump = thread->dump->netdev_dumps[cur];
+        ofpbuf_use_stack(&key, keybuf, sizeof *keybuf);
+        ofpbuf_use_stack(&act, actbuf, sizeof *actbuf);
+        ofpbuf_use_stack(&mask, maskbuf, sizeof *maskbuf);
+        has_next = netdev_offload_tc_flow_dump_next(netdev_dump, &match,
+                                                    &actions, &stats, &attrs,
+                                                    &ufid,
+                                                    &thread->nl_flows,
+                                                    &act);
+
+        if (has_next) {
+            dpif_offload_tc_netdev_match_to_dpif_flow(&match,
+                                                      &key, &mask,
+                                                      actions,
+                                                      &stats,
+                                                      &attrs,
+                                                      &ufid,
+                                                      f,
+                                                      thread->dump->dump.terse
+                                                    );
+            n_flows++;
+        } else {
+            dpif_offload_tc_advance_provider_dump(thread);
+        }
+    }
+    return n_flows;
+}
+
+static int
+dpif_offload_tc_flow_dump_destroy(struct dpif_offload_flow_dump *dump_)
+{
+    struct dpif_offload_tc_flow_dump *dump;
+    int error = 0;
+
+    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];
+        int rc = netdev_offload_tc_flow_dump_destroy(dump_netdev);
+
+        if (rc && !error) {
+            error = rc;
+        }
+    }
+    ovs_mutex_init(&dump->netdev_dump_mutex);
     free(dump);
-    return 0;
+    return error;
 }
 
 static struct dpif_offload_flow_dump_thread *
 dpif_offload_tc_flow_dump_thread_create(struct dpif_offload_flow_dump *dump)
 {
-    struct dpif_offload_flow_dump_thread *thread;
+    struct dpif_offload_tc_flow_dump_thread *thread;
 
     thread = xmalloc(sizeof *thread);
-    dpif_offload_flow_dump_thread_init(thread, dump);
-    return thread;
+    dpif_offload_flow_dump_thread_init(&thread->thread, dump);
+    thread->dump = dpif_offload_tc_flow_dump_cast(dump);
+    thread->netdev_dump_index = 0;
+    thread->netdev_dump_done = !thread->dump->netdev_dump_count;
+    ofpbuf_init(&thread->nl_flows, NL_DUMP_BUFSIZE);
+    return &thread->thread;
 }
 
 static void
 dpif_offload_tc_flow_dump_thread_destroy(
-    struct dpif_offload_flow_dump_thread *thread)
+    struct dpif_offload_flow_dump_thread *thread_)
 {
+    struct dpif_offload_tc_flow_dump_thread *thread;
+
+    thread = dpif_offload_tc_flow_dump_thread_cast(thread_);
+    ofpbuf_uninit(&thread->nl_flows);
     free(thread);
 }
 
diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
index 22f5d665c..2060d08fb 100644
--- a/lib/dpif-offload.c
+++ b/lib/dpif-offload.c
@@ -1220,3 +1220,9 @@ dpif_offload_port_mgr_traverse_ports(
         }
     }
 }
+
+size_t
+dpif_offload_port_mgr_port_count(struct dpif_offload_port_mgr *mgr)
+{
+    return cmap_count(&mgr->odp_port_to_port);
+}
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index 214414e45..44518b3c1 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -586,10 +586,10 @@ netdev_offload_tc_flow_flush(struct netdev *netdev)
     return 0;
 }
 
-static int
-netdev_tc_flow_dump_create(struct netdev *netdev,
-                           struct netdev_flow_dump **dump_out,
-                           bool terse)
+int
+netdev_offload_tc_flow_dump_create(struct netdev *netdev,
+                                   struct netdev_flow_dump **dump_out,
+                                   bool terse)
 {
     enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev);
     struct netdev_flow_dump *dump;
@@ -618,9 +618,8 @@ netdev_tc_flow_dump_create(struct netdev *netdev,
 
     return 0;
 }
-
-static int
-netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump)
+int
+netdev_offload_tc_flow_dump_destroy(struct netdev_flow_dump *dump)
 {
     nl_dump_done(dump->nl_dump);
     netdev_close(dump->netdev);
@@ -1351,15 +1350,15 @@ parse_tc_flower_to_match(const struct netdev *netdev,
     return 0;
 }
 
-static bool
-netdev_tc_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)
+bool
+netdev_offload_tc_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)
 {
     struct netdev *netdev = dump->netdev;
     struct ofpbuf nl_flow;
@@ -3465,9 +3464,6 @@ dpif_offload_tc_meter_del(const struct dpif_offload 
*offload OVS_UNUSED,
 
 const struct netdev_flow_api netdev_offload_tc = {
    .type = "linux_tc",
-   .flow_dump_create = netdev_tc_flow_dump_create,
-   .flow_dump_destroy = netdev_tc_flow_dump_destroy,
-   .flow_dump_next = netdev_tc_flow_dump_next,
    .flow_put = netdev_tc_flow_put,
    .flow_get = netdev_tc_flow_get,
    .flow_del = netdev_tc_flow_del,
diff --git a/lib/netdev-offload-tc.h b/lib/netdev-offload-tc.h
index 60a890643..d628e42ba 100644
--- a/lib/netdev-offload-tc.h
+++ b/lib/netdev-offload-tc.h
@@ -24,6 +24,15 @@ struct netdev;
 /* 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 match *, struct nlattr **actions,
+                                      struct dpif_flow_stats *,
+                                      struct dpif_flow_attrs *, ovs_u128 *ufid,
+                                      struct ofpbuf *rbuffer,
+                                      struct ofpbuf *wbuffer);
 void dpif_offload_tc_meter_init(void);
 int dpif_offload_tc_meter_set(const struct dpif_offload *, ofproto_meter_id,
                               struct ofputil_meter_config *);
@@ -33,4 +42,4 @@ int dpif_offload_tc_meter_del(const struct dpif_offload *, 
ofproto_meter_id,
                               struct ofputil_meter_stats *);
 uint64_t dpif_offload_tc_flow_get_n_offloaded(const struct dpif_offload *);
 
-#endif /* NETDEV_OFFLOAD_TC_H */
\ No newline at end of file
+#endif /* NETDEV_OFFLOAD_TC_H */
-- 
2.50.1

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

Reply via email to