All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lucas Meneghel Rodrigues <lmr@redhat.com>
To: autotest@test.kernel.org
Cc: Yogananth Subramanian <anantyog@in.ibm.com>, kvm@vger.kernel.org
Subject: [PATCH] KVM test: Add support for ipv6 addresses
Date: Wed, 24 Feb 2010 01:10:56 -0300	[thread overview]
Message-ID: <1266984656-4036-1-git-send-email-lmr@redhat.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 768 bytes --]


This patch enables ipv6 address support in kvm-autotest.
The patch adds a new dictionary called "address6_cache" for ip6 address.
Tcpdump is used to create this cache of link-local ipv6 address.

Link-local ipv6 address is used because it eliminates to need to create
complex configuration on both the host and the guest.

The ipv6 address for a guest can be obtained by using the new function
get_address6 in kvm_vm.py

Signed-off-by: Yogananth Subramanian <anantyog@in.ibm.com>
---
 client/tests/kvm/kvm_preprocessing.py |   29 ++++++++++++++++++-
 client/tests/kvm/kvm_utils.py         |   28 +++++++++++++++++++
 client/tests/kvm/kvm_vm.py            |   49 +++++++++++++++++++++++++++++++--
 3 files changed, 101 insertions(+), 5 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-KVM-test-Add-support-for-ipv6-addresses.patch --]
[-- Type: text/x-patch; name="0001-KVM-test-Add-support-for-ipv6-addresses.patch", Size: 8891 bytes --]

diff --git a/client/tests/kvm/kvm_preprocessing.py b/client/tests/kvm/kvm_preprocessing.py
index e91d1da..4ea13b2 100644
--- a/client/tests/kvm/kvm_preprocessing.py
+++ b/client/tests/kvm/kvm_preprocessing.py
@@ -51,7 +51,8 @@ def preprocess_vm(test, params, env, name):
         logging.debug("VM object found in environment")
     else:
         logging.debug("VM object does not exist; creating it")
-        vm = kvm_vm.VM(name, params, test.bindir, env.get("address_cache"))
+        vm = kvm_vm.VM(name, params, test.bindir, env.get("address_cache"),
+                       env.get("address6_cache"))
         kvm_utils.env_register_vm(env, name, vm)
 
     start_vm = False
@@ -199,6 +200,14 @@ def preprocess(test, params, env):
             command=command,
             output_func=_update_address_cache,
             output_params=(env["address_cache"],))
+
+        env["address6_cache"] = {}
+        command6 = "/usr/sbin/tcpdump -npv ip6 -i any 'dst net ff02::2'"
+        env["tcpdump6"] = kvm_subprocess.kvm_tail(
+            command=command6,
+            output_func=_update_address6_cache,
+            output_params=(env["address6_cache"],))
+
         if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(),
                               0.1, 0.1, 1.0):
             logging.warn("Could not start tcpdump")
@@ -321,6 +330,8 @@ def postprocess(test, params, env):
     if not living_vms and env.has_key("tcpdump"):
         env["tcpdump"].close()
         del env["tcpdump"]
+        env["tcpdump6"].close()
+        del env["tcpdump6"]
 
 
 def postprocess_on_error(test, params, env):
@@ -343,7 +354,21 @@ def _update_address_cache(address_cache, line):
         matches = re.findall(r"\w*:\w*:\w*:\w*:\w*:\w*", line)
         if matches and address_cache.get("last_seen"):
             mac_address = matches[0].lower()
