xref: /freebsd/tests/sys/netinet/ip_mroute.py (revision 09e702ad40af0067017613070b42d72cbc2bec3a)
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