def __init__(self, **kargs): self.conn = kargs['conn'] self.objstore = kargs['objstore'] self.events = kargs['eventsloop'] self.task = TaskModel(**kargs) self.devs_model = DevicesModel(**kargs) self.dev_model = DeviceModel(**kargs) self._cb = None self.events.registerDetachDevicesEvent( self.conn, self._event_devices, self)
def _delete_affected_pci_devices(self, dom, dev_name, pci_devs): try: self.dev_model.lookup(dev_name) except NotFoundError: return affected_names = set( DevicesModel(conn=self.conn).get_list( _passthrough_affected_by=dev_name)) for pci_name, e in pci_devs: if pci_name in affected_names: xmlstr = etree.tostring(e) dom.detachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all'))
def _passthrough_device_validate(self, dev_name): eligible_dev_names = \ DevicesModel(conn=self.conn).get_list(_passthrough='true') if dev_name not in eligible_dev_names: raise InvalidParameter('KCHVMHDEV0002E', {'dev_name': dev_name})
def _attach_pci_device(self, vmid, dev_info): self._validate_pci_passthrough_env() dom = VMModel.get_vm(vmid, self.conn) # Due to libvirt limitation, we don't support live assigne device to # vfio driver. driver = ('vfio' if DOM_STATE_MAP[dom.info()[0]] == "shutoff" and self.caps.kernel_vfio else 'kvm') # on powerkvm systems it must be vfio driver. distro, _, _ = platform.linux_distribution() if distro == 'IBM_PowerKVM': driver = 'vfio' # Attach all PCI devices in the same IOMMU group dev_model = DeviceModel(conn=self.conn) devs_model = DevicesModel(conn=self.conn) affected_names = devs_model.get_list( _passthrough_affected_by=dev_info['name']) passthrough_names = devs_model.get_list(_cap='pci', _passthrough='true') group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [dev_model.lookup(dev_name) for dev_name in group_names] pci_infos.append(dev_info) is_multifunction = len(pci_infos) > 1 and \ DOM_STATE_MAP[dom.info()[0]] == "shutoff" pci_infos = sorted(pci_infos, key=itemgetter('name')) # all devices in the group that is going to be attached to the vm # must be detached from the host first with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() device_flags = get_vm_config_flag(dom, mode='all') slot = 0 if is_multifunction: slot = self._available_slot(dom) with RollbackContext() as rollback: for pci_info in pci_infos: pci_info['detach_driver'] = driver xmlstr = self._get_pci_device_xml(pci_info, slot, is_multifunction) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() return dev_info['name']
def _attach_pci_device(self, cb, params): cb('Attaching PCI device') vmid = params['vmid'] dev_info = params['dev_info'] self._validate_pci_passthrough_env() dom = VMModel.get_vm(vmid, self.conn) # Due to libvirt limitation, we don't support live assigne device to # vfio driver. driver = ('vfio' if DOM_STATE_MAP[dom.info()[0]] == "shutoff" and self.caps.kernel_vfio else 'kvm') # on powerkvm systems it must be vfio driver. distro, _, _ = platform.linux_distribution() if distro == 'IBM_PowerKVM': driver = 'vfio' # Attach all PCI devices in the same IOMMU group dev_model = DeviceModel(conn=self.conn) devs_model = DevicesModel(conn=self.conn) affected_names = devs_model.get_list( _passthrough_affected_by=dev_info['name']) passthrough_names = devs_model.get_list(_cap='pci', _passthrough='true') group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [dev_model.lookup(dev_name) for dev_name in group_names] pci_infos.append(dev_info) is_multifunction = len(pci_infos) > 1 pci_infos = sorted(pci_infos, key=itemgetter('name')) # does not allow hot-plug of 3D graphic cards is_3D_device = dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) # all devices in the group that is going to be attached to the vm # must be detached from the host first with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() device_flags = get_vm_config_flag(dom, mode='all') # when attaching a 3D graphic device it might be necessary to increase # the window size memory in order to be able to attach more than one # device to the same guest if is_3D_device: self.update_mmio_guest(vmid, True) slot = 0 if is_multifunction: # search for the first available slot in guest xml slot = self._available_slot(dom) with RollbackContext() as rollback: # multifunction hotplug is a special case where all functions # must be attached together within one xml file, the same does # not happen to multifunction coldplug - where each function is # attached individually if DOM_STATE_MAP[dom.info()[0]] != 'shutoff' and is_multifunction: xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: wok_log.error( 'Failed to attach mutifunction device VM %s: \n%s', vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() cb('OK', True) return for pci_info in pci_infos: pci_info['detach_driver'] = driver cb('Reading source device XML') xmlstr = self._get_pci_device_xml(pci_info, slot, is_multifunction) try: cb('Attaching device to VM') dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() cb('OK', True)