Eelco Chaudron via dev <[email protected]> writes:
> This patch introduces an API that allows offload providers to
> manage global configurations. It also moves the 'n-offload-threads'
> and 'tc-policy' setting to the appropriate providers using
> this new API.
>
> Signed-off-by: Eelco Chaudron <[email protected]>
> ---
> lib/dpif-offload-dpdk.c | 82 ++++++++++++++++++++++++++++++++++---
> lib/dpif-offload-provider.h | 17 +++++++-
> lib/dpif-offload-tc.c | 52 +++++++++++++++++++++--
> lib/dpif-offload.c | 18 ++++++++
> lib/dpif.c | 1 +
> lib/netdev-offload.c | 37 ++++++-----------
> tests/dpif-netdev.at | 6 +--
> tests/ofproto-macros.at | 2 +-
> 8 files changed, 176 insertions(+), 39 deletions(-)
>
> diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c
> index 838a6839b..9a0d62b20 100644
> --- a/lib/dpif-offload-dpdk.c
> +++ b/lib/dpif-offload-dpdk.c
> @@ -20,21 +20,84 @@
> #include "dpif-offload-provider.h"
> #include "util.h"
>
> +#include "openvswitch/vlog.h"
> +
> +VLOG_DEFINE_THIS_MODULE(dpif_offload_dpdk);
> +
> +#define DEFAULT_OFFLOAD_THREAD_NB 1
> +#define MAX_OFFLOAD_THREAD_NB 10
> +
> +static unsigned int offload_thread_nb = DEFAULT_OFFLOAD_THREAD_NB;
> +
> +/* dpif offload interface for the dpdk rte_flow implementation. */
> +struct dpif_offload_dpdk {
> + struct dpif_offload offload;
> +
> + /* Configuration specific variables. */
> + struct ovsthread_once once_enable; /* Track first-time enablement. */
> +};
> +
> +static struct dpif_offload_dpdk *
> +dpif_offload_dpdk_cast(const struct dpif_offload *offload)
> +{
> + dpif_offload_assert_class(offload, &dpif_offload_dpdk_class);
> + return CONTAINER_OF(offload, struct dpif_offload_dpdk, offload);
> +}
> +
> static int
> dpif_offload_dpdk_open(const struct dpif_offload_class *offload_class,
> struct dpif *dpif, struct dpif_offload **offload_)
> {
> - struct dpif_offload *offload = xmalloc(sizeof *offload);
> + struct dpif_offload_dpdk *offload;
> +
> + offload = xmalloc(sizeof *offload);
> +
> + dpif_offload_init(&offload->offload, offload_class, dpif);
> + offload->once_enable = (struct ovsthread_once)
> OVSTHREAD_ONCE_INITIALIZER;
>
> - dpif_offload_init(offload, offload_class, dpif);
> - *offload_ = offload;
> + *offload_ = &offload->offload;
> return 0;
> }
>
> static void
> -dpif_offload_dpdk_close(struct dpif_offload *dpif_offload)
> +dpif_offload_dpdk_close(struct dpif_offload *offload_)
> {
> - free(dpif_offload);
> + struct dpif_offload_dpdk *offload = dpif_offload_dpdk_cast(offload_);
> +
> + free(offload);
> +}
> +
> +static void
> +dpif_offload_dpdk_set_config(struct dpif_offload *offload_,
> + const struct smap *other_cfg)
> +{
> + struct dpif_offload_dpdk *offload = dpif_offload_dpdk_cast(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)) {
For this and the TC block, does it make sense to have a NEWS section and
also a warning that these global configs may be disappearing? Or
rather, I guess the idea is that there can be a global config and then a
per-dp offload state that shadows it? Otherwise, I don't understand the
comment block - maybe it would be better to have that as part of the
commit message. WDYT?
> + if (ovsthread_once_start(&offload->once_enable)) {
> +
> + offload_thread_nb = smap_get_ullong(other_cfg,
> + "n-offload-threads",
> + DEFAULT_OFFLOAD_THREAD_NB);
> + if (offload_thread_nb == 0 ||
> + offload_thread_nb > MAX_OFFLOAD_THREAD_NB) {
> + VLOG_WARN("netdev: Invalid number of threads requested: %u",
> + offload_thread_nb);
> + offload_thread_nb = DEFAULT_OFFLOAD_THREAD_NB;
> + }
> +
> + if (smap_get(other_cfg, "n-offload-threads")) {
> + VLOG_INFO("Flow API using %u thread%s",
> + offload_thread_nb,
> + offload_thread_nb > 1 ? "s" : "");
> + }
> +
> + ovsthread_once_done(&offload->once_enable);
> + }
> + }
> }
>
> struct dpif_offload_class dpif_offload_dpdk_class = {
> @@ -44,4 +107,13 @@ struct dpif_offload_class dpif_offload_dpdk_class = {
> NULL},
> .open = dpif_offload_dpdk_open,
> .close = dpif_offload_dpdk_close,
> + .set_config = dpif_offload_dpdk_set_config,
> };
> +
> +/* XXX: Temporary functions below, which will be removed once fully
> + * refactored. */
> +unsigned int dpif_offload_dpdk_get_thread_nb(void);
> +unsigned int dpif_offload_dpdk_get_thread_nb(void)
> +{
> + return offload_thread_nb;
> +}
> diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h
> index a7869b587..f0c0ea232 100644
> --- a/lib/dpif-offload-provider.h
> +++ b/lib/dpif-offload-provider.h
> @@ -19,6 +19,8 @@
>
> #include "dpif-provider.h"
> #include "ovs-thread.h"
> +#include "smap.h"
> +#include "util.h"
>
> #include "openvswitch/list.h"
>
> @@ -85,6 +87,11 @@ struct dpif_offload_class {
> * open() above. If your implementation accesses this provider using
> * RCU pointers, it's responsible for handling deferred deallocation. */
> void (*close)(struct dpif_offload *);
> + /* Pass custom configuration options to the offload provider. The
> + * implementation might postpone applying the changes until run() is
> + * called. */
> + void (*set_config)(struct dpif_offload *,
> + const struct smap *other_config);
> };
>
>
> @@ -94,8 +101,16 @@ extern struct dpif_offload_class dpif_offload_dpdk_class;
> extern struct dpif_offload_class dpif_offload_tc_class;
>
>
> -/* Global function, called by the dpif layer. */
> +/* 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);
> +
> +static inline void dpif_offload_assert_class(
> + const struct dpif_offload *dpif_offload,
> + const struct dpif_offload_class *dpif_offload_class)
> +{
> + ovs_assert(dpif_offload->class == dpif_offload_class);
> +}
>
>
> #endif /* DPIF_OFFLOAD_PROVIDER_H */
> diff --git a/lib/dpif-offload-tc.c b/lib/dpif-offload-tc.c
> index 88efdaac8..d0204e1bb 100644
> --- a/lib/dpif-offload-tc.c
> +++ b/lib/dpif-offload-tc.c
> @@ -18,23 +18,66 @@
>
> #include "dpif-offload.h"
> #include "dpif-offload-provider.h"
> +#include "tc.h"
> #include "util.h"
>
> +/* dpif offload interface for the tc implementation. */
> +struct dpif_offload_tc {
> + struct dpif_offload offload;
> +
> + /* Configuration specific variables. */
> + struct ovsthread_once once_enable; /* Track first-time enablement. */
> +};
> +
> +static struct dpif_offload_tc *
> +dpif_offload_tc_cast(const struct dpif_offload *offload)
> +{
> + dpif_offload_assert_class(offload, &dpif_offload_tc_class);
> + return CONTAINER_OF(offload, struct dpif_offload_tc, offload);
> +}
> +
> static int
> dpif_offload_tc_open(const struct dpif_offload_class *offload_class,
> struct dpif *dpif, struct dpif_offload **dpif_offload)
> {
> - struct dpif_offload *offload = xmalloc(sizeof *offload);
> + struct dpif_offload_tc *offload_tc;
> +
> + offload_tc = xmalloc(sizeof *offload_tc);
> +
> + dpif_offload_init(&offload_tc->offload, offload_class, dpif);
> + offload_tc->once_enable = (struct ovsthread_once) \
> + OVSTHREAD_ONCE_INITIALIZER;
>
> - dpif_offload_init(offload, offload_class, dpif);
> - *dpif_offload = offload;
> + *dpif_offload = &offload_tc->offload;
> return 0;
> }
>
> static void
> dpif_offload_tc_close(struct dpif_offload *dpif_offload)
> {
> - free(dpif_offload);
> + struct dpif_offload_tc *offload_tc = dpif_offload_tc_cast(dpif_offload);
> +
> + free(offload_tc);
> +}
> +
> +static void
> +dpif_offload_tc_set_config(struct dpif_offload *offload,
> + const struct smap *other_cfg)
> +{
> + struct dpif_offload_tc *offload_tc = dpif_offload_tc_cast(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_tc->once_enable)) {
> +
> + tc_set_policy(smap_get_def(other_cfg, "tc-policy",
> + TC_POLICY_DEFAULT));
> +
> + ovsthread_once_done(&offload_tc->once_enable);
> + }
> + }
> }
>
> struct dpif_offload_class dpif_offload_tc_class = {
> @@ -44,4 +87,5 @@ struct dpif_offload_class dpif_offload_tc_class = {
> NULL},
> .open = dpif_offload_tc_open,
> .close = dpif_offload_tc_close,
> + .set_config = dpif_offload_tc_set_config,
> };
> diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c
> index 7921207be..1b5f0ae71 100644
> --- a/lib/dpif-offload.c
> +++ b/lib/dpif-offload.c
> @@ -356,6 +356,23 @@ dpif_offload_detach_providers(struct dpif *dpif)
> }
> }
>
> +void
> +dpif_offload_set_config(struct dpif *dpif, const struct smap *other_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->set_config) {
> + offload->class->set_config(offload, other_cfg);
> + }
> + }
> +}
> +
>
> void
> dpif_offload_init(struct dpif_offload *offload,
> @@ -521,6 +538,7 @@ dpif_offload_set_global_cfg(const struct smap *other_cfg)
>
> if (ovsthread_once_start(&once_enable)) {
> atomic_store_relaxed(&dpif_offload_global_enabled, true);
> + VLOG_INFO("hw-offload API Enabled");
>
> if (smap_get_bool(other_cfg, "offload-rebalance", false)) {
> atomic_store_relaxed(&dpif_offload_rebalance_policy, true);
> diff --git a/lib/dpif.c b/lib/dpif.c
> index 91fa00888..4d4b5127b 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -1594,6 +1594,7 @@ dpif_set_config(struct dpif *dpif, const struct smap
> *cfg)
> if (error) {
> log_operation(dpif, "set_config", error);
> }
> + dpif_offload_set_config(dpif, cfg);
> }
>
> return error;
> diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c
> index 01fdadbc3..0fad1b983 100644
> --- a/lib/netdev-offload.c
> +++ b/lib/netdev-offload.c
> @@ -61,10 +61,16 @@ VLOG_DEFINE_THIS_MODULE(netdev_offload);
>
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>
> -#define DEFAULT_OFFLOAD_THREAD_NB 1
> +/* XXX: Temporarily duplicates definition in dpif-offload-dpdk.c. */
> #define MAX_OFFLOAD_THREAD_NB 10
> -
> +#define DEFAULT_OFFLOAD_THREAD_NB 1
> static unsigned int offload_thread_nb = DEFAULT_OFFLOAD_THREAD_NB;
> +
> +unsigned int dpif_offload_dpdk_get_thread_nb(void); /* XXX: Temporarily
> + * external declaration
> + * until fully
> refactored.
> + */
> +
> DEFINE_EXTERN_PER_THREAD_DATA(netdev_offload_thread_id, OVSTHREAD_ID_UNSET);
>
> /* Protects 'netdev_flow_apis'. */
> @@ -853,37 +859,18 @@ netdev_ports_flow_init(void)
> }
>
> void
> -netdev_set_flow_api_enabled(const struct smap *ovs_other_config)
> +netdev_set_flow_api_enabled(const struct smap *ovs_other_config OVS_UNUSED)
> {
> if (dpif_offload_is_offload_enabled()) {
> static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
>
> if (ovsthread_once_start(&once)) {
>
> - offload_thread_nb = smap_get_ullong(ovs_other_config,
> - "n-offload-threads",
> - DEFAULT_OFFLOAD_THREAD_NB);
> - if (offload_thread_nb == 0 ||
> - offload_thread_nb > MAX_OFFLOAD_THREAD_NB) {
> - VLOG_WARN("netdev: Invalid number of threads requested: %u",
> - offload_thread_nb);
> - offload_thread_nb = DEFAULT_OFFLOAD_THREAD_NB;
> - }
> -
> - if (smap_get(ovs_other_config, "n-offload-threads")) {
> - VLOG_INFO("netdev: Flow API Enabled, using %u thread%s",
> - offload_thread_nb,
> - offload_thread_nb > 1 ? "s" : "");
> - } else {
> - VLOG_INFO("netdev: Flow API Enabled");
> - }
> -
> -#ifdef __linux__
> - tc_set_policy(smap_get_def(ovs_other_config, "tc-policy",
> - TC_POLICY_DEFAULT));
> +#ifdef DPDK_NETDEV
> + offload_thread_nb = dpif_offload_dpdk_get_thread_nb();
> #endif
> - netdev_ports_flow_init();
>
> + netdev_ports_flow_init();
> ovsthread_once_done(&once);
> }
> }
> diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
> index 10dbbb4c7..6596af810 100644
> --- a/tests/dpif-netdev.at
> +++ b/tests/dpif-netdev.at
> @@ -414,7 +414,7 @@ m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD],
> AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
> netdev_dummy:file:dbg])
>
> AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
> - OVS_WAIT_UNTIL([grep "netdev: Flow API Enabled" ovs-vswitchd.log])
> + OVS_WAIT_UNTIL([grep "hw-offload API Enabled" ovs-vswitchd.log])
>
> AT_CHECK([ovs-ofctl del-flows br0])
> AT_CHECK([ovs-ofctl add-flow br0 in_port=1,actions=IN_PORT])
> @@ -477,7 +477,7 @@ m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS],
> AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
> netdev_dummy:file:dbg])
>
> AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
> - OVS_WAIT_UNTIL([grep "netdev: Flow API Enabled" ovs-vswitchd.log])
> + OVS_WAIT_UNTIL([grep "hw-offload API Enabled" ovs-vswitchd.log])
>
> AT_CHECK([ovs-ofctl del-flows br0])
>
> @@ -554,7 +554,7 @@ m4_define([DPIF_NETDEV_FLOW_HW_OFFLOAD_OFFSETS_VID_ARP],
> AT_CHECK([ovs-appctl vlog/set dpif:file:dbg dpif_netdev:file:dbg
> netdev_dummy:file:dbg])
>
> AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
> - OVS_WAIT_UNTIL([grep "netdev: Flow API Enabled" ovs-vswitchd.log])
> + OVS_WAIT_UNTIL([grep "hw-offload API Enabled" ovs-vswitchd.log])
>
> AT_CHECK([ovs-ofctl del-flows br0])
>
> diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
> index 71cd2aed0..8894dd711 100644
> --- a/tests/ofproto-macros.at
> +++ b/tests/ofproto-macros.at
> @@ -224,7 +224,7 @@ m4_define([_OVS_VSWITCHD_START],
> /ofproto|INFO|datapath ID changed to fedcba9876543210/d
> /dpdk|INFO|DPDK Disabled - Use other_config:dpdk-init to enable/d
> /netlink_socket|INFO|netlink: could not enable listening to all nsid/d
> -/netdev_offload|INFO|netdev: Flow API Enabled/d
> +/dpif_offload|INFO|hw-offload API Enabled/d
> /probe tc:/d
> /setting extended ack support failed/d
> /tc: Using policy/d
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev