
On 10/14/2016 05:55 PM, Lucio Correia wrote:
- Today it is not possible to hotplug a PCI in Power Systems without an USB xhci controller existing in the VM. This commit checks if there is such controller in the VM, displaying an error message if not. - When creating VMs using Kimchi in a Power System, the USB xhci controller is defined by default to have PCI hotplug support. - From now on all templates are created with xhci usb controller, so a hotplug must be performed flawlessly. If anything wrong the test case will fail.
Signed-off-by: Jose Ricardo Ziviani <joserz@linux.vnet.ibm.com> Signed-off-by: Lucio Correia <luciojhc@linux.vnet.ibm.com> --- i18n.py | 1 + model/vmhostdevs.py | 34 ++++++++++++++++++++++++++++++++++ tests/test_model.py | 25 +++++++++++++++++++++++++ vmtemplate.py | 17 +++++++++++++++++ 4 files changed, 77 insertions(+)
diff --git a/i18n.py b/i18n.py index 82c679b..159021d 100644 --- a/i18n.py +++ b/i18n.py @@ -150,6 +150,7 @@ messages = { "KCHVMHDEV0005E": _('The device %(name)s is probably in use by the host. Unable to attach it to the guest.'), "KCHVMHDEV0006E": _('Hot-(un)plug of device %(name)s is not supported.'), "KCHVMHDEV0007E": _('Failed to attach %(device)s to %(vm)s'), + "KCHVMHDEV0008E": _('VM %(vmid)s does not have an USB XHCI controller to accept PCI hotplug.'),
"KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), diff --git a/model/vmhostdevs.py b/model/vmhostdevs.py index e289f03..edb6e36 100644 --- a/model/vmhostdevs.py +++ b/model/vmhostdevs.py @@ -43,6 +43,9 @@ from wok.plugins.kimchi.xmlutils.qemucmdline import QEMU_NAMESPACE
CMDLINE_FIELD_NAME = 'spapr-pci-host-bridge.mem_win_size' +USB_MODELS_PCI_HOTPLUG = ["piix3-uhci", "piix4-uhci", "ehci", "ich9-ehci1", + "ich9-uhci1", "ich9-uhci2", "ich9-uhci3", + "vt82c686b-uhci", "pci-ohci", "nec-xhci"] WINDOW_SIZE_BAR = 0x800000000
@@ -135,6 +138,28 @@ class VMHostDevsModel(object):
return '<devices>%s</devices>' % hostdevs
+ def have_xhci_usb_controller(self, vmid): + dom = VMModel.get_vm(vmid, self.conn) + + root = objectify.fromstring(dom.XMLDesc(0)) + + try: + controllers = root.devices.controller + + except AttributeError: + return False + + for controller in controllers: + + if 'model' not in controller.attrib: + continue + + if controller.attrib['type'] == 'usb' and \ + controller.attrib['model'] in USB_MODELS_PCI_HOTPLUG: + return True + + return False + def _get_pci_device_xml(self, dev_info, slot, is_multifunction): if 'detach_driver' not in dev_info: dev_info['detach_driver'] = 'kvm' @@ -234,6 +259,15 @@ class VMHostDevsModel(object): dom = VMModel.get_vm(vmid, self.conn) driver = 'vfio' if self.caps.kernel_vfio else 'kvm'
+ # 'vfio' systems requires a xhci usb controller in order to support + # pci hotplug on Power. + if driver == 'vfio' and platform.machine().startswith('ppc') and \ + DOM_STATE_MAP[dom.info()[0]] != "shutoff" and \ + not self.have_xhci_usb_controller(vmid): + msg = WokMessage('KCHVMHDEV0008E', {'vmid': vmid}) + cb(msg.get_text(), False) + raise InvalidOperation("KCHVMHDEV0008E", {'vmid': vmid}) + # Attach all PCI devices in the same IOMMU group affected_names = self.devs_model.get_list( _passthrough_affected_by=dev_info['name']) diff --git a/tests/test_model.py b/tests/test_model.py index 082cb9d..4ddd0d2 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -1626,6 +1626,31 @@ class ModelTests(unittest.TestCase): volumes = inst.storagevolumes_get_list(args['name']) self.assertEquals(len(volumes), 2)
+ def _host_is_power():
+ import platform
Move the import to the import block at the top of file.
+ return platform.machine().startswith('ppc') + + @unittest.skipUnless(_host_is_power(), 'Only required for Power hosts') + def test_pci_hotplug_requires_xhci_usb_controller(self): + config.set("authentication", "method", "pam") + inst = model.Model(None, objstore_loc=self.tmp_store) + tpl_params = {'name': 'test', 'memory': 1024, 'cdrom': UBUNTU_ISO} + inst.templates_create(tpl_params) + + with RollbackContext() as rollback: + vm_params = {'name': 'kimchi-vm1', 'template': '/templates/test'} + task1 = inst.vms_create(vm_params) + inst.task_wait(task1['id']) + rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, + 'kimchi-vm1') + # Start vm + inst.vm_start('kimchi-vm1') + rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff, + 'kimchi-vm1') + # check if create VM has USB XHCI controller + self.assertTrue( + inst.vmhostdevs_have_xhci_usb_controller('kimchi-vm1')) +
class BaseModelTests(unittest.TestCase): class FoosModel(object): diff --git a/vmtemplate.py b/vmtemplate.py index 0288330..56b339f 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -18,6 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os +import platform import stat import time import urlparse @@ -358,6 +359,18 @@ class VMTemplate(object): self.info['os_version']) return unicode(interfaces, 'utf-8')
+ def _get_usb_controller(self): + # powerkvm systems must include xhci controller model + if not platform.machine().startswith('ppc'): + return '' +
+ return """ + <controller type='usb' index='0' model='nec-xhci'> + <address type='pci' domain='0x0000' + bus='0x00' slot='0x0f' function='0x0'/> + </controller>
If it is not exist, please, add a new module to /xmlutils to generated the above XML by using lxml module instead of using plan text.
+ """ + def _get_input_output_xml(self): sound = """ <sound model='%(sound_model)s' /> @@ -469,6 +482,9 @@ class VMTemplate(object): # cpu_info element params['cpu_info_xml'] = self._get_cpu_xml()
+ # usb controller xhci + params['usb_controller'] = self._get_usb_controller() + xml = """ <domain type='%(domain)s'> %(qemu-stream-cmdline)s @@ -503,6 +519,7 @@ class VMTemplate(object): %(interfaces)s %(graphics)s %(input_output)s + %(usb_controller)s %(serial)s <memballoon model='virtio' /> </devices>