* [PATCH net-next] selftests/net: Add two xdp tests to xdp.py
@ 2026-04-01 5:27 Leon Hwang
2026-04-01 20:20 ` Jakub Kicinski
0 siblings, 1 reply; 4+ messages in thread
From: Leon Hwang @ 2026-04-01 5:27 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Shuah Khan, Alexei Starovoitov, Daniel Borkmann,
Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
linux-kselftest, linux-kernel, bpf, Leon Hwang
In "bpf: Disallow freplace on XDP with mismatched xdp_has_frags values" [1],
these two XDP tests are suggested to add to xdp.py.
1. Verify the failure of attaching non-frag-capable prog to mtu=9k driver.
2. Verify the failure of updating frag-capable prog with non-frag-capable
prog, when the frag-capable prog attaches to mtu=9k driver.
They have been verified against Mellanox CX6 and Intel 82599ES NICs.
With dropping other tests, here are the test logs.
# ethtool -i eth0
driver: mlx5_core
version: 6.19.0-061900-generic
# NETIF=eth0 python3 xdp.py
TAP version 13
1..2
ok 1 xdp.test_xdp_native_attach_sb_to_mb
ok 2 xdp.test_xdp_native_update_mb_to_sb
# Totals: pass:2 fail:0 xfail:0 xpass:0 skip:0 error:0
# ethtool -i eth0
driver: ixgbe
version: 6.19.0-061900-generic
# NETIF=eth0 python3 xdp.py
TAP version 13
1..2
ok 1 xdp.test_xdp_native_attach_sb_to_mb # SKIP RTNETLINK answers: Invalid argument
ok 2 xdp.test_xdp_native_update_mb_to_sb # SKIP RTNETLINK answers: Invalid argument
# Totals: pass:0 fail:0 xfail:0 xpass:0 skip:2 error:0
Links:
[1] https://lore.kernel.org/bpf/20260326124205.1a3bb825@kernel.org/
Signed-off-by: Leon Hwang <leon.huangfu@shopee.com>
---
tools/testing/selftests/drivers/net/xdp.py | 53 +++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/drivers/net/xdp.py b/tools/testing/selftests/drivers/net/xdp.py
index d86446569f89..fe34b491778b 100755
--- a/tools/testing/selftests/drivers/net/xdp.py
+++ b/tools/testing/selftests/drivers/net/xdp.py
@@ -13,7 +13,7 @@ from enum import Enum
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, ksft_ne, ksft_pr
from lib.py import KsftNamedVariant, ksft_variants
-from lib.py import KsftFailEx, NetDrvEpEnv
+from lib.py import KsftFailEx, KsftSkipEx, NetDrvEpEnv
from lib.py import EthtoolFamily, NetdevFamily, NlError
from lib.py import bkg, cmd, rand_port, wait_port_listen
from lib.py import ip, defer
@@ -693,6 +693,55 @@ def test_xdp_native_qstats(cfg, act):
ksft_ge(after['tx-packets'], before['tx-packets'])
+def _set_jumbo_mtu(cfg, mtu):
+ ip(f"link set dev {cfg.ifname} mtu {mtu}")
+ defer(ip, f"link set dev {cfg.ifname} mtu 1500")
+
+
+def _exec_cmd(cfg, obj, sec, ip_opts=""):
+ return cmd(f"ip {ip_opts} link set dev {cfg.ifname} xdpdrv obj {obj} sec {sec}", shell=True, fail=False)
+
+
+def test_xdp_native_attach_sb_to_mb(cfg):
+ obj = cfg.net_lib_dir / "xdp_dummy.bpf.o"
+ mtu = 9000
+
+ _set_jumbo_mtu(cfg, mtu)
+
+ probe = _exec_cmd(cfg, obj, "xdp.frags")
+ if probe.ret != 0:
+ output = probe.stderr.strip() or probe.stdout.strip()
+ raise KsftSkipEx(output or "device does not support multi-buffer XDP")
+
+ ip(f"link set dev {cfg.ifname} xdpdrv off")
+
+ probe = _exec_cmd(cfg, obj, "xdp")
+ if probe.ret == 0:
+ ip(f"link set dev {cfg.ifname} xdpdrv off")
+ raise KsftFailEx(f"driver unexpectedly allows non-multi-buffer XDP at MTU {mtu}")
+
+
+def test_xdp_native_update_mb_to_sb(cfg):
+ obj = cfg.net_lib_dir / "xdp_dummy.bpf.o"
+
+ _set_jumbo_mtu(cfg, 9000)
+
+ attach = _exec_cmd(cfg, obj, "xdp.frags")
+ if attach.ret != 0:
+ output = attach.stderr.strip() or attach.stdout.strip()
+ raise KsftSkipEx(output or "device does not support multi-buffer XDP")
+
+ defer(ip, f"link set dev {cfg.ifname} xdpdrv off")
+
+ update1 = _exec_cmd(cfg, obj, "xdp.frags", "-force")
+ if update1.ret != 0:
+ raise KsftFailEx("device fails to update multi-buffer XDP")
+
+ update2 = _exec_cmd(cfg, obj, "xdp", "-force")
+ if update2.ret == 0:
+ raise KsftFailEx("device unexpectedly updates non-multi-buffer XDP")
+
+
def main():
"""
Main function to execute the XDP tests.
@@ -718,6 +767,8 @@ def main():
test_xdp_native_adjst_head_grow_data,
test_xdp_native_adjst_head_shrnk_data,
test_xdp_native_qstats,
+ test_xdp_native_attach_sb_to_mb,
+ test_xdp_native_update_mb_to_sb,
],
args=(cfg,))
ksft_exit()
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH net-next] selftests/net: Add two xdp tests to xdp.py
2026-04-01 5:27 [PATCH net-next] selftests/net: Add two xdp tests to xdp.py Leon Hwang
@ 2026-04-01 20:20 ` Jakub Kicinski
2026-04-02 3:22 ` Leon Hwang
0 siblings, 1 reply; 4+ messages in thread
From: Jakub Kicinski @ 2026-04-01 20:20 UTC (permalink / raw)
To: Leon Hwang
Cc: netdev, Andrew Lunn, David S . Miller, Eric Dumazet, Paolo Abeni,
Shuah Khan, Alexei Starovoitov, Daniel Borkmann,
Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
linux-kselftest, linux-kernel, bpf
On Wed, 1 Apr 2026 13:27:46 +0800 Leon Hwang wrote:
> In "bpf: Disallow freplace on XDP with mismatched xdp_has_frags values" [1],
> these two XDP tests are suggested to add to xdp.py.
>
> 1. Verify the failure of attaching non-frag-capable prog to mtu=9k driver.
> 2. Verify the failure of updating frag-capable prog with non-frag-capable
> prog, when the frag-capable prog attaches to mtu=9k driver.
>
> They have been verified against Mellanox CX6 and Intel 82599ES NICs.
>
> With dropping other tests, here are the test logs.
>
> # ethtool -i eth0
> driver: mlx5_core
> version: 6.19.0-061900-generic
>
> # NETIF=eth0 python3 xdp.py
> TAP version 13
> 1..2
> ok 1 xdp.test_xdp_native_attach_sb_to_mb
> ok 2 xdp.test_xdp_native_update_mb_to_sb
> # Totals: pass:2 fail:0 xfail:0 xpass:0 skip:0 error:0
>
> # ethtool -i eth0
> driver: ixgbe
> version: 6.19.0-061900-generic
>
> # NETIF=eth0 python3 xdp.py
> TAP version 13
> 1..2
> ok 1 xdp.test_xdp_native_attach_sb_to_mb # SKIP RTNETLINK answers: Invalid argument
> ok 2 xdp.test_xdp_native_update_mb_to_sb # SKIP RTNETLINK answers: Invalid argument
> # Totals: pass:0 fail:0 xfail:0 xpass:0 skip:2 error:0
>
> Links:
> [1] https://lore.kernel.org/bpf/20260326124205.1a3bb825@kernel.org/
Thanks for working on it!
> diff --git a/tools/testing/selftests/drivers/net/xdp.py b/tools/testing/selftests/drivers/net/xdp.py
> index d86446569f89..fe34b491778b 100755
> --- a/tools/testing/selftests/drivers/net/xdp.py
> +++ b/tools/testing/selftests/drivers/net/xdp.py
> @@ -13,7 +13,7 @@ from enum import Enum
>
> from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, ksft_ne, ksft_pr
> from lib.py import KsftNamedVariant, ksft_variants
> -from lib.py import KsftFailEx, NetDrvEpEnv
> +from lib.py import KsftFailEx, KsftSkipEx, NetDrvEpEnv
> from lib.py import EthtoolFamily, NetdevFamily, NlError
> from lib.py import bkg, cmd, rand_port, wait_port_listen
> from lib.py import ip, defer
> @@ -693,6 +693,55 @@ def test_xdp_native_qstats(cfg, act):
> ksft_ge(after['tx-packets'], before['tx-packets'])
>
>
> +def _set_jumbo_mtu(cfg, mtu):
> + ip(f"link set dev {cfg.ifname} mtu {mtu}")
> + defer(ip, f"link set dev {cfg.ifname} mtu 1500")
cfg records the original MTU, you can copy this line from here:
https://elixir.bootlin.com/linux/v7.0-rc6/source/tools/testing/selftests/drivers/net/gro.py#L88
> +def _exec_cmd(cfg, obj, sec, ip_opts=""):
> + return cmd(f"ip {ip_opts} link set dev {cfg.ifname} xdpdrv obj {obj} sec {sec}", shell=True, fail=False)
We shouldn't need the shell=True where?
Also it's probably cleaner to pass fail as optional argument here
so that you can let this throw an exception in the cases we expect
to succeed instead of having to check in the caller explicitly
> +def test_xdp_native_attach_sb_to_mb(cfg):
> + obj = cfg.net_lib_dir / "xdp_dummy.bpf.o"
> + mtu = 9000
> +
> + _set_jumbo_mtu(cfg, mtu)
> +
> + probe = _exec_cmd(cfg, obj, "xdp.frags")
> + if probe.ret != 0:
> + output = probe.stderr.strip() or probe.stdout.strip()
> + raise KsftSkipEx(output or "device does not support multi-buffer XDP")
May be simpler and cleaner to print the whole command separately:
if probe.ret != 0:
ksft_pr(probe)
raise KsftSkipEx("device does not support multi-buffer XDP")
> + ip(f"link set dev {cfg.ifname} xdpdrv off")
> +
> + probe = _exec_cmd(cfg, obj, "xdp")
> + if probe.ret == 0:
> + ip(f"link set dev {cfg.ifname} xdpdrv off")
> + raise KsftFailEx(f"driver unexpectedly allows non-multi-buffer XDP at MTU {mtu}")
Hm, TBH I don't think this sb_to_mb case is adding any coverage.
Let's just add the test case below?
> +def test_xdp_native_update_mb_to_sb(cfg):
> + obj = cfg.net_lib_dir / "xdp_dummy.bpf.o"
> +
> + _set_jumbo_mtu(cfg, 9000)
> +
> + attach = _exec_cmd(cfg, obj, "xdp.frags")
> + if attach.ret != 0:
> + output = attach.stderr.strip() or attach.stdout.strip()
> + raise KsftSkipEx(output or "device does not support multi-buffer XDP")
> +
> + defer(ip, f"link set dev {cfg.ifname} xdpdrv off")
> +
> + update1 = _exec_cmd(cfg, obj, "xdp.frags", "-force")
> + if update1.ret != 0:
> + raise KsftFailEx("device fails to update multi-buffer XDP")
> +
> + update2 = _exec_cmd(cfg, obj, "xdp", "-force")
> + if update2.ret == 0:
> + raise KsftFailEx("device unexpectedly updates non-multi-buffer XDP")
--
pw-bot: cr
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net-next] selftests/net: Add two xdp tests to xdp.py
2026-04-01 20:20 ` Jakub Kicinski
@ 2026-04-02 3:22 ` Leon Hwang
2026-04-02 14:35 ` Jakub Kicinski
0 siblings, 1 reply; 4+ messages in thread
From: Leon Hwang @ 2026-04-02 3:22 UTC (permalink / raw)
To: Jakub Kicinski, Leon Hwang
Cc: netdev, Andrew Lunn, David S . Miller, Eric Dumazet, Paolo Abeni,
Shuah Khan, Alexei Starovoitov, Daniel Borkmann,
Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
linux-kselftest, linux-kernel, bpf
On 2/4/26 04:20, Jakub Kicinski wrote:
> On Wed, 1 Apr 2026 13:27:46 +0800 Leon Hwang wrote:
[...]
>> +def _set_jumbo_mtu(cfg, mtu):
>> + ip(f"link set dev {cfg.ifname} mtu {mtu}")
>> + defer(ip, f"link set dev {cfg.ifname} mtu 1500")
>
> cfg records the original MTU, you can copy this line from here:
> https://elixir.bootlin.com/linux/v7.0-rc6/source/tools/testing/selftests/drivers/net/gro.py#L88
>
Sure, will use cfg.dev['mtu'] instead of hard code 1500.
>> +def _exec_cmd(cfg, obj, sec, ip_opts=""):
>> + return cmd(f"ip {ip_opts} link set dev {cfg.ifname} xdpdrv obj {obj} sec {sec}", shell=True, fail=False)
>
> We shouldn't need the shell=True where?
> Also it's probably cleaner to pass fail as optional argument here
> so that you can let this throw an exception in the cases we expect
> to succeed instead of having to check in the caller explicitly
>
Right, shell=True is unnecessary here. Will drop it.
Will pass fail as optional arg to let it fail if fail=True.
>> +def test_xdp_native_attach_sb_to_mb(cfg):
>> + obj = cfg.net_lib_dir / "xdp_dummy.bpf.o"
>> + mtu = 9000
>> +
>> + _set_jumbo_mtu(cfg, mtu)
>> +
>> + probe = _exec_cmd(cfg, obj, "xdp.frags")
>> + if probe.ret != 0:
>> + output = probe.stderr.strip() or probe.stdout.strip()
>> + raise KsftSkipEx(output or "device does not support multi-buffer XDP")
>
> May be simpler and cleaner to print the whole command separately:
>
> if probe.ret != 0:
> ksft_pr(probe)
> raise KsftSkipEx("device does not support multi-buffer XDP")
>
Ack.
>> + ip(f"link set dev {cfg.ifname} xdpdrv off")
>> +
>> + probe = _exec_cmd(cfg, obj, "xdp")
>> + if probe.ret == 0:
>> + ip(f"link set dev {cfg.ifname} xdpdrv off")
>> + raise KsftFailEx(f"driver unexpectedly allows non-multi-buffer XDP at MTU {mtu}")
>
> Hm, TBH I don't think this sb_to_mb case is adding any coverage.
> Let's just add the test case below?
>
Ok. Will drop this case.
>
>> +def test_xdp_native_update_mb_to_sb(cfg):
>> + obj = cfg.net_lib_dir / "xdp_dummy.bpf.o"
>> +
>> + _set_jumbo_mtu(cfg, 9000)
>> +
>> + attach = _exec_cmd(cfg, obj, "xdp.frags")
>> + if attach.ret != 0:
>> + output = attach.stderr.strip() or attach.stdout.strip()
>> + raise KsftSkipEx(output or "device does not support multi-buffer XDP")
>> +
>> + defer(ip, f"link set dev {cfg.ifname} xdpdrv off")
>> +
>> + update1 = _exec_cmd(cfg, obj, "xdp.frags", "-force")
>> + if update1.ret != 0:
>> + raise KsftFailEx("device fails to update multi-buffer XDP")
>> +
>> + update2 = _exec_cmd(cfg, obj, "xdp", "-force")
>> + if update2.ret == 0:
>> + raise KsftFailEx("device unexpectedly updates non-multi-buffer XDP")
From sashiko's review [1]:
On architectures with larger page sizes, such as 16KB or 64KB on ARM64 or
PowerPC, a 9000-byte packet can fit entirely within a single buffer. In
these environments, the driver might legally accept a non-frag XDP program,
which would lead to a false positive failure here.
WDYT?
[1]
https://sashiko.dev/#/patchset/20260401052746.314667-1-leon.huangfu%40shopee.com
Thanks,
Leon
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net-next] selftests/net: Add two xdp tests to xdp.py
2026-04-02 3:22 ` Leon Hwang
@ 2026-04-02 14:35 ` Jakub Kicinski
0 siblings, 0 replies; 4+ messages in thread
From: Jakub Kicinski @ 2026-04-02 14:35 UTC (permalink / raw)
To: Leon Hwang
Cc: Leon Hwang, netdev, Andrew Lunn, David S . Miller, Eric Dumazet,
Paolo Abeni, Shuah Khan, Alexei Starovoitov, Daniel Borkmann,
Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
linux-kselftest, linux-kernel, bpf
On Thu, 2 Apr 2026 11:22:15 +0800 Leon Hwang wrote:
> >> +def test_xdp_native_update_mb_to_sb(cfg):
> >> + obj = cfg.net_lib_dir / "xdp_dummy.bpf.o"
> >> +
> >> + _set_jumbo_mtu(cfg, 9000)
> >> +
> >> + attach = _exec_cmd(cfg, obj, "xdp.frags")
> >> + if attach.ret != 0:
> >> + output = attach.stderr.strip() or attach.stdout.strip()
> >> + raise KsftSkipEx(output or "device does not support multi-buffer XDP")
> >> +
> >> + defer(ip, f"link set dev {cfg.ifname} xdpdrv off")
> >> +
> >> + update1 = _exec_cmd(cfg, obj, "xdp.frags", "-force")
> >> + if update1.ret != 0:
> >> + raise KsftFailEx("device fails to update multi-buffer XDP")
> >> +
> >> + update2 = _exec_cmd(cfg, obj, "xdp", "-force")
> >> + if update2.ret == 0:
> >> + raise KsftFailEx("device unexpectedly updates non-multi-buffer XDP")
>
> From sashiko's review [1]:
>
> On architectures with larger page sizes, such as 16KB or 64KB on ARM64 or
> PowerPC, a 9000-byte packet can fit entirely within a single buffer. In
> these environments, the driver might legally accept a non-frag XDP program,
> which would lead to a false positive failure here.
Yes the test is indeed not checking all the corner cases, it should be:
# set mtu to 9k
# try attach xdp
# if ret == 0:
# return // must be 64k pages or something
# try attach xdp.frags
# if ret != 0:
# raise SKIP // driver doesn't support multi-buf
# defer xdp off
# try --froce switch to xdp
# if ret == 0:
# raise FAIL // replace is missing a check
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-04-02 14:35 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-01 5:27 [PATCH net-next] selftests/net: Add two xdp tests to xdp.py Leon Hwang
2026-04-01 20:20 ` Jakub Kicinski
2026-04-02 3:22 ` Leon Hwang
2026-04-02 14:35 ` Jakub Kicinski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox