@@ -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"]
@@ -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)
@@ -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"