On 23/07/2026 16:11, Eelco Chaudron wrote:
External email: Use caution opening links or attachments


On 1 Jul 2026, at 15:58, Eli Britstein wrote:

Introduce a new netdev type - "doca".
The code is placed in new files.
- ovs-doca: initialization of doca library and utility functions that
   are used currently by netdev-doca and also will be used for future
   hw-offload code.
- netdev-doca: implementation of the new netdev.

Supported ports are mlx5 ports in switch-dev mode only that with a NIC
that supports hw-steering.

The netdev has the concept of ESW manager. A representor port is
functional only if its ESW manager is attached to OVS. In case it is
not, the representor appears as functional in ovs-vsctl show, but it is
not. Upon initializing of an ESW manager port, each representor is
reconfigured to be functional, and upon destruction, they are first stopped.

Steering infrastructure:
- RX packets of all ports are steered to a common queue. This queue is
   polled using dpdk API and the packets are classified to a per-port
   memory structure.
- TX packets are marked with the target port as metadata and sent to a
   common queue. The egress pipe matches on the metadata and forwards the
   packets accordingly.

Signed-off-by: Eli Britstein <[email protected]>
---
Thanks for the new revision Eli! Some minor comments below.

//Eelco

  Documentation/automake.mk             |    2 +
  Documentation/howto/doca.rst          |  144 ++
  Documentation/howto/index.rst         |    1 +
...
+
+    fwd.type = DOCA_FLOW_FWD_RSS;
+    fwd.rss_type = DOCA_FLOW_RESOURCE_TYPE_NON_SHARED;
+    memset(&fwd.rss.nr_queues, 0xFF, sizeof fwd.rss.nr_queues);
I am not very familiar with the DOCA API, but looking at
doca_flow.h, struct doca_flow_resource_rss_cfg has both
outer_flags and nr_queues.  The template marks nr_queues
as changeable (0xFF) but leaves outer_flags at 0.  In
netdev_doca_rss_entries_init(), each of the 11 RSS entries
sets a different outer_flags value via
netdev_doca_rss_flags().  Does DOCA honour per-entry
outer_flags when the template has it at zero, or should
it also be set to 0xFF here?

This is doca-flow API.

https://networking-docs.nvidia.com/doca/archive/3-4-0/doca-flow#Setting-Pipe-Forwarding


+    rv = ovs_doca_pipe_create(&dev->common.up, &match, NULL, &monitor,
+                              &actions, &actions, NULL, &fwd, NULL,
+                              NETDEV_DOCA_RSS_NUM_ENTRIES * RTE_MAX_ETHPORTS,
+                              false, false, UINT64_C(1) << AUX_QUEUE, "RSS",
...
+
+    /* A device may report more queues than it makes available (this has
+     * been observed for Intel xl710, which reserves some of them for
Does this comment make sense in the context of netdev-doca?
Maybe consider updating it.

+     * SRIOV):  rte_eth_*_queue_setup will fail if a queue is not
+     * available.  When this happens we can retry the configuration
+     * and request less queues. */
+    while (n_rxq && n_txq) {
+        if (diag) {
+            VLOG_INFO("Retrying setup with (rxq:%d txq:%d)", n_rxq, n_txq);
Removed this comment, and also the retry loop.
+        }
...
+        case DOCA_LOG_LEVEL_ERROR:
+            VLOG_ERR_RL(&dbg_rl, "%.*s", (int) size, buf);
+            break;
+        case DOCA_LOG_LEVEL_CRIT:
+            VLOG_EMER("%.*s", (int) size, buf);
Should we also rate limit these?
There is no "VLOG_EMER_RL". I think it should abort, but anyway, this follows dpdk.c.

+            break;
+    }
+
+    return size;
+}
+
+static cookie_io_functions_t ovs_doca_log_func = {
...
+        queues[qid].n_waiting_entries--;
+    }
If an async entry ADD fails at the HW level, the only
indication is a VLL_ERR log from the callback.  The callers
have no way to detect this failure; ovs_doca_complete_queue_esw()
returns DOCA_SUCCESS regardless.  This means the steering
pipeline could be partially configured with no error propagated
to the caller.  Should we check doca_flow_pipe_entry_get_status()
after completion, or have the callback set a failure flag?
This will also be needed when installing actual offloaded flows,
where the caller must know whether the flow was committed to HW.
Nice catch. Added.

