[libvirt] [PATCH RFC 4/4] qemu: Implement virConnectGetDomainCapabilities

Michal Privoznik mprivozn at redhat.com
Thu Jun 26 10:18:28 UTC 2014


Signed-off-by: Michal Privoznik <mprivozn at 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




More information about the libvir-list mailing list