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