>-----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 06/41] dpif-offload: Add offload provider
>set_config API.
>
>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     | 84 ++++++++++++++++++++++++++++++++++---
> lib/dpif-offload-provider.h | 18 +++++++-
> 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, 178 insertions(+), 40 deletions(-)
>
>diff --git a/lib/dpif-offload-dpdk.c b/lib/dpif-offload-dpdk.c index
>03c8f6492..6ac4af8d8 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 **dpif_offload)
>+                       struct dpif *dpif, struct dpif_offload
>+ **offload_)
Change the name of the argument already in the first commit introduced it.
> {
>-    struct dpif_offload *offload = xmalloc(sizeof(struct dpif_offload));
>+    struct dpif_offload_dpdk *offload;
>+
>+    offload = xmalloc(sizeof(struct dpif_offload_dpdk));
>+
>+    dpif_offload_init(&offload->offload, offload_class, dpif);
>+    offload->once_enable = (struct ovsthread_once)
>+ OVSTHREAD_ONCE_INITIALIZER;
>
>-    dpif_offload_init(offload, offload_class, dpif);
>-    *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)) {
>+        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
>73bb1a57c..09a7dfc2c 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"
>
> /* The DPIF Offload Provider introduces an abstraction layer for hardware @@
>-84,6 +86,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);
> };
>
>
>@@ -92,8 +99,17 @@ extern struct dpif_offload_class
>dpif_offload_dummy_x_class;  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 f5d62566e..c09530daa 100644
>--- a/lib/dpif-offload-tc.c
>+++ b/lib/dpif-offload-tc.c
>@@ -19,22 +19,65 @@
> #include "dpif-offload.h"
> #include "dpif-offload-provider.h"
> #include "util.h"
>+#include "tc.h"
Move line up.
>+
>+/* 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(struct dpif_offload));
>+    struct dpif_offload_tc *offload_tc;
>+
>+    offload_tc = xmalloc(sizeof(struct dpif_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 2d734beb0..4c89ae443 100644
>--- a/lib/dpif-offload.c
>+++ b/lib/dpif-offload.c
>@@ -355,6 +355,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,
>@@ -520,6 +537,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");
Can we move it to the commit introduced this code?
>
>             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

Reply via email to