Skip to content

Commit 1d0dc85

Browse files
wdebruijkuba-moo
authored andcommitted
selftests: drv-net: add checksum tests
Run tools/testing/selftest/net/csum.c as part of drv-net. This binary covers multiple scenarios, based on arguments given, for both IPv4 and IPv6: - Accept UDP correct checksum - Detect UDP invalid checksum - Accept TCP correct checksum - Detect TCP invalid checksum - Transmit UDP: basic checksum offload - Transmit UDP: zero checksum conversion The test direction is reversed between receive and transmit tests, so that the NIC under test is always the local machine. In total this adds up to 12 testcases, with more to follow. For conciseness, I replaced individual functions with a function factory. Also detect hardware offload feature availability using Ethtool netlink and skip tests when either feature is off. This need may be common for offload feature tests and eventually deserving of a thin wrapper in lib.py. Missing are the PF_PACKET based send tests ('-P'). These use virtio_net_hdr to program hardware checksum offload. Which requires looking up the local MAC address and (harder) the MAC of the next hop. I'll have to give it some though how to do that robustly and where that code would belong. Tested: make -C tools/testing/selftests/ \ TARGETS="drivers/net drivers/net/hw" \ install INSTALL_PATH=/tmp/ksft cd /tmp/ksft sudo NETIF=ens4 REMOTE_TYPE=ssh \ REMOTE_ARGS="[email protected]" \ LOCAL_V4="10.40.0.1" \ REMOTE_V4="10.40.0.2" \ ./run_kselftest.sh -t drivers/net/hw:csum.py Signed-off-by: Willem de Bruijn <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 58a4ff5 commit 1d0dc85

File tree

7 files changed

+132
-2
lines changed

7 files changed

+132
-2
lines changed

tools/testing/selftests/drivers/net/hw/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0+ OR MIT
22

