From 614581f32ba14311b06821e6f8279d431a6ca840 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Wed, 25 Jun 2014 13:24:53 +0200 Subject: [PATCH] Introduce domain_capabilities This new module holds and formats capabilities for emulator. If you are about to create a new domain, you may want to know what is the host or hypervisor capable of. To make sure we don't regress on the XML, the formatting is not something left for each driver to implement, rather there's general format function. The domain capabilities is a lockable object (even though the locking is not necessary yet) which uses reference counter. Signed-off-by: Michal Privoznik --- docs/formatdomaincaps.html.in | 232 ++++++++++++++++ docs/schemas/Makefile.am | 1 + docs/schemas/domaincaps.rng | 90 +++++++ docs/sitemap.html.in | 4 + libvirt.spec.in | 1 + mingw-libvirt.spec.in | 2 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/conf/domain_capabilities.c | 254 ++++++++++++++++++ src/conf/domain_capabilities.h | 103 +++++++ src/libvirt_private.syms | 7 + tests/Makefile.am | 8 + .../domaincapsschemadata/domaincaps-basic.xml | 10 + .../domaincapsschemadata/domaincaps-full.xml | 56 ++++ tests/domaincapsschematest | 11 + tests/domaincapstest.c | 149 ++++++++++ 16 files changed, 930 insertions(+) create mode 100644 docs/formatdomaincaps.html.in create mode 100644 docs/schemas/domaincaps.rng create mode 100644 src/conf/domain_capabilities.c create mode 100644 src/conf/domain_capabilities.h create mode 100644 tests/domaincapsschemadata/domaincaps-basic.xml create mode 100644 tests/domaincapsschemadata/domaincaps-full.xml create mode 100755 tests/domaincapsschematest create mode 100644 tests/domaincapstest.c diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in new file mode 100644 index 0000000000..66b6017742 --- /dev/null +++ b/docs/formatdomaincaps.html.in @@ -0,0 +1,232 @@ + + + + +

Domain capabilities XML format

+ + + +

Overview

+ +

Sometimes, when a new domain is to be created it may come handy to know + the capabilities of the hypervisor so the correct combination of devices and + drivers is used. For example, when management application is considering the + mode for a host device's passthrough there are several options depending not + only on host, but on hypervisor in question too. If the hypervisor is qemu + then it needs to be more recent to support VFIO, while legacy KVM is + achievable just fine with older qemus.

+ +

The main difference between virConnectGetCapabilities and the emulator + capabilities API is, the former one aims more on the host capabilities + (e.g. NUMA topology, security models in effect, etc.) while the latter one + specializes on the hypervisor capabilities.

+ +

While the Driver Capabilities provides the + host capabilities (e.g NUMA topology, security models in effect, etc.), the + Domain Capabilities provides the hypervisor specific capabilities for + Management Applications to query and make decisions regarding what to + utilize.

+ +

The Domain Capabilities can provide information such as the correct + combination of devices and drivers that are supported. Knowing which host + and hypervisor specific options are available or supported would allow the + management application to choose an appropriate mode for a pass-through + host device as well as which adapter to utilize.

+ +

Element and attribute overview

+ +

A new query interface was added to the virConnect API's to retrieve the + XML listing of the set of domain capabilities (Since + 1.2.7):

+ +
+    virConnectGetDomainCapabilities
+
+ +

The root element that emulator capability XML document starts with has + name domainCapabilities. It contains at least four direct + child elements:

+ +
+<domainCapabilities>
+  <path>/usr/bin/qemu-system-x86_64</path>
+  <domain>kvm</domain>
+  <machine>pc-i440fx-2.1</machine>
+  <arch>x86_64</arch>
+  ...
+</domainCapabilities>
+
+
+
path
+
The full path to the emulator binary.
+ +
domain
+
Describes the virtualization + type (or so called domain type).
+ +
machine
+
The domain's machine + type.
+ +
arch
+
The domain's + architecture.
+ +
+ +

CPU Allocation

