mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
Add further netkit queue-lease coverage for netns lifecycle of the guest and physical halves, channel resize across active leases, single-device and multi-lessee scenarios, L3 mode operation, lease capacity exhaustion, and corner-cases of e.g. queue-create rejection paths. Also make the tests more robust by removing the time.sleep(0.1) after netns deletion and turn them into a wait loop. Full test run: # ./nk_qlease.py TAP version 13 1..45 ok 1 nk_qlease.test_remove_phys ok 2 nk_qlease.test_double_lease ok 3 nk_qlease.test_virtual_lessor ok 4 nk_qlease.test_phys_lessee ok 5 nk_qlease.test_different_lessors ok 6 nk_qlease.test_queue_out_of_range ok 7 nk_qlease.test_resize_leased ok 8 nk_qlease.test_self_lease ok 9 nk_qlease.test_create_tx_type ok 10 nk_qlease.test_create_primary ok 11 nk_qlease.test_create_limit ok 12 nk_qlease.test_link_flap_phys ok 13 nk_qlease.test_queue_get_virtual ok 14 nk_qlease.test_remove_virt_first ok 15 nk_qlease.test_multiple_leases ok 16 nk_qlease.test_lease_queue_tx_type ok 17 nk_qlease.test_invalid_netns ok 18 nk_qlease.test_invalid_phys_ifindex ok 19 nk_qlease.test_multi_netkit_remove_phys ok 20 nk_qlease.test_single_remove_phys ok 21 nk_qlease.test_link_flap_virt ok 22 nk_qlease.test_phys_queue_no_lease ok 23 nk_qlease.test_same_ns_lease ok 24 nk_qlease.test_resize_after_unlease ok 25 nk_qlease.test_lease_queue_zero ok 26 nk_qlease.test_release_and_reuse ok 27 nk_qlease.test_veth_queue_create ok 28 nk_qlease.test_two_netkits_same_queue ok 29 nk_qlease.test_l3_mode_lease ok 30 nk_qlease.test_single_double_lease ok 31 nk_qlease.test_single_different_lessors ok 32 nk_qlease.test_cross_ns_netns_id ok 33 nk_qlease.test_delete_guest_netns ok 34 nk_qlease.test_move_guest_netns ok 35 nk_qlease.test_resize_phys_no_reduction ok 36 nk_qlease.test_delete_one_netkit_of_two ok 37 nk_qlease.test_bind_rx_leased_phys_queue ok 38 nk_qlease.test_resize_phys_shrink_past_leased ok 39 nk_qlease.test_resize_virt_not_supported ok 40 nk_qlease.test_lease_devices_down ok 41 nk_qlease.test_lease_capacity_exhaustion ok 42 nk_qlease.test_resize_phys_up ok 43 nk_qlease.test_multi_ns_lease ok 44 nk_qlease.test_multi_ns_delete_one ok 45 nk_qlease.test_move_phys_netns # Totals: pass:45 fail:0 xfail:0 xpass:0 skip:0 error:0 Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Link: https://patch.msgid.link/20260413220809.604592-4-daniel@iogearbox.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2110 lines
64 KiB
Python
Executable File
2110 lines
64 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
|
|
import errno
|
|
import time
|
|
from lib.py import (
|
|
ksft_run,
|
|
ksft_exit,
|
|
ksft_eq,
|
|
ksft_ne,
|
|
ksft_in,
|
|
ksft_not_in,
|
|
ksft_raises,
|
|
)
|
|
from lib.py import (
|
|
NetNS,
|
|
NetNSEnter,
|
|
EthtoolFamily,
|
|
NetdevFamily,
|
|
RtnlFamily,
|
|
NetdevSimDev,
|
|
)
|
|
from lib.py import (
|
|
NlError,
|
|
Netlink,
|
|
cmd,
|
|
defer,
|
|
ip,
|
|
)
|
|
|
|
|
|
def wait_until(cond, timeout=2.0, interval=0.05):
|
|
deadline = time.monotonic() + timeout
|
|
while not cond():
|
|
if time.monotonic() >= deadline:
|
|
return
|
|
time.sleep(interval)
|
|
|
|
|
|
def create_netkit(rxqueues, mode="l2"):
|
|
all_links = ip("-d link show", json=True)
|
|
old_idxs = {
|
|
link["ifindex"]
|
|
for link in all_links
|
|
if link.get("linkinfo", {}).get("info_kind") == "netkit"
|
|
}
|
|
|
|
rtnl = RtnlFamily()
|
|
rtnl.newlink(
|
|
{
|
|
"linkinfo": {
|
|
"kind": "netkit",
|
|
"data": {
|
|
"mode": mode,
|
|
"policy": "forward",
|
|
"peer-policy": "forward",
|
|
},
|
|
},
|
|
"num-rx-queues": rxqueues,
|
|
},
|
|
flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL],
|
|
)
|
|
|
|
all_links = ip("-d link show", json=True)
|
|
nk_links = [
|
|
link
|
|
for link in all_links
|
|
if link.get("linkinfo", {}).get("info_kind") == "netkit"
|
|
and link["ifindex"] not in old_idxs
|
|
]
|
|
nk_links.sort(key=lambda x: x["ifindex"])
|
|
return (
|
|
nk_links[1]["ifname"],
|
|
nk_links[1]["ifindex"],
|
|
nk_links[0]["ifname"],
|
|
nk_links[0]["ifindex"],
|
|
)
|
|
|
|
|
|
def create_netkit_single(rxqueues):
|
|
rtnl = RtnlFamily()
|
|
rtnl.newlink(
|
|
{
|
|
"linkinfo": {
|
|
"kind": "netkit",
|
|
"data": {
|
|
"mode": "l2",
|
|
"pairing": "single",
|
|
},
|
|
},
|
|
"num-rx-queues": rxqueues,
|
|
},
|
|
flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL],
|
|
)
|
|
|
|
all_links = ip("-d link show", json=True)
|
|
nk_links = [
|
|
link
|
|
for link in all_links
|
|
if link.get("linkinfo", {}).get("info_kind") == "netkit"
|
|
and "UP" not in link.get("flags", [])
|
|
]
|
|
return nk_links[0]["ifname"], nk_links[0]["ifindex"]
|
|
|
|
|
|
def test_remove_phys(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
nk_queue_id = result["id"]
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["ifindex"], nk_guest_idx)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
|
|
|
|
nsimdev.remove()
|
|
wait_until(lambda: cmd(f"ip link show dev {nk_host}", fail=False).ret != 0)
|
|
ret = cmd(f"ip link show dev {nk_host}", fail=False)
|
|
ksft_ne(ret.ret, 0)
|
|
|
|
|
|
def test_double_lease(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
|
|
defer(cmd, f"ip link del dev {nk_host}")
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
|
|
|
|
|
|
def test_virtual_lessor(netns) -> None:
|
|
nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_a}")
|
|
ip(f"link set dev {nk_host_a} up")
|
|
ip(f"link set dev {nk_guest_a} up")
|
|
|
|
nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_b}")
|
|
|
|
ip(f"link set dev {nk_guest_b} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_b} up")
|
|
ip(f"link set dev {nk_guest_b} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_b_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nk_guest_a_idx,
|
|
"queue": {"id": 0, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_phys_lessee(_netns) -> None:
|
|
nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev_a.remove)
|
|
nsim_a = nsimdev_a.nsims[0]
|
|
ip(f"link set dev {nsim_a.ifname} up")
|
|
|
|
nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev_b.remove)
|
|
nsim_b = nsimdev_b.nsims[0]
|
|
ip(f"link set dev {nsim_b.ifname} up")
|
|
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nsim_a.ifindex,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim_b.ifindex,
|
|
"queue": {"id": 0, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_different_lessors(netns) -> None:
|
|
nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev_a.remove)
|
|
nsim_a = nsimdev_a.nsims[0]
|
|
ip(f"link set dev {nsim_a.ifname} up")
|
|
|
|
nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev_b.remove)
|
|
nsim_b = nsimdev_b.nsims[0]
|
|
ip(f"link set dev {nsim_b.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim_a.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim_b.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
|
|
|
|
|
|
def test_queue_out_of_range(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 2, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.ERANGE)
|
|
|
|
|
|
def test_resize_leased(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
ethnl = EthtoolFamily()
|
|
with ksft_raises(NlError) as e:
|
|
ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_self_lease(_netns) -> None:
|
|
nk_host, _, _, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nk_guest_idx,
|
|
"queue": {"id": 0, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_veth_queue_create(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
ip("link add veth0 type veth peer name veth1")
|
|
defer(cmd, "ip link del dev veth0", fail=False)
|
|
|
|
all_links = ip("-d link show", json=True)
|
|
veth_peer = [
|
|
link
|
|
for link in all_links
|
|
if link.get("ifname") == "veth1"
|
|
]
|
|
veth_peer_idx = veth_peer[0]["ifindex"]
|
|
|
|
ip(f"link set dev veth1 netns {netns.name}")
|
|
ip("link set dev veth0 up")
|
|
ip("link set dev veth1 up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": veth_peer_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_create_tx_type(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "tx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_create_primary(_netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, nk_host_idx, _, _ = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_host} up")
|
|
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_host_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
|
|
|
|
|
|
def test_create_limit(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=1)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_link_flap_phys(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}")
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
nk_queue_id = result["id"]
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
|
|
|
|
# Link flap the physical device
|
|
ip(f"link set dev {nsim.ifname} down")
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
# Verify lease survives the flap
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
|
|
|
|
|
|
def test_queue_get_virtual(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}")
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
nk_queue_id = result["id"]
|
|
|
|
# queue-get on virtual device's leased queue should not show lease
|
|
# info (lease info is only shown from the physical device's side)
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nk_guest_idx, "id": nk_queue_id, "type": "rx"}
|
|
)
|
|
ksft_eq(queue_info["id"], nk_queue_id)
|
|
ksft_eq(queue_info["ifindex"], nk_guest_idx)
|
|
ksft_not_in("lease", queue_info)
|
|
|
|
# Default queue (not leased) also has no lease info
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nk_guest_idx, "id": 0, "type": "rx"}
|
|
)
|
|
ksft_not_in("lease", queue_info)
|
|
|
|
|
|
def test_remove_virt_first(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
|
|
|
|
# Delete netkit (virtual device removed first, physical stays)
|
|
cmd(f"ip link del dev {nk_host}")
|
|
|
|
# Verify lease is cleaned up on physical device
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_not_in("lease", queue_info)
|
|
|
|
|
|
def test_multiple_leases(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=3)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=4)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
r1 = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
r2 = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 2, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
ksft_eq(r1["id"], 1)
|
|
ksft_eq(r2["id"], 2)
|
|
|
|
# Verify both leases visible on physical device
|
|
netdevnl = NetdevFamily()
|
|
q1 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
q2 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
|
|
)
|
|
ksft_in("lease", q1)
|
|
ksft_in("lease", q2)
|
|
ksft_eq(q1["lease"]["ifindex"], nk_guest_idx)
|
|
ksft_eq(q2["lease"]["ifindex"], nk_guest_idx)
|
|
ksft_eq(q1["lease"]["queue"]["id"], r1["id"])
|
|
ksft_eq(q2["lease"]["queue"]["id"], r2["id"])
|
|
|
|
|
|
def test_lease_queue_tx_type(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "tx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_invalid_netns(netns) -> None:
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": 1,
|
|
"queue": {"id": 0, "type": "rx"},
|
|
"netns-id": 999,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.ENONET)
|
|
|
|
|
|
def test_invalid_phys_ifindex(netns) -> None:
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": 99999,
|
|
"queue": {"id": 0, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.ENODEV)
|
|
|
|
|
|
def test_multi_netkit_remove_phys(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=3)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
# Create two netkit pairs, each leasing a different physical queue
|
|
nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
|
|
|
|
nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest_a} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_a} up")
|
|
ip(f"link set dev {nk_guest_a} up", ns=netns)
|
|
|
|
ip(f"link set dev {nk_guest_b} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_b} up")
|
|
ip(f"link set dev {nk_guest_b} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_a_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_b_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 2, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
# Removing the physical device should take down both netkit pairs
|
|
nsimdev.remove()
|
|
wait_until(lambda: cmd(f"ip link show dev {nk_host_a}", fail=False).ret != 0
|
|
and cmd(f"ip link show dev {nk_host_b}", fail=False).ret != 0)
|
|
ret = cmd(f"ip link show dev {nk_host_a}", fail=False)
|
|
ksft_ne(ret.ret, 0)
|
|
ret = cmd(f"ip link show dev {nk_host_b}", fail=False)
|
|
ksft_ne(ret.ret, 0)
|
|
|
|
|
|
def test_single_remove_phys(_netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_name, nk_idx = create_netkit_single(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_name}", fail=False)
|
|
|
|
ip(f"link set dev {nk_name} up")
|
|
|
|
netdevnl = NetdevFamily()
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
|
|
# Removing the physical device should take down the single netkit device
|
|
nsimdev.remove()
|
|
wait_until(lambda: cmd(f"ip link show dev {nk_name}", fail=False).ret != 0)
|
|
ret = cmd(f"ip link show dev {nk_name}", fail=False)
|
|
ksft_ne(ret.ret, 0)
|
|
|
|
|
|
def test_link_flap_virt(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}")
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
nk_queue_id = result["id"]
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
|
|
|
|
# Link flap the virtual (netkit) device
|
|
ip(f"link set dev {nk_guest} down", ns=netns)
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
# Verify lease survives the virtual device flap
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
|
|
|
|
|
|
def test_phys_queue_no_lease(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}")
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
# Physical queue 0 (not leased) should have no lease info
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 0, "type": "rx"}
|
|
)
|
|
ksft_not_in("lease", queue_info)
|
|
|
|
# Physical queue 1 (leased) should have lease info
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
|
|
def test_same_ns_lease(_netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_name, nk_idx = create_netkit_single(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_name}", fail=False)
|
|
|
|
ip(f"link set dev {nk_name} up")
|
|
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
# Same namespace: lease info should NOT have netns-id
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["ifindex"], nk_idx)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
|
|
ksft_not_in("netns-id", queue_info["lease"])
|
|
|
|
|
|
def test_resize_after_unlease(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
# Resize should fail while lease is active
|
|
ethnl = EthtoolFamily()
|
|
with ksft_raises(NlError) as e:
|
|
ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
# Delete netkit, clearing the lease
|
|
cmd(f"ip link del dev {nk_host}")
|
|
|
|
# Resize should now succeed
|
|
ethnl.channels_set({"header": {"dev-index": nsim.ifindex}, "combined-count": 1})
|
|
|
|
|
|
def test_lease_queue_zero(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 0, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 0, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
|
|
|
|
|
|
def test_release_and_reuse(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
src_queue = 1
|
|
|
|
# First lease
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
# Delete netkit, freeing the lease
|
|
cmd(f"ip link del dev {nk_host}")
|
|
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_not_in("lease", queue_info)
|
|
|
|
# Re-create netkit and lease the same physical queue again
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)):
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
|
|
|
|
|
|
def test_two_netkits_same_queue(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
|
|
|
|
nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest_a} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_a} up")
|
|
ip(f"link set dev {nk_guest_a} up", ns=netns)
|
|
|
|
ip(f"link set dev {nk_guest_b} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_b} up")
|
|
ip(f"link set dev {nk_guest_b} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_a_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_b_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
|
|
|
|
|
|
def test_l3_mode_lease(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2, mode="l3")
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
result = netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["ifindex"], nk_guest_idx)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
|
|
|
|
|
|
def test_single_double_lease(_netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_name, nk_idx = create_netkit_single(rxqueues=3)
|
|
defer(cmd, f"ip link del dev {nk_name}", fail=False)
|
|
|
|
ip(f"link set dev {nk_name} up")
|
|
|
|
netdevnl = NetdevFamily()
|
|
result = netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EBUSY)
|
|
|
|
|
|
def test_single_different_lessors(_netns) -> None:
|
|
nsimdev_a = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev_a.remove)
|
|
nsim_a = nsimdev_a.nsims[0]
|
|
ip(f"link set dev {nsim_a.ifname} up")
|
|
|
|
nsimdev_b = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev_b.remove)
|
|
nsim_b = nsimdev_b.nsims[0]
|
|
ip(f"link set dev {nsim_b.ifname} up")
|
|
|
|
nk_name, nk_idx = create_netkit_single(rxqueues=3)
|
|
defer(cmd, f"ip link del dev {nk_name}", fail=False)
|
|
|
|
ip(f"link set dev {nk_name} up")
|
|
|
|
netdevnl = NetdevFamily()
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim_a.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.queue_create(
|
|
{
|
|
"ifindex": nk_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim_b.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
|
|
|
|
|
|
def test_cross_ns_netns_id(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_in("netns-id", queue_info["lease"])
|
|
|
|
|
|
def test_delete_guest_netns(_netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
test_ns = NetNS()
|
|
ip("netns set init 0", ns=test_ns)
|
|
ip("link set lo up", ns=test_ns)
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {test_ns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=test_ns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(test_ns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
del test_ns
|
|
wait_until(lambda: "lease" not in netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}))
|
|
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_not_in("lease", queue_info)
|
|
|
|
ret = cmd(f"ip link show dev {nk_host}", fail=False)
|
|
ksft_ne(ret.ret, 0)
|
|
|
|
|
|
def test_move_guest_netns(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
result = netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
nk_queue_id = result["id"]
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
|
|
|
|
new_ns = NetNS()
|
|
defer(new_ns.__del__)
|
|
ip(f"link set dev {nk_guest} netns {new_ns.name}", ns=netns)
|
|
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
|
|
|
|
|
|
def test_resize_phys_no_reduction(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
ethnl = EthtoolFamily()
|
|
ethnl.channels_set(
|
|
{"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
|
|
def test_delete_one_netkit_of_two(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=3)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
|
|
|
|
nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest_a} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_a} up")
|
|
ip(f"link set dev {nk_guest_a} up", ns=netns)
|
|
|
|
ip(f"link set dev {nk_guest_b} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_b} up")
|
|
ip(f"link set dev {nk_guest_b} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_a_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_b_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 2, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
q1 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
q2 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
|
|
)
|
|
ksft_in("lease", q1)
|
|
ksft_in("lease", q2)
|
|
|
|
cmd(f"ip link del dev {nk_host_a}")
|
|
|
|
q1 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
q2 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
|
|
)
|
|
ksft_not_in("lease", q1)
|
|
ksft_in("lease", q2)
|
|
|
|
|
|
def test_bind_rx_leased_phys_queue(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl.bind_rx(
|
|
{
|
|
"ifindex": nsim.ifindex,
|
|
"fd": 0,
|
|
"queues": [
|
|
{"id": 0, "type": "rx"},
|
|
{"id": 1, "type": "rx"},
|
|
],
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
|
|
|
|
|
|
def test_resize_phys_shrink_past_leased(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=4)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
ethnl = EthtoolFamily()
|
|
|
|
# Shrink past the leased queue — only queue 3 removed, queue 1 untouched
|
|
ethnl.channels_set(
|
|
{"header": {"dev-index": nsim.ifindex}, "combined-count": 3}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
# Shrink further — queue 2 removed, queue 1 still untouched
|
|
ethnl.channels_set(
|
|
{"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
|
|
)
|
|
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
# Shrink into the leased queue — queue 1 is busy, must fail
|
|
with ksft_raises(NlError) as e:
|
|
ethnl.channels_set(
|
|
{"header": {"dev-index": nsim.ifindex}, "combined-count": 1}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
|
|
def test_resize_virt_not_supported(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, nk_host_idx, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
# Channel resize on the netkit host must fail — not supported
|
|
ethnl = EthtoolFamily()
|
|
with ksft_raises(NlError) as e:
|
|
ethnl.channels_set(
|
|
{"header": {"dev-index": nk_host_idx}, "combined-count": 1}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EOPNOTSUPP)
|
|
|
|
# Lease must be intact
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
|
|
def test_lease_devices_down(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
|
|
# Create lease while both physical and virtual devices are down
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
result = netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
# Bring devices up before queue_get: netdevsim only instantiates NAPIs in
|
|
# ndo_open, and netdev-genl queue_get returns -ENOENT without a NAPI.
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], result["id"])
|
|
|
|
|
|
def test_lease_capacity_exhaustion(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=4)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
# rxqueues=3 means num_rx_queues=3, real_num_rx_queues starts at 1.
|
|
# Can create 2 leased queues (real goes 1->2->3) but not a 3rd (3->4 > 3).
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=3)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
r1 = netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(r1["id"], 1)
|
|
|
|
r2 = netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 2, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(r2["id"], 2)
|
|
|
|
# Third lease fails — netkit queue capacity exhausted
|
|
with ksft_raises(NlError) as e:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 3, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
|
|
|
# Verify the two successful leases are intact
|
|
netdevnl = NetdevFamily()
|
|
q1 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
q2 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
|
|
)
|
|
ksft_in("lease", q1)
|
|
ksft_in("lease", q2)
|
|
|
|
|
|
def test_resize_phys_up(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=3)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
# Shrink nsim first so we have room to grow
|
|
ethnl = EthtoolFamily()
|
|
ethnl.channels_set(
|
|
{"header": {"dev-index": nsim.ifindex}, "combined-count": 2}
|
|
)
|
|
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
# Grow channels — should succeed since leased queue is not removed
|
|
ethnl.channels_set(
|
|
{"header": {"dev-index": nsim.ifindex}, "combined-count": 3}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
# New queue 2 should exist without a lease
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
|
|
)
|
|
ksft_not_in("lease", queue_info)
|
|
|
|
|
|
def test_multi_ns_lease(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=3)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
ns_b = NetNS()
|
|
defer(ns_b.__del__)
|
|
ip("netns set init 0", ns=ns_b)
|
|
ip("link set lo up", ns=ns_b)
|
|
|
|
# First netkit pair, guest in netns
|
|
nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
|
|
ip(f"link set dev {nk_guest_a} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_a} up")
|
|
ip(f"link set dev {nk_guest_a} up", ns=netns)
|
|
|
|
# Second netkit pair, guest in ns_b
|
|
nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
|
|
ip(f"link set dev {nk_guest_b} netns {ns_b.name}")
|
|
ip(f"link set dev {nk_host_b} up")
|
|
ip(f"link set dev {nk_guest_b} up", ns=ns_b)
|
|
|
|
# Lease from netns
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
result = netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_a_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
# Lease from ns_b (different namespace, same physical device)
|
|
with NetNSEnter(str(ns_b)), NetdevFamily() as netdevnl_ns:
|
|
result = netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_b_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 2, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
ksft_eq(result["id"], 1)
|
|
|
|
# Verify both leases from the physical side
|
|
netdevnl = NetdevFamily()
|
|
q1 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
q2 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
|
|
)
|
|
ksft_in("lease", q1)
|
|
ksft_in("lease", q2)
|
|
ksft_eq(q1["lease"]["ifindex"], nk_guest_a_idx)
|
|
ksft_eq(q2["lease"]["ifindex"], nk_guest_b_idx)
|
|
|
|
|
|
def test_multi_ns_delete_one(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=3)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
ns_b = NetNS()
|
|
ip("netns set init 0", ns=ns_b)
|
|
ip("link set lo up", ns=ns_b)
|
|
|
|
# First netkit pair, guest in netns (ns_a)
|
|
nk_host_a, _, nk_guest_a, nk_guest_a_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_a}", fail=False)
|
|
ip(f"link set dev {nk_guest_a} netns {netns.name}")
|
|
ip(f"link set dev {nk_host_a} up")
|
|
ip(f"link set dev {nk_guest_a} up", ns=netns)
|
|
|
|
# Second netkit pair, guest in ns_b
|
|
nk_host_b, _, nk_guest_b, nk_guest_b_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host_b}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest_b} netns {ns_b.name}")
|
|
ip(f"link set dev {nk_host_b} up")
|
|
ip(f"link set dev {nk_guest_b} up", ns=ns_b)
|
|
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_a_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 1, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
with NetNSEnter(str(ns_b)), NetdevFamily() as netdevnl_ns:
|
|
netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_b_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": 2, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)
|
|
|
|
netdevnl = NetdevFamily()
|
|
q1 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
q2 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
|
|
)
|
|
ksft_in("lease", q1)
|
|
ksft_in("lease", q2)
|
|
|
|
# Delete ns_b — destroys nk_guest_b, triggers unlease of queue 2
|
|
del ns_b
|
|
wait_until(lambda: "lease" not in netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}))
|
|
|
|
# ns_a's lease on queue 1 must survive
|
|
q1 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 1, "type": "rx"}
|
|
)
|
|
ksft_in("lease", q1)
|
|
ksft_eq(q1["lease"]["ifindex"], nk_guest_a_idx)
|
|
|
|
# ns_b's lease on queue 2 must be gone
|
|
q2 = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": 2, "type": "rx"}
|
|
)
|
|
ksft_not_in("lease", q2)
|
|
|
|
# nk_host_b should be gone too (phys removal cascades to netkit pair)
|
|
ret = cmd(f"ip link show dev {nk_host_b}", fail=False)
|
|
ksft_ne(ret.ret, 0)
|
|
|
|
|
|
def test_move_phys_netns(netns) -> None:
|
|
nsimdev = NetdevSimDev(port_count=1, queue_count=2)
|
|
defer(nsimdev.remove)
|
|
nsim = nsimdev.nsims[0]
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
nk_host, _, nk_guest, nk_guest_idx = create_netkit(rxqueues=2)
|
|
defer(cmd, f"ip link del dev {nk_host}", fail=False)
|
|
|
|
ip(f"link set dev {nk_guest} netns {netns.name}")
|
|
ip(f"link set dev {nk_host} up")
|
|
ip(f"link set dev {nk_guest} up", ns=netns)
|
|
|
|
src_queue = 1
|
|
with NetNSEnter(str(netns)), NetdevFamily() as netdevnl_ns:
|
|
nk_queue_id = netdevnl_ns.queue_create(
|
|
{
|
|
"ifindex": nk_guest_idx,
|
|
"type": "rx",
|
|
"lease": {
|
|
"ifindex": nsim.ifindex,
|
|
"queue": {"id": src_queue, "type": "rx"},
|
|
"netns-id": 0,
|
|
},
|
|
}
|
|
)["id"]
|
|
|
|
netdevnl = NetdevFamily()
|
|
queue_info = netdevnl.queue_get(
|
|
{"ifindex": nsim.ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
|
|
# Move the physical device to a new namespace. Move it back to init_net
|
|
# on cleanup before the other defers fire (new_ns deletion, nsimdev.remove)
|
|
# so nsim lives in a stable namespace when they run.
|
|
new_ns = NetNS()
|
|
defer(new_ns.__del__)
|
|
ip(f"link set dev {nsim.ifname} netns {new_ns.name}")
|
|
defer(ip, f"link set dev {nsim.ifname} netns init", ns=new_ns)
|
|
|
|
# Physical device is now in new_ns — find its ifindex there
|
|
all_links = ip("-d link show", json=True, ns=new_ns)
|
|
nsim_in_new = [lnk for lnk in all_links if lnk.get("ifname") == nsim.ifname]
|
|
new_ifindex = nsim_in_new[0]["ifindex"]
|
|
|
|
# Moving a device across netns brings it admin-down; bring it back up so
|
|
# netdevsim re-creates the NAPI (netdev-genl queue_get needs it).
|
|
ip(f"link set dev {nsim.ifname} up", ns=new_ns)
|
|
|
|
# Verify lease survived the namespace move
|
|
with NetNSEnter(str(new_ns)), NetdevFamily() as netdevnl_ns:
|
|
queue_info = netdevnl_ns.queue_get(
|
|
{"ifindex": new_ifindex, "id": src_queue, "type": "rx"}
|
|
)
|
|
ksft_in("lease", queue_info)
|
|
ksft_eq(queue_info["lease"]["queue"]["id"], nk_queue_id)
|
|
|
|
|
|
def main() -> None:
|
|
netns = NetNS()
|
|
cmd("ip netns attach init 1")
|
|
ip("netns set init 0", ns=netns)
|
|
ip("link set lo up", ns=netns)
|
|
|
|
ksft_run(
|
|
[
|
|
test_remove_phys,
|
|
test_double_lease,
|
|
test_virtual_lessor,
|
|
test_phys_lessee,
|
|
test_different_lessors,
|
|
test_queue_out_of_range,
|
|
test_resize_leased,
|
|
test_self_lease,
|
|
test_create_tx_type,
|
|
test_create_primary,
|
|
test_create_limit,
|
|
test_link_flap_phys,
|
|
test_queue_get_virtual,
|
|
test_remove_virt_first,
|
|
test_multiple_leases,
|
|
test_lease_queue_tx_type,
|
|
test_invalid_netns,
|
|
test_invalid_phys_ifindex,
|
|
test_multi_netkit_remove_phys,
|
|
test_single_remove_phys,
|
|
test_link_flap_virt,
|
|
test_phys_queue_no_lease,
|
|
test_same_ns_lease,
|
|
test_resize_after_unlease,
|
|
test_lease_queue_zero,
|
|
test_release_and_reuse,
|
|
test_veth_queue_create,
|
|
test_two_netkits_same_queue,
|
|
test_l3_mode_lease,
|
|
test_single_double_lease,
|
|
test_single_different_lessors,
|
|
test_cross_ns_netns_id,
|
|
test_delete_guest_netns,
|
|
test_move_guest_netns,
|
|
test_resize_phys_no_reduction,
|
|
test_delete_one_netkit_of_two,
|
|
test_bind_rx_leased_phys_queue,
|
|
test_resize_phys_shrink_past_leased,
|
|
test_resize_virt_not_supported,
|
|
test_lease_devices_down,
|
|
test_lease_capacity_exhaustion,
|
|
test_resize_phys_up,
|
|
test_multi_ns_lease,
|
|
test_multi_ns_delete_one,
|
|
test_move_phys_netns,
|
|
],
|
|
args=(netns,),
|
|
)
|
|
|
|
cmd("ip netns del init", fail=False)
|
|
ksft_exit()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|