Eelco Chaudron via dev <[email protected]> writes:
> This patch adds support for configuring the priority of
> offload providers. 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 a memory leak with the 'dpif_offload_provider_priority_list'
> variable.
>
> v3 changes:
> - Fixed some new line style issues.
> - Removed duplicate code in dpif_offload_attach_providers_().
> ---
> lib/dpif-offload.c | 124 ++++++++++++++++++++++++++++++++++------
> lib/dpif-offload.h | 4 ++
> tests/ofproto-dpif.at | 37 +++++++++++-
> tests/ofproto-macros.at | 9 ++-
> vswitchd/bridge.c | 2 +
> vswitchd/vswitch.xml | 19 ++++++
> 6 files changed, 175 insertions(+), 20 deletions(-)
>
> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
> index 6aae46356..60ee0a07d 100644
> --- a/lib/dpif-offload.c
> +++ b/lib/dpif-offload.c
> @@ -43,10 +43,16 @@ static const struct dpif_offload_class
> *base_dpif_offload_classes[] = {
> #ifdef DPDK_NETDEV
> &dpif_offload_dpdk_class,
> #endif
> + /* If you add an offload class to this structure, make sure you also
> + * update the dpif_offload_provider_priority_list below. */
> &dpif_offload_dummy_class,
> &dpif_offload_dummy_x_class,
> };
>
> +#define DEFAULT_PROVIDER_PRIORITY_LIST "tc,dpdk,dummy,dummy_x"
> +
> +static char *dpif_offload_provider_priority_list = NULL;
> +
> static int
> dpif_offload_register_provider__(const struct dpif_offload_class *class)
> OVS_REQUIRES(dpif_offload_mutex)
> @@ -131,6 +137,11 @@ dp_offload_initialize(void)
> return;
> }
>
> + if (!dpif_offload_provider_priority_list) {
> + dpif_offload_provider_priority_list = xstrdup(
> + DEFAULT_PROVIDER_PRIORITY_LIST);
> + }
> +
> unixctl_command_register("dpif/offload/classes", NULL, 0, 0,
> dpif_offload_show_classes, NULL);
>
> @@ -190,13 +201,37 @@ dpif_offload_attach_dp_offload(struct dpif *dpif,
> return 0;
> }
>
> +static void
> +dpif_offload_attach_providers__(struct dpif *dpif,
> + struct dp_offload *dp_offload,
> + struct dpif_offload *offload)
> + OVS_REQUIRES(dpif_offload_mutex)
> +{
> + int error;
> +
> + ovs_list_remove(&offload->dpif_list_node);
> + error = dpif_offload_attach_provider_to_dp_offload(dp_offload,
> + offload);
> + if (error) {
> + VLOG_WARN(
> + "failed to add dpif offload provider %s to %s: %s",
> + offload->class->type, dpif_name(dpif),
> + ovs_strerror(error));
> +
> + offload->class->close(offload);
> + }
> +}
> +
> static int
> dpif_offload_attach_providers_(struct dpif *dpif)
> OVS_REQUIRES(dpif_offload_mutex)
> {
> + struct ovs_list provider_list = OVS_LIST_INITIALIZER(&provider_list);
> const char *dpif_type_str = dpif_normalize_type(dpif_type(dpif));
> struct dp_offload *dp_offload;
> + struct dpif_offload *offload;
> struct shash_node *node;
> + char *tokens, *saveptr;
>
> /* Allocate and attach dp_offload to dpif. */
> dp_offload = xmalloc(sizeof *dp_offload);
> @@ -206,37 +241,51 @@ dpif_offload_attach_providers_(struct dpif *dpif)
> ovs_list_init(&dp_offload->offload_providers);
> shash_add(&dpif_offload_providers, dp_offload->dpif_name, dp_offload);
>
> - /* Attach all the providers supporting this dpif type. */
> + /* Open all the providers supporting this dpif type. */
> SHASH_FOR_EACH (node, &dpif_offload_classes) {
> const struct dpif_offload_class *class = node->data;
>
> for (size_t i = 0; class->supported_dpif_types[i] != NULL; i++) {
> if (!strcmp(class->supported_dpif_types[i], dpif_type_str)) {
> - struct dpif_offload *offload;
> - int error;
> -
> - error = class->open(class, dpif, &offload);
> - if (!error) {
> - error = dpif_offload_attach_provider_to_dp_offload(
> - dp_offload, offload);
> - if (error) {
> - VLOG_WARN("failed to add dpif offload provider "
> - "%s to %s: %s",
> - class->type, dpif_name(dpif),
> - ovs_strerror(error));
> - class->close(offload);
> - }
> - } else {
> + int error = class->open(class, dpif, &offload);
> +
> + if (error) {
> VLOG_WARN("failed to initialize dpif offload provider "
> "%s for %s: %s",
> class->type, dpif_name(dpif),
> ovs_strerror(error));
> + } else {
> + ovs_list_push_back(&provider_list,
> + &offload->dpif_list_node);
> }
> break;
Weird - I must be misunderstanding, but I would expect that this
wouldn't actually properly seek through the list, because the first
match would land on this break. Did I miss something?
> }
> }
> }
>
> + /* Attach all the providers based on the priority list. */
> + tokens = xstrdup(dpif_offload_provider_priority_list);
> +
> + for (char *name = strtok_r(tokens, ",", &saveptr);
> + name;
> + name = strtok_r(NULL, ",", &saveptr)) {
> +
> + LIST_FOR_EACH_SAFE (offload, dpif_list_node, &provider_list) {
> + if (strcmp(name, offload->class->type)) {
> + continue;
> + }
> +
> + dpif_offload_attach_providers__(dpif, dp_offload, offload);
> + break;
> + }
> + }
> + free(tokens);
> +
> + /* Add remaining entries in order. */
> + LIST_FOR_EACH_SAFE (offload, dpif_list_node, &provider_list) {
> + dpif_offload_attach_providers__(dpif, dp_offload, offload);
> + }
> +
> /* Attach dp_offload to dpif. */
> ovsrcu_set(&dpif->dp_offload, dp_offload);
>
> @@ -399,3 +448,46 @@ dpif_offload_dump_done(struct dpif_offload_dump *dump)
> {
> return dump->error == EOF ? 0 : dump->error;
> }
> +
> +void
> +dpif_offload_set_global_cfg(const struct smap *other_cfg)
> +{
> + static struct ovsthread_once init_once = OVSTHREAD_ONCE_INITIALIZER;
> + const char *priority = smap_get(other_cfg, "hw-offload-priority");
> +
> + /* The 'hw-offload-priority' parameter can only be set at startup,
> + * any successive change needs a restart. */
> + 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. */
> + dp_offload_initialize();
> +
> + /* If priority is not set keep the default value. */
> + if (priority) {
> + char *tokens = xstrdup(priority);
> + char *saveptr;
> +
> + free(dpif_offload_provider_priority_list);
> + dpif_offload_provider_priority_list = xstrdup(priority);
> +
> + /* Log a warning for unknown offload providers. */
> + for (char *name = strtok_r(tokens, ",", &saveptr);
> + name;
> + name = strtok_r(NULL, ",", &saveptr)) {
> +
> + if (!shash_find(&dpif_offload_classes, name)) {
> + VLOG_WARN("'hw-offload-priority' configuration has an "
> + "unknown type; %s", name);
If a weird config gets into this, maybe it's better to also remove it
from the in-memory list. WDYT?
> + }
> + }
> + free(tokens);
> + }
> + ovsthread_once_done(&init_once);
> + } else {
> + if (priority && strcmp(priority,
> + dpif_offload_provider_priority_list)) {
> + VLOG_INFO_ONCE("'hw-offload-priority' configuration changed; "
> + "restart required");
> + }
> + }
> +}
> diff --git a/lib/dpif-offload.h b/lib/dpif-offload.h
> index d61d8e0bf..43d8b6b74 100644
> --- a/lib/dpif-offload.h
> +++ b/lib/dpif-offload.h
> @@ -30,6 +30,10 @@ struct dpif_offload_dump {
> void *state;
> };
>
> +
> +/* Global functions. */
> +void dpif_offload_set_global_cfg(const struct smap *other_cfg);
> +
>
> /* Per dpif specific functions. */
> void dpif_offload_init(struct dpif_offload *,
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index 11f9e346a..1d80fc439 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -10108,6 +10108,41 @@ AT_SETUP([ofproto-dpif - offload - ovs-appctl
> dpif/offload/])
> AT_KEYWORDS([dpif-offload])
> OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy])
>
> +AT_CHECK([ovs-appctl dpif/offload/show], [0], [dnl
> +dummy@ovs-dummy:
> + dummy
> + dummy_x
> +])
> +
> +AT_CHECK([ovs-appctl --format json --pretty dpif/offload/show], [0], [dnl
> +{
> + "dummy@ovs-dummy": {
> + "providers": [[
> + "dummy",
> + "dummy_x"]]}}
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - offload - priority order - warning])
> +AT_KEYWORDS([dpif-offload])
> +OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy], [],
> [],
> + [], [-- set Open_vSwitch . other_config:hw-offload-priority=none,dummy])
> +
> +OVS_WAIT_UNTIL(
> + [grep "'hw-offload-priority' configuration has an unknown type; none" \
> + ovs-vswitchd.log])
> +
> +OVS_VSWITCHD_STOP(
> + ["/'hw-offload-priority' configuration has an unknown type;/d"])
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - offload - priority order])
> +AT_KEYWORDS([dpif-offload])
> +OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy], [],
> [],
> + [], [-- set Open_vSwitch . other_config:hw-offload-priority=dummy_x,dummy])
> +
> AT_CHECK([ovs-appctl dpif/offload/show], [0], [dnl
> dummy@ovs-dummy:
> dummy_x
> @@ -10122,7 +10157,7 @@ AT_CHECK([ovs-appctl --format json --pretty
> dpif/offload/show], [0], [dnl
> "dummy"]]}}
> ])
>
> -OVS_VSWITCHD_STOP
> +OVS_TRAFFIC_VSWITCHD_STOP
> AT_CLEANUP
>
> dnl ----------------------------------------------------------------------
> diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
> index 3cd49d7a7..71cd2aed0 100644
> --- a/tests/ofproto-macros.at
> +++ b/tests/ofproto-macros.at
> @@ -227,11 +227,12 @@ m4_define([_OVS_VSWITCHD_START],
> /netdev_offload|INFO|netdev: Flow API Enabled/d
> /probe tc:/d
> /setting extended ack support failed/d
> -/tc: Using policy/d']])
> +/tc: Using policy/d
> +/'"'"'hw-offload-priority'"'"' configuration has an unknown type;/d']])
> ])
>
> # OVS_VSWITCHD_START([vsctl-args], [vsctl-output], [=override],
> -# [vswitchd-aux-args])
> +# [vswitchd-aux-args] [dbinit-aux-args])
> #
> # Creates a database and starts ovsdb-server, starts ovs-vswitchd
> # connected to that database, calls ovs-vsctl to create a bridge named
> @@ -248,7 +249,9 @@ m4_define([_OVS_VSWITCHD_START],
> # 'vswitchd-aux-args' provides a way to pass extra command line arguments
> # to ovs-vswitchd
> m4_define([OVS_VSWITCHD_START],
> - [_OVS_VSWITCHD_START([--enable-dummy$3 --disable-system
> --disable-system-route $4])
> + [_OVS_VSWITCHD_START(
> + [--enable-dummy$3 --disable-system --disable-system-route $4],
> + [$5])
> AT_CHECK([add_of_br 0 $1 m4_if([$2], [], [], [| uuidfilt])], [0], [$2])
> ])
>
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 475eefefa..62dec1391 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -28,6 +28,7 @@
> #include "daemon.h"
> #include "dirs.h"
> #include "dpif.h"
> +#include "dpif-offload.h"
> #include "dpdk.h"
> #include "hash.h"
> #include "openvswitch/hmap.h"
> @@ -3395,6 +3396,7 @@ bridge_run(void)
> cfg = ovsrec_open_vswitch_first(idl);
>
> 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 b93ad9344..e235f7e79 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -254,6 +254,25 @@
> </p>
> </column>
>
> + <column name="other_config" key="hw-offload-priority"
> + type='{"type": "string"}'>
> + <p>
> + This configuration sets the order of the hardware offload providers
> + to try when multiple exist for a given datapath implementation.
> The
> + The argument provided should be a list of comma-separated hardware
> + offload provider names.
> + </p>
> + <p>
> + If implementations are missing from the list, they are added at the
> + end in undefined order.
> + </p>
> + <p>
> + The default value is <code>tc,dpdk,dummy,dummy_x</code>. Changing
> + this value requires restarting the daemon if hardware offload is
> + already enabled.
> + </p>
> + </column>
> +
> <column name="other_config" key="n-offload-threads"
> type='{"type": "integer", "minInteger": 1, "maxInteger": 10}'>
> <p>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev