public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: passt-dev@passt.top, Stefano Brivio <sbrivio@redhat.com>
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH 6/7] avocado: Helper to get link-local address and wait for SLAAC to complete
Date: Thu, 20 Apr 2023 11:11:07 +1000	[thread overview]
Message-ID: <20230420011108.494181-7-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20230420011108.494181-1-david@gibson.dropbear.id.au>

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 avocado/common.py | 67 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/avocado/common.py b/avocado/common.py
index 94308b8..d859c5d 100644
--- a/avocado/common.py
+++ b/avocado/common.py
@@ -7,6 +7,7 @@
 # Copyright Red Hat
 # Author: David Gibson <david@gibson.dropbear.id.au>
 
+import ipaddress
 import json
 import os.path
 import sys
@@ -38,6 +39,11 @@ class NsTool:
     def pid(self):
         return self.pid
 
+    def relative_pid(self, relative_to):
+        cmd = '{} info -p {}'.format(NSTOOL, self.sockpath)
+        txt = relative_to.system_output(cmd)
+        return int(txt)
+
     def _xcmd(self, cmd, sudo=False):
         if sudo:
             opts = '--keep-caps'
@@ -71,6 +77,24 @@ class NsToolUnshare(NsTool):
         self.holder.stop()
 
 
+def ll_addr(x, ifname):
+    ifinfo = json.loads(x('ip -6 -j addr show {}'.format(ifname)))
+    for adinfo in ifinfo[0]['addr_info']:
+        if adinfo['scope'] != 'link':
+            continue
+        if adinfo.get('tentative') is True:
+            continue
+        return ipaddress.ip_address(adinfo['local'])
+    return None
+
+
+def slaac_wait(x, ifname):
+    addr = None
+    while addr is None:
+        addr = ll_addr(x, ifname)
+    return addr
+
+
 #
 # Tests for the test infrastructure itself
 #
@@ -144,3 +168,46 @@ class NsConnectTests(BaseTest):
     def test_connect(self):
         hostns = NsTool(self.sockpath)
         hostns.system_output('true')
+
+
+class SlaacWaitTests(BaseTest):
+    def setUp(self):
+        super().setUp()
+
+        self.ns1 = NsToolUnshare(self.workdir, 'ns1', '-Ucn')
+        self.ns2 = NsToolUnshare(self.workdir, 'ns2', '-n', parent=self.ns1)
+
+    def tearDown(self):
+        del(self.ns2)
+        del(self.ns1)
+
+        super().tearDown()
+
+    def test_slaac_wait(self, sysctls={}):
+        TESTMAC = '02:aa:bb:cc:dd:ee'
+        TESTIP = ipaddress.ip_address('fe80::aa:bbff:fecc:ddee')
+
+        self.ns1.system_output('ip link add type veth', sudo=True)
+        relpid = self.ns2.relative_pid(self.ns1)
+        self.ns1.system_output(
+            'ip link set veth1 netns {}'.format(relpid), sudo=True)
+        self.ns1.system_output(
+            'ip link set dev veth0 address {}'.format(TESTMAC), sudo=True)
+
+        for (key, val) in sysctls.items():
+            self.ns1.system_output(
+                'sysctl net.ipv6.conf.veth0.{}={}'.format(key, val), sudo=True)
+            self.ns2.system_output(
+                'sysctl net.ipv6.conf.veth1.{}={}'.format(key, val), sudo=True)
+
+        self.ns2.system_output('ip link set veth1 up', sudo=True)
+        self.ns1.system_output('ip link set veth0 up', sudo=True)
+
+        addr = slaac_wait(self.ns1.system_output, 'veth0')
+        self.assertEqual(addr, TESTIP)
+
+    def test_optimistic_dad(self):
+        self.test_slaac_wait({'optimistic_dad': 1})
+
+    def test_no_dad(self):
+        self.test_slaac_wait({'accept_dad': 0})
-- 
@@ -7,6 +7,7 @@
 # Copyright Red Hat
 # Author: David Gibson <david@gibson.dropbear.id.au>
 
+import ipaddress
 import json
 import os.path
 import sys
@@ -38,6 +39,11 @@ class NsTool:
     def pid(self):
         return self.pid
 
