Eelco Chaudron via dev <[email protected]> writes:

> 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 <[email protected]>
> ---
>
> v2 changes:
>   - Use ovs_mutex_destroy() instead of ovs_mutex_init() in
>     dpif_offload_tc_flow_dump_destroy().
> ---
>  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     |   9 ++
>  5 files changed, 267 insertions(+), 33 deletions(-)
>
> diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
> index 2c761c13e..8840441c0 100644
> --- a/lib/dpif-offload-provider.h
> +++ b/lib/dpif-offload-provider.h
> @@ -281,6 +281,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(
> @@ -292,6 +293,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)

Since you're spinning another version, I think this might be better
added in

  [07/40] dpif-offload: Add port registration and management APIs.

At least because it can be used as the FOR construct in
`dpif_offload_port_mgr_traverse_ports`

>  /* 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 781fc53c6..94f3573cc 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 "tc.h"
>  #include "util.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)
>  {
> @@ -284,46 +311,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_destroy(&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 df7bf5082..51a250a73 100644
> --- a/lib/dpif-offload.c
> +++ b/lib/dpif-offload.c
> @@ -1242,3 +1242,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 af9a10356..289dbbf72 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;
> @@ -3442,9 +3441,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 5002ab00b..ba06737ef 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 *);

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to