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