All of lore.kernel.org
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: juanlu@fastmail.com
Cc: dw@davidwei.uk, netdev@vger.kernel.org, io-uring@vger.kernel.org,
	linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org,
	kuba@kernel.org, asml.silence@gmail.com, pabeni@redhat.com,
	shuah@kernel.org
Subject: Re: [net-next,v6,6/6] selftests: net: add rss_multiqueue test variant to iou-zcrx
Date: Wed, 02 Sep 2026 23:38:18 +0000	[thread overview]
Message-ID: <178839229826.3394541.7285066966620333885@kernel.org> (raw)
In-Reply-To: <20260831-iou-zcrx-v6-6-02d1d012f0fd@fastmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 2 · Low: 0

- [Medium] `rss_multiqueue()` in
  tools/testing/selftests/drivers/net/hw/iou-zcrx.py claims to "exercise…
- [Medium] The readiness handshake used by the Python driver no longer
  implies that the receiver is armed.

--

selftests: net: add rss_multiqueue test variant to iou-zcrx

Adds a new rss_multiqueue variant to the iou-zcrx Python test which builds
a two-queue RSS context, steers the tcp6 flow into it, and runs the
iou-zcrx helper with two receive threads. The existing test_zcrx variants
now also pass an explicit thread count of one.

> diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
> index b7a225fe4beae..c833535d8a03c 100755
> --- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
> +++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
> @@ -30,6 +30,13 @@ def create_rss_ctx(cfg):
>      return int(values)
>  
>  
> +def create_rss_ctx_multi(cfg, start, count):
> +    """Create an RSS context spanning count queues from start, return its ID."""
> +    output = ethtool(f"-X {cfg.ifname} context new start {start} equal {count}").stdout
> +    values = re.search(r'New RSS context is (\d+)', output).group(1)
> +    return int(values)
> +
> +

[ ... ]

> @@ -127,17 +134,56 @@ def _require_ntuple(cfg):
>          defer(ethtool, f"-K {cfg.ifname} ntuple-filters off")
>  
>  
> +def rss_multiqueue(cfg):
> +    """Steer the test flow to a multi-queue RSS context for multi-thread zcrx."""

[ ... ]

> +    cfg.num_threads = 2
> +    cfg.target = channels - cfg.num_threads
> +    ethtool(f"-X {cfg.ifname} equal {cfg.target}")
> +    defer(ethtool, f"-X {cfg.ifname} default")
> +
> +    rss_ctx_id = create_rss_ctx_multi(cfg, cfg.target, cfg.num_threads)
> +    defer(ethtool, f"-X {cfg.ifname} delete context {rss_ctx_id}")
> +
> +    flow_rule_id = set_flow_rule_rss(cfg, rss_ctx_id)
> +    defer(ethtool, f"-N {cfg.ifname} delete {flow_rule_id}")

[Severity: Medium]

Can this variant report a pass when only one of the two queues carried
zcrx traffic?

The RSS context spans queues [cfg.target, cfg.target + 1] and the flow rule
matches only flow-type tcp6 dst-port, so all connections share the same
addresses and destination port. The variant never configures or checks
ethtool -n rx-flow-hash tcp6, so on a device whose tcp6 hash covers only
addresses, every connection lands on the same queue. Even with a full
4-tuple hash, the four flows over a two-entry indirection table all collide
on a single queue roughly one run in eight.

On the helper side, run_server() distributes accepted connections purely by
the hardware-selected napi id:

tools/testing/selftests/drivers/net/hw/iou-zcrx.c:run_server() {
	total_conns = cfg_num_threads * cfg_num_threads;
	while (accepted < total_conns) {
		int idx = 0;
		connfd = accept(fd, NULL, NULL);
		...
		if (cfg_num_threads > 1)
			idx = find_thread_by_conn(ctxs, connfd);
	...
}

and a worker that ends up with no connections exits successfully:

tools/testing/selftests/drivers/net/hw/iou-zcrx.c:server_worker() {
	...
	while (ctx->nr_conns > 0 && gettimeofday_ms() < tstop)
		server_loop(ctx);

	if (ctx->nr_conns != 0)
		error(1, 0, "test failed: %d connections incomplete",
		      ctx->nr_conns);
	...
}

With nr_conns == 0 the loop and the check are both skipped, the process
exits 0, and rss_multiqueue passes while behaving exactly like the existing
single-queue rss variant.

Would it make sense to require L4 tcp6 hashing, fail when a worker in
multi-thread mode gets zero connections or zero bytes, and/or verify
io-uring page pool activity for both cfg.target and cfg.target + 1 from
Python? check_iou_rx_buf_len() and cfg.netnl.page_pool_get() already give
the per-queue view needed for the last part.

>  @ksft_variants([
>      KsftNamedVariant("single", single),
>      KsftNamedVariant("rss", rss),
> +    KsftNamedVariant("rss_multiqueue", rss_multiqueue),
>  ])
>  def test_zcrx(cfg, setup) -> None:
>      cfg.require_ipver('6')
>      _require_ntuple(cfg)
>  
> +    cfg.num_threads = 1
> +
>      setup(cfg)
> -    rx_cmd = f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} -q {cfg.target}"
> -    tx_cmd = f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} -l 12840"
> +
> +    rx_cmd = (f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} "
> +              f"-q {cfg.target} -t {cfg.num_threads}")
> +    tx_cmd = (f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} "
> +              f"-l 12840 -t {cfg.num_threads}")
>      with bkg(rx_cmd, exit_wait=True):
>          wait_port_listen(cfg.port, proto="tcp")
>          cmd(tx_cmd, host=cfg.remote)

