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
+
+
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+
+
+ 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
+
+
+
+
+
+ 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
.
+
+
+ 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/>.
+
+
+
+ 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, "" #item ">\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)