On 18 May 2026, at 13:27, 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]>
Hi Eli, I guess we have some unresolved items from v3, https://patchwork.ozlabs.org/project/openvswitch/patch/[email protected]/, which I guess should be addressed. I did not look at the full details of our discussion, but I assume they will be fixed in v5. Maybe you should just send out the v5 if you have it ready addressing my comments, to quickly move forward when David's comments come in. I guess his v4 comments will directly apply to v5 as I skipped reviewing the DPDK part. Cheers, Eelco > +static int > +netdev_doca_mempool_configure(struct netdev_doca *dev) > + OVS_REQUIRES(dev->common.mutex) > +{ > + struct netdev_dpdk_common *common = &dev->common; > + uint32_t buf_size = netdev_dpdk_buf_size(common->requested_mtu); > + const char *netdev_name = netdev_get_name(&common->up); > + int socket_id = common->requested_socket_id; > + struct doca_mp *dmp; > + uint32_t mbuf_size; > + uint32_t n_mbufs; > + int mtu; > + > + if (!netdev_doca_is_esw_mgr(&common->up)) { [...] > + return 0; > + } > + > + mtu = FRAME_LEN_TO_MTU(buf_size); > + mbuf_size = MTU_TO_FRAME_LEN(mtu); > + n_mbufs = doca_calculate_mbufs(dev); > + > + /* Sweep mempools before create. */ > + doca_mp_sweep(); > + > + dmp = doca_rte_zmalloc("dmp", sizeof *dmp); > + if (!dmp) { > + return ENOMEM; > + } > + > + dmp->mp = netdev_dpdk_mp_create_pool(netdev_name, n_mbufs, mbuf_size, > + socket_id); > + if (!dmp->mp) { > + VLOG_ERR("%s: Failed to create mempool", netdev_name); > + return ENOMEM; We leak 'dmp' allocated memory here. > + } [...] > +/* Complete the queue 'qid' on the netdev's ESW until OVS_DOCA_QUEUE_DEPTH > + * entries are available. */ > +static doca_error_t > +ovs_doca_complete_queue_esw(struct netdev_doca_esw_ctx *esw, > + unsigned int qid) > +{ > + struct ovs_doca_offload_queue *queue; > + long long int timeout_ms; > + unsigned int n_waiting; > + doca_error_t err; > + uint32_t room; > + int retries; > + > + queue = &esw->offload_queues[qid]; > + n_waiting = queue->n_waiting_entries; > + > + if (n_waiting == 0) { > + COVERAGE_INC(ovs_doca_queue_empty); > + return DOCA_SUCCESS; > + } > + > + /* 1 second timeout. */ > + timeout_ms = time_msec() + 1 * 1000; > + retries = 100; > + do { > + unsigned int n_processed; > + > + /* Use 'max_processed_entries' == 0 to always attempt processing > + * the full length of the queue. */ > + err = doca_flow_entries_process(esw->esw_port, qid, > + OVS_DOCA_ENTRY_PROCESS_TIMEOUT_US, > 0); > + if (err != DOCA_SUCCESS) { > + VLOG_WARN_RL(&rl, "%s: Failed to process entries in queue " > + "%u. Error: %d (%s)", > + netdev_get_name(esw->esw_netdev), qid, > + err, doca_error_get_descr(err)); > + return err; > + } > + > + n_processed = n_waiting - queue->n_waiting_entries; > + if (n_processed == 0) { > + COVERAGE_INC(ovs_doca_queue_none_processed); > + } > + n_waiting = queue->n_waiting_entries; > + > + room = OVS_DOCA_QUEUE_DEPTH - n_waiting; > + if (n_processed == 0 && retries-- <= 0) { > + COVERAGE_INC(ovs_doca_queue_block); > + break; > + } > + > + if (timeout_ms && time_msec() > timeout_ms) { > + VLOG_EMER("Timeout reached trying to complete queue %u: " > + "%u remaining entries", qid, n_waiting); Should this break or return an error here? Without it, VLOG_EMER fires on every subsequent iteration since time_msec() > timeout_ms remains true, flooding the log. > + } > + } while (err == DOCA_SUCCESS && room < OVS_DOCA_QUEUE_DEPTH); > + > + return err; > +} [...] _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
