Path: blob/main/tests/sys/net/routing/test_rtsock_multipath.py
39604 views
import pytest1from atf_python.sys.net.rtsock import RtConst2from atf_python.sys.net.rtsock import Rtsock3from atf_python.sys.net.rtsock import RtsockRtMessage4from atf_python.sys.net.tools import ToolsHelper5from atf_python.sys.net.vnet import SingleVnetTestTemplate678class TestRtmMultipath(SingleVnetTestTemplate):9def setup_method(self, method):10method_name = method.__name__11if "multipath4" in method_name:12self.IPV4_PREFIXES = ["192.0.2.1/24"]13self.PREFIX = "128.66.0.0/24"14elif "multipath6" in method_name:15self.IPV6_PREFIXES = ["2001:db8::1/64"]16self.PREFIX = "2001:db8:0:ddbb::/64"17super().setup_method(method)18self.rtsock = Rtsock()1920def get_prefix_routes(self):21family = "inet6" if ":" in self.PREFIX else "inet"22routes = ToolsHelper.get_routes(family)23return [r for r in routes if r["destination"] == self.PREFIX]2425@pytest.mark.parametrize(26"gws",27[28pytest.param(["+.10=2", "+.5=3"], id="transition_multi"),29pytest.param(["+.10=2", "+.5=3", "-.10=2"], id="transition_single1"),30pytest.param(["+.10=2", "+.5=3", "-.5=3"], id="transition_single2"),31pytest.param(32["+.10", "+.11", "+.50", "+.13", "+.145", "+.72"], id="correctness1"33),34pytest.param(35["+.10", "+.11", "+.50", "-.50", "+.145", "+.72"], id="correctness2"36),37pytest.param(["+.10=1", "+.5=2"], id="weight1"),38pytest.param(["+.10=2", "+.5=7"], id="weight2"),39pytest.param(["+.10=13", "+.5=21"], id="weight3_max"),40pytest.param(["+.10=2", "+.5=3", "~.5=4"], id="change_new_weight1"),41pytest.param(["+.10=2", "+.5=3", "~.10=3"], id="change_new_weight2"),42pytest.param(43["+.10=2", "+.5=3", "+.7=4", "~.10=3"], id="change_new_weight3"44),45pytest.param(["+.10=2", "+.5=3", "~.5=3"], id="change_same_weight1"),46pytest.param(47["+.10=2", "+.5=3", "+.7=4", "~.5=3"], id="change_same_weight2"48),49],50)51@pytest.mark.require_user("root")52def test_rtm_multipath4(self, gws):53"""Tests RTM_ADD with IPv4 dest transitioning to multipath"""54self._test_rtm_multipath(gws, "192.0.2")5556@pytest.mark.parametrize(57"gws",58[59pytest.param(["+:10=2", "+:5=3"], id="transition_multi"),60pytest.param(["+:10=2", "+:5=3", "-:10=2"], id="transition_single1"),61pytest.param(["+:10=2", "+:5=3", "-:5=3"], id="transition_single2"),62pytest.param(63["+:10", "+:11", "+:50", "+:13", "+:145", "+:72"], id="correctness1"64),65pytest.param(66["+:10", "+:11", "+:50", "-:50", "+:145", "+:72"], id="correctness2"67),68pytest.param(["+:10=1", "+:5=2"], id="weight1"),69pytest.param(["+:10=2", "+:5=7"], id="weight2"),70pytest.param(["+:10=13", "+:5=21"], id="weight3_max"),71pytest.param(["+:10=13", "+:5=21"], id="weight3_max"),72pytest.param(["+:10=2", "+:5=3", "~:5=4"], id="change_new_weight1"),73pytest.param(["+:10=2", "+:5=3", "~:10=3"], id="change_new_weight2"),74pytest.param(75["+:10=2", "+:5=3", "+:7=4", "~:10=3"], id="change_new_weight3"76),77pytest.param(["+:10=2", "+:5=3", "~:5=3"], id="change_same_weight1"),78pytest.param(79["+:10=2", "+:5=3", "+:7=4", "~:5=3"], id="change_same_weight2"80),81],82)83@pytest.mark.require_user("root")84def test_rtm_multipath6(self, gws):85"""Tests RTM_ADD with IPv6 dest transitioning to multipath"""86self._test_rtm_multipath(gws, "2001:db8:")8788def _test_rtm_multipath(self, gws, gw_prefix: str):89desired_map = {}90for gw_act in gws:91# GW format: <+-~>GW[=weight]92if "=" in gw_act:93arr = gw_act[1:].split("=")94weight = int(arr[1])95gw = gw_prefix + arr[0]96else:97weight = None98gw = gw_prefix + gw_act[1:]99if gw_act[0] == "+":100msg = self.rtsock.new_rtm_add(self.PREFIX, gw)101desired_map[gw] = self.rtsock.get_weight(weight)102elif gw_act[0] == "-":103msg = self.rtsock.new_rtm_del(self.PREFIX, gw)104del desired_map[gw]105else:106msg = self.rtsock.new_rtm_change(self.PREFIX, gw)107desired_map[gw] = self.rtsock.get_weight(weight)108109msg.rtm_flags = RtConst.RTF_GATEWAY110if weight:111msg.rtm_inits |= RtConst.RTV_WEIGHT112msg.rtm_rmx.rmx_weight = weight113# Prepare SAs to check for114desired_sa = {115RtConst.RTA_DST: msg.get_sa(RtConst.RTA_DST),116RtConst.RTA_NETMASK: msg.get_sa(RtConst.RTA_NETMASK),117RtConst.RTA_GATEWAY: msg.get_sa(RtConst.RTA_GATEWAY),118}119self.rtsock.write_message(msg)120121data = self.rtsock.read_data(msg.rtm_seq)122msg_in = RtsockRtMessage.from_bytes(data)123msg_in.print_in_message()124msg_in.verify(msg.rtm_type, desired_sa)125assert msg_in.rtm_rmx.rmx_weight == self.rtsock.get_weight(weight)126127routes = self.get_prefix_routes()128derived_map = {r["gateway"]: r["weight"] for r in routes}129assert derived_map == desired_map130131@pytest.mark.require_user("root")132def test_rtm_multipath4_add_same_eexist(self):133"""Tests adding same IPv4 gw to the multipath group (EEXIST)"""134gws = ["192.0.2.10", "192.0.2.11", "192.0.2.11"]135self._test_rtm_multipath_add_same_eexist(gws)136137@pytest.mark.require_user("root")138def test_rtm_multipath6_add_same_eexist(self):139"""Tests adding same IPv4 gw to the multipath group (EEXIST)"""140gws = ["2001:db8::10", "2001:db8::11", "2001:db8::11"]141self._test_rtm_multipath_add_same_eexist(gws)142143def _test_rtm_multipath_add_same_eexist(self, gws):144for idx, gw in enumerate(gws):145msg = self.rtsock.new_rtm_add(self.PREFIX, gw)146msg.rtm_flags = RtConst.RTF_GATEWAY147try:148self.rtsock.write_message(msg)149except FileExistsError as e:150if idx != 2:151raise152print("Succcessfully raised {}".format(e))153154@pytest.mark.require_user("root")155def test_rtm_multipath4_del_unknown_esrch(self):156"""Tests deleting non-existing dest from the multipath group (ESRCH)"""157gws = ["192.0.2.10", "192.0.2.11"]158self._test_rtm_multipath_del_unknown_esrch(gws, "192.0.2.7")159160@pytest.mark.require_user("root")161def test_rtm_multipath6_del_unknown_esrch(self):162"""Tests deleting non-existing dest from the multipath group (ESRCH)"""163gws = ["2001:db8::10", "2001:db8::11"]164self._test_rtm_multipath_del_unknown_esrch(gws, "2001:db8::7")165166@pytest.mark.require_user("root")167def _test_rtm_multipath_del_unknown_esrch(self, gws, target_gw):168for gw in gws:169msg = self.rtsock.new_rtm_add(self.PREFIX, gw)170msg.rtm_flags = RtConst.RTF_GATEWAY171self.rtsock.write_message(msg)172msg = self.rtsock.new_rtm_del(self.PREFIX, target_gw)173msg.rtm_flags = RtConst.RTF_GATEWAY174try:175self.rtsock.write_message(msg)176except ProcessLookupError as e:177print("Succcessfully raised {}".format(e))178179@pytest.mark.require_user("root")180def test_rtm_multipath4_change_unknown_esrch(self):181"""Tests changing non-existing dest in the multipath group (ESRCH)"""182gws = ["192.0.2.10", "192.0.2.11"]183self._test_rtm_multipath_change_unknown_esrch(gws, "192.0.2.7")184185@pytest.mark.require_user("root")186def test_rtm_multipath6_change_unknown_esrch(self):187"""Tests changing non-existing dest in the multipath group (ESRCH)"""188gws = ["2001:db8::10", "2001:db8::11"]189self._test_rtm_multipath_change_unknown_esrch(gws, "2001:db8::7")190191@pytest.mark.require_user("root")192def _test_rtm_multipath_change_unknown_esrch(self, gws, target_gw):193for gw in gws:194msg = self.rtsock.new_rtm_add(self.PREFIX, gw)195msg.rtm_flags = RtConst.RTF_GATEWAY196self.rtsock.write_message(msg)197msg = self.rtsock.new_rtm_change(self.PREFIX, target_gw)198msg.rtm_flags = RtConst.RTF_GATEWAY199try:200self.rtsock.write_message(msg)201except ProcessLookupError as e:202print("Succcessfully raised {}".format(e))203204@pytest.mark.require_user("root")205def test_rtm_multipath4_add_zero_weight(self):206"""Tests RTM_ADD with dest transitioning to multipath"""207208desired_map = {}209for gw in ["192.0.2.10", "192.0.2.11", "192.0.2.13"]:210msg = self.rtsock.new_rtm_add(self.PREFIX, gw)211msg.rtm_flags = RtConst.RTF_GATEWAY212msg.rtm_rmx.rmx_weight = 0213msg.rtm_inits |= RtConst.RTV_WEIGHT214self.rtsock.write_message(msg)215desired_map[gw] = self.rtsock.get_weight(0)216217routes = self.get_prefix_routes()218derived_map = {r["gateway"]: r["weight"] for r in routes}219assert derived_map == desired_map220221@pytest.mark.require_user("root")222def test_rtm_multipath4_getroute(self):223"""Tests RTM_GET with exact prefix lookup on the multipath group"""224gws = ["192.0.2.10", "192.0.2.11", "192.0.2.13"]225return self._test_rtm_multipath_getroute(gws)226227@pytest.mark.require_user("root")228def test_rtm_multipath6_getroute(self):229"""Tests RTM_GET with exact prefix lookup on the multipath group"""230gws = ["2001:db8::10", "2001:db8::11", "2001:db8::13"]231return self._test_rtm_multipath_getroute(gws)232233def _test_rtm_multipath_getroute(self, gws):234valid_gws = []235for gw in gws:236msg = self.rtsock.new_rtm_add(self.PREFIX, gw)237msg.rtm_flags = RtConst.RTF_GATEWAY238self.rtsock.write_message(msg)239240desired_sa = {241RtConst.RTA_DST: msg.get_sa(RtConst.RTA_DST),242RtConst.RTA_NETMASK: msg.get_sa(RtConst.RTA_NETMASK),243}244valid_gws.append(msg.get_sa(RtConst.RTA_GATEWAY))245246msg_get = RtsockRtMessage(247RtConst.RTM_GET,248self.rtsock.get_seq(),249msg.get_sa(RtConst.RTA_DST),250msg.get_sa(RtConst.RTA_NETMASK),251)252self.rtsock.write_message(msg_get)253254data = self.rtsock.read_data(msg_get.rtm_seq)255msg_in = RtsockRtMessage.from_bytes(data)256msg_in.print_in_message()257msg_in.verify(RtConst.RTM_GET, desired_sa)258259# Additionally, check that the gateway is among the valid260# gateways261gw_found = False262gw_in = msg_in.get_sa(RtConst.RTA_GATEWAY)263for valid_gw in valid_gws:264try:265assert valid_gw == gw_in266gw_found = True267break268except AssertionError:269pass270assert gw_found is True271272273