33
TEST_PROGS = \
4+
csum.py \
45
devlink_port_split.py \
56
ethtool.sh \
67
ethtool_extended_state.sh \
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: GPL-2.0
3+
4+
"""Run the tools/testing/selftests/net/csum testsuite."""
5+
6+
from os import path
7+
8+
from lib.py import ksft_run, ksft_exit, KsftSkipEx
9+
from lib.py import EthtoolFamily, NetDrvEpEnv
10+
from lib.py import bkg, cmd, wait_port_listen
11+
12+
def test_receive(cfg, ipv4=False, extra_args=None):
13+
"""Test local nic checksum receive. Remote host sends crafted packets."""
14+
if not cfg.have_rx_csum:
15+
raise KsftSkipEx(f"Test requires rx checksum offload on {cfg.ifname}")
16+
17+
if ipv4:
18+
ip_args = f"-4 -S {cfg.remote_v4} -D {cfg.v4}"
19+
else:
20+
ip_args = f"-6 -S {cfg.remote_v6} -D {cfg.v6}"
21+
22+
rx_cmd = f"{cfg.bin_local} -i {cfg.ifname} -n 100 {ip_args} -r 1 -R {extra_args}"
23+
tx_cmd = f"{cfg.bin_remote} -i {cfg.ifname} -n 100 {ip_args} -r 1 -T {extra_args}"
24+
25+
with bkg(rx_cmd, exit_wait=True):
26+
wait_port_listen(34000, proto="udp")
27+
cmd(tx_cmd, host=cfg.remote)
28+
29+
30+
def test_transmit(cfg, ipv4=False, extra_args=None):
31+
"""Test local nic checksum transmit. Remote host verifies packets."""
32+
if (not cfg.have_tx_csum_generic and
33+
not (cfg.have_tx_csum_ipv4 and ipv4) and
34+
not (cfg.have_tx_csum_ipv6 and not ipv4)):
35+
raise KsftSkipEx(f"Test requires tx checksum offload on {cfg.ifname}")
36+
37+
if ipv4:
38+
ip_args = f"-4 -S {cfg.v4} -D {cfg.remote_v4}"
39+
else:
40+
ip_args = f"-6 -S {cfg.v6} -D {cfg.remote_v6}"
41+
42+
# Cannot randomize input when calculating zero checksum
43+
if extra_args != "-U -Z":
44+
extra_args += " -r 1"
45+
46+
rx_cmd = f"{cfg.bin_remote} -i {cfg.ifname} -L 1 -n 100 {ip_args} -R {extra_args}"
47+
tx_cmd = f"{cfg.bin_local} -i {cfg.ifname} -L 1 -n 100 {ip_args} -T {extra_args}"
48+
49+
with bkg(rx_cmd, host=cfg.remote, exit_wait=True):
50+
wait_port_listen(34000, proto="udp", host=cfg.remote)
51+
cmd(tx_cmd)
52+
53+
54+
def test_builder(name, cfg, ipv4=False, tx=False, extra_args=""):
55+
"""Construct specific tests from the common template.
56+
57+
Most tests follow the same basic pattern, differing only in
58+
Direction of the test and optional flags passed to csum."""
59+
def f(cfg):
60+
if ipv4:
61+
cfg.require_v4()
62+
else:
63+
cfg.require_v6()
64+
65+
if tx:
66+
test_transmit(cfg, ipv4, extra_args)
67+
else:
68+
test_receive(cfg, ipv4, extra_args)
69+
70+
if ipv4:
71+
f.__name__ = "ipv4_" + name
72+
else:
73+
f.__name__ = "ipv6_" + name
74+
return f
75+
76+
77+
def check_nic_features(cfg) -> None:
78+
"""Test whether Tx and Rx checksum offload are enabled.
79+
80+
If the device under test has either off, then skip the relevant tests."""
81+
cfg.have_tx_csum_generic = False
82+
cfg.have_tx_csum_ipv4 = False
83+
cfg.have_tx_csum_ipv6 = False
84+
cfg.have_rx_csum = False
85+
86+
ethnl = EthtoolFamily()
87+
features = ethnl.features_get({"header": {"dev-index": cfg.ifindex}})
88+
for f in features["active"]["bits"]["bit"]:
89+
if f["name"] == "tx-checksum-ip-generic":
90+
cfg.have_tx_csum_generic = True
91+
elif f["name"] == "tx-checksum-ipv4":
92+
cfg.have_tx_csum_ipv4 = True
93+
elif f["name"] == "tx-checksum-ipv6":
94+
cfg.have_tx_csum_ipv6 = True
95+
elif f["name"] == "rx-checksum":
96+
cfg.have_rx_csum = True
97+
98+
99+
def main() -> None:
100+
with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
101+
check_nic_features(cfg)
102+
103+
cfg.bin_local = path.abspath(path.dirname(__file__) + "/../../../net/lib/csum")
104+
cfg.bin_remote = cfg.remote.deploy(cfg.bin_local)
105+
106+
cases = []
107+
for ipv4 in [True, False]:
108+
cases.append(test_builder("rx_tcp", cfg, ipv4, False, "-t"))
109+
cases.append(test_builder("rx_tcp_invalid", cfg, ipv4, False, "-t -E"))
110+
111+
cases.append(test_builder("rx_udp", cfg, ipv4, False, ""))
112+
cases.append(test_builder("rx_udp_invalid", cfg, ipv4, False, "-E"))
113+
114+
cases.append(test_builder("tx_udp_csum_offload", cfg, ipv4, True, "-U"))
115+
cases.append(test_builder("tx_udp_zero_checksum", cfg, ipv4, True, "-U -Z"))
116+
117+
ksft_run(cases=cases, args=(cfg, ))
118+
ksft_exit()
119+
120+
121+
if __name__ == "__main__":
122+
main()

tools/testing/selftests/net/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
bind_bhash
33
bind_timewait
44
bind_wildcard
5-
csum
65
cmsg_sender
76
diag_uid
87
fin_ack_lat

tools/testing/selftests/net/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ TEST_PROGS += test_ingress_egress_chaining.sh
8181
TEST_GEN_PROGS += so_incoming_cpu
8282
TEST_PROGS += sctp_vrf.sh
8383
TEST_GEN_FILES += sctp_hello
84-
TEST_GEN_FILES += csum
8584
TEST_GEN_FILES += ip_local_port_range
8685
TEST_GEN_FILES += bind_wildcard
8786
TEST_PROGS += test_vxlan_mdb.sh
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
csum
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
# SPDX-License-Identifier: GPL-2.0
22

3+
CFLAGS = -Wall -Wl,--no-as-needed -O2 -g
4+
CFLAGS += -I../../../../../usr/include/ $(KHDR_INCLUDES)
5+
# Additional include paths needed by kselftest.h
6+
CFLAGS += -I../../
7+
38
TEST_FILES := ../../../../../Documentation/netlink/specs
49
TEST_FILES += ../../../../net/ynl
510

11+
TEST_GEN_FILES += csum
12+
613
TEST_INCLUDES := $(wildcard py/*.py)
714

815
include ../../lib.mk

0 commit comments

Comments
 (0)