forked from mirrors/linux
		
	selftests: net: Add test cases for link and peer netns
- Add test for creating link in another netns when a link of the same name and ifindex exists in current netns. - Add test to verify that link is created in target netns directly - no link new/del events should be generated in link netns or current netns. - Add test cases to verify that link-netns is set as expected for various drivers and combination of namespace-related parameters. Signed-off-by: Xiao Liang <shaw.leon@gmail.com> Link: https://patch.msgid.link/20250219125039.18024-14-shaw.leon@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
							parent
							
								
									0303294162
								
							
						
					
					
						commit
						85cb3711ac
					
				
					 4 changed files with 157 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -36,6 +36,7 @@ TEST_PROGS += cmsg_so_priority.sh
 | 
			
		|||
TEST_PROGS += test_so_rcv.sh
 | 
			
		||||
TEST_PROGS += cmsg_time.sh cmsg_ipv6.sh
 | 
			
		||||
TEST_PROGS += netns-name.sh
 | 
			
		||||
TEST_PROGS += link_netns.py
 | 
			
		||||
TEST_PROGS += nl_netdev.py
 | 
			
		||||
TEST_PROGS += rtnetlink.py
 | 
			
		||||
TEST_PROGS += srv6_end_dt46_l3vpn_test.sh
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -107,3 +107,8 @@ CONFIG_XFRM_INTERFACE=m
 | 
			
		|||
CONFIG_XFRM_USER=m
 | 
			
		||||
CONFIG_IP_NF_MATCH_RPFILTER=m
 | 
			
		||||
CONFIG_IP6_NF_MATCH_RPFILTER=m
 | 
			
		||||
CONFIG_IPVLAN=m
 | 
			
		||||
CONFIG_CAN=m
 | 
			
		||||
CONFIG_CAN_DEV=m
 | 
			
		||||
CONFIG_CAN_VXCAN=m
 | 
			
		||||
CONFIG_NETKIT=y
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										141
									
								
								tools/testing/selftests/net/link_netns.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										141
									
								
								tools/testing/selftests/net/link_netns.py
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,141 @@
 | 
			
		|||
#!/usr/bin/env python3
 | 
			
		||||
# SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
from lib.py import ksft_run, ksft_exit, ksft_true
 | 
			
		||||
from lib.py import ip
 | 
			
		||||
from lib.py import NetNS, NetNSEnter
 | 
			
		||||
