mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-24 22:55:23 +00: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:
parent
467b561ac2
commit
f094aaac48
@ -2757,11 +2757,10 @@
|
|||||||
backend, which is compatible with UEFI SecureBoot) or "kvm"
|
backend, which is compatible with UEFI SecureBoot) or "kvm"
|
||||||
(for the legacy device assignment handled directly by the KVM
|
(for the legacy device assignment handled directly by the KVM
|
||||||
kernel module)<span class="since">Since 1.0.5 (QEMU and KVM
|
kernel module)<span class="since">Since 1.0.5 (QEMU and KVM
|
||||||
only, requires kernel 3.6 or newer)</span>. Currently, "kvm"
|
only, requires kernel 3.6 or newer)</span>. The default, when
|
||||||
is the default used by libvirt when not explicitly provided,
|
the driver name is not explicitly specified, is to check wether
|
||||||
but since the two are functionally equivalent, this default
|
VFIO is available and use it if it's the case. If VFIO is not
|
||||||
could be changed in the future with no impact to domains that
|
available, the legacy "kvm" assignment is attempted.
|
||||||
don't specify anything.
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>readonly</code></dt>
|
<dt><code>readonly</code></dt>
|
||||||
<dd>Indicates that the device is readonly, only supported by SCSI host
|
<dd>Indicates that the device is readonly, only supported by SCSI host
|
||||||
|
@ -399,7 +399,7 @@ enum virDomainHostdevSubsysType {
|
|||||||
|
|
||||||
/* the backend driver used for PCI hostdev devices */
|
/* the backend driver used for PCI hostdev devices */
|
||||||
typedef enum {
|
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_KVM, /* force legacy kvm style */
|
||||||
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO, /* force vfio */
|
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO, /* force vfio */
|
||||||
|
|
||||||
|
@ -262,6 +262,7 @@ virDomainHostdevFind;
|
|||||||
virDomainHostdevInsert;
|
virDomainHostdevInsert;
|
||||||
virDomainHostdevModeTypeToString;
|
virDomainHostdevModeTypeToString;
|
||||||
virDomainHostdevRemove;
|
virDomainHostdevRemove;
|
||||||
|
virDomainHostdevSubsysPciBackendTypeToString;
|
||||||
virDomainHostdevSubsysTypeToString;
|
virDomainHostdevSubsysTypeToString;
|
||||||
virDomainHubTypeFromString;
|
virDomainHubTypeFromString;
|
||||||
virDomainHubTypeToString;
|
virDomainHubTypeToString;
|
||||||
|
@ -5484,10 +5484,10 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
|
|||||||
virQEMUCapsPtr qemuCaps)
|
virQEMUCapsPtr qemuCaps)
|
||||||
{
|
{
|
||||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
int backend = dev->source.subsys.u.pci.backend;
|
||||||
|
|
||||||
switch ((virDomainHostdevSubsysPciBackendType)
|
/* caller has to assign proper passthrough backend type */
|
||||||
dev->source.subsys.u.pci.backend) {
|
switch ((virDomainHostdevSubsysPciBackendType) backend) {
|
||||||
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
|
|
||||||
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
|
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
|
||||||
virBufferAddLit(&buf, "pci-assign");
|
virBufferAddLit(&buf, "pci-assign");
|
||||||
if (configfd && *configfd)
|
if (configfd && *configfd)
|
||||||
@ -5498,9 +5498,11 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
|
|||||||
virBufferAddLit(&buf, "vfio-pci");
|
virBufferAddLit(&buf, "vfio-pci");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
|
||||||
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
|
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
_("PCI passhthrough type needs to be specified"));
|
_("invalid PCI passthrough type '%s'"),
|
||||||
|
virDomainHostdevSubsysPciBackendTypeToString(backend));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,7 +564,8 @@ qemuHostdevHostSupportsPassthroughLegacy(void)
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
|
qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
|
||||||
size_t nhostdevs)
|
size_t nhostdevs,
|
||||||
|
virQEMUCapsPtr qemuCaps)
|
||||||
{
|
{
|
||||||
bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
|
bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
|
||||||
bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
|
bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
|
||||||
@ -581,6 +582,23 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch ((virDomainHostdevSubsysPciBackendType) *backend) {
|
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:
|
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
|
||||||
if (!supportsPassthroughVFIO) {
|
if (!supportsPassthroughVFIO) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
@ -589,7 +607,6 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
|
|
||||||
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
|
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
|
||||||
if (!supportsPassthroughKVM) {
|
if (!supportsPassthroughKVM) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
@ -613,7 +630,8 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
|
|||||||
const char *name,
|
const char *name,
|
||||||
const unsigned char *uuid,
|
const unsigned char *uuid,
|
||||||
virDomainHostdevDefPtr *hostdevs,
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
int nhostdevs)
|
int nhostdevs,
|
||||||
|
virQEMUCapsPtr qemuCaps)
|
||||||
{
|
{
|
||||||
virPCIDeviceListPtr pcidevs;
|
virPCIDeviceListPtr pcidevs;
|
||||||
int last_processed_hostdev_vf = -1;
|
int last_processed_hostdev_vf = -1;
|
||||||
@ -621,7 +639,7 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
|
|||||||
int ret = -1;
|
int ret = -1;
|
||||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||||
|
|
||||||
if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs))
|
if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
virObjectLock(driver->activePciHostdevs);
|
virObjectLock(driver->activePciHostdevs);
|
||||||
@ -1142,13 +1160,15 @@ cleanup:
|
|||||||
int
|
int
|
||||||
qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
|
virQEMUCapsPtr qemuCaps,
|
||||||
bool coldBoot)
|
bool coldBoot)
|
||||||
{
|
{
|
||||||
if (!def->nhostdevs)
|
if (!def->nhostdevs)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
|
if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
|
||||||
def->hostdevs, def->nhostdevs) < 0)
|
def->hostdevs, def->nhostdevs,
|
||||||
|
qemuCaps) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
|
if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
|
||||||
|
@ -37,7 +37,8 @@ int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
|
|||||||
const char *name,
|
const char *name,
|
||||||
const unsigned char *uuid,
|
const unsigned char *uuid,
|
||||||
virDomainHostdevDefPtr *hostdevs,
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
int nhostdevs);
|
int nhostdevs,
|
||||||
|
virQEMUCapsPtr qemuCaps);
|
||||||
int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
|
int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
|
||||||
bool mandatory,
|
bool mandatory,
|
||||||
virUSBDevicePtr *usb);
|
virUSBDevicePtr *usb);
|
||||||
@ -50,6 +51,7 @@ int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
|
|||||||
int nhostdevs);
|
int nhostdevs);
|
||||||
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
|
virQEMUCapsPtr qemuCaps,
|
||||||
bool coldBoot);
|
bool coldBoot);
|
||||||
void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
|
void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
@ -1140,7 +1140,7 @@ int qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver,
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
|
if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
|
||||||
&hostdev, 1) < 0)
|
&hostdev, 1, priv->qemuCaps) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch ((virDomainHostdevSubsysPciBackendType) backend) {
|
switch ((virDomainHostdevSubsysPciBackendType) backend) {
|
||||||
|
@ -3567,6 +3567,12 @@ int qemuProcessStart(virConnectPtr conn,
|
|||||||
goto cleanup;
|
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
|
/* network devices must be "prepared" before hostdevs, because
|
||||||
* setting up a network device might create a new hostdev that
|
* setting up a network device might create a new hostdev that
|
||||||
* will need to be setup.
|
* will need to be setup.
|
||||||
@ -3577,7 +3583,8 @@ int qemuProcessStart(virConnectPtr conn,
|
|||||||
|
|
||||||
/* Must be run before security labelling */
|
/* Must be run before security labelling */
|
||||||
VIR_DEBUG("Preparing host devices");
|
VIR_DEBUG("Preparing host devices");
|
||||||
if (qemuPrepareHostDevices(driver, vm->def, !migrateFrom) < 0)
|
if (qemuPrepareHostDevices(driver, vm->def, priv->qemuCaps,
|
||||||
|
!migrateFrom) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
VIR_DEBUG("Preparing chr devices");
|
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))
|
if (!qemuValidateCpuMax(vm->def, priv->qemuCaps))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
@ -98,6 +98,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
|
|||||||
virConnectPtr conn;
|
virConnectPtr conn;
|
||||||
char *log = NULL;
|
char *log = NULL;
|
||||||
virCommandPtr cmd = NULL;
|
virCommandPtr cmd = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (!(conn = virGetConnect()))
|
if (!(conn = virGetConnect()))
|
||||||
goto out;
|
goto out;
|
||||||
@ -154,6 +155,16 @@ static int testCompareXMLToArgvFiles(const char *xml,
|
|||||||
if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0)
|
if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0)
|
||||||
goto out;
|
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,
|
if (!(cmd = qemuBuildCommandLine(conn, &driver, vmdef, &monitor_chr,
|
||||||
(flags & FLAG_JSON), extraFlags,
|
(flags & FLAG_JSON), extraFlags,
|
||||||
migrateFrom, migrateFd, NULL,
|
migrateFrom, migrateFd, NULL,
|
||||||
|
Loading…
Reference in New Issue
Block a user