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
4import errno
5import time
6from lib.py import (
7 ksft_run,
8 ksft_exit,
9 ksft_eq,
10 ksft_ne,
11 ksft_in,
12 ksft_not_in,
13 ksft_raises,
14)
15from lib.py import (
16 NetNS,
17 NetNSEnter,
18 EthtoolFamily,
19 NetdevFamily,
20 RtnlFamily,
21 NetdevSimDev,
22)
23from lib.py import (
24 NlError,
25 Netlink,
26 cmd,
27 defer,
28 ip,
29)
30
31
32def wait_until(cond, timeout=2.0, interval=0.05):
33 deadline = time.monotonic() + timeout
34 while not cond():
35 if time.monotonic() >= deadline:
36 return
37 time.sleep(interval)
38
39
40def create_netkit(rxqueues, mode="l2"):
41 all_links = ip("-d link show", json=True)
42 old_idxs = {
43 link["ifindex"]
44 for link in all_links
45 if link.get("linkinfo", {}).get("info_kind") == "netkit"
46 }
47
48 rtnl = RtnlFamily()
49 rtnl.newlink(
50 {
51 "linkinfo": {
52 "kind": "netkit",
53 "data": {
54 "mode": mode,
55 "policy": "forward",
56 "peer-policy": "forward",
57 },
58 },
59 "num-rx-queues": rxqueues,
60 },
61 flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL],
62 )
63
64 all_links = ip("-d link show", json=True)
65 nk_links = [
66 link
67 for link in all_links
68 if link.get("linkinfo", {}).get("info_kind") == "netkit"
69 and link["ifindex"] not in old_idxs
70 ]
71 nk_links.sort(key=lambda x: x["ifindex"])
72 return (
73 nk_links[1]["ifname"],
74 nk_links[1]["ifindex"],
75 nk_links[0]["ifname"],
76 nk_links[0]["ifindex"],
77 )
78
79
80def create_netkit_single(rxqueues):
81 rtnl = RtnlFamily()
82 rtnl.newlink(
83 {
84 "linkinfo": {
85 "kind": "netkit",
86 "data": {
87 "mode": "l2",
88 "pairing": "single",
89 },
90 },
91 "num-rx-queues": rxqueues,
92 },
93 flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL],
94 )
95
96 all_links = ip("-d link show", json=True)
97 nk_links = [
98 link
99 for link in all_links
100 if link.get("linkinfo", {}).get("info_kind") == "netkit"
101 and "UP" not in link.get("flags", [])
102 ]
103 return nk_links[0]["ifname"], nk_links[0]["ifindex"]
104
105
106def test_remove_phys(netns) -> None:
107 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
108 defer(nsimdev.remove)
109 nsim = nsimdev.nsims[0]
110 ip(f"link set dev {nsim.ifname} up")
111
112 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
113 defer(cmd, f"ip link del dev {nk_host}", fail=False)
114
115 ip(f"link set dev {nk_guest} netns {netns.name}")
116 ip(f"link set dev {nk_host} up")
117 ip(f"link set dev {nk_guest} up", ns=netns)
118
119 src_queue = 1
120 with NetNSEnter(str(netns)):
121 netdevnl = NetdevFamily()
122 result = netdevnl.queue_create(
123 {
124 "ifindex": nk_guest_idx,
125 "type": "rx",
126 "lease": {
127 "ifindex": nsim.ifindex,
128 "queue": {"id": src_queue, "type": "rx"},
129 "netns-id": 0,
130 },
131 }
132 )
133 nk_queue_id = result["id"]
134
135 netdevnl = NetdevFamily()
136 queue_info = netdevnl.queue_get(
137 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
138 )
139 ksft_in("lease", queue_info)
140 ksft_eq(queue_info["lease"]["ifindex"], nk_guest_idx)
141 ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
142
143 nsimdev.remove()
144 wait_until(lambda: cmd(f"ip link show dev {nk_host}", fail=False).ret != 0)
145 ret = cmd(f"ip link show dev {nk_host}", fail=False)
146 ksft_ne(ret.ret, 0)
147
148
149def test_double_lease(netns) -> None:
150 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
151 defer(nsimdev.remove)
152 nsim = nsimdev.nsims[0]
153 ip(f"link set dev {nsim.ifname} up")
154
155 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
156 defer(cmd, f"ip link del dev {nk_host}")
157
158 ip(f"link set dev {nk_guest} netns {netns.name}")
159 ip(f"link set dev {nk_host} up")
160 ip(f"link set dev {nk_guest} up", ns=netns)
161
162 src_queue = 1
163 with NetNSEnter(str(netns)):
164 netdevnl = NetdevFamily()
165 result = netdevnl.queue_create(
166 {
167 "ifindex": nk_guest_idx,
168 "type": "rx",
169 "lease": {
170 "ifindex": nsim.ifindex,
171 "queue": {"id": src_queue, "type": "rx"},
172 "netns-id": 0,
173 },
174 }
175 )
176 ksft_eq(result["id"], 1)
177
178 with ksft_raises(NlError) as e:
179 netdevnl.queue_create(
180 {
181 "ifindex": nk_guest_idx,
182 "type": "rx",
183 "lease": {
184 "ifindex": nsim.ifindex,
185 "queue": {"id": src_queue, "type": "rx"},
186 "netns-id": 0,
187 },
188 }
189 )
190 ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
191
192
193def test_virtual_lessor(netns) -> None:
194 nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
195 defer(cmd, f"ip link del dev {nk_host_a}")
196 ip(f"link set dev {nk_host_a} up")
197 ip(f"link set dev {nk_guest_a} up")
198
199 nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
200 defer(cmd, f"ip link del dev {nk_host_b}")
201
202 ip(f"link set dev {nk_guest_b} netns {netns.name}")
203 ip(f"link set dev {nk_host_b} up")
204 ip(f"link set dev {nk_guest_b} up", ns=netns)
205
206 with NetNSEnter(str(netns)):
207 netdevnl = NetdevFamily()
208 with ksft_raises(NlError) as e:
209 netdevnl.queue_create(
210 {
211 "ifindex": nk_guest_b_idx,
212 "type": "rx",
213 "lease": {
214 "ifindex": nk_guest_a_idx,
215 "queue": {"id": 0, "type": "rx"},
216 "netns-id": 0,
217 },
218 }
219 )
220 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
221
222
223def test_phys_lessee(_netns) -> None:
224 nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
225 defer(nsimdev_a.remove)
226 nsim_a = nsimdev_a.nsims[0]
227 ip(f"link set dev {nsim_a.ifname} up")
228
229 nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
230 defer(nsimdev_b.remove)
231 nsim_b = nsimdev_b.nsims[0]
232 ip(f"link set dev {nsim_b.ifname} up")
233
234 netdevnl = NetdevFamily()
235 with ksft_raises(NlError) as e:
236 netdevnl.queue_create(
237 {
238 "ifindex": nsim_a.ifindex,
239 "type": "rx",
240 "lease": {
241 "ifindex": nsim_b.ifindex,
242 "queue": {"id": 0, "type": "rx"},
243 },
244 }
245 )
246 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
247
248
249def test_different_lessors(netns) -> None:
250 nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
251 defer(nsimdev_a.remove)
252 nsim_a = nsimdev_a.nsims[0]
253 ip(f"link set dev {nsim_a.ifname} up")
254
255 nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
256 defer(nsimdev_b.remove)
257 nsim_b = nsimdev_b.nsims[0]
258 ip(f"link set dev {nsim_b.ifname} up")
259
260 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
261 defer(cmd, f"ip link del dev {nk_host}", fail=False)
262
263 ip(f"link set dev {nk_guest} netns {netns.name}")
264 ip(f"link set dev {nk_host} up")
265 ip(f"link set dev {nk_guest} up", ns=netns)
266
267 with NetNSEnter(str(netns)):
268 netdevnl = NetdevFamily()
269 netdevnl.queue_create(
270 {
271 "ifindex": nk_guest_idx,
272 "type": "rx",
273 "lease": {
274 "ifindex": nsim_a.ifindex,
275 "queue": {"id": 1, "type": "rx"},
276 "netns-id": 0,
277 },
278 }
279 )
280
281 with ksft_raises(NlError) as e:
282 netdevnl.queue_create(
283 {
284 "ifindex": nk_guest_idx,
285 "type": "rx",
286 "lease": {
287 "ifindex": nsim_b.ifindex,
288 "queue": {"id": 1, "type": "rx"},
289 "netns-id": 0,
290 },
291 }
292 )
293 ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
294
295
296def test_queue_out_of_range(netns) -> None:
297 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
298 defer(nsimdev.remove)
299 nsim = nsimdev.nsims[0]
300 ip(f"link set dev {nsim.ifname} up")
301
302 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
303 defer(cmd, f"ip link del dev {nk_host}", fail=False)
304
305 ip(f"link set dev {nk_guest} netns {netns.name}")
306 ip(f"link set dev {nk_host} up")
307 ip(f"link set dev {nk_guest} up", ns=netns)
308
309 with NetNSEnter(str(netns)):
310 netdevnl = NetdevFamily()
311 with ksft_raises(NlError) as e:
312 netdevnl.queue_create(
313 {
314 "ifindex": nk_guest_idx,
315 "type": "rx",
316 "lease": {
317 "ifindex": nsim.ifindex,
318 "queue": {"id": 2, "type": "rx"},
319 "netns-id": 0,
320 },
321 }
322 )
323 ksft_eq(e.exception.nl_msg.error, -errno.ERANGE)
324
325
326def test_resize_leased(netns) -> None:
327 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
328 defer(nsimdev.remove)
329 nsim = nsimdev.nsims[0]
330 ip(f"link set dev {nsim.ifname} up")
331
332 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
333 defer(cmd, f"ip link del dev {nk_host}", fail=False)
334
335 ip(f"link set dev {nk_guest} netns {netns.name}")
336 ip(f"link set dev {nk_host} up")
337 ip(f"link set dev {nk_guest} up", ns=netns)
338
339 with NetNSEnter(str(netns)):
340 netdevnl = NetdevFamily()
341 netdevnl.queue_create(
342 {
343 "ifindex": nk_guest_idx,
344 "type": "rx",
345 "lease": {
346 "ifindex": nsim.ifindex,
347 "queue": {"id": 1, "type": "rx"},
348 "netns-id": 0,
349 },
350 }
351 )
352
353 ethnl = EthtoolFamily()
354 with ksft_raises(NlError) as e:
355 ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
356 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
357
358
359def test_self_lease(_netns) -> None:
360 nk_host, _, _, nk_guest_idx = create_netkit(rxqueues=2)
361 defer(cmd, f"ip link del dev {nk_host}", fail=False)
362
363 netdevnl = NetdevFamily()
364 with ksft_raises(NlError) as e:
365 netdevnl.queue_create(
366 {
367 "ifindex": nk_guest_idx,
368 "type": "rx",
369 "lease": {
370 "ifindex": nk_guest_idx,
371 "queue": {"id": 0, "type": "rx"},
372 },
373 }
374 )
375 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
376
377
378def test_veth_queue_create(netns) -> None:
379 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
380 defer(nsimdev.remove)
381 nsim = nsimdev.nsims[0]
382 ip(f"link set dev {nsim.ifname} up")
383
384 ip("link add veth0 type veth peer name veth1")
385 defer(cmd, "ip link del dev veth0", fail=False)
386
387 all_links = ip("-d link show", json=True)
388 veth_peer = [
389 link
390 for link in all_links
391 if link.get("ifname") == "veth1"
392 ]
393 veth_peer_idx = veth_peer[0]["ifindex"]
394
395 ip(f"link set dev veth1 netns {netns.name}")
396 ip("link set dev veth0 up")
397 ip("link set dev veth1 up", ns=netns)
398
399 with NetNSEnter(str(netns)):
400 netdevnl = NetdevFamily()
401 with ksft_raises(NlError) as e:
402 netdevnl.queue_create(
403 {
404 "ifindex": veth_peer_idx,
405 "type": "rx",
406 "lease": {
407 "ifindex": nsim.ifindex,
408 "queue": {"id": 1, "type": "rx"},
409 "netns-id": 0,
410 },
411 }
412 )
413 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
414
415
416def test_create_tx_type(netns) -> None:
417 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
418 defer(nsimdev.remove)
419 nsim = nsimdev.nsims[0]
420 ip(f"link set dev {nsim.ifname} up")
421
422 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
423 defer(cmd, f"ip link del dev {nk_host}", fail=False)
424
425 ip(f"link set dev {nk_guest} netns {netns.name}")
426 ip(f"link set dev {nk_host} up")
427 ip(f"link set dev {nk_guest} up", ns=netns)
428
429 with NetNSEnter(str(netns)):
430 netdevnl = NetdevFamily()
431 with ksft_raises(NlError) as e:
432 netdevnl.queue_create(
433 {
434 "ifindex": nk_guest_idx,
435 "type": "tx",
436 "lease": {
437 "ifindex": nsim.ifindex,
438 "queue": {"id": 1, "type": "rx"},
439 "netns-id": 0,
440 },
441 }
442 )
443 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
444
445
446def test_create_primary(_netns) -> None:
447 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
448 defer(nsimdev.remove)
449 nsim = nsimdev.nsims[0]
450 ip(f"link set dev {nsim.ifname} up")
451
452 nk_host, nk_host_idx, _, _ = create_netkit(rxqueues=2)
453 defer(cmd, f"ip link del dev {nk_host}", fail=False)
454
455 ip(f"link set dev {nk_host} up")
456
457 netdevnl = NetdevFamily()
458 with ksft_raises(NlError) as e:
459 netdevnl.queue_create(
460 {
461 "ifindex": nk_host_idx,
462 "type": "rx",
463 "lease": {
464 "ifindex": nsim.ifindex,
465 "queue": {"id": 1, "type": "rx"},
466 },
467 }
468 )
469 ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
470
471
472def test_create_limit(netns) -> None:
473 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
474 defer(nsimdev.remove)
475 nsim = nsimdev.nsims[0]
476 ip(f"link set dev {nsim.ifname} up")
477
478 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=1)
479 defer(cmd, f"ip link del dev {nk_host}", fail=False)
480
481 ip(f"link set dev {nk_guest} netns {netns.name}")
482 ip(f"link set dev {nk_host} up")
483 ip(f"link set dev {nk_guest} up", ns=netns)
484
485 with NetNSEnter(str(netns)):
486 netdevnl = NetdevFamily()
487 with ksft_raises(NlError) as e:
488 netdevnl.queue_create(
489 {
490 "ifindex": nk_guest_idx,
491 "type": "rx",
492 "lease": {
493 "ifindex": nsim.ifindex,
494 "queue": {"id": 1, "type": "rx"},
495 "netns-id": 0,
496 },
497 }
498 )
499 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
500
501
502def test_link_flap_phys(netns) -> None:
503 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
504 defer(nsimdev.remove)
505 nsim = nsimdev.nsims[0]
506 ip(f"link set dev {nsim.ifname} up")
507
508 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
509 defer(cmd, f"ip link del dev {nk_host}")
510
511 ip(f"link set dev {nk_guest} netns {netns.name}")
512 ip(f"link set dev {nk_host} up")
513 ip(f"link set dev {nk_guest} up", ns=netns)
514
515 src_queue = 1
516 with NetNSEnter(str(netns)):
517 netdevnl = NetdevFamily()
518 result = netdevnl.queue_create(
519 {
520 "ifindex": nk_guest_idx,
521 "type": "rx",
522 "lease": {
523 "ifindex": nsim.ifindex,
524 "queue": {"id": src_queue, "type": "rx"},
525 "netns-id": 0,
526 },
527 }
528 )
529 nk_queue_id = result["id"]
530
531 netdevnl = NetdevFamily()
532 queue_info = netdevnl.queue_get(
533 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
534 )
535 ksft_in("lease", queue_info)
536 ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
537
538 # Link flap the physical device
539 ip(f"link set dev {nsim.ifname} down")
540 ip(f"link set dev {nsim.ifname} up")
541
542 # Verify lease survives the flap
543 queue_info = netdevnl.queue_get(
544 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
545 )
546 ksft_in("lease", queue_info)
547 ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
548
549
550def test_queue_get_virtual(netns) -> None:
551 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
552 defer(nsimdev.remove)
553 nsim = nsimdev.nsims[0]
554 ip(f"link set dev {nsim.ifname} up")
555
556 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
557 defer(cmd, f"ip link del dev {nk_host}")
558
559 ip(f"link set dev {nk_guest} netns {netns.name}")
560 ip(f"link set dev {nk_host} up")
561 ip(f"link set dev {nk_guest} up", ns=netns)
562
563 src_queue = 1
564 with NetNSEnter(str(netns)):
565 netdevnl = NetdevFamily()
566 result = netdevnl.queue_create(
567 {
568 "ifindex": nk_guest_idx,
569 "type": "rx",
570 "lease": {
571 "ifindex": nsim.ifindex,
572 "queue": {"id": src_queue, "type": "rx"},
573 "netns-id": 0,
574 },
575 }
576 )
577 nk_queue_id = result["id"]
578
579 # queue-get on virtual device's leased queue should not show lease
580 # info (lease info is only shown from the physical device's side)
581 queue_info = netdevnl.queue_get(
582 {"ifindex": nk_guest_idx, "id": nk_queue_id, "type": "rx"}
583 )
584 ksft_eq(queue_info["id"], nk_queue_id)
585 ksft_eq(queue_info["ifindex"], nk_guest_idx)
586 ksft_not_in("lease", queue_info)
587
588 # Default queue (not leased) also has no lease info
589 queue_info = netdevnl.queue_get(
590 {"ifindex": nk_guest_idx, "id": 0, "type": "rx"}
591 )
592 ksft_not_in("lease", queue_info)
593
594
595def test_remove_virt_first(netns) -> None:
596 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
597 defer(nsimdev.remove)
598 nsim = nsimdev.nsims[0]
599 ip(f"link set dev {nsim.ifname} up")
600
601 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
602
603 ip(f"link set dev {nk_guest} netns {netns.name}")
604 ip(f"link set dev {nk_host} up")
605 ip(f"link set dev {nk_guest} up", ns=netns)
606
607 src_queue = 1
608 with NetNSEnter(str(netns)):
609 netdevnl = NetdevFamily()
610 result = netdevnl.queue_create(
611 {
612 "ifindex": nk_guest_idx,
613 "type": "rx",
614 "lease": {
615 "ifindex": nsim.ifindex,
616 "queue": {"id": src_queue, "type": "rx"},
617 "netns-id": 0,
618 },
619 }
620 )
621 ksft_eq(result["id"], 1)
622
623 netdevnl = NetdevFamily()
624 queue_info = netdevnl.queue_get(
625 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
626 )
627 ksft_in("lease", queue_info)
628 ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
629
630 # Delete netkit (virtual device removed first, physical stays)
631 cmd(f"ip link del dev {nk_host}")
632
633 # Verify lease is cleaned up on physical device
634 queue_info = netdevnl.queue_get(
635 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
636 )
637 ksft_not_in("lease", queue_info)
638
639
640def test_multiple_leases(netns) -> None:
641 nsimdev = NetdevSimDev(port_count=1, queue_count=3)
642 defer(nsimdev.remove)
643 nsim = nsimdev.nsims[0]
644 ip(f"link set dev {nsim.ifname} up")
645
646 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=4)
647 defer(cmd, f"ip link del dev {nk_host}", fail=False)
648
649 ip(f"link set dev {nk_guest} netns {netns.name}")
650 ip(f"link set dev {nk_host} up")
651 ip(f"link set dev {nk_guest} up", ns=netns)
652
653 with NetNSEnter(str(netns)):
654 netdevnl = NetdevFamily()
655 r1 = netdevnl.queue_create(
656 {
657 "ifindex": nk_guest_idx,
658 "type": "rx",
659 "lease": {
660 "ifindex": nsim.ifindex,
661 "queue": {"id": 1, "type": "rx"},
662 "netns-id": 0,
663 },
664 }
665 )
666 r2 = netdevnl.queue_create(
667 {
668 "ifindex": nk_guest_idx,
669 "type": "rx",
670 "lease": {
671 "ifindex": nsim.ifindex,
672 "queue": {"id": 2, "type": "rx"},
673 "netns-id": 0,
674 },
675 }
676 )
677
678 ksft_eq(r1["id"], 1)
679 ksft_eq(r2["id"], 2)
680
681 # Verify both leases visible on physical device
682 netdevnl = NetdevFamily()
683 q1 = netdevnl.queue_get(
684 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
685 )
686 q2 = netdevnl.queue_get(
687 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
688 )
689 ksft_in("lease", q1)
690 ksft_in("lease", q2)
691 ksft_eq(q1["lease"]["ifindex"], nk_guest_idx)
692 ksft_eq(q2["lease"]["ifindex"], nk_guest_idx)
693 ksft_eq(q1["lease"]["queue"]["id"], r1["id"])
694 ksft_eq(q2["lease"]["queue"]["id"], r2["id"])
695
696
697def test_lease_queue_tx_type(netns) -> None:
698 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
699 defer(nsimdev.remove)
700 nsim = nsimdev.nsims[0]
701 ip(f"link set dev {nsim.ifname} up")
702
703 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
704 defer(cmd, f"ip link del dev {nk_host}", fail=False)
705
706 ip(f"link set dev {nk_guest} netns {netns.name}")
707 ip(f"link set dev {nk_host} up")
708 ip(f"link set dev {nk_guest} up", ns=netns)
709
710 with NetNSEnter(str(netns)):
711 netdevnl = NetdevFamily()
712 with ksft_raises(NlError) as e:
713 netdevnl.queue_create(
714 {
715 "ifindex": nk_guest_idx,
716 "type": "rx",
717 "lease": {
718 "ifindex": nsim.ifindex,
719 "queue": {"id": 1, "type": "tx"},
720 "netns-id": 0,
721 },
722 }
723 )
724 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
725
726
727def test_invalid_netns(netns) -> None:
728 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
729 defer(cmd, f"ip link del dev {nk_host}", fail=False)
730
731 ip(f"link set dev {nk_guest} netns {netns.name}")
732 ip(f"link set dev {nk_host} up")
733 ip(f"link set dev {nk_guest} up", ns=netns)
734
735 with NetNSEnter(str(netns)):
736 netdevnl = NetdevFamily()
737 with ksft_raises(NlError) as e:
738 netdevnl.queue_create(
739 {
740 "ifindex": nk_guest_idx,
741 "type": "rx",
742 "lease": {
743 "ifindex": 1,
744 "queue": {"id": 0, "type": "rx"},
745 "netns-id": 999,
746 },
747 }
748 )
749 ksft_eq(e.exception.nl_msg.error, -errno.ENONET)
750
751
752def test_invalid_phys_ifindex(netns) -> None:
753 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
754 defer(cmd, f"ip link del dev {nk_host}", fail=False)
755
756 ip(f"link set dev {nk_guest} netns {netns.name}")
757 ip(f"link set dev {nk_host} up")
758 ip(f"link set dev {nk_guest} up", ns=netns)
759
760 with NetNSEnter(str(netns)):
761 netdevnl = NetdevFamily()
762 with ksft_raises(NlError) as e:
763 netdevnl.queue_create(
764 {
765 "ifindex": nk_guest_idx,
766 "type": "rx",
767 "lease": {
768 "ifindex": 99999,
769 "queue": {"id": 0, "type": "rx"},
770 "netns-id": 0,
771 },
772 }
773 )
774 ksft_eq(e.exception.nl_msg.error, -errno.ENODEV)
775
776
777def test_multi_netkit_remove_phys(netns) -> None:
778 nsimdev = NetdevSimDev(port_count=1, queue_count=3)
779 defer(nsimdev.remove)
780 nsim = nsimdev.nsims[0]
781 ip(f"link set dev {nsim.ifname} up")
782
783 # Create two netkit pairs, each leasing a different physical queue
784 nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
785 defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
786
787 nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
788 defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
789
790 ip(f"link set dev {nk_guest_a} netns {netns.name}")
791 ip(f"link set dev {nk_host_a} up")
792 ip(f"link set dev {nk_guest_a} up", ns=netns)
793
794 ip(f"link set dev {nk_guest_b} netns {netns.name}")
795 ip(f"link set dev {nk_host_b} up")
796 ip(f"link set dev {nk_guest_b} up", ns=netns)
797
798 with NetNSEnter(str(netns)):
799 netdevnl = NetdevFamily()
800 netdevnl.queue_create(
801 {
802 "ifindex": nk_guest_a_idx,
803 "type": "rx",
804 "lease": {
805 "ifindex": nsim.ifindex,
806 "queue": {"id": 1, "type": "rx"},
807 "netns-id": 0,
808 },
809 }
810 )
811 netdevnl.queue_create(
812 {
813 "ifindex": nk_guest_b_idx,
814 "type": "rx",
815 "lease": {
816 "ifindex": nsim.ifindex,
817 "queue": {"id": 2, "type": "rx"},
818 "netns-id": 0,
819 },
820 }
821 )
822
823 # Removing the physical device should take down both netkit pairs
824 nsimdev.remove()
825 wait_until(lambda: cmd(f"ip link show dev {nk_host_a}", fail=False).ret != 0
826 and cmd(f"ip link show dev {nk_host_b}", fail=False).ret != 0)
827 ret = cmd(f"ip link show dev {nk_host_a}", fail=False)
828 ksft_ne(ret.ret, 0)
829 ret = cmd(f"ip link show dev {nk_host_b}", fail=False)
830 ksft_ne(ret.ret, 0)
831
832
833def test_single_remove_phys(_netns) -> None:
834 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
835 defer(nsimdev.remove)
836 nsim = nsimdev.nsims[0]
837 ip(f"link set dev {nsim.ifname} up")
838
839 nk_name, nk_idx = create_netkit_single(rxqueues=2)
840 defer(cmd, f"ip link del dev {nk_name}", fail=False)
841
842 ip(f"link set dev {nk_name} up")
843
844 netdevnl = NetdevFamily()
845 netdevnl.queue_create(
846 {
847 "ifindex": nk_idx,
848 "type": "rx",
849 "lease": {
850 "ifindex": nsim.ifindex,
851 "queue": {"id": 1, "type": "rx"},
852 },
853 }
854 )
855
856 # Removing the physical device should take down the single netkit device
857 nsimdev.remove()
858 wait_until(lambda: cmd(f"ip link show dev {nk_name}", fail=False).ret != 0)
859 ret = cmd(f"ip link show dev {nk_name}", fail=False)
860 ksft_ne(ret.ret, 0)
861
862
863def test_link_flap_virt(netns) -> None:
864 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
865 defer(nsimdev.remove)
866 nsim = nsimdev.nsims[0]
867 ip(f"link set dev {nsim.ifname} up")
868
869 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
870 defer(cmd, f"ip link del dev {nk_host}")
871
872 ip(f"link set dev {nk_guest} netns {netns.name}")
873 ip(f"link set dev {nk_host} up")
874 ip(f"link set dev {nk_guest} up", ns=netns)
875
876 src_queue = 1
877 with NetNSEnter(str(netns)):
878 netdevnl = NetdevFamily()
879 result = netdevnl.queue_create(
880 {
881 "ifindex": nk_guest_idx,
882 "type": "rx",
883 "lease": {
884 "ifindex": nsim.ifindex,
885 "queue": {"id": src_queue, "type": "rx"},
886 "netns-id": 0,
887 },
888 }
889 )
890 nk_queue_id = result["id"]
891
892 netdevnl = NetdevFamily()
893 queue_info = netdevnl.queue_get(
894 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
895 )
896 ksft_in("lease", queue_info)
897 ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
898
899 # Link flap the virtual (netkit) device
900 ip(f"link set dev {nk_guest} down", ns=netns)
901 ip(f"link set dev {nk_guest} up", ns=netns)
902
903 # Verify lease survives the virtual device flap
904 queue_info = netdevnl.queue_get(
905 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
906 )
907 ksft_in("lease", queue_info)
908 ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
909
910
911def test_phys_queue_no_lease(netns) -> None:
912 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
913 defer(nsimdev.remove)
914 nsim = nsimdev.nsims[0]
915 ip(f"link set dev {nsim.ifname} up")
916
917 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
918 defer(cmd, f"ip link del dev {nk_host}")
919
920 ip(f"link set dev {nk_guest} netns {netns.name}")
921 ip(f"link set dev {nk_host} up")
922 ip(f"link set dev {nk_guest} up", ns=netns)
923
924 with NetNSEnter(str(netns)):
925 netdevnl = NetdevFamily()
926 netdevnl.queue_create(
927 {
928 "ifindex": nk_guest_idx,
929 "type": "rx",
930 "lease": {
931 "ifindex": nsim.ifindex,
932 "queue": {"id": 1, "type": "rx"},
933 "netns-id": 0,
934 },
935 }
936 )
937
938 # Physical queue 0 (not leased) should have no lease info
939 netdevnl = NetdevFamily()
940 queue_info = netdevnl.queue_get(
941 {"ifindex": nsim.ifindex, "id": 0, "type": "rx"}
942 )
943 ksft_not_in("lease", queue_info)
944
945 # Physical queue 1 (leased) should have lease info
946 queue_info = netdevnl.queue_get(
947 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
948 )
949 ksft_in("lease", queue_info)
950
951
952def test_same_ns_lease(_netns) -> None:
953 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
954 defer(nsimdev.remove)
955 nsim = nsimdev.nsims[0]
956 ip(f"link set dev {nsim.ifname} up")
957
958 nk_name, nk_idx = create_netkit_single(rxqueues=2)
959 defer(cmd, f"ip link del dev {nk_name}", fail=False)
960
961 ip(f"link set dev {nk_name} up")
962
963 netdevnl = NetdevFamily()
964 result = netdevnl.queue_create(
965 {
966 "ifindex": nk_idx,
967 "type": "rx",
968 "lease": {
969 "ifindex": nsim.ifindex,
970 "queue": {"id": 1, "type": "rx"},
971 },
972 }
973 )
974 ksft_eq(result["id"], 1)
975
976 # Same namespace: lease info should NOT have netns-id
977 queue_info = netdevnl.queue_get(
978 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
979 )
980 ksft_in("lease", queue_info)
981 ksft_eq(queue_info["lease"]["ifindex"], nk_idx)
982 ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
983 ksft_not_in("netns-id", queue_info["lease"])
984
985
986def test_resize_after_unlease(netns) -> None:
987 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
988 defer(nsimdev.remove)
989 nsim = nsimdev.nsims[0]
990 ip(f"link set dev {nsim.ifname} up")
991
992 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
993
994 ip(f"link set dev {nk_guest} netns {netns.name}")
995 ip(f"link set dev {nk_host} up")
996 ip(f"link set dev {nk_guest} up", ns=netns)
997
998 with NetNSEnter(str(netns)):
999 netdevnl = NetdevFamily()
1000 netdevnl.queue_create(
1001 {
1002 "ifindex": nk_guest_idx,
1003 "type": "rx",
1004 "lease": {
1005 "ifindex": nsim.ifindex,
1006 "queue": {"id": 1, "type": "rx"},
1007 "netns-id": 0,
1008 },
1009 }
1010 )
1011
1012 # Resize should fail while lease is active
1013 ethnl = EthtoolFamily()
1014 with ksft_raises(NlError) as e:
1015 ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
1016 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
1017
1018 # Delete netkit, clearing the lease
1019 cmd(f"ip link del dev {nk_host}")
1020
1021 # Resize should now succeed
1022 ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
1023
1024
1025def test_lease_queue_zero(netns) -> None:
1026 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1027 defer(nsimdev.remove)
1028 nsim = nsimdev.nsims[0]
1029 ip(f"link set dev {nsim.ifname} up")
1030
1031 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1032 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1033
1034 ip(f"link set dev {nk_guest} netns {netns.name}")
1035 ip(f"link set dev {nk_host} up")
1036 ip(f"link set dev {nk_guest} up", ns=netns)
1037
1038 with NetNSEnter(str(netns)):
1039 netdevnl = NetdevFamily()
1040 result = netdevnl.queue_create(
1041 {
1042 "ifindex": nk_guest_idx,
1043 "type": "rx",
1044 "lease": {
1045 "ifindex": nsim.ifindex,
1046 "queue": {"id": 0, "type": "rx"},
1047 "netns-id": 0,
1048 },
1049 }
1050 )
1051 ksft_eq(result["id"], 1)
1052
1053 netdevnl = NetdevFamily()
1054 queue_info = netdevnl.queue_get(
1055 {"ifindex": nsim.ifindex, "id": 0, "type": "rx"}
1056 )
1057 ksft_in("lease", queue_info)
1058 ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
1059
1060
1061def test_release_and_reuse(netns) -> None:
1062 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1063 defer(nsimdev.remove)
1064 nsim = nsimdev.nsims[0]
1065 ip(f"link set dev {nsim.ifname} up")
1066
1067 src_queue = 1
1068
1069 # First lease
1070 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1071
1072 ip(f"link set dev {nk_guest} netns {netns.name}")
1073 ip(f"link set dev {nk_host} up")
1074 ip(f"link set dev {nk_guest} up", ns=netns)
1075
1076 with NetNSEnter(str(netns)):
1077 netdevnl = NetdevFamily()
1078 netdevnl.queue_create(
1079 {
1080 "ifindex": nk_guest_idx,
1081 "type": "rx",
1082 "lease": {
1083 "ifindex": nsim.ifindex,
1084 "queue": {"id": src_queue, "type": "rx"},
1085 "netns-id": 0,
1086 },
1087 }
1088 )
1089
1090 netdevnl = NetdevFamily()
1091 queue_info = netdevnl.queue_get(
1092 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1093 )
1094 ksft_in("lease", queue_info)
1095
1096 # Delete netkit, freeing the lease
1097 cmd(f"ip link del dev {nk_host}")
1098
1099 queue_info = netdevnl.queue_get(
1100 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1101 )
1102 ksft_not_in("lease", queue_info)
1103
1104 # Re-create netkit and lease the same physical queue again
1105 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1106 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1107
1108 ip(f"link set dev {nk_guest} netns {netns.name}")
1109 ip(f"link set dev {nk_host} up")
1110 ip(f"link set dev {nk_guest} up", ns=netns)
1111
1112 with NetNSEnter(str(netns)):
1113 netdevnl = NetdevFamily()
1114 result = netdevnl.queue_create(
1115 {
1116 "ifindex": nk_guest_idx,
1117 "type": "rx",
1118 "lease": {
1119 "ifindex": nsim.ifindex,
1120 "queue": {"id": src_queue, "type": "rx"},
1121 "netns-id": 0,
1122 },
1123 }
1124 )
1125 ksft_eq(result["id"], 1)
1126
1127 netdevnl = NetdevFamily()
1128 queue_info = netdevnl.queue_get(
1129 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1130 )
1131 ksft_in("lease", queue_info)
1132 ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
1133
1134
1135def test_two_netkits_same_queue(netns) -> None:
1136 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1137 defer(nsimdev.remove)
1138 nsim = nsimdev.nsims[0]
1139 ip(f"link set dev {nsim.ifname} up")
1140
1141 nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
1142 defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
1143
1144 nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
1145 defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
1146
1147 ip(f"link set dev {nk_guest_a} netns {netns.name}")
1148 ip(f"link set dev {nk_host_a} up")
1149 ip(f"link set dev {nk_guest_a} up", ns=netns)
1150
1151 ip(f"link set dev {nk_guest_b} netns {netns.name}")
1152 ip(f"link set dev {nk_host_b} up")
1153 ip(f"link set dev {nk_guest_b} up", ns=netns)
1154
1155 src_queue = 1
1156 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1157 netdevnl_ns.queue_create(
1158 {
1159 "ifindex": nk_guest_a_idx,
1160 "type": "rx",
1161 "lease": {
1162 "ifindex": nsim.ifindex,
1163 "queue": {"id": src_queue, "type": "rx"},
1164 "netns-id": 0,
1165 },
1166 }
1167 )
1168
1169 with ksft_raises(NlError) as e:
1170 netdevnl_ns.queue_create(
1171 {
1172 "ifindex": nk_guest_b_idx,
1173 "type": "rx",
1174 "lease": {
1175 "ifindex": nsim.ifindex,
1176 "queue": {"id": src_queue, "type": "rx"},
1177 "netns-id": 0,
1178 },
1179 }
1180 )
1181 ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
1182
1183
1184def test_l3_mode_lease(netns) -> None:
1185 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1186 defer(nsimdev.remove)
1187 nsim = nsimdev.nsims[0]
1188 ip(f"link set dev {nsim.ifname} up")
1189
1190 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2, mode="l3")
1191 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1192
1193 ip(f"link set dev {nk_guest} netns {netns.name}")
1194 ip(f"link set dev {nk_host} up")
1195 ip(f"link set dev {nk_guest} up", ns=netns)
1196
1197 src_queue = 1
1198 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1199 result = netdevnl_ns.queue_create(
1200 {
1201 "ifindex": nk_guest_idx,
1202 "type": "rx",
1203 "lease": {
1204 "ifindex": nsim.ifindex,
1205 "queue": {"id": src_queue, "type": "rx"},
1206 "netns-id": 0,
1207 },
1208 }
1209 )
1210 ksft_eq(result["id"], 1)
1211
1212 netdevnl = NetdevFamily()
1213 queue_info = netdevnl.queue_get(
1214 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1215 )
1216 ksft_in("lease", queue_info)
1217 ksft_eq(queue_info["lease"]["ifindex"], nk_guest_idx)
1218 ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
1219
1220
1221def test_single_double_lease(_netns) -> None:
1222 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1223 defer(nsimdev.remove)
1224 nsim = nsimdev.nsims[0]
1225 ip(f"link set dev {nsim.ifname} up")
1226
1227 nk_name, nk_idx = create_netkit_single(rxqueues=3)
1228 defer(cmd, f"ip link del dev {nk_name}", fail=False)
1229
1230 ip(f"link set dev {nk_name} up")
1231
1232 netdevnl = NetdevFamily()
1233 result = netdevnl.queue_create(
1234 {
1235 "ifindex": nk_idx,
1236 "type": "rx",
1237 "lease": {
1238 "ifindex": nsim.ifindex,
1239 "queue": {"id": 1, "type": "rx"},
1240 },
1241 }
1242 )
1243 ksft_eq(result["id"], 1)
1244
1245 with ksft_raises(NlError) as e:
1246 netdevnl.queue_create(
1247 {
1248 "ifindex": nk_idx,
1249 "type": "rx",
1250 "lease": {
1251 "ifindex": nsim.ifindex,
1252 "queue": {"id": 1, "type": "rx"},
1253 },
1254 }
1255 )
1256 ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
1257
1258
1259def test_single_different_lessors(_netns) -> None:
1260 nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
1261 defer(nsimdev_a.remove)
1262 nsim_a = nsimdev_a.nsims[0]
1263 ip(f"link set dev {nsim_a.ifname} up")
1264
1265 nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
1266 defer(nsimdev_b.remove)
1267 nsim_b = nsimdev_b.nsims[0]
1268 ip(f"link set dev {nsim_b.ifname} up")
1269
1270 nk_name, nk_idx = create_netkit_single(rxqueues=3)
1271 defer(cmd, f"ip link del dev {nk_name}", fail=False)
1272
1273 ip(f"link set dev {nk_name} up")
1274
1275 netdevnl = NetdevFamily()
1276 netdevnl.queue_create(
1277 {
1278 "ifindex": nk_idx,
1279 "type": "rx",
1280 "lease": {
1281 "ifindex": nsim_a.ifindex,
1282 "queue": {"id": 1, "type": "rx"},
1283 },
1284 }
1285 )
1286
1287 with ksft_raises(NlError) as e:
1288 netdevnl.queue_create(
1289 {
1290 "ifindex": nk_idx,
1291 "type": "rx",
1292 "lease": {
1293 "ifindex": nsim_b.ifindex,
1294 "queue": {"id": 1, "type": "rx"},
1295 },
1296 }
1297 )
1298 ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
1299
1300
1301def test_cross_ns_netns_id(netns) -> None:
1302 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1303 defer(nsimdev.remove)
1304 nsim = nsimdev.nsims[0]
1305 ip(f"link set dev {nsim.ifname} up")
1306
1307 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1308 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1309
1310 ip(f"link set dev {nk_guest} netns {netns.name}")
1311 ip(f"link set dev {nk_host} up")
1312 ip(f"link set dev {nk_guest} up", ns=netns)
1313
1314 src_queue = 1
1315 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1316 netdevnl_ns.queue_create(
1317 {
1318 "ifindex": nk_guest_idx,
1319 "type": "rx",
1320 "lease": {
1321 "ifindex": nsim.ifindex,
1322 "queue": {"id": src_queue, "type": "rx"},
1323 "netns-id": 0,
1324 },
1325 }
1326 )
1327
1328 netdevnl = NetdevFamily()
1329 queue_info = netdevnl.queue_get(
1330 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1331 )
1332 ksft_in("lease", queue_info)
1333 ksft_in("netns-id", queue_info["lease"])
1334
1335
1336def test_delete_guest_netns(_netns) -> None:
1337 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1338 defer(nsimdev.remove)
1339 nsim = nsimdev.nsims[0]
1340 ip(f"link set dev {nsim.ifname} up")
1341
1342 test_ns = NetNS()
1343 ip("netns set init 0", ns=test_ns)
1344 ip("link set lo up", ns=test_ns)
1345
1346 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1347 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1348
1349 ip(f"link set dev {nk_guest} netns {test_ns.name}")
1350 ip(f"link set dev {nk_host} up")
1351 ip(f"link set dev {nk_guest} up", ns=test_ns)
1352
1353 src_queue = 1
1354 with NetNSEnter(str(test_ns)), NetdevFamily() as netdevnl_ns:
1355 netdevnl_ns.queue_create(
1356 {
1357 "ifindex": nk_guest_idx,
1358 "type": "rx",
1359 "lease": {
1360 "ifindex": nsim.ifindex,
1361 "queue": {"id": src_queue, "type": "rx"},
1362 "netns-id": 0,
1363 },
1364 }
1365 )
1366
1367 netdevnl = NetdevFamily()
1368 queue_info = netdevnl.queue_get(
1369 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1370 )
1371 ksft_in("lease", queue_info)
1372
1373 del test_ns
1374 wait_until(lambda: "lease" not in netdevnl.queue_get(
1375 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}))
1376
1377 queue_info = netdevnl.queue_get(
1378 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1379 )
1380 ksft_not_in("lease", queue_info)
1381
1382 ret = cmd(f"ip link show dev {nk_host}", fail=False)
1383 ksft_ne(ret.ret, 0)
1384
1385
1386def test_move_guest_netns(netns) -> None:
1387 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1388 defer(nsimdev.remove)
1389 nsim = nsimdev.nsims[0]
1390 ip(f"link set dev {nsim.ifname} up")
1391
1392 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1393 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1394
1395 ip(f"link set dev {nk_guest} netns {netns.name}")
1396 ip(f"link set dev {nk_host} up")
1397 ip(f"link set dev {nk_guest} up", ns=netns)
1398
1399 src_queue = 1
1400 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1401 result = netdevnl_ns.queue_create(
1402 {
1403 "ifindex": nk_guest_idx,
1404 "type": "rx",
1405 "lease": {
1406 "ifindex": nsim.ifindex,
1407 "queue": {"id": src_queue, "type": "rx"},
1408 "netns-id": 0,
1409 },
1410 }
1411 )
1412 nk_queue_id = result["id"]
1413
1414 netdevnl = NetdevFamily()
1415 queue_info = netdevnl.queue_get(
1416 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1417 )
1418 ksft_in("lease", queue_info)
1419 ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
1420
1421 new_ns = NetNS()
1422 defer(new_ns.__del__)
1423 ip(f"link set dev {nk_guest} netns {new_ns.name}", ns=netns)
1424
1425 queue_info = netdevnl.queue_get(
1426 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1427 )
1428 ksft_in("lease", queue_info)
1429 ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
1430
1431
1432def test_resize_phys_no_reduction(netns) -> None:
1433 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1434 defer(nsimdev.remove)
1435 nsim = nsimdev.nsims[0]
1436 ip(f"link set dev {nsim.ifname} up")
1437
1438 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1439 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1440
1441 ip(f"link set dev {nk_guest} netns {netns.name}")
1442 ip(f"link set dev {nk_host} up")
1443 ip(f"link set dev {nk_guest} up", ns=netns)
1444
1445 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1446 netdevnl_ns.queue_create(
1447 {
1448 "ifindex": nk_guest_idx,
1449 "type": "rx",
1450 "lease": {
1451 "ifindex": nsim.ifindex,
1452 "queue": {"id": 1, "type": "rx"},
1453 "netns-id": 0,
1454 },
1455 }
1456 )
1457
1458 ethnl = EthtoolFamily()
1459 ethnl.channels_set(
1460 {"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
1461 )
1462
1463 netdevnl = NetdevFamily()
1464 queue_info = netdevnl.queue_get(
1465 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1466 )
1467 ksft_in("lease", queue_info)
1468
1469
1470def test_delete_one_netkit_of_two(netns) -> None:
1471 nsimdev = NetdevSimDev(port_count=1, queue_count=3)
1472 defer(nsimdev.remove)
1473 nsim = nsimdev.nsims[0]
1474 ip(f"link set dev {nsim.ifname} up")
1475
1476 nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
1477 defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
1478
1479 nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
1480 defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
1481
1482 ip(f"link set dev {nk_guest_a} netns {netns.name}")
1483 ip(f"link set dev {nk_host_a} up")
1484 ip(f"link set dev {nk_guest_a} up", ns=netns)
1485
1486 ip(f"link set dev {nk_guest_b} netns {netns.name}")
1487 ip(f"link set dev {nk_host_b} up")
1488 ip(f"link set dev {nk_guest_b} up", ns=netns)
1489
1490 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1491 netdevnl_ns.queue_create(
1492 {
1493 "ifindex": nk_guest_a_idx,
1494 "type": "rx",
1495 "lease": {
1496 "ifindex": nsim.ifindex,
1497 "queue": {"id": 1, "type": "rx"},
1498 "netns-id": 0,
1499 },
1500 }
1501 )
1502 netdevnl_ns.queue_create(
1503 {
1504 "ifindex": nk_guest_b_idx,
1505 "type": "rx",
1506 "lease": {
1507 "ifindex": nsim.ifindex,
1508 "queue": {"id": 2, "type": "rx"},
1509 "netns-id": 0,
1510 },
1511 }
1512 )
1513
1514 netdevnl = NetdevFamily()
1515 q1 = netdevnl.queue_get(
1516 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1517 )
1518 q2 = netdevnl.queue_get(
1519 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
1520 )
1521 ksft_in("lease", q1)
1522 ksft_in("lease", q2)
1523
1524 cmd(f"ip link del dev {nk_host_a}")
1525
1526 q1 = netdevnl.queue_get(
1527 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1528 )
1529 q2 = netdevnl.queue_get(
1530 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
1531 )
1532 ksft_not_in("lease", q1)
1533 ksft_in("lease", q2)
1534
1535
1536def test_bind_rx_leased_phys_queue(netns) -> None:
1537 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1538 defer(nsimdev.remove)
1539 nsim = nsimdev.nsims[0]
1540 ip(f"link set dev {nsim.ifname} up")
1541
1542 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1543 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1544
1545 ip(f"link set dev {nk_guest} netns {netns.name}")
1546 ip(f"link set dev {nk_host} up")
1547 ip(f"link set dev {nk_guest} up", ns=netns)
1548
1549 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1550 netdevnl_ns.queue_create(
1551 {
1552 "ifindex": nk_guest_idx,
1553 "type": "rx",
1554 "lease": {
1555 "ifindex": nsim.ifindex,
1556 "queue": {"id": 1, "type": "rx"},
1557 "netns-id": 0,
1558 },
1559 }
1560 )
1561
1562 netdevnl = NetdevFamily()
1563 with ksft_raises(NlError) as e:
1564 netdevnl.bind_rx(
1565 {
1566 "ifindex": nsim.ifindex,
1567 "fd": 0,
1568 "queues": [
1569 {"id": 0, "type": "rx"},
1570 {"id": 1, "type": "rx"},
1571 ],
1572 }
1573 )
1574 ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
1575
1576
1577def test_resize_phys_shrink_past_leased(netns) -> None:
1578 nsimdev = NetdevSimDev(port_count=1, queue_count=4)
1579 defer(nsimdev.remove)
1580 nsim = nsimdev.nsims[0]
1581 ip(f"link set dev {nsim.ifname} up")
1582
1583 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1584 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1585
1586 ip(f"link set dev {nk_guest} netns {netns.name}")
1587 ip(f"link set dev {nk_host} up")
1588 ip(f"link set dev {nk_guest} up", ns=netns)
1589
1590 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1591 netdevnl_ns.queue_create(
1592 {
1593 "ifindex": nk_guest_idx,
1594 "type": "rx",
1595 "lease": {
1596 "ifindex": nsim.ifindex,
1597 "queue": {"id": 1, "type": "rx"},
1598 "netns-id": 0,
1599 },
1600 }
1601 )
1602
1603 ethnl = EthtoolFamily()
1604
1605 # Shrink past the leased queue — only queue 3 removed, queue 1 untouched
1606 ethnl.channels_set(
1607 {"header": {"dev-index": nsim.ifindex}, "combined-count": 3}
1608 )
1609
1610 netdevnl = NetdevFamily()
1611 queue_info = netdevnl.queue_get(
1612 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1613 )
1614 ksft_in("lease", queue_info)
1615
1616 # Shrink further — queue 2 removed, queue 1 still untouched
1617 ethnl.channels_set(
1618 {"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
1619 )
1620
1621 queue_info = netdevnl.queue_get(
1622 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1623 )
1624 ksft_in("lease", queue_info)
1625
1626 # Shrink into the leased queue — queue 1 is busy, must fail
1627 with ksft_raises(NlError) as e:
1628 ethnl.channels_set(
1629 {"header": {"dev-index": nsim.ifindex}, "combined-count": 1}
1630 )
1631 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
1632
1633
1634def test_resize_virt_not_supported(netns) -> None:
1635 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1636 defer(nsimdev.remove)
1637 nsim = nsimdev.nsims[0]
1638 ip(f"link set dev {nsim.ifname} up")
1639
1640 nk_host, nk_host_idx, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1641 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1642
1643 ip(f"link set dev {nk_guest} netns {netns.name}")
1644 ip(f"link set dev {nk_host} up")
1645 ip(f"link set dev {nk_guest} up", ns=netns)
1646
1647 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1648 netdevnl_ns.queue_create(
1649 {
1650 "ifindex": nk_guest_idx,
1651 "type": "rx",
1652 "lease": {
1653 "ifindex": nsim.ifindex,
1654 "queue": {"id": 1, "type": "rx"},
1655 "netns-id": 0,
1656 },
1657 }
1658 )
1659
1660 # Channel resize on the netkit host must fail — not supported
1661 ethnl = EthtoolFamily()
1662 with ksft_raises(NlError) as e:
1663 ethnl.channels_set(
1664 {"header": {"dev-index": nk_host_idx}, "combined-count": 1}
1665 )
1666 ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
1667
1668 # Lease must be intact
1669 netdevnl = NetdevFamily()
1670 queue_info = netdevnl.queue_get(
1671 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1672 )
1673 ksft_in("lease", queue_info)
1674
1675
1676def test_lease_devices_down(netns) -> None:
1677 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1678 defer(nsimdev.remove)
1679 nsim = nsimdev.nsims[0]
1680
1681 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1682 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1683
1684 ip(f"link set dev {nk_guest} netns {netns.name}")
1685
1686 # Create lease while both physical and virtual devices are down
1687 src_queue = 1
1688 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1689 result = netdevnl_ns.queue_create(
1690 {
1691 "ifindex": nk_guest_idx,
1692 "type": "rx",
1693 "lease": {
1694 "ifindex": nsim.ifindex,
1695 "queue": {"id": src_queue, "type": "rx"},
1696 "netns-id": 0,
1697 },
1698 }
1699 )
1700 ksft_eq(result["id"], 1)
1701
1702 # Bring devices up before queue_get: netdevsim only instantiates NAPIs in
1703 # ndo_open, and netdev-genl queue_get returns -ENOENT without a NAPI.
1704 ip(f"link set dev {nsim.ifname} up")
1705 ip(f"link set dev {nk_host} up")
1706 ip(f"link set dev {nk_guest} up", ns=netns)
1707
1708 netdevnl = NetdevFamily()
1709 queue_info = netdevnl.queue_get(
1710 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
1711 )
1712 ksft_in("lease", queue_info)
1713 ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
1714
1715
1716def test_lease_capacity_exhaustion(netns) -> None:
1717 nsimdev = NetdevSimDev(port_count=1, queue_count=4)
1718 defer(nsimdev.remove)
1719 nsim = nsimdev.nsims[0]
1720 ip(f"link set dev {nsim.ifname} up")
1721
1722 # rxqueues=3 means num_rx_queues=3, real_num_rx_queues starts at 1.
1723 # Can create 2 leased queues (real goes 1->2->3) but not a 3rd (3->4 > 3).
1724 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
1725 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1726
1727 ip(f"link set dev {nk_guest} netns {netns.name}")
1728 ip(f"link set dev {nk_host} up")
1729 ip(f"link set dev {nk_guest} up", ns=netns)
1730
1731 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1732 r1 = netdevnl_ns.queue_create(
1733 {
1734 "ifindex": nk_guest_idx,
1735 "type": "rx",
1736 "lease": {
1737 "ifindex": nsim.ifindex,
1738 "queue": {"id": 1, "type": "rx"},
1739 "netns-id": 0,
1740 },
1741 }
1742 )
1743 ksft_eq(r1["id"], 1)
1744
1745 r2 = netdevnl_ns.queue_create(
1746 {
1747 "ifindex": nk_guest_idx,
1748 "type": "rx",
1749 "lease": {
1750 "ifindex": nsim.ifindex,
1751 "queue": {"id": 2, "type": "rx"},
1752 "netns-id": 0,
1753 },
1754 }
1755 )
1756 ksft_eq(r2["id"], 2)
1757
1758 # Third lease fails — netkit queue capacity exhausted
1759 with ksft_raises(NlError) as e:
1760 netdevnl_ns.queue_create(
1761 {
1762 "ifindex": nk_guest_idx,
1763 "type": "rx",
1764 "lease": {
1765 "ifindex": nsim.ifindex,
1766 "queue": {"id": 3, "type": "rx"},
1767 "netns-id": 0,
1768 },
1769 }
1770 )
1771 ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
1772
1773 # Verify the two successful leases are intact
1774 netdevnl = NetdevFamily()
1775 q1 = netdevnl.queue_get(
1776 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1777 )
1778 q2 = netdevnl.queue_get(
1779 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
1780 )
1781 ksft_in("lease", q1)
1782 ksft_in("lease", q2)
1783
1784
1785def test_resize_phys_up(netns) -> None:
1786 nsimdev = NetdevSimDev(port_count=1, queue_count=3)
1787 defer(nsimdev.remove)
1788 nsim = nsimdev.nsims[0]
1789 ip(f"link set dev {nsim.ifname} up")
1790
1791 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1792 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1793
1794 ip(f"link set dev {nk_guest} netns {netns.name}")
1795 ip(f"link set dev {nk_host} up")
1796 ip(f"link set dev {nk_guest} up", ns=netns)
1797
1798 # Shrink nsim first so we have room to grow
1799 ethnl = EthtoolFamily()
1800 ethnl.channels_set(
1801 {"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
1802 )
1803
1804 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1805 netdevnl_ns.queue_create(
1806 {
1807 "ifindex": nk_guest_idx,
1808 "type": "rx",
1809 "lease": {
1810 "ifindex": nsim.ifindex,
1811 "queue": {"id": 1, "type": "rx"},
1812 "netns-id": 0,
1813 },
1814 }
1815 )
1816
1817 # Grow channels — should succeed since leased queue is not removed
1818 ethnl.channels_set(
1819 {"header": {"dev-index": nsim.ifindex}, "combined-count": 3}
1820 )
1821
1822 netdevnl = NetdevFamily()
1823 queue_info = netdevnl.queue_get(
1824 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1825 )
1826 ksft_in("lease", queue_info)
1827
1828 # New queue 2 should exist without a lease
1829 queue_info = netdevnl.queue_get(
1830 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
1831 )
1832 ksft_not_in("lease", queue_info)
1833
1834
1835def test_multi_ns_lease(netns) -> None:
1836 nsimdev = NetdevSimDev(port_count=1, queue_count=3)
1837 defer(nsimdev.remove)
1838 nsim = nsimdev.nsims[0]
1839 ip(f"link set dev {nsim.ifname} up")
1840
1841 ns_b = NetNS()
1842 defer(ns_b.__del__)
1843 ip("netns set init 0", ns=ns_b)
1844 ip("link set lo up", ns=ns_b)
1845
1846 # First netkit pair, guest in netns
1847 nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
1848 defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
1849 ip(f"link set dev {nk_guest_a} netns {netns.name}")
1850 ip(f"link set dev {nk_host_a} up")
1851 ip(f"link set dev {nk_guest_a} up", ns=netns)
1852
1853 # Second netkit pair, guest in ns_b
1854 nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
1855 defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
1856 ip(f"link set dev {nk_guest_b} netns {ns_b.name}")
1857 ip(f"link set dev {nk_host_b} up")
1858 ip(f"link set dev {nk_guest_b} up", ns=ns_b)
1859
1860 # Lease from netns
1861 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1862 result = netdevnl_ns.queue_create(
1863 {
1864 "ifindex": nk_guest_a_idx,
1865 "type": "rx",
1866 "lease": {
1867 "ifindex": nsim.ifindex,
1868 "queue": {"id": 1, "type": "rx"},
1869 "netns-id": 0,
1870 },
1871 }
1872 )
1873 ksft_eq(result["id"], 1)
1874
1875 # Lease from ns_b (different namespace, same physical device)
1876 with NetNSEnter(str(ns_b)), NetdevFamily() as netdevnl_ns:
1877 result = netdevnl_ns.queue_create(
1878 {
1879 "ifindex": nk_guest_b_idx,
1880 "type": "rx",
1881 "lease": {
1882 "ifindex": nsim.ifindex,
1883 "queue": {"id": 2, "type": "rx"},
1884 "netns-id": 0,
1885 },
1886 }
1887 )
1888 ksft_eq(result["id"], 1)
1889
1890 # Verify both leases from the physical side
1891 netdevnl = NetdevFamily()
1892 q1 = netdevnl.queue_get(
1893 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1894 )
1895 q2 = netdevnl.queue_get(
1896 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
1897 )
1898 ksft_in("lease", q1)
1899 ksft_in("lease", q2)
1900 ksft_eq(q1["lease"]["ifindex"], nk_guest_a_idx)
1901 ksft_eq(q2["lease"]["ifindex"], nk_guest_b_idx)
1902
1903
1904def test_multi_ns_delete_one(netns) -> None:
1905 nsimdev = NetdevSimDev(port_count=1, queue_count=3)
1906 defer(nsimdev.remove)
1907 nsim = nsimdev.nsims[0]
1908 ip(f"link set dev {nsim.ifname} up")
1909
1910 ns_b = NetNS()
1911 ip("netns set init 0", ns=ns_b)
1912 ip("link set lo up", ns=ns_b)
1913
1914 # First netkit pair, guest in netns (ns_a)
1915 nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
1916 defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
1917 ip(f"link set dev {nk_guest_a} netns {netns.name}")
1918 ip(f"link set dev {nk_host_a} up")
1919 ip(f"link set dev {nk_guest_a} up", ns=netns)
1920
1921 # Second netkit pair, guest in ns_b
1922 nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
1923 defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
1924
1925 ip(f"link set dev {nk_guest_b} netns {ns_b.name}")
1926 ip(f"link set dev {nk_host_b} up")
1927 ip(f"link set dev {nk_guest_b} up", ns=ns_b)
1928
1929 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
1930 netdevnl_ns.queue_create(
1931 {
1932 "ifindex": nk_guest_a_idx,
1933 "type": "rx",
1934 "lease": {
1935 "ifindex": nsim.ifindex,
1936 "queue": {"id": 1, "type": "rx"},
1937 "netns-id": 0,
1938 },
1939 }
1940 )
1941
1942 with NetNSEnter(str(ns_b)), NetdevFamily() as netdevnl_ns:
1943 netdevnl_ns.queue_create(
1944 {
1945 "ifindex": nk_guest_b_idx,
1946 "type": "rx",
1947 "lease": {
1948 "ifindex": nsim.ifindex,
1949 "queue": {"id": 2, "type": "rx"},
1950 "netns-id": 0,
1951 },
1952 }
1953 )
1954
1955 netdevnl = NetdevFamily()
1956 q1 = netdevnl.queue_get(
1957 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1958 )
1959 q2 = netdevnl.queue_get(
1960 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
1961 )
1962 ksft_in("lease", q1)
1963 ksft_in("lease", q2)
1964
1965 # Delete ns_b — destroys nk_guest_b, triggers unlease of queue 2
1966 del ns_b
1967 wait_until(lambda: "lease" not in netdevnl.queue_get(
1968 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}))
1969
1970 # ns_a's lease on queue 1 must survive
1971 q1 = netdevnl.queue_get(
1972 {"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
1973 )
1974 ksft_in("lease", q1)
1975 ksft_eq(q1["lease"]["ifindex"], nk_guest_a_idx)
1976
1977 # ns_b's lease on queue 2 must be gone
1978 q2 = netdevnl.queue_get(
1979 {"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
1980 )
1981 ksft_not_in("lease", q2)
1982
1983 # nk_host_b should be gone too (phys removal cascades to netkit pair)
1984 ret = cmd(f"ip link show dev {nk_host_b}", fail=False)
1985 ksft_ne(ret.ret, 0)
1986
1987
1988def test_move_phys_netns(netns) -> None:
1989 nsimdev = NetdevSimDev(port_count=1, queue_count=2)
1990 defer(nsimdev.remove)
1991 nsim = nsimdev.nsims[0]
1992 ip(f"link set dev {nsim.ifname} up")
1993
1994 nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
1995 defer(cmd, f"ip link del dev {nk_host}", fail=False)
1996
1997 ip(f"link set dev {nk_guest} netns {netns.name}")
1998 ip(f"link set dev {nk_host} up")
1999 ip(f"link set dev {nk_guest} up", ns=netns)
2000
2001 src_queue = 1
2002 with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
2003 nk_queue_id = netdevnl_ns.queue_create(
2004 {
2005 "ifindex": nk_guest_idx,
2006 "type": "rx",
2007 "lease": {
2008 "ifindex": nsim.ifindex,
2009 "queue": {"id": src_queue, "type": "rx"},
2010 "netns-id": 0,
2011 },
2012 }
2013 )["id"]
2014
2015 netdevnl = NetdevFamily()
2016 queue_info = netdevnl.queue_get(
2017 {"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
2018 )
2019 ksft_in("lease", queue_info)
2020
2021 # Move the physical device to a new namespace. Move it back to init_net
2022 # on cleanup before the other defers fire (new_ns deletion, nsimdev.remove)
2023 # so nsim lives in a stable namespace when they run.
2024 new_ns = NetNS()
2025 defer(new_ns.__del__)
2026 ip(f"link set dev {nsim.ifname} netns {new_ns.name}")
2027 defer(ip, f"link set dev {nsim.ifname} netns init", ns=new_ns)
2028
2029 # Physical device is now in new_ns — find its ifindex there
2030 all_links = ip("-d link show", json=True, ns=new_ns)
2031 nsim_in_new = [lnk for lnk in all_links if lnk.get("ifname") == nsim.ifname]
2032 new_ifindex = nsim_in_new[0]["ifindex"]
2033
2034 # Moving a device across netns brings it admin-down; bring it back up so
2035 # netdevsim re-creates the NAPI (netdev-genl queue_get needs it).
2036 ip(f"link set dev {nsim.ifname} up", ns=new_ns)
2037
2038 # Verify lease survived the namespace move
2039 with NetNSEnter(str(new_ns)), NetdevFamily() as netdevnl_ns:
2040 queue_info = netdevnl_ns.queue_get(
2041 {"ifindex": new_ifindex, "id": src_queue, "type": "rx"}
2042 )
2043 ksft_in("lease", queue_info)
2044 ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
2045
2046
2047def main() -> None:
2048 netns = NetNS()
2049 cmd("ip netns attach init 1")
2050 ip("netns set init 0", ns=netns)
2051 ip("link set lo up", ns=netns)
2052
2053 ksft_run(
2054 [
2055 test_remove_phys,
2056 test_double_lease,
2057 test_virtual_lessor,
2058 test_phys_lessee,
2059 test_different_lessors,
2060 test_queue_out_of_range,
2061 test_resize_leased,
2062 test_self_lease,
2063 test_create_tx_type,
2064 test_create_primary,
2065 test_create_limit,
2066 test_link_flap_phys,
2067 test_queue_get_virtual,
2068 test_remove_virt_first,
2069 test_multiple_leases,
2070 test_lease_queue_tx_type,
2071 test_invalid_netns,
2072 test_invalid_phys_ifindex,
2073 test_multi_netkit_remove_phys,
2074 test_single_remove_phys,
2075 test_link_flap_virt,
2076 test_phys_queue_no_lease,
2077 test_same_ns_lease,
2078 test_resize_after_unlease,
2079 test_lease_queue_zero,
2080 test_release_and_reuse,
2081 test_veth_queue_create,
2082 test_two_netkits_same_queue,
2083 test_l3_mode_lease,
2084 test_single_double_lease,
2085 test_single_different_lessors,
2086 test_cross_ns_netns_id,
2087 test_delete_guest_netns,
2088 test_move_guest_netns,
2089 test_resize_phys_no_reduction,
2090 test_delete_one_netkit_of_two,
2091 test_bind_rx_leased_phys_queue,
2092 test_resize_phys_shrink_past_leased,
2093 test_resize_virt_not_supported,
2094 test_lease_devices_down,
2095 test_lease_capacity_exhaustion,
2096 test_resize_phys_up,
2097 test_multi_ns_lease,
2098 test_multi_ns_delete_one,
2099 test_move_phys_netns,
2100 ],
2101 args=(netns,),
2102 )
2103
2104 cmd("ip netns del init", fail=False)
2105 ksft_exit()
2106
2107
2108if __name__ == "__main__":
2109 main()