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 DAB415A0291 for ; Tue, 16 May 2023 04:01:49 +0200 (CEST) Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4QKzxd4BtNz4y1m; Tue, 16 May 2023 12:01:41 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=201602; t=1684202501; bh=XsptuVDCai9rr2mk7Y0uJXMYm9X9u5FE1Xmn65Rn5pc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LN3niT2lxPkr2QP0J5NfhDb4tvxePGrPhhD4QSqKMt0cBA9SYqn0ZJR4z4UJhtIIY mNyOTEC1cx0jtKr1qYjNWUhvNVBPDoSZOBshA6HcXC0McHp56mMEouud3KI+lbI+F3 W1tDdOb82HnogFVTca1wN9cWVoHnteuFSdiAwT5E= From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH v2 19/21] avocado/tasst: Helpers for testing DHCP & DHCPv6 behaviour Date: Tue, 16 May 2023 12:01:33 +1000 Message-Id: <20230516020135.1901256-20-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230516020135.1901256-1-david@gibson.dropbear.id.au> References: <20230516020135.1901256-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: GVRM34IG6E4B5HIGHIU2B53DFSBWKIFI X-Message-ID-Hash: GVRM34IG6E4B5HIGHIU2B53DFSBWKIFI 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: jarichte@redhat.com, Cleber Rosa , 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: Signed-off-by: David Gibson --- avocado/tasst/dhcp.py | 133 ++++++++++++++++++++++++++++++++++++++++ avocado/tasst/dhcpv6.py | 123 +++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 avocado/tasst/dhcp.py create mode 100644 avocado/tasst/dhcpv6.py diff --git a/avocado/tasst/dhcp.py b/avocado/tasst/dhcp.py new file mode 100644 index 0000000..071fc20 --- /dev/null +++ b/avocado/tasst/dhcp.py @@ -0,0 +1,133 @@ +#! /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/dhcp.py - Helpers for testing DHCP +# +# Copyright Red Hat +# Author: David Gibson + +import ipaddress +import os + +from tasst import Tasst, TasstSubData +from tasst.address import IpiAllocator, TEST_NET_1 +from tasst.nstool import UnshareSite + + +class BaseDhcpTasst(Tasst): + """ + Test DHCP behaviour. + + :avocado: disable + """ + + DHCLIENT = '/sbin/dhclient' + + def subsetup(self, site, ifname, addr, gw, mtu): + site.require_cmds(self.DHCLIENT) + + pidfile = os.path.join(self.workdir, 'dhclient.pid') + leasefile = os.path.join(self.workdir, 'dhclient.leases') + + # We need '-nc' because we may be running with capabilities + # but not UID 0. Without -nc dhclient drops capabilities + # before invoking dhclient-script, so it's unable to actually + # configure the interface + site.fg('{} -4 -v -nc -pf {} -lf {} {}' + .format(self.DHCLIENT, pidfile, leasefile, ifname), sudo=True) + + Tasst.subsetup(self, BaseDhcpTasst, + TasstSubData(site=site, ifname=ifname, addr=addr, gw=gw, mtu=mtu)) + + def test_addr(self): + sub = self.get_subsetup(BaseDhcpTasst) + (addr,) = sub.site.addrs(sub.ifname, family='inet', scope='global') + self.assertEquals(addr.ip, sub.addr) + + def test_route(self): + sub = self.get_subsetup(BaseDhcpTasst) + (defroute,) = sub.site.routes4(dst='default') + self.assertEquals(ipaddress.ip_address(defroute['gateway']), sub.gw) + + def test_mtu(self): + sub = self.get_subsetup(BaseDhcpTasst) + self.assertEquals(sub.site.mtu(sub.ifname), sub.mtu) + + +class MetaDhcpTasst(BaseDhcpTasst): + """Ugly workaround for + https://github.com/avocado-framework/avocado/issues/5680. + Explicitly apply the "meta" tag to inherited tests + + :avocado: disable + :avocado: tags=meta + + """ + + def test_addr(self): + super().test_addr() + + def test_route(self): + super().test_route() + + def test_mtu(self): + super().test_mtu() + + +class DhcpdTasst(MetaDhcpTasst): + DHCPD = 'dhcpd' + SUBNET = TEST_NET_1 + + def setUp(self): + super().setUp() + + ifname = 'clientif' + server_ifname = 'serverif' + + self.client = UnshareSite(self.__class__.__name__ + '.client', '-Un') + self.server = UnshareSite(self.__class__.__name__ + '.server', '-n', + parent=self.client, sudo=True) + + self.server.require_cmds(self.DHCPD) + + self.client.veth(ifname, server_ifname, self.server) + + # Configure the DHCP server + ipa = IpiAllocator(self.SUBNET) + (server_ip4,) = ipa.next_ipis() + (client_ip4,) = ipa.next_ipis() + + confpath = os.path.join(self.workdir, 'dhcpd.conf') + open(confpath, 'w').write(''' + subnet {} netmask {} {{ + option routers {}; + range {} {}; + }} + '''.format(self.SUBNET.network_address, self.SUBNET.netmask, + server_ip4.ip, client_ip4.ip, client_ip4.ip)) + self.pidpath = os.path.join(self.workdir, 'dhcpd.pid') + leasepath = os.path.join(self.workdir, 'dhcpd.leases') + open(leasepath, 'w').write('') + + self.server.ifup('lo') + self.server.ifup(server_ifname, server_ip4) + + opts = ('-f -d -4 -cf {} -lf {} -pf {}'.format(confpath, leasepath, self.pidpath)) + self.server.fg('{} -t {}'.format(self.DHCPD, opts)) # test config + self.dhcpd = self.server.bg('{} {}'.format(self.DHCPD, opts), sudo=True) + + # Configure the client + self.client.ifup('lo') + BaseDhcpTasst.subsetup(self, self.client, ifname, client_ip4.ip, server_ip4.ip, 1500) + + def tearDown(self): + pid = int(open(self.pidpath).read()) + self.server.fg('kill {}'.format(pid)) + status = self.dhcpd.wait() + self.server.close() + self.client.close() + super().tearDown() diff --git a/avocado/tasst/dhcpv6.py b/avocado/tasst/dhcpv6.py new file mode 100644 index 0000000..e885c06 --- /dev/null +++ b/avocado/tasst/dhcpv6.py @@ -0,0 +1,123 @@ +#! /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/dhcpv6.py - Helpers for testing DHCPv6 +# +# Copyright Red Hat +# Author: David Gibson + +import ipaddress +import os + +from tasst import Tasst, TasstSubData +from tasst.address import IpiAllocator, TEST_NET6_TASST_A +from tasst.nstool import UnshareSite + + +class BaseDhcpv6Tasst(Tasst): + """ + Test DHCPv6 behaviour. + + :avocado: disable + """ + + DHCLIENT = '/sbin/dhclient' + + def subsetup(self, site, ifname, addr): + site.require_cmds(self.DHCLIENT) + + pidfile = os.path.join(self.workdir, 'dhclient.pid') + leasefile = os.path.join(self.workdir, 'dhclient.leases') + + # We need '-nc' because we may be running with capabilities + # but not UID 0. Without -nc dhclient drops capabilities + # before invoking dhclient-script, so it's unable to actually + # configure the interface + site.fg('{} -6 -v -nc -pf {} -lf {} {}' + .format(self.DHCLIENT, pidfile, leasefile, ifname), sudo=True) + + Tasst.subsetup(self, BaseDhcpv6Tasst, + TasstSubData(site=site, ifname=ifname, addr=addr)) + + def test_addr(self): + sub = self.get_subsetup(BaseDhcpv6Tasst) + addrs = [a.ip for a in sub.site.addrs(sub.ifname, family='inet6', scope='global')] + self.assertIn(sub.addr, addrs) # Might also have a SLAAC address + + +class MetaDhcpv6Tasst(BaseDhcpv6Tasst): + """Ugly workaround for + https://github.com/avocado-framework/avocado/issues/5680. + Explicitly apply the "meta" tag to inherited tests + + :avocado: disable + :avocado: tags=meta + + """ + + def test_addr(self): + super().test_addr() + + +class Dhcpd6Tasst(MetaDhcpv6Tasst): + """ + :avocado: tags=meta + """ + + DHCPD = 'dhcpd' + SUBNET = TEST_NET6_TASST_A + + def setUp(self): + super().setUp() + + ifname = 'clientif' + server_ifname = 'serverif' + + self.client = UnshareSite(self.__class__.__name__ + '.client', '-Un') + self.server = UnshareSite(self.__class__.__name__ + '.server', '-n', + parent=self.client, sudo=True) + + self.server.require_cmds(self.DHCPD) + + self.client.veth(ifname, server_ifname, self.server) + + # Allocate IPs, and sort out link local addressing + ipa = IpiAllocator(self.SUBNET) + (server_ip6,) = ipa.next_ipis() + (client_ip6,) = ipa.next_ipis() + + self.server.ifup('lo') + self.server.ifup(server_ifname, server_ip6) + self.client.ifup('lo') + self.client.ifup(ifname) + (server_ip6_ll,) = self.server.addr_wait(server_ifname, family='inet6', scope='link') + + # Configure the DHCP server + confpath = os.path.join(self.workdir, 'dhcpd.conf') + open(confpath, 'w').write(''' + subnet6 {} {{ + range6 {} {}; + }} + '''.format(self.SUBNET, client_ip6.ip, client_ip6.ip)) + self.pidpath = os.path.join(self.workdir, 'dhcpd.pid') + leasepath = os.path.join(self.workdir, 'dhcpd.leases') + open(leasepath, 'w').write('') + + opts = ('-f -d -6 -cf {} -lf {} -pf {}'.format(confpath, leasepath, self.pidpath)) + self.server.fg('{} -t {}'.format(self.DHCPD, opts)) # test config + self.dhcpd = self.server.bg('{} {}'.format(self.DHCPD, opts), sudo=True) + + # Configure the client + BaseDhcpv6Tasst.subsetup(self, self.client, ifname, client_ip6.ip) + + def tearDown(self): + pid = int(open(self.pidpath).read()) + self.server.fg('kill {}'.format(pid)) + status = self.dhcpd.wait() + self.server.close() + self.client.close() + super().tearDown() -- 2.40.1