constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e)
}
+_MIGRATION_CAPS_DELIM = ":"
+
def _GenerateDeviceKVMId(dev_type, dev, idx=None):
"""Helper function to generate a unique device name used by KVM
constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
+ constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK,
constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
constants.HV_DISK_CACHE:
hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
_INFO_VERSION_CMD = "info version"
- _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
+ # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller
+ _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000"
+ _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"]
ANCILLARY_FILES = [
_KVM_NETWORK_SCRIPT,
data.append(info)
return data
- def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
+ def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks,
kvmhelp, devlist):
"""Generate KVM options regarding instance's block devices.
@type instance: L{objects.Instance}
@param instance: the instance object
+ @type up_hvp: dict
+ @param up_hvp: the instance's runtime hypervisor parameters
@type kvm_disks: list of tuples
@param kvm_disks: list of tuples [(disk, link_name)..]
@type kvmhelp: string
@return: list of command line options eventually used by kvm executable
"""
- hvp = instance.hvparams
- kernel_path = hvp[constants.HV_KERNEL_PATH]
+ kernel_path = up_hvp[constants.HV_KERNEL_PATH]
if kernel_path:
boot_disk = False
else:
- boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
+ boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
# whether this is an older KVM version that uses the boot=on flag
# on devices
dev_opts = []
device_driver = None
- disk_type = hvp[constants.HV_DISK_TYPE]
+ disk_type = up_hvp[constants.HV_DISK_TYPE]
if disk_type == constants.HT_DISK_PARAVIRTUAL:
if_val = ",if=%s" % self._VIRTIO
try:
else:
if_val = ",if=%s" % disk_type
# Cache mode
- disk_cache = hvp[constants.HV_DISK_CACHE]
+ disk_cache = up_hvp[constants.HV_DISK_CACHE]
if instance.disk_template in constants.DTS_EXT_MIRROR:
if disk_cache != "none":
# TODO: make this a hard error, instead of a silent overwrite
kvm_cmd.extend(["-smp", ",".join(smp_list)])
kvm_cmd.extend(["-pidfile", pidfile])
- kvm_cmd.extend(["-balloon", "virtio"])
+
+ pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
+
+ # As requested by music lovers
+ if hvp[constants.HV_SOUNDHW]:
+ soundhw = hvp[constants.HV_SOUNDHW]
+ # For some reason only few sound devices require a PCI slot
+ # while the Audio controller *must* be in slot 3.
+ # That's why we bridge this option early in command line
+ if soundhw in self._SOUNDHW_WITH_PCI_SLOT:
+ _ = _GetFreeSlot(pci_reservations, reserve=True)
+ kvm_cmd.extend(["-soundhw", soundhw])
+
+ if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI:
+ # The SCSI controller requires another PCI slot.
+ _ = _GetFreeSlot(pci_reservations, reserve=True)
+
+ # Add id to ballon and place to the first available slot (3 or 4)
+ addr = _GetFreeSlot(pci_reservations, reserve=True)
+ pci_info = ",bus=pci.0,addr=%s" % hex(addr)
+ kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info])
kvm_cmd.extend(["-daemonize"])
if not instance.hvparams[constants.HV_ACPI]:
kvm_cmd.extend(["-no-acpi"])
else:
# Enable the spice agent communication channel between the host and the
# agent.
- kvm_cmd.extend(["-device", "virtio-serial-pci"])
+ addr = _GetFreeSlot(pci_reservations, reserve=True)
+ pci_info = ",bus=pci.0,addr=%s" % hex(addr)
+ kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % pci_info])
kvm_cmd.extend([
"-device",
"virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
if hvp[constants.HV_CPU_TYPE]:
kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
- # As requested by music lovers
- if hvp[constants.HV_SOUNDHW]:
- kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
-
# Pass a -vga option if requested, or if spice is used, for backwards
# compatibility.
if hvp[constants.HV_VGA]:
if hvp[constants.HV_KVM_EXTRA]:
kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
- pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS)
kvm_disks = []
for disk, link_name in block_devices:
disk.pci = _GetFreeSlot(pci_reservations, disk.pci, True)
devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
+ up_hvp,
kvm_disks,
kvmhelp,
devlist)
instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
self._CallMonitorCommand(instance_name, migrate_command)
+ # These commands are supported in latest qemu versions.
+ # Since _CallMonitorCommand does not catch monitor errors
+ # this does not raise an exception in case command is not supported
+ # TODO: either parse output of command or see if the command supported
+ # via info help (see hotplug)
+ migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS]
+ if migration_caps:
+ for c in migration_caps.split(_MIGRATION_CAPS_DELIM):
+ migrate_command = ("migrate_set_capability %s on" % c)
+ self._CallMonitorCommand(instance_name, migrate_command)
+
migrate_command = "migrate -d tcp:%s:%s" % (target, port)
self._CallMonitorCommand(instance_name, migrate_command)