提交 94e3f23e 编写于 作者: M Michal Privoznik

qemu: Implement virConnectGetDomainCapabilities

So far only information on disks and host devices are exposed in the
capabilities XML. Well, at least something. Even a new test is
introduced. The qemu capabilities are stolen from already existing
qemucapabilities test. There's one tricky point though. Functions that
checks host's KVM and VFIO capabilities, are impossible to mock
currently. So in the test, we are setting the capabilities by hand.
Signed-off-by: NMichal Privoznik <mprivozn@redhat.com>
上级 cb01d2b5
......@@ -439,6 +439,7 @@ virDomainVideoTypeFromString;
virDomainVideoTypeToString;
virDomainVirtioEventIdxTypeFromString;
virDomainVirtioEventIdxTypeToString;
virDomainVirtTypeFromString;
virDomainVirtTypeToString;
virDomainWatchdogActionTypeFromString;
virDomainWatchdogActionTypeToString;
......
......@@ -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>
......@@ -3565,3 +3566,92 @@ virQEMUCapsGetDefaultMachine(virQEMUCapsPtr qemuCaps)
return NULL;
return qemuCaps->machineTypes[0];
}
static void
virQEMUCapsFillDomainDeviceDiskCaps(virQEMUCapsPtr qemuCaps,
virDomainCapsDeviceDiskPtr disk)
{
disk->device.supported = true;
/* QEMU supports all of these */
VIR_DOMAIN_CAPS_ENUM_SET(disk->diskDevice,
VIR_DOMAIN_DISK_DEVICE_DISK,
VIR_DOMAIN_DISK_DEVICE_CDROM,
VIR_DOMAIN_DISK_DEVICE_FLOPPY);
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SG_IO))
VIR_DOMAIN_CAPS_ENUM_SET(disk->diskDevice, VIR_DOMAIN_DISK_DEVICE_LUN);
VIR_DOMAIN_CAPS_ENUM_SET(disk->bus,
VIR_DOMAIN_DISK_BUS_IDE,
VIR_DOMAIN_DISK_BUS_FDC,
VIR_DOMAIN_DISK_BUS_SCSI,
VIR_DOMAIN_DISK_BUS_VIRTIO,
/* VIR_DOMAIN_DISK_BUS_SD */);
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE))
VIR_DOMAIN_CAPS_ENUM_SET(disk->bus, 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 */
VIR_DOMAIN_CAPS_ENUM_SET(hostdev->mode,
VIR_DOMAIN_HOSTDEV_MODE_SUBSYS);
VIR_DOMAIN_CAPS_ENUM_SET(hostdev->startupPolicy,
VIR_DOMAIN_STARTUP_POLICY_DEFAULT,
VIR_DOMAIN_STARTUP_POLICY_MANDATORY,
VIR_DOMAIN_STARTUP_POLICY_REQUISITE,
VIR_DOMAIN_STARTUP_POLICY_OPTIONAL);
VIR_DOMAIN_CAPS_ENUM_SET(hostdev->subsysType,
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB,
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI);
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE) &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE) &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC))
VIR_DOMAIN_CAPS_ENUM_SET(hostdev->subsysType,
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI);
/* No virDomainHostdevCapsType for QEMU */
virDomainCapsEnumClear(&hostdev->capsType);
virDomainCapsEnumClear(&hostdev->pciBackend);
if (supportsPassthroughVFIO &&
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
VIR_DOMAIN_CAPS_ENUM_SET(hostdev->pciBackend,
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT,
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO);
}
if (supportsPassthroughKVM &&
(virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE) ||
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
VIR_DOMAIN_CAPS_ENUM_SET(hostdev->pciBackend,
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT,
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM);
}
}
void
virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
virQEMUCapsPtr qemuCaps)
{
virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev;
int maxvcpus = virQEMUCapsGetMachineMaxCpus(qemuCaps, domCaps->machine);
domCaps->maxvcpus = maxvcpus;
virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, disk);
virQEMUCapsFillDomainDeviceHostdevCaps(qemuCaps, hostdev);
}
......@@ -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 {
......@@ -314,4 +315,7 @@ int virQEMUCapsInitGuestFromBinary(virCapsPtr caps,
virQEMUCapsPtr kvmbinCaps,
virArch guestarch);
void virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
virQEMUCapsPtr qemuCaps);
#endif /* __QEMU_CAPABILITIES_H__*/
......@@ -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
......@@ -16885,6 +16886,105 @@ 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 */
virDomainCapsPtr domCaps = NULL;
int arch = VIR_ARCH_NONE; /* virArch */
virCheckFlags(0, 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 (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) {
virReportError(VIR_ERR_INVALID_ARG,
_("unknown architecture: %s"),
arch_str);
goto cleanup;
}
if (emulatorbin) {
virArch arch_from_caps;
if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache,
emulatorbin)))
goto cleanup;
arch_from_caps = virQEMUCapsGetArch(qemuCaps);
if (arch == VIR_ARCH_NONE)
arch = arch_from_caps;
if (arch_from_caps != arch) {
virReportError(VIR_ERR_INVALID_ARG,
_("architecture from emulator '%s' doesn't "
"match given architecture '%s'"),
virArchToString(arch_from_caps),
virArchToString(arch));
goto cleanup;
}
} else if (arch_str) {
if (!(qemuCaps = virQEMUCapsCacheLookupByArch(driver->qemuCapsCache,
arch)))
goto cleanup;
if (!emulatorbin)
emulatorbin = virQEMUCapsGetBinary(qemuCaps);
/* Deliberately not checking if provided @emulatorbin matches @arch,
* since if @emulatorbin was specified the match has been checked a few
* lines above. */
} else {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("at least one of emulatorbin or "
"architecture fields must be present"));
goto cleanup;
}
if (machine) {
/* Turn @machine into canonical name */
machine = virQEMUCapsGetCanonicalMachine(qemuCaps, machine);
if (!virQEMUCapsIsMachineSupported(qemuCaps, machine)) {
virReportError(VIR_ERR_INVALID_ARG,
_("the machine '%s' is not supported by emulator '%s'"),
machine, emulatorbin);
goto cleanup;
}
} else {
machine = virQEMUCapsGetDefaultMachine(qemuCaps);
}
if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
goto cleanup;
virQEMUCapsFillDomainCaps(domCaps, qemuCaps);
ret = virDomainCapsFormat(domCaps);
cleanup:
virObjectUnref(domCaps);
virObjectUnref(qemuCaps);
return ret;
}
static virDriver qemuDriver = {
.no = VIR_DRV_QEMU,
.name = QEMU_DRIVER_NAME,
......@@ -17080,6 +17180,7 @@ static virDriver qemuDriver = {
.domainGetTime = qemuDomainGetTime, /* 1.2.5 */
.domainSetTime = qemuDomainSetTime, /* 1.2.5 */
.nodeGetFreePages = qemuNodeGetFreePages, /* 1.2.6 */
.connectGetDomainCapabilities = qemuConnectGetDomainCapabilities, /* 1.2.7 */
};
......
......@@ -835,6 +835,11 @@ domaincapstest_SOURCES = \
domaincapstest.c testutils.h testutils.c
domaincapstest_LDADD = $(LDADDS)
if WITH_QEMU
domaincapstest_SOURCES += testutilsqemu.c testutilsqemu.h
domaincapstest_LDADD += $(qemu_LDADDS)
endif WITH_QEMU
if WITH_LIBVIRTD
libvirtdconftest_SOURCES = \
libvirtdconftest.c testutils.h testutils.c \
......
<domainCapabilities>
<path>/usr/bin/qemu-system-x86_64</path>
<domain>kvm</domain>
<machine>pc-1.2</machine>
<arch>x86_64</arch>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
<value>disk</value>
<value>cdrom</value>
<value>floppy</value>
<value>lun</value>
</enum>
<enum name='bus'>
<value>ide</value>
<value>fdc</value>
<value>scsi</value>
<value>virtio</value>
<value>usb</value>
</enum>
</disk>
<hostdev supported='yes'>
<enum name='mode'>
<value>subsystem</value>
</enum>
<enum name='startupPolicy'>
<value>default</value>
<value>mandatory</value>
<value>requisite</value>
<value>optional</value>
</enum>
<enum name='subsysType'>
<value>usb</value>
<value>pci</value>
<value>scsi</value>
</enum>
<enum name='capsType'/>
<enum name='pciBackend'>
<value>default</value>
<value>kvm</value>
<value>vfio</value>
</enum>
</hostdev>
</devices>
</domainCapabilities>
......@@ -54,6 +54,30 @@ fillAll(virDomainCapsPtr domCaps,
SET_ALL_BITS(hostdev->pciBackend);
}
#ifdef WITH_QEMU
# include "testutilsqemu.h"
static void
fillQemuCaps(virDomainCapsPtr domCaps,
void *opaque)
{
virQEMUCapsPtr qemuCaps = (virQEMUCapsPtr) opaque;
virQEMUCapsFillDomainCaps(domCaps, qemuCaps);
/* The function above tries to query host's KVM & VFIO capabilities by
* calling qemuHostdevHostSupportsPassthroughLegacy() and
* qemuHostdevHostSupportsPassthroughVFIO() which, however, can't be
* successfully mocked as they are not exposed as internal APIs. Therefore,
* instead of mocking set the expected values here by hand. */
VIR_DOMAIN_CAPS_ENUM_SET(domCaps->hostdev.pciBackend,
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT,
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM,
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO);
}
#endif /* WITH_QEMU */
static virDomainCapsPtr
buildVirDomainCaps(const char *emulatorbin,
const char *machine,
......@@ -143,6 +167,27 @@ mymain(void)
DO_TEST("full", "/bin/emulatorbin", "my-machine-type",
VIR_ARCH_X86_64, VIR_DOMAIN_VIRT_KVM, .fillFunc = fillAll);
#ifdef WITH_QEMU
# define DO_TEST_QEMU(Filename, QemuCapsFile, Emulatorbin, Machine, Arch, Type, ...) \
do { \
const char *capsPath = abs_srcdir "/qemucapabilitiesdata/" QemuCapsFile ".caps"; \
virQEMUCapsPtr qemuCaps = qemuTestParseCapabilities(capsPath); \
struct test_virDomainCapsFormatData data = {.filename = Filename, \
.emulatorbin = Emulatorbin, .machine = Machine, .arch = Arch, \
.type = Type, .fillFunc = fillQemuCaps, .opaque = qemuCaps}; \
if (!qemuCaps) { \
fprintf(stderr, "Unable to build qemu caps from %s\n", capsPath); \
ret = -1; \
} else if (virtTestRun(Filename, test_virDomainCapsFormat, &data) < 0) \
ret = -1; \
} while (0)
DO_TEST_QEMU("qemu_1.6.50-1", "caps_1.6.50-1", "/usr/bin/qemu-system-x86_64",
"pc-1.2", VIR_ARCH_X86_64, VIR_DOMAIN_VIRT_KVM);
#endif /* WITH_QEMU */
return ret;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册