| Index: client/tests/kvm/kvm_vm.py
|
| diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
|
| index 135d08ebd8270040bfeb50aa4e5ae1132ccecfbc..a860437f6ea41e92d8f069b8bdc6e3a61d45e7f6 100755
|
| --- a/client/tests/kvm/kvm_vm.py
|
| +++ b/client/tests/kvm/kvm_vm.py
|
| @@ -5,7 +5,7 @@ Utility classes and functions to handle Virtual Machine creation using qemu.
|
| @copyright: 2008-2009 Red Hat Inc.
|
| """
|
|
|
| -import time, socket, os, logging, fcntl, re, commands, glob
|
| +import time, socket, os, logging, fcntl, re, commands, shelve, glob
|
| import kvm_utils, kvm_subprocess, kvm_monitor, rss_file_transfer
|
| from autotest_lib.client.common_lib import error
|
| from autotest_lib.client.bin import utils
|
| @@ -109,15 +109,15 @@ class VM:
|
| self.serial_console = None
|
| self.redirs = {}
|
| self.vnc_port = 5900
|
| - self.uuid = None
|
| self.monitors = []
|
| self.pci_assignable = None
|
| + self.netdev_id = []
|
| + self.uuid = None
|
|
|
| self.name = name
|
| self.params = params
|
| self.root_dir = root_dir
|
| self.address_cache = address_cache
|
| - self.netdev_id = []
|
|
|
| # Find a unique identifier for this VM
|
| while True:
|
| @@ -234,20 +234,40 @@ class VM:
|
| if boot: cmd += ",boot=on"
|
| return cmd
|
|
|
| - def add_nic(help, vlan, model=None, mac=None, netdev_id=None):
|
| - if has_option(help, "netdev"):
|
| - cmd = " -net nic,netdev=%s" % netdev_id
|
| + def add_nic(help, vlan, model=None, mac=None, netdev_id=None,
|
| + nic_extra_params=None):
|
| + if has_option(help, "device"):
|
| + if model == "virtio":
|
| + model="virtio-net-pci"
|
| + if not model:
|
| + model= "rtl8139"
|
| + cmd = " -device %s" % model
|
| + if mac:
|
| + cmd += ",mac=%s" % mac
|
| + if has_option(help, "netdev"):
|
| + cmd += ",netdev=%s" % netdev_id
|
| + else:
|
| + cmd += "vlan=%d," % vlan
|
| + if nic_extra_params:
|
| + cmd += ",%s" % nic_extra_params
|
| else:
|
| - cmd = " -net nic,vlan=%d" % vlan
|
| - if model: cmd += ",model=%s" % model
|
| - if mac: cmd += ",macaddr='%s'" % mac
|
| + if has_option(help, "netdev"):
|
| + cmd = " -net nic,netdev=%s" % netdev_id
|
| + else:
|
| + cmd = " -net nic,vlan=%d" % vlan
|
| + if model:
|
| + cmd += ",model=%s" % model
|
| + if mac:
|
| + cmd += ",macaddr='%s'" % mac
|
| return cmd
|
|
|
| def add_net(help, vlan, mode, ifname=None, script=None,
|
| downscript=None, tftp=None, bootfile=None, hostfwd=[],
|
| - netdev_id=None):
|
| + netdev_id=None, vhost=False):
|
| if has_option(help, "netdev"):
|
| cmd = " -netdev %s,id=%s" % (mode, netdev_id)
|
| + if vhost:
|
| + cmd +=",vhost=on"
|
| else:
|
| cmd = " -net %s,vlan=%d" % (mode, vlan)
|
| if mode == "tap":
|
| @@ -384,11 +404,10 @@ class VM:
|
| 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
|
| - mac = None
|
| - if "address_index" in nic_params:
|
| - mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
|
| + mac = self.get_mac_address(vlan)
|
| qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
|
| - self.netdev_id[vlan])
|
| + self.netdev_id[vlan],
|
| + nic_params.get("nic_extra_params"))
|
| # Handle the '-net tap' or '-net user' part
|
| script = nic_params.get("nic_script")
|
| downscript = nic_params.get("nic_downscript")
|
| @@ -400,10 +419,11 @@ class VM:
|
| if tftp:
|
| tftp = kvm_utils.get_path(root_dir, tftp)
|
| qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
|
| - nic_params.get("nic_ifname"),
|
| + self.get_ifname(vlan),
|
| script, downscript, tftp,
|
| nic_params.get("bootp"), redirs,
|
| - self.netdev_id[vlan])
|
| + self.netdev_id[vlan],
|
| + nic_params.get("vhost")=="yes")
|
| # Proceed to next NIC
|
| vlan += 1
|
|
|
| @@ -487,22 +507,22 @@ class VM:
|
| return qemu_cmd
|
|
|
|
|
| - def create(self, name=None, params=None, root_dir=None,
|
| - for_migration=False, timeout=5.0, extra_params=None):
|
| + def create(self, name=None, params=None, root_dir=None, timeout=5.0,
|
| + migration_mode=None, migration_exec_cmd=None, mac_source=None):
|
| """
|
| Start the VM by running a qemu command.
|
| - All parameters are optional. The following applies to all parameters
|
| - but for_migration: If a parameter is not supplied, the corresponding
|
| - value stored in the class attributes is used, and if it is supplied,
|
| - it is stored for later use.
|
| + All parameters are optional. If name, params or root_dir are not
|
| + supplied, the respective values stored as class attributes are used.
|
|
|
| @param name: The name of the object
|
| @param params: A dict containing VM params
|
| @param root_dir: Base directory for relative filenames
|
| - @param for_migration: If True, start the VM with the -incoming
|
| - option
|
| - @param extra_params: extra params for qemu command.e.g -incoming option
|
| - Please use this parameter instead of for_migration.
|
| + @param migration_mode: If supplied, start VM for incoming migration
|
| + using this protocol (either 'tcp', 'unix' or 'exec')
|
| + @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."'
|
| + (e.g. 'gzip -c -d filename') if migration_mode is 'exec'
|
| + @param mac_source: A VM object from which to copy MAC addresses. If not
|
| + specified, new addresses will be generated.
|
| """
|
| self.destroy()
|
|
|
| @@ -577,6 +597,15 @@ class VM:
|
| self.uuid = f.read().strip()
|
| f.close()
|
|
|
| + # Generate or copy MAC addresses for all NICs
|
| + num_nics = len(kvm_utils.get_sub_dict_names(params, "nics"))
|
| + for vlan in range(num_nics):
|
| + mac = mac_source and mac_source.get_mac_address(vlan)
|
| + if mac:
|
| + kvm_utils.set_mac_address(self.instance, vlan, mac)
|
| + else:
|
| + kvm_utils.generate_mac_address(self.instance, vlan)
|
| +
|
| # Assign a PCI assignable device
|
| self.pci_assignable = None
|
| pa_type = params.get("pci_assignable")
|
| @@ -623,17 +652,15 @@ class VM:
|
| # Make qemu command
|
| qemu_command = self.make_qemu_command()
|
|
|
| - # Enable migration support for VM by adding extra_params.
|
| - if extra_params is not None:
|
| - if " -incoming tcp:0:%d" == extra_params:
|
| - self.migration_port = kvm_utils.find_free_port(5200, 6000)
|
| - qemu_command += extra_params % self.migration_port
|
| - elif " -incoming unix:%s" == extra_params:
|
| - self.migration_file = os.path.join("/tmp/", "unix-" +
|
| - time.strftime("%Y%m%d-%H%M%S"))
|
| - qemu_command += extra_params % self.migration_file
|
| - else:
|
| - qemu_command += extra_params
|
| + # Add migration parameters if required
|
| + if migration_mode == "tcp":
|
| + self.migration_port = kvm_utils.find_free_port(5200, 6000)
|
| + qemu_command += " -incoming tcp:0:%d" % self.migration_port
|
| + elif migration_mode == "unix":
|
| + self.migration_file = "/tmp/migration-unix-%s" % self.instance
|
| + qemu_command += " -incoming unix:%s" % self.migration_file
|
| + elif migration_mode == "exec":
|
| + qemu_command += ' -incoming "exec:%s"' % migration_exec_cmd
|
|
|
| logging.debug("Running qemu command:\n%s", qemu_command)
|
| self.process = kvm_subprocess.run_bg(qemu_command, None,
|
| @@ -750,7 +777,7 @@ class VM:
|
| logging.debug("Shutdown command sent; waiting for VM "
|
| "to go down...")
|
| if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
|
| - logging.debug("VM is down")
|
| + logging.debug("VM is down, freeing mac address.")
|
| return
|
| finally:
|
| session.close()
|
| @@ -794,6 +821,14 @@ class VM:
|
| os.unlink(f)
|
| except OSError:
|
| pass
|
| + if hasattr(self, "migration_file"):
|
| + try:
|
| + os.unlink(self.migration_file)
|
| + except OSError:
|
| + pass
|
| + num_nics = len(kvm_utils.get_sub_dict_names(self.params, "nics"))
|
| + for vlan in range(num_nics):
|
| + self.free_mac_address(vlan)
|
|
|
|
|
| @property
|
| @@ -880,26 +915,23 @@ class VM:
|
| 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)
|
| + mac = self.get_mac_address(index)
|
| if not mac:
|
| logging.debug("MAC address unavailable")
|
| return None
|
| - if not ip or nic_params.get("always_use_tcpdump") == "yes":
|
| - # Get the IP address from the cache
|
| - ip = self.address_cache.get(mac)
|
| - if not ip:
|
| - logging.debug("Could not find IP address for MAC address: "
|
| - "%s" % mac)
|
| - return None
|
| - # Make sure the IP 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_ip_address_ownership(ip, macs):
|
| - logging.debug("Could not verify MAC-IP address mapping: "
|
| - "%s ---> %s" % (mac, ip))
|
| - return None
|
| + mac = mac.lower()
|
| + # Get the IP address from the cache
|
| + ip = self.address_cache.get(mac)
|
| + if not ip:
|
| + logging.debug("Could not find IP address for MAC address: %s" %
|
| + mac)
|
| + return None
|
| + # Make sure the IP address is assigned to this guest
|
| + macs = [self.get_mac_address(i) for i in range(len(nics))]
|
| + if not kvm_utils.verify_ip_address_ownership(ip, macs):
|
| + logging.debug("Could not verify MAC-IP address mapping: "
|
| + "%s ---> %s" % (mac, ip))
|
| + return None
|
| return ip
|
| else:
|
| return "localhost"
|
| @@ -925,6 +957,39 @@ class VM:
|
| return self.redirs.get(port)
|
|
|
|
|
| + def get_ifname(self, nic_index=0):
|
| + """
|
| + Return the ifname of a tap device associated with a NIC.
|
| +
|
| + @param nic_index: Index of the NIC
|
| + """
|
| + nics = kvm_utils.get_sub_dict_names(self.params, "nics")
|
| + nic_name = nics[nic_index]
|
| + nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
|
| + if nic_params.get("nic_ifname"):
|
| + return nic_params.get("nic_ifname")
|
| + else:
|
| + return "t%d-%s" % (nic_index, self.instance[-11:])
|
| +
|
| +
|
| + def get_mac_address(self, nic_index=0):
|
| + """
|
| + Return the MAC address of a NIC.
|
| +
|
| + @param nic_index: Index of the NIC
|
| + """
|
| + return kvm_utils.get_mac_address(self.instance, nic_index)
|
| +
|
| +
|
| + def free_mac_address(self, nic_index=0):
|
| + """
|
| + Free a NIC's MAC address.
|
| +
|
| + @param nic_index: Index of the NIC
|
| + """
|
| + kvm_utils.free_mac_address(self.instance, nic_index)
|
| +
|
| +
|
| def get_pid(self):
|
| """
|
| Return the VM's PID. If the VM is dead return None.
|
|
|