diff mbox

KVM test: Add support for ipv6 addresses

Message ID 1266984656-4036-1-git-send-email-lmr@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lucas Meneghel Rodrigues Feb. 24, 2010, 4:10 a.m. UTC
None
diff mbox

Patch

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):
         """