On 10 Dec 2025, at 8:51, Eli Britstein wrote:

>> -----Original Message-----
>> From: dev <[email protected]> On Behalf Of Eelco Chaudron
>> Sent: Tuesday, 2 December 2025 16:05
>> To: [email protected]
>> Subject: [ovs-dev] [PATCH v2 07/41] dpif-offload: Add port registration and
>> management APIs.
>>
>> This patch introduces a common port management layer for offload providers
>> and integrates it into the dpif-offload subsystem.  Existing dummy offload
>> provider is updated to use the new APIs.
>>
>> Signed-off-by: Eelco Chaudron <[email protected]>
>> ---
>>
>> v2 changes:
>>  - Fixed indentation issues.
>>  - Added comment to dpif_offload_attach_providers().
>>  - Fix netdev reference issue in dpif_offload_port_mgr_add().
>> ---
>> lib/dpif-offload-dpdk.c     |  17 +++
>> lib/dpif-offload-dummy.c    | 152 +++++++++++++++++++-
>> lib/dpif-offload-provider.h |  75 +++++++++-
>> lib/dpif-offload-tc.c       |  20 +++
>> lib/dpif-offload.c          | 268 +++++++++++++++++++++++++++++++++++-
>> lib/dpif.c                  |  12 +-
>> lib/dummy.h                 |   3 +
>> lib/netdev-dpdk.c           |   4 +-
>> lib/netdev-dpdk.h           |   2 +-
>> lib/netdev-dummy.c          |  20 +--
>> lib/netdev-offload-dpdk.c   |   4 +-
>> lib/netdev-provider.h       |   1 +
>> 12 files changed, 553 insertions(+), 25 deletions(-)
>>
>> diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c index
>> 6ac4af8d8..76e0ba15f 100644
>> --- a/lib/dpif-offload-dpdk.c
>> +++ b/lib/dpif-offload-dpdk.c
>> @@ -18,6 +18,8 @@
>>
>> #include "dpif-offload.h"
>> #include "dpif-offload-provider.h"
>> +#include "netdev-provider.h"
>> +#include "netdev-vport.h"
>> #include "util.h"
>>
>> #include "openvswitch/vlog.h"
>> @@ -100,6 +102,20 @@ dpif_offload_dpdk_set_config(struct dpif_offload
>> *offload_,
>>     }
>> }
>>
>> +static bool
>> +dpif_offload_dpdk_can_offload(struct dpif_offload *offload OVS_UNUSED,
> I see the offload parameter is not used also at the final commit. Do we still 
> want to keep it?

It’s part of the consistent API, so other implementations might need it in the 
future.

>> +                              struct netdev *netdev) {
>> +    if (netdev_vport_is_vport_class(netdev->netdev_class)
>> +          && strcmp(netdev_get_dpif_type(netdev), "netdev")) {
> Indentation.

ACK
>> +        VLOG_DBG("%s: vport doesn't belong to the netdev datapath, 
>> skipping",
>> +                 netdev_get_name(netdev));
>> +        return false;
>> +    }
>> +
>> +    return netdev_dpdk_flow_api_supported(netdev, true); }
>> +
>> struct dpif_offload_class dpif_offload_dpdk_class = {
>>     .type = "dpdk",
>>     .supported_dpif_types = (const char *const[]) { @@ -108,6 +124,7 @@
>> struct dpif_offload_class dpif_offload_dpdk_class = {
>>     .open = dpif_offload_dpdk_open,
>>     .close = dpif_offload_dpdk_close,
>>     .set_config = dpif_offload_dpdk_set_config,
>> +    .can_offload = dpif_offload_dpdk_can_offload,
>> };
>>
>> /* XXX: Temporary functions below, which will be removed once fully diff 
>> --git
>> a/lib/dpif-offload-dummy.c b/lib/dpif-offload-dummy.c index
>> 1d7b72b00..827165ba2 100644
>> --- a/lib/dpif-offload-dummy.c
>> +++ b/lib/dpif-offload-dummy.c
>> @@ -15,27 +15,167 @@
>>  */
>>
>> #include <config.h>
>> +#include <errno.h>
>>
>> #include "dpif.h"
>> #include "dpif-offload-provider.h"
>> #include "dpif-offload.h"
>> +#include "dummy.h"
>> +#include "netdev-provider.h"
>> #include "util.h"
>>
>> +
>> +struct dpif_offload_dummy {
>> +    struct dpif_offload offload;
>> +    struct dpif_offload_port_mgr *port_mgr;
>> +
>> +    /* Configuration specific variables. */
>> +    struct ovsthread_once once_enable; /* Track first-time enablement.
>> +*/ };
>> +
>> +static struct dpif_offload_dummy *
>> +dpif_offload_dummy_cast(const struct dpif_offload *offload) {
>> +    return CONTAINER_OF(offload, struct dpif_offload_dummy, offload); }
>> +
>> +static void
>> +dpif_offload_dummy_enable_offload(struct dpif_offload *dpif_offload,
>> +                                  struct dpif_offload_port_mgr_port
>> +*port) {
>> +    dpif_offload_set_netdev_offload(port->netdev, dpif_offload); }
>> +
>> +static void
>> +dpif_offload_dummy_cleanup_offload(
>> +    struct dpif_offload *dpif_offload OVS_UNUSED,
> No need for this argument.

ACK
>> +    struct dpif_offload_port_mgr_port *port) {
>> +    dpif_offload_set_netdev_offload(port->netdev, NULL); }
>> +
>> +static int
>> +dpif_offload_dummy_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 dpif_offload_dummy *offload_dummy;
>> +
>> +    offload_dummy = dpif_offload_dummy_cast(dpif_offload);
>> +    if (dpif_offload_port_mgr_add(offload_dummy->port_mgr, port, netdev,
>> +                                  port_no, false)) {
>> +
>> +        if (dpif_offload_is_offload_enabled()) {
>> +            dpif_offload_dummy_enable_offload(dpif_offload, port);
>> +        }
>> +        return 0;
>> +    }
>> +
>> +    free(port);
>> +    return EEXIST;
>> +}
>> +
>> +static int
>> +dpif_offload_dummy_port_del(struct dpif_offload *dpif_offload,
>> +                            odp_port_t port_no) {
>> +    struct dpif_offload_dummy *offload_dummy;
>> +    struct dpif_offload_port_mgr_port *port;
>> +
>> +    offload_dummy = dpif_offload_dummy_cast(dpif_offload);
>> +
>> +    port = dpif_offload_port_mgr_remove(offload_dummy->port_mgr, port_no,
>> +                                        true);
>> +    if (port) {
>> +        if (dpif_offload_is_offload_enabled()) {
>> +            dpif_offload_dummy_cleanup_offload(dpif_offload, port);
>> +        }
>> +        netdev_close(port->netdev);
>> +        ovsrcu_postpone(free, port);
>> +    }
>> +    return 0;
>> +}
>> +
>> static int
>> dpif_offload_dummy_open(const struct dpif_offload_class *offload_class,
>>                         struct dpif *dpif, struct dpif_offload 
>> **dpif_offload)  {
>> -    struct dpif_offload *offload = xmalloc(sizeof(struct dpif_offload));
>> +    struct dpif_offload_dummy *offload_dummy;
>> +
>> +    offload_dummy = xmalloc(sizeof(struct dpif_offload_dummy));
>>
>> -    dpif_offload_init(offload, offload_class, dpif);
>> -    *dpif_offload = offload;
>> +    dpif_offload_init(&offload_dummy->offload, offload_class, dpif);
>> +    offload_dummy->port_mgr = dpif_offload_port_mgr_init();
>> +    offload_dummy->once_enable = (struct ovsthread_once)
>> +        OVSTHREAD_ONCE_INITIALIZER;
>> +
>> +    *dpif_offload = &offload_dummy->offload;
>>     return 0;
>> }
>>
>> +static bool
>> +dpif_offload_dummy_cleanup_port(struct dpif_offload_port_mgr_port *port,
>> +                                void *aux) {
>> +    struct dpif_offload *offload = aux;
>> +
>> +    dpif_offload_dummy_port_del(offload, port->port_no);
>> +    return false;
>> +}
>> +
>> static void
>> dpif_offload_dummy_close(struct dpif_offload *dpif_offload)  {
>> -    free(dpif_offload);
>> +    struct dpif_offload_dummy *offload_dummy;
>> +
>> +    offload_dummy = dpif_offload_dummy_cast(dpif_offload);
>> +
>> +    /* 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_traverse_ports(offload_dummy->port_mgr,
>> +                                         dpif_offload_dummy_cleanup_port,
>> +                                         dpif_offload);
>> +
>> +    dpif_offload_port_mgr_uninit(offload_dummy->port_mgr);
>> +    free(offload_dummy);
>> +}
>> +
>> +static bool
>> +dpif_offload_dummy_late_enable(struct dpif_offload_port_mgr_port *port,
>> +                               void *aux) {
>> +    dpif_offload_dummy_enable_offload(aux, port);
>> +    return false;
>> +}
>> +
>> +static void
>> +dpif_offload_dummy_set_config(struct dpif_offload *dpif_offload,
>> +                              const struct smap *other_cfg) {
>> +    struct dpif_offload_dummy *offload_dummy;
>> +
>> +    offload_dummy = dpif_offload_dummy_cast(dpif_offload);
>> +
>> +    /* We maintain the existing behavior where global configurations
>> +     * are only accepted when hardware offload is initially enabled.
>> +     * Once enabled, they cannot be updated or reconfigured. */
>> +    if (smap_get_bool(other_cfg, "hw-offload", false)) {
>> +        if (ovsthread_once_start(&offload_dummy->once_enable)) {
>> +
>> +            dpif_offload_port_mgr_traverse_ports(
>> +                offload_dummy->port_mgr, dpif_offload_dummy_late_enable,
>> +                dpif_offload);
>> +
>> +            ovsthread_once_done(&offload_dummy->once_enable);
>> +        }
>> +    }
>> +}
>> +
>> +static bool
>> +dpif_offload_dummy_can_offload(struct dpif_offload *dpif_offload
>> OVS_UNUSED,
>> +                               struct netdev *netdev) {
>> +    return is_dummy_netdev_class(netdev->netdev_class) ? true : false;
> No need for the ?:

ACK
>> }
>>
>> #define DEFINE_DPIF_DUMMY_CLASS(NAME, TYPE_STR)         \
>> @@ -46,6 +186,10 @@ dpif_offload_dummy_close(struct dpif_offload
>> *dpif_offload)
>>             NULL},                                      \
>>         .open = dpif_offload_dummy_open,                \
>>         .close = dpif_offload_dummy_close,              \
>> +        .set_config = dpif_offload_dummy_set_config,    \
>> +        .can_offload = dpif_offload_dummy_can_offload,  \
>> +        .port_add = dpif_offload_dummy_port_add,        \
>> +        .port_del = dpif_offload_dummy_port_del,        \
>>     }
>>
>> DEFINE_DPIF_DUMMY_CLASS(dpif_offload_dummy_class, "dummy"); diff --git
>> a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h index
>> 09a7dfc2c..496959ea3 100644
>> --- a/lib/dpif-offload-provider.h
>> +++ b/lib/dpif-offload-provider.h
>> @@ -17,6 +17,7 @@
>> #ifndef DPIF_OFFLOAD_PROVIDER_H
>> #define DPIF_OFFLOAD_PROVIDER_H
>>
>> +#include "cmap.h"
>> #include "dpif-provider.h"
>> #include "ovs-thread.h"
>> #include "smap.h"
>> @@ -76,8 +77,8 @@ struct dpif_offload_class {
>>     /* Attempts to open the offload provider for the specified dpif.
>>      * If successful, stores a pointer to the new dpif offload in
>>      * 'dpif_offload **', which must be of class 'dpif_offload_class'.
>> -     * On failure, there are no requirements for what is stored in
>> -     * 'dpif_offload **'. */
>> +     * On failure (indicated by a negative return value), there are no
>> +     * requirements for what is stored in 'dpif_offload **'. */
> This comment change can be on the first commit introduced it.

ACK will move it.

>>     int (*open)(const struct dpif_offload_class *,
>>                 struct dpif *, struct dpif_offload **);
>>
>> @@ -91,6 +92,31 @@ struct dpif_offload_class {
>>      * called. */
>>     void (*set_config)(struct dpif_offload *,
>>                        const struct smap *other_config);
>> +
>> +    /* Verifies whether the offload provider supports offloading flows for 
>> the
>> +     * given 'netdev'.  Returns 'false' if the provider lacks the 
>> capabilities
>> +     * to offload on this port, otherwise returns 'true'. */
>> +    bool (*can_offload)(struct dpif_offload *,
>> +                        struct netdev *);
>> +
>> +    /* This callback is invoked when a 'netdev' port has been successfully
>> +     * added to the dpif and should be handled by this offload provider.
>> +     * It is assumed that the `can_offload` callback was previously called
>> +     * and returned 'true' before this function is executed. */
>> +    int (*port_add)(struct dpif_offload *, struct netdev *,
>> +                    odp_port_t port_no);
>> +
>> +    /* This callback is invoked when the 'port_no' port has been 
>> successfully
>> +     * removed from the dpif.  Note that it is called for every deleted 
>> port,
>> +     * even if 'port_added' was never called, as the framework does not 
>> track
>> +     * added ports. */
>> +    int (*port_del)(struct dpif_offload *, odp_port_t port_no);
>> +
>> +    /* Refreshes the configuration of 'port_no' port.  The implementation 
>> might
>> +     * postpone applying the changes until run() is called.  The same note
>> +     * as above in 'port_deleted' applies here.*/
>> +    void (*port_set_config)(struct dpif_offload *, odp_port_t port_no,
>> +                            const struct smap *cfg);
>> };
>>
>>
>> @@ -100,9 +126,54 @@ 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.
>> +*/ struct dpif_offload_port_mgr {
>> +    struct ovs_mutex cmap_mod_lock;
>> +
>> +    struct cmap odp_port_to_port;
>> +    struct cmap netdev_to_port;
>> +    struct cmap ifindex_to_port;
>> +};
>> +
>> +struct dpif_offload_port_mgr_port {
>> +    struct cmap_node odp_port_node;
>> +    struct cmap_node netdev_node;
>> +    struct cmap_node ifindex_node;
>> +    struct netdev *netdev;
>> +    odp_port_t port_no;
>> +    int ifindex;
>> +};
>> +
>> +
>> +/* 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 *,
>> +                               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, bool keep_netdev_ref);
>> +void dpif_offload_port_mgr_uninit(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); void
>> +dpif_offload_port_mgr_traverse_ports(
>> +    struct dpif_offload_port_mgr *mgr,
>> +    bool (*cb)(struct dpif_offload_port_mgr_port *, void *),
>> +    void *aux);
>> +
>> +
>> /* Global functions, called by the dpif layer or offload providers. */  void
>> dp_offload_initialize(void);  void dpif_offload_set_config(struct dpif *, 
>> const
>> struct smap *other_cfg);
>> +void dpif_offload_port_add(struct dpif *, struct netdev *, odp_port_t);
>> +void dpif_offload_port_del(struct dpif *, odp_port_t); void
>> +dpif_offload_port_set_config(struct dpif *, odp_port_t,
>> +                                  const struct smap *cfg); void
>> +dpif_offload_set_netdev_offload(struct netdev *, struct dpif_offload
>> +*);
>>
>> static inline void dpif_offload_assert_class(
>>     const struct dpif_offload *dpif_offload, diff --git 
>> a/lib/dpif-offload-tc.c
>> b/lib/dpif-offload-tc.c index c09530daa..2c9081438 100644
>> --- a/lib/dpif-offload-tc.c
>> +++ b/lib/dpif-offload-tc.c
>> @@ -18,9 +18,15 @@
>>
>> #include "dpif-offload.h"
>> #include "dpif-offload-provider.h"
>> +#include "netdev-provider.h"
>> +#include "netdev-vport.h"
>> #include "util.h"
>> #include "tc.h"
>>
>> +#include "openvswitch/vlog.h"
>> +
>> +VLOG_DEFINE_THIS_MODULE(dpif_offload_tc);
>> +
>> /* dpif offload interface for the tc implementation. */  struct 
>> dpif_offload_tc {
>>     struct dpif_offload offload;
>> @@ -80,6 +86,19 @@ dpif_offload_tc_set_config(struct dpif_offload *offload,
>>     }
>> }
>>
>> +static bool
>> +dpif_offload_tc_can_offload(struct dpif_offload *dpif_offload OVS_UNUSED,
>> +                            struct netdev *netdev) {
>> +    if (netdev_vport_is_vport_class(netdev->netdev_class) &&
>> +        strcmp(netdev_get_dpif_type(netdev), "system")) {
>> +        VLOG_DBG("%s: vport doesn't belong to the system datapath, 
>> skipping",
>> +                 netdev_get_name(netdev));
>> +        return false;
>> +    }
>> +    return true;
>> +}
>> +
>> struct dpif_offload_class dpif_offload_tc_class = {
>>     .type = "tc",
>>     .supported_dpif_types = (const char *const[]) { @@ -88,4 +107,5 @@ struct
>> dpif_offload_class dpif_offload_tc_class = {
>>     .open = dpif_offload_tc_open,
>>     .close = dpif_offload_tc_close,
>>     .set_config = dpif_offload_tc_set_config,
>> +    .can_offload = dpif_offload_tc_can_offload,
>> };
>> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c index 
>> 4c89ae443..43258dd55
>> 100644
>> --- a/lib/dpif-offload.c
>> +++ b/lib/dpif-offload.c
>> @@ -20,6 +20,7 @@
>> #include "dpif-offload.h"
>> #include "dpif-offload-provider.h"
>> #include "dpif-provider.h"
>> +#include "netdev-provider.h"
>> #include "unixctl.h"
>> #include "util.h"
>> #include "openvswitch/dynamic-string.h"
>> @@ -149,7 +150,8 @@ dp_offload_initialize(void)
>>
>>     for (int i = 0; i < ARRAY_SIZE(base_dpif_offload_classes); i++) {
>>         ovs_assert(base_dpif_offload_classes[i]->open
>> -                   && base_dpif_offload_classes[i]->close);
>> +                   && base_dpif_offload_classes[i]->close
>> +                   && base_dpif_offload_classes[i]->can_offload);
>>
>>         dpif_offload_register_provider(base_dpif_offload_classes[i]);
>>     }
>> @@ -172,7 +174,7 @@ dpif_offload_attach_provider_to_dp_offload__(struct
>> dp_offload *dp_offload,
>>     LIST_FOR_EACH (offload_entry, dpif_list_node, providers_list) {
>>         if (offload_entry == offload || !strcmp(offload->name,
>>                                                 offload_entry->name)) {
>> -            return EEXIST;
>> +            return -EEXIST;
> ?

See new comment below.

>>         }
>>     }
>>
>> @@ -199,7 +201,7 @@ dpif_offload_attach_dp_offload(struct dpif *dpif,  {
>>     ovsrcu_set(&dpif->dp_offload, dp_offload);
>>     ovs_refcount_ref(&dp_offload->ref_cnt);
>> -    return 0;
>> +    return EEXIST;
>> }
>>
>> static int
>> @@ -293,6 +295,9 @@ dpif_offload_attach_providers_(struct dpif *dpif)
>>     return 0;
>> }
>>
>> +/* This function returns 0 if a new provider set was attached to the
>> +dpif,
>> + * returns EEXIST if an existing set of providers was attached, and
>> + * returns a negative error code on error. */
>> int
>> dpif_offload_attach_providers(struct dpif *dpif)  { @@ -414,6 +419,92 @@
>> dpif_offload_is_offload_rebalance_policy_enabled(void)
>>     return enabled;
>> }
>>
>> +void
>> +dpif_offload_set_netdev_offload(struct netdev *netdev,
>> +                                struct dpif_offload *offload) {
>> +    ovsrcu_set(&netdev->dpif_offload, offload); }
>> +
>> +void
>> +dpif_offload_port_add(struct dpif *dpif, struct netdev *netdev,
>> +                      odp_port_t port_no) {
>> +    struct dp_offload *dp_offload = dpif_offload_get_dp_offload(dpif);
>> +    struct dpif_offload *offload;
>> +
>> +    if (!dp_offload) {
>> +        return;
>> +    }
>> +
>> +    LIST_FOR_EACH (offload, dpif_list_node, &dp_offload->offload_providers) 
>> {
>> +        if (!offload->class->port_add) {
>> +            continue;
>> +        }
>> +
>> +        if (offload->class->can_offload(offload, netdev)) {
>> +            int err = offload->class->port_add(offload, netdev, port_no);
>> +            if (!err) {
>> +                VLOG_DBG("netdev %s added to dpif-offload provider %s",
>> +                         netdev_get_name(netdev), 
>> dpif_offload_name(offload));
>> +                break;
>> +            } else {
>> +                VLOG_ERR("Failed adding netdev %s to dpif-offload provider "
>> +                         "%s, error %s",
>> +                         netdev_get_name(netdev), 
>> dpif_offload_name(offload),
>> +                         ovs_strerror(err));
>> +            }
>> +        } else {
>> +            VLOG_DBG(
>> +                "netdev %s failed can_offload for dpif-offload provider %s",
>> +                netdev_get_name(netdev), dpif_offload_name(offload));
>> +        }
>> +    }
>> +}
>> +
>> +void
>> +dpif_offload_port_del(struct dpif *dpif, odp_port_t port_no) {
>> +    struct dp_offload *dp_offload = dpif_offload_get_dp_offload(dpif);
>> +    struct dpif_offload *offload;
>> +
>> +    if (!dp_offload) {
>> +        return;
>> +    }
>> +
>> +    LIST_FOR_EACH (offload, dpif_list_node, &dp_offload->offload_providers) 
>> {
>> +        int err;
>> +
>> +        if (!offload->class->port_del) {
>> +            continue;
>> +        }
>> +
>> +        err = offload->class->port_del(offload, port_no);
>> +        if (err) {
>> +            VLOG_ERR("Failed deleting port_no %d from dpif-offload provider 
>> "
>> +                     "%s, error %s", port_no, dpif_offload_name(offload),
>> +                     ovs_strerror(err));
>> +        }
>> +    }
>> +}
>> +
>> +void
>> +dpif_offload_port_set_config(struct dpif *dpif, odp_port_t port_no,
>> +                             const struct smap *cfg) {
>> +    struct dp_offload *dp_offload = dpif_offload_get_dp_offload(dpif);
>> +    struct dpif_offload *offload;
>> +
>> +    if (!dp_offload) {
>> +        return;
>> +    }
>> +    LIST_FOR_EACH (offload, dpif_list_node, &dp_offload->offload_providers) 
>> {
>> +        if (offload->class->port_set_config) {
>> +            offload->class->port_set_config(offload, port_no, cfg);
>> +        }
>> +    }
>> +}
>> +
>> void
>> dpif_offload_dump_start(struct dpif_offload_dump *dump,
>>                         const struct dpif *dpif) @@ -547,3 +638,174 @@
>> dpif_offload_set_global_cfg(const struct smap *other_cfg)
>>         }
>>     }
>> }
>> +
>> +
>>
>>
>> +struct dpif_offload_port_mgr *
>> +dpif_offload_port_mgr_init(void)
>> +{
>> +    struct dpif_offload_port_mgr *mgr = xmalloc(sizeof *mgr);
>> +
>> +    ovs_mutex_init(&mgr->cmap_mod_lock);
>> +
>> +    cmap_init(&mgr->odp_port_to_port);
>> +    cmap_init(&mgr->netdev_to_port);
>> +    cmap_init(&mgr->ifindex_to_port);
>> +
>> +    return mgr;
>> +}
>> +
>> +void dpif_offload_port_mgr_uninit(struct dpif_offload_port_mgr *mgr) {
>> +    if (!mgr) {
>> +        return;
>> +    }
>> +
>> +    ovs_assert(cmap_count(&mgr->odp_port_to_port) == 0);
>> +    ovs_assert(cmap_count(&mgr->netdev_to_port) == 0);
>> +    ovs_assert(cmap_count(&mgr->ifindex_to_port) == 0);
>> +
>> +    cmap_destroy(&mgr->odp_port_to_port);
>> +    cmap_destroy(&mgr->netdev_to_port);
>> +    cmap_destroy(&mgr->ifindex_to_port);
>> +    free(mgr);
>> +}
>> +
>> +struct dpif_offload_port_mgr_port *
>> +dpif_offload_port_mgr_find_by_ifindex(struct dpif_offload_port_mgr *mgr,
>> +                                      int ifindex) {
>> +    struct dpif_offload_port_mgr_port *port;
>> +
>> +    if (ifindex < 0) {
>> +        return NULL;
>> +    }
>> +
>> +    CMAP_FOR_EACH_WITH_HASH (port, ifindex_node, hash_int(ifindex, 0),
>> +                             &mgr->ifindex_to_port)
>> +    {
> "{" should be in the same line above.

ACK
>> +        if (port->ifindex == ifindex) {
>> +            return port;
>> +        }
>> +    }
>> +    return NULL;
>> +}
>> +
>> +struct dpif_offload_port_mgr_port *
>> +dpif_offload_port_mgr_find_by_netdev(struct dpif_offload_port_mgr *mgr,
>> +                                     struct netdev *netdev) {
>> +    struct dpif_offload_port_mgr_port *port;
>> +
>> +    if (!netdev) {
>> +        return NULL;
>> +    }
>> +
>> +    CMAP_FOR_EACH_WITH_HASH (port, netdev_node, hash_pointer(netdev,
>> 0),
>> +                             &mgr->netdev_to_port)
>> +    {
>> +        if (port->netdev == netdev) {
>> +            return port;
>> +        }
>> +    }
>> +    return NULL;
>> +}
>> +
>> +struct dpif_offload_port_mgr_port *
>> +dpif_offload_port_mgr_find_by_odp_port(struct dpif_offload_port_mgr *mgr,
>> +                                       odp_port_t port_no) {
>> +    struct dpif_offload_port_mgr_port *port;
>> +
>> +    CMAP_FOR_EACH_WITH_HASH (port, odp_port_node,
>> +                             hash_int(odp_to_u32(port_no), 0),
>> +                             &mgr->odp_port_to_port)
>> +    {
>> +        if (port->port_no == port_no) {
>> +            return port;
>> +        }
>> +    }
>> +    return NULL;
>> +}
>> +
>> +struct dpif_offload_port_mgr_port *
>> +dpif_offload_port_mgr_remove(struct dpif_offload_port_mgr *mgr,
>> +                             odp_port_t port_no, bool keep_netdev_ref)
>> +{
>> +    struct dpif_offload_port_mgr_port *port;
>> +
>> +    ovs_mutex_lock(&mgr->cmap_mod_lock);
>> +
>> +    port = dpif_offload_port_mgr_find_by_odp_port(mgr, port_no);
>> +
>> +    if (port) {
>> +        cmap_remove(&mgr->odp_port_to_port, &port->odp_port_node,
>> +                    hash_int(odp_to_u32(port_no), 0));
>> +        cmap_remove(&mgr->netdev_to_port, &port->netdev_node,
>> +                    hash_pointer(port->netdev, 0));
>> +
>> +        if (port->ifindex >= 0) {
>> +            cmap_remove(&mgr->ifindex_to_port, &port->ifindex_node,
>> +                        hash_int(port->ifindex, 0));
>> +        }
>> +        if (!keep_netdev_ref) {
>> +            netdev_close(port->netdev);
>> +        }
>> +    }
>> +
>> +    ovs_mutex_unlock(&mgr->cmap_mod_lock);
>> +    return port;
>> +}
>> +
>> +bool
>> +dpif_offload_port_mgr_add(struct dpif_offload_port_mgr *mgr,
>> +                          struct dpif_offload_port_mgr_port *port,
>> +                          struct netdev *netdev, odp_port_t port_no,
>> +                          bool need_ifindex) {
>> +    ovs_assert(netdev);
>> +
>> +    memset(port, 0, sizeof *port);
>> +    port->port_no = port_no;
>> +    port->ifindex = need_ifindex ? netdev_get_ifindex(netdev) : -1;
>> +
>> +    ovs_mutex_lock(&mgr->cmap_mod_lock);
>> +
>> +    if (dpif_offload_port_mgr_find_by_odp_port(mgr, port_no)
>> +        || dpif_offload_port_mgr_find_by_ifindex(mgr, port->ifindex)
>> +        || dpif_offload_port_mgr_find_by_netdev(mgr, netdev)) {
>> +
>> +        ovs_mutex_unlock(&mgr->cmap_mod_lock);
>> +        return false;
>> +    }
>> +
>> +    port->netdev = netdev_ref(netdev);
>> +
>> +    cmap_insert(&mgr->odp_port_to_port, &port->odp_port_node,
>> +                hash_int(odp_to_u32(port_no), 0));
>> +
>> +    cmap_insert(&mgr->netdev_to_port, &port->netdev_node,
>> +                hash_pointer(netdev, 0));
>> +
>> +    if (port->ifindex >= 0) {
>> +        cmap_insert(&mgr->ifindex_to_port, &port->ifindex_node,
>> +                    hash_int(port->ifindex, 0));
>> +    }
>> +
>> +    ovs_mutex_unlock(&mgr->cmap_mod_lock);
>> +    return true;
>> +}
>> +
>> +void
>> +dpif_offload_port_mgr_traverse_ports(
>> +    struct dpif_offload_port_mgr *mgr,
>> +    bool (*cb)(struct dpif_offload_port_mgr_port *, void *),
>> +    void *aux)
>> +{
>> +    struct dpif_offload_port_mgr_port *port;
>> +
>> +    CMAP_FOR_EACH (port, odp_port_node, &mgr->odp_port_to_port) {
>> +        if (cb(port, aux)) {
>> +            break;
>> +        }
>> +    }
>> +}
>> diff --git a/lib/dpif.c b/lib/dpif.c
>> index 4d4b5127b..fb889322a 100644
>> --- a/lib/dpif.c
>> +++ b/lib/dpif.c
>> @@ -359,10 +359,12 @@ do_open(const char *name, const char *type, bool
>> create, struct dpif **dpifp)
>>         const char *dpif_type_str = dpif_normalize_type(dpif_type(dpif));
>>         struct dpif_port_dump port_dump;
>>         struct dpif_port dpif_port;
>> +        bool new_offload_provider;
>>
>>         ovs_assert(dpif->dpif_class == registered_class->dpif_class);
>>
>> -        dpif_offload_attach_providers(dpif);
>> +        new_offload_provider = dpif_offload_attach_providers(dpif) == EEXIST
>> +                                   ? false : true;
> new_offload_provider = dpif_offload_attach_providers(dpif) != EEXIST

ACK

>>
>>         DPIF_PORT_FOR_EACH(&dpif_port, &port_dump, dpif) {
>>             struct netdev *netdev;
>> @@ -377,6 +379,9 @@ do_open(const char *name, const char *type, bool
>> create, struct dpif **dpifp)
>>             if (!err) {
>>                 netdev_set_dpif_type(netdev, dpif_type_str);
>>                 netdev_ports_insert(netdev, &dpif_port);
>> +                if (new_offload_provider) {
>> +                    dpif_offload_port_add(dpif, netdev, dpif_port.port_no);
>> +                }
>>                 netdev_close(netdev);
>>             } else {
>>                 VLOG_WARN("could not open netdev %s type %s: %s", @@ -621,6
>> +626,8 @@ dpif_port_add(struct dpif *dpif, struct netdev *netdev, odp_port_t
>> *port_nop)
>>             dpif_port.name = CONST_CAST(char *, netdev_name);
>>             dpif_port.port_no = port_no;
>>             netdev_ports_insert(netdev, &dpif_port);
>> +
>> +            dpif_offload_port_add(dpif, netdev, port_no);
>>         }
>>     } else {
>>         VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s", @@ -652,6
>> +659,8 @@ dpif_port_del(struct dpif *dpif, odp_port_t port_no, bool
>> local_delete)
>>         }
>>     }
>>
>> +    dpif_offload_port_del(dpif, port_no);
>> +
>>     netdev_ports_remove(port_no, dpif_normalize_type(dpif_type(dpif)));
>>     return error;
>> }
>> @@ -703,6 +712,7 @@ dpif_port_set_config(struct dpif *dpif, odp_port_t
>> port_no,
>>         if (error) {
>>             log_operation(dpif, "port_set_config", error);
>>         }
>> +        dpif_offload_port_set_config(dpif, port_no, cfg);
>>     }
>>
>>     return error;
>> diff --git a/lib/dummy.h b/lib/dummy.h
>> index b16ce0bbb..f0eb30ee2 100644
>> --- a/lib/dummy.h
>> +++ b/lib/dummy.h
>> @@ -19,6 +19,8 @@
>>
>> #include <stdbool.h>
>>
>> +struct netdev_class;
>> +
>> /* Degree of dummy support.
>>  *
>>  * Beyond enabling support for dummies, it can be useful to replace some 
>> kinds
>> @@ -38,5 +40,6 @@ void dpif_dummy_register(enum dummy_level);  void
>> netdev_dummy_register(enum dummy_level);  void
>> timeval_dummy_register(void);  void ofpact_dummy_enable(void);
>> +bool is_dummy_netdev_class(const struct netdev_class *);
>>
>> #endif /* dummy.h */
>> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index ff5a75a36..fbd60d377
>> 100644
>> --- a/lib/netdev-dpdk.c
>> +++ b/lib/netdev-dpdk.c
>> @@ -6516,7 +6516,7 @@ out:
>> }
>>
>> bool
>> -netdev_dpdk_flow_api_supported(struct netdev *netdev)
>> +netdev_dpdk_flow_api_supported(struct netdev *netdev, bool check_only)
>> {
>>     struct netdev_dpdk *dev;
>>     bool ret = false;
>> @@ -6535,7 +6535,7 @@ netdev_dpdk_flow_api_supported(struct netdev
>> *netdev)
>>     dev = netdev_dpdk_cast(netdev);
>>     ovs_mutex_lock(&dev->mutex);
>>     if (dev->type == DPDK_DEV_ETH) {
>> -        if (dev->requested_rx_steer_flags) {
>> +        if (dev->requested_rx_steer_flags && !check_only) {
>>             VLOG_WARN("%s: rx-steering is mutually exclusive with 
>> hw-offload,"
>>                       " falling back to default rss mode",
>>                       netdev_get_name(netdev)); diff --git 
>> a/lib/netdev-dpdk.h
>> b/lib/netdev-dpdk.h index 86df7a1e8..e6779d478 100644
>> --- a/lib/netdev-dpdk.h
>> +++ b/lib/netdev-dpdk.h
>> @@ -32,7 +32,7 @@ struct netdev;
>> void netdev_dpdk_register(const struct smap *);  void free_dpdk_buf(struct
>> dp_packet *);
>>
>> -bool netdev_dpdk_flow_api_supported(struct netdev *);
>> +bool netdev_dpdk_flow_api_supported(struct netdev *, bool check_only);
>>
>> int
>> netdev_dpdk_rte_flow_destroy(struct netdev *netdev, diff --git a/lib/netdev-
>> dummy.c b/lib/netdev-dummy.c index b72820fcc..0e5239eeb 100644
>> --- a/lib/netdev-dummy.c
>> +++ b/lib/netdev-dummy.c
>> @@ -203,8 +203,8 @@ static void dummy_packet_stream_close(struct
>> dummy_packet_stream *);  static void pkt_list_delete(struct ovs_list *);  
>> static
>> void addr_list_delete(struct ovs_list *);
>>
>> -static bool
>> -is_dummy_class(const struct netdev_class *class)
>> +bool
>> +is_dummy_netdev_class(const struct netdev_class *class)
>> {
>>     return class->construct == netdev_dummy_construct;  } @@ -212,14
>> +212,14 @@ is_dummy_class(const struct netdev_class *class)  static struct
>> netdev_dummy *  netdev_dummy_cast(const struct netdev *netdev)  {
>> -    ovs_assert(is_dummy_class(netdev_get_class(netdev)));
>> +    ovs_assert(is_dummy_netdev_class(netdev_get_class(netdev)));
>>     return CONTAINER_OF(netdev, struct netdev_dummy, up);  }
>>
>> static struct netdev_rxq_dummy *
>> netdev_rxq_dummy_cast(const struct netdev_rxq *rx)  {
>> -    ovs_assert(is_dummy_class(netdev_get_class(rx->netdev)));
>> +    ovs_assert(is_dummy_netdev_class(netdev_get_class(rx->netdev)));
>>     return CONTAINER_OF(rx, struct netdev_rxq_dummy, up);  }
>>
>> @@ -1850,7 +1850,7 @@ static const struct netdev_class dummy_pmd_class
>> = {  static int  netdev_dummy_offloads_init_flow_api(struct netdev *netdev)  
>> {
>> -    return is_dummy_class(netdev->netdev_class) ? 0 : EOPNOTSUPP;
>> +    return is_dummy_netdev_class(netdev->netdev_class) ? 0 :
>> + EOPNOTSUPP;
>> }
>>
>> static const struct netdev_flow_api netdev_offload_dummy = { @@ -2022,7
>> +2022,7 @@ netdev_dummy_receive(struct unixctl_conn *conn,
>>     int i, k = 1, rx_qid = 0;
>>
>>     netdev = netdev_from_name(argv[k++]);
>> -    if (!netdev || !is_dummy_class(netdev->netdev_class)) {
>> +    if (!netdev || !is_dummy_netdev_class(netdev->netdev_class)) {
>>         unixctl_command_reply_error(conn, "no such dummy netdev");
>>         goto exit_netdev;
>>     }
>> @@ -2113,7 +2113,7 @@ netdev_dummy_set_admin_state(struct
>> unixctl_conn *conn, int argc,
>>
>>     if (argc > 2) {
>>         struct netdev *netdev = netdev_from_name(argv[1]);
>> -        if (netdev && is_dummy_class(netdev->netdev_class)) {
>> +        if (netdev && is_dummy_netdev_class(netdev->netdev_class)) {
>>             struct netdev_dummy *dummy_dev = netdev_dummy_cast(netdev);
>>
>>             ovs_mutex_lock(&dummy_dev->mutex);
>> @@ -2175,7 +2175,7 @@ netdev_dummy_conn_state(struct unixctl_conn
>> *conn, int argc,
>>         const char *dev_name = argv[1];
>>         struct netdev *netdev = netdev_from_name(dev_name);
>>
>> -        if (netdev && is_dummy_class(netdev->netdev_class)) {
>> +        if (netdev && is_dummy_netdev_class(netdev->netdev_class)) {
>>             struct netdev_dummy *dummy_dev = netdev_dummy_cast(netdev);
>>
>>             ovs_mutex_lock(&dummy_dev->mutex);
>> @@ -2210,7 +2210,7 @@ netdev_dummy_ip4addr(struct unixctl_conn *conn,
>> int argc OVS_UNUSED,  {
>>     struct netdev *netdev = netdev_from_name(argv[1]);
>>
>> -    if (netdev && is_dummy_class(netdev->netdev_class)) {
>> +    if (netdev && is_dummy_netdev_class(netdev->netdev_class)) {
>>         struct in_addr ip, mask;
>>         struct in6_addr ip6;
>>         uint32_t plen;
>> @@ -2244,7 +2244,7 @@ netdev_dummy_ip6addr(struct unixctl_conn *conn,
>> int argc OVS_UNUSED,  {
>>     struct netdev *netdev = netdev_from_name(argv[1]);
>>
>> -    if (netdev && is_dummy_class(netdev->netdev_class)) {
>> +    if (netdev && is_dummy_netdev_class(netdev->netdev_class)) {
>>         struct in6_addr ip6;
>>         char *error;
>>         uint32_t plen;
>> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c index
>> ca1982ccd..c4f97be70 100644
>> --- a/lib/netdev-offload-dpdk.c
>> +++ b/lib/netdev-offload-dpdk.c
>> @@ -2500,7 +2500,7 @@ netdev_offload_dpdk_init_flow_api(struct netdev
>> *netdev)
>>         return EOPNOTSUPP;
>>     }
>>
>> -    if (netdev_dpdk_flow_api_supported(netdev)) {
>> +    if (netdev_dpdk_flow_api_supported(netdev, false)) {
>>         ret = offload_data_init(netdev);
>>     }
>>
>> @@ -2510,7 +2510,7 @@ netdev_offload_dpdk_init_flow_api(struct netdev
>> *netdev)  static void  netdev_offload_dpdk_uninit_flow_api(struct netdev
>> *netdev)  {
>> -    if (netdev_dpdk_flow_api_supported(netdev)) {
>> +    if (netdev_dpdk_flow_api_supported(netdev, true)) {
>>         offload_data_destroy(netdev);
>>     }
>> }
>> diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index
>> 33a68c49c..87bc95180 100644
>> --- a/lib/netdev-provider.h
>> +++ b/lib/netdev-provider.h
>> @@ -100,6 +100,7 @@ struct netdev {
>>     struct ovs_list saved_flags_list; /* Contains "struct 
>> netdev_saved_flags". */
>>
>>     /* Functions to control flow offloading. */
>> +    OVSRCU_TYPE(const struct dpif_offload *) dpif_offload;
>>     OVSRCU_TYPE(const struct netdev_flow_api *) flow_api;
>>     const char *dpif_type;          /* Type of dpif this netdev belongs to. 
>> */
>>     struct netdev_hw_info hw_info;  /* Offload-capable netdev info. */

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

Reply via email to