History

selftests: drv-net: add test for RSS on flow label

Add a simple test for checking that RSS on flow label works, and that its rejected for IPv4 flows. # ./tools/testing/selftests/drivers/net/hw/rss_flow_label.py TAP version 13 1..2 ok 1 rss_flow_label.test_rss_flow_label ok 2 rss_flow_label.test_rss_flow_label_6only # Totals: pass:2 fail:0 xfail:0 xpass:0 skip:0 error:0

Jakub Kicinski committed 1 year ago

Commit 26dbe031 parent 46c0faa2 files · +168 −0Browse files

Unified · Split

2 files
  1. tools/testing/selftests/drivers/net/hw/Makefile +1 −0
  2. tools/testing/selftests/drivers/net/hw/rss_flow_label.py +167 −0
tools/testing/selftests/drivers/net/hw/Makefile+1−0
@@ -18,6 +18,7 @@ TEST_PROGS = \ · 17 unmodified lines
1818 pp_alloc_fail.py \
1919 rss_api.py \
2020 rss_ctx.py \
21+ rss_flow_label.py \
2122 rss_input_xfrm.py \
2223 tso.py \
2324 xsk_reconfig.py \
tools/testing/selftests/drivers/net/hw/rss_flow_label.py+167−0
@@ -0,0 +1,167 @@
1+#!/usr/bin/env python3
2+# SPDX-License-Identifier: GPL-2.0
3+
4+"""
5+Tests for RSS hashing on IPv6 Flow Label.
6+"""
7+
8+import glob
9+import os
10+import socket
11+from lib.py import CmdExitFailure
12+from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, ksft_in, \
13+ ksft_not_in, ksft_raises, KsftSkipEx
14+from lib.py import bkg, cmd, defer, fd_read_timeout, rand_port
15+from lib.py import NetDrvEpEnv
16+
17+
18+def _check_system(cfg):
19+ if not hasattr(socket, "SO_INCOMING_CPU"):
20+ raise KsftSkipEx("socket.SO_INCOMING_CPU was added in Python 3.11")
21+
22+ qcnt = len(glob.glob(f"/sys/class/net/{cfg.ifname}/queues/rx-*"))
23+ if qcnt < 2:
24+ raise KsftSkipEx(f"Local has only {qcnt} queues")
25+
26+ for f in [f"/sys/class/net/{cfg.ifname}/queues/rx-0/rps_flow_cnt",
27+ f"/sys/class/net/{cfg.ifname}/queues/rx-0/rps_cpus"]:
28+ try:
29+ with open(f, 'r') as fp:
30+ setting = fp.read().strip()
31+ # CPU mask will be zeros and commas
32+ if setting.replace("0", "").replace(",", ""):
33+ raise KsftSkipEx(f"RPS/RFS is configured: {f}: {setting}")
34+ except FileNotFoundError:
35+ pass
36+
37+ # 1 is the default, if someone changed it we probably shouldn"t mess with it
38+ af = cmd("cat /proc/sys/net/ipv6/auto_flowlabels", host=cfg.remote).stdout
39+ if af.strip() != "1":
40+ raise KsftSkipEx("Remote does not have auto_flowlabels enabled")
41+
42+
43+def _ethtool_get_cfg(cfg, fl_type):
44+ descr = cmd(f"ethtool -n {cfg.ifname} rx-flow-hash {fl_type}").stdout
45+
46+ converter = {
47+ "IP SA": "s",
48+ "IP DA": "d",
49+ "L3 proto": "t",
50+ "L4 bytes 0 & 1 [TCP/UDP src port]": "f",
51+ "L4 bytes 2 & 3 [TCP/UDP dst port]": "n",
52+ "IPv6 Flow Label": "l",
53+ }
54+
55+ ret = ""
56+ for line in descr.split("\n")[1:-2]:
57+ # if this raises we probably need to add more keys to converter above
58+ ret += converter[line]
59+ return ret
60+
61+
62+def _traffic(cfg, one_sock, one_cpu):
63+ local_port = rand_port(socket.SOCK_DGRAM)
64+ remote_port = rand_port(socket.SOCK_DGRAM)
65+
66+ sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
67+ sock.bind(("", local_port))
68+ sock.connect((cfg.remote_addr_v["6"], 0))
69+ if one_sock:
70+ send = f"exec 5<>/dev/udp/{cfg.addr_v['6']}/{local_port}; " \
71+ "for i in `seq 20`; do echo a >&5; sleep 0.02; done; exec 5>&-"
72+ else:
73+ send = "for i in `seq 20`; do echo a | socat -t0.02 - UDP6:" \
74+ f"[{cfg.addr_v['6']}]:{local_port},sourceport={remote_port}; done"
75+
76+ cpus = set()
77+ with bkg(send, shell=True, host=cfg.remote, exit_wait=True):
78+ for _ in range(20):
79+ fd_read_timeout(sock.fileno(), 1)
80+ cpu = sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU)
81+ cpus.add(cpu)
82+
83+ if one_cpu:
84+ ksft_eq(len(cpus), 1,
85+ f"{one_sock=} - expected one CPU, got traffic on: {cpus=}")
86+ else:
87+ ksft_ge(len(cpus), 2,
88+ f"{one_sock=} - expected many CPUs, got traffic on: {cpus=}")
89+
90+
91+def test_rss_flow_label(cfg):
92+ """
93+ Test hashing on IPv6 flow label. Send traffic over a single socket
94+ and over multiple sockets. Depend on the remote having auto-label
95+ enabled so that it randomizes the label per socket.
96+ """
97+
98+ cfg.require_ipver("6")
99+ cfg.require_cmd("socat", remote=True)
100+ _check_system(cfg)
101+
102+ # Enable flow label hashing for UDP6
103+ initial = _ethtool_get_cfg(cfg, "udp6")
104+ no_lbl = initial.replace("l", "")
105+ if "l" not in initial:
106+ try:
107+ cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 l{no_lbl}")
108+ except CmdExitFailure as exc:
109+ raise KsftSkipEx("Device doesn't support Flow Label for UDP6") from exc
110+
111+ defer(cmd, f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {initial}")
112+
113+ _traffic(cfg, one_sock=True, one_cpu=True)
114+ _traffic(cfg, one_sock=False, one_cpu=False)
115+
116+ # Disable it, we should see no hashing (reset was already defer()ed)
117+ cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {no_lbl}")
118+
119+ _traffic(cfg, one_sock=False, one_cpu=True)
120+
121+
122+def _check_v4_flow_types(cfg):
123+ for fl_type in ["tcp4", "udp4", "ah4", "esp4", "sctp4"]:
124+ try:
125+ cur = cmd(f"ethtool -n {cfg.ifname} rx-flow-hash {fl_type}").stdout
126+ ksft_not_in("Flow Label", cur,
127+ comment=f"{fl_type=} has Flow Label:" + cur)
128+ except CmdExitFailure:
129+ # Probably does not support this flow type
130+ pass
131+
132+
133+def test_rss_flow_label_6only(cfg):
134+ """
135+ Test interactions with IPv4 flow types. It should not be possible to set
136+ IPv6 Flow Label hashing for an IPv4 flow type. The Flow Label should also
137+ not appear in the IPv4 "current config".
138+ """
139+
140+ with ksft_raises(CmdExitFailure) as cm:
141+ cmd(f"ethtool -N {cfg.ifname} rx-flow-hash tcp4 sdfnl")
142+ ksft_in("Invalid argument", cm.exception.cmd.stderr)
143+
144+ _check_v4_flow_types(cfg)
145+
146+ # Try to enable Flow Labels and check again, in case it leaks thru
147+ initial = _ethtool_get_cfg(cfg, "udp6")
148+ changed = initial.replace("l", "") if "l" in initial else initial + "l"
149+
150+ cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {changed}")
151+ restore = defer(cmd, f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {initial}")
152+
153+ _check_v4_flow_types(cfg)
154+ restore.exec()
155+ _check_v4_flow_types(cfg)
156+
157+
158+def main() -> None:
159+ with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
160+ ksft_run([test_rss_flow_label,
161+ test_rss_flow_label_6only],
162+ args=(cfg, ))
163+ ksft_exit()
164+
165+
166+if __name__ == "__main__":
167+ main()

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t