The attribute can be used to request a specific way of checking whether
the virtual CPU matches created by the hypervisor matches the
specification in domain XML.
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
docs/formatdomain.html.in | 30 ++++++++++++++++++++++++++++++
docs/schemas/cputypes.rng | 10 ++++++++++
docs/schemas/domaincommon.rng | 3 +++
src/conf/cpu_conf.c | 30 ++++++++++++++++++++++++++++++
src/conf/cpu_conf.h | 12 ++++++++++++
src/conf/domain_conf.c | 21 +++++++++++++++++++++
6 files changed, 106 insertions(+)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 75367d6dd..3bea3c75a 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1247,6 +1247,36 @@
<span class="since">Since 0.8.5</span> the
<code>match</code>
attribute can be omitted and will default to <code>exact</code>.
+ Sometimes the hypervisor is not able to create a virtual CPU exactly
+ matching the specification passed by libvirt.
+ <span class="since">Since 3.2.0</span>, an optional
<code>check</code>
+ attribute can be used to request a specific way of checking whether
+ the virtual CPU matches the specification. It is usually safe to omit
+ this attribute when starting a domain and stick with the default
+ value. Once the domain starts, libvirt will automatically change the
+ <code>check</code> attribute to the best supported value to ensure
the
+ virtual CPU does not change when the domain is migrated to another
+ host. The following values can be used:
+
+ <dl>
+ <dt><code>none</code></dt>
+ <dd>Libvirt does no checking and it is up to the hypervisor to
+ refuse to start the domain if it cannot provide the requested CPU.
+ With QEMU this means no checking is done at all since the default
+ behavior of QEMU is to emit warnings, but start the domain anyway.
+ </dd>
+
+ <dt><code>partial</code></dt>
+ <dd>Libvirt will check the guest CPU specification before starting
+ a domain, but the rest is left on the hypervisor. It can still
+ provide a different virtual CPU.</dd>
+
+ <dt><code>full</code></dt>
+ <dd>The virtual CPU created by the hypervisor will be checked
+ against the CPU specification and the domain will not be started
+ unless the two CPUs match.</dd>
+ </dl>
+
<span class="since">Since 0.9.10</span>, an optional
<code>mode</code>
attribute may be used to make it easier to configure a guest CPU to be
as close to host CPU as possible. Possible values for the
diff --git a/docs/schemas/cputypes.rng b/docs/schemas/cputypes.rng
index 7cc9dd3d8..8189114e3 100644
--- a/docs/schemas/cputypes.rng
+++ b/docs/schemas/cputypes.rng
@@ -23,6 +23,16 @@
</attribute>
</define>
+ <define name="cpuCheck">
+ <attribute name="check">
+ <choice>
+ <value>none</value>
+ <value>partial</value>
+ <value>full</value>
+ </choice>
+ </attribute>
+ </define>
+
<define name="cpuModel">
<element name="model">
<optional>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 5e593285e..767d6979c 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4503,6 +4503,9 @@
<optional>
<ref name="cpuMatch"/>
</optional>
+ <optional>
+ <ref name="cpuCheck"/>
+ </optional>
<interleave>
<optional>
<ref name="cpuModel"/>
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 2724fa30a..90accaea7 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -45,6 +45,12 @@ VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST,
"exact",
"strict")
+VIR_ENUM_IMPL(virCPUCheck, VIR_CPU_CHECK_LAST,
+ "default",
+ "none",
+ "partial",
+ "full")
+
VIR_ENUM_IMPL(virCPUFallback, VIR_CPU_FALLBACK_LAST,
"allow",
"forbid")
@@ -182,6 +188,7 @@ virCPUDefCopyWithoutModel(const virCPUDef *cpu)
copy->type = cpu->type;
copy->mode = cpu->mode;
copy->match = cpu->match;
+ copy->check = cpu->check;
copy->fallback = cpu->fallback;
copy->sockets = cpu->sockets;
copy->cores = cpu->cores;
@@ -277,6 +284,7 @@ virCPUDefParseXML(xmlNodePtr node,
if (def->type == VIR_CPU_TYPE_GUEST) {
char *match = virXMLPropString(node, "match");
+ char *check;
if (!match) {
if (virXPathBoolean("boolean(./model)", ctxt))
@@ -294,6 +302,18 @@ virCPUDefParseXML(xmlNodePtr node,
goto error;
}
}
+
+ if ((check = virXMLPropString(node, "check"))) {
+ def->check = virCPUCheckTypeFromString(check);
+ VIR_FREE(check);
+
+ if (def->check < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Invalid check attribute for CPU "
+ "specification"));
+ goto error;
+ }
+ }
}
if (def->type == VIR_CPU_TYPE_HOST) {
@@ -532,6 +552,16 @@ virCPUDefFormatBufFull(virBufferPtr buf,
}
virBufferAsprintf(&attributeBuf, " match='%s'", tmp);
}
+
+ if (def->check) {
+ if (!(tmp = virCPUCheckTypeToString(def->check))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected CPU check policy %d"),
+ def->check);
+ goto cleanup;
+ }
+ virBufferAsprintf(&attributeBuf, " check='%s'", tmp);
+ }
}
/* Format children */
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index cc3fbf0a4..507f630dc 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -64,6 +64,17 @@ typedef enum {
VIR_ENUM_DECL(virCPUMatch)
typedef enum {
+ VIR_CPU_CHECK_DEFAULT,
+ VIR_CPU_CHECK_NONE,
+ VIR_CPU_CHECK_PARTIAL,
+ VIR_CPU_CHECK_FULL,
+
+ VIR_CPU_CHECK_LAST
+} virCPUCheck;
+
+VIR_ENUM_DECL(virCPUCheck)
+
+typedef enum {
VIR_CPU_FALLBACK_ALLOW,
VIR_CPU_FALLBACK_FORBID,
@@ -98,6 +109,7 @@ struct _virCPUDef {
int type; /* enum virCPUType */
int mode; /* enum virCPUMode */
int match; /* enum virCPUMatch */
+ int check; /* virCPUCheck */
virArch arch;
char *model;
char *vendor_id; /* vendor id returned by CPUID in the guest */
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 88d419e27..a2cdb260a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -4587,6 +4587,24 @@ virDomainVcpuDefPostParse(virDomainDefPtr def)
static int
+virDomainDefPostParseCPU(virDomainDefPtr def)
+{
+ if (!def->cpu)
+ return 0;
+
+ if (def->cpu->mode == VIR_CPU_MODE_CUSTOM &&
+ !def->cpu->model &&
+ def->cpu->check != VIR_CPU_CHECK_DEFAULT) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("check attribute specified for CPU with no model"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
virDomainDefPostParseInternal(virDomainDefPtr def,
struct virDomainDefPostParseDeviceIteratorData *data)
{
@@ -4636,6 +4654,9 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
virDomainDefPostParseGraphics(def);
+ if (virDomainDefPostParseCPU(def) < 0)
+ return -1;
+
return 0;
}
--
2.12.0