diff --git a/tests/sys/netinet/carp.py b/tests/sys/netinet/carp.py --- a/tests/sys/netinet/carp.py +++ b/tests/sys/netinet/carp.py @@ -1,5 +1,9 @@ import pytest +import subprocess +import time from atf_python.sys.net.tools import ToolsHelper +from atf_python.sys.net.vnet import VnetInstance +from atf_python.sys.net.vnet import VnetInterface from atf_python.sys.net.vnet import VnetTestTemplate sc = None @@ -51,3 +55,102 @@ carp_pkts = sc.sniff(iface=if1.name, stop_filter=filter_f, timeout=5) self.check_carp_src_mac(carp_pkts) + + +class BaseCarpTest(VnetTestTemplate): + REQUIRED_MODULES = ["carp"] + + def wait_for_carp(self, vnet: VnetInstance, epair: VnetInterface): + while True: + out = ToolsHelper.get_output("ifconfig {}".format(epair.name)) + for line in out.splitlines(): + if "carp" in line and "MASTER" in line: + self.send_object(vnet.pipe, "") + return + print("vnet {}: waiting for CARP on {}".format(vnet.name, epair.name)) + time.sleep(0.5) + + def run(self, cmd): + assert subprocess.run(cmd.split()).returncode == 0 + + +class TestCarpBasicIPv4(BaseCarpTest): + TOPOLOGY = { + "vnet1": {"ifaces": ["epair2", "epair3", "bridge"]}, + "vnet2": {"ifaces": ["epair2"]}, + "vnet3": {"ifaces": ["epair3"]}, + "epair2": {"prefixes4": [("", "192.0.2.202/29")]}, + "epair3": {"prefixes4": [("", "192.0.2.203/29")]}, + "bridge": {"type": "bridge", "prefixes4": [("192.0.2.4/29", "")]}, + } + + def vnet2_handler(self, vnet: VnetInstance): + self.run("ifconfig {} add vhid 1 192.0.2.1/29".format(vnet.epair2.name)) + self.wait_for_carp(vnet, vnet.epair2) + self.wait() + + def vnet3_handler(self, vnet: VnetInstance): + self.run("ifconfig {} add vhid 1 192.0.2.1/29".format(vnet.epair3.name)) + self.wait_for_carp(vnet, vnet.epair3) + self.wait() + + @pytest.mark.require_user("root") + def test_carp(self): + """Basic CARP test (IPv4)""" + vnet = self.vnet + + vnet.epair2.turn_up() + vnet.epair3.turn_up() + + self.run( + "ifconfig {} addm {} addm {}".format( + vnet.bridge.name, vnet.epair2.name, vnet.epair3.name + ) + ) + + # Wait for carp readiness on one of the VNETs + self.wait_objects_any([self.vnet2.pipe, self.vnet3.pipe], timeout=10) + + self.run("ping -c3 192.0.2.1") + + +class TestCarpBasicIPv6(BaseCarpTest): + TOPOLOGY = { + "vnet1": {"ifaces": ["epair2", "epair3", "bridge"]}, + "vnet2": {"ifaces": ["epair2"]}, + "vnet3": {"ifaces": ["epair3"]}, + "epair2": {"prefixes6": [("", "2001:db8::1:2/64")]}, + "epair3": {"prefixes6": [("", "2001:db8::1:3/64")]}, + "bridge": {"type": "bridge", "prefixes6": [("2001:db8::0:4/64", "")]}, + } + + def vnet2_handler(self, vnet: VnetInstance): + epair = vnet.epair2 + self.run("ifconfig {} inet6 add vhid 1 2001:db8::0:1/64".format(epair.name)) + self.wait_for_carp(vnet, epair) + self.wait() + + def vnet3_handler(self, vnet: VnetInstance): + epair = vnet.epair3 + self.run("ifconfig {} inet6 add vhid 1 2001:db8::0:1/64".format(epair.name)) + self.wait_for_carp(vnet, epair) + self.wait() + + @pytest.mark.require_user("root") + def test_carp(self): + """Basic CARP test (IPv4)""" + vnet = self.vnet + + vnet.epair2.turn_up() + vnet.epair3.turn_up() + + self.run( + "ifconfig {} addm {} addm {}".format( + vnet.bridge.name, vnet.epair2.name, vnet.epair3.name + ) + ) + + # Wait for carp readiness on one of the VNETs + self.wait_objects_any([self.vnet2.pipe, self.vnet3.pipe], timeout=10) + + self.run("ping -6 -c3 2001:db8::0:1")