From patchwork Sun Aug 2 23:58:11 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Goldish X-Patchwork-Id: 38806 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n72NshNN009526 for ; Sun, 2 Aug 2009 23:54:43 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753777AbZHBXyj (ORCPT ); Sun, 2 Aug 2009 19:54:39 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753815AbZHBXyj (ORCPT ); Sun, 2 Aug 2009 19:54:39 -0400 Received: from mx2.redhat.com ([66.187.237.31]:37201 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753687AbZHBXyi (ORCPT ); Sun, 2 Aug 2009 19:54:38 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n72Nruwt016612; Sun, 2 Aug 2009 19:54:06 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n72NriuY022142; Sun, 2 Aug 2009 19:53:45 -0400 Received: from localhost.localdomain (dhcp-1-188.tlv.redhat.com [10.35.1.188]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n72Nre6I017975; Sun, 2 Aug 2009 19:53:43 -0400 From: Michael Goldish To: autotest@test.kernel.org, kvm@vger.kernel.org Cc: Michael Goldish Subject: [KVM-AUTOTEST PATCH 02/12] KVM test: add basic TAP support with static MAC-IP mapping Date: Mon, 3 Aug 2009 02:58:11 +0300 Message-Id: <9ec0626f3ca8c20d08cfd2448dbf249632ed969a.1249257056.git.mgoldish@redhat.com> In-Reply-To: <7845d2fd228ec0232af10e48dbb29e1076a265d6.1249257056.git.mgoldish@redhat.com> References: <1249257501-19337-1-git-send-email-mgoldish@redhat.com> <7845d2fd228ec0232af10e48dbb29e1076a265d6.1249257056.git.mgoldish@redhat.com> In-Reply-To: <7845d2fd228ec0232af10e48dbb29e1076a265d6.1249257056.git.mgoldish@redhat.com> References: <7845d2fd228ec0232af10e48dbb29e1076a265d6.1249257056.git.mgoldish@redhat.com> X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The network mode is specified by a NIC parameter named 'nic_mode'. Currently two modes are supported: 'tap' and 'user'. Other NIC parameters are now handled: nic_script, nic_downscript and nic_ifname. nic_ifname should usually not be specified (qemu chooses one automatically). nic_script and nic_downscript may specify a relative path, e.g. 'qemu-ifup', which refers to a file in the KVM test local dir, or an absolute path, e.g. '/etc/qemu-ifup'. This patch mainly modifies VM.get_address(), VM.get_port() and VM.make_qemu_command(), and adds a 'script_dir' parameter to several VM routines. 'script_dir' should normally be the KVM test local dir. Signed-off-by: Michael Goldish --- client/tests/kvm/kvm_preprocessing.py | 8 ++- client/tests/kvm/kvm_tests.cfg.sample | 6 ++ client/tests/kvm/kvm_vm.py | 95 +++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 30 deletions(-) diff --git a/client/tests/kvm/kvm_preprocessing.py b/client/tests/kvm/kvm_preprocessing.py index d118826..4d77630 100644 --- a/client/tests/kvm/kvm_preprocessing.py +++ b/client/tests/kvm/kvm_preprocessing.py @@ -46,6 +46,7 @@ def preprocess_vm(test, params, env, name): qemu_path = os.path.join(test.bindir, "qemu") image_dir = os.path.join(test.bindir, "images") iso_dir = os.path.join(test.bindir, "isos") + script_dir = test.bindir logging.debug("Preprocessing VM '%s'..." % name) vm = kvm_utils.env_get_vm(env, name) @@ -53,7 +54,7 @@ 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, qemu_path, image_dir, iso_dir) + vm = kvm_vm.VM(name, params, qemu_path, image_dir, iso_dir, script_dir) kvm_utils.env_register_vm(env, name, vm) start_vm = False @@ -74,14 +75,15 @@ def preprocess_vm(test, params, env, name): elif vm.make_qemu_command() != vm.make_qemu_command(name, params, qemu_path, image_dir, - iso_dir): + iso_dir, + script_dir): logging.debug("VM's qemu command differs from requested one; " "restarting it...") start_vm = True if start_vm: if not vm.create(name, params, qemu_path, image_dir, iso_dir, - for_migration): + script_dir, for_migration): message = "Could not start VM" logging.error(message) raise error.TestError(message) diff --git a/client/tests/kvm/kvm_tests.cfg.sample b/client/tests/kvm/kvm_tests.cfg.sample index 7cd12cb..4b9d7eb 100644 --- a/client/tests/kvm/kvm_tests.cfg.sample +++ b/client/tests/kvm/kvm_tests.cfg.sample @@ -24,6 +24,12 @@ display = vnc redirs = ssh guest_port_ssh = 22 +# NIC parameters +nic_mode = tap +#nic_mode = user +nic_script = qemu-ifup +address_index = 0 + # Tests variants: diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py index eba9b84..0c35e64 100644 --- a/client/tests/kvm/kvm_vm.py +++ b/client/tests/kvm/kvm_vm.py @@ -100,7 +100,8 @@ class VM: This class handles all basic VM operations. """ - def __init__(self, name, params, qemu_path, image_dir, iso_dir): + def __init__(self, name, params, qemu_path, image_dir, iso_dir, + script_dir): """ Initialize the object and set a few attributes. @@ -110,6 +111,7 @@ class VM: @param qemu_path: The path of the qemu binary @param image_dir: The directory where images reside @param iso_dir: The directory where ISOs reside + @param script_dir: The directory where -net tap scripts reside """ self.process = None self.redirs = {} @@ -121,7 +123,7 @@ class VM: self.qemu_path = qemu_path self.image_dir = image_dir self.iso_dir = iso_dir - + self.script_dir = script_dir # Find available monitor filename while True: @@ -135,7 +137,7 @@ class VM: def clone(self, name=None, params=None, qemu_path=None, image_dir=None, - iso_dir=None): + iso_dir=None, script_dir=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(). @@ -147,6 +149,7 @@ class VM: @param qemu_path: Optional new path to qemu @param image_dir: Optional new image dir @param iso_dir: Optional new iso directory + @param script_dir: Optional new -net tap script directory """ if name == None: name = self.name @@ -158,23 +161,24 @@ class VM: image_dir = self.image_dir if iso_dir == None: iso_dir = self.iso_dir - return VM(name, params, qemu_path, image_dir, iso_dir) + if script_dir == None: + script_dir = self.script_dir + return VM(name, params, qemu_path, image_dir, iso_dir, script_dir) def make_qemu_command(self, name=None, params=None, qemu_path=None, - image_dir=None, iso_dir=None): + image_dir=None, iso_dir=None, script_dir=None): """ Generate a qemu command line. All parameters are optional. If a parameter is not supplied, the corresponding value stored in the class attributes is used. - @param name: The name of the object @param params: A dict containing VM params @param qemu_path: The path of the qemu binary @param image_dir: The directory where images reside @param iso_dir: The directory where ISOs reside - + @param script_dir: The directory where -net tap scripts reside @note: The params dict should contain: mem -- memory size in MBs @@ -210,6 +214,8 @@ class VM: image_dir = self.image_dir if iso_dir == None: iso_dir = self.iso_dir + if script_dir == None: + script_dir = self.script_dir # Start constructing the qemu command qemu_cmd = "" @@ -241,10 +247,30 @@ class VM: vlan = 0 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"): nic_params = kvm_utils.get_sub_dict(params, nic_name) + # Handle the '-net nic' part qemu_cmd += " -net nic,vlan=%d" % vlan if nic_params.get("nic_model"): qemu_cmd += ",model=%s" % nic_params.get("nic_model") - qemu_cmd += " -net user,vlan=%d" % vlan + if nic_params.has_key("address_index"): + mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params) + qemu_cmd += ",macaddr=%s" % mac + # Handle the '-net tap' or '-net user' part + mode = nic_params.get("nic_mode", "user") + qemu_cmd += " -net %s,vlan=%d" % (mode, vlan) + if mode == "tap": + if nic_params.get("nic_ifname"): + qemu_cmd += ",ifname=%s" % nic_params.get("nic_ifname") + if nic_params.get("nic_script"): + script_path = nic_params.get("nic_script") + if not os.path.isabs(script_path): + script_path = os.path.join(script_dir, script_path) + qemu_cmd += ",script=%s" % script_path + if nic_params.get("nic_downscript"): + script_path = nic_params.get("nic_downscript") + if not os.path.isabs(script_path): + script_path = os.path.join(script_dir, script_path) + qemu_cmd += ",downscript=%s" % script_path + # Proceed to next NIC vlan += 1 mem = params.get("mem") @@ -263,7 +289,7 @@ class VM: for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"): redir_params = kvm_utils.get_sub_dict(params, redir_name) guest_port = int(redir_params.get("guest_port")) - host_port = self.get_port(guest_port) + host_port = self.redirs.get(guest_port) qemu_cmd += " -redir tcp:%s::%s" % (host_port, guest_port) if params.get("display") == "vnc": @@ -282,7 +308,8 @@ class VM: def create(self, name=None, params=None, qemu_path=None, image_dir=None, - iso_dir=None, for_migration=False, timeout=5.0): + iso_dir=None, script_dir=None, for_migration=False, + timeout=5.0): """ Start the VM by running a qemu command. All parameters are optional. The following applies to all parameters @@ -295,6 +322,7 @@ class VM: @param qemu_path: The path of the qemu binary @param image_dir: The directory where images reside @param iso_dir: The directory where ISOs reside + @param script_dir: The directory where -net tap scripts reside @param for_migration: If True, start the VM with the -incoming option """ @@ -310,11 +338,14 @@ class VM: self.image_dir = image_dir if iso_dir != None: self.iso_dir = iso_dir + if script_dir != None: + self.script_dir = script_dir name = self.name params = self.params qemu_path = self.qemu_path image_dir = self.image_dir iso_dir = self.iso_dir + script_dir = self.script_dir # Verify the md5sum of the ISO image iso = params.get("cdrom") @@ -325,14 +356,14 @@ class VM: return False compare = False if params.get("md5sum_1m"): - logging.debug("Comparing expected MD5 sum with MD5 sum of first" - "MB of ISO file...") + logging.debug("Comparing expected MD5 sum with MD5 sum of " + "first MB of ISO file...") actual_md5sum = kvm_utils.md5sum_file(iso, 1048576) expected_md5sum = params.get("md5sum_1m") compare = True elif params.get("md5sum"): - logging.debug("Comparing expected MD5 sum with MD5 sum of ISO" - " file...") + logging.debug("Comparing expected MD5 sum with MD5 sum of ISO " + "file...") actual_md5sum = kvm_utils.md5sum_file(iso) expected_md5sum = params.get("md5sum") compare = True @@ -581,32 +612,42 @@ class VM: return self.params - def get_address(self): + def get_address(self, index=0): """ - Return the guest's address in host space. + Return the address of a NIC of the guest, in host space. - If port redirection is used, return 'localhost' (the guest has no IP - address of its own). Otherwise return the guest's IP address. + If port redirection is used, return 'localhost' (the NIC has no IP + address of its own). Otherwise return the NIC's IP address. + + @param index: Index of the NIC whose address is requested. """ - # Currently redirection is always used, so return 'localhost' - return "localhost" + nic_name = kvm_utils.get_sub_dict_names(self.params, "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) + return ip + else: + return "localhost" - def get_port(self, port): + def get_port(self, port, index=0): """ Return the port in host space corresponding to port in guest space. @param port: Port number in host space. + @param index: Index of the NIC. @return: If port redirection is used, return the host port redirected to guest port port. Otherwise return port. """ - # Currently redirection is always used, so use the redirs dict - if self.redirs.has_key(port): - return self.redirs[port] + nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[index] + nic_params = kvm_utils.get_sub_dict(self.params, nic_name) + if nic_params.get("nic_mode") == "tap": + return port else: - logging.debug("Warning: guest port %s requested but not" - " redirected" % port) - return None + if not self.redirs.has_key(port): + logging.warn("Warning: guest port %s requested but not " + "redirected" % port) + return self.redirs.get(port) def get_pid(self):