xref: /linux/tools/testing/selftests/drivers/net/queues.py (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
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_not_in, ksft_raises, KsftSkipEx, KsftFailEx
6from lib.py import EthtoolFamily, NetdevFamily, NlError
7from lib.py import NetDrvEnv
8from lib.py import bkg, cmd, defer, ip
9import errno
10import glob
11import os
12import socket
13import struct
14
15def sys_get_queues(ifname, qtype='rx') -> int:
16    folders = glob.glob(f'/sys/class/net/{ifname}/queues/{qtype}-*')
17    return len(folders)
18
19
20def nl_get_queues(cfg, nl, qtype='rx'):
21    queues = nl.queue_get({'ifindex': cfg.ifindex}, dump=True)
22    if queues:
23        return len([q for q in queues if q['type'] == qtype])
24    return None
25
26
27def check_xsk(cfg, nl, xdp_queue_id=0) -> None:
28    # Probe for support
29    xdp = cmd(f'{cfg.test_dir / "xdp_helper"} - -', fail=False)
30    if xdp.ret == 255:
31        raise KsftSkipEx('AF_XDP unsupported')
32    elif xdp.ret > 0:
33        raise KsftFailEx('unable to create AF_XDP socket')
34
35    with bkg(f'{cfg.test_dir / "xdp_helper"} {cfg.ifindex} {xdp_queue_id}',
36             ksft_wait=3):
37
38        rx = tx = False
39
40        queues = nl.queue_get({'ifindex': cfg.ifindex}, dump=True)
41        if not queues:
42            raise KsftSkipEx("Netlink reports no queues")
43
44        for q in queues:
45            if q['id'] == 0:
46                if q['type'] == 'rx':
47                    rx = True
48                if q['type'] == 'tx':
49                    tx = True
50
51                ksft_eq(q.get('xsk', None), {},
52                        comment="xsk attr on queue we configured")
53            else:
54                ksft_not_in('xsk', q,
55                            comment="xsk attr on queue we didn't configure")
56
57        ksft_eq(rx, True)
58        ksft_eq(tx, True)
59
60
61def get_queues(cfg, nl) -> None:
62    snl = NetdevFamily(recv_size=4096)
63
64    for qtype in ['rx', 'tx']:
65        queues = nl_get_queues(cfg, snl, qtype)
66        if not queues:
67            raise KsftSkipEx('queue-get not supported by device')
68
69        expected = sys_get_queues(cfg.dev['ifname'], qtype)
70        ksft_eq(queues, expected)
71
72
73def addremove_queues(cfg, nl) -> None:
74    queues = nl_get_queues(cfg, nl)
75    if not queues:
76        raise KsftSkipEx('queue-get not supported by device')
77
78    curr_queues = sys_get_queues(cfg.dev['ifname'])
79    if curr_queues == 1:
80        raise KsftSkipEx('cannot decrement queue: already at 1')
81
82    netnl = EthtoolFamily()
83    channels = netnl.channels_get({'header': {'dev-index': cfg.ifindex}})
84    rx_type = 'rx'
85    if channels.get('combined-count', 0) > 0:
86            rx_type = 'combined'
87
88    expected = curr_queues - 1
89    cmd(f"ethtool -L {cfg.dev['ifname']} {rx_type} {expected}", timeout=10)
90    queues = nl_get_queues(cfg, nl)
91    ksft_eq(queues, expected)
92
93    expected = curr_queues
94    cmd(f"ethtool -L {cfg.dev['ifname']} {rx_type} {expected}", timeout=10)
95    queues = nl_get_queues(cfg, nl)
96    ksft_eq(queues, expected)
97
98
99@ksft_disruptive
100def check_down(cfg, nl) -> None:
101    # Check the NAPI IDs before interface goes down and hides them
102    napis = nl.napi_get({'ifindex': cfg.ifindex}, dump=True)
103
104    ip(f"link set dev {cfg.dev['ifname']} down")
105    defer(ip, f"link set dev {cfg.dev['ifname']} up")
106
107    with ksft_raises(NlError) as cm:
108        nl.queue_get({'ifindex': cfg.ifindex, 'id': 0, 'type': 'rx'})
109    ksft_eq(cm.exception.nl_msg.error, -errno.ENOENT)
110
111    if napis:
112        with ksft_raises(NlError) as cm:
113            nl.napi_get({'id': napis[0]['id']})
114        ksft_eq(cm.exception.nl_msg.error, -errno.ENOENT)
115
116
117def main() -> None:
118    with NetDrvEnv(__file__, queue_count=100) as cfg:
119        ksft_run([get_queues, addremove_queues, check_down, check_xsk],
120                 args=(cfg, NetdevFamily()))
121    ksft_exit()
122
123
124if __name__ == "__main__":
125    main()
126