xref: /linux/tools/testing/selftests/drivers/net/queues.py (revision 1e15510b71c99c6e49134d756df91069f7d18141)
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    rx_type = 'rx'
49    if channels.get('combined-count', 0) > 0:
50            rx_type = 'combined'
51
52    expected = curr_queues - 1
53    cmd(f"ethtool -L {cfg.dev['ifname']} {rx_type} {expected}", timeout=10)
54    queues = nl_get_queues(cfg, nl)
55    ksft_eq(queues, expected)
56
57    expected = curr_queues
58    cmd(f"ethtool -L {cfg.dev['ifname']} {rx_type} {expected}", timeout=10)
59    queues = nl_get_queues(cfg, nl)
60    ksft_eq(queues, expected)
61
62
63@ksft_disruptive
64def check_down(cfg, nl) -> None:
65    # Check the NAPI IDs before interface goes down and hides them
66    napis = nl.napi_get({'ifindex': cfg.ifindex}, dump=True)
67
68    ip(f"link set dev {cfg.dev['ifname']} down")
69    defer(ip, f"link set dev {cfg.dev['ifname']} up")
70
71    with ksft_raises(NlError) as cm:
72        nl.queue_get({'ifindex': cfg.ifindex, 'id': 0, 'type': 'rx'})
73    ksft_eq(cm.exception.nl_msg.error, -errno.ENOENT)
74
75    if napis:
76        with ksft_raises(NlError) as cm:
77            nl.napi_get({'id': napis[0]['id']})
78        ksft_eq(cm.exception.nl_msg.error, -errno.ENOENT)
79
80
81def main() -> None:
82    with NetDrvEnv(__file__, queue_count=100) as cfg:
83        ksft_run([get_queues, addremove_queues, check_down], args=(cfg, NetdevFamily()))
84    ksft_exit()
85
86
87if __name__ == "__main__":
88    main()
89