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