File Index
Files and directories
Sign in
FILE

hds.py

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/drivers/net/hds.py PYTHON
  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()
~/ Read-only file preview.