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(a)linux.vnet.ibm.com>
Signed-off-by: Lucio Correia <luciojhc(a)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>