From patchwork Wed Feb 24 04:10:56 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lucas Meneghel Rodrigues X-Patchwork-Id: 81599 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o1O4BDjB023525 for ; Wed, 24 Feb 2010 04:11:14 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755147Ab0BXELI (ORCPT ); Tue, 23 Feb 2010 23:11:08 -0500 Received: from mx1.redhat.com ([209.132.183.28]:3347 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753407Ab0BXELH (ORCPT ); Tue, 23 Feb 2010 23:11:07 -0500 Received: from int-mx08.intmail.prod.int.phx2.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o1O4B2rj008224 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 23 Feb 2010 23:11:02 -0500 Received: from localhost.localdomain (vpn-10-4.rdu.redhat.com [10.11.10.4]) by int-mx08.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o1O4Ax25011837; Tue, 23 Feb 2010 23:11:00 -0500 From: Lucas Meneghel Rodrigues To: autotest@test.kernel.org Cc: kvm@vger.kernel.org, Lucas Meneghel Rodrigues , Yogananth Subramanian Subject: [PATCH] KVM test: Add support for ipv6 addresses Date: Wed, 24 Feb 2010 01:10:56 -0300 Message-Id: <1266984656-4036-1-git-send-email-lmr@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.67 on 10.5.11.21 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 24 Feb 2010 04:11:14 +0000 (UTC) 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): """