+ +

Before any devices capability occurs, there might be a info on domain + wide capabilities, e.g. virtual CPUs:

+ +
+<domainCapabilities>
+  ...
+  <vcpu max='255'/>
+  ...
+</domainCapabilities>
+
+ +
+
vcpu
+
The maximum number of supported virtual CPUs
+
+ +

Devices

+ +

+ The final set of XML elements describe the supported devices and their + capabilities. All devices occur as children of the main + devices element. +

+ +
+<domainCapabilities>
+  ...
+  <devices>
+    <disk supported='yes'>
+      <enum name='diskDevice'>
+        <value>disk</value>
+        <value>cdrom</value>
+        <value>floppy</value>
+        <value>lun</value>
+      </enum>
+      ...
+    </disk>
+    <hostdev supported='no'/>
+  </devices>
+</domainCapabilities>
+
+ +

Reported capabilities are expressed as an enumerated list of available + options for each of the element or attribute. For example, the + <disk/> element has an attribute device which can + support the values disk, cdrom, + floppy, or lun.

+ +

Hard drives, floppy disks, CDROMs

+

Disk capabilities are exposed under disk element. For + instance:

+ +
+<domainCapabilities>
+  ...
+  <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>xen</value>
+        <value>usb</value>
+        <value>uml</value>
+        <value>sata</value>
+        <value>sd</value>
+      </enum>
+    </disk>
+    ...
+  </devices>
+</domainCapabilities>
+
+ +
+
diskDevice
+
Options for the device attribute of the <disk/> + element.
+ +
bus
+
Options for the bus attribute of the <target/> + element for a <disk/>.
+
+ +

Host device assignment

+

Some host devices can be passed through to a guest (e.g. USB, PCI and + SCSI). Well, only if the following is enabled:

