Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3
4import errno
5import os
6import random
7from typing import Union
8from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_raises, KsftSkipEx
9from lib.py import CmdExitFailure, EthtoolFamily, NlError
10from lib.py import NetDrvEnv
11from lib.py import defer, ethtool, ip
12
13
14def _get_hds_mode(cfg, netnl) -> str:
15 try:
16 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
17 except NlError as e:
18 raise KsftSkipEx('ring-get not supported by device')
19 if 'tcp-data-split' not in rings:
20 raise KsftSkipEx('tcp-data-split not supported by device')
21 return rings['tcp-data-split']
22
23
24def _xdp_onoff(cfg):
25 prog = cfg.net_lib_dir / "xdp_dummy.bpf.o"
26 ip("link set dev %s xdp obj %s sec xdp" %
27 (cfg.ifname, prog))
28 ip("link set dev %s xdp off" % cfg.ifname)
29
30
31def _ioctl_ringparam_modify(cfg, netnl) -> None:
32 """
33 Helper for performing a hopefully unimportant IOCTL SET.
34 IOCTL does not support HDS, so it should not affect the HDS config.
35 """
36 try:
37 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
38 except NlError as e:
39 raise KsftSkipEx('ring-get not supported by device')
40
41 if 'tx' not in rings:
42 raise KsftSkipEx('setting Tx ring size not supported')
43
44 try:
45 ethtool(f"--disable-netlink -G {cfg.ifname} tx {rings['tx'] // 2}")
46 except CmdExitFailure as e:
47 ethtool(f"--disable-netlink -G {cfg.ifname} tx {rings['tx'] * 2}")
48 defer(ethtool, f"-G {cfg.ifname} tx {rings['tx']}")
49
50
51def get_hds(cfg, netnl) -> None:
52 _get_hds_mode(cfg, netnl)
53
54
55def get_hds_thresh(cfg, netnl) -> None:
56 try:
57 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
58 except NlError as e:
59 raise KsftSkipEx('ring-get not supported by device')
60 if 'hds-thresh' not in rings:
61 raise KsftSkipEx('hds-thresh not supported by device')
62
63
64def _hds_reset(cfg, netnl, rings) -> None:
65 cur = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
66
67 arg = {'header': {'dev-index': cfg.ifindex}}
68 if cur.get('tcp-data-split') != rings.get('tcp-data-split'):
69 # Try to reset to "unknown" first, we don't know if the setting
70 # was the default or user chose it. Default seems more likely.
71 arg['tcp-data-split'] = "unknown"
72 netnl.rings_set(arg)
73 cur = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
74 if cur['tcp-data-split'] == rings['tcp-data-split']:
75 del arg['tcp-data-split']
76 else:
77 # Try the explicit setting
78 arg['tcp-data-split'] = rings['tcp-data-split']
79 if cur.get('hds-thresh') != rings.get('hds-thresh'):
80 arg['hds-thresh'] = rings['hds-thresh']
81 if len(arg) > 1:
82 netnl.rings_set(arg)
83
84
85def _defer_reset_hds(cfg, netnl) -> Union[dict, None]:
86 try:
87 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
88 if 'hds-thresh' in rings or 'tcp-data-split' in rings:
89 defer(_hds_reset, cfg, netnl, rings)
90 except NlError as e:
91 pass
92
93
94def set_hds_enable(cfg, netnl) -> None:
95 _defer_reset_hds(cfg, netnl)
96 try:
97 netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'tcp-data-split': 'enabled'})
98 except NlError as e:
99 if e.error == errno.EINVAL:
100 raise KsftSkipEx("disabling of HDS not supported by the device")
101 elif e.error == errno.EOPNOTSUPP:
102 raise KsftSkipEx("ring-set not supported by the device")
103 try:
104 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
105 except NlError as e:
106 raise KsftSkipEx('ring-get not supported by device')
107 if 'tcp-data-split' not in rings:
108 raise KsftSkipEx('tcp-data-split not supported by device')
109
110 ksft_eq('enabled', rings['tcp-data-split'])
111
112def set_hds_disable(cfg, netnl) -> None:
113 _defer_reset_hds(cfg, netnl)
114 try:
115 netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'tcp-data-split': 'disabled'})
116 except NlError as e:
117 if e.error == errno.EINVAL:
118 raise KsftSkipEx("disabling of HDS not supported by the device")
119 elif e.error == errno.EOPNOTSUPP:
120 raise KsftSkipEx("ring-set not supported by the device")
121 try:
122 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
123 except NlError as e:
124 raise KsftSkipEx('ring-get not supported by device')
125 if 'tcp-data-split' not in rings:
126 raise KsftSkipEx('tcp-data-split not supported by device')
127
128 ksft_eq('disabled', rings['tcp-data-split'])
129
130def set_hds_thresh_zero(cfg, netnl) -> None:
131 _defer_reset_hds(cfg, netnl)
132 try:
133 netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': 0})
134 except NlError as e:
135 if e.error == errno.EINVAL:
136 raise KsftSkipEx("hds-thresh-set not supported by the device")
137 elif e.error == errno.EOPNOTSUPP:
138 raise KsftSkipEx("ring-set not supported by the device")
139 try:
140 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
141 except NlError as e:
142 raise KsftSkipEx('ring-get not supported by device')
143 if 'hds-thresh' not in rings:
144 raise KsftSkipEx('hds-thresh not supported by device')
145
146 ksft_eq(0, rings['hds-thresh'])
147
148def set_hds_thresh_random(cfg, netnl) -> None:
149 _defer_reset_hds(cfg, netnl)
150 try:
151 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
152 except NlError as e:
153 raise KsftSkipEx('ring-get not supported by device')
154 if 'hds-thresh' not in rings:
155 raise KsftSkipEx('hds-thresh not supported by device')
156 if 'hds-thresh-max' not in rings:
157 raise KsftSkipEx('hds-thresh-max not defined by device')
158
159 if rings['hds-thresh-max'] < 2:
160 raise KsftSkipEx('hds-thresh-max is too small')
161 elif rings['hds-thresh-max'] == 2:
162 hds_thresh = 1
163 else:
164 while True:
165 hds_thresh = random.randint(1, rings['hds-thresh-max'] - 1)
166 if hds_thresh != rings['hds-thresh']:
167 break
168
169 try:
170 netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_thresh})
171 except NlError as e:
172 if e.error == errno.EINVAL:
173 raise KsftSkipEx("hds-thresh-set not supported by the device")
174 elif e.error == errno.EOPNOTSUPP:
175 raise KsftSkipEx("ring-set not supported by the device")
176 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
177 ksft_eq(hds_thresh, rings['hds-thresh'])
178
179def set_hds_thresh_max(cfg, netnl) -> None:
180 _defer_reset_hds(cfg, netnl)
181 try:
182 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
183 except NlError as e:
184 raise KsftSkipEx('ring-get not supported by device')
185 if 'hds-thresh' not in rings:
186 raise KsftSkipEx('hds-thresh not supported by device')
187 try:
188 netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': rings['hds-thresh-max']})
189 except NlError as e:
190 if e.error == errno.EINVAL:
191 raise KsftSkipEx("hds-thresh-set not supported by the device")
192 elif e.error == errno.EOPNOTSUPP:
193 raise KsftSkipEx("ring-set not supported by the device")
194 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
195 ksft_eq(rings['hds-thresh'], rings['hds-thresh-max'])
196
197def set_hds_thresh_gt(cfg, netnl) -> None:
198 _defer_reset_hds(cfg, netnl)
199 try:
200 rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
201 except NlError as e:
202 raise KsftSkipEx('ring-get not supported by device')
203 if 'hds-thresh' not in rings:
204 raise KsftSkipEx('hds-thresh not supported by device')
205 if 'hds-thresh-max' not in rings:
206 raise KsftSkipEx('hds-thresh-max not defined by device')
207 hds_gt = rings['hds-thresh-max'] + 1
208 with ksft_raises(NlError) as e:
209 netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_gt})
210 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
211
212
213def set_xdp(cfg, netnl) -> None:
214 """
215 Enable single-buffer XDP on the device.
216 When HDS is in "auto" / UNKNOWN mode, XDP installation should work.
217 """
218 mode = _get_hds_mode(cfg, netnl)
219 if mode == 'enabled':
220 _defer_reset_hds(cfg, netnl)
221 netnl.rings_set({'header': {'dev-index': cfg.ifindex},
222 'tcp-data-split': 'unknown'})
223
224 _xdp_onoff(cfg)
225
226
227def enabled_set_xdp(cfg, netnl) -> None:
228 """
229 Enable single-buffer XDP on the device.
230 When HDS is in "enabled" mode, XDP installation should not work.
231 """
232 _get_hds_mode(cfg, netnl)
233 netnl.rings_set({'header': {'dev-index': cfg.ifindex},
234 'tcp-data-split': 'enabled'})
235
236 defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},
237 'tcp-data-split': 'unknown'})
238
239 with ksft_raises(CmdExitFailure) as e:
240 _xdp_onoff(cfg)
241
242
243def set_xdp(cfg, netnl) -> None:
244 """
245 Enable single-buffer XDP on the device.
246 When HDS is in "auto" / UNKNOWN mode, XDP installation should work.
247 """
248 mode = _get_hds_mode(cfg, netnl)
249 if mode == 'enabled':
250 netnl.rings_set({'header': {'dev-index': cfg.ifindex},
251 'tcp-data-split': 'unknown'})
252
253 _xdp_onoff(cfg)
254
255
256def enabled_set_xdp(cfg, netnl) -> None:
257 """
258 Enable single-buffer XDP on the device.
259 When HDS is in "enabled" mode, XDP installation should not work.
260 """
261 _get_hds_mode(cfg, netnl) # Trigger skip if not supported
262
263 netnl.rings_set({'header': {'dev-index': cfg.ifindex},
264 'tcp-data-split': 'enabled'})
265 defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},
266 'tcp-data-split': 'unknown'})
267
268 with ksft_raises(CmdExitFailure) as e:
269 _xdp_onoff(cfg)
270
271
272def ioctl(cfg, netnl) -> None:
273 mode1 = _get_hds_mode(cfg, netnl)
274 _ioctl_ringparam_modify(cfg, netnl)
275 mode2 = _get_hds_mode(cfg, netnl)
276
277 ksft_eq(mode1, mode2)
278
279
280def ioctl_set_xdp(cfg, netnl) -> None:
281 """
282 Like set_xdp(), but we perturb the settings via the legacy ioctl.
283 """
284 mode = _get_hds_mode(cfg, netnl)
285 if mode == 'enabled':
286 netnl.rings_set({'header': {'dev-index': cfg.ifindex},
287 'tcp-data-split': 'unknown'})
288
289 _ioctl_ringparam_modify(cfg, netnl)
290
291 _xdp_onoff(cfg)
292
293
294def ioctl_enabled_set_xdp(cfg, netnl) -> None:
295 """
296 Enable single-buffer XDP on the device.
297 When HDS is in "enabled" mode, XDP installation should not work.
298 """
299 _get_hds_mode(cfg, netnl) # Trigger skip if not supported
300
301 netnl.rings_set({'header': {'dev-index': cfg.ifindex},
302 'tcp-data-split': 'enabled'})
303 defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},
304 'tcp-data-split': 'unknown'})
305
306 with ksft_raises(CmdExitFailure) as e:
307 _xdp_onoff(cfg)
308
309
310def main() -> None:
311 with NetDrvEnv(__file__, queue_count=3) as cfg:
312 ksft_run([get_hds,
313 get_hds_thresh,
314 set_hds_disable,
315 set_hds_enable,
316 set_hds_thresh_random,
317 set_hds_thresh_zero,
318 set_hds_thresh_max,
319 set_hds_thresh_gt,
320 set_xdp,
321 enabled_set_xdp,
322 ioctl,
323 ioctl_set_xdp,
324 ioctl_enabled_set_xdp],
325 args=(cfg, EthtoolFamily()))
326 ksft_exit()
327
328if __name__ == "__main__":
329 main()