From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from gandalf.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id E76495A0277 for ; Wed, 31 May 2023 03:59:04 +0200 (CEST) Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4QWC9S3ZY7z4x4l; Wed, 31 May 2023 11:58:52 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=201602; t=1685498332; bh=+05uMTCmQ0LGStRXubeaEKOXx28U26Chaid5Rxpw7Kc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qNr92RSsI/3n4C3wXoysRg0axKcd8IO8v3wK1ifwIHQ0N4UIa4k9KrZwc6/HtcZmU zsxvCWUVAlSPMEPjo2OyC/hKhEtZ/EuEqIgQn1WWSJQMpdFXF14q3e/TGEtCcfhefB DBFf4WBacVa+eX1GVNkYe0XkLH/saTXSE/E2oWTI= From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH v3 13/20] avocado/tasst: Add helper to wait for IP address to appear Date: Wed, 31 May 2023 11:58:42 +1000 Message-Id: <20230531015849.3229596-14-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230531015849.3229596-1-david@gibson.dropbear.id.au> References: <20230531015849.3229596-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: HSWDJC3IK2TSRSBYUETHCHXB7Z6HBVKM X-Message-ID-Hash: HSWDJC3IK2TSRSBYUETHCHXB7Z6HBVKM X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Cleber Rosa , jarichte@redhat.com, David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add a helper to the Site() class to wait for an address with specified characteristics to be ready on an interface. In particular this is useful for waiting for IPv6 SLAAC & DAD (Duplicate Address Detection) to complete. Because DAD is not going to be useful in many of our scenarios, also extend Site.ifup() to allow DAD to be switched to optimistic mode or disabled. Signed-off-by: David Gibson --- avocado/tasst/meta/static_ifup.py | 46 +++++++++++++++++++++++++++++++ avocado/tasst/meta/veth.py | 20 ++++++++++++++ avocado/tasst/site.py | 22 ++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 avocado/tasst/meta/static_ifup.py diff --git a/avocado/tasst/meta/static_ifup.py b/avocado/tasst/meta/static_ifup.py new file mode 100644 index 0000000..eba8fef --- /dev/null +++ b/avocado/tasst/meta/static_ifup.py @@ -0,0 +1,46 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/metatest/static_ifup - Static address configuration +# +# These test code from tasst.site, but require additional support from +# tasst.nstool. +# +# Copyright Red Hat +# Author: David Gibson + +import contextlib +import ipaddress + +import avocado + +from tasst import Tasst +from tasst.nstool import UnshareSite + + +class StaticNetTasst(Tasst): + """ + Test helpers for static network configuration + + :avocado: tags=meta + """ + + IFNAME = 'testveth' + TEST_IPS = [ipaddress.ip_interface('192.0.2.1/24'), + ipaddress.ip_interface('2001:db8:9a55::1/112'), + ipaddress.ip_interface('10.1.2.3/8')] + + @contextlib.contextmanager + def setup_ns(self): + with UnshareSite(type(self).__name__, '-Un') as ns: + ns.veth(self.IFNAME, self.IFNAME + 'peer') + ns.ifup(self.IFNAME, *self.TEST_IPS, dad='disable') + yield ns + + def test_addr(self): + with self.setup_ns() as ns: + self.assertCountEqual(ns.addrs(self.IFNAME, scope='global'), self.TEST_IPS) diff --git a/avocado/tasst/meta/veth.py b/avocado/tasst/meta/veth.py index 301ccb9..4dfb15a 100644 --- a/avocado/tasst/meta/veth.py +++ b/avocado/tasst/meta/veth.py @@ -14,6 +14,7 @@ # Author: David Gibson import contextlib +import ipaddress import avocado @@ -46,3 +47,22 @@ class VethTasst(Tasst): with self.setup_veth() as (ns1, ns2): self.assertEquals(ns1.mtu('veth1'), 1500) self.assertEquals(ns2.mtu('veth2'), 1500) + + def test_slaac(self, dad=None): + TESTMAC = '02:aa:bb:cc:dd:ee' + TESTIP = ipaddress.ip_interface('fe80::aa:bbff:fecc:ddee/64') + + with self.setup_veth() as (ns1, ns2): + ns1.fg('ip link set dev veth1 address {}'.format(TESTMAC), sudo=True) + + ns1.ifup('veth1', dad=dad) + ns2.ifup('veth2') + + addrs = ns1.addr_wait('veth1', family='inet6', scope='link') + self.assertEqual(addrs, [TESTIP]) + + def test_optimistic_dad(self): + self.test_slaac(dad='optimistic') + + def test_no_dad(self): + self.test_slaac(dad='disable') diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py index f19a3fc..f064a22 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -57,8 +57,22 @@ class Site(contextlib.AbstractContextManager): info = json.loads(self.output('ip -j link show')) return [i['ifname'] for i in info] - def ifup(self, ifname): + def ifup(self, ifname, *addrs, dad=None): self.require_cmds('ip') + + if dad == 'disable': + self.fg('sysctl net.ipv6.conf.{}.accept_dad=0'.format(ifname), sudo=True) + elif dad == 'optimistic': + self.fg('sysctl net.ipv6.conf.{}.optimistic_dad=1'.format(ifname), sudo=True) + elif dad is not None: + raise ValueError + + for a in addrs: + if (not isinstance(a, ipaddress.IPv4Interface) + and not isinstance(a, ipaddress.IPv6Interface)): + raise TypeError + self.fg('ip addr add {} dev {}'.format(a.with_prefixlen, ifname), sudo=True) + self.fg('ip link set {} up'.format(ifname), sudo=True) def mtu(self, ifname): @@ -84,6 +98,12 @@ class Site(contextlib.AbstractContextManager): for ai in self.addrinfos(ifname, **filter) if not 'tentative' in ai] + def addr_wait(self, ifname, **filter): + while True: + addrs = self.addrs(ifname, **filter) + if addrs: + return addrs + class SiteTasst(Tasst): """ -- 2.40.1