1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3 4import time 5 6from lib.py import ksft_run, ksft_exit, ksft_true 7from lib.py import ip 8from lib.py import NetNS, NetNSEnter 9from lib.py import RtnlFamily 10 11 12LINK_NETNSID = 100 13 14 15def test_event() -> None: 16 with NetNS() as ns1, NetNS() as ns2: 17 with NetNSEnter(str(ns2)): 18 rtnl = RtnlFamily() 19 20 rtnl.ntf_subscribe("rtnlgrp-link") 21 22 ip(f"netns set {ns2} {LINK_NETNSID}", ns=str(ns1)) 23 ip(f"link add netns {ns1} link-netnsid {LINK_NETNSID} dummy1 type dummy") 24 ip(f"link add netns {ns1} dummy2 type dummy", ns=str(ns2)) 25 26 ip("link del dummy1", ns=str(ns1)) 27 ip("link del dummy2", ns=str(ns1)) 28 29 time.sleep(1) 30 rtnl.check_ntf() 31 ksft_true(rtnl.async_msg_queue.empty(), 32 "Received unexpected link notification") 33 34 35def validate_link_netns(netns, ifname, link_netnsid) -> bool: 36 link_info = ip(f"-d link show dev {ifname}", ns=netns, json=True) 37 if not link_info: 38 return False 39 return link_info[0].get("link_netnsid") == link_netnsid 40 41 42def test_link_net() -> None: 43 configs = [ 44 # type, common args, type args, fallback to dev_net 45 ("ipvlan", "link dummy1", "", False), 46 ("macsec", "link dummy1", "", False), 47 ("macvlan", "link dummy1", "", False), 48 ("macvtap", "link dummy1", "", False), 49 ("vlan", "link dummy1", "id 100", False), 50 ("gre", "", "local 192.0.2.1", True), 51 ("vti", "", "local 192.0.2.1", True), 52 ("ipip", "", "local 192.0.2.1", True), 53 ("ip6gre", "", "local 2001:db8::1", True), 54 ("ip6tnl", "", "local 2001:db8::1", True), 55 ("vti6", "", "local 2001:db8::1", True), 56 ("sit", "", "local 192.0.2.1", True), 57 ("xfrm", "", "if_id 1", True), 58 ] 59 60 with NetNS() as ns1, NetNS() as ns2, NetNS() as ns3: 61 net1, net2, net3 = str(ns1), str(ns2), str(ns3) 62 63 # prepare link netnsid and a dummy link needed by certain drivers 64 ip(f"netns set {net3} {LINK_NETNSID}", ns=str(net2)) 65 ip("link add dummy1 type dummy", ns=net3) 66 67 cases = [ 68 # source, "netns", "link-netns", expected link-netns 69 (net3, None, None, None, None), 70 (net3, net2, None, None, LINK_NETNSID), 71 (net2, None, net3, LINK_NETNSID, LINK_NETNSID), 72 (net1, net2, net3, LINK_NETNSID, LINK_NETNSID), 73 ] 74 75 for src_net, netns, link_netns, exp1, exp2 in cases: 76 tgt_net = netns or src_net 77 for typ, cargs, targs, fb_dev_net in configs: 78 cmd = "link add" 79 if netns: 80 cmd += f" netns {netns}" 81 if link_netns: 82 cmd += f" link-netns {link_netns}" 83 cmd += f" {cargs} foo type {typ} {targs}" 84 ip(cmd, ns=src_net) 85 if fb_dev_net: 86 ksft_true(validate_link_netns(tgt_net, "foo", exp1), 87 f"{typ} link_netns validation failed") 88 else: 89 ksft_true(validate_link_netns(tgt_net, "foo", exp2), 90 f"{typ} link_netns validation failed") 91 ip(f"link del foo", ns=tgt_net) 92 93 94def test_peer_net() -> None: 95 types = [ 96 "vxcan", 97 "netkit", 98 "veth", 99 ] 100 101 with NetNS() as ns1, NetNS() as ns2, NetNS() as ns3, NetNS() as ns4: 102 net1, net2, net3, net4 = str(ns1), str(ns2), str(ns3), str(ns4) 103 104 ip(f"netns set {net3} {LINK_NETNSID}", ns=str(net2)) 105 106 cases = [ 107 # source, "netns", "link-netns", "peer netns", expected 108 (net1, None, None, None, None), 109 (net1, net2, None, None, None), 110 (net2, None, net3, None, LINK_NETNSID), 111 (net1, net2, net3, None, None), 112 (net2, None, None, net3, LINK_NETNSID), 113 (net1, net2, None, net3, LINK_NETNSID), 114 (net2, None, net2, net3, LINK_NETNSID), 115 (net1, net2, net4, net3, LINK_NETNSID), 116 ] 117 118 for src_net, netns, link_netns, peer_netns, exp in cases: 119 tgt_net = netns or src_net 120 for typ in types: 121 cmd = "link add" 122 if netns: 123 cmd += f" netns {netns}" 124 if link_netns: 125 cmd += f" link-netns {link_netns}" 126 cmd += f" foo type {typ}" 127 if peer_netns: 128 cmd += f" peer netns {peer_netns}" 129 ip(cmd, ns=src_net) 130 ksft_true(validate_link_netns(tgt_net, "foo", exp), 131 f"{typ} peer_netns validation failed") 132 ip(f"link del foo", ns=tgt_net) 133 134 135def main() -> None: 136 ksft_run([test_event, test_link_net, test_peer_net]) 137 ksft_exit() 138 139 140if __name__ == "__main__": 141 main() 142