[Severity: Medium]

Does wait_port_listen() still mean the receiver is armed once every
test_zcrx variant goes through the threaded server path?

wait_port_listen() in tools/testing/selftests/net/lib/py/utils.py only
polls /proc/net/tcp for TCP state 0A (LISTEN). In the threaded server the
listen() now happens before the setup barrier:

tools/testing/selftests/drivers/net/hw/iou-zcrx.c:run_server() {
	...
	/* pthread_create() loop for the workers */
	...
	if (listen(fd, 1024) < 0)
		error(1, 0, "listen()");

	pthread_barrier_wait(&setup_done);
	...
}

while the worker only reaches that barrier after the 32 MB mmap and
io_uring_register_ifq() done by setup_zcrx():

tools/testing/selftests/drivers/net/hw/iou-zcrx.c:server_worker() {
	io_uring_queue_init_params(512, &ctx->ring, &params);
	setup_zcrx(ctx);

	if (cfg_dry_run)
		return NULL;

	pthread_barrier_wait(ctx->setup_done);
	...
}

So the port is observable as LISTEN while the zcrx ifq is not yet
registered, and cmd(tx_cmd, host=cfg.remote) can start streaming into that
window.

Two consequences seem possible. Bytes arriving before
io_uring_register_ifq() land in ordinary driver pages and
io_zcrx_recv_frag() falls back to io_zcrx_copy_frag(), so the payload check
still succeeds while the zero-copy path is not exercised.

Also, test_zcrx_large_chunks() calls check_iou_rx_buf_len() right after
wait_port_listen(), which raises when the pool is not there yet:

tools/testing/selftests/drivers/net/hw/iou-zcrx.py:check_iou_rx_buf_len() {
    ...
    if len(pools) != 1:
        raise Exception(f"Expected 1 io-uring page pool, found {len(pools)}")
    ...
}

Would moving listen(fd, 1024) to after pthread_barrier_wait(&setup_done)
restore the previous ordering, where the port only became observable once
zcrx registration had completed?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831-iou-zcrx-v6-0-02d1d012f0fd%40fastmail.com

      reply	other threads:[~2026-09-02 23:38 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 17:34 [PATCH net-next v6 0/6] selftests: net: make iou-zcrx tests multithreaded Juanlu Herrero
2026-08-31 17:34 ` [PATCH net-next v6 1/6] selftests: net: fix get_refill_ring_size() to use its local variable Juanlu Herrero
2026-08-31 18:09   ` David Wei
2026-08-31 17:34 ` [PATCH net-next v6 2/6] selftests: net: remove unused variable in process_recvzc() Juanlu Herrero
2026-08-31 18:09   ` David Wei
2026-08-31 17:34 ` [PATCH net-next v6 3/6] selftests: net: refactor server state into struct thread_ctx Juanlu Herrero
2026-08-31 17:34 ` [PATCH net-next v6 4/6] selftests: net: add multithread client support to iou-zcrx Juanlu Herrero
2026-09-02 23:38   ` [net-next,v6,4/6] " netdev-bot+sashiko
2026-08-31 17:34 ` [PATCH net-next v6 5/6] selftests: net: add multithread server " Juanlu Herrero
2026-08-31 18:08   ` David Wei
2026-09-02 23:38   ` [net-next,v6,5/6] " netdev-bot+sashiko
2026-09-03 11:06     ` Paolo Abeni
2026-09-03 20:47       ` Juanlu Herrero
2026-09-09 16:16     ` Bobby Eshleman
2026-09-09 18:47       ` Juanlu Herrero
2026-08-31 17:34 ` [PATCH net-next v6 6/6] selftests: net: add rss_multiqueue test variant " Juanlu Herrero
2026-09-02 23:38   ` netdev-bot+sashiko [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178839229826.3394541.7285066966620333885@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=asml.silence@gmail.com \
    --cc=dw@davidwei.uk \
    --cc=io-uring@vger.kernel.org \
    --cc=juanlu@fastmail.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=shuah@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.