Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 82 ++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 4 ++ src/qemu/qemu_driver.c | 102 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6c583b0..4bf57a4 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -437,6 +437,7 @@ virDomainVideoTypeFromString; virDomainVideoTypeToString; virDomainVirtioEventIdxTypeFromString; virDomainVirtioEventIdxTypeToString; +virDomainVirtTypeFromString; virDomainVirtTypeToString; virDomainWatchdogActionTypeFromString; virDomainWatchdogActionTypeToString; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 8e0a550..0a1f6fc 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -39,6 +39,7 @@ #include "virnodesuspend.h" #include "qemu_monitor.h" #include "virstring.h" +#include "qemu_hostdev.h" #include <fcntl.h> #include <sys/stat.h> @@ -3509,3 +3510,84 @@ virQEMUCapsSupportsChardev(virDomainDefPtr def, (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO)); } + + +static void +virQEMUCapsFillDomainDeviceDiskCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsDeviceDiskPtr disk) +{ + disk->device.supported = true; + /* QEMU supports all of these */ + disk->diskDevice.values = (1 << VIR_DOMAIN_DISK_DEVICE_DISK) | + (1 << VIR_DOMAIN_DISK_DEVICE_CDROM) | + (1 << VIR_DOMAIN_DISK_DEVICE_FLOPPY) | + (1 << VIR_DOMAIN_DISK_DEVICE_LUN); + + disk->bus.values = (1 << VIR_DOMAIN_DISK_BUS_IDE) | + (1 << VIR_DOMAIN_DISK_BUS_FDC) | + (1 << VIR_DOMAIN_DISK_BUS_SCSI) | + (1 << VIR_DOMAIN_DISK_BUS_VIRTIO) | + (1 << VIR_DOMAIN_DISK_BUS_XEN) | + (1 << VIR_DOMAIN_DISK_BUS_SD); + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE)) + disk->bus.values |= (1 << VIR_DOMAIN_DISK_BUS_USB); +} + + +static void +virQEMUCapsFillDomainDeviceHostdevCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsDeviceHostdevPtr hostdev) +{ + bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy(); + bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO(); + + hostdev->device.supported = true; + /* VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES is for containers only */ + hostdev->subsysType.values = (1 << VIR_DOMAIN_HOSTDEV_MODE_SUBSYS); + + hostdev->startupPolicy.values = (1 << VIR_DOMAIN_STARTUP_POLICY_DEFAULT) | + (1 << VIR_DOMAIN_STARTUP_POLICY_MANDATORY) | + (1 << VIR_DOMAIN_STARTUP_POLICY_REQUISITE) | + (1 << VIR_DOMAIN_STARTUP_POLICY_OPTIONAL); + + hostdev->subsysType.values = (1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) | + (1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) + hostdev->subsysType.values |= 1 << VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI; + + /* No virDomainHostdevCapsType for QEMU */ + hostdev->capsType.values = 0; + + hostdev->pciBackend.values = 0; + if (supportsPassthroughVFIO && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) { + hostdev->pciBackend.values |= (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) | + (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO); + + } + + if (supportsPassthroughKVM && + (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE) || + virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) { + hostdev->pciBackend.values |= (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) | + (1 << VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM); + } +} + + +void +virQEMUCapsFillDomainCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsPtr domCaps) +{ + virDomainCapsDeviceDiskPtr disk = &domCaps->disk; + virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev; + int maxvcpus = virQEMUCapsGetMachineMaxCpus(qemuCaps, domCaps->machine); + + domCaps->maxvcpus = maxvcpus; + + virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, disk); + virQEMUCapsFillDomainDeviceHostdevCaps(qemuCaps, hostdev); +} diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 53ebe90..bb59172 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -28,6 +28,7 @@ # include "capabilities.h" # include "vircommand.h" # include "qemu_monitor.h" +# include "domain_capabilities.h" /* Internal flags to keep track of qemu command line capabilities */ typedef enum { @@ -307,4 +308,7 @@ int virQEMUCapsInitGuestFromBinary(virCapsPtr caps, virQEMUCapsPtr kvmbinCaps, virArch guestarch); +void virQEMUCapsFillDomainCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsPtr domCaps); + #endif /* __QEMU_CAPABILITIES_H__*/ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d34da6f..96a9f13 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -95,6 +95,7 @@ #include "viraccessapicheckqemu.h" #include "storage/storage_driver.h" #include "virhostdev.h" +#include "domain_capabilities.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -16902,6 +16903,106 @@ qemuNodeGetFreePages(virConnectPtr conn, } +static char * +qemuConnectGetDomainCapabilities(virConnectPtr conn, + const char *emulatorbin, + const char *arch_str, + const char *machine, + const char *virttype_str, + unsigned int flags) +{ + char *ret = NULL; + virQEMUDriverPtr driver = conn->privateData; + virQEMUCapsPtr qemuCaps = NULL; + int virttype; /* virDomainVirtType */ + size_t ncanonicalMachine, i; + const char **canonicalMachine; + virDomainCapsPtr domCaps = NULL; + int arch; /* virArch */ + + virCheckFlags(0, ret); + virCheckNonNullArgReturn(emulatorbin, ret); + virCheckNonNullArgReturn(virttype_str, ret); + + if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0) + return ret; + + if ((virttype = virDomainVirtTypeFromString(virttype_str)) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown virttype: %s"), virttype_str); + goto cleanup; + } + + if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, + emulatorbin))) + goto cleanup; + + if (machine) { + const char *machine_tmp; + + if (!(machine_tmp = virQEMUCapsGetCanonicalMachine(qemuCaps, + machine))) { + /* This should never ever happen (TM) */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("an error that should never " + "ever happen just occurred")); + goto cleanup; + } + machine = machine_tmp; + } + + /* The virQEMUCapsGetMachineTypes expects char *** but we want to stress + * the fact that we are not going to change machine types array, so we are + * using const char *** */ + if (!(ncanonicalMachine = virQEMUCapsGetMachineTypes(qemuCaps, + (char ***) &canonicalMachine))) { + virReportError(VIR_ERR_INVALID_ARG, + _(" emulator doesn't support any machines: %s"), + emulatorbin); + goto cleanup; + } + + if (machine) { + for (i = 0; i < ncanonicalMachine; i++) { + if (STREQ(machine, canonicalMachine[i])) + break; + } + + if (i == ncanonicalMachine) { + virReportError(VIR_ERR_INVALID_ARG, + _("the machine '%s' is not supported by emulator '%s'"), + machine, emulatorbin); + goto cleanup; + } + } else { + /* The default machine type is at the first position */ + machine = canonicalMachine[0]; + } + + if (arch_str) { + if ((arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown architecture: %s"), + arch_str); + goto cleanup; + } + } else { + arch = virQEMUCapsGetArch(qemuCaps); + } + + if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype))) + goto cleanup; + + virQEMUCapsFillDomainCaps(qemuCaps, domCaps); + + ret = virDomainCapsFormat(domCaps); + cleanup: + virObjectUnref(domCaps); + virObjectUnref(qemuCaps); + return ret; +} + + static virDriver qemuDriver = { .no = VIR_DRV_QEMU, .name = QEMU_DRIVER_NAME, @@ -17097,6 +17198,7 @@ static virDriver qemuDriver = { .domainGetTime = qemuDomainGetTime, /* 1.2.5 */ .domainSetTime = qemuDomainSetTime, /* 1.2.5 */ .nodeGetFreePages = qemuNodeGetFreePages, /* 1.2.6 */ + .connectGetDomainCapabilities = qemuConnectGetDomainCapabilities, /* 1.2.6 */ }; -- 1.8.5.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list