On 26 Jul 2026, at 16:11, Eli Britstein wrote:
> 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
Thanks for pointing me to the docs. Still not clear to me
whether it needs the mask or not, but I guess you are the
expert ;)
The rest of the comment replies look good. I will try to
skim the v6 and do a full review after my PTO.
//Eelco
>>> + 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