Hello everyone,

I like to submit a patch to enable 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

I will be happy to re-implement or modify the patch based to your
comments.

Thanks 
yogi 

Signed-off-by: Yogananth Subramanian <anant...@in.ibm.com>
---
 kvm_preprocessing.py |   27 ++++++++++++++++++++++++++-
 kvm_utils.py         |   28 ++++++++++++++++++++++++++++
 kvm_vm.py            |   49 ++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 100 insertions(+), 4 deletions(-)

diff -aurpN autotest/client/tests/kvm/kvm_preprocessing.py 
autotest-new/client/tests/kvm/kvm_preprocessing.py
--- autotest/client/tests/kvm/kvm_preprocessing.py      2009-12-14 
09:20:56.000000000 +0000
+++ autotest-new/client/tests/kvm/kvm_preprocessing.py  2009-12-14 
09:47:34.000000000 +0000
@@ -51,7 +51,8 @@ def preprocess_vm(test, params, env, nam
         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
@@ -200,6 +201,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")
@@ -317,6 +326,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,3 +354,17 @@ def _update_address_cache(address_cache,
                           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) 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 -aurpN autotest/client/tests/kvm/kvm_utils.py 
autotest-new/client/tests/kvm/kvm_utils.py
--- autotest/client/tests/kvm/kvm_utils.py      2009-12-14 09:20:56.000000000 
+0000
+++ autotest-new/client/tests/kvm/kvm_utils.py  2009-12-14 09:45:58.000000000 
+0000
@@ -208,6 +208,34 @@ def verify_ip_address_ownership(ip, macs
     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 -aurpN autotest/client/tests/kvm/kvm_vm.py 
autotest-new/client/tests/kvm/kvm_vm.py
--- autotest/client/tests/kvm/kvm_vm.py 2009-12-14 09:20:56.000000000 +0000
+++ autotest-new/client/tests/kvm/kvm_vm.py     2009-12-14 09:49:45.000000000 
+0000
@@ -100,7 +100,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.
 
@@ -109,6 +109,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 = {}
@@ -119,6 +120,7 @@ class VM:
         self.params = params
         self.root_dir = root_dir
         self.address_cache = address_cache
+        self.address6_cache = address6_cache
 
         # Find available monitor filename
         while True:
@@ -131,7 +133,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().
@@ -142,6 +145,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
@@ -151,7 +155,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):
@@ -658,6 +664,43 @@ class VM:
                     logging.debug("Could not verify MAC-IP address mapping: "
                                   "%s ---> %s" % (mac, ip))
                     return None
+            return ip
+        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"
--


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to