+ +
+<domainCapabilities>
+  ...
+  <devices>
+    <hostdev supported='yes'>
+      <enum name='mode'>
+        <value>subsystem</value>
+        <value>capabilities</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'>
+        <value>storage</value>
+        <value>misc</value>
+        <value>net</value>
+      </enum>
+      <enum name='pciBackend'>
+        <value>default</value>
+        <value>kvm</value>
+        <value>vfio</value>
+        <value>xen</value>
+      </enum>
+    </hostdev>
+  </devices>
+</domainCapabilities>
+
+ +
+
mode
+
Options for the mode attribute of the <hostdev/> + element.
+ +
startupPolicy
+
Options for the startupPolicy attribute of the + <hostdev/> element.
+ +
subsysType
+
Options for the type attribute of the <hostdev/> + element in case of mode="subsystem".
+ +
capsType
+
Options for the type attribute of the <hostdev/> + element in case of mode="capabilities".
+ +
pciBackend
+
Options for the name attribute of the <driver/> + element.
+
+ + diff --git a/docs/schemas/Makefile.am b/docs/schemas/Makefile.am index d71c327f05..0e14dc6c92 100644 --- a/docs/schemas/Makefile.am +++ b/docs/schemas/Makefile.am @@ -19,6 +19,7 @@ schema_DATA = \ basictypes.rng \ capability.rng \ domain.rng \ + domaincaps.rng \ domaincommon.rng \ domainsnapshot.rng \ interface.rng \ diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng new file mode 100644 index 0000000000..627b69998d --- /dev/null +++ b/docs/schemas/domaincaps.rng @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + yes + no + + + + + + + + + + + + + + + + + + + diff --git a/docs/sitemap.html.in b/docs/sitemap.html.in index 78e84e310c..1e918692d8 100644 --- a/docs/sitemap.html.in +++ b/docs/sitemap.html.in @@ -174,6 +174,10 @@ Capabilities The driver capabilities XML format +
  • + Domain capabilities + The domain capabilities XML format +
  • Node Devices The host device XML format diff --git a/libvirt.spec.in b/libvirt.spec.in index 8b9a1f80b3..8802746913 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -2164,6 +2164,7 @@ exit 0 %{_datadir}/libvirt/schemas/basictypes.rng %{_datadir}/libvirt/schemas/capability.rng %{_datadir}/libvirt/schemas/domain.rng +%{_datadir}/libvirt/schemas/domaincaps.rng %{_datadir}/libvirt/schemas/domaincommon.rng %{_datadir}/libvirt/schemas/domainsnapshot.rng %{_datadir}/libvirt/schemas/interface.rng diff --git a/mingw-libvirt.spec.in b/mingw-libvirt.spec.in index 91c2dc2554..a555f9cd92 100644 --- a/mingw-libvirt.spec.in +++ b/mingw-libvirt.spec.in @@ -205,6 +205,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh %{mingw32_datadir}/libvirt/schemas/basictypes.rng %{mingw32_datadir}/libvirt/schemas/capability.rng %{mingw32_datadir}/libvirt/schemas/domain.rng +%{mingw32_datadir}/libvirt/schemas/domaincaps.rng %{mingw32_datadir}/libvirt/schemas/domaincommon.rng %{mingw32_datadir}/libvirt/schemas/domainsnapshot.rng %{mingw32_datadir}/libvirt/schemas/interface.rng @@ -265,6 +266,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh %{mingw64_datadir}/libvirt/schemas/basictypes.rng %{mingw64_datadir}/libvirt/schemas/capability.rng %{mingw64_datadir}/libvirt/schemas/domain.rng +%{mingw64_datadir}/libvirt/schemas/domaincaps.rng %{mingw64_datadir}/libvirt/schemas/domaincommon.rng %{mingw64_datadir}/libvirt/schemas/domainsnapshot.rng %{mingw64_datadir}/libvirt/schemas/interface.rng diff --git a/po/POTFILES.in b/po/POTFILES.in index d338151cae..64a987ecab 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -16,6 +16,7 @@ src/conf/capabilities.c src/conf/cpu_conf.c src/conf/device_conf.c src/conf/domain_addr.c +src/conf/domain_capabilities.c src/conf/domain_conf.c src/conf/domain_event.c src/conf/interface_conf.c diff --git a/src/Makefile.am b/src/Makefile.am index 047d4c6c2e..e2f76a7496 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -248,6 +248,7 @@ NETDEV_CONF_SOURCES = \ DOMAIN_CONF_SOURCES = \ conf/capabilities.c conf/capabilities.h \ conf/domain_addr.c conf/domain_addr.h \ + conf/domain_capabilities.c conf/domain_capabilities.h \ conf/domain_conf.c conf/domain_conf.h \ conf/domain_audit.c conf/domain_audit.h \ conf/domain_nwfilter.c conf/domain_nwfilter.h \ diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c new file mode 100644 index 0000000000..df190eb108 --- /dev/null +++ b/src/conf/domain_capabilities.c @@ -0,0 +1,254 @@ +/* + * domain_capabilities.c: domain capabilities XML processing + * + * Copyright (C) 2014 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Michal Privoznik + */ + +#include + +#include "domain_capabilities.h" +#include "domain_conf.h" +#include "viralloc.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_CAPABILITIES + +static virClassPtr virDomainCapsClass; + +static void virDomainCapsDispose(void *obj); + +static int virDomainCapsOnceInit(void) +{ + if (!(virDomainCapsClass = virClassNew(virClassForObjectLockable(), + "virDomainCapsClass", + sizeof(virDomainCaps), + virDomainCapsDispose))) + return -1; + return 0; +} + + +VIR_ONCE_GLOBAL_INIT(virDomainCaps) + + +static void +virDomainCapsDispose(void *obj) +{ + virDomainCapsPtr caps = obj; + + VIR_FREE(caps->path); + VIR_FREE(caps->machine); +} + + +virDomainCapsPtr +virDomainCapsNew(const char *path, + const char *machine, + virArch arch, + virDomainVirtType virttype) +{ + virDomainCapsPtr caps = NULL; + + if (virDomainCapsInitialize() < 0) + return NULL; + + if (!(caps = virObjectLockableNew(virDomainCapsClass))) + return NULL; + + if (VIR_STRDUP(caps->path, path) < 0 || + VIR_STRDUP(caps->machine, machine) < 0) + goto error; + caps->arch = arch; + caps->virttype = virttype; + + return caps; + error: + virObjectUnref(caps); + return NULL; +} + + +int +virDomainCapsEnumSet(virDomainCapsEnumPtr capsEnum, + const char *capsEnumName, + size_t nvalues, + unsigned int *values) +{ + int ret = -1; + size_t i; + + for (i = 0; i < nvalues; i++) { + unsigned int val = 1 << values[i]; + + if (!val) { + /* Integer overflow */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("integer overflow on %s. Please contact the " + "libvirt development team at libvir-list@redhat.com"), + capsEnumName); + goto cleanup; + } + + capsEnum->values |= val; + } + + ret = 0; + cleanup: + return ret; +} + + +void +virDomainCapsEnumClear(virDomainCapsEnumPtr capsEnum) +{ + capsEnum->values = 0; +} + + +static int +virDomainCapsEnumFormat(virBufferPtr buf, + virDomainCapsEnumPtr capsEnum, + const char *capsEnumName, + virDomainCapsValToStr valToStr) +{ + int ret = -1; + size_t i; + + virBufferAsprintf(buf, "values) { + virBufferAddLit(buf, "/>\n"); + ret = 0; + goto cleanup; + } + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < sizeof(capsEnum->values) * CHAR_BIT; i++) { + const char *val; + + if (!(capsEnum->values & (1 << i))) + continue; + + if ((val = (valToStr)(i))) + virBufferAsprintf(buf, "%s\n", val); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + + ret = 0; + cleanup: + return ret; +} + +#define FORMAT_PROLOGUE(item) \ + do { \ + virBufferAsprintf(buf, "<" #item " supported='%s'%s\n", \ + item->device.supported ? "yes" : "no", \ + item->device.supported ? ">" : "/>"); \ + if (!item->device.supported) \ + return; \ + virBufferAdjustIndent(buf, 2); \ + } while (0) + +#define FORMAT_EPILOGUE(item) \ + do { \ + virBufferAdjustIndent(buf, -2); \ + virBufferAddLit(buf, "\n"); \ + } while (0) + +#define ENUM_PROCESS(master, capsEnum, valToStr) \ + do { \ + virDomainCapsEnumFormat(buf, &master->capsEnum, \ + #capsEnum, valToStr); \ + } while (0) + +static void +virDomainCapsDeviceDiskFormat(virBufferPtr buf, + virDomainCapsDeviceDiskPtr const disk) +{ + FORMAT_PROLOGUE(disk); + + ENUM_PROCESS(disk, diskDevice, virDomainDiskDeviceTypeToString); + ENUM_PROCESS(disk, bus, virDomainDiskBusTypeToString); + + FORMAT_EPILOGUE(disk); +} + + +static void +virDomainCapsDeviceHostdevFormat(virBufferPtr buf, + virDomainCapsDeviceHostdevPtr const hostdev) +{ + FORMAT_PROLOGUE(hostdev); + + ENUM_PROCESS(hostdev, mode, virDomainHostdevModeTypeToString); + ENUM_PROCESS(hostdev, startupPolicy, virDomainStartupPolicyTypeToString); + ENUM_PROCESS(hostdev, subsysType, virDomainHostdevSubsysTypeToString); + ENUM_PROCESS(hostdev, capsType, virDomainHostdevCapsTypeToString); + ENUM_PROCESS(hostdev, pciBackend, virDomainHostdevSubsysPCIBackendTypeToString); + + FORMAT_EPILOGUE(hostdev); +} + + +static int +virDomainCapsFormatInternal(virBufferPtr buf, + virDomainCapsPtr const caps) +{ + const char *virttype_str = virDomainVirtTypeToString(caps->virttype); + const char *arch_str = virArchToString(caps->arch); + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + + virBufferAsprintf(buf, "%s\n", caps->path); + virBufferAsprintf(buf, "%s\n", virttype_str); + virBufferAsprintf(buf, "%s\n", caps->machine); + virBufferAsprintf(buf, "%s\n", arch_str); + + if (caps->maxvcpus) + virBufferAsprintf(buf, "\n", caps->maxvcpus); + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + + virDomainCapsDeviceDiskFormat(buf, &caps->disk); + virDomainCapsDeviceHostdevFormat(buf, &caps->hostdev); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); + return 0; +} + + +char * +virDomainCapsFormat(virDomainCapsPtr const caps) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (virDomainCapsFormatInternal(&buf, caps) < 0) { + virBufferFreeAndReset(&buf); + return NULL; + } + + return virBufferContentAndReset(&buf); +} diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h new file mode 100644 index 0000000000..731e66f8a4 --- /dev/null +++ b/src/conf/domain_capabilities.h @@ -0,0 +1,103 @@ +/* + * domain_capabilities.h: domain capabilities XML processing + * + * Copyright (C) 2014 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Michal Privoznik + */ + +#ifndef __DOMAIN_CAPABILITIES_H__ +# define __DOMAIN_CAPABILITIES_H__ + +# include "internal.h" +# include "domain_conf.h" + +typedef const char * (*virDomainCapsValToStr)(int value); + +typedef struct _virDomainCaps virDomainCaps; +typedef virDomainCaps *virDomainCapsPtr; + +typedef struct _virDomainCapsEnum virDomainCapsEnum; +typedef virDomainCapsEnum *virDomainCapsEnumPtr; +struct _virDomainCapsEnum { + unsigned int values; /* Bitmask of values supported in the corresponding enum */ +}; + +typedef struct _virDomainCapsDevice virDomainCapsDevice; +typedef virDomainCapsDevice *virDomainCapsDevicePtr; +struct _virDomainCapsDevice { + bool supported; /* true if is supported by hypervisor */ +}; + +typedef struct _virDomainCapsDeviceDisk virDomainCapsDeviceDisk; +typedef virDomainCapsDeviceDisk *virDomainCapsDeviceDiskPtr; +struct _virDomainCapsDeviceDisk { + virDomainCapsDevice device; + virDomainCapsEnum diskDevice; /* Info about virDomainDiskDevice enum values */ + virDomainCapsEnum bus; /* Info about virDomainDiskBus enum values */ + /* add new fields here */ +}; + +typedef struct _virDomainCapsDeviceHostdev virDomainCapsDeviceHostdev; +typedef virDomainCapsDeviceHostdev *virDomainCapsDeviceHostdevPtr; +struct _virDomainCapsDeviceHostdev { + virDomainCapsDevice device; + virDomainCapsEnum mode; /* Info about virDomainHostdevMode */ + virDomainCapsEnum startupPolicy; /* Info about virDomainStartupPolicy */ + virDomainCapsEnum subsysType; /* Info about virDomainHostdevSubsysType */ + virDomainCapsEnum capsType; /* Info about virDomainHostdevCapsType */ + virDomainCapsEnum pciBackend; /* Info about virDomainHostdevSubsysPCIBackendType */ + /* add new fields here */ +}; + +struct _virDomainCaps { + virObjectLockable parent; + + char *path; /* path to emulator binary */ + virDomainVirtType virttype; /* virtualization type */ + char *machine; /* machine type */ + virArch arch; /* domain architecture */ + + /* Some machine specific info */ + int maxvcpus; + + virDomainCapsDeviceDisk disk; + virDomainCapsDeviceHostdev hostdev; + /* add new domain devices here */ +}; + +virDomainCapsPtr virDomainCapsNew(const char *path, + const char *machine, + virArch arch, + virDomainVirtType virttype); + +# define VIR_DOMAIN_CAPS_ENUM_SET(capsEnum, ...) \ + do { \ + unsigned int __values[] = {__VA_ARGS__}; \ + size_t __nvalues = ARRAY_CARDINALITY(__values); \ + virDomainCapsEnumSet(&(capsEnum), #capsEnum, \ + __nvalues, __values); \ + } while (0) + +int virDomainCapsEnumSet(virDomainCapsEnumPtr capsEnum, + const char *capsEnumName, + size_t nvalues, + unsigned int *values); +void virDomainCapsEnumClear(virDomainCapsEnumPtr capsEnum); + +char * virDomainCapsFormat(virDomainCapsPtr const caps); +#endif /* __DOMAIN_CAPABILITIES_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index cc5fd325af..e3164403df 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -130,6 +130,13 @@ virDomainAuditStop; virDomainAuditVcpu; +# conf/domain_capabilities.h +virDomainCapsEnumClear; +virDomainCapsEnumSet; +virDomainCapsFormat; +virDomainCapsNew; + + # conf/domain_conf.h virBlkioDeviceArrayClear; virDiskNameToBusDeviceIndex; diff --git a/tests/Makefile.am b/tests/Makefile.am index 025b847c8b..97af0d9d37 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -74,6 +74,8 @@ EXTRA_DIST = \ commanddata \ confdata \ cputestdata \ + domaincapsschemadata \ + domaincapsschematest \ domainconfdata \ domainschemadata \ domainschematest \ @@ -167,6 +169,7 @@ test_programs = virshtest sockettest \ virnetdevbandwidthtest \ virkmodtest \ vircapstest \ + domaincapstest \ domainconftest \ virhostdevtest \ vircaps2xmltest \ @@ -318,6 +321,7 @@ test_scripts = \ networkschematest \ storagepoolschematest \ storagevolschematest \ + domaincapsschematest \ domainschematest \ nodedevschematest \ nwfilterschematest \ @@ -827,6 +831,10 @@ vircaps2xmltest_SOURCES = \ vircaps2xmltest.c testutils.h testutils.c vircaps2xmltest_LDADD = $(LDADDS) +domaincapstest_SOURCES = \ + domaincapstest.c testutils.h testutils.c +domaincapstest_LDADD = $(LDADDS) + if WITH_LIBVIRTD libvirtdconftest_SOURCES = \ libvirtdconftest.c testutils.h testutils.c \ diff --git a/tests/domaincapsschemadata/domaincaps-basic.xml b/tests/domaincapsschemadata/domaincaps-basic.xml new file mode 100644 index 0000000000..99635199b4 --- /dev/null +++ b/tests/domaincapsschemadata/domaincaps-basic.xml @@ -0,0 +1,10 @@ + + /bin/emulatorbin + uml + my-machine-type + x86_64 + + + + + diff --git a/tests/domaincapsschemadata/domaincaps-full.xml b/tests/domaincapsschemadata/domaincaps-full.xml new file mode 100644 index 0000000000..58dd4cbdb0 --- /dev/null +++ b/tests/domaincapsschemadata/domaincaps-full.xml @@ -0,0 +1,56 @@ + + /bin/emulatorbin + kvm + my-machine-type + x86_64 + + + + + disk + cdrom + floppy + lun + + + ide + fdc + scsi + virtio + xen + usb + uml + sata + sd + + + + + subsystem + capabilities + + + default + mandatory + requisite + optional + + + usb + pci + scsi + + + storage + misc + net + + + default + kvm + vfio + xen + + + + diff --git a/tests/domaincapsschematest b/tests/domaincapsschematest new file mode 100755 index 0000000000..9baf44a473 --- /dev/null +++ b/tests/domaincapsschematest @@ -0,0 +1,11 @@ +#!/bin/sh + +: ${srcdir=.} +. $srcdir/test-lib.sh +. $abs_srcdir/schematestutils.sh + +DIRS="" +DIRS="$DIRS domaincapsschemadata" +SCHEMA="domaincaps.rng" + +check_schema "$DIRS" "$SCHEMA" diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c new file mode 100644 index 0000000000..6cdd086dcb --- /dev/null +++ b/tests/domaincapstest.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) Red Hat, Inc. 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Authors: + * Michal Privoznik + */ + +#include +#include + +#include "testutils.h" +#include "domain_capabilities.h" + + +#define VIR_FROM_THIS VIR_FROM_NONE + +typedef void (*virDomainCapsFill)(virDomainCapsPtr domCaps, + void *opaque); + +#define SET_ALL_BITS(x) \ + memset(&(x.values), 0xff, sizeof(x.values)) + +static void +fillAll(virDomainCapsPtr domCaps, + void *opaque ATTRIBUTE_UNUSED) +{ + virDomainCapsDeviceDiskPtr disk = &domCaps->disk; + virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev; + domCaps->maxvcpus = 255; + + disk->device.supported = true; + SET_ALL_BITS(disk->diskDevice); + SET_ALL_BITS(disk->bus); + + hostdev->device.supported = true; + SET_ALL_BITS(hostdev->mode); + SET_ALL_BITS(hostdev->startupPolicy); + SET_ALL_BITS(hostdev->subsysType); + SET_ALL_BITS(hostdev->capsType); + SET_ALL_BITS(hostdev->pciBackend); +} + +static virDomainCapsPtr +buildVirDomainCaps(const char *emulatorbin, + const char *machine, + virArch arch, + virDomainVirtType type, + virDomainCapsFill fillFunc, + void *opaque) +{ + virDomainCapsPtr domCaps; + + if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, type))) + goto cleanup; + + if (fillFunc) + fillFunc(domCaps, opaque); + + cleanup: + return domCaps; +} + +struct test_virDomainCapsFormatData { + const char *filename; + const char *emulatorbin; + const char *machine; + virArch arch; + virDomainVirtType type; + virDomainCapsFill fillFunc; + void *opaque; +}; + +static int +test_virDomainCapsFormat(const void *opaque) +{ + struct test_virDomainCapsFormatData *data = + (struct test_virDomainCapsFormatData *) opaque; + virDomainCapsPtr domCaps = NULL; + char *path = NULL; + char *domCapsXML = NULL; + char *domCapsFromFile = NULL; + int ret = -1; + + if (virAsprintf(&path, "%s/domaincapsschemadata/domaincaps-%s.xml", + abs_srcdir, data->filename) < 0) + goto cleanup; + + if (virFileReadAll(path, 8192, &domCapsFromFile) < 0) + goto cleanup; + + if (!(domCaps = buildVirDomainCaps(data->emulatorbin, data->machine, + data->arch, data->type, + data->fillFunc, data->opaque))) + goto cleanup; + + if (!(domCapsXML = virDomainCapsFormat(domCaps))) + goto cleanup; + + if (STRNEQ(domCapsFromFile, domCapsXML)) { + virtTestDifference(stderr, domCapsFromFile, domCapsXML); + goto cleanup; + } + + ret = 0; + cleanup: + VIR_FREE(domCapsFromFile); + VIR_FREE(domCapsXML); + VIR_FREE(path); + virObjectUnref(domCaps); + return ret; +} + +static int +mymain(void) +{ + int ret = 0; + +#define DO_TEST(Filename, Emulatorbin, Machine, Arch, Type, ...) \ + do { \ + struct test_virDomainCapsFormatData data = {.filename = Filename, \ + .emulatorbin = Emulatorbin, .machine = Machine, .arch = Arch, \ + .type = Type, __VA_ARGS__}; \ + if (virtTestRun(Filename, test_virDomainCapsFormat, &data) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST("basic", "/bin/emulatorbin", "my-machine-type", + VIR_ARCH_X86_64, VIR_DOMAIN_VIRT_UML); + DO_TEST("full", "/bin/emulatorbin", "my-machine-type", + VIR_ARCH_X86_64, VIR_DOMAIN_VIRT_KVM, .fillFunc = fillAll); + + return ret; +} + +VIRT_TEST_MAIN(mymain)