This patch adds support for configuring the priority of offload providers at a port level. When multiple providers exist and support the same port, the 'hw-offload-priority' option allows specifying the order in which they are tried.
Signed-off-by: Eelco Chaudron <[email protected]> --- v2 changes: - Fixed indentation problem in bridge_run(). --- lib/dpif-offload.c | 104 ++++++++++++++++++++++++++++++++++++------- lib/dpif-offload.h | 2 +- vswitchd/bridge.c | 5 ++- vswitchd/vswitch.xml | 24 ++++++++++ 4 files changed, 116 insertions(+), 19 deletions(-) diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c index 5c6b827c3..42055008e 100644 --- a/lib/dpif-offload.c +++ b/lib/dpif-offload.c @@ -23,6 +23,8 @@ #include "netdev-provider.h" #include "unixctl.h" #include "util.h" +#include "vswitch-idl.h" + #include "openvswitch/dynamic-string.h" #include "openvswitch/shash.h" #include "openvswitch/vlog.h" @@ -55,6 +57,7 @@ static const struct dpif_offload_class *base_dpif_offload_classes[] = { static char *dpif_offload_provider_priority_list = NULL; static atomic_bool dpif_offload_global_enabled = false; static atomic_bool dpif_offload_rebalance_policy = false; +static struct smap port_order_cfg = SMAP_INITIALIZER(&port_order_cfg); static int dpif_offload_register_provider__(const struct dpif_offload_class *class) @@ -428,34 +431,79 @@ dpif_offload_set_netdev_offload(struct netdev *netdev, ovsrcu_set(&netdev->dpif_offload, offload); } +static bool +dpif_offload_try_port_add(struct dpif_offload *offload, struct netdev *netdev, + odp_port_t port_no) +{ + 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)); + return true; + } 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)); + } + return false; +} + 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); + const char *port_priority = smap_get(&port_order_cfg, + netdev_get_name(netdev)); struct dpif_offload *offload; if (!dp_offload) { return; } - LIST_FOR_EACH (offload, dpif_list_node, &dp_offload->offload_providers) { - 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)); + if (port_priority) { + char *tokens = xstrdup(port_priority); + char *saveptr; + + VLOG_DBG("for netdev %s using port priority %s", + netdev_get_name(netdev), port_priority); + + for (char *name = strtok_r(tokens, ",", &saveptr); + name; + name = strtok_r(NULL, ",", &saveptr)) { + bool provider_added = false; + + if (!strcmp("none", name)) { + break; + } + + LIST_FOR_EACH (offload, dpif_list_node, + &dp_offload->offload_providers) { + if (!strcmp(name, offload->class->type)) { + + provider_added = dpif_offload_try_port_add(offload, netdev, + port_no); + break; + } + } + + if (provider_added) { + break; + } + } + free(tokens); + } else { + LIST_FOR_EACH (offload, dpif_list_node, + &dp_offload->offload_providers) { + if (dpif_offload_try_port_add(offload, netdev, port_no)) { 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)); } } } @@ -569,13 +617,16 @@ dpif_offload_dump_done(struct dpif_offload_dump *dump) } void -dpif_offload_set_global_cfg(const struct smap *other_cfg) +dpif_offload_set_global_cfg(const struct ovsrec_open_vswitch *cfg) { static struct ovsthread_once init_once = OVSTHREAD_ONCE_INITIALIZER; - const char *priority = smap_get(other_cfg, "hw-offload-priority"); + const struct smap *other_cfg = &cfg->other_config; + const char *priority; /* The 'hw-offload-priority' parameter can only be set at startup, * any successive change needs a restart. */ + priority = smap_get(other_cfg, "hw-offload-priority"); + if (ovsthread_once_start(&init_once)) { /* Initialize the dpif-offload layer in case it's not yet initialized * at the first invocation of setting the configuration. */ @@ -629,6 +680,25 @@ dpif_offload_set_global_cfg(const struct smap *other_cfg) ovsthread_once_done(&once_enable); } } + + /* Filter out the 'hw-offload-priority' per port setting we need it before + * ports are added, so we can assign the correct offload-provider. + * Note that we can safely rebuild the map here, as we only access this + * from the same (main) thread. */ + smap_clear(&port_order_cfg); + for (int i = 0; i < cfg->n_bridges; i++) { + const struct ovsrec_bridge *br_cfg = cfg->bridges[i]; + + for (int j = 0; j < br_cfg->n_ports; j++) { + const struct ovsrec_port *port_cfg = br_cfg->ports[j]; + + priority = smap_get(&port_cfg->other_config, + "hw-offload-priority"); + if (priority) { + smap_add(&port_order_cfg, port_cfg->name, priority); + } + } + } } diff --git a/lib/dpif-offload.h b/lib/dpif-offload.h index f35f9b8a8..9cee3a8f4 100644 --- a/lib/dpif-offload.h +++ b/lib/dpif-offload.h @@ -32,7 +32,7 @@ struct dpif_offload_dump { /* Global functions. */ -void dpif_offload_set_global_cfg(const struct smap *other_cfg); +void dpif_offload_set_global_cfg(const struct ovsrec_open_vswitch *); bool dpif_offload_is_offload_enabled(void); bool dpif_offload_is_offload_rebalance_policy_enabled(void); diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 62dec1391..10fcc49a7 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -3395,8 +3395,11 @@ bridge_run(void) } cfg = ovsrec_open_vswitch_first(idl); + if (cfg && ovsdb_idl_get_seqno(idl) != idl_seqno) { + dpif_offload_set_global_cfg(cfg); + } + if (cfg) { - dpif_offload_set_global_cfg(&cfg->other_config); netdev_set_flow_api_enabled(&cfg->other_config); dpdk_init(&cfg->other_config); userspace_tso_init(&cfg->other_config); diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 061d0a568..1c53a2859 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -2600,6 +2600,30 @@ e.g. <code>fake-bridge-bridge-id</code>. </column> + <column name="other_config" key="hw-offload-priority" + type='{"type": "string"}'> + <p> + This configuration sets an explicit list of hardware offload + providers to try on this port. The argument should be a + comma-separated list of hardware offload provider names, or the + word <code>none</code>. + </p> + <p> + If <code>none</code> is encountered in the list, further trying of + offload providers is stopped. For example, if the list only contains + <code>none</code>, hardware offload is disabled on this port even if + it is globally enabled. Note that unknown hardware offload provider + names are ignored. + </p> + <p> + The default value is <code>none</code>, i.e., not set, which uses the + global + <ref table="Open_vSwitch" column="other_config" key="hw-offload-priority"/> + configuration. Changing this value after offload enablement requires + restarting the daemon. + </p> + </column> + <column name="other_config" key="transient" type='{"type": "boolean"}'> <p> -- 2.50.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
