The patch adds <cpu> element to domain capabilities XML:
<cpu>
<mode name='host-passthrough' supported='yes'/>
<mode name='host-model' supported='yes'/>
<mode name='custom' supported='yes'>
<model>Broadwell</model>
<model>Broadwell-noTSX</model>
...
</mode>
</cpu>
Applications can use it to inspect what CPU configuration modes are
supported for a specific combination of domain type, emulator binary,
guest architecture and machine type.
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
docs/formatdomaincaps.html.in | 44 ++++++
docs/schemas/domaincaps.rng | 43 ++++++
src/conf/domain_capabilities.c | 150 +++++++++++++++++++++
src/conf/domain_capabilities.h | 33 +++++
src/libvirt_private.syms | 4 +
tests/domaincapsschemadata/basic.xml | 5 +
tests/domaincapsschemadata/full.xml | 9 ++
tests/domaincapsschemadata/libxl-xenfv-usb.xml | 5 +
tests/domaincapsschemadata/libxl-xenfv.xml | 5 +
tests/domaincapsschemadata/libxl-xenpv-usb.xml | 5 +
tests/domaincapsschemadata/libxl-xenpv.xml | 5 +
tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml | 5 +
.../qemu_2.6.0-gicv2-virt.aarch64.xml | 5 +
.../qemu_2.6.0-gicv3-virt.aarch64.xml | 5 +
tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml | 5 +
tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml | 5 +
tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml | 5 +
tests/domaincapstest.c | 9 ++
18 files changed, 347 insertions(+)
diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in
index d5a8414..15a13c1 100644
--- a/docs/formatdomaincaps.html.in
+++ b/docs/formatdomaincaps.html.in
@@ -142,6 +142,50 @@
<loader/> element.</dd>
</dl>
+ <h3><a name="elementsCPU">CPU
configuration</a></h3>
+
+ <p>
+ The <code>cpu</code> element exposes options usable for configuring
+ guest CPU.
+ </p>
+
+<pre>
+<domainCapabilities>
+ ...
+ <cpu>
+ <mode name='host-passthrough' supported='yes'/>
+ <mode name='host-model' supported='yes'/>
+ <mode name='custom' supported='yes'>
+ <model>Broadwell</model>
+ <model>Broadwell-noTSX</model>
+ <model>Haswell</model>
+ ...
+ </mode>
+ </cpu>
+ ...
+<domainCapabilities>
+</pre>
+
+ <p>
+ Each CPU mode understood by libvirt is described with a
+ <code>mode</code> element which tells whether the particular mode
+ is supported and provides (when applicable) more details about it:
+ </p>
+
+ <dl>
+ <dt><code>host-passthrough</code></dt>
+ <dd>No mode specific details are provided.</dd>
+
+ <dt><code>host-model</code></dt>
+ <dd>No mode specific details are provided yet.</dd>
+
+ <dt><code>custom</code></dt>
+ <dd>
+ The <code>mode</code> element contains a list of supported CPU
+ models, each described by a dedicated <code>model</code> element.
+ </dd>
+ </dl>
+
<h3><a name="elementsDevices">Devices</a></h3>
<p>
diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng
index 97da41f..9f3d225 100644
--- a/docs/schemas/domaincaps.rng
+++ b/docs/schemas/domaincaps.rng
@@ -29,6 +29,9 @@
<ref name='os'/>
</optional>
<optional>
+ <ref name='cpu'/>
+ </optional>
+ <optional>
<ref name='devices'/>
</optional>
<optional>
@@ -68,6 +71,46 @@
</element>
</define>
+ <define name='cpu'>
+ <element name='cpu'>
+ <ref name='cpuHost'/>
+ <ref name='cpuHostModel'/>
+ <ref name='cpuCustom'/>
+ </element>
+ </define>
+
+ <define name='cpuHost'>
+ <element name='mode'>
+ <attribute name='name'>
+ <value>host-passthrough</value>
+ </attribute>
+ <ref name='supported'/>
+ </element>
+ </define>
+
+ <define name='cpuHostModel'>
+ <element name='mode'>
+ <attribute name='name'>
+ <value>host-model</value>
+ </attribute>
+ <ref name='supported'/>
+ </element>
+ </define>
+
+ <define name='cpuCustom'>
+ <element name='mode'>
+ <attribute name='name'>
+ <value>custom</value>
+ </attribute>
+ <ref name='supported'/>
+ <zeroOrMore>
+ <element name='model'>
+ <text/>
+ </element>
+ </zeroOrMore>
+ </element>
+ </define>
+
<define name='devices'>
<element name='devices'>
<interleave>
diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index 1676f0e..c07f995 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -30,8 +30,10 @@
#define VIR_FROM_THIS VIR_FROM_CAPABILITIES
static virClassPtr virDomainCapsClass;
+static virClassPtr virDomainCapsCPUModelsClass;
static void virDomainCapsDispose(void *obj);
+static void virDomainCapsCPUModelsDispose(void *obj);
static int virDomainCapsOnceInit(void)
{
@@ -40,6 +42,14 @@ static int virDomainCapsOnceInit(void)
sizeof(virDomainCaps),
virDomainCapsDispose)))
return -1;
+
+ virDomainCapsCPUModelsClass = virClassNew(virClassForObject(),
+ "virDomainCapsCPUModelsClass",
+ sizeof(virDomainCapsCPUModels),
+ virDomainCapsCPUModelsDispose);
+ if (!virDomainCapsCPUModelsClass)
+ return -1;
+
return 0;
}
@@ -68,11 +78,25 @@ virDomainCapsDispose(void *obj)
VIR_FREE(caps->path);
VIR_FREE(caps->machine);
+ virObjectUnref(caps->cpu.custom);
virDomainCapsStringValuesFree(&caps->os.loader.values);
}
+static void
+virDomainCapsCPUModelsDispose(void *obj)
+{
+ virDomainCapsCPUModelsPtr cpuModels = obj;
+ size_t i;
+
+ for (i = 0; i < cpuModels->count; i++)
+ VIR_FREE(cpuModels->models[i].name);
+
+ VIR_FREE(cpuModels->models);
+}
+
+
virDomainCapsPtr
virDomainCapsNew(const char *path,
const char *machine,
@@ -100,6 +124,86 @@ virDomainCapsNew(const char *path,
}
+virDomainCapsCPUModelsPtr
+virDomainCapsCPUModelsNew(size_t nmodels)
+{
+ virDomainCapsCPUModelsPtr cpuModels = NULL;
+
+ if (virDomainCapsInitialize() < 0)
+ return NULL;
+
+ if (!(cpuModels = virObjectNew(virDomainCapsCPUModelsClass)))
+ return NULL;
+
+ if (VIR_ALLOC_N(cpuModels->models, nmodels) < 0)
+ goto error;
+ cpuModels->alloc = nmodels;
+
+ return cpuModels;
+
+ error:
+ virObjectUnref(cpuModels);
+ return NULL;
+}
+
+
+virDomainCapsCPUModelsPtr
+virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old)
+{
+ virDomainCapsCPUModelsPtr cpuModels;
+ size_t i;
+
+ if (!(cpuModels = virDomainCapsCPUModelsNew(old->count)))
+ return NULL;
+
+ for (i = 0; i < old->count; i++) {
+ if (virDomainCapsCPUModelsAdd(cpuModels, old->models[i].name, -1) < 0)
+ goto error;
+ }
+
+ return cpuModels;
+
+ error:
+ virObjectUnref(cpuModels);
+ return NULL;
+}
+
+
+int
+virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels,
+ char **name)
+{
+ if (VIR_RESIZE_N(cpuModels->models, cpuModels->alloc,
+ cpuModels->count, 1) < 0)
+ return -1;
+
+ cpuModels->models[cpuModels->count++].name = *name;
+ *name = NULL;
+ return 0;
+}
+
+
+int
+virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels,
+ const char *name,
+ ssize_t nameLen)
+{
+ char *copy = NULL;
+
+ if (VIR_STRNDUP(copy, name, nameLen) < 0)
+ goto error;
+
+ if (virDomainCapsCPUModelsAddSteal(cpuModels, ©) < 0)
+ goto error;
+
+ return 0;
+
+ error:
+ VIR_FREE(copy);
+ return -1;
+}
+
+
int
virDomainCapsEnumSet(virDomainCapsEnumPtr capsEnum,
const char *capsEnumName,
@@ -234,6 +338,51 @@ virDomainCapsOSFormat(virBufferPtr buf,
}
static void
+virDomainCapsCPUCustomFormat(virBufferPtr buf,
+ virDomainCapsCPUModelsPtr custom)
+{
+ size_t i;
+
+ virBufferAdjustIndent(buf, 2);
+
+ for (i = 0; i < custom->count; i++) {
+ virBufferAsprintf(buf, "<model>%s</model>\n",
+ custom->models[i].name);
+ }
+
+ virBufferAdjustIndent(buf, -2);
+}
+
+static void
+virDomainCapsCPUFormat(virBufferPtr buf,
+ virDomainCapsCPUPtr cpu)
+{
+ virBufferAddLit(buf, "<cpu>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferAsprintf(buf, "<mode name='%s'
supported='%s'/>\n",
+ virCPUModeTypeToString(VIR_CPU_MODE_HOST_PASSTHROUGH),
+ cpu->hostPassthrough ? "yes" : "no");
+
+ virBufferAsprintf(buf, "<mode name='%s'
supported='%s'/>\n",
+ virCPUModeTypeToString(VIR_CPU_MODE_HOST_MODEL),
+ cpu->hostModel ? "yes" : "no");
+
+ virBufferAsprintf(buf, "<mode name='%s' ",
+ virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM));
+ if (cpu->custom && cpu->custom->count) {
+ virBufferAddLit(buf, "supported='yes'>\n");
+ virDomainCapsCPUCustomFormat(buf, cpu->custom);
+ virBufferAddLit(buf, "</mode>\n");
+ } else {
+ virBufferAddLit(buf, "supported='no'/>\n");
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</cpu>\n");
+}
+
+static void
virDomainCapsDeviceDiskFormat(virBufferPtr buf,
virDomainCapsDeviceDiskPtr const disk)
{
@@ -333,6 +482,7 @@ virDomainCapsFormatInternal(virBufferPtr buf,
virBufferAsprintf(buf, "<vcpu max='%d'/>\n",
caps->maxvcpus);
virDomainCapsOSFormat(buf, &caps->os);
+ virDomainCapsCPUFormat(buf, &caps->cpu);
virBufferAddLit(buf, "<devices>\n");
virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
index 492a9cf..509c306 100644
--- a/src/conf/domain_capabilities.h
+++ b/src/conf/domain_capabilities.h
@@ -102,6 +102,30 @@ struct _virDomainCapsFeatureGIC {
virDomainCapsEnum version; /* Info about virGICVersion */
};
+typedef struct _virDomainCapsCPUModel virDomainCapsCPUModel;
+typedef virDomainCapsCPUModel *virDomainCapsCPUModelPtr;
+struct _virDomainCapsCPUModel {
+ char *name;
+};
+
+typedef struct _virDomainCapsCPUModels virDomainCapsCPUModels;
+typedef virDomainCapsCPUModels *virDomainCapsCPUModelsPtr;
+struct _virDomainCapsCPUModels {
+ virObject parent;
+
+ size_t alloc;
+ size_t count;
+ virDomainCapsCPUModelPtr models;
+};
+
+typedef struct _virDomainCapsCPU virDomainCapsCPU;
+typedef virDomainCapsCPU *virDomainCapsCPUPtr;
+struct _virDomainCapsCPU {
+ bool hostPassthrough;
+ bool hostModel;
+ virDomainCapsCPUModelsPtr custom;
+};
+
struct _virDomainCaps {
virObjectLockable parent;
@@ -114,6 +138,7 @@ struct _virDomainCaps {
int maxvcpus;
virDomainCapsOS os;
+ virDomainCapsCPU cpu;
virDomainCapsDeviceDisk disk;
virDomainCapsDeviceGraphics graphics;
virDomainCapsDeviceVideo video;
@@ -129,6 +154,14 @@ virDomainCapsPtr virDomainCapsNew(const char *path,
virArch arch,
virDomainVirtType virttype);
+virDomainCapsCPUModelsPtr virDomainCapsCPUModelsNew(size_t nmodels);
+virDomainCapsCPUModelsPtr virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old);
+int virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels,
+ char **name);
+int virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels,
+ const char *name,
+ ssize_t nameLen);
+
# define VIR_DOMAIN_CAPS_ENUM_SET(capsEnum, ...) \
do { \
unsigned int __values[] = {__VA_ARGS__}; \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 419c33d..f91ce17 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -152,6 +152,10 @@ virDomainAuditVcpu;
# conf/domain_capabilities.h
+virDomainCapsCPUModelsAdd;
+virDomainCapsCPUModelsAddSteal;
+virDomainCapsCPUModelsCopy;
+virDomainCapsCPUModelsNew;
virDomainCapsEnumClear;
virDomainCapsEnumSet;
virDomainCapsFormat;
diff --git a/tests/domaincapsschemadata/basic.xml b/tests/domaincapsschemadata/basic.xml
index 5513f99..6b788d9 100644
--- a/tests/domaincapsschemadata/basic.xml
+++ b/tests/domaincapsschemadata/basic.xml
@@ -4,6 +4,11 @@
<machine>my-machine-type</machine>
<arch>x86_64</arch>
<os supported='no'/>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='no'/>
<graphics supported='no'/>
diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml
index 2f529ff..80fd1f0 100644
--- a/tests/domaincapsschemadata/full.xml
+++ b/tests/domaincapsschemadata/full.xml
@@ -19,6 +19,15 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='yes'/>
+ <mode name='host-model' supported='yes'/>
+ <mode name='custom' supported='yes'>
+ <model>Model1</model>
+ <model>Model2</model>
+ <model>Model3</model>
+ </mode>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/libxl-xenfv-usb.xml
b/tests/domaincapsschemadata/libxl-xenfv-usb.xml
index c071d12..6a9e3d9 100644
--- a/tests/domaincapsschemadata/libxl-xenfv-usb.xml
+++ b/tests/domaincapsschemadata/libxl-xenfv-usb.xml
@@ -17,6 +17,11 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/libxl-xenfv.xml
b/tests/domaincapsschemadata/libxl-xenfv.xml
index 9436ef8..d48e699 100644
--- a/tests/domaincapsschemadata/libxl-xenfv.xml
+++ b/tests/domaincapsschemadata/libxl-xenfv.xml
@@ -17,6 +17,11 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/libxl-xenpv-usb.xml
b/tests/domaincapsschemadata/libxl-xenpv-usb.xml
index 4dd07bd..d1a3918 100644
--- a/tests/domaincapsschemadata/libxl-xenpv-usb.xml
+++ b/tests/domaincapsschemadata/libxl-xenpv-usb.xml
@@ -7,6 +7,11 @@
<os supported='yes'>
<loader supported='no'/>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/libxl-xenpv.xml
b/tests/domaincapsschemadata/libxl-xenpv.xml
index ab00a28..c0e3193 100644
--- a/tests/domaincapsschemadata/libxl-xenpv.xml
+++ b/tests/domaincapsschemadata/libxl-xenpv.xml
@@ -7,6 +7,11 @@
<os supported='yes'>
<loader supported='no'/>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml
b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml
index 161d0ab..6da28b0 100644
--- a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml
+++ b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml
@@ -18,6 +18,11 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml
b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml
index f5f0f1c..ee51684 100644
--- a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml
+++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml
@@ -18,6 +18,11 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml
b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml
index 1ae8172..88cced9 100644
--- a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml
+++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml
@@ -18,6 +18,11 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml
b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml
index 4e87cd2..09c0e1c 100644
--- a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml
+++ b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml
@@ -18,6 +18,11 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml
b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml
index 583fdf0..40b255e 100644
--- a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml
+++ b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml
@@ -18,6 +18,11 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml
b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml
index c453ce3..6706fec 100644
--- a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml
+++ b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml
@@ -18,6 +18,11 @@
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c
index 5b7b7d0..907c0ad 100644
--- a/tests/domaincapstest.c
+++ b/tests/domaincapstest.c
@@ -60,6 +60,7 @@ fillAllCaps(virDomainCapsPtr domCaps)
{
virDomainCapsOSPtr os = &domCaps->os;
virDomainCapsLoaderPtr loader = &os->loader;
+ virDomainCapsCPUPtr cpu = &domCaps->cpu;
virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
virDomainCapsDeviceGraphicsPtr graphics = &domCaps->graphics;
virDomainCapsDeviceVideoPtr video = &domCaps->video;
@@ -77,6 +78,14 @@ fillAllCaps(virDomainCapsPtr domCaps)
NULL) < 0)
return -1;
+ cpu->hostPassthrough = true;
+ cpu->hostModel = true;
+ if (!(cpu->custom = virDomainCapsCPUModelsNew(3)) ||
+ virDomainCapsCPUModelsAdd(cpu->custom, "Model1", -1) < 0 ||
+ virDomainCapsCPUModelsAdd(cpu->custom, "Model2", -1) < 0 ||
+ virDomainCapsCPUModelsAdd(cpu->custom, "Model3", -1) < 0)
+ return -1;
+
disk->supported = true;
SET_ALL_BITS(disk->diskDevice);
SET_ALL_BITS(disk->bus);
--
2.9.2