Re: [PATCH net-next v4 5/6] selftests: net: add multithread server support to iou-zcrx
Paolo Abeni <[email protected]> Tue, 4 Aug 2026 12:42:41 +0200
| Newsgroups | gmane.linux.network |
|---|---|
| Message-ID | <[email protected]> |
On 7/30/26 12:18 AM, Juanlu Herrero wrote: > Run the iou-zcrx server as N worker threads, each owning one receive > queue with its own io_uring and zero-copy receive (zcrx) ifq, so the > test can exercise multi-queue zero-copy receive. > > The main thread owns the listening socket, accepts connections, and > dispatches each to the worker owning the queue it landed on by matching > SO_INCOMING_NAPI_ID against per-queue NAPI IDs. > > Assisted-by: Claude:claude-opus-4-8 > Signed-off-by: Juanlu Herrero <[email protected]> > --- > .../testing/selftests/drivers/net/hw/Makefile | 5 +- > .../selftests/drivers/net/hw/iou-zcrx.c | 290 ++++++++++++++---- > 2 files changed, 226 insertions(+), 69 deletions(-) > > diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile > index 3cab3b4adbb2e..035581b58bc66 100644 > --- a/tools/testing/selftests/drivers/net/hw/Makefile > +++ b/tools/testing/selftests/drivers/net/hw/Makefile > @@ -13,10 +13,6 @@ else > $(warning excluding iouring tests, liburing not installed or too old) > endif > > -TEST_GEN_FILES := \ > - $(COND_GEN_FILES) \ > -# end of TEST_GEN_FILES > - > TEST_PROGS = \ > csum.py \ > devlink_port_split.py \ > @@ -71,6 +67,7 @@ TEST_INCLUDES := \ > YNL_GEN_FILES := \ > ncdevmem \ > toeplitz \ > + $(COND_GEN_FILES) \ > # end of YNL_GEN_FILES > TEST_GEN_FILES += $(YNL_GEN_FILES) > TEST_GEN_FILES += $(patsubst %.c,%.o,$(wildcard *.bpf.c)) > diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c > index 7bc61f3b70ca6..16259129df46d 100644 > --- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c > +++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c > @@ -27,6 +27,7 @@ > #include <netinet/tcp.h> > #include <netinet/udp.h> > #include <sys/epoll.h> > +#include <sys/eventfd.h> > #include <sys/ioctl.h> > #include <sys/mman.h> > #include <sys/resource.h> > @@ -38,6 +39,8 @@ > #include <sys/wait.h> > > #include <liburing.h> > +#include <ynl.h> > +#include "netdev-user.h" > > #define SKIP_CODE 42 > > @@ -91,6 +94,7 @@ static int cfg_num_threads = 1; > static char *payload; > > #define CONNS_PER_THREAD 4 > +#define MAX_CONNS_PER_THREAD 64 > > struct thread_ctx { > struct io_uring ring; > @@ -99,9 +103,14 @@ struct thread_ctx { > size_t ring_size; > struct io_uring_zcrx_rq rq_ring; > unsigned long area_token; > - int connfd; > - bool stop; > - size_t received; > + int queue_id; > + int napi_id; > + int ready_fd; > + int start_fd; > + > + int connfds[MAX_CONNS_PER_THREAD]; > + size_t received[MAX_CONNS_PER_THREAD]; > + int nr_conns; > }; > > static unsigned long gettimeofday_ms(void) > @@ -201,7 +210,7 @@ static void setup_zcrx(struct thread_ctx *ctx) > > struct t_io_uring_zcrx_ifq_reg reg = { > .if_idx = ifindex, > - .if_rxq = cfg_queue_id, > + .if_rxq = ctx->queue_id, > .rq_entries = rq_entries, > .area_ptr = (__u64)(unsigned long)&area_reg, > .region_ptr = (__u64)(unsigned long)®ion_reg, > @@ -226,53 +235,32 @@ static void setup_zcrx(struct thread_ctx *ctx) > ctx->area_token = area_reg.rq_area_token; > } > > -static void add_accept(struct thread_ctx *ctx, int sockfd) > +static void add_recvzc(struct thread_ctx *ctx, int conn_idx) > { > struct io_uring_sqe *sqe; > > sqe = io_uring_get_sqe(&ctx->ring); > > - io_uring_prep_accept(sqe, sockfd, NULL, NULL, 0); > - sqe->user_data = 1; > -} > - > -static void add_recvzc(struct thread_ctx *ctx, int sockfd) > -{ > - struct io_uring_sqe *sqe; > - > - sqe = io_uring_get_sqe(&ctx->ring); > - > - io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, sockfd, NULL, 0, 0); > + io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, ctx->connfds[conn_idx], > + NULL, 0, 0); > sqe->ioprio |= IORING_RECV_MULTISHOT; > - sqe->user_data = 2; > + sqe->user_data = conn_idx; > } > > -static void add_recvzc_oneshot(struct thread_ctx *ctx, int sockfd, size_t len) > +static void add_recvzc_oneshot(struct thread_ctx *ctx, int conn_idx, size_t len) > { > struct io_uring_sqe *sqe; > > sqe = io_uring_get_sqe(&ctx->ring); > > - io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, sockfd, NULL, len, 0); > + io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, ctx->connfds[conn_idx], > + NULL, len, 0); > sqe->ioprio |= IORING_RECV_MULTISHOT; > - sqe->user_data = 2; > + sqe->user_data = conn_idx; > } > > -static void process_accept(struct thread_ctx *ctx, struct io_uring_cqe *cqe) > -{ > - if (cqe->res < 0) > - error(1, 0, "accept()"); > - if (ctx->connfd) > - error(1, 0, "Unexpected second connection"); > - > - ctx->connfd = cqe->res; > - if (cfg_oneshot) > - add_recvzc_oneshot(ctx, ctx->connfd, page_size); > - else > - add_recvzc(ctx, ctx->connfd); > -} > - > -static void process_recvzc(struct thread_ctx *ctx, struct io_uring_cqe *cqe) > +static void process_recvzc(struct thread_ctx *ctx, struct io_uring_cqe *cqe, > + int conn_idx) > { > unsigned int rq_mask = ctx->rq_ring.ring_entries - 1; > struct io_uring_zcrx_cqe *rcqe; > @@ -283,7 +271,7 @@ static void process_recvzc(struct thread_ctx *ctx, struct io_uring_cqe *cqe) > int i; > > if (cqe->res == 0 && cqe->flags == 0 && cfg_oneshot_recvs == 0) { > - ctx->stop = true; > + ctx->nr_conns--; > return; > } > > @@ -292,11 +280,11 @@ static void process_recvzc(struct thread_ctx *ctx, struct io_uring_cqe *cqe) > > if (cfg_oneshot) { > if (cqe->res == 0 && cqe->flags == 0 && cfg_oneshot_recvs) { > - add_recvzc_oneshot(ctx, ctx->connfd, page_size); > + add_recvzc_oneshot(ctx, conn_idx, page_size); > cfg_oneshot_recvs--; Sashiko noted that the above update is now racy in multithread tests: https://sashiko.dev/#/patchset/20260729221825.42773-1-juanlu%40fastmail.com Also please respect the reverse christmas tree order consistently. /P