+}
+
+static int
+ovs_doca_init__(const struct smap *ovs_other_config)
+{
+    struct doca_flow_definitions_cfg *defs_cfg = NULL;
+    struct doca_flow_definitions *defs = NULL;
+    struct doca_flow_cfg *cfg;
+    doca_error_t err;
+
+    if (!dpdk_available()) {
+        VLOG_ERR("DOCA requires DPDK. Set other_config:dpdk-init=true.");
+        return ENODEV;
+    }
+
+    if (rte_flow_dynf_metadata_register() < 0) {
+        VLOG_ERR("Failed to register dynamic metadata, Error: %d (%s)",
+                 rte_errno, rte_strerror(rte_errno));
+        return ENOTSUP;
+    }
+
+    log_stream = fopencookie(NULL, "w+", ovs_doca_log_func);
+    if (!log_stream) {
+        VLOG_ERR("Can't redirect DOCA log: %s.", ovs_strerror(errno));
+    } else {
+        /* Create a logger back-end that prints to the redirected log. */
+        doca_log_backend_create_with_file_sdk(log_stream, &ovs_doca_log);
+        doca_log_level_set_global_sdk_limit(DOCA_LOG_LEVEL_WARNING);
+    }
+
+    unixctl_command_register("doca/log-set", "{level}. "
+                             "level=crit/err/warn/info/dbg/trc", 0, 1,
+                             ovs_doca_unixctl_log_set, NULL);
+    unixctl_command_register("doca/log-get", "", 0, 0,
+                             unixctl_mem_stream, ovs_doca_log_get);
+
+    /* DOCA configuration happens earlier than dpif-netdev's.
+     * To avoid reorganizing them, read the relevant item directly. */
+    ovs_doca_max_megaflows_counters =
+        smap_get_uint(ovs_other_config, "flow-limit",
+                      OFPROTO_FLOW_LIMIT_DEFAULT);
+
+#define RV_TEST(call)                                                    \
+    do {                                                                 \
+        err = (call);                                                    \
+        if (err != DOCA_SUCCESS) {                                       \
+            VLOG_ERR("DOCA initialization failed, %s(). Error: %d (%s)", \
+                     #call, err, doca_error_get_descr(err));             \
+            return ENODEV;                                               \
+        }                                                                \
+    } while (0)
+
+    RV_TEST(doca_flow_cfg_create(&cfg));
+    RV_TEST(doca_flow_cfg_set_pipe_queues(cfg, OVS_DOCA_MAX_STEERING_QUEUES));
+    RV_TEST(doca_flow_cfg_set_resource_mode(cfg,
+                                            DOCA_FLOW_RESOURCE_MODE_PORT));
+    RV_TEST(doca_flow_cfg_set_mode_args(cfg, "switch,hws,isolated,expert"));
+    RV_TEST(doca_flow_cfg_set_queue_depth(cfg, OVS_DOCA_QUEUE_DEPTH));
+    RV_TEST(doca_flow_cfg_set_cb_entry_process(cfg, ovs_doca_entry_process));
+    RV_TEST(ovs_doca_init_defs(cfg, &defs, &defs_cfg));
+    RV_TEST(doca_flow_init(cfg));
+    ovs_doca_destroy_defs(defs, defs_cfg);
+    RV_TEST(doca_flow_cfg_destroy(cfg));
+
The RV_TEST macro returns immediately on failure, so if
doca_flow_cfg_create() succeeds but any subsequent setter
fails, cfg is never destroyed.  Likewise if doca_flow_init()
fails after ovs_doca_init_defs(), both defs and defs_cfg are
leaked.
Ack

+#undef RV_TEST
+
+    netdev_doca_register();
+    return 0;
...
+        room = OVS_DOCA_QUEUE_DEPTH - n_waiting;
+        if (n_processed == 0 && retries-- <= 0) {
+            COVERAGE_INC(ovs_doca_queue_block);
+            break;
+        }
When 100 consecutive iterations produce zero progress the
loop breaks, but err is still DOCA_SUCCESS.  n_waiting_entries
may be nonzero.  The caller receives success but the entry
may not be committed to HW.  Should set an error before
breaking:

     if (n_processed == 0 && retries-- <= 0) {
         COVERAGE_INC(ovs_doca_queue_block);
         err = DOCA_ERROR_AGAIN;
         break;
     }

Or should we just document we will ignore the error, and
a successive call will retry?
Addressed as part of the previous comment about doca_flow_pipe_entry_get_status().

+
+        if (timeout_ms && time_msec() > timeout_ms) {
timeout_ms is always nonzero (set to time_msec() + 1000
earlier), so "if (timeout_ms && ...)" is always true,
and can be removed.

+            err = DOCA_ERROR_TIME_OUT;
+            VLOG_EMER("Timeout reached trying to complete queue %u: "
+                      "%u remaining entries", qid, n_waiting);
Should we rate-limit this in case the queue is persistently
timing out?  This is called from the flow add/remove path,
so a stuck queue could flood the log.

   VLOG_EMER_RL(%rl, "...");
There is no VLOG_EMER_RL. Changed to VLOG_ERR_RL.

+        }
+    } while (err == DOCA_SUCCESS && room < OVS_DOCA_QUEUE_DEPTH);
+
+    return err;
+}
...
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to