diff options
| author | Mark Johnston <markj@FreeBSD.org> | 2026-03-30 13:32:35 +0000 |
|---|---|---|
| committer | Mark Johnston <markj@FreeBSD.org> | 2026-03-30 16:08:21 +0000 |
| commit | 09e702ad40af0067017613070b42d72cbc2bec3a (patch) | |
| tree | f4bbd584dc5401e8b8382e2cd3755f60b4078ecd /tests | |
| parent | d4339cebbe8e0b26f92a74eb5d4d9a20403c2ad1 (diff) | |
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/sys/netinet/Makefile | 13 | ||||
| -rw-r--r-- | tests/sys/netinet/ip6_mrouted.c | 191 | ||||
| -rw-r--r-- | tests/sys/netinet/ip_mroute.py | 428 | ||||
| -rw-r--r-- | tests/sys/netinet6/Makefile | 1 |
4 files changed, 629 insertions, 4 deletions
diff --git a/tests/sys/netinet/Makefile b/tests/sys/netinet/Makefile index 42906aa2dd93..a13b0b42e2bc 100644 --- a/tests/sys/netinet/Makefile +++ b/tests/sys/netinet/Makefile @@ -29,9 +29,10 @@ ATF_TESTS_SH= arp \ output \ redirect -ATF_TESTS_PYTEST+= carp.py -ATF_TESTS_PYTEST+= igmp.py -ATF_TESTS_PYTEST+= tcp_hpts_test.py +ATF_TESTS_PYTEST+= carp.py \ + igmp.py \ + ip_mroute.py \ + tcp_hpts_test.py LIBADD.so_reuseport_lb_test= pthread LIBADD.udp_bindings= pthread @@ -54,7 +55,11 @@ TEST_METADATA.raw+= execenv="jail" \ execenv_jail_params="vnet allow.raw_sockets" TEST_METADATA.redirect+= required_programs="python" -PROGS= udp_dontroute tcp_user_cookie multicast-send multicast-receive +PROGS= ip6_mrouted \ + multicast-send \ + multicast-receive \ + tcp_user_cookie \ + udp_dontroute ${PACKAGE}FILES+= redirect.py diff --git a/tests/sys/netinet/ip6_mrouted.c b/tests/sys/netinet/ip6_mrouted.c new file mode 100644 index 000000000000..f3df8330df10 --- /dev/null +++ b/tests/sys/netinet/ip6_mrouted.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2026 Stormshield + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * A dead-simple IPv6 multicast routing daemon. It registers itself with the + * multicast routing code and then waits for messages from the kernel. Received + * messages are handled by installing multicast routes. + */ + +#include <sys/types.h> +#include <sys/event.h> +#include <sys/queue.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet6/ip6_mroute.h> +#include <arpa/inet.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +struct mif { + const char *name; + int mifi; + int pifi; + STAILQ_ENTRY(mif) next; +}; +static STAILQ_HEAD(, mif) miflist = STAILQ_HEAD_INITIALIZER(miflist); + +static void * +xmalloc(size_t size) +{ + void *ptr; + + ptr = malloc(size); + if (ptr == NULL) + err(1, "malloc"); + return (ptr); +} + +static void +usage(void) +{ + fprintf(stderr, + "usage: %s [-i <iface>] [-m <srcaddr>/<groupaddr>/<iface>]\n", + getprogname()); + exit(1); +} + +static void +add_route(int sd, const struct in6_addr *src, const struct in6_addr *group, + mifi_t mifi) +{ + struct mf6cctl mfcc; + struct mif *mif; + int error; + + memset(&mfcc, 0, sizeof(mfcc)); + mfcc.mf6cc_parent = mifi; + mfcc.mf6cc_origin.sin6_family = AF_INET6; + mfcc.mf6cc_origin.sin6_len = sizeof(struct sockaddr_in6); + mfcc.mf6cc_origin.sin6_addr = *src; + mfcc.mf6cc_mcastgrp.sin6_family = AF_INET6; + mfcc.mf6cc_mcastgrp.sin6_len = sizeof(struct sockaddr_in6); + mfcc.mf6cc_mcastgrp.sin6_addr = *group; + + STAILQ_FOREACH(mif, &miflist, next) { + if (mif->mifi != mifi) + IF_SET(mif->mifi, &mfcc.mf6cc_ifset); + } + + error = setsockopt(sd, IPPROTO_IPV6, MRT6_ADD_MFC, + &mfcc, sizeof(mfcc)); + if (error != 0) + err(1, "setsockopt(MRT6_ADD_MFC)"); +} + +static void +handle_upcalls(int sd) +{ + struct kevent ev; + int kq; + + kq = kqueue(); + if (kq < 0) + err(1, "kqueue"); + EV_SET(&ev, sd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); + if (kevent(kq, &ev, 1, NULL, 0, NULL) < 0) + err(1, "kevent"); + + for (;;) { + char buf1[INET6_ADDRSTRLEN], buf2[INET6_ADDRSTRLEN]; + struct mrt6msg msg; + ssize_t len; + int n; + + n = kevent(kq, NULL, 0, &ev, 1, NULL); + if (n < 0) { + if (errno == EINTR) + break; + err(1, "kevent"); + } + if (n == 0) + continue; + assert(n == 1); + assert(ev.filter == EVFILT_READ); + + len = recv(sd, &msg, sizeof(msg), 0); + if (len < 0) + err(1, "recv"); + if ((size_t)len < sizeof(msg)) { + warnx("short read on upcall, %zd bytes", len); + continue; + } + + printf("upcall received:\n"); + printf("msgtype=%d mif=%d src=%s dst=%s\n", + msg.im6_msgtype, msg.im6_mif, + inet_ntop(AF_INET6, &msg.im6_src, buf1, sizeof(buf1)), + inet_ntop(AF_INET6, &msg.im6_dst, buf2, sizeof(buf2))); + + add_route(sd, &msg.im6_src, &msg.im6_dst, msg.im6_mif); + } + + close(kq); +} + +int +main(int argc, char **argv) +{ + struct mif *mif; + int ch, error, mifi, sd, v; + + mifi = 0; + while ((ch = getopt(argc, argv, "i:m:")) != -1) { + switch (ch) { + case 'i': + mif = xmalloc(sizeof(*mif)); + mif->name = strdup(optarg); + mif->mifi = mifi++; + mif->pifi = if_nametoindex(optarg); + if (mif->pifi == 0) + errx(1, "unknown interface %s", optarg); + STAILQ_INSERT_TAIL(&miflist, mif, next); + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + sd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + if (sd < 0) + err(1, "socket"); + + v = 1; + error = setsockopt(sd, IPPROTO_IPV6, MRT6_INIT, &v, sizeof(v)); + if (error != 0) + err(1, "setsockopt(MRT6_INIT)"); + + STAILQ_FOREACH(mif, &miflist, next) { + struct mif6ctl mifc; + + mifc.mif6c_mifi = mif->mifi; + mifc.mif6c_pifi = mif->pifi; + mifc.mif6c_flags = 0; + error = setsockopt(sd, IPPROTO_IPV6, MRT6_ADD_MIF, + &mifc, sizeof(mifc)); + if (error != 0) + err(1, "setsockopt(MRT6_ADD_MIF) on %s", mif->name); + } + + handle_upcalls(sd); + + error = setsockopt(sd, IPPROTO_IPV6, MRT6_DONE, NULL, 0); + if (error != 0) + err(1, "setsockopt(MRT6_DONE)"); + + return (0); +} diff --git a/tests/sys/netinet/ip_mroute.py b/tests/sys/netinet/ip_mroute.py new file mode 100644 index 000000000000..5416d824d3c2 --- /dev/null +++ b/tests/sys/netinet/ip_mroute.py @@ -0,0 +1,428 @@ +# +# Copyright (c) 2025 Stormshield +# +# SPDX-License-Identifier: BSD-2-Clause +# + +import pytest +import socket +import struct +import subprocess +import time +from pathlib import Path + +from atf_python.sys.net.vnet import VnetTestTemplate + + +class MRouteTestTemplate(VnetTestTemplate): + """ + Helper class for multicast routing tests. Test classes should inherit from this one. + """ + COORD_SOCK = "coord.sock" + + @staticmethod + def _msgwait(sock: socket.socket, expected: bytes): + msg = sock.recv(1024) + assert msg == expected + + @staticmethod + def sendmsg(msg: bytes, path: str): + s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + s.sendto(msg, path) + s.close() + + @staticmethod + def _makesock(path: str): + s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + s.bind(path) + return s + + @staticmethod + def mcast_join_INET6(addr: str, port: int): + pass + + def jointest(self, vnet): + """Let the coordinator know that we're ready, and wait for go-ahead.""" + coord = self._makesock(vnet.alias + ".sock") + self.sendmsg(b"ok " + vnet.alias.encode(), self.COORD_SOCK) + self._msgwait(coord, b"join") + + def donetest(self): + """Let the coordinator that we completed successfully.""" + self.sendmsg(b"done", self.COORD_SOCK) + + def starttest(self, vnets: list[str]): + self.vnets = vnets + for vnet in vnets: + self.sendmsg(b"join", vnet + ".sock") + + def waittest(self): + for vnet in self.vnets: + self._msgwait(self.coord, b"done") + + def setup_method(self, method): + self.coord = self._makesock(self.COORD_SOCK) + super().setup_method(method) + + # Loop until all other hosts have sent the ok message. + received = set() + vnet_names = set(self.vnet_map.keys()) - {self.vnet.alias} + while len(received) < len(vnet_names): + msg = self.coord.recv(1024) + received.add(msg) + assert received == {b"ok " + name.encode() for name in vnet_names} + + +class MRouteINETTestTemplate(MRouteTestTemplate): + @staticmethod + def run_pimd(ident: str, ifaces: list[str], rpaddr: str, group: str, fib=0): + conf = f"pimd-{ident}.conf" + with open(conf, "w") as conf_file: + conf_file.write("no phyint\n") + for iface in ifaces: + conf_file.write(f"phyint {iface} enable\n") + conf_file.write(f"rp-address {rpaddr} {group}\n") + + cmd = f"setfib {fib} pimd -i {ident} -f {conf} -p pimd-{ident}.pid -n" + return subprocess.Popen(cmd.split(), stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + + @staticmethod + def mcast_join(addr: str, port: int): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + mreq = struct.pack("4si", socket.inet_aton(addr), socket.INADDR_ANY) + s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + s.bind((addr, port)) + time.sleep(1) # Give the kernel a bit of time to join the group. + return s + + @staticmethod + def mcast_sendto(addr: str, port: int, iface: str, msg: bytes): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + mreqn = struct.pack("iii", socket.INADDR_ANY, socket.INADDR_ANY, + socket.if_nametoindex(iface)) + s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, mreqn) + s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 64) + s.sendto(msg, (addr, port)) + s.close() + + def setup_method(self, method): + self.require_module("ip_mroute") + super().setup_method(method) + + +class MRouteINET6TestTemplate(MRouteTestTemplate): + @staticmethod + def run_ip6_mrouted(ident: str, ifaces: list[str], fib=0): + ifaces_str = ' '.join(f"-i {iface}" for iface in ifaces) + exepath = Path(__file__).parent / "ip6_mrouted" + cmd = f"setfib {fib} {exepath} {ifaces_str}" + return subprocess.Popen(cmd.split(), stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + + @staticmethod + def mcast_join(addr: str, port: int, iface: str): + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + mreq = struct.pack("16si", socket.inet_pton(socket.AF_INET6, addr), + socket.if_nametoindex(iface)) + s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq) + s.bind((addr, port)) + time.sleep(1) # Give the kernel a bit of time to join the + return s + + @staticmethod + def mcast_sendto(addr: str, port: int, iface: str, msg: bytes): + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + mreq = struct.pack("i", socket.if_nametoindex(iface)) + s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, mreq) + s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 64) + s.sendto(msg, (addr, port)) + s.close() + + def setup_method(self, method): + self.require_module("ip6_mroute") + super().setup_method(method) + + +class Test1RBasicINET(MRouteINETTestTemplate): + """Basic multicast routing setup with 2 hosts connected via a router.""" + + TOPOLOGY = { + "vnet_router": {"ifaces": ["if1", "if2"]}, + "vnet_host1": {"ifaces": ["if1"]}, + "vnet_host2": {"ifaces": ["if2"]}, + "if1": {"prefixes4": [("192.168.1.1/24", "192.168.1.2/24")]}, + "if2": {"prefixes4": [("192.168.2.1/24", "192.168.2.2/24")]}, + } + MULTICAST_ADDR = "239.0.0.1" + + def setup_method(self, method): + # Create VNETs and start the handlers. + super().setup_method(method) + + ifaces = [self.vnet.iface_alias_map[i].name for i in ["if1", "if2"]] + self.pimd = self.run_pimd("test", ifaces, "127.0.0.1", self.MULTICAST_ADDR + "/32") + time.sleep(3) # Give pimd a bit of time to get itself together. + + def vnet_host1_handler(self, vnet): + self.jointest(vnet) + + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) + + # Wait for host 2 to send a message, then send a reply. + self._msgwait(self.sock, b"Hello, Multicast!") + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Goodbye, Multicast!") + self._msgwait(self.sock, b"Goodbye, Multicast!") + self.donetest() + + def vnet_host2_handler(self, vnet): + self.jointest(vnet) + + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) + + # Send a message to host 1, then wait for a reply. + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Hello, Multicast!") + self._msgwait(self.sock, b"Hello, Multicast!") + self._msgwait(self.sock, b"Goodbye, Multicast!") + self.donetest() + + @pytest.mark.require_user("root") + @pytest.mark.require_progs(["pimd"]) + @pytest.mark.timeout(30) + def test(self): + self.starttest(["vnet_host1", "vnet_host2"]) + self.waittest() + + +class Test1RCrissCrossINET(MRouteINETTestTemplate): + """ + Test a router connected to four hosts, with pairs of interfaces + in different FIBs. + """ + + TOPOLOGY = { + "vnet_router": {"ifaces": ["if1", "if2", "if3", "if4"]}, + "vnet_host1": {"ifaces": ["if1"]}, + "vnet_host2": {"ifaces": ["if2"]}, + "vnet_host3": {"ifaces": ["if3"]}, + "vnet_host4": {"ifaces": ["if4"]}, + "if1": { + "prefixes4": [("192.168.1.1/24", "192.168.1.2/24")], + "prefixes6": [], + "fib": (0, 0), + }, + "if2": { + "prefixes4": [("192.168.2.1/24", "192.168.2.2/24")], + "prefixes6": [], + "fib": (0, 0), + }, + "if3": { + "prefixes4": [("192.168.3.1/24", "192.168.3.2/24")], + "prefixes6": [], + "fib": (1, 0), + }, + "if4": { + "prefixes4": [("192.168.4.1/24", "192.168.4.2/24")], + "prefixes6": [], + "fib": (1, 0), + }, + } + MULTICAST_ADDR = "239.0.0.1" + + def setup_method(self, method): + # Create VNETs and start the handlers. + super().setup_method(method) + + # Start a pimd instance per FIB. + ifaces = [self.vnet.iface_alias_map[i].name for i in ["if1", "if2"]] + self.pimd0 = self.run_pimd("test0", ifaces, "127.0.0.1", self.MULTICAST_ADDR + "/32", + fib=0) + ifaces = [self.vnet.iface_alias_map[i].name for i in ["if3", "if4"]] + self.pimd1 = self.run_pimd("test1", ifaces, "127.0.0.1", self.MULTICAST_ADDR + "/32", + fib=1) + time.sleep(3) # Give pimd a bit of time to get itself together. + + def vnet_host1_handler(self, vnet): + self.jointest(vnet) + + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) + self._msgwait(self.sock, b"Hello, Multicast on FIB 0!") + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Goodbye, Multicast on FIB 0!") + self.donetest() + + def vnet_host2_handler(self, vnet): + self.jointest(vnet) + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Hello, Multicast on FIB 0!") + self._msgwait(self.sock, b"Hello, Multicast on FIB 0!") + self._msgwait(self.sock, b"Goodbye, Multicast on FIB 0!") + self.donetest() + + def vnet_host3_handler(self, vnet): + self.jointest(vnet) + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) + self._msgwait(self.sock, b"Hello, Multicast on FIB 1!") + self.mcast_sendto(self.MULTICAST_ADDR, 12345, + vnet.ifaces[0].name, b"Goodbye, Multicast on FIB 1!") + self.donetest() + + def vnet_host4_handler(self, vnet): + self.jointest(vnet) + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345) + time.sleep(1) + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Hello, Multicast on FIB 1!") + self._msgwait(self.sock, b"Hello, Multicast on FIB 1!") + self._msgwait(self.sock, b"Goodbye, Multicast on FIB 1!") + self.donetest() + + @pytest.mark.require_user("root") + @pytest.mark.require_progs(["pimd"]) + @pytest.mark.timeout(30) + def test(self): + self.starttest(["vnet_host1", "vnet_host2", "vnet_host3", "vnet_host4"]) + self.waittest() + + +class Test1RBasicINET6(MRouteINET6TestTemplate): + """Basic multicast routing setup with 2 hosts connected via a router.""" + + TOPOLOGY = { + "vnet_router": {"ifaces": ["if1", "if2"]}, + "vnet_host1": {"ifaces": ["if1"]}, + "vnet_host2": {"ifaces": ["if2"]}, + "if1": { + "prefixes6": [("2001:db8:0:1::1/64", "2001:db8:0:1::2/64")] + }, + "if2": { + "prefixes6": [("2001:db8:0:2::1/64", "2001:db8:0:2::2/64")] + }, + } + MULTICAST_ADDR = "ff05::1" + + def setup_method(self, method): + # Create VNETs and start the handlers. + super().setup_method(method) + + ifaces = [self.vnet.iface_alias_map[i].name for i in ["if1", "if2"]] + self.mrouted = self.run_ip6_mrouted("test", ifaces) + time.sleep(1) + + def vnet_host1_handler(self, vnet): + self.jointest(vnet) + + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) + + # Wait for host 2 to send a message, then send a reply. + self._msgwait(self.sock, b"Hello, Multicast!") + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Goodbye, Multicast!") + self._msgwait(self.sock, b"Goodbye, Multicast!") + self.donetest() + + def vnet_host2_handler(self, vnet): + self.jointest(vnet) + + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) + + # Send a message to host 1, then wait for a reply. + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Hello, Multicast!") + self._msgwait(self.sock, b"Hello, Multicast!") + self._msgwait(self.sock, b"Goodbye, Multicast!") + self.donetest() + + @pytest.mark.require_user("root") + @pytest.mark.timeout(30) + def test(self): + self.starttest(["vnet_host1", "vnet_host2"]) + self.waittest() + + +class Test1RCrissCrossINET6(MRouteINET6TestTemplate): + """ + Test a router connected to four hosts, with pairs of interfaces + in different FIBs. + """ + + TOPOLOGY = { + "vnet_router": {"ifaces": ["if1", "if2", "if3", "if4"]}, + "vnet_host1": {"ifaces": ["if1"]}, + "vnet_host2": {"ifaces": ["if2"]}, + "vnet_host3": {"ifaces": ["if3"]}, + "vnet_host4": {"ifaces": ["if4"]}, + "if1": { + "prefixes6": [("2001:db8:0:1::1/64", "2001:db8:0:1::2/64")], + "fib": (0, 0), + }, + "if2": { + "prefixes6": [("2001:db8:0:2::1/64", "2001:db8:0:2::2/64")], + "fib": (0, 0), + }, + "if3": { + "prefixes6": [("2001:db8:0:3::1/64", "2001:db8:0:3::2/64")], + "fib": (1, 0), + }, + "if4": { + "prefixes6": [("2001:db8:0:4::1/64", "2001:db8:0:4::2/64")], + "fib": (1, 0), + }, + } + MULTICAST_ADDR = "ff05::1" + + def setup_method(self, method): + # Create VNETs and start the handlers. + super().setup_method(method) + + # Start an ip6_mrouted instance per FIB. + ifaces = [self.vnet.iface_alias_map[i].name for i in ["if1", "if2"]] + self.pimd0 = self.run_ip6_mrouted("test0", ifaces, fib=0) + ifaces = [self.vnet.iface_alias_map[i].name for i in ["if3", "if4"]] + self.pimd1 = self.run_ip6_mrouted("test1", ifaces, fib=1) + time.sleep(1) # Give ip6_mrouted a bit of time to get itself together. + + def vnet_host1_handler(self, vnet): + self.jointest(vnet) + + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) + self._msgwait(self.sock, b"Hello, Multicast on FIB 0!") + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Goodbye, Multicast on FIB 0!") + self.donetest() + + def vnet_host2_handler(self, vnet): + self.jointest(vnet) + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Hello, Multicast on FIB 0!") + self._msgwait(self.sock, b"Hello, Multicast on FIB 0!") + self._msgwait(self.sock, b"Goodbye, Multicast on FIB 0!") + self.donetest() + + def vnet_host3_handler(self, vnet): + self.jointest(vnet) + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) + self._msgwait(self.sock, b"Hello, Multicast on FIB 1!") + self.mcast_sendto(self.MULTICAST_ADDR, 12345, + vnet.ifaces[0].name, b"Goodbye, Multicast on FIB 1!") + self.donetest() + + def vnet_host4_handler(self, vnet): + self.jointest(vnet) + self.sock = self.mcast_join(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name) + time.sleep(1) + self.mcast_sendto(self.MULTICAST_ADDR, 12345, vnet.ifaces[0].name, + b"Hello, Multicast on FIB 1!") + self._msgwait(self.sock, b"Hello, Multicast on FIB 1!") + self._msgwait(self.sock, b"Goodbye, Multicast on FIB 1!") + self.donetest() + + @pytest.mark.require_user("root") + @pytest.mark.timeout(30) + def test(self): + self.starttest(["vnet_host1", "vnet_host2", "vnet_host3", "vnet_host4"]) + self.waittest() diff --git a/tests/sys/netinet6/Makefile b/tests/sys/netinet6/Makefile index 26f1a18a8d32..f5a04a299dc6 100644 --- a/tests/sys/netinet6/Makefile +++ b/tests/sys/netinet6/Makefile @@ -1,6 +1,7 @@ PACKAGE= tests TESTSDIR= ${TESTSBASE}/sys/netinet6 +BINDIR= ${TESTSDIR} FILESDIR= ${TESTSDIR} ATF_TESTS_PYTEST= test_ip6_output.py |
