Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
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