[Kimchi-devel] [PATCH] [Kimchi] USB xhci hotplug: Check controller, define in template, add test in Power

Lucio Correia luciojhc at linux.vnet.ibm.com
Fri Oct 14 20:55:29 UTC 2016


- 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 at linux.vnet.ibm.com>
Signed-off-by: Lucio Correia <luciojhc at 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
+        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>
+        """
+
     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>
-- 
2.7.4




More information about the Kimchi-devel mailing list