from lib.py import RtnlFamily
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
LINK_NETNSID = 100
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_event() -> None:
 | 
			
		||||
    with NetNS() as ns1, NetNS() as ns2:
 | 
			
		||||
        with NetNSEnter(str(ns2)):
 | 
			
		||||
            rtnl = RtnlFamily()
 | 
			
		||||
 | 
			
		||||
        rtnl.ntf_subscribe("rtnlgrp-link")
 | 
			
		||||
 | 
			
		||||
        ip(f"netns set {ns2} {LINK_NETNSID}", ns=str(ns1))
 | 
			
		||||
        ip(f"link add netns {ns1} link-netnsid {LINK_NETNSID} dummy1 type dummy")
 | 
			
		||||
        ip(f"link add netns {ns1} dummy2 type dummy", ns=str(ns2))
 | 
			
		||||
 | 
			
		||||
        ip("link del dummy1", ns=str(ns1))
 | 
			
		||||
        ip("link del dummy2", ns=str(ns1))
 | 
			
		||||
 | 
			
		||||
        time.sleep(1)
 | 
			
		||||
        rtnl.check_ntf()
 | 
			
		||||
        ksft_true(rtnl.async_msg_queue.empty(),
 | 
			
		||||
                  "Received unexpected link notification")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_link_netns(netns, ifname, link_netnsid) -> bool:
 | 
			
		||||
    link_info = ip(f"-d link show dev {ifname}", ns=netns, json=True)
 | 
			
		||||
    if not link_info:
 | 
			
		||||
        return False
 | 
			
		||||
    return link_info[0].get("link_netnsid") == link_netnsid
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_link_net() -> None:
 | 
			
		||||
    configs = [
 | 
			
		||||
        # type, common args, type args, fallback to dev_net
 | 
			
		||||
        ("ipvlan", "link dummy1", "", False),
 | 
			
		||||
        ("macsec", "link dummy1", "", False),
 | 
			
		||||
        ("macvlan", "link dummy1", "", False),
 | 
			
		||||
        ("macvtap", "link dummy1", "", False),
 | 
			
		||||
        ("vlan", "link dummy1", "id 100", False),
 | 
			
		||||
        ("gre", "", "local 192.0.2.1", True),
 | 
			
		||||
        ("vti", "", "local 192.0.2.1", True),
 | 
			
		||||
        ("ipip", "", "local 192.0.2.1", True),
 | 
			
		||||
        ("ip6gre", "", "local 2001:db8::1", True),
 | 
			
		||||
        ("ip6tnl", "", "local 2001:db8::1", True),
 | 
			
		||||
        ("vti6", "", "local 2001:db8::1", True),
 | 
			
		||||
        ("sit", "", "local 192.0.2.1", True),
 | 
			
		||||
        ("xfrm", "", "if_id 1", True),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    with NetNS() as ns1, NetNS() as ns2, NetNS() as ns3:
 | 
			
		||||
        net1, net2, net3 = str(ns1), str(ns2), str(ns3)
 | 
			
		||||
 | 
			
		||||
        # prepare link netnsid  and a dummy link needed by certain drivers
 | 
			
		||||
        ip(f"netns set {net3} {LINK_NETNSID}", ns=str(net2))
 | 
			
		||||
        ip("link add dummy1 type dummy", ns=net3)
 | 
			
		||||
 | 
			
		||||
        cases = [
 | 
			
		||||
            # source, "netns", "link-netns", expected link-netns
 | 
			
		||||
            (net3, None, None, None, None),
 | 
			
		||||
            (net3, net2, None, None, LINK_NETNSID),
 | 
			
		||||
            (net2, None, net3, LINK_NETNSID, LINK_NETNSID),
 | 
			
		||||
            (net1, net2, net3, LINK_NETNSID, LINK_NETNSID),
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        for src_net, netns, link_netns, exp1, exp2 in cases:
 | 
			
		||||
            tgt_net = netns or src_net
 | 
			
		||||
            for typ, cargs, targs, fb_dev_net in configs:
 | 
			
		||||
                cmd = "link add"
 | 
			
		||||
                if netns:
 | 
			
		||||
                    cmd += f" netns {netns}"
 | 
			
		||||
                if link_netns:
 | 
			
		||||
                    cmd += f" link-netns {link_netns}"
 | 
			
		||||
                cmd += f" {cargs} foo type {typ} {targs}"
 | 
			
		||||
                ip(cmd, ns=src_net)
 | 
			
		||||
                if fb_dev_net:
 | 
			
		||||
                    ksft_true(validate_link_netns(tgt_net, "foo", exp1),
 | 
			
		||||
                              f"{typ} link_netns validation failed")
 | 
			
		||||
                else:
 | 
			
		||||
                    ksft_true(validate_link_netns(tgt_net, "foo", exp2),
 | 
			
		||||
                              f"{typ} link_netns validation failed")
 | 
			
		||||
                ip(f"link del foo", ns=tgt_net)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_peer_net() -> None:
 | 
			
		||||
    types = [
 | 
			
		||||
        "vxcan",
 | 
			
		||||
        "netkit",
 | 
			
		||||
        "veth",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    with NetNS() as ns1, NetNS() as ns2, NetNS() as ns3, NetNS() as ns4:
 | 
			
		||||
        net1, net2, net3, net4 = str(ns1), str(ns2), str(ns3), str(ns4)
 | 
			
		||||
 | 
			
		||||
        ip(f"netns set {net3} {LINK_NETNSID}", ns=str(net2))
 | 
			
		||||
 | 
			
		||||
        cases = [
 | 
			
		||||
            # source, "netns", "link-netns", "peer netns", expected
 | 
			
		||||
            (net1, None, None, None, None),
 | 
			
		||||
            (net1, net2, None, None, None),
 | 
			
		||||
            (net2, None, net3, None, LINK_NETNSID),
 | 
			
		||||
            (net1, net2, net3, None, None),
 | 
			
		||||
            (net2, None, None, net3, LINK_NETNSID),
 | 
			
		||||
            (net1, net2, None, net3, LINK_NETNSID),
 | 
			
		||||
            (net2, None, net2, net3, LINK_NETNSID),
 | 
			
		||||
            (net1, net2, net4, net3, LINK_NETNSID),
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        for src_net, netns, link_netns, peer_netns, exp in cases:
 | 
			
		||||
            tgt_net = netns or src_net
 | 
			
		||||
            for typ in types:
 | 
			
		||||
                cmd = "link add"
 | 
			
		||||
                if netns:
 | 
			
		||||
                    cmd += f" netns {netns}"
 | 
			
		||||
                if link_netns:
 | 
			
		||||
                    cmd += f" link-netns {link_netns}"
 | 
			
		||||
                cmd += f" foo type {typ}"
 | 
			
		||||
                if peer_netns:
 | 
			
		||||
                    cmd += f" peer netns {peer_netns}"
 | 
			
		||||
                ip(cmd, ns=src_net)
 | 
			
		||||
                ksft_true(validate_link_netns(tgt_net, "foo", exp),
 | 
			
		||||
                          f"{typ} peer_netns validation failed")
 | 
			
		||||
                ip(f"link del foo", ns=tgt_net)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main() -> None:
 | 
			
		||||
    ksft_run([test_event, test_link_net, test_peer_net])
 | 
			
		||||
    ksft_exit()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +78,16 @@ ip -netns $NS link show dev $ALT_NAME 2> /dev/null &&
 | 
			
		|||
    fail "Can still find alt-name after move"
 | 
			
		||||
ip -netns $test_ns link del $DEV || fail
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Test no conflict of the same name/ifindex in different netns
 | 
			
		||||
#
 | 
			
		||||
ip -netns $NS link add name $DEV index 100 type dummy || fail
 | 
			
		||||
ip -netns $NS link add netns $test_ns name $DEV index 100 type dummy ||
 | 
			
		||||
    fail "Can create in netns without moving"
 | 
			
		||||
ip -netns $test_ns link show dev $DEV >> /dev/null || fail "Device not found"
 | 
			
		||||
ip -netns $NS link del $DEV || fail
 | 
			
		||||
ip -netns $test_ns link del $DEV || fail
 | 
			
		||||
 | 
			
		||||
echo -ne "$(basename $0) \t\t\t\t"
 | 
			
		||||
if [ $RET_CODE -eq 0 ]; then
 | 
			
		||||
    echo "[  OK  ]"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue