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]> --- lib/dpif-offload-dummy.c | 152 ++++++++++++++++++++- lib/dpif-offload-provider.h | 71 ++++++++++ lib/dpif-offload-rte_flow.c | 17 +++ lib/dpif-offload-tc.c | 20 +++ lib/dpif-offload.c | 260 +++++++++++++++++++++++++++++++++++- lib/dpif.c | 5 + 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, 539 insertions(+), 20 deletions(-) diff --git a/lib/dpif-offload-dummy.c b/lib/dpif-offload-dummy.c index 04f4b5227..d4997891c 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, + 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; } #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 ae92a6f74..ce309a672 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" @@ -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_rte_flow_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-rte_flow.c b/lib/dpif-offload-rte_flow.c index 3cfe0f3d3..0041b5613 100644 --- a/lib/dpif-offload-rte_flow.c +++ b/lib/dpif-offload-rte_flow.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" @@ -102,6 +104,20 @@ dpif_offload_rte_set_config(struct dpif_offload *offload, } } +static bool +dpif_offload_rte_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), "netdev")) { + 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_rte_flow_class = { .type = "rte_flow", .supported_dpif_types = (const char *const[]) { @@ -110,6 +126,7 @@ struct dpif_offload_class dpif_offload_rte_flow_class = { .open = dpif_offload_rte_open, .close = dpif_offload_rte_close, .set_config = dpif_offload_rte_set_config, + .can_offload = dpif_offload_rte_can_offload, }; /* XXX: Temporary functions below, which will be removed once fully 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 12fb4e7b8..e8d96aef9 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" @@ -142,7 +143,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]); } @@ -407,6 +409,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) @@ -539,3 +627,173 @@ 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) + { + 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->netdev = netdev_ref(netdev); + 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, port->netdev)) { + + ovs_mutex_unlock(&mgr->cmap_mod_lock); + return false; + } + + 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 a173d643a..54fce1e08 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -621,6 +621,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 +654,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 +707,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 2d15909bc..32298e707 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -6499,7 +6499,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; @@ -6518,7 +6518,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 16f863284..947bd9fa7 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c @@ -2501,7 +2501,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); } @@ -2511,7 +2511,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 5ae379469..26c63839a 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. */ -- 2.50.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