-            logging.debug("(address cache) Adding cache entry: %s ---> %s",
+            logging.debug("(address cache ipv4) Adding cache entry: %s ---> %s",
                           mac_address, address_cache.get("last_seen"))
             address_cache[mac_address] = address_cache.get("last_seen")
             del address_cache["last_seen"]
+
+def _update_address6_cache(address6_cache, line):
+    if re.search("ff02::2:", line, re.IGNORECASE):
+        matches = re.findall(r"(fe80.+) >", line)
+        if matches:
+            address6_cache["last_seen"] = matches[0]
+    if re.search("source link-address option", line, re.IGNORECASE):
+        matches = re.findall(r"\w*:\w*:\w*:\w*:\w*:\w*", line)
+        if matches and address6_cache.get("last_seen"):
+            mac_address = matches[0].lower()
+            logging.debug("(address cache ipv6) Adding cache entry: %s ---> %s",
+                          mac_address, address6_cache.get("last_seen"))
+            address6_cache[mac_address] = address6_cache.get("last_seen")
+            del address6_cache["last_seen"]
diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py
index 4565dc1..a574520 100644
--- a/client/tests/kvm/kvm_utils.py
+++ b/client/tests/kvm/kvm_utils.py
@@ -208,6 +208,34 @@ def verify_ip_address_ownership(ip, macs, timeout=10.0):
     o = commands.getoutput("/sbin/arping -f -c 3 -I %s %s" % (dev, ip))
     return bool(regex.search(o))
 
+def verify_ip6_address_ownership(ip, macs, timeout=10.0):
+    """
+    Use ping6 and the ND cache to make sure a given IP address belongs to one
+    of the given MAC addresses.
+
+    @param ip: An IP6 address.
+    @param macs: A list or tuple of MAC addresses.
+    @return: True iff ip is assigned to a MAC address in macs.
+    """
+    # Compile a regex that matches the given IP6 address and any of the given
+    # MAC addresses
+    mac_regex = "|".join("(%s)" % mac for mac in macs)
+    regex = re.compile(r"\b%s\b.*\b(%s)\b" % (ip, mac_regex), re.IGNORECASE)
+
+    # Get the name of the bridge device for ping6
+    o = commands.getoutput("/sbin/ip route get ff02::1" )
+    dev = re.findall("dev\s+\S+", o, re.IGNORECASE)
+    if not dev:
+        return False
+    dev = dev[0].split()[-1]
+
+    if bool(commands.getstatusoutput("/bin/ping6 -c 11 -I %s %s"% (dev, ip)[0])):
+        return False
+
+    # Check the ND cache
+    o = commands.getoutput("/sbin/ip -6 neigh show")
+    if regex.search(o):
+        return True
 
 # Functions for working with the environment (a dict-like object)
 
diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index 921414d..76babd4 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -95,7 +95,7 @@ class VM:
     This class handles all basic VM operations.
     """
 
-    def __init__(self, name, params, root_dir, address_cache):
+    def __init__(self, name, params, root_dir, address_cache, address6_cache):
         """
         Initialize the object and set a few attributes.
 
@@ -104,6 +104,7 @@ class VM:
                 (see method make_qemu_command for a full description)
         @param root_dir: Base directory for relative filenames
         @param address_cache: A dict that maps MAC addresses to IP addresses
+        @param address_cache: A dict that maps MAC addresses to IP6 addresses
         """
         self.process = None
         self.redirs = {}
@@ -114,6 +115,7 @@ class VM:
         self.params = params
         self.root_dir = root_dir
         self.address_cache = address_cache
+        self.address6_cache = address6_cache
         self.pci_assignable = None
 
         # Find available monitor filename
@@ -127,7 +129,8 @@ class VM:
                 break
 
 
-    def clone(self, name=None, params=None, root_dir=None, address_cache=None):
+    def clone(self, name=None, params=None, root_dir=None, address_cache=None,
+              address6_cache=None):
         """
         Return a clone of the VM object with optionally modified parameters.
         The clone is initially not alive and needs to be started using create().
@@ -138,6 +141,7 @@ class VM:
         @param params: Optional new VM creation parameters
         @param root_dir: Optional new base directory for relative filenames
         @param address_cache: A dict that maps MAC addresses to IP addresses
+        @param address_cache: A dict that maps MAC addresses to IP6 addresses
         """
         if name is None:
             name = self.name
@@ -147,7 +151,9 @@ class VM:
             root_dir = self.root_dir
         if address_cache is None:
             address_cache = self.address_cache
-        return VM(name, params, root_dir, address_cache)
+        if address6_cache is None:
+            address6_cache = self.address6_cache
+        return VM(name, params, root_dir, address_cache, address6_cache)
 
 
     def make_qemu_command(self, name=None, params=None, root_dir=None):
@@ -720,6 +726,43 @@ class VM:
         else:
             return "localhost"
 
+    def get_address6(self, index=0):
+        """
+        Return the address of a NIC of the guest, in host space.
+
+        If port redirection is used, return 'localhost' (the NIC has no IP
+        address of its own).  Otherwise return the NIC's IP6 address.
+
+        @param index: Index of the NIC whose address is requested.
+        """
+        nics = kvm_utils.get_sub_dict_names(self.params, "nics")
+        nic_name = nics[index]
+        nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
+        if nic_params.get("nic_mode") == "tap":
+            mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
+            if not mac:
+                logging.debug("MAC address unavailable")
+                return None
+            if not ip or nic_params.get("always_use_tcpdump") == "yes":
+                # Get the IP6 address from the cache
+                ip = self.address6_cache.get(mac)
+                if not ip:
+                    logging.debug("Could not find IP address for MAC address: "
+                                  "%s" % mac)
+                    return None
+                # Make sure the IP6 address is assigned to this guest
+                nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
+                             for nic in nics]
+                macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
+                        for dict in nic_dicts]
+                if not kvm_utils.verify_ip6_address_ownership(ip, macs):
+                    logging.debug("Could not verify MAC-IP address mapping: "
+                                  "%s ---> %s" % (mac, ip))
+                    return None
+            return ip
+        else:
+            return "localhost"
+
 
     def get_port(self, port, nic_index=0):
         """

[-- Attachment #3: Type: text/plain, Size: 152 bytes --]

_______________________________________________
Autotest mailing list
Autotest@test.kernel.org
http://test.kernel.org/cgi-bin/mailman/listinfo/autotest

             reply	other threads:[~2010-02-24  4:10 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-02-24  4:10 Lucas Meneghel Rodrigues [this message]
2010-02-24  4:16 ` [Autotest] [PATCH] KVM test: Add support for ipv6 addresses Lucas Meneghel Rodrigues
2010-02-25 13:41   ` yogi
2010-02-25 20:09     ` Lucas Meneghel Rodrigues
2010-03-02 15:02       ` yogi

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=1266984656-4036-1-git-send-email-lmr@redhat.com \
    --to=lmr@redhat.com \
    --cc=anantyog@in.ibm.com \
    --cc=autotest@test.kernel.org \
    --cc=kvm@vger.kernel.org \
    /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.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.