Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/drivers/net/hw/nk_qlease.py
171056 views
1
#!/usr/bin/env python3
2
# SPDX-License-Identifier: GPL-2.0
3
4
import re
5
import time
6
import threading
7
from os import path
8
from lib.py import (
9
ksft_run,
10
ksft_exit,
11
ksft_eq,
12
ksft_in,
13
ksft_not_in,
14
ksft_raises,
15
)
16
from lib.py import (
17
NetDrvContEnv,
18
NetNSEnter,
19
EthtoolFamily,
20
NetdevFamily,
21
)
22
from lib.py import (
23
bkg,
24
cmd,
25
defer,
26
ethtool,
27
ip,
28
rand_port,
29
wait_port_listen,
30
)
31
from lib.py import KsftSkipEx, CmdExitFailure
32
33
34
def set_flow_rule(cfg):
35
output = ethtool(
36
f"-N {cfg.ifname} flow-type tcp6 dst-port {cfg.port} action {cfg.src_queue}"
37
).stdout
38
values = re.search(r"ID (\d+)", output).group(1)
39
return int(values)
40
41
42
def test_iou_zcrx(cfg) -> None:
43
cfg.require_ipver("6")
44
ethnl = EthtoolFamily()
45
46
rings = ethnl.rings_get({"header": {"dev-index": cfg.ifindex}})
47
rx_rings = rings["rx"]
48
hds_thresh = rings.get("hds-thresh", 0)
49
50
ethnl.rings_set(
51
{
52
"header": {"dev-index": cfg.ifindex},
53
"tcp-data-split": "enabled",
54
"hds-thresh": 0,
55
"rx": 64,
56
}
57
)
58
defer(
59
ethnl.rings_set,
60
{
61
"header": {"dev-index": cfg.ifindex},
62
"tcp-data-split": "unknown",
63
"hds-thresh": hds_thresh,
64
"rx": rx_rings,
65
},
66
)
67
68
ethtool(f"-X {cfg.ifname} equal {cfg.src_queue}")
69
defer(ethtool, f"-X {cfg.ifname} default")
70
71
flow_rule_id = set_flow_rule(cfg)
72
defer(ethtool, f"-N {cfg.ifname} delete {flow_rule_id}")
73
74
rx_cmd = f"ip netns exec {cfg.netns.name} {cfg.bin_local} -s -p {cfg.port} -i {cfg._nk_guest_ifname} -q {cfg.nk_queue}"
75
tx_cmd = f"{cfg.bin_remote} -c -h {cfg.nk_guest_ipv6} -p {cfg.port} -l 12840"
76
with bkg(rx_cmd, exit_wait=True):
77
wait_port_listen(cfg.port, proto="tcp", ns=cfg.netns)
78
cmd(tx_cmd, host=cfg.remote)
79
80
81
def test_attrs(cfg) -> None:
82
cfg.require_ipver("6")
83
netdevnl = NetdevFamily()
84
queue_info = netdevnl.queue_get(
85
{"ifindex": cfg.ifindex, "id": cfg.src_queue, "type": "rx"}
86
)
87
88
ksft_eq(queue_info["id"], cfg.src_queue)
89
ksft_eq(queue_info["type"], "rx")
90
ksft_eq(queue_info["ifindex"], cfg.ifindex)
91
92
ksft_in("lease", queue_info)
93
lease = queue_info["lease"]
94
ksft_eq(lease["ifindex"], cfg.nk_guest_ifindex)
95
ksft_eq(lease["queue"]["id"], cfg.nk_queue)
96
ksft_eq(lease["queue"]["type"], "rx")
97
ksft_in("netns-id", lease)
98
99
100
def test_attach_xdp_with_mp(cfg) -> None:
101
cfg.require_ipver("6")
102
ethnl = EthtoolFamily()
103
104
rings = ethnl.rings_get({"header": {"dev-index": cfg.ifindex}})
105
rx_rings = rings["rx"]
106
hds_thresh = rings.get("hds-thresh", 0)
107
108
ethnl.rings_set(
109
{
110
"header": {"dev-index": cfg.ifindex},
111
"tcp-data-split": "enabled",
112
"hds-thresh": 0,
113
"rx": 64,
114
}
115
)
116
defer(
117
ethnl.rings_set,
118
{
119
"header": {"dev-index": cfg.ifindex},
120
"tcp-data-split": "unknown",
121
"hds-thresh": hds_thresh,
122
"rx": rx_rings,
123
},
124
)
125
126
ethtool(f"-X {cfg.ifname} equal {cfg.src_queue}")
127
defer(ethtool, f"-X {cfg.ifname} default")
128
129
netdevnl = NetdevFamily()
130
131
rx_cmd = f"ip netns exec {cfg.netns.name} {cfg.bin_local} -s -p {cfg.port} -i {cfg._nk_guest_ifname} -q {cfg.nk_queue}"
132
with bkg(rx_cmd):
133
wait_port_listen(cfg.port, proto="tcp", ns=cfg.netns)
134
135
time.sleep(0.1)
136
queue_info = netdevnl.queue_get(
137
{"ifindex": cfg.ifindex, "id": cfg.src_queue, "type": "rx"}
138
)
139
ksft_in("io-uring", queue_info)
140
141
prog = cfg.net_lib_dir / "xdp_dummy.bpf.o"
142
with ksft_raises(CmdExitFailure):
143
ip(f"link set dev {cfg.ifname} xdp obj {prog} sec xdp.frags")
144
145
time.sleep(0.1)
146
queue_info = netdevnl.queue_get(
147
{"ifindex": cfg.ifindex, "id": cfg.src_queue, "type": "rx"}
148
)
149
ksft_not_in("io-uring", queue_info)
150
151
152
def test_destroy(cfg) -> None:
153
cfg.require_ipver("6")
154
ethnl = EthtoolFamily()
155
156
rings = ethnl.rings_get({"header": {"dev-index": cfg.ifindex}})
157
rx_rings = rings["rx"]
158
hds_thresh = rings.get("hds-thresh", 0)
159
160
ethnl.rings_set(
161
{
162
"header": {"dev-index": cfg.ifindex},
163
"tcp-data-split": "enabled",
164
"hds-thresh": 0,
165
"rx": 64,
166
}
167
)
168
defer(
169
ethnl.rings_set,
170
{
171
"header": {"dev-index": cfg.ifindex},
172
"tcp-data-split": "unknown",
173
"hds-thresh": hds_thresh,
174
"rx": rx_rings,
175
},
176
)
177
178
ethtool(f"-X {cfg.ifname} equal {cfg.src_queue}")
179
defer(ethtool, f"-X {cfg.ifname} default")
180
181
rx_cmd = f"ip netns exec {cfg.netns.name} {cfg.bin_local} -s -p {cfg.port} -i {cfg._nk_guest_ifname} -q {cfg.nk_queue}"
182
rx_proc = cmd(rx_cmd, background=True)
183
wait_port_listen(cfg.port, proto="tcp", ns=cfg.netns)
184
185
netdevnl = NetdevFamily()
186
queue_info = netdevnl.queue_get(
187
{"ifindex": cfg.ifindex, "id": cfg.src_queue, "type": "rx"}
188
)
189
ksft_in("io-uring", queue_info)
190
191
# ip link del will wait for all refs to drop first, but iou-zcrx is holding
192
# onto a ref. Terminate iou-zcrx async via a thread after a delay.
193
kill_timer = threading.Timer(1, rx_proc.proc.terminate)
194
kill_timer.start()
195
196
ip(f"link del dev {cfg._nk_host_ifname}")
197
kill_timer.join()
198
cfg._nk_host_ifname = None
199
cfg._nk_guest_ifname = None
200
201
queue_info = netdevnl.queue_get(
202
{"ifindex": cfg.ifindex, "id": cfg.src_queue, "type": "rx"}
203
)
204
ksft_not_in("io-uring", queue_info)
205
206
cmd(f"tc filter del dev {cfg.ifname} ingress pref {cfg._bpf_prog_pref}")
207
cfg._tc_attached = False
208
209
flow_rule_id = set_flow_rule(cfg)
210
defer(ethtool, f"-N {cfg.ifname} delete {flow_rule_id}")
211
212
rx_cmd = f"{cfg.bin_local} -s -p {cfg.port} -i {cfg.ifname} -q {cfg.src_queue}"
213
tx_cmd = f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {cfg.port} -l 12840"
214
with bkg(rx_cmd, exit_wait=True):
215
wait_port_listen(cfg.port, proto="tcp")
216
cmd(tx_cmd, host=cfg.remote)
217
# Short delay since iou cleanup is async and takes a bit of time.
218
time.sleep(0.1)
219
queue_info = netdevnl.queue_get(
220
{"ifindex": cfg.ifindex, "id": cfg.src_queue, "type": "rx"}
221
)
222
ksft_not_in("io-uring", queue_info)
223
224
225
def main() -> None:
226
with NetDrvContEnv(__file__, rxqueues=2) as cfg:
227
cfg.bin_local = path.abspath(
228
path.dirname(__file__) + "/../../../drivers/net/hw/iou-zcrx"
229
)
230
cfg.bin_remote = cfg.remote.deploy(cfg.bin_local)
231
cfg.port = rand_port()
232
233
ethnl = EthtoolFamily()
234
channels = ethnl.channels_get({"header": {"dev-index": cfg.ifindex}})
235
channels = channels["combined-count"]
236
if channels < 2:
237
raise KsftSkipEx("Test requires NETIF with at least 2 combined channels")
238
239
cfg.src_queue = channels - 1
240
241
with NetNSEnter(str(cfg.netns)):
242
netdevnl = NetdevFamily()
243
bind_result = netdevnl.queue_create(
244
{
245
"ifindex": cfg.nk_guest_ifindex,
246
"type": "rx",
247
"lease": {
248
"ifindex": cfg.ifindex,
249
"queue": {"id": cfg.src_queue, "type": "rx"},
250
"netns-id": 0,
251
},
252
}
253
)
254
cfg.nk_queue = bind_result["id"]
255
256
# test_destroy must be last because it destroys the netkit devices
257
ksft_run(
258
[test_iou_zcrx, test_attrs, test_attach_xdp_with_mp, test_destroy],
259
args=(cfg,),
260
)
261
ksft_exit()
262
263
264
if __name__ == "__main__":
265
main()
266
267