[libvirt] [PATCHv2 3/3] qemu: Prefer VFIO for PCI device passthrough

Peter Krempa pkrempa at redhat.com
Tue Sep 24 13:10:07 UTC 2013


Prefer using VFIO (if available) to the legacy KVM device passthrough.

With this patch a PCI passthrough device without the driver configured
will be started with VFIO if it's available on the host. If not legacy
KVM passthrough is checked and error is reported if it's not available.
---

Notes:
    Version 2:
    - adapted to changes from previous changes
    - error out if VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT reaches CMD generator
      and adapt tests to avoid it
    - change the code to use the shared function

 docs/formatdomain.html.in |  9 ++++-----
 src/conf/domain_conf.h    |  2 +-
 src/qemu/qemu_command.c   |  5 +++--
 src/qemu/qemu_hostdev.c   | 21 +++++++++++++++++++--
 src/qemu/qemu_hostdev.h   |  3 ++-
 src/qemu/qemu_hotplug.c   |  2 +-
 src/qemu/qemu_process.c   |  4 +++-
 tests/qemuxml2argvtest.c  | 11 +++++++++++
 8 files changed, 44 insertions(+), 13 deletions(-)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 3689399..6f3f7cf 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2755,11 +2755,10 @@
         backend, which is compatible with UEFI SecureBoot) or "kvm"
         (for the legacy device assignment handled directly by the KVM
         kernel module)<span class="since">Since 1.0.5 (QEMU and KVM
-        only, requires kernel 3.6 or newer)</span>. Currently, "kvm"
-        is the default used by libvirt when not explicitly provided,
-        but since the two are functionally equivalent, this default
-        could be changed in the future with no impact to domains that
-        don't specify anything.
+        only, requires kernel 3.6 or newer)</span>. The default, when
+        the driver name is not explicitly specified, is to check wether
+        VFIO is available and use it if it's the case. If VFIO is not
+        available, the legacy "kvm" assignment is attempted.
       </dd>
       <dt><code>readonly</code></dt>
       <dd>Indicates that the device is readonly, only supported by SCSI host
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 9414ebf..43d8746 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -399,7 +399,7 @@ enum virDomainHostdevSubsysType {

 /* the backend driver used for PCI hostdev devices */
 typedef enum {
-    VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, /* currently kvm, could change */
+    VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, /* detect automaticaly, prefer VFIO */
     VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM,    /* force legacy kvm style */
     VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO,   /* force vfio */

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 06c0fcb..c346816 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -5392,7 +5392,6 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,

     switch ((virDomainHostdevSubsysPciBackendType)
             dev->source.subsys.u.pci.backend) {
-    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
     case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
         virBufferAddLit(&buf, "pci-assign");
         if (configfd && *configfd)
@@ -5403,9 +5402,11 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
         virBufferAddLit(&buf, "vfio-pci");
         break;

+
+    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
     case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("unknown PCI passhthrough type"));
+                       _("PCI passhthrough type needs to be specified"));
         break;
     }

diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
index dbbc2b4..ad408d8 100644
--- a/src/qemu/qemu_hostdev.c
+++ b/src/qemu/qemu_hostdev.c
@@ -1366,7 +1366,8 @@ qemuHostdevHostSupportsPassthroughLegacy(void)

 bool
 qemuHostdevHostVerifySupport(virDomainHostdevDefPtr *hostdevs,
-                             size_t nhostdevs)
+                             size_t nhostdevs,
+                             virQEMUCapsPtr qemuCaps)
 {
     int supportsPassthroughKVM = -1;
     int supportsPassthroughVFIO = -1;
@@ -1387,6 +1388,23 @@ qemuHostdevHostVerifySupport(virDomainHostdevDefPtr *hostdevs,
             }

             switch ((virDomainHostdevSubsysPciBackendType) *backend) {
+            case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
+                if (supportsPassthroughVFIO &&
+                    virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
+                    *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
+                } else if (supportsPassthroughKVM &&
+                           (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE) ||
+                            virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
+                    *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
+                } else {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                   _("host doesn't support passthrough of "
+                                     "host PCI devices"));
+                    return false;
+                }
+
+                break;
+
             case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
                 if (!supportsPassthroughVFIO) {
                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -1395,7 +1413,6 @@ qemuHostdevHostVerifySupport(virDomainHostdevDefPtr *hostdevs,
                 }
                 break;

-            case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
             case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
                 if (!supportsPassthroughKVM) {
                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h
index 6d88830..afe67a5 100644
--- a/src/qemu/qemu_hostdev.h
+++ b/src/qemu/qemu_hostdev.h
@@ -70,7 +70,8 @@ int qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
                                       char *stateDir);

 bool qemuHostdevHostVerifySupport(virDomainHostdevDefPtr *hostdevs,
-                                  size_t nhostdevs);
+                                  size_t nhostdevs,
+                                  virQEMUCapsPtr qemuCaps);


 #endif /* __QEMU_HOSTDEV_H__ */
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 604a0ed..a6afebe 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1144,7 +1144,7 @@ int qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver,
         return -1;

     /* verify the availability of passthrough support */
-    if (!qemuHostdevHostVerifySupport(&hostdev, 1))
+    if (!qemuHostdevHostVerifySupport(&hostdev, 1, priv->qemuCaps))
         goto error;

     switch ((virDomainHostdevSubsysPciBackendType) *backend) {
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index baf021f..6af4223 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3714,7 +3714,9 @@ int qemuProcessStart(virConnectPtr conn,
     }

     /* check and assign device assignment settings */
-    if (!qemuHostdevHostVerifySupport(vm->def->hostdevs, vm->def->nhostdevs))
+    if (!qemuHostdevHostVerifySupport(vm->def->hostdevs,
+                                      vm->def->nhostdevs,
+                                      priv->qemuCaps))
         goto cleanup;

     /*
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index ec4a6e5..690b705 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -98,6 +98,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
     virConnectPtr conn;
     char *log = NULL;
     virCommandPtr cmd = NULL;
+    size_t i;

     if (!(conn = virGetConnect()))
         goto out;
@@ -154,6 +155,16 @@ static int testCompareXMLToArgvFiles(const char *xml,
     if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0)
         goto out;

+    for (i = 0; i < vmdef->nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = vmdef->hostdevs[i];
+
+        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
+            hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) {
+            hostdev->source.subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
+        }
+    }
+
     if (!(cmd = qemuBuildCommandLine(conn, &driver, vmdef, &monitor_chr,
                                      (flags & FLAG_JSON), extraFlags,
                                      migrateFrom, migrateFd, NULL,
-- 
1.8.3.2




More information about the libvir-list mailing list