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
