From nobody Fri Jan 13 21:25:20 2023 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Ntvb44cJqz2ql2c; Fri, 13 Jan 2023 21:25:20 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Ntvb43zwTz42Kp; Fri, 13 Jan 2023 21:25:20 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1673645120; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4YrFtFx8avB/TDRFRjAjIf/Tx4aPBRv0ZpgHQoDzOK8=; b=sBmBBfgTMhVmlo2t9DD+5cRua1SbDdAa5UEg5Ze1VMWwX0kzjieIwG0VkFEZTudtGncbzp PrcKgHM8l1RQi6Xva1pe9vRgIjKqFJtNz2ppI+NXf9gQTNOqyqP0pzUnDB/T0dKnFKqsO1 I79WMplNXYnYal313Mrwn6kixI+5tTa/dxLPGzcadDk6QAtHNK/DnZHLkYVU4v4+JQ7wgj 8riZDJNX5pOdzm9XmIhNJ17qQLy21+k+3MmGG9vbwDJwNLijEqA1pBJ6qco2LNMKMWWfzD s9aZZHT1EV82TkB65IQgIYqUuOsIsBMZbsqJPLUQtHlEFB2EyuCy2bps03ykyQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1673645120; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4YrFtFx8avB/TDRFRjAjIf/Tx4aPBRv0ZpgHQoDzOK8=; b=FTq/y7OI0G6mQ4008mo3VKNloYlRiAE+SZXbX6X2Qwi7wJZ133N5O0BxcO4Aj0+SYQcsHL S/2jhSdVndZHc7IJRlBjweNAghZXm/VMdCj9Sw/6dCwRJeYubfZ6edMGyOg9oBdVhGD2ir PaG2ckH8GGl+pIr4PFWYISBbk9ChJf3ezQ/+2d5MxBXt1wTi92TBpiUtifrYWF18orlyhF QqltO/XhdJdyO9+7So9EZ/eRS974WhPEvK/4ptLMb0qMdElonH72X5GCZWwA/hJ6eNEcIG 3pk9HtbyMwt8EtZFhg351z7zyt5UpI6IflXNtZOqZz/IPNyuYuFC+rpfI5W7Eg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1673645120; a=rsa-sha256; cv=none; b=HkM6/OkYJ8zv9Yqfmma3tbEw/u4grWbjFsXLv4VOGEk3QbzCKaunrKXsXNfzjE2xawECFE CwI8ZDBUSj0vM78EKzqI4G/qDnxnTU5pJPrUCuJagI3gLf81syf0h4zhPtI4fpaY+LXbTf SsbLJaL6EqTa27PS8YLBWCpQUyLFk4SUOzoKJ5rxevrs4Q458suAmpG4DNzItqUVNbR70H 2iQRX+7JmeFmsDosNfUH+bdyIqdMAzQGfhhahegPZ86Op3K9ETRJF/F3RGtyeWsOS8uZnX LxRkJ9ROBXP5NJbC7YQHmPGuu88o37u0OT26FYru4T1kuk/mmkpL9cLHVxkakA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Ntvb432fszNDJ; Fri, 13 Jan 2023 21:25:20 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 30DLPKAG041706; Fri, 13 Jan 2023 21:25:20 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 30DLPK3e041705; Fri, 13 Jan 2023 21:25:20 GMT (envelope-from git) Date: Fri, 13 Jan 2023 21:25:20 GMT Message-Id: <202301132125.30DLPK3e041705@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: 1386e7f6ea56 - stable/13 - routing: add multipath pytest tests List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: melifaro X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 1386e7f6ea5660db3ae66e1184d6c5e3ce599acf Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=1386e7f6ea5660db3ae66e1184d6c5e3ce599acf commit 1386e7f6ea5660db3ae66e1184d6c5e3ce599acf Author: Alexander V. Chernikov AuthorDate: 2022-06-25 19:25:38 +0000 Commit: Alexander V. Chernikov CommitDate: 2023-01-13 21:24:10 +0000 routing: add multipath pytest tests Differential Revision: https://reviews.freebsd.org/D31084 (cherry picked from commit bd03f10a6018a68cb1800f6db01b7552c39784bb) --- tests/sys/net/routing/Makefile | 1 + tests/sys/net/routing/test_rtsock_multipath.py | 271 +++++++++++++++++++++++++ 2 files changed, 272 insertions(+) diff --git a/tests/sys/net/routing/Makefile b/tests/sys/net/routing/Makefile index d32ba9af54a1..d71ba828f958 100644 --- a/tests/sys/net/routing/Makefile +++ b/tests/sys/net/routing/Makefile @@ -7,6 +7,7 @@ TESTSDIR= ${TESTSBASE}/sys/net/routing ATF_TESTS_C += test_rtsock_l3 ATF_TESTS_C += test_rtsock_lladdr +ATF_TESTS_PYTEST += test_rtsock_multipath.py ${PACKAGE}FILES+= generic_cleanup.sh ${PACKAGE}FILESMODE_generic_cleanup.sh=0555 diff --git a/tests/sys/net/routing/test_rtsock_multipath.py b/tests/sys/net/routing/test_rtsock_multipath.py new file mode 100755 index 000000000000..f4734d2f65bb --- /dev/null +++ b/tests/sys/net/routing/test_rtsock_multipath.py @@ -0,0 +1,271 @@ +import pytest +from atf_python.sys.net.rtsock import RtConst +from atf_python.sys.net.rtsock import Rtsock +from atf_python.sys.net.rtsock import RtsockRtMessage +from atf_python.sys.net.tools import ToolsHelper +from atf_python.sys.net.vnet import SingleVnetTestTemplate + + +class TestRtmMultipath(SingleVnetTestTemplate): + def setup_method(self, method): + method_name = method.__name__ + if "multipath4" in method_name: + self.IPV4_PREFIXES = ["192.0.2.1/24"] + self.PREFIX = "128.66.0.0/24" + elif "multipath6" in method_name: + self.IPV6_PREFIXES = ["2001:db8::1/64"] + self.PREFIX = "2001:db8:0:ddbb::/64" + super().setup_method(method) + self.rtsock = Rtsock() + + def get_prefix_routes(self): + family = "inet6" if ":" in self.PREFIX else "inet" + routes = ToolsHelper.get_routes(family) + return [r for r in routes if r["destination"] == self.PREFIX] + + @pytest.mark.parametrize( + "gws", + [ + pytest.param(["+.10=2", "+.5=3"], id="transition_multi"), + pytest.param(["+.10=2", "+.5=3", "-.10=2"], id="transition_single1"), + pytest.param(["+.10=2", "+.5=3", "-.5=3"], id="transition_single2"), + pytest.param( + ["+.10", "+.11", "+.50", "+.13", "+.145", "+.72"], id="correctness1" + ), + pytest.param( + ["+.10", "+.11", "+.50", "-.50", "+.145", "+.72"], id="correctness2" + ), + pytest.param(["+.10=1", "+.5=2"], id="weight1"), + pytest.param(["+.10=2", "+.5=7"], id="weight2"), + pytest.param(["+.10=13", "+.5=21"], id="weight3_max"), + pytest.param(["+.10=2", "+.5=3", "~.5=4"], id="change_new_weight1"), + pytest.param(["+.10=2", "+.5=3", "~.10=3"], id="change_new_weight2"), + pytest.param( + ["+.10=2", "+.5=3", "+.7=4", "~.10=3"], id="change_new_weight3" + ), + pytest.param(["+.10=2", "+.5=3", "~.5=3"], id="change_same_weight1"), + pytest.param( + ["+.10=2", "+.5=3", "+.7=4", "~.5=3"], id="change_same_weight2" + ), + ], + ) + @pytest.mark.require_user("root") + def test_rtm_multipath4(self, gws): + """Tests RTM_ADD with IPv4 dest transitioning to multipath""" + self._test_rtm_multipath(gws, "192.0.2") + + @pytest.mark.parametrize( + "gws", + [ + pytest.param(["+:10=2", "+:5=3"], id="transition_multi"), + pytest.param(["+:10=2", "+:5=3", "-:10=2"], id="transition_single1"), + pytest.param(["+:10=2", "+:5=3", "-:5=3"], id="transition_single2"), + pytest.param( + ["+:10", "+:11", "+:50", "+:13", "+:145", "+:72"], id="correctness1" + ), + pytest.param( + ["+:10", "+:11", "+:50", "-:50", "+:145", "+:72"], id="correctness2" + ), + pytest.param(["+:10=1", "+:5=2"], id="weight1"), + pytest.param(["+:10=2", "+:5=7"], id="weight2"), + pytest.param(["+:10=13", "+:5=21"], id="weight3_max"), + pytest.param(["+:10=13", "+:5=21"], id="weight3_max"), + pytest.param(["+:10=2", "+:5=3", "~:5=4"], id="change_new_weight1"), + pytest.param(["+:10=2", "+:5=3", "~:10=3"], id="change_new_weight2"), + pytest.param( + ["+:10=2", "+:5=3", "+:7=4", "~:10=3"], id="change_new_weight3" + ), + pytest.param(["+:10=2", "+:5=3", "~:5=3"], id="change_same_weight1"), + pytest.param( + ["+:10=2", "+:5=3", "+:7=4", "~:5=3"], id="change_same_weight2" + ), + ], + ) + @pytest.mark.require_user("root") + def test_rtm_multipath6(self, gws): + """Tests RTM_ADD with IPv6 dest transitioning to multipath""" + self._test_rtm_multipath(gws, "2001:db8:") + + def _test_rtm_multipath(self, gws, gw_prefix: str): + desired_map = {} + for gw_act in gws: + # GW format: <+-~>GW[=weight] + if "=" in gw_act: + arr = gw_act[1:].split("=") + weight = int(arr[1]) + gw = gw_prefix + arr[0] + else: + weight = None + gw = gw_prefix + gw_act[1:] + if gw_act[0] == "+": + msg = self.rtsock.new_rtm_add(self.PREFIX, gw) + desired_map[gw] = self.rtsock.get_weight(weight) + elif gw_act[0] == "-": + msg = self.rtsock.new_rtm_del(self.PREFIX, gw) + del desired_map[gw] + else: + msg = self.rtsock.new_rtm_change(self.PREFIX, gw) + desired_map[gw] = self.rtsock.get_weight(weight) + + msg.rtm_flags = RtConst.RTF_GATEWAY + if weight: + msg.rtm_inits |= RtConst.RTV_WEIGHT + msg.rtm_rmx.rmx_weight = weight + # Prepare SAs to check for + desired_sa = { + RtConst.RTA_DST: msg.get_sa(RtConst.RTA_DST), + RtConst.RTA_NETMASK: msg.get_sa(RtConst.RTA_NETMASK), + RtConst.RTA_GATEWAY: msg.get_sa(RtConst.RTA_GATEWAY), + } + self.rtsock.write_message(msg) + + data = self.rtsock.read_data(msg.rtm_seq) + msg_in = RtsockRtMessage.from_bytes(data) + msg_in.print_in_message() + msg_in.verify(msg.rtm_type, desired_sa) + assert msg_in.rtm_rmx.rmx_weight == self.rtsock.get_weight(weight) + + routes = self.get_prefix_routes() + derived_map = {r["gateway"]: r["weight"] for r in routes} + assert derived_map == desired_map + + @pytest.mark.require_user("root") + def test_rtm_multipath4_add_same_eexist(self): + """Tests adding same IPv4 gw to the multipath group (EEXIST)""" + gws = ["192.0.2.10", "192.0.2.11", "192.0.2.11"] + self._test_rtm_multipath_add_same_eexist(gws) + + @pytest.mark.require_user("root") + def test_rtm_multipath6_add_same_eexist(self): + """Tests adding same IPv4 gw to the multipath group (EEXIST)""" + gws = ["2001:db8::10", "2001:db8::11", "2001:db8::11"] + self._test_rtm_multipath_add_same_eexist(gws) + + def _test_rtm_multipath_add_same_eexist(self, gws): + for idx, gw in enumerate(gws): + msg = self.rtsock.new_rtm_add(self.PREFIX, gw) + msg.rtm_flags = RtConst.RTF_GATEWAY + try: + self.rtsock.write_message(msg) + except FileExistsError as e: + if idx != 2: + raise + print("Succcessfully raised {}".format(e)) + + @pytest.mark.require_user("root") + def test_rtm_multipath4_del_unknown_esrch(self): + """Tests deleting non-existing dest from the multipath group (ESRCH)""" + gws = ["192.0.2.10", "192.0.2.11"] + self._test_rtm_multipath_del_unknown_esrch(gws, "192.0.2.7") + + @pytest.mark.require_user("root") + def test_rtm_multipath6_del_unknown_esrch(self): + """Tests deleting non-existing dest from the multipath group (ESRCH)""" + gws = ["2001:db8::10", "2001:db8::11"] + self._test_rtm_multipath_del_unknown_esrch(gws, "2001:db8::7") + + @pytest.mark.require_user("root") + def _test_rtm_multipath_del_unknown_esrch(self, gws, target_gw): + for gw in gws: + msg = self.rtsock.new_rtm_add(self.PREFIX, gw) + msg.rtm_flags = RtConst.RTF_GATEWAY + self.rtsock.write_message(msg) + msg = self.rtsock.new_rtm_del(self.PREFIX, target_gw) + msg.rtm_flags = RtConst.RTF_GATEWAY + try: + self.rtsock.write_message(msg) + except ProcessLookupError as e: + print("Succcessfully raised {}".format(e)) + + @pytest.mark.require_user("root") + def test_rtm_multipath4_change_unknown_esrch(self): + """Tests changing non-existing dest in the multipath group (ESRCH)""" + gws = ["192.0.2.10", "192.0.2.11"] + self._test_rtm_multipath_change_unknown_esrch(gws, "192.0.2.7") + + @pytest.mark.require_user("root") + def test_rtm_multipath6_change_unknown_esrch(self): + """Tests changing non-existing dest in the multipath group (ESRCH)""" + gws = ["2001:db8::10", "2001:db8::11"] + self._test_rtm_multipath_change_unknown_esrch(gws, "2001:db8::7") + + @pytest.mark.require_user("root") + def _test_rtm_multipath_change_unknown_esrch(self, gws, target_gw): + for gw in gws: + msg = self.rtsock.new_rtm_add(self.PREFIX, gw) + msg.rtm_flags = RtConst.RTF_GATEWAY + self.rtsock.write_message(msg) + msg = self.rtsock.new_rtm_change(self.PREFIX, target_gw) + msg.rtm_flags = RtConst.RTF_GATEWAY + try: + self.rtsock.write_message(msg) + except ProcessLookupError as e: + print("Succcessfully raised {}".format(e)) + + @pytest.mark.require_user("root") + def test_rtm_multipath4_add_zero_weight(self): + """Tests RTM_ADD with dest transitioning to multipath""" + + desired_map = {} + for gw in ["192.0.2.10", "192.0.2.11", "192.0.2.13"]: + msg = self.rtsock.new_rtm_add(self.PREFIX, gw) + msg.rtm_flags = RtConst.RTF_GATEWAY + msg.rtm_rmx.rmx_weight = 0 + msg.rtm_inits |= RtConst.RTV_WEIGHT + self.rtsock.write_message(msg) + desired_map[gw] = self.rtsock.get_weight(0) + + routes = self.get_prefix_routes() + derived_map = {r["gateway"]: r["weight"] for r in routes} + assert derived_map == desired_map + + @pytest.mark.require_user("root") + def test_rtm_multipath4_getroute(self): + """Tests RTM_GET with exact prefix lookup on the multipath group""" + gws = ["192.0.2.10", "192.0.2.11", "192.0.2.13"] + return self._test_rtm_multipath_getroute(gws) + + @pytest.mark.require_user("root") + def test_rtm_multipath6_getroute(self): + """Tests RTM_GET with exact prefix lookup on the multipath group""" + gws = ["2001:db8::10", "2001:db8::11", "2001:db8::13"] + return self._test_rtm_multipath_getroute(gws) + + def _test_rtm_multipath_getroute(self, gws): + valid_gws = [] + for gw in gws: + msg = self.rtsock.new_rtm_add(self.PREFIX, gw) + msg.rtm_flags = RtConst.RTF_GATEWAY + self.rtsock.write_message(msg) + + desired_sa = { + RtConst.RTA_DST: msg.get_sa(RtConst.RTA_DST), + RtConst.RTA_NETMASK: msg.get_sa(RtConst.RTA_NETMASK), + } + valid_gws.append(msg.get_sa(RtConst.RTA_GATEWAY)) + + msg_get = RtsockRtMessage( + RtConst.RTM_GET, + self.rtsock.get_seq(), + msg.get_sa(RtConst.RTA_DST), + msg.get_sa(RtConst.RTA_NETMASK), + ) + self.rtsock.write_message(msg_get) + + data = self.rtsock.read_data(msg_get.rtm_seq) + msg_in = RtsockRtMessage.from_bytes(data) + msg_in.print_in_message() + msg_in.verify(RtConst.RTM_GET, desired_sa) + + # Additionally, check that the gateway is among the valid + # gateways + gw_found = False + gw_in = msg_in.get_sa(RtConst.RTA_GATEWAY) + for valid_gw in valid_gws: + try: + assert valid_gw == gw_in + gw_found = True + break + except AssertionError: + pass + assert gw_found is True