1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-23 21:34:54 +03:00

qemu: Prefer VFIO for PCI device passthrough

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.
This commit is contained in:
Peter Krempa 2013-09-20 10:39:51 +02:00
parent 467b561ac2
commit f094aaac48
9 changed files with 61 additions and 25 deletions

View File

@ -2757,11 +2757,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

View 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 */

View File

@ -262,6 +262,7 @@ virDomainHostdevFind;
virDomainHostdevInsert;
virDomainHostdevModeTypeToString;
virDomainHostdevRemove;
virDomainHostdevSubsysPciBackendTypeToString;
virDomainHostdevSubsysTypeToString;
virDomainHubTypeFromString;
virDomainHubTypeToString;

View 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;
}

View 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)

View 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,

View 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) {

View 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;

View 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,