+    def relative_pid(self, relative_to):
+        cmd = '{} info -p {}'.format(NSTOOL, self.sockpath)
+        txt = relative_to.system_output(cmd)
+        return int(txt)
+
     def _xcmd(self, cmd, sudo=False):
         if sudo:
             opts = '--keep-caps'
@@ -71,6 +77,24 @@ class NsToolUnshare(NsTool):
         self.holder.stop()
 
 
+def ll_addr(x, ifname):
+    ifinfo = json.loads(x('ip -6 -j addr show {}'.format(ifname)))
+    for adinfo in ifinfo[0]['addr_info']:
+        if adinfo['scope'] != 'link':
+            continue
+        if adinfo.get('tentative') is True:
+            continue
+        return ipaddress.ip_address(adinfo['local'])
+    return None
+
+
+def slaac_wait(x, ifname):
+    addr = None
+    while addr is None:
+        addr = ll_addr(x, ifname)
+    return addr
+
+
 #
 # Tests for the test infrastructure itself
 #
@@ -144,3 +168,46 @@ class NsConnectTests(BaseTest):
     def test_connect(self):
         hostns = NsTool(self.sockpath)
         hostns.system_output('true')
+
+
+class SlaacWaitTests(BaseTest):
+    def setUp(self):
+        super().setUp()
+
+        self.ns1 = NsToolUnshare(self.workdir, 'ns1', '-Ucn')
+        self.ns2 = NsToolUnshare(self.workdir, 'ns2', '-n', parent=self.ns1)
+
+    def tearDown(self):
+        del(self.ns2)
+        del(self.ns1)
+
+        super().tearDown()
+
+    def test_slaac_wait(self, sysctls={}):
+        TESTMAC = '02:aa:bb:cc:dd:ee'
+        TESTIP = ipaddress.ip_address('fe80::aa:bbff:fecc:ddee')
+
+        self.ns1.system_output('ip link add type veth', sudo=True)
+        relpid = self.ns2.relative_pid(self.ns1)
+        self.ns1.system_output(
+            'ip link set veth1 netns {}'.format(relpid), sudo=True)
+        self.ns1.system_output(
+            'ip link set dev veth0 address {}'.format(TESTMAC), sudo=True)
+
+        for (key, val) in sysctls.items():
+            self.ns1.system_output(
+                'sysctl net.ipv6.conf.veth0.{}={}'.format(key, val), sudo=True)
+            self.ns2.system_output(
+                'sysctl net.ipv6.conf.veth1.{}={}'.format(key, val), sudo=True)
+
+        self.ns2.system_output('ip link set veth1 up', sudo=True)
+        self.ns1.system_output('ip link set veth0 up', sudo=True)
+
+        addr = slaac_wait(self.ns1.system_output, 'veth0')
+        self.assertEqual(addr, TESTIP)
+
+    def test_optimistic_dad(self):
+        self.test_slaac_wait({'optimistic_dad': 1})
+
+    def test_no_dad(self):
+        self.test_slaac_wait({'accept_dad': 0})
-- 
2.40.0


  parent reply	other threads:[~2023-04-20  1:11 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-20  1:11 [PATCH 0/7] RFC: Proof-of-concept conversion of some tests to Avocado framework David Gibson
2023-04-20  1:11 ` [PATCH 1/7] avocado: Make a duplicate copy of testsuite for comparison purposes David Gibson
2023-04-20  1:11 ` [PATCH 2/7] avocado: Don't double download assets for test/ and oldtest/ David Gibson
2023-04-20  1:11 ` [PATCH 3/7] avocado: Move static checkers to avocado David Gibson
2023-04-20  1:11 ` [PATCH 4/7] avocado: Convert build tests " David Gibson
2023-04-20  1:11 ` [PATCH 5/7] avocado: Helper functions and classes to run commands via nstool David Gibson
2023-04-20  1:11 ` David Gibson [this message]
2023-04-20  1:11 ` [PATCH 7/7] avocado: Convert pasta transfer tests to Avocado David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230420011108.494181-7-david@gibson.dropbear.id.au \
    --to=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    --cc=sbrivio@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).