On 2/2/26 11:50 AM, Eelco Chaudron wrote:
> Move port manager instances from provider-specific data structures
> into the common struct dpif_offload. This removes duplication across
> providers and clarifies ownership of port-related state.
> 
> With the port manager owned by dpif_offload, offload providers are
> required to use the common port management APIs. This simplifies
> external port management and eliminates the need for provider-specific
> port enumeration logic.
> 
> The port dump functions were also simplified using the
> CMAP_CURSOR_FOR_EACH_CONTINUE() API.
> 
> Signed-off-by: Eelco Chaudron <[email protected]>
> ---
> 
> v2: Addresses Ilya's comments.
> v3: Rebase to latest upstream.
> ---
>  lib/dpif-offload-dpdk-netdev.c |   5 +-
>  lib/dpif-offload-dpdk.c        | 107 ++++-------
>  lib/dpif-offload-dummy.c       |  94 +++-------
>  lib/dpif-offload-provider.h    |  70 ++-----
>  lib/dpif-offload-tc-netdev.c   |   5 +-
>  lib/dpif-offload-tc.c          | 114 ++++--------
>  lib/dpif-offload.c             | 331 ++++++++++++++-------------------
>  lib/dpif-offload.h             |  32 +---
>  8 files changed, 261 insertions(+), 497 deletions(-)
> 
> diff --git a/lib/dpif-offload-dpdk-netdev.c b/lib/dpif-offload-dpdk-netdev.c
> index d61365ed76..efe99065e4 100644
> --- a/lib/dpif-offload-dpdk-netdev.c
> +++ b/lib/dpif-offload-dpdk-netdev.c
> @@ -2788,8 +2788,9 @@ dpdk_netdev_flow_del(struct dpdk_offload *offload, 
> struct netdev *netdev,
>      return dpdk_flow_destroy(offload, rte_flow_data, false, false);
>  }
>  
> -int dpdk_netdev_offload_init(struct netdev *netdev,
> -                             unsigned int offload_thread_count)
> +int
> +dpdk_netdev_offload_init(struct netdev *netdev,
> +                         unsigned int offload_thread_count)
>  {
>      int ret = EOPNOTSUPP;
>  
> diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c
> index 5b58f3be00..2991c24bbd 100644
> --- a/lib/dpif-offload-dpdk.c
> +++ b/lib/dpif-offload-dpdk.c
> @@ -93,7 +93,6 @@ struct dpdk_offload_thread_item {
>  /* dpif offload interface for the dpdk rte_flow implementation. */
>  struct dpdk_offload {
>      struct dpif_offload offload;
> -    struct dpif_offload_port_mgr *port_mgr;
>  
>      atomic_count next_offload_thread_id;
>      atomic_bool offload_thread_shutdown;
> @@ -565,9 +564,9 @@ dpdk_offload_traverse_ports(const struct dpdk_offload 
> *offload,
>                              bool (*cb)(struct netdev *, odp_port_t, void *),
>                              void *aux)
>  {
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, &offload->offload) {
>          if (cb(port->netdev, port->port_no, aux)) {
>              break;
>          }
> @@ -576,7 +575,7 @@ dpdk_offload_traverse_ports(const struct dpdk_offload 
> *offload,
>  
>  static int
>  dpdk_offload_enable(struct dpif_offload *offload_,
> -                    struct dpif_offload_port_mgr_port *port)
> +                    struct dpif_offload_port *port)
>  {
>      struct dpdk_offload *offload = dpdk_offload_cast(offload_);
>      struct netdev *netdev = port->netdev;
> @@ -588,7 +587,7 @@ dpdk_offload_enable(struct dpif_offload *offload_,
>  
>  static int
>  dpdk_offload_cleanup(struct dpif_offload *offload_ OVS_UNUSED,
> -                     struct dpif_offload_port_mgr_port *port)
> +                     struct dpif_offload_port *port)
>  {
>      struct netdev *netdev = port->netdev;
>  
> @@ -598,16 +597,14 @@ dpdk_offload_cleanup(struct dpif_offload *offload_ 
> OVS_UNUSED,
>  }
>  
>  static int
> -dpdk_offload_port_add(struct dpif_offload *offload_, struct netdev *netdev,
> +dpdk_offload_port_add(struct dpif_offload *offload, struct netdev *netdev,
>                        odp_port_t port_no)
>  {
> -    struct dpif_offload_port_mgr_port *port = xmalloc(sizeof *port);
> -    struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> +    struct dpif_offload_port *port = xmalloc(sizeof *port);
>  
> -    if (dpif_offload_port_mgr_add(offload->port_mgr, port, netdev,
> -                                  port_no, false)) {
> +    if (dpif_offload_port_mgr_add(offload, port, netdev, port_no, false)) {
>          if (dpif_offload_enabled()) {
> -            return dpdk_offload_enable(offload_, port);
> +            return dpdk_offload_enable(offload, port);
>          }
>          return 0;
>      }
> @@ -617,7 +614,7 @@ dpdk_offload_port_add(struct dpif_offload *offload_, 
> struct netdev *netdev,
>  }
>  
>  static void
> -dpdk_offload_free_port(struct dpif_offload_port_mgr_port *port)
> +dpdk_offload_free_port(struct dpif_offload_port *port)
>  {
>      netdev_close(port->netdev);
>      free(port);
> @@ -627,10 +624,10 @@ static int
>  dpdk_offload_port_del(struct dpif_offload *offload_, odp_port_t port_no)
>  {
>      struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>      int ret = 0;
>  
> -    port = dpif_offload_port_mgr_find_by_odp_port(offload->port_mgr, 
> port_no);
> +    port = dpif_offload_port_mgr_find_by_odp_port(offload_, port_no);
>  
>      if (dpif_offload_enabled() && port) {
>          /* If hardware offload is enabled, we first need to flush (complete)
> @@ -640,7 +637,7 @@ dpdk_offload_port_del(struct dpif_offload *offload_, 
> odp_port_t port_no)
>          dpdk_offload_flush(offload, port->netdev);
>      }
>  
> -    port = dpif_offload_port_mgr_remove(offload->port_mgr, port_no);
> +    port = dpif_offload_port_mgr_remove(offload_, port_no);
>      if (port) {
>          if (dpif_offload_enabled()) {
>              ret = dpdk_offload_cleanup(offload_, port);
> @@ -650,40 +647,13 @@ dpdk_offload_port_del(struct dpif_offload *offload_, 
> odp_port_t port_no)
>      return ret;
>  }
>  
> -static int
> -dpdk_offload_port_dump_start(const struct dpif_offload *offload_,
> -                             void **statep)
> -{
> -    struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_start(offload->port_mgr, statep);
> -}
> -
> -static int
> -dpdk_offload_port_dump_next(const struct dpif_offload *offload_, void *state,
> -                            struct dpif_offload_port *port)
> -{
> -    struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_next(offload->port_mgr, state,
> -                                                port);
> -}
> -
> -static int
> -dpdk_offload_port_dump_done(const struct dpif_offload *offload_, void *state)
> -{
> -    struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_done(offload->port_mgr, state);
> -}
> -
> -struct netdev *
> -dpdk_offload_get_netdev(const struct dpdk_offload *offload, odp_port_t 
> port_no)
> +static struct netdev *
> +dpdk_offload_get_netdev__(const struct dpif_offload *offload,
> +                          odp_port_t port_no)
>  {
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    port = dpif_offload_port_mgr_find_by_odp_port(offload->port_mgr,
> -                                                  port_no);
> +    port = dpif_offload_port_mgr_find_by_odp_port(offload, port_no);
>      if (!port) {
>          return NULL;
>      }
> @@ -691,12 +661,10 @@ dpdk_offload_get_netdev(const struct dpdk_offload 
> *offload, odp_port_t port_no)
>      return port->netdev;
>  }
>  
> -static struct netdev *
> -dpdk_offload_get_netdev__(struct dpif_offload *offload_, odp_port_t port_no)
> +struct netdev *
> +dpdk_offload_get_netdev(const struct dpdk_offload *offload, odp_port_t 
> port_no)
>  {
> -    struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> -
> -    return dpdk_offload_get_netdev(offload, port_no);
> +    return dpdk_offload_get_netdev__(&offload->offload, port_no);
>  }
>  
>  static int
> @@ -706,7 +674,6 @@ dpdk_offload_open(const struct dpif_offload_class 
> *offload_class,
>      struct dpdk_offload *offload = xmalloc(sizeof *offload);
>  
>      dpif_offload_init(&offload->offload, offload_class, dpif);
> -    offload->port_mgr = dpif_offload_port_mgr_init();
>      offload->once_enable = (struct ovsthread_once) 
> OVSTHREAD_ONCE_INITIALIZER;
>      offload->offload_thread_count = DEFAULT_OFFLOAD_THREAD_COUNT;
>      offload->offload_threads = NULL;
> @@ -723,9 +690,9 @@ static void
>  dpdk_offload_close(struct dpif_offload *offload_)
>  {
>      struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, offload_) {
>          dpdk_offload_port_del(offload_, port->port_no);
>      }
>  
> @@ -738,13 +705,12 @@ dpdk_offload_close(struct dpif_offload *offload_)
>          free(offload->offload_threads);
>      }
>  
> -    dpif_offload_port_mgr_uninit(offload->port_mgr);
> -
>      if (offload->flow_mark_pool) {
>          id_fpool_destroy(offload->flow_mark_pool);
>      }
>  
>      ovsthread_once_destroy(&offload->once_enable);
> +    dpif_offload_destroy(offload_);
>      free(offload);
>  }
>  
> @@ -756,7 +722,7 @@ dpdk_offload_set_config(struct dpif_offload *offload_,
>  
>      if (smap_get_bool(other_cfg, "hw-offload", false)) {
>          if (ovsthread_once_start(&offload->once_enable)) {
> -            struct dpif_offload_port_mgr_port *port;
> +            struct dpif_offload_port *port;
>  
>              unsigned int offload_thread_count = smap_get_uint(
>                  other_cfg, "n-offload-threads", 
> DEFAULT_OFFLOAD_THREAD_COUNT);
> @@ -774,7 +740,7 @@ dpdk_offload_set_config(struct dpif_offload *offload_,
>              offload->offload_thread_count = offload_thread_count;
>  
>              dpdk_offload_threads_init(offload);
> -            DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +            DPIF_OFFLOAD_PORT_FOR_EACH (port, offload_) {
>                  dpdk_offload_enable(offload_, port);
>              }
>  
> @@ -784,16 +750,14 @@ dpdk_offload_set_config(struct dpif_offload *offload_,
>  }
>  
>  static void
> -dpdk_offload_get_debug(const struct dpif_offload *offload_, struct ds *ds,
> +dpdk_offload_get_debug(const struct dpif_offload *offload, struct ds *ds,
>                         struct json *json)
>  {
> -    struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> -
>      if (json) {
>          struct json *json_ports = json_object_create();
> -        struct dpif_offload_port_mgr_port *port;
> +        struct dpif_offload_port *port;
>  
> -        DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +        DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
>              struct json *json_port = json_object_create();
>  
>              json_object_put(json_port, "port_no",
> @@ -809,9 +773,9 @@ dpdk_offload_get_debug(const struct dpif_offload 
> *offload_, struct ds *ds,
>              json_destroy(json_ports);
>          }
>      } else if (ds) {
> -        struct dpif_offload_port_mgr_port *port;
> +        struct dpif_offload_port *port;
>  
> -        DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +        DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
>              ds_put_format(ds, "  - %s: port_no: %u\n",
>                            netdev_get_name(port->netdev), port->port_no);
>          }
> @@ -836,14 +800,14 @@ static uint64_t
>  dpdk_flow_count(const struct dpif_offload *offload_)
>  {
>      struct dpdk_offload *offload = dpdk_offload_cast(offload_);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>      uint64_t total = 0;
>  
>      if (!dpif_offload_enabled()) {
>          return 0;
>      }
>  
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, offload_) {
>          total += dpdk_netdev_flow_count(port->netdev,
>                                          offload->offload_thread_count);
>      }
> @@ -854,14 +818,14 @@ dpdk_flow_count(const struct dpif_offload *offload_)
>  static uint64_t
>  dpdk_flow_count_by_thread(struct dpdk_offload *offload, unsigned int tid)
>  {
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>      uint64_t total = 0;
>  
>      if (!dpif_offload_enabled()) {
>          return 0;
>      }
>  
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, &offload->offload) {
>          total += dpdk_netdev_flow_count_by_thread(port->netdev, tid);
>      }
>  
> @@ -1077,9 +1041,6 @@ struct dpif_offload_class dpif_offload_dpdk_class = {
>      .can_offload = dpdk_can_offload,
>      .port_add = dpdk_offload_port_add,
>      .port_del = dpdk_offload_port_del,
> -    .port_dump_start = dpdk_offload_port_dump_start,
> -    .port_dump_next = dpdk_offload_port_dump_next,
> -    .port_dump_done = dpdk_offload_port_dump_done,
>      .flow_count = dpdk_flow_count,
>      .get_netdev = dpdk_offload_get_netdev__,
>      .netdev_hw_post_process = dpdk_offload_hw_post_process,
> diff --git a/lib/dpif-offload-dummy.c b/lib/dpif-offload-dummy.c
> index c2d5b9675b..b7b24d6064 100644
> --- a/lib/dpif-offload-dummy.c
> +++ b/lib/dpif-offload-dummy.c
> @@ -51,7 +51,6 @@ struct dummy_offloaded_flow {
>  
>  struct dummy_offload {
>      struct dpif_offload offload;
> -    struct dpif_offload_port_mgr *port_mgr;
>      struct id_fpool *flow_mark_pool;
>      dpif_offload_flow_unreference_cb *unreference_cb;
>  
> @@ -60,7 +59,7 @@ struct dummy_offload {
>  };
>  
>  struct dummy_offload_port {
> -    struct dpif_offload_port_mgr_port pm_port;
> +    struct dpif_offload_port pm_port;
>  
>      struct ovs_mutex port_mutex; /* Protect all below members. */
>      struct hmap offloaded_flows OVS_GUARDED;
> @@ -97,7 +96,7 @@ dummy_free_flow_mark(struct dummy_offload *offload, 
> uint32_t flow_mark)
>  }
>  
>  static struct dummy_offload_port *
> -dummy_offload_port_cast(struct dpif_offload_port_mgr_port *port)
> +dummy_offload_port_cast(struct dpif_offload_port *port)
>  {
>      return CONTAINER_OF(port, struct dummy_offload_port, pm_port);
>  }
> @@ -271,7 +270,7 @@ dummy_find_offloaded_flow_and_update(struct 
> dummy_offload_port *port,
>  
>  static void
>  dummy_offload_enable(struct dpif_offload *dpif_offload,
> -                     struct dpif_offload_port_mgr_port *port)
> +                     struct dpif_offload_port *port)
>  {
>      atomic_store_relaxed(&port->netdev->hw_info.post_process_api_supported,
>                           true);
> @@ -279,7 +278,7 @@ dummy_offload_enable(struct dpif_offload *dpif_offload,
>  }
>  
>  static void
> -dummy_offload_cleanup(struct dpif_offload_port_mgr_port *port)
> +dummy_offload_cleanup(struct dpif_offload_port *port)
>  {
>      dpif_offload_set_netdev_offload(port->netdev, NULL);
>  }
> @@ -338,8 +337,8 @@ dummy_offload_port_add(struct dpif_offload *dpif_offload,
>      hmap_init(&port->offloaded_flows);
>      ovs_mutex_unlock(&port->port_mutex);
>  
> -    if (dpif_offload_port_mgr_add(offload->port_mgr, &port->pm_port,
> -                                  netdev, port_no, false)) {
> +    if (dpif_offload_port_mgr_add(dpif_offload, &port->pm_port, netdev,
> +                                  port_no, false)) {
>  
>          if (dpif_offload_enabled()) {
>              dummy_offload_enable(dpif_offload, &port->pm_port);
> @@ -355,9 +354,9 @@ static int
>  dummy_offload_port_del(struct dpif_offload *dpif_offload, odp_port_t port_no)
>  {
>      struct dummy_offload *offload = dummy_offload_cast(dpif_offload);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    port = dpif_offload_port_mgr_remove(offload->port_mgr, port_no);
> +    port = dpif_offload_port_mgr_remove(dpif_offload, port_no);
>      if (port) {
>          struct dummy_offload_port *dummy_port;
>  
> @@ -370,40 +369,13 @@ dummy_offload_port_del(struct dpif_offload 
> *dpif_offload, odp_port_t port_no)
>      return 0;
>  }
>  
> -static int
> -dummy_offload_port_dump_start(const struct dpif_offload *offload_,
> -                              void **statep)
> -{
> -    struct dummy_offload *offload = dummy_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_start(offload->port_mgr, statep);
> -}
> -
> -static int
> -dummy_offload_port_dump_next(const struct dpif_offload *offload_, void 
> *state,
> -                             struct dpif_offload_port *port)
> -{
> -    struct dummy_offload *offload = dummy_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_next(offload->port_mgr, state,
> -                                                port);
> -}
> -
> -static int
> -dummy_offload_port_dump_done(const struct dpif_offload *offload_, void 
> *state)
> -{
> -    struct dummy_offload *offload = dummy_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_done(offload->port_mgr, state);
> -}
> -
>  static struct netdev *
> -dummy_offload_get_netdev(struct dpif_offload *dpif_offload, odp_port_t 
> port_no)
> +dummy_offload_get_netdev(const struct dpif_offload *dpif_offload,
> +                         odp_port_t port_no)
>  {
> -    struct dummy_offload *offload = dummy_offload_cast(dpif_offload);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    port = dpif_offload_port_mgr_find_by_odp_port(offload->port_mgr, 
> port_no);
> +    port = dpif_offload_port_mgr_find_by_odp_port(dpif_offload, port_no);
>      if (!port) {
>          return NULL;
>      }
> @@ -420,7 +392,6 @@ dummy_offload_open(const struct dpif_offload_class 
> *offload_class,
>      offload = xmalloc(sizeof *offload);
>  
>      dpif_offload_init(&offload->offload, offload_class, dpif);
> -    offload->port_mgr = dpif_offload_port_mgr_init();
>      offload->once_enable = (struct ovsthread_once) 
> OVSTHREAD_ONCE_INITIALIZER;
>      offload->flow_mark_pool = NULL;
>      offload->unreference_cb = NULL;
> @@ -433,19 +404,19 @@ static void
>  dummy_offload_close(struct dpif_offload *dpif_offload)
>  {
>      struct dummy_offload *offload = dummy_offload_cast(dpif_offload);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
>      /* The ofproto layer may not call dpif_port_del() for all ports,
>       * especially internal ones, so we need to clean up any remaining ports. 
> */
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, dpif_offload) {
>          dummy_offload_port_del(dpif_offload, port->port_no);
>      }
>  
> -    dpif_offload_port_mgr_uninit(offload->port_mgr);
>      if (offload->flow_mark_pool) {
>          id_fpool_destroy(offload->flow_mark_pool);
>      }
>      ovsthread_once_destroy(&offload->once_enable);
> +    dpif_offload_destroy(dpif_offload);
>      free(offload);
>  }
>  
> @@ -457,9 +428,9 @@ dummy_offload_set_config(struct dpif_offload 
> *dpif_offload,
>  
>      if (smap_get_bool(other_cfg, "hw-offload", false)) {
>          if (ovsthread_once_start(&offload->once_enable)) {
> -            struct dpif_offload_port_mgr_port *port;
> +            struct dpif_offload_port *port;
>  
> -            DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +            DPIF_OFFLOAD_PORT_FOR_EACH (port, dpif_offload) {
>                  dummy_offload_enable(dpif_offload, port);
>              }
>  
> @@ -469,16 +440,14 @@ dummy_offload_set_config(struct dpif_offload 
> *dpif_offload,
>  }
>  
>  static void
> -dummy_offload_get_debug(const struct dpif_offload *offload_, struct ds *ds,
> +dummy_offload_get_debug(const struct dpif_offload *offload, struct ds *ds,
>                          struct json *json)
>  {
> -    struct dummy_offload *offload = dummy_offload_cast(offload_);
> -
>      if (json) {
>          struct json *json_ports = json_object_create();
> -        struct dpif_offload_port_mgr_port *port;
> +        struct dpif_offload_port *port;
>  
> -        DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +        DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
>              struct json *json_port = json_object_create();
>  
>              json_object_put(json_port, "port_no",
> @@ -494,9 +463,9 @@ dummy_offload_get_debug(const struct dpif_offload 
> *offload_, struct ds *ds,
>              json_destroy(json_ports);
>          }
>      } else if (ds) {
> -        struct dpif_offload_port_mgr_port *port;
> +        struct dpif_offload_port *port;
>  
> -        DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +        DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
>              ds_put_format(ds, "  - %s: port_no: %u\n",
>                            netdev_get_name(port->netdev), port->port_no);
>          }
> @@ -504,17 +473,14 @@ dummy_offload_get_debug(const struct dpif_offload 
> *offload_, struct ds *ds,
>  }
>  
>  static int
> -dummy_offload_get_global_stats(const struct dpif_offload *offload_,
> +dummy_offload_get_global_stats(const struct dpif_offload *offload,
>                                 struct netdev_custom_stats *stats)
>  {
> -    struct dummy_offload *offload = dummy_offload_cast(offload_);
> -
>      /* Add a single counter telling how many ports we are servicing. */
> -    stats->label = xstrdup(dpif_offload_name(offload_));
> +    stats->label = xstrdup(dpif_offload_name(offload));
>      stats->size = 1;
>      stats->counters = xmalloc(sizeof(struct netdev_custom_counter) * 1);
> -    stats->counters[0].value = dpif_offload_port_mgr_port_count(
> -        offload->port_mgr);
> +    stats->counters[0].value = dpif_offload_port_mgr_port_count(offload);
>      ovs_strzcpy(stats->counters[0].name, "Offloaded port count",
>                  sizeof stats->counters[0].name);
>  
> @@ -537,13 +503,12 @@ dummy_offload_log_operation(const char *op, int error, 
> const ovs_u128 *ufid)
>  }
>  
>  static struct dummy_offload_port *
> -dummy_offload_get_port_by_netdev(const struct dpif_offload *offload_,
> +dummy_offload_get_port_by_netdev(const struct dpif_offload *offload,
>                                   struct netdev *netdev)
>  {
> -    struct dummy_offload *offload = dummy_offload_cast(offload_);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    port = dpif_offload_port_mgr_find_by_netdev(offload->port_mgr, netdev);
> +    port = dpif_offload_port_mgr_find_by_netdev(offload, netdev);
>      if (!port) {
>          return NULL;
>      }
> @@ -832,9 +797,6 @@ dummy_netdev_simulate_offload(struct netdev *netdev, 
> struct dp_packet *packet,
>          .can_offload = dummy_can_offload,                                   \
>          .port_add = dummy_offload_port_add,                                 \
>          .port_del = dummy_offload_port_del,                                 \
> -        .port_dump_start = dummy_offload_port_dump_start,                   \
> -        .port_dump_next = dummy_offload_port_dump_next,                     \
> -        .port_dump_done = dummy_offload_port_dump_done,                     \
>          .get_netdev = dummy_offload_get_netdev,                             \
>          .netdev_hw_post_process = dummy_offload_hw_post_process,            \
>          .netdev_flow_put = dummy_flow_put,                                  \
> diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
> index 44e55f27c7..02ef46cb08 100644
> --- a/lib/dpif-offload-provider.h
> +++ b/lib/dpif-offload-provider.h
> @@ -56,6 +56,7 @@ struct dpif_offload_provider_collection {
>  struct dpif_offload {
>      const struct dpif_offload_class *class;
>      struct ovs_list dpif_list_node;
> +    struct dpif_offload_port_mgr *ports;
>      char *name;
>  };
>  
> @@ -162,30 +163,6 @@ struct dpif_offload_class {
>      void (*port_set_config)(struct dpif_offload *, odp_port_t port_no,
>                              const struct smap *cfg);
>  
> -    /* Attempts to begin dumping the ports in a dpif_offload.  On success,
> -     * returns 0 and initializes '*statep' with any data needed for 
> iteration.
> -     * On failure, returns a positive errno value. */
> -    int (*port_dump_start)(const struct dpif_offload *, void **statep);
> -
> -    /* Attempts to retrieve another port from 'dpif_offload' for 'state', 
> which
> -     * was initialized by a successful call to the 'port_dump_start' function
> -     * for 'dpif_offload'.  On success, stores a new dpif_offload_port into
> -     * 'port' and returns 0.  Returns EOF if the end of the port table has 
> been
> -     * reached, or a positive errno value on error.  This function will not 
> be
> -     * called again once it returns nonzero once for a given iteration (but
> -     * the 'port_dump_done' function will be called afterward).
> -     *
> -     * The dpif provider retains ownership of the data stored in 'port'.  It
> -     * must remain valid until at least the next call to 'port_dump_next' or
> -     * 'port_dump_done' for 'state'. */
> -    int (*port_dump_next)(const struct dpif_offload *, void *state,
> -                          struct dpif_offload_port *);
> -
> -    /* Releases resources from 'dpif_offload' for 'state', which was
> -     * initialized by a successful call to the 'port_dump_start' function for
> -     * 'dpif_offload'. */
> -    int (*port_dump_done)(const struct dpif_offload *dpif, void *state);
> -
>      /* Deletes all offloaded flows for this offload_provider.  Return 0 if
>       * successful, otherwise returns a positive errno value. */
>      int (*flow_flush)(const struct dpif_offload *);
> @@ -274,8 +251,8 @@ struct dpif_offload_class {
>       * NOT incremented.  Callers needing to hold a reference must call
>       * netdev_ref() on the returned netdev.  Returns NULL if port_no is
>       * not found. */
> -    struct netdev *(*get_netdev)(struct dpif_offload *, odp_port_t port_no);
> -
> +    struct netdev *(*get_netdev)(const struct dpif_offload *,
> +                                 odp_port_t port_no);
>  
>      /* These APIs operate directly on the provided netdev for performance
>       * reasons.  They are intended for use in fast path processing and should
> @@ -336,7 +313,7 @@ extern struct dpif_offload_class dpif_offload_dpdk_class;
>  extern struct dpif_offload_class dpif_offload_tc_class;
>  
>  
> -/* Structure used by the common dpif port management library functions. */
> +/* Structures used by the common dpif port management library functions. */
>  struct dpif_offload_port_mgr {
>      struct ovs_mutex cmap_mod_lock;
>  
> @@ -345,7 +322,7 @@ struct dpif_offload_port_mgr {
>      struct cmap ifindex_to_port;
>  };
>  
> -struct dpif_offload_port_mgr_port {
> +struct dpif_offload_port {
>      struct cmap_node odp_port_node;
>      struct cmap_node netdev_node;
>      struct cmap_node ifindex_node;
> @@ -357,30 +334,23 @@ struct dpif_offload_port_mgr_port {
>  
>  /* Global dpif port management library functions. */
>  struct dpif_offload_port_mgr *dpif_offload_port_mgr_init(void);
> -bool dpif_offload_port_mgr_add(struct dpif_offload_port_mgr *,
> -                               struct dpif_offload_port_mgr_port *,
> +void dpif_offload_port_mgr_destroy(struct dpif_offload *);
> +bool dpif_offload_port_mgr_add(struct dpif_offload *,
> +                               struct dpif_offload_port *,
>                                 struct netdev *netdev, odp_port_t,
>                                 bool need_ifindex);
> -struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_remove(
> -    struct dpif_offload_port_mgr *, odp_port_t);
> -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(
> -    struct dpif_offload_port_mgr *, struct netdev *);
> -struct dpif_offload_port_mgr_port *dpif_offload_port_mgr_find_by_odp_port(
> -    struct dpif_offload_port_mgr *, odp_port_t);
> -int dpif_offload_port_mgr_port_dump_start(struct dpif_offload_port_mgr *,
> -                                          void **statep);
> -int dpif_offload_port_mgr_port_dump_next(struct dpif_offload_port_mgr *,
> -                                         void *state,
> -                                         struct dpif_offload_port *);
> -int dpif_offload_port_mgr_port_dump_done(struct dpif_offload_port_mgr *,
> -                                         void *state);
> -
> -#define DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH(PORT, PORT_MGR) \
> -    CMAP_FOR_EACH (PORT, odp_port_node, &(PORT_MGR)->odp_port_to_port)
> +struct dpif_offload_port *dpif_offload_port_mgr_remove(struct dpif_offload *,
> +                                                       odp_port_t);
> +size_t dpif_offload_port_mgr_port_count(const struct dpif_offload *);
> +struct dpif_offload_port *dpif_offload_port_mgr_find_by_ifindex(
> +    const struct dpif_offload *, int ifindex);
> +struct dpif_offload_port *dpif_offload_port_mgr_find_by_netdev(
> +    const struct dpif_offload *, struct netdev *);
> +struct dpif_offload_port *dpif_offload_port_mgr_find_by_odp_port(
> +    const struct dpif_offload *, odp_port_t);
> +
> +#define DPIF_OFFLOAD_PORT_FOR_EACH(PORT, OFFLOAD) \
> +    CMAP_FOR_EACH (PORT, odp_port_node, &(OFFLOAD)->ports->odp_port_to_port)
>  
>  /* Global functions, called by the dpif layer or offload providers. */
>  void dpif_offload_module_init(void);
> diff --git a/lib/dpif-offload-tc-netdev.c b/lib/dpif-offload-tc-netdev.c
> index 11a72118a3..a2f4ab8b5d 100644
> --- a/lib/dpif-offload-tc-netdev.c
> +++ b/lib/dpif-offload-tc-netdev.c
> @@ -668,8 +668,9 @@ parse_flower_rewrite_to_netlink_action(struct ofpbuf *buf,
>      }
>  }
>  
> -static void parse_tc_flower_geneve_opts(struct tc_action *action,
> -                                        struct ofpbuf *buf)
> +static void
> +parse_tc_flower_geneve_opts(struct tc_action *action,
> +                            struct ofpbuf *buf)
>  {
>      int tun_opt_len = action->encap.data.present.len;
>      size_t geneve_off;
> diff --git a/lib/dpif-offload-tc.c b/lib/dpif-offload-tc.c
> index fca106584a..3b84d9f20f 100644
> --- a/lib/dpif-offload-tc.c
> +++ b/lib/dpif-offload-tc.c
> @@ -35,7 +35,6 @@ VLOG_DEFINE_THIS_MODULE(dpif_offload_tc);
>  /* dpif offload interface for the tc implementation. */
>  struct tc_offload {
>      struct dpif_offload offload;
> -    struct dpif_offload_port_mgr *port_mgr;
>  
>      /* Configuration specific variables. */
>      struct ovsthread_once once_enable; /* Track first-time enablement. */
> @@ -75,7 +74,7 @@ tc_offload_cast(const struct dpif_offload *offload)
>  
>  static int
>  tc_offload_enable(struct dpif_offload *dpif_offload,
> -                  struct dpif_offload_port_mgr_port *port)
> +                  struct dpif_offload_port *port)
>  {
>      int ret = tc_netdev_init(port->netdev);
>  
> @@ -91,7 +90,7 @@ tc_offload_enable(struct dpif_offload *dpif_offload,
>  
>  static int
>  tc_offload_cleanup(struct dpif_offload *dpif_offload OVS_UNUSED,
> -                   struct dpif_offload_port_mgr_port *port)
> +                   struct dpif_offload_port *port)
>  {
>      dpif_offload_set_netdev_offload(port->netdev, NULL);
>      return 0;
> @@ -101,11 +100,9 @@ static int
>  tc_port_add(struct dpif_offload *dpif_offload, struct netdev *netdev,
>              odp_port_t port_no)
>  {
> -    struct dpif_offload_port_mgr_port *port = xmalloc(sizeof *port);
> -    struct tc_offload *offload = tc_offload_cast(dpif_offload);
> +    struct dpif_offload_port *port = xmalloc(sizeof *port);
>  
> -    if (dpif_offload_port_mgr_add(offload->port_mgr, port, netdev, port_no,
> -                                  true)) {
> +    if (dpif_offload_port_mgr_add(dpif_offload, port, netdev, port_no, 
> true)) {
>          if (dpif_offload_enabled()) {
>              return tc_offload_enable(dpif_offload, port);
>          }
> @@ -117,7 +114,7 @@ tc_port_add(struct dpif_offload *dpif_offload, struct 
> netdev *netdev,
>  }
>  
>  static void
> -tc_free_port(struct dpif_offload_port_mgr_port *port)
> +tc_free_port(struct dpif_offload_port *port)
>  {
>      netdev_close(port->netdev);
>      free(port);
> @@ -126,11 +123,10 @@ tc_free_port(struct dpif_offload_port_mgr_port *port)
>  static int
>  tc_port_del(struct dpif_offload *dpif_offload, odp_port_t port_no)
>  {
> -    struct tc_offload *offload = tc_offload_cast(dpif_offload);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>      int ret = 0;
>  
> -    port = dpif_offload_port_mgr_remove(offload->port_mgr, port_no);
> +    port = dpif_offload_port_mgr_remove(dpif_offload, port_no);
>      if (port) {
>          if (dpif_offload_enabled()) {
>              ret = tc_offload_cleanup(dpif_offload, port);
> @@ -140,39 +136,12 @@ tc_port_del(struct dpif_offload *dpif_offload, 
> odp_port_t port_no)
>      return ret;
>  }
>  
> -static int
> -tc_port_dump_start(const struct dpif_offload *offload_, void **statep)
> -{
> -    struct tc_offload *offload = tc_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_start(offload->port_mgr, statep);
> -}
> -
> -static int
> -tc_port_dump_next(const struct dpif_offload *offload_, void *state,
> -                  struct dpif_offload_port *port)
> -{
> -    struct tc_offload *offload = tc_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_next(offload->port_mgr, state,
> -                                                port);
> -}
> -
> -static int
> -tc_port_dump_done(const struct dpif_offload *offload_, void *state)
> -{
> -    struct tc_offload *offload = tc_offload_cast(offload_);
> -
> -    return dpif_offload_port_mgr_port_dump_done(offload->port_mgr, state);
> -}
> -
>  static struct netdev *
> -tc_get_netdev(struct dpif_offload *dpif_offload, odp_port_t port_no)
> +tc_get_netdev(const struct dpif_offload *dpif_offload, odp_port_t port_no)
>  {
> -    struct tc_offload *offload = tc_offload_cast(dpif_offload);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    port = dpif_offload_port_mgr_find_by_odp_port(offload->port_mgr, 
> port_no);
> +    port = dpif_offload_port_mgr_find_by_odp_port(dpif_offload, port_no);
>      if (!port) {
>          return NULL;
>      }
> @@ -187,7 +156,6 @@ tc_offload_open(const struct dpif_offload_class 
> *offload_class,
>      struct tc_offload *offload = xmalloc(sizeof *offload);
>  
>      dpif_offload_init(&offload->offload, offload_class, dpif);
> -    offload->port_mgr = dpif_offload_port_mgr_init();
>      offload->once_enable = (struct ovsthread_once) 
> OVSTHREAD_ONCE_INITIALIZER;
>      offload->recirc_id_shared = !!(dpif_get_features(dpif)
>                                     & OVS_DP_F_TC_RECIRC_SHARING);
> @@ -205,14 +173,14 @@ static void
>  tc_offload_close(struct dpif_offload *dpif_offload)
>  {
>      struct tc_offload *offload = tc_offload_cast(dpif_offload);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, dpif_offload) {
>          tc_port_del(dpif_offload, port->port_no);
>      }
>  
> -    dpif_offload_port_mgr_uninit(offload->port_mgr);
>      ovsthread_once_destroy(&offload->once_enable);
> +    dpif_offload_destroy(dpif_offload);
>      free(offload);
>  }
>  
> @@ -224,12 +192,12 @@ tc_offload_set_config(struct dpif_offload *offload_,
>  
>      if (smap_get_bool(other_cfg, "hw-offload", false)) {
>          if (ovsthread_once_start(&offload->once_enable)) {
> -            struct dpif_offload_port_mgr_port *port;
> +            struct dpif_offload_port *port;
>  
>              tc_set_policy(smap_get_def(other_cfg, "tc-policy",
>                                         TC_POLICY_DEFAULT));
>  
> -            DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +            DPIF_OFFLOAD_PORT_FOR_EACH (port, offload_) {
>                  tc_offload_enable(offload_, port);
>              }
>  
> @@ -239,16 +207,14 @@ tc_offload_set_config(struct dpif_offload *offload_,
>  }
>  
>  static void
> -tc_offload_get_debug(const struct dpif_offload *offload_, struct ds *ds,
> +tc_offload_get_debug(const struct dpif_offload *offload, struct ds *ds,
>                       struct json *json)
>  {
> -    struct tc_offload *offload = tc_offload_cast(offload_);
> -
>      if (json) {
>          struct json *json_ports = json_object_create();
> -        struct dpif_offload_port_mgr_port *port;
> +        struct dpif_offload_port *port;
>  
> -        DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +        DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
>              struct json *json_port = json_object_create();
>  
>              json_object_put(json_port, "port_no",
> @@ -266,9 +232,9 @@ tc_offload_get_debug(const struct dpif_offload *offload_, 
> struct ds *ds,
>              json_destroy(json_ports);
>          }
>      } else if (ds) {
> -        struct dpif_offload_port_mgr_port *port;
> +        struct dpif_offload_port *port;
>  
> -        DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +        DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
>              ds_put_format(ds, "  - %s: port_no: %u, ifindex: %d\n",
>                            netdev_get_name(port->netdev),
>                            port->port_no, port->ifindex);
> @@ -290,13 +256,12 @@ tc_can_offload(struct dpif_offload *dpif_offload 
> OVS_UNUSED,
>  }
>  
>  static int
> -tc_flow_flush(const struct dpif_offload *offload_)
> +tc_flow_flush(const struct dpif_offload *offload)
>  {
> -    struct tc_offload *offload = tc_offload_cast(offload_);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>      int error = 0;
>  
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
>          int rc = tc_netdev_flow_flush(port->netdev);
>  
>          if (rc && !error) {
> @@ -320,22 +285,21 @@ tc_flow_dump_thread_cast(
>  }
>  
>  static struct dpif_offload_flow_dump *
> -tc_flow_dump_create(const struct dpif_offload *offload_, bool terse)
> +tc_flow_dump_create(const struct dpif_offload *offload, bool terse)
>  {
> -    struct tc_offload *offload = tc_offload_cast(offload_);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>      size_t added_port_count = 0;
>      struct tc_flow_dump *dump;
>      size_t port_count;
>  
> -    port_count = dpif_offload_port_mgr_port_count(offload->port_mgr);
> +    port_count = dpif_offload_port_mgr_port_count(offload);
>  
>      dump = xmalloc(sizeof *dump +
>                     (port_count * sizeof(struct netdev_tc_flow_dump)));
>  
> -    dpif_offload_flow_dump_init(&dump->dump, offload_, terse);
> +    dpif_offload_flow_dump_init(&dump->dump, offload, terse);
>  
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
>          if (added_port_count >= port_count) {
>              break;
>          }
> @@ -526,7 +490,7 @@ tc_parse_flow_put(struct tc_offload *offload_tc, struct 
> dpif *dpif,
>                    struct dpif_flow_put *put)
>  {
>      static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>      const struct nlattr *nla;
>      struct tc_offload_info info;
>      struct match match;
> @@ -548,7 +512,7 @@ tc_parse_flow_put(struct tc_offload *offload_tc, struct 
> dpif *dpif,
>      }
>  
>      in_port = match.flow.in_port.odp_port;
> -    port = dpif_offload_port_mgr_find_by_odp_port(offload_tc->port_mgr,
> +    port = dpif_offload_port_mgr_find_by_odp_port(&offload_tc->offload,
>                                                    in_port);
>      if (!port) {
>          return EOPNOTSUPP;
> @@ -557,12 +521,12 @@ tc_parse_flow_put(struct tc_offload *offload_tc, struct 
> dpif *dpif,
>      /* Check the output port for a tunnel. */
>      NL_ATTR_FOR_EACH (nla, left, put->actions, put->actions_len) {
>          if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) {
> -            struct dpif_offload_port_mgr_port *mgr_port;
> +            struct dpif_offload_port *mgr_port;
>              odp_port_t out_port;
>  
>              out_port = nl_attr_get_odp_port(nla);
>              mgr_port = dpif_offload_port_mgr_find_by_odp_port(
> -                offload_tc->port_mgr, out_port);
> +                                &offload_tc->offload, out_port);
>  
>              if (!mgr_port) {
>                  err = EOPNOTSUPP;
> @@ -650,8 +614,8 @@ out:
>  static int
>  tc_parse_flow_get(struct tc_offload *offload_tc, struct dpif_flow_get *get)
>  {
> -    struct dpif_offload_port_mgr_port *port;
>      struct dpif_flow *dpif_flow = get->flow;
> +    struct dpif_offload_port *port;
>      struct odputil_keybuf maskbuf;
>      struct odputil_keybuf keybuf;
>      struct odputil_keybuf actbuf;
> @@ -666,7 +630,7 @@ tc_parse_flow_get(struct tc_offload *offload_tc, struct 
> dpif_flow_get *get)
>  
>      ofpbuf_use_stack(&buf, &act_buf, sizeof act_buf);
>  
> -    DPIF_OFFLOAD_PORT_MGR_PORT_FOR_EACH (port, offload_tc->port_mgr) {
> +    DPIF_OFFLOAD_PORT_FOR_EACH (port, &offload_tc->offload) {
>          if (!tc_netdev_flow_get(port->netdev, &match, &actions, get->ufid,
>                                  &stats, &attrs, &buf)) {
>              err = 0;
> @@ -751,12 +715,11 @@ tc_operate(struct dpif *dpif, const struct dpif_offload 
> *offload_,
>  }
>  
>  odp_port_t
> -tc_get_port_id_by_ifindex(const struct dpif_offload *offload_, int ifindex)
> +tc_get_port_id_by_ifindex(const struct dpif_offload *offload, int ifindex)
>  {
> -    struct tc_offload *offload = tc_offload_cast(offload_);
> -    struct dpif_offload_port_mgr_port *port;
> +    struct dpif_offload_port *port;
>  
> -    port = dpif_offload_port_mgr_find_by_ifindex(offload->port_mgr, ifindex);
> +    port = dpif_offload_port_mgr_find_by_ifindex(offload, ifindex);
>      if (port) {
>          return port->port_no;
>      }
> @@ -774,9 +737,6 @@ struct dpif_offload_class dpif_offload_tc_class = {
>      .can_offload = tc_can_offload,
>      .port_add = tc_port_add,
>      .port_del = tc_port_del,
> -    .port_dump_start = tc_port_dump_start,
> -    .port_dump_next = tc_port_dump_next,
> -    .port_dump_done = tc_port_dump_done,
>      .flow_flush = tc_flow_flush,
>      .flow_dump_create = tc_flow_dump_create,
>      .flow_dump_next = tc_flow_dump_next,
> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
> index 6437bca427..e0259e1e3c 100644
> --- a/lib/dpif-offload.c
> +++ b/lib/dpif-offload.c
> @@ -159,9 +159,6 @@ dpif_offload_module_init(void)
>                     && base_dpif_offload_classes[i]->can_offload
>                     && base_dpif_offload_classes[i]->port_add
>                     && base_dpif_offload_classes[i]->port_del
> -                   && base_dpif_offload_classes[i]->port_dump_start
> -                   && base_dpif_offload_classes[i]->port_dump_next
> -                   && base_dpif_offload_classes[i]->port_dump_done
>                     && base_dpif_offload_classes[i]->get_netdev);
>  
>          ovs_assert((base_dpif_offload_classes[i]->flow_dump_create &&
> @@ -360,11 +357,8 @@ provider_collection_free_rcu(
>      /* We need to use the safe variant here as we removed the entry, and the
>       * close API will free() it. */
>      LIST_FOR_EACH_SAFE (offload_entry, dpif_list_node, &collection->list) {
> -        char *name = offload_entry->name;
> -
>          ovs_list_remove(&offload_entry->dpif_list_node);
>          offload_entry->class->close(offload_entry);
> -        free(name);
>      }
>  
>      /* Free remaining resources. */
> @@ -434,6 +428,16 @@ dpif_offload_init(struct dpif_offload *offload,
>  
>      offload->class = class;
>      offload->name = xasprintf("%s[%s]", class->type, dpif_name(dpif));
> +    offload->ports = dpif_offload_port_mgr_init();
> +}
> +
> +void
> +dpif_offload_destroy(struct dpif_offload *offload)
> +{
> +    ovs_assert(offload);
> +
> +    dpif_offload_port_mgr_destroy(offload);
> +    free(offload->name);
>  }
>  
>  const char *
> @@ -460,9 +464,9 @@ dpif_offload_get_debug(const struct dpif_offload 
> *offload, struct ds *ds,
>      return true;
>  }
>  
> -int dpif_offload_stats_get(struct dpif *dpif,
> -                           struct netdev_custom_stats **stats_,
> -                           size_t *n_stats)
> +int
> +dpif_offload_stats_get(struct dpif *dpif, struct netdev_custom_stats 
> **stats_,
> +                       size_t *n_stats)
>  {
>      struct dpif_offload_provider_collection *collection;
>      struct netdev_custom_stats *stats;
> @@ -1177,101 +1181,85 @@ dpif_offload_flow_dump_thread_destroy(struct 
> dpif_flow_dump_thread *thread)
>      free(thread->offload_threads);
>  }
>  
> -static bool
> -dpif_offload_get_next_offload_for_dump(struct dpif_offload_port_dump *dump)
> -{
> -    struct dpif_offload_provider_collection *collection;
> -    const struct dpif_offload *offload;
> -    const struct dpif_offload *prev_offload;
> -
> -    collection = dpif_get_offload_provider_collection(dump->dpif);
> -    if (!collection) {
> -        dump->offload = NULL;
> -        return false;
> -    }
> -
> -    prev_offload = dump->offload;
> -    dump->offload = NULL;
> -
> -    LIST_FOR_EACH (offload, dpif_list_node, &collection->list) {
> -        if (!prev_offload) {
> -            /* We need the first offload provider. */
> -            dump->offload = offload;
> -            break;
> -        }
> -        if (offload->dpif_list_node.next != &collection->list
> -            && prev_offload == offload) {
> -            /* This is the current offload provider, so we need the next
> -             * one if available.  If not we will exit with !dump->offload. */
> -            dump->offload = CONTAINER_OF(offload->dpif_list_node.next,
> -                                         struct dpif_offload, 
> dpif_list_node);
> -            break;
> -        }
> -    }
> -
> -    return dump->offload ? true : false;
> -}
> +struct dpif_offload_port_dump {
> +    void *offload_state;
> +    struct dpif_offload *offload;
> +    struct cmap_cursor cursor;
> +    int error;
> +};
>  
> -void
> +static void
>  dpif_offload_port_dump_start(struct dpif_offload_port_dump *dump,
>                               const struct dpif *dpif)
>  {
> +    ovs_assert(dump && dpif);
> +
>      memset(dump, 0, sizeof *dump);
> -    dump->dpif = dpif;
> -    if (!dpif_offload_get_next_offload_for_dump(dump)) {
> -        dump->error = EOF;
> +    dpif_offload_dump_start(dpif, &dump->offload_state);
> +    if (dpif_offload_dump_next(dump->offload_state, &dump->offload)) {
> +        dump->cursor = cmap_cursor_start(
> +                            &dump->offload->ports->odp_port_to_port);
>      } else {
> -        dump->error = dump->offload->class->port_dump_start(dump->offload,
> -                                                            &dump->state);
> +        dump->error = EINVAL;
>      }
>  }
>  
> -bool
> +static bool
>  dpif_offload_port_dump_next(struct dpif_offload_port_dump *dump,
> -                            struct dpif_offload_port *port)
> +                            struct dpif_offload_port **port)
>  {
> -    const struct dpif_offload *offload = dump->offload;
> +    ovs_assert(dump && port);
>  
> -    while (true) {
> +    if (dump->error || !dump->offload || !dump->offload_state) {
> +        return false;
> +    }
>  
> -        if (dump->error) {
> -            break;
> +    while (true) {
> +        CMAP_CURSOR_FOR_EACH_CONTINUE (*port, odp_port_node, &dump->cursor) {
> +            return true;
>          }
>  
> -        dump->error = offload->class->port_dump_next(offload, dump->state,
> -                                                     port);
> -        if (dump->error) {
> -            offload->class->port_dump_done(offload, dump->state);
> -
> -            if (dump->error != EOF) {
> -                /* If the error is not EOF, we stop dumping ports from all
> -                 * providers and return it. */
> -                break;
> -            }
> -
> -            if (dpif_offload_get_next_offload_for_dump(dump)) {
> -                offload = dump->offload;
> -                dump->error = offload->class->port_dump_start(offload,
> -                                                              &dump->state);
> -                continue;
> -            }
> +        if (dpif_offload_dump_next(dump->offload_state, &dump->offload)) {
> +            dump->cursor = cmap_cursor_start(
> +                                &dump->offload->ports->odp_port_to_port);
> +        } else {
> +            break;
>          }
> -        break;
> -    }
> +    };
>  
> -    return dump->error ? false : true;
> +    dump->error = EOF;
> +    return false;
>  }
>  
> -int
> +static int
>  dpif_offload_port_dump_done(struct dpif_offload_port_dump *dump)
>  {
> -    if (!dump->error && dump->offload) {
> -        dump->error = dump->offload->class->port_dump_done(dump->offload,
> -                                                           dump->state);
> +    int error;
> +
> +    ovs_assert(dump);
> +
> +    error = dpif_offload_dump_done(dump->offload_state);
> +    if (error && error != EOF) {
> +        dump->error = error;
>      }
> +
>      return dump->error == EOF ? 0 : dump->error;
>  }
>  
> +/* Iterates through each DPIF_OFFLOAD_PORT in DPIF, using DUMP as state.
> + *
> + * If you break out of the loop, then you need to free the dump structure by
> + * hand using dpif_offload_port_dump_done().
> + *
> + * IMPORTANT: You must not RCU quiesce during the FOR_EACH loop, or even
> + *            between port dump function calls if used standalone. */
> +#define DPIF_OFFLOAD_PROVIDERS_PORT_FOR_EACH(DPIF_OFFLOAD_PORT, DUMP, DPIF) \
> +    for (dpif_offload_port_dump_start(DUMP, DPIF);                          \
> +         (dpif_offload_port_dump_next(DUMP, DPIF_OFFLOAD_PORT)              \
> +          ? true                                                            \
> +          : (dpif_offload_port_dump_done(DUMP), false));                    \
> +        )

Still not sure why we need this macro and any of the dpif_offload_port_dump_*
functions...


> +
>  static struct netdev *
>  dpif_offload_get_netdev_by_port_id__(
>      struct dpif_offload_provider_collection *collection,
> @@ -1312,7 +1300,7 @@ dpif_offload_netdevs_out_of_resources(struct dpif *dpif)
>  {
>      struct dpif_offload_provider_collection *collection;
>      struct dpif_offload_port_dump dump;
> -    struct dpif_offload_port port;
> +    struct dpif_offload_port *port;
>      bool oor = false;
>  
>      collection = dpif_get_offload_provider_collection(dpif);
> @@ -1320,8 +1308,8 @@ dpif_offload_netdevs_out_of_resources(struct dpif *dpif)
>          return false;
>      }
>  
> -    DPIF_OFFLOAD_PORT_FOR_EACH (&port, &dump, dpif) {
> -        if (port.netdev->hw_info.oor) {
> +    DPIF_OFFLOAD_PROVIDERS_PORT_FOR_EACH (&port, &dump, dpif) {

Can this be just two nested loops instead?

  LIST_FOR_EACH (offload, dpif_list_node, providers_list) {
      DPIF_OFFLOAD_PORT_FOR_EACH (port, offload) {
          ...
      }
  }

Or do we have some other use case for this dpif_offload_port_dump_* interface?

Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to