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 <david(a)gibson.dropbear.id.au> --- avocado/tasst/meta/static_ifup.py | 47 +++++++++++++++++++++++++++++++ avocado/tasst/meta/veth.py | 20 +++++++++++++ avocado/tasst/site.py | 22 ++++++++++++++- 3 files changed, 88 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..02d9650 --- /dev/null +++ b/avocado/tasst/meta/static_ifup.py @@ -0,0 +1,47 @@ +#! /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 <david(a)gibson.dropbear.id.au> + +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')] + + def setUp(self): + super().setUp() + self.ns = UnshareSite(type(self).__name__, '-Un') + self.ns.veth(self.IFNAME, self.IFNAME + 'peer') + self.ns.ifup(self.IFNAME, *self.TEST_IPS, dad='disable') + + def tearDown(self): + self.ns.close() + super().tearDown() + + def test_addr(self): + self.assertCountEqual(self.ns.addrs(self.IFNAME, scope='global'), self.TEST_IPS) diff --git a/avocado/tasst/meta/veth.py b/avocado/tasst/meta/veth.py index afca192..362252b 100644 --- a/avocado/tasst/meta/veth.py +++ b/avocado/tasst/meta/veth.py @@ -13,6 +13,8 @@ # Copyright Red Hat # Author: David Gibson <david(a)gibson.dropbear.id.au> +import ipaddress + import avocado from tasst import Tasst @@ -45,3 +47,21 @@ class VethTasst(Tasst): def test_mtu(self): self.assertEquals(self.ns1.mtu('veth1'), 1500) self.assertEquals(self.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') + + self.ns1.fg('ip link set dev veth1 address {}'.format(TESTMAC), sudo=True) + + self.ns1.ifup('veth1', dad=dad) + self.ns2.ifup('veth2') + + addrs = self.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 00b86aa..3197839 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -60,8 +60,22 @@ class Site: 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): @@ -87,6 +101,12 @@ class Site: 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 BaseSiteTasst(Tasst): """ -- 2.40.1