From: Bobby Eshleman <bobbyeshleman@meta.com>
Add tests for devmem RX over a netkit device with a leased queue. This
is the same as the other devmem RX test except for ncdevmem executes in
a namespace, binds to a netkit, and skips the ethtool NIC configuration
steps (relying on the test runner for that setup).
The RX path is setup as the following:
RX Path
-------
Remote Physical NIC Netkit Host Netkit Guest (netns)
| | | |
|--- TCP send ------>| | |
|-------------------->| |
dmabuf |--- BPF redirect -->|
Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
---
tools/testing/selftests/drivers/net/hw/Makefile | 1 +
.../testing/selftests/drivers/net/hw/nk_devmem.py | 104 +++++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile
index 91df028abfc0..3cd68e06f592 100644
--- a/tools/testing/selftests/drivers/net/hw/Makefile
+++ b/tools/testing/selftests/drivers/net/hw/Makefile
@@ -32,6 +32,7 @@ TEST_PROGS = \
irq.py \
loopback.sh \
nic_timestamp.py \
+ nk_devmem.py \
nk_netns.py \
pp_alloc_fail.py \
rss_api.py \
diff --git a/tools/testing/selftests/drivers/net/hw/nk_devmem.py b/tools/testing/selftests/drivers/net/hw/nk_devmem.py
new file mode 100755
index 000000000000..0a66ff85db9d
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/nk_devmem.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+"""Test devmem TCP through netkit with queue leasing."""
+
+import re
+from os import path
+from lib.py import ksft_run, ksft_exit, ksft_eq, KsftSkipEx
+from lib.py import NetDrvContEnv, NetNSEnter, EthtoolFamily, NetdevFamily
+from lib.py import bkg, cmd, defer, ethtool, rand_port, wait_port_listen
+
+
+def set_flow_rule(cfg):
+ """Insert an ethtool flow rule steering traffic to the leased queue."""
+ output = ethtool(
+ f"-N {cfg.ifname} flow-type tcp6 dst-port {cfg.port}"
+ f" action {cfg.src_queue}"
+ ).stdout
+ values = re.search(r'ID (\d+)', output).group(1)
+ return int(values)
+
+
+def configure_nic(cfg):
+ """Common setup for devmem tests: channels, rings, RSS, queue lease."""
+ cfg.require_ipver('6')
+ ethnl = EthtoolFamily()
+
+ channels = ethnl.channels_get({'header': {'dev-index': cfg.ifindex}})
+ channels = channels['combined-count']
+ if channels < 2:
+ raise KsftSkipEx(
+ 'Test requires NETIF with at least 2 combined channels'
+ )
+
+ rings = ethnl.rings_get({'header': {'dev-index': cfg.ifindex}})
+ rx_rings = rings['rx']
+ hds_thresh = rings.get('hds-thresh', 0)
+ orig_data_split = rings.get('tcp-data-split', 'unknown')
+
+ ethnl.rings_set({'header': {'dev-index': cfg.ifindex},
+ 'tcp-data-split': 'enabled',
+ 'hds-thresh': 0,
+ 'rx': min(64, rx_rings)})
+ defer(ethnl.rings_set, {'header': {'dev-index': cfg.ifindex},
+ 'tcp-data-split': orig_data_split,
+ 'hds-thresh': hds_thresh,
+ 'rx': rx_rings})
+
+ cfg.src_queue = channels - 1
+ ethtool(f"-X {cfg.ifname} equal {cfg.src_queue}")
+ defer(ethtool, f"-X {cfg.ifname} default")
+
+ if hasattr(cfg, 'nk_queue'):
+ return
+
+ with NetNSEnter(str(cfg.netns)):
+ netdevnl = NetdevFamily()
+ lease_result = netdevnl.queue_create(
+ {
+ "ifindex": cfg.nk_guest_ifindex,
+ "type": "rx",
+ "lease": {
+ "ifindex": cfg.ifindex,
+ "queue": {"id": cfg.src_queue, "type": "rx"},
+ "netns-id": 0,
+ },
+ }
+ )
+ cfg.nk_queue = lease_result['id']
+
+
+def test_devmem(cfg) -> None:
+ """Test devmem RX: send from remote, receive on netkit guest."""
+ configure_nic(cfg)
+
+ flow_rule_id = set_flow_rule(cfg)
+ defer(ethtool, f"-N {cfg.ifname} delete {flow_rule_id}")
+
+ rx_cmd = (f"ip netns exec {cfg.netns.name} {cfg.bin_local}"
+ f" -l -f {cfg._nk_guest_ifname} -s {cfg.nk_guest_ipv6}"
+ f" -p {cfg.port} -t {cfg.nk_queue} -q 1 -v 7 -n")
+ socat = f"socat -u - TCP6:[{cfg.nk_guest_ipv6}]:{cfg.port}"
+
+ with bkg(rx_cmd, exit_wait=True) as ncdevmem_rx:
+ wait_port_listen(cfg.port, proto="tcp", ns=cfg.netns)
+ cmd(f"yes $(echo -e \x01\x02\x03\x04\x05\x06) | head -c 1K"
+ f" | {socat}",
+ host=cfg.remote, shell=True)
+
+ ksft_eq(ncdevmem_rx.ret, 0)
+
+
+def main() -> None:
+ """Run netkit devmem tests."""
+ with NetDrvContEnv(__file__, rxqueues=2) as cfg:
+ cfg.bin_local = path.abspath(
+ path.dirname(__file__) + "/ncdevmem"
+ )
+ cfg.port = rand_port()
+ ksft_run([test_devmem], args=(cfg,))
+ ksft_exit()
+
+
+if __name__ == "__main__":
+ main()
--
2.52.0
On 03/16, Bobby Eshleman wrote: > From: Bobby Eshleman <bobbyeshleman@meta.com> > > Add tests for devmem RX over a netkit device with a leased queue. This > is the same as the other devmem RX test except for ncdevmem executes in > a namespace, binds to a netkit, and skips the ethtool NIC configuration > steps (relying on the test runner for that setup). > > The RX path is setup as the following: > > RX Path > ------- > > Remote Physical NIC Netkit Host Netkit Guest (netns) > | | | | > |--- TCP send ------>| | | > |-------------------->| | > dmabuf |--- BPF redirect -->| > Is it too messy to parametrize the existing test to run both with and without the namespaces? Feels like should be somewhat doable in python?
On Tue, Mar 17, 2026 at 05:08:20PM -0700, Stanislav Fomichev wrote:
> On 03/16, Bobby Eshleman wrote:
> > From: Bobby Eshleman <bobbyeshleman@meta.com>
> >
> > Add tests for devmem RX over a netkit device with a leased queue. This
> > is the same as the other devmem RX test except for ncdevmem executes in
> > a namespace, binds to a netkit, and skips the ethtool NIC configuration
> > steps (relying on the test runner for that setup).
> >
> > The RX path is setup as the following:
> >
> > RX Path
> > -------
> >
> > Remote Physical NIC Netkit Host Netkit Guest (netns)
> > | | | |
> > |--- TCP send ------>| | |
> > |-------------------->| |
> > dmabuf |--- BPF redirect -->|
> >
>
> Is it too messy to parametrize the existing test to run both with and
> without the namespaces? Feels like should be somewhat doable in python?
IIUC, we could have main() do something like:
for env [NetDrvContEnv, NetDrvEpEnv]:
with env as cfg:
[...]
ksft_run(tests, args=(cfg,))
And then the tests could call helpers that check cfg.netns to use the
nk_{guest,host}_ip6 addresses when true, otherwise use the regular
addresses?
It should be doable if I'm following your drift.
Best,
Bobby
On 03/17, Bobby Eshleman wrote:
> On Tue, Mar 17, 2026 at 05:08:20PM -0700, Stanislav Fomichev wrote:
> > On 03/16, Bobby Eshleman wrote:
> > > From: Bobby Eshleman <bobbyeshleman@meta.com>
> > >
> > > Add tests for devmem RX over a netkit device with a leased queue. This
> > > is the same as the other devmem RX test except for ncdevmem executes in
> > > a namespace, binds to a netkit, and skips the ethtool NIC configuration
> > > steps (relying on the test runner for that setup).
> > >
> > > The RX path is setup as the following:
> > >
> > > RX Path
> > > -------
> > >
> > > Remote Physical NIC Netkit Host Netkit Guest (netns)
> > > | | | |
> > > |--- TCP send ------>| | |
> > > |-------------------->| |
> > > dmabuf |--- BPF redirect -->|
> > >
> >
> > Is it too messy to parametrize the existing test to run both with and
> > without the namespaces? Feels like should be somewhat doable in python?
>
> IIUC, we could have main() do something like:
>
> for env [NetDrvContEnv, NetDrvEpEnv]:
> with env as cfg:
> [...]
> ksft_run(tests, args=(cfg,))
>
>
> And then the tests could call helpers that check cfg.netns to use the
> nk_{guest,host}_ip6 addresses when true, otherwise use the regular
> addresses?
>
> It should be doable if I'm following your drift.
Yeah, yeah, this plus some small changes here and there (to pass your
new -n in the netns mode for example).
On Wed, Mar 18, 2026 at 07:59:57AM -0700, Stanislav Fomichev wrote:
> On 03/17, Bobby Eshleman wrote:
> > On Tue, Mar 17, 2026 at 05:08:20PM -0700, Stanislav Fomichev wrote:
> > > On 03/16, Bobby Eshleman wrote:
> > > > From: Bobby Eshleman <bobbyeshleman@meta.com>
> > > >
> > > > Add tests for devmem RX over a netkit device with a leased queue. This
> > > > is the same as the other devmem RX test except for ncdevmem executes in
> > > > a namespace, binds to a netkit, and skips the ethtool NIC configuration
> > > > steps (relying on the test runner for that setup).
> > > >
> > > > The RX path is setup as the following:
> > > >
> > > > RX Path
> > > > -------
> > > >
> > > > Remote Physical NIC Netkit Host Netkit Guest (netns)
> > > > | | | |
> > > > |--- TCP send ------>| | |
> > > > |-------------------->| |
> > > > dmabuf |--- BPF redirect -->|
> > > >
> > >
> > > Is it too messy to parametrize the existing test to run both with and
> > > without the namespaces? Feels like should be somewhat doable in python?
> >
> > IIUC, we could have main() do something like:
> >
> > for env [NetDrvContEnv, NetDrvEpEnv]:
> > with env as cfg:
> > [...]
> > ksft_run(tests, args=(cfg,))
> >
> >
> > And then the tests could call helpers that check cfg.netns to use the
> > nk_{guest,host}_ip6 addresses when true, otherwise use the regular
> > addresses?
> >
> > It should be doable if I'm following your drift.
>
> Yeah, yeah, this plus some small changes here and there (to pass your
> new -n in the netns mode for example).
Sounds good, I'll give it a look.
On Wed, 18 Mar 2026 09:21:32 -0700 Bobby Eshleman wrote:
> > > IIUC, we could have main() do something like:
> > >
> > > for env [NetDrvContEnv, NetDrvEpEnv]:
> > > with env as cfg:
> > > [...]
> > > ksft_run(tests, args=(cfg,))
> > >
> > >
> > > And then the tests could call helpers that check cfg.netns to use the
> > > nk_{guest,host}_ip6 addresses when true, otherwise use the regular
> > > addresses?
> > >
> > > It should be doable if I'm following your drift.
> >
> > Yeah, yeah, this plus some small changes here and there (to pass your
> > new -n in the netns mode for example).
>
> Sounds good, I'll give it a look.
I haven't actually looked but double check ksft_run can actually
be called multiple times. We may have some global state :S
On Wed, Mar 18, 2026 at 04:10:10PM -0700, Jakub Kicinski wrote:
> On Wed, 18 Mar 2026 09:21:32 -0700 Bobby Eshleman wrote:
> > > > IIUC, we could have main() do something like:
> > > >
> > > > for env [NetDrvContEnv, NetDrvEpEnv]:
> > > > with env as cfg:
> > > > [...]
> > > > ksft_run(tests, args=(cfg,))
> > > >
> > > >
> > > > And then the tests could call helpers that check cfg.netns to use the
> > > > nk_{guest,host}_ip6 addresses when true, otherwise use the regular
> > > > addresses?
> > > >
> > > > It should be doable if I'm following your drift.
> > >
> > > Yeah, yeah, this plus some small changes here and there (to pass your
> > > new -n in the netns mode for example).
> >
> > Sounds good, I'll give it a look.
>
> I haven't actually looked but double check ksft_run can actually
> be called multiple times. We may have some global state :S
The result is global, but accumulates correctly.
But the tap output doubles:
TAP version 13
1..2
ok 1 devmem.check_nk_rx
ok 2 devmem.check_nk_tx
# Totals: pass:2 ...
TAP version 13
1..4
ok 1 devmem.check_rx
ok 2 devmem.check_tx
ok 3 devmem.check_tx_chunks
ok 4 devmem.check_rx_hds
# Totals: pass:4 ...
Not sure what outside parsing expects yet...
© 2016 - 2026 Red Hat, Inc.