]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Prefer VFIO for PCI device passthrough
authorPeter Krempa <pkrempa@redhat.com>
Fri, 20 Sep 2013 08:39:51 +0000 (10:39 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Thu, 10 Oct 2013 10:00:56 +0000 (12:00 +0200)
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.

docs/formatdomain.html.in
src/conf/domain_conf.h
src/libvirt_private.syms
src/qemu/qemu_command.c
src/qemu/qemu_hostdev.c
src/qemu/qemu_hostdev.h
src/qemu/qemu_hotplug.c
src/qemu/qemu_process.c
tests/qemuxml2argvtest.c

index 8f744871d27dacee88582b9cee073db43a1e793a..8c998db1762a60e4a88fd2da1361694f723e8ea0 100644 (file)
         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
index 5d5e4431f942c5905b59d2777b1bfb8d98ca5e50..df28fa684d7fa4c21372eacb59007344b0ea583e 100644 (file)
@@ -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 */
 
index fe40834c0c5d0f9dc219b4753792f7cc2a62a342..cdeb8e06e6de672a1ae8450518f99ba4853faf5e 100644 (file)
@@ -262,6 +262,7 @@ virDomainHostdevFind;
 virDomainHostdevInsert;
 virDomainHostdevModeTypeToString;
 virDomainHostdevRemove;
+virDomainHostdevSubsysPciBackendTypeToString;
 virDomainHostdevSubsysTypeToString;
 virDomainHubTypeFromString;
 virDomainHubTypeToString;
index 52dc295254952cc82cc5edf241a3a758591c7b36..22cc5f227f04f5a14bdfac724e0da4d8fb6b9952 100644 (file)
@@ -5484,10 +5484,10 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
                           virQEMUCapsPtr qemuCaps)
 {
     virBuffer buf = VIR_BUFFER_INITIALIZER;
+    int backend = dev->source.subsys.u.pci.backend;
 
-    switch ((virDomainHostdevSubsysPciBackendType)
-            dev->source.subsys.u.pci.backend) {
-    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
+    /* caller has to assign proper passthrough backend type */
+    switch ((virDomainHostdevSubsysPciBackendType) backend) {
     case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
         virBufferAddLit(&buf, "pci-assign");
         if (configfd && *configfd)
@@ -5498,9 +5498,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",
-                       _("PCI passhthrough type needs to be specified"));
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("invalid PCI passthrough type '%s'"),
+                       virDomainHostdevSubsysPciBackendTypeToString(backend));
         break;
     }
 
index 7f3170d5f8e6a5c9bb3bc30a63c693468ee5f206..81e0e8848c2fd0da20623b260484f0f1f1a2b285 100644 (file)
@@ -564,7 +564,8 @@ qemuHostdevHostSupportsPassthroughLegacy(void)
 
 static bool
 qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
-                                  size_t nhostdevs)
+                                  size_t nhostdevs,
+                                  virQEMUCapsPtr qemuCaps)
 {
     bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
     bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
@@ -581,6 +582,23 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
             continue;
 
         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",
@@ -589,7 +607,6 @@ qemuPrepareHostdevPCICheckSupport(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",
@@ -613,7 +630,8 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
                              const char *name,
                              const unsigned char *uuid,
                              virDomainHostdevDefPtr *hostdevs,
-                             int nhostdevs)
+                             int nhostdevs,
+                             virQEMUCapsPtr qemuCaps)
 {
     virPCIDeviceListPtr pcidevs;
     int last_processed_hostdev_vf = -1;
@@ -621,7 +639,7 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
     int ret = -1;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
 
-    if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs))
+    if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps))
         goto cleanup;
 
     virObjectLock(driver->activePciHostdevs);
@@ -1142,13 +1160,15 @@ cleanup:
 int
 qemuPrepareHostDevices(virQEMUDriverPtr driver,
                        virDomainDefPtr def,
+                       virQEMUCapsPtr qemuCaps,
                        bool coldBoot)
 {
     if (!def->nhostdevs)
         return 0;
 
     if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
-                                     def->hostdevs, def->nhostdevs) < 0)
+                                     def->hostdevs, def->nhostdevs,
+                                     qemuCaps) < 0)
         return -1;
 
     if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
index 327d4d567979bf4ab433c100114838da314208e5..272086effa97ba1c34ad53b248ff09a6650930cf 100644 (file)
@@ -37,7 +37,8 @@ int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
                                  const char *name,
                                  const unsigned char *uuid,
                                  virDomainHostdevDefPtr *hostdevs,
-                                 int nhostdevs);
+                                 int nhostdevs,
+                                 virQEMUCapsPtr qemuCaps);
 int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
                              bool mandatory,
                              virUSBDevicePtr *usb);
@@ -50,6 +51,7 @@ int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
                                   int nhostdevs);
 int qemuPrepareHostDevices(virQEMUDriverPtr driver,
                            virDomainDefPtr def,
+                           virQEMUCapsPtr qemuCaps,
                            bool coldBoot);
 void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
                                        const char *name,
index 71c78226b7bb4f3128552115151b123e68eb8d4d..b6ae21870edbdb85ffd52c9e9e2b35948ef4422e 100644 (file)
@@ -1140,7 +1140,7 @@ int qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver,
         return -1;
 
     if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
-                                     &hostdev, 1) < 0)
+                                     &hostdev, 1, priv->qemuCaps) < 0)
         return -1;
 
     switch ((virDomainHostdevSubsysPciBackendType) backend) {
index 079f062bcd6613f4d66d13160574c43386ba1558..354e079a7559293d35034382e3634e2cbb27e074 100644 (file)
@@ -3567,6 +3567,12 @@ int qemuProcessStart(virConnectPtr conn,
             goto cleanup;
     }
 
+    VIR_DEBUG("Determining emulator version");
+    virObjectUnref(priv->qemuCaps);
+    if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache,
+                                                      vm->def->emulator)))
+        goto cleanup;
+
     /* network devices must be "prepared" before hostdevs, because
      * setting up a network device might create a new hostdev that
      * will need to be setup.
@@ -3577,7 +3583,8 @@ int qemuProcessStart(virConnectPtr conn,
 
     /* Must be run before security labelling */
     VIR_DEBUG("Preparing host devices");
-    if (qemuPrepareHostDevices(driver, vm->def, !migrateFrom) < 0)
+    if (qemuPrepareHostDevices(driver, vm->def, priv->qemuCaps,
+                               !migrateFrom) < 0)
         goto cleanup;
 
     VIR_DEBUG("Preparing chr devices");
@@ -3659,12 +3666,6 @@ int qemuProcessStart(virConnectPtr conn,
         }
     }
 
-    VIR_DEBUG("Determining emulator version");
-    virObjectUnref(priv->qemuCaps);
-    if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache,
-                                                      vm->def->emulator)))
-        goto cleanup;
-
     if (!qemuValidateCpuMax(vm->def, priv->qemuCaps))
         goto cleanup;
 
index 286f1a362838838863d47feb2ab73eead64ea871..060acf29bad95ed71a4a567eeef5cf17ebcfadeb 100644 (file)
@@ -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,