xref: /linux/tools/testing/selftests/drivers/net/hds.py (revision b6d27a345f9d12fb80d61a1b1801ced9c1d6178a)
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
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_max(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    try:
120        netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': rings['hds-thresh-max']})
121    except NlError as e:
122        if e.error == errno.EINVAL:
123            raise KsftSkipEx("hds-thresh-set not supported by the device")
124        elif e.error == errno.EOPNOTSUPP:
125            raise KsftSkipEx("ring-set not supported by the device")
126    rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
127    ksft_eq(rings['hds-thresh'], rings['hds-thresh-max'])
128
129def set_hds_thresh_gt(cfg, netnl) -> None:
130    try:
131        rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
132    except NlError as e:
133        raise KsftSkipEx('ring-get not supported by device')
134    if 'hds-thresh' not in rings:
135        raise KsftSkipEx('hds-thresh not supported by device')
136    if 'hds-thresh-max' not in rings:
137        raise KsftSkipEx('hds-thresh-max not defined by device')
138    hds_gt = rings['hds-thresh-max'] + 1
139    with ksft_raises(NlError) as e:
140        netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_gt})
141    ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
142
143
144def set_xdp(cfg, netnl) -> None:
145    """
146    Enable single-buffer XDP on the device.
147    When HDS is in "auto" / UNKNOWN mode, XDP installation should work.
148    """
149    mode = _get_hds_mode(cfg, netnl)
150    if mode == 'enabled':
151        netnl.rings_set({'header': {'dev-index': cfg.ifindex},
152                         'tcp-data-split': 'unknown'})
153
154    _xdp_onoff(cfg)
155
156
157def enabled_set_xdp(cfg, netnl) -> None:
158    """
159    Enable single-buffer XDP on the device.
160    When HDS is in "enabled" mode, XDP installation should not work.
161    """
162    _get_hds_mode(cfg, netnl)
163    netnl.rings_set({'header': {'dev-index': cfg.ifindex},
164                     'tcp-data-split': 'enabled'})
165
166    defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},
167                            'tcp-data-split': 'unknown'})
168
169    with ksft_raises(CmdExitFailure) as e:
170        _xdp_onoff(cfg)
171
172
173def set_xdp(cfg, netnl) -> None:
174    """
175    Enable single-buffer XDP on the device.
176    When HDS is in "auto" / UNKNOWN mode, XDP installation should work.
177    """
178    mode = _get_hds_mode(cfg, netnl)
179    if mode == 'enabled':
180        netnl.rings_set({'header': {'dev-index': cfg.ifindex},
181                         'tcp-data-split': 'unknown'})
182
183    _xdp_onoff(cfg)
184
185
186def enabled_set_xdp(cfg, netnl) -> None:
187    """
188    Enable single-buffer XDP on the device.
189    When HDS is in "enabled" mode, XDP installation should not work.
190    """
191    _get_hds_mode(cfg, netnl)  # Trigger skip if not supported
192
193    netnl.rings_set({'header': {'dev-index': cfg.ifindex},
194                     'tcp-data-split': 'enabled'})
195    defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},
196                            'tcp-data-split': 'unknown'})
197
198    with ksft_raises(CmdExitFailure) as e:
199        _xdp_onoff(cfg)
200
201
202def ioctl(cfg, netnl) -> None:
203    mode1 = _get_hds_mode(cfg, netnl)
204    _ioctl_ringparam_modify(cfg, netnl)
205    mode2 = _get_hds_mode(cfg, netnl)
206
207    ksft_eq(mode1, mode2)
208
209
210def ioctl_set_xdp(cfg, netnl) -> None:
211    """
212    Like set_xdp(), but we perturb the settings via the legacy ioctl.
213    """
214    mode = _get_hds_mode(cfg, netnl)
215    if mode == 'enabled':
216        netnl.rings_set({'header': {'dev-index': cfg.ifindex},
217                         'tcp-data-split': 'unknown'})
218
219    _ioctl_ringparam_modify(cfg, netnl)
220
221    _xdp_onoff(cfg)
222
223
224def ioctl_enabled_set_xdp(cfg, netnl) -> None:
225    """
226    Enable single-buffer XDP on the device.
227    When HDS is in "enabled" mode, XDP installation should not work.
228    """
229    _get_hds_mode(cfg, netnl)  # Trigger skip if not supported
230
231    netnl.rings_set({'header': {'dev-index': cfg.ifindex},
232                     'tcp-data-split': 'enabled'})
233    defer(netnl.rings_set, {'header': {'dev-index': cfg.ifindex},
234                            'tcp-data-split': 'unknown'})
235
236    with ksft_raises(CmdExitFailure) as e:
237        _xdp_onoff(cfg)
238
239
240def main() -> None:
241    with NetDrvEnv(__file__, queue_count=3) as cfg:
242        ksft_run([get_hds,
243                  get_hds_thresh,
244                  set_hds_disable,
245                  set_hds_enable,
246                  set_hds_thresh_zero,
247                  set_hds_thresh_max,
248                  set_hds_thresh_gt,
249                  set_xdp,
250                  enabled_set_xdp,
251                  ioctl,
252                  ioctl_set_xdp,
253                  ioctl_enabled_set_xdp],
254                 args=(cfg, EthtoolFamily()))
255    ksft_exit()
256
257if __name__ == "__main__":
258    main()
259