1*09e702adSMark Johnston# 2*09e702adSMark Johnston# Copyright (c) 2025 Stormshield 3*09e702adSMark Johnston# 4*09e702adSMark Johnston# SPDX-License-Identifier: BSD-2-Clause 5*09e702adSMark Johnston# 6*09e702adSMark Johnston 7*09e702adSMark Johnstonimport pytest 8*09e702adSMark Johnstonimport socket 9*09e702adSMark Johnstonimport struct 10*09e702adSMark Johnstonimport subprocess 11*09e702adSMark Johnstonimport time 12*09e702adSMark Johnstonfrom pathlib import Path 13*09e702adSMark Johnston 14*09e702adSMark Johnstonfrom atf_python.sys.net.vnet import VnetTestTemplate 15*09e702adSMark Johnston 16*09e702adSMark Johnston 17*09e702adSMark Johnstonclass MRouteTestTemplate(VnetTestTemplate): 18*09e702adSMark Johnston """ 19*09e702adSMark Johnston Helper class for multicast routing tests. Test classes should inherit from this one. 20*09e702adSMark Johnston """ 21*09e702adSMark Johnston COORD_SOCK = "coord.sock" 22*09e702adSMark Johnston 23*09e702adSMark Johnston @staticmethod 24*09e702adSMark Johnston def _msgwait(sock: socket.socket, expected: bytes): 25*09e702adSMark Johnston msg = sock.recv(1024) 26*09e702adSMark Johnston assert msg == expected 27*09e702adSMark Johnston 28*09e702adSMark Johnston @staticmethod 29*09e702adSMark Johnston def sendmsg(msg: bytes, path: str): 30*09e702adSMark Johnston s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) 31*09e702adSMark Johnston s.sendto(msg, path) 32*09e702adSMark Johnston s.close() 33*09e702adSMark Johnston 34*09e702adSMark Johnston @staticmethod 35*09e702adSMark Johnston def _makesock(path: str): 36*09e702adSMark Johnston s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) 37*09e702adSMark Johnston s.bind(path) 38*09e702adSMark Johnston return s 39*09e702adSMark Johnston 40*09e702adSMark Johnston @staticmethod 41*09e702adSMark Johnston def mcast_join_INET6(addr: str, port: int): 42*09e702adSMark Johnston pass 43*09e702adSMark Johnston 44*09e702adSMark Johnston def jointest(self, vnet): 45*09e702adSMark Johnston """Let the coordinator know that we're ready, and wait for go-ahead.""" 46*09e702adSMark Johnston coord = self._makesock(vnet.alias + ".sock") 47*09e702adSMark Johnston self.sendmsg(b"ok " + vnet.alias.encode(), self.COORD_SOCK) 48*09e702adSMark Johnston self._msgwait(coord, b"join") 49*09e702adSMark Johnston 50*09e702adSMark Johnston def donetest(self): 51*09e702adSMark Johnston """Let the coordinator that we completed successfully.""" 52*09e702adSMark Johnston self.sendmsg(b"done", self.COORD_SOCK) 53*09e702adSMark Johnston 54*09e702adSMark Johnston def starttest(self, vnets: list[str]): 55*09e702adSMark Johnston self.vnets = vnets 56*09e702adSMark Johnston for vnet in vnets: 57*09e702adSMark Johnston self.sendmsg(b"join", vnet + ".sock") 58*09e702adSMark Johnston 59*09e702adSMark Johnston def waittest(self): 60*09e702adSMark Johnston for vnet in self.vnets: 61*09e702adSMark Johnston self._msgwait(self.coord, b"done") 62*09e702adSMark Johnston 63*09e702adSMark Johnston def setup_method(self, method): 64*09e702adSMark Johnston self.coord = self._makesock(self.COORD_SOCK) 65*09e702adSMark Johnston super().setup_method(method) 66*09e702adSMark Johnston 67*09e702adSMark Johnston # Loop until all other hosts have sent the ok message. 68*09e702adSMark Johnston received = set() 69*09e702adSMark Johnston vnet_names = set(self.vnet_map.keys()) - {self.vnet.alias} 70*09e702adSMark Johnston while len(received) < len(vnet_names): 71*09e702adSMark Johnston msg = self.coord.recv(1024) 72*09e702adSMark Johnston received.add(msg) 73*09e702adSMark Johnston assert received == {b"ok " + name.encode() for name in vnet_names} 74*09e702adSMark Johnston 75*09e702adSMark Johnston 76*09e702adSMark Johnstonclass MRouteINETTestTemplate(MRouteTestTemplate): 77*09e702adSMark Johnston @staticmethod 78*09e702adSMark Johnston def run_pimd(ident: str, ifaces: list[str], rpaddr: str, group: str, fib=0): 79*09e702adSMark Johnston conf = f"pimd-{ident}.conf" 80*09e702adSMark Johnston with open(conf, "w") as conf_file: 81*09e702adSMark Johnston conf_file.write("no phyint\n") 82*09e702adSMark Johnston for iface in ifaces: 83*09e702adSMark Johnston conf_file.write(f"phyint {iface} enable\n") 84*09e702adSMark Johnston conf_file.write(f"rp-address {rpaddr} {group}\n") 85*09e702adSMark Johnston 86*09e702adSMark Johnston cmd = f"setfib {fib} pimd -i {ident} -f {conf} -p pimd-{ident}.pid -n" 87*09e702adSMark Johnston return subprocess.Popen(cmd.split(), stdout=subprocess.DEVNULL, 88*09e702adSMark Johnston stderr=subprocess.DEVNULL) 89*09e702adSMark Johnston 90*09e702adSMark Johnston @staticmethod 91*09e702adSMark Johnston def mcast_join(addr: str, port: int): 92*09e702adSMark Johnston s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 93*09e702adSMark Johnston mreq = struct.pack("4si", socket.inet_aton(addr), socket.INADDR_ANY) 94*09e702adSMark Johnston s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 95*09e702adSMark Johnston s.bind((addr, port)) 96*09e702adSMark Johnston time.sleep(1) # Give the kernel a bit of time to join the group. 97*09e702adSMark Johnston return s 98*09e702adSMark Johnston 99*09e702adSMark Johnston @staticmethod 100*09e702adSMark Johnston def mcast_sendto(addr: str, port: int, iface: str, msg: bytes): 101*09e702adSMark Johnston s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 102*09e702adSMark Johnston mreqn = struct.pack("iii", socket.INADDR_ANY, socket.INADDR_ANY, 103*09e702adSMark Johnston socket.if_nametoindex(iface)) 104*09e702adSMark Johnston s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, mreqn) 105*09e702adSMark Johnston s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 64) 106*09e702adSMark Johnston s.sendto(msg, (addr, port)) 107*09e702adSMark Johnston s.close() 108*09e702adSMark Johnston 109*09e702adSMark Johnston def setup_method(self, method): 110*09e702adSMark Johnston self.require_module("ip_mroute") 111*09e702adSMark Johnston super().setup_method(method) 112*09e702adSMark Johnston 113*09e702adSMark Johnston 114*09e702adSMark Johnstonclass MRouteINET6TestTemplate(MRouteTestTemplate): 115*09e702adSMark Johnston @staticmethod 116*09e702adSMark Johnston def run_ip6_mrouted(ident: str, ifaces: list[str], fib=0): 117*09e702adSMark Johnston ifaces_str = ' '.join(f"-i {iface}" for iface in ifaces) 118*09e702adSMark Johnston exepath = Path(__file__).parent / "ip6_mrouted" 119*09e702adSMark Johnston cmd = f"setfib {fib} {exepath} {ifaces_str}" 120*09e702adSMark Johnston return subprocess.Popen(cmd.split(), stdout=subprocess.DEVNULL, 121*09e702adSMark Johnston stderr=subprocess.DEVNULL) 122*09e702adSMark Johnston 123*09e702adSMark Johnston @staticmethod 124*09e702adSMark Johnston def mcast_join(addr: str, port: int, iface: str): 125*09e702adSMark Johnston s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 126*09e702adSMark Johnston mreq = struct.pack("16si", socket.inet_pton(socket.AF_INET6, addr), 127*09e702adSMark Johnston socket.if_nametoindex(iface)) 128*09e702adSMark Johnston s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) 129*09e702adSMark Johnston s.bind((addr, port)) 130*09e702adSMark Johnston time.sleep(1) # Give the kernel a bit of time to join the 131*09e702adSMark Johnston return s 132*09e702adSMark Johnston 133*09e702adSMark Johnston @staticmethod 134*09e702adSMark Johnston def mcast_sendto(addr: str, port: int, iface: str, msg: bytes): 135*09e702adSMark Johnston s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 136*09e702adSMark Johnston mreq = struct.pack("i", socket.if_nametoindex(iface)) 137*09e702adSMark Johnston s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, mreq) 138*09e702adSMark Johnston s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 64) 139*09e702adSMark Johnston s.sendto(msg, (addr, port)) 140*09e702adSMark Johnston s.close() 141*09e702adSMark Johnston 142*09e702adSMark Johnston def setup_method(self, method): 143*09e702adSMark Johnston self.require_module("ip6_mroute") 144*09e702adSMark Johnston super().setup_method(method) 145*09e702adSMark Johnston 146*09e702adSMark Johnston 147*09e702adSMark Johnstonclass Test1RBasicINET(MRouteINETTestTemplate): 148*09e702adSMark Johnston """Basic multicast routing setup with 2 hosts connected via a router.""" 149*09e702adSMark Johnston 150*09e702adSMark Johnston TOPOLOGY = { 151*09e702adSMark Johnston "vnet_router": {"ifaces": ["if1", "if2"]}, 152*09e702adSMark Johnston "vnet_host1": {"ifaces": ["if1"]}, 153*09e702adSMark Johnston "vnet_host2": {"ifaces": ["if2"]}, 154*09e702adSMark Johnston "if1": {"prefixes4": [("192.168.1.1/24", "192.168.1.2/24")]}, 155*09e702adSMark Johnston "if2": {"prefixes4": [("192.168.2.1/24", "192.168.2.2/24")]}, 156*09e702adSMark Johnston } 157*09e702adSMark Johnston MULTICAST_ADDR = "239.0.0.1" 158*09e702adSMark Johnston 159*09e702adSMark Johnston def setup_method(self, method): 160*09e702adSMark Johnston # Create VNETs and start the handlers. 161*09e702adSMark Johnston super().setup_method(method) 162*09e702adSMark Johnston 163*09e702adSMark Johnston ifaces = [self.vnet.iface_alias_map[i].name for i in ["if1", "if2"]] 164*09e702adSMark Johnston self.pimd = self.run_pimd("test", ifaces, "127.0.0.1", self.MULTICAST_ADDR + "/32") 165*09e702adSMark Johnston time.sleep(3) # Give pimd a bit of time to get itself together. 166*09e702adSMark Johnston 167*09e702adSMark Johnston def vnet_host1_handler(self, vnet): 168*09e702adSMark Johnston self.jointest(vnet) 169*09e702adSMark Johnston 170*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) 171*09e702adSMark Johnston 172*09e702adSMark Johnston # Wait for host 2 to send a message, then send a reply. 173*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast!") 174*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 175*09e702adSMark Johnston b"Goodbye, Multicast!") 176*09e702adSMark Johnston self._msgwait(self.sock, b"Goodbye, Multicast!") 177*09e702adSMark Johnston self.donetest() 178*09e702adSMark Johnston 179*09e702adSMark Johnston def vnet_host2_handler(self, vnet): 180*09e702adSMark Johnston self.jointest(vnet) 181*09e702adSMark Johnston 182*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) 183*09e702adSMark Johnston 184*09e702adSMark Johnston # Send a message to host 1, then wait for a reply. 185*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 186*09e702adSMark Johnston b"Hello, Multicast!") 187*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast!") 188*09e702adSMark Johnston self._msgwait(self.sock, b"Goodbye, Multicast!") 189*09e702adSMark Johnston self.donetest() 190*09e702adSMark Johnston 191*09e702adSMark Johnston @pytest.mark.require_user("root") 192*09e702adSMark Johnston @pytest.mark.require_progs(["pimd"]) 193*09e702adSMark Johnston @pytest.mark.timeout(30) 194*09e702adSMark Johnston def test(self): 195*09e702adSMark Johnston self.starttest(["vnet_host1", "vnet_host2"]) 196*09e702adSMark Johnston self.waittest() 197*09e702adSMark Johnston 198*09e702adSMark Johnston 199*09e702adSMark Johnstonclass Test1RCrissCrossINET(MRouteINETTestTemplate): 200*09e702adSMark Johnston """ 201*09e702adSMark Johnston Test a router connected to four hosts, with pairs of interfaces 202*09e702adSMark Johnston in different FIBs. 203*09e702adSMark Johnston """ 204*09e702adSMark Johnston 205*09e702adSMark Johnston TOPOLOGY = { 206*09e702adSMark Johnston "vnet_router": {"ifaces": ["if1", "if2", "if3", "if4"]}, 207*09e702adSMark Johnston "vnet_host1": {"ifaces": ["if1"]}, 208*09e702adSMark Johnston "vnet_host2": {"ifaces": ["if2"]}, 209*09e702adSMark Johnston "vnet_host3": {"ifaces": ["if3"]}, 210*09e702adSMark Johnston "vnet_host4": {"ifaces": ["if4"]}, 211*09e702adSMark Johnston "if1": { 212*09e702adSMark Johnston "prefixes4": [("192.168.1.1/24", "192.168.1.2/24")], 213*09e702adSMark Johnston "prefixes6": [], 214*09e702adSMark Johnston "fib": (0, 0), 215*09e702adSMark Johnston }, 216*09e702adSMark Johnston "if2": { 217*09e702adSMark Johnston "prefixes4": [("192.168.2.1/24", "192.168.2.2/24")], 218*09e702adSMark Johnston "prefixes6": [], 219*09e702adSMark Johnston "fib": (0, 0), 220*09e702adSMark Johnston }, 221*09e702adSMark Johnston "if3": { 222*09e702adSMark Johnston "prefixes4": [("192.168.3.1/24", "192.168.3.2/24")], 223*09e702adSMark Johnston "prefixes6": [], 224*09e702adSMark Johnston "fib": (1, 0), 225*09e702adSMark Johnston }, 226*09e702adSMark Johnston "if4": { 227*09e702adSMark Johnston "prefixes4": [("192.168.4.1/24", "192.168.4.2/24")], 228*09e702adSMark Johnston "prefixes6": [], 229*09e702adSMark Johnston "fib": (1, 0), 230*09e702adSMark Johnston }, 231*09e702adSMark Johnston } 232*09e702adSMark Johnston MULTICAST_ADDR = "239.0.0.1" 233*09e702adSMark Johnston 234*09e702adSMark Johnston def setup_method(self, method): 235*09e702adSMark Johnston # Create VNETs and start the handlers. 236*09e702adSMark Johnston super().setup_method(method) 237*09e702adSMark Johnston 238*09e702adSMark Johnston # Start a pimd instance per FIB. 239*09e702adSMark Johnston ifaces = [self.vnet.iface_alias_map[i].name for i in ["if1", "if2"]] 240*09e702adSMark Johnston self.pimd0 = self.run_pimd("test0", ifaces, "127.0.0.1", self.MULTICAST_ADDR + "/32", 241*09e702adSMark Johnston fib=0) 242*09e702adSMark Johnston ifaces = [self.vnet.iface_alias_map[i].name for i in ["if3", "if4"]] 243*09e702adSMark Johnston self.pimd1 = self.run_pimd("test1", ifaces, "127.0.0.1", self.MULTICAST_ADDR + "/32", 244*09e702adSMark Johnston fib=1) 245*09e702adSMark Johnston time.sleep(3) # Give pimd a bit of time to get itself together. 246*09e702adSMark Johnston 247*09e702adSMark Johnston def vnet_host1_handler(self, vnet): 248*09e702adSMark Johnston self.jointest(vnet) 249*09e702adSMark Johnston 250*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) 251*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast on FIB 0!") 252*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 253*09e702adSMark Johnston b"Goodbye, Multicast on FIB 0!") 254*09e702adSMark Johnston self.donetest() 255*09e702adSMark Johnston 256*09e702adSMark Johnston def vnet_host2_handler(self, vnet): 257*09e702adSMark Johnston self.jointest(vnet) 258*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) 259*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 260*09e702adSMark Johnston b"Hello, Multicast on FIB 0!") 261*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast on FIB 0!") 262*09e702adSMark Johnston self._msgwait(self.sock, b"Goodbye, Multicast on FIB 0!") 263*09e702adSMark Johnston self.donetest() 264*09e702adSMark Johnston 265*09e702adSMark Johnston def vnet_host3_handler(self, vnet): 266*09e702adSMark Johnston self.jointest(vnet) 267*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) 268*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast on FIB 1!") 269*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, 270*09e702adSMark Johnston vnet.ifaces[0].name, b"Goodbye, Multicast on FIB 1!") 271*09e702adSMark Johnston self.donetest() 272*09e702adSMark Johnston 273*09e702adSMark Johnston def vnet_host4_handler(self, vnet): 274*09e702adSMark Johnston self.jointest(vnet) 275*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) 276*09e702adSMark Johnston time.sleep(1) 277*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 278*09e702adSMark Johnston b"Hello, Multicast on FIB 1!") 279*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast on FIB 1!") 280*09e702adSMark Johnston self._msgwait(self.sock, b"Goodbye, Multicast on FIB 1!") 281*09e702adSMark Johnston self.donetest() 282*09e702adSMark Johnston 283*09e702adSMark Johnston @pytest.mark.require_user("root") 284*09e702adSMark Johnston @pytest.mark.require_progs(["pimd"]) 285*09e702adSMark Johnston @pytest.mark.timeout(30) 286*09e702adSMark Johnston def test(self): 287*09e702adSMark Johnston self.starttest(["vnet_host1", "vnet_host2", "vnet_host3", "vnet_host4"]) 288*09e702adSMark Johnston self.waittest() 289*09e702adSMark Johnston 290*09e702adSMark Johnston 291*09e702adSMark Johnstonclass Test1RBasicINET6(MRouteINET6TestTemplate): 292*09e702adSMark Johnston """Basic multicast routing setup with 2 hosts connected via a router.""" 293*09e702adSMark Johnston 294*09e702adSMark Johnston TOPOLOGY = { 295*09e702adSMark Johnston "vnet_router": {"ifaces": ["if1", "if2"]}, 296*09e702adSMark Johnston "vnet_host1": {"ifaces": ["if1"]}, 297*09e702adSMark Johnston "vnet_host2": {"ifaces": ["if2"]}, 298*09e702adSMark Johnston "if1": { 299*09e702adSMark Johnston "prefixes6": [("2001:db8:0:1::1/64", "2001:db8:0:1::2/64")] 300*09e702adSMark Johnston }, 301*09e702adSMark Johnston "if2": { 302*09e702adSMark Johnston "prefixes6": [("2001:db8:0:2::1/64", "2001:db8:0:2::2/64")] 303*09e702adSMark Johnston }, 304*09e702adSMark Johnston } 305*09e702adSMark Johnston MULTICAST_ADDR = "ff05::1" 306*09e702adSMark Johnston 307*09e702adSMark Johnston def setup_method(self, method): 308*09e702adSMark Johnston # Create VNETs and start the handlers. 309*09e702adSMark Johnston super().setup_method(method) 310*09e702adSMark Johnston 311*09e702adSMark Johnston ifaces = [self.vnet.iface_alias_map[i].name for i in ["if1", "if2"]] 312*09e702adSMark Johnston self.mrouted = self.run_ip6_mrouted("test", ifaces) 313*09e702adSMark Johnston time.sleep(1) 314*09e702adSMark Johnston 315*09e702adSMark Johnston def vnet_host1_handler(self, vnet): 316*09e702adSMark Johnston self.jointest(vnet) 317*09e702adSMark Johnston 318*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) 319*09e702adSMark Johnston 320*09e702adSMark Johnston # Wait for host 2 to send a message, then send a reply. 321*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast!") 322*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 323*09e702adSMark Johnston b"Goodbye, Multicast!") 324*09e702adSMark Johnston self._msgwait(self.sock, b"Goodbye, Multicast!") 325*09e702adSMark Johnston self.donetest() 326*09e702adSMark Johnston 327*09e702adSMark Johnston def vnet_host2_handler(self, vnet): 328*09e702adSMark Johnston self.jointest(vnet) 329*09e702adSMark Johnston 330*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) 331*09e702adSMark Johnston 332*09e702adSMark Johnston # Send a message to host 1, then wait for a reply. 333*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 334*09e702adSMark Johnston b"Hello, Multicast!") 335*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast!") 336*09e702adSMark Johnston self._msgwait(self.sock, b"Goodbye, Multicast!") 337*09e702adSMark Johnston self.donetest() 338*09e702adSMark Johnston 339*09e702adSMark Johnston @pytest.mark.require_user("root") 340*09e702adSMark Johnston @pytest.mark.timeout(30) 341*09e702adSMark Johnston def test(self): 342*09e702adSMark Johnston self.starttest(["vnet_host1", "vnet_host2"]) 343*09e702adSMark Johnston self.waittest() 344*09e702adSMark Johnston 345*09e702adSMark Johnston 346*09e702adSMark Johnstonclass Test1RCrissCrossINET6(MRouteINET6TestTemplate): 347*09e702adSMark Johnston """ 348*09e702adSMark Johnston Test a router connected to four hosts, with pairs of interfaces 349*09e702adSMark Johnston in different FIBs. 350*09e702adSMark Johnston """ 351*09e702adSMark Johnston 352*09e702adSMark Johnston TOPOLOGY = { 353*09e702adSMark Johnston "vnet_router": {"ifaces": ["if1", "if2", "if3", "if4"]}, 354*09e702adSMark Johnston "vnet_host1": {"ifaces": ["if1"]}, 355*09e702adSMark Johnston "vnet_host2": {"ifaces": ["if2"]}, 356*09e702adSMark Johnston "vnet_host3": {"ifaces": ["if3"]}, 357*09e702adSMark Johnston "vnet_host4": {"ifaces": ["if4"]}, 358*09e702adSMark Johnston "if1": { 359*09e702adSMark Johnston "prefixes6": [("2001:db8:0:1::1/64", "2001:db8:0:1::2/64")], 360*09e702adSMark Johnston "fib": (0, 0), 361*09e702adSMark Johnston }, 362*09e702adSMark Johnston "if2": { 363*09e702adSMark Johnston "prefixes6": [("2001:db8:0:2::1/64", "2001:db8:0:2::2/64")], 364*09e702adSMark Johnston "fib": (0, 0), 365*09e702adSMark Johnston }, 366*09e702adSMark Johnston "if3": { 367*09e702adSMark Johnston "prefixes6": [("2001:db8:0:3::1/64", "2001:db8:0:3::2/64")], 368*09e702adSMark Johnston "fib": (1, 0), 369*09e702adSMark Johnston }, 370*09e702adSMark Johnston "if4": { 371*09e702adSMark Johnston "prefixes6": [("2001:db8:0:4::1/64", "2001:db8:0:4::2/64")], 372*09e702adSMark Johnston "fib": (1, 0), 373*09e702adSMark Johnston }, 374*09e702adSMark Johnston } 375*09e702adSMark Johnston MULTICAST_ADDR = "ff05::1" 376*09e702adSMark Johnston 377*09e702adSMark Johnston def setup_method(self, method): 378*09e702adSMark Johnston # Create VNETs and start the handlers. 379*09e702adSMark Johnston super().setup_method(method) 380*09e702adSMark Johnston 381*09e702adSMark Johnston # Start an ip6_mrouted instance per FIB. 382*09e702adSMark Johnston ifaces = [self.vnet.iface_alias_map[i].name for i in ["if1", "if2"]] 383*09e702adSMark Johnston self.pimd0 = self.run_ip6_mrouted("test0", ifaces, fib=0) 384*09e702adSMark Johnston ifaces = [self.vnet.iface_alias_map[i].name for i in ["if3", "if4"]] 385*09e702adSMark Johnston self.pimd1 = self.run_ip6_mrouted("test1", ifaces, fib=1) 386*09e702adSMark Johnston time.sleep(1) # Give ip6_mrouted a bit of time to get itself together. 387*09e702adSMark Johnston 388*09e702adSMark Johnston def vnet_host1_handler(self, vnet): 389*09e702adSMark Johnston self.jointest(vnet) 390*09e702adSMark Johnston 391*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) 392*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast on FIB 0!") 393*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 394*09e702adSMark Johnston b"Goodbye, Multicast on FIB 0!") 395*09e702adSMark Johnston self.donetest() 396*09e702adSMark Johnston 397*09e702adSMark Johnston def vnet_host2_handler(self, vnet): 398*09e702adSMark Johnston self.jointest(vnet) 399*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) 400*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 401*09e702adSMark Johnston b"Hello, Multicast on FIB 0!") 402*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast on FIB 0!") 403*09e702adSMark Johnston self._msgwait(self.sock, b"Goodbye, Multicast on FIB 0!") 404*09e702adSMark Johnston self.donetest() 405*09e702adSMark Johnston 406*09e702adSMark Johnston def vnet_host3_handler(self, vnet): 407*09e702adSMark Johnston self.jointest(vnet) 408*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) 409*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast on FIB 1!") 410*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, 411*09e702adSMark Johnston vnet.ifaces[0].name, b"Goodbye, Multicast on FIB 1!") 412*09e702adSMark Johnston self.donetest() 413*09e702adSMark Johnston 414*09e702adSMark Johnston def vnet_host4_handler(self, vnet): 415*09e702adSMark Johnston self.jointest(vnet) 416*09e702adSMark Johnston self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) 417*09e702adSMark Johnston time.sleep(1) 418*09e702adSMark Johnston self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, 419*09e702adSMark Johnston b"Hello, Multicast on FIB 1!") 420*09e702adSMark Johnston self._msgwait(self.sock, b"Hello, Multicast on FIB 1!") 421*09e702adSMark Johnston self._msgwait(self.sock, b"Goodbye, Multicast on FIB 1!") 422*09e702adSMark Johnston self.donetest() 423*09e702adSMark Johnston 424*09e702adSMark Johnston @pytest.mark.require_user("root") 425*09e702adSMark Johnston @pytest.mark.timeout(30) 426*09e702adSMark Johnston def test(self): 427*09e702adSMark Johnston self.starttest(["vnet_host1", "vnet_host2", "vnet_host3", "vnet_host4"]) 428*09e702adSMark Johnston self.waittest() 429