xref: /linux/tools/testing/selftests/drivers/net/queues.py (revision f9aa1fb9f8c0542f5f6e6e620de320995d5622ad)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3
4from lib.py import ksft_disruptive, ksft_exit, ksft_run
5from lib.py import ksft_eq, ksft_raises, KsftSkipEx
6from lib.py import EthtoolFamily, NetdevFamily, NlError
7from lib.py import NetDrvEnv
8from lib.py import cmd, defer, ip
9import errno
10import glob
11
12
13def sys_get_queues(ifname, qtype='rx') -> int:
14    folders = glob.glob(f'/sys/class/net/{ifname}/queues/{qtype}-*')
15    return len(folders)
16
17
18def nl_get_queues(cfg, nl, qtype='rx'):
19    queues = nl.queue_get({'ifindex': cfg.ifindex}, dump=True)
20    if queues:
21        return len([q for q in queues if q['type'] == qtype])
22    return None
23
24
25def get_queues(cfg, nl) -> None:
26    snl = NetdevFamily(recv_size=4096)
27
28    for qtype in ['rx', 'tx']:
29        queues = nl_get_queues(cfg, snl, qtype)
30        if not queues:
31            raise KsftSkipEx('queue-get not supported by device')
32
33        expected = sys_get_queues(cfg.dev['ifname'], qtype)
34        ksft_eq(queues, expected)
35
36
37def addremove_queues(cfg, nl) -> None:
38    queues = nl_get_queues(cfg, nl)
39    if not queues:
40        raise KsftSkipEx('queue-get not supported by device')
41
42    curr_queues = sys_get_queues(cfg.dev['ifname'])
43    if curr_queues == 1:
44        raise KsftSkipEx('cannot decrement queue: already at 1')
45
46    netnl = EthtoolFamily()
47    channels = netnl.channels_get({'header': {'dev-index': cfg.ifindex}})
48    if channels['combined-count'] == 0:
49        rx_type = 'rx'
50    else:
51        rx_type = 'combined'
52
53    expected = curr_queues - 1
54    cmd(f"ethtool -L {cfg.dev['ifname']} {rx_type} {expected}", timeout=10)
55    queues = nl_get_queues(cfg, nl)
56    ksft_eq(queues, expected)
57
58    expected = curr_queues
59    cmd(f"ethtool -L {cfg.dev['ifname']} {rx_type} {expected}", timeout=10)
60    queues = nl_get_queues(cfg, nl)
61    ksft_eq(queues, expected)
62
63
64@ksft_disruptive
65def check_down(cfg, nl) -> None:
66    # Check the NAPI IDs before interface goes down and hides them
67    napis = nl.napi_get({'ifindex': cfg.ifindex}, dump=True)
68
69    ip(f"link set dev {cfg.dev['ifname']} down")
70    defer(ip, f"link set dev {cfg.dev['ifname']} up")
71
72    with ksft_raises(NlError) as cm:
73        nl.queue_get({'ifindex': cfg.ifindex, 'id': 0, 'type': 'rx'})
74    ksft_eq(cm.exception.nl_msg.error, -errno.ENOENT)
75
76    if napis:
77        with ksft_raises(NlError) as cm:
78            nl.napi_get({'id': napis[0]['id']})
79        ksft_eq(cm.exception.nl_msg.error, -errno.ENOENT)
80
81
82def main() -> None:
83    with NetDrvEnv(__file__, queue_count=100) as cfg:
84        ksft_run([get_queues, addremove_queues, check_down], args=(cfg, NetdevFamily()))
85    ksft_exit()
86
87
88if __name__ == "__main__":
89    main()
90