mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
selftests: drv-net: add tests for napi IRQ affinity notifiers
Add tests to check that the napi retained the IRQ after down/up,
multiple changes in the number of rx queues and after
attaching/releasing XDP program.
Tested on ice and idpf:
# NETIF=<iface> tools/testing/selftests/drivers/net/hw/irq.py
KTAP version 1
1..4
ok 1 irq.check_irqs_reported
ok 2 irq.check_reconfig_queues
ok 3 irq.check_reconfig_xdp
ok 4 irq.check_down
# Totals: pass:4 fail:0 xfail:0 xpass:0 skip:0 error:0
Tested-by: Ahmed Zaki <ahmed.zaki@intel.com>
Link: https://patch.msgid.link/20250224232228.990783-7-ahmed.zaki@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
deab38f8f0
commit
185646a8a0
|
|
@ -10,6 +10,7 @@ TEST_PROGS = \
|
|||
ethtool_rmon.sh \
|
||||
hw_stats_l3.sh \
|
||||
hw_stats_l3_gre.sh \
|
||||
irq.py \
|
||||
loopback.sh \
|
||||
nic_link_layer.py \
|
||||
nic_performance.py \
|
||||
|
|
@ -34,9 +35,12 @@ TEST_INCLUDES := \
|
|||
# YNL files, must be before "include ..lib.mk"
|
||||
YNL_GEN_FILES := ncdevmem
|
||||
TEST_GEN_FILES += $(YNL_GEN_FILES)
|
||||
TEST_GEN_FILES += $(patsubst %.c,%.o,$(wildcard *.bpf.c))
|
||||
|
||||
include ../../../lib.mk
|
||||
|
||||
# YNL build
|
||||
YNL_GENS := ethtool netdev
|
||||
include ../../../net/ynl.mk
|
||||
|
||||
include ../../../net/bpf.mk
|
||||
|
|
|
|||
99
tools/testing/selftests/drivers/net/hw/irq.py
Executable file
99
tools/testing/selftests/drivers/net/hw/irq.py
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
from lib.py import ksft_run, ksft_exit
|
||||
from lib.py import ksft_ge, ksft_eq
|
||||
from lib.py import KsftSkipEx
|
||||
from lib.py import ksft_disruptive
|
||||
from lib.py import EthtoolFamily, NetdevFamily
|
||||
from lib.py import NetDrvEnv
|
||||
from lib.py import cmd, ip, defer
|
||||
|
||||
|
||||
def read_affinity(irq) -> str:
|
||||
with open(f'/proc/irq/{irq}/smp_affinity', 'r') as fp:
|
||||
return fp.read().lstrip("0,").strip()
|
||||
|
||||
|
||||
def write_affinity(irq, what) -> str:
|
||||
if what != read_affinity(irq):
|
||||
with open(f'/proc/irq/{irq}/smp_affinity', 'w') as fp:
|
||||
fp.write(what)
|
||||
|
||||
|
||||
def check_irqs_reported(cfg) -> None:
|
||||
""" Check that device reports IRQs for NAPI instances """
|
||||
napis = cfg.netnl.napi_get({"ifindex": cfg.ifindex}, dump=True)
|
||||
irqs = sum(['irq' in x for x in napis])
|
||||
|
||||
ksft_ge(irqs, 1)
|
||||
ksft_eq(irqs, len(napis))
|
||||
|
||||
|
||||
def _check_reconfig(cfg, reconfig_cb) -> None:
|
||||
napis = cfg.netnl.napi_get({"ifindex": cfg.ifindex}, dump=True)
|
||||
for n in reversed(napis):
|
||||
if 'irq' in n:
|
||||
break
|
||||
else:
|
||||
raise KsftSkipEx(f"Device has no NAPI with IRQ attribute (#napis: {len(napis)}")
|
||||
|
||||
old = read_affinity(n['irq'])
|
||||
# pick an affinity that's not the current one
|
||||
new = "3" if old != "3" else "5"
|
||||
write_affinity(n['irq'], new)
|
||||
defer(write_affinity, n['irq'], old)
|
||||
|
||||
reconfig_cb(cfg)
|
||||
|
||||
ksft_eq(read_affinity(n['irq']), new, comment="IRQ affinity changed after reconfig")
|
||||
|
||||
|
||||
def check_reconfig_queues(cfg) -> None:
|
||||
def reconfig(cfg) -> None:
|
||||
channels = cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifindex}})
|
||||
if channels['combined-count'] == 0:
|
||||
rx_type = 'rx'
|
||||
else:
|
||||
rx_type = 'combined'
|
||||
cur_queue_cnt = channels[f'{rx_type}-count']
|
||||
max_queue_cnt = channels[f'{rx_type}-max']
|
||||
|
||||
cmd(f"ethtool -L {cfg.ifname} {rx_type} 1")
|
||||
cmd(f"ethtool -L {cfg.ifname} {rx_type} {max_queue_cnt}")
|
||||
cmd(f"ethtool -L {cfg.ifname} {rx_type} {cur_queue_cnt}")
|
||||
|
||||
_check_reconfig(cfg, reconfig)
|
||||
|
||||
|
||||
def check_reconfig_xdp(cfg) -> None:
|
||||
def reconfig(cfg) -> None:
|
||||
ip(f"link set dev %s xdp obj %s sec xdp" %
|
||||
(cfg.ifname, cfg.rpath("xdp_dummy.bpf.o")))
|
||||
ip(f"link set dev %s xdp off" % cfg.ifname)
|
||||
|
||||
_check_reconfig(cfg, reconfig)
|
||||
|
||||
|
||||
@ksft_disruptive
|
||||
def check_down(cfg) -> None:
|
||||
def reconfig(cfg) -> None:
|
||||
ip("link set dev %s down" % cfg.ifname)
|
||||
ip("link set dev %s up" % cfg.ifname)
|
||||
|
||||
_check_reconfig(cfg, reconfig)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
with NetDrvEnv(__file__, nsim_test=False) as cfg:
|
||||
cfg.ethnl = EthtoolFamily()
|
||||
cfg.netnl = NetdevFamily()
|
||||
|
||||
ksft_run([check_irqs_reported, check_reconfig_queues,
|
||||
check_reconfig_xdp, check_down],
|
||||
args=(cfg, ))
|
||||
ksft_exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
13
tools/testing/selftests/drivers/net/hw/xdp_dummy.bpf.c
Normal file
13
tools/testing/selftests/drivers/net/hw/xdp_dummy.bpf.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define KBUILD_MODNAME "xdp_dummy"
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
SEC("xdp")
|
||||
int xdp_dummy_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
|
@ -58,14 +58,20 @@ class NetDrvEnv(NetDrvEnvBase):
|
|||
"""
|
||||
Class for a single NIC / host env, with no remote end
|
||||
"""
|
||||
def __init__(self, src_path, **kwargs):
|
||||
def __init__(self, src_path, nsim_test=None, **kwargs):
|
||||
super().__init__(src_path)
|
||||
|
||||
self._ns = None
|
||||
|
||||
if 'NETIF' in self.env:
|
||||
if nsim_test is True:
|
||||
raise KsftXfailEx("Test only works on netdevsim")
|
||||
|
||||
self.dev = ip("-d link show dev " + self.env['NETIF'], json=True)[0]
|
||||
else:
|
||||
if nsim_test is False:
|
||||
raise KsftXfailEx("Test does not work on netdevsim")
|
||||
|
||||
self._ns = NetdevSimDev(**kwargs)
|
||||
self.dev = self._ns.nsims[0].dev
|
||||
self.ifname = self.dev['ifname']
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user