[Kimchi-devel] [PATCH v2] Fix passthrough bugs

Jose Ricardo Ziviani joserz at linux.vnet.ibm.com
Fri Oct 23 01:02:08 UTC 2015


 - when the guest is turned off, a multi function pci device must be
   attached using mutifunction attribute in the pci address. Otherwise
   the pci won't be attached correctly. Libvirt doesn't support
   multifunction hotplug, so we don't change anything if the guest is
   running.
 - after any recent libvirt update, the device dettachment must be
   done just before attaching it into the guest because they query
   /sys to retrieve some device state.

Signed-off-by: Jose Ricardo Ziviani <joserz at linux.vnet.ibm.com>
---
 src/wok/plugins/kimchi/model/vmhostdevs.py | 63 ++++++++++++++++++++++++++++--
 1 file changed, 59 insertions(+), 4 deletions(-)

diff --git a/src/wok/plugins/kimchi/model/vmhostdevs.py b/src/wok/plugins/kimchi/model/vmhostdevs.py
index 7d13585..c7ce454 100644
--- a/src/wok/plugins/kimchi/model/vmhostdevs.py
+++ b/src/wok/plugins/kimchi/model/vmhostdevs.py
@@ -23,6 +23,7 @@ import os
 import platform
 from lxml import etree, objectify
 from lxml.builder import E
+from operator import itemgetter
 
 from wok.exception import InvalidOperation, InvalidParameter, NotFoundError
 from wok.exception import OperationFailed
@@ -62,6 +63,9 @@ class VMHostDevsModel(object):
         self._passthrough_device_validate(dev_name)
         dev_info = DeviceModel(conn=self.conn).lookup(dev_name)
 
+        if dev_info['device_type'] == 'pci':
+            return self._attach_pci_device(vmid, dev_info)
+
         with RollbackContext() as rollback:
             try:
                 dev = self.conn.get().nodeDeviceLookupByName(dev_name)
@@ -79,7 +83,7 @@ class VMHostDevsModel(object):
 
         return info
 
-    def _get_pci_device_xml(self, dev_info):
+    def _get_pci_device_xml(self, dev_info, slot, is_multifunction):
         if 'detach_driver' not in dev_info:
             dev_info['detach_driver'] = 'kvm'
 
@@ -88,8 +92,29 @@ class VMHostDevsModel(object):
                                     slot=str(dev_info['slot']),
                                     function=str(dev_info['function'])))
         driver = E.driver(name=dev_info['detach_driver'])
-        host_dev = E.hostdev(source, driver,
-                             mode='subsystem', type='pci', managed='yes')
+
+        if is_multifunction:
+            multi = E.address(type='pci',
+                              domain='0',
+                              bus='0',
+                              slot=str(slot),
+                              function=str(dev_info['function']))
+
+            if dev_info['function'] == 0:
+                multi = E.address(type='pci',
+                                  domain='0',
+                                  bus='0',
+                                  slot=str(slot),
+                                  function=str(dev_info['function']),
+                                  multifunction='on')
+
+
+            host_dev = E.hostdev(source, driver, multi,
+                                 mode='subsystem', type='pci', managed='yes')
+
+        else:
+            host_dev = E.hostdev(source, driver,
+                                 mode='subsystem', type='pci', managed='yes')
 
         return etree.tostring(host_dev)
 
@@ -110,6 +135,27 @@ class VMHostDevsModel(object):
             if rc != 0:
                 wok_log.warning("Unable to turn on sebool virt_use_sysfs")
 
+    def _available_slot(self, dom):
+        xmlstr = dom.XMLDesc(0)
+        root = objectify.fromstring(xmlstr)
+        slots = []
+        try:
+            devices = root.devices
+            slots = [DeviceModel._toint(dev.attrib['slot'])
+                     for dev in devices.findall('.//address')
+                     if 'slot' in dev.attrib]
+
+        except AttributeError:
+            return 1
+
+        slots = sorted(slots)
+
+        for free, slot in enumerate(slots, start=1):
+            if free < slot:
+                return free
+
+        return free+1
+
     def _attach_pci_device(self, vmid, dev_info):
         self._validate_pci_passthrough_env()
 
@@ -135,6 +181,10 @@ class VMHostDevsModel(object):
         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:
@@ -153,10 +203,15 @@ class VMHostDevsModel(object):
 
         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)
+                xmlstr = self._get_pci_device_xml(pci_info,
+                                                  slot,
+                                                  is_multifunction)
                 try:
                     dom.attachDeviceFlags(xmlstr, device_flags)
                 except libvirt.libvirtError:
-- 
1.9.1




More information about the Kimchi-devel mailing list