Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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.net_lib_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.net_lib_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()