diff mbox

[KVM-AUTOTEST,v2,02/11] KVM test: add basic TAP support with static MAC-IP mapping

Message ID 42ceeed70c7c1ec9f4d78d91d67a290f3ac11e6e.1250091576.git.mgoldish@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Michael Goldish Aug. 12, 2009, 3:59 p.m. UTC
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 directory 'scripts' under the
main KVM test directory.

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 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 mbox

Patch

diff --git a/client/tests/kvm/kvm_preprocessing.py b/client/tests/kvm/kvm_preprocessing.py
index d118826..22c2b8b 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 = os.path.join(test.bindir, "scripts")
 
     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..9ad115e 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 = user
+#nic_mode = tap
+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 2ea6681..33f37e5 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):