Introduce /domain/cpu/@check XML attribute

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@redhat.com>
This commit is contained in:
Jiri Denemark 2017-03-01 15:18:22 +01:00
parent 38567e94de
commit 641b8c721e
6 changed files with 102 additions and 0 deletions

View File

@ -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

View File

@ -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>

View File

@ -4504,6 +4504,9 @@
<optional>
<ref name="cpuMatch"/>
</optional>
<optional>
<ref name="cpuCheck"/>
</optional>
<interleave>
<optional>
<ref name="cpuModel"/>

View File

@ -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,19 @@ virCPUDefParseXML(xmlNodePtr node,
goto error;
}
}
if ((check = virXMLPropString(node, "check"))) {
int value = virCPUCheckTypeFromString(check);
VIR_FREE(check);
if (value < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Invalid check attribute for CPU "
"specification"));
goto error;
}
def->check = value;
}
}
if (def->type == VIR_CPU_TYPE_HOST) {
@ -532,6 +553,11 @@ virCPUDefFormatBufFull(virBufferPtr buf,
}
virBufferAsprintf(&attributeBuf, " match='%s'", tmp);
}
if (def->check) {
virBufferAsprintf(&attributeBuf, " check='%s'",
virCPUCheckTypeToString(def->check));
}
}
/* Format children */

View File

@ -63,6 +63,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 */
virCPUCheck check;
virArch arch;
char *model;
char *vendor_id; /* vendor id returned by CPUID in the guest */

View File

@ -4592,6 +4592,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)
@ -4642,6 +4660,9 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
virDomainDefPostParseGraphics(def);
if (virDomainDefPostParseCPU(def) < 0)
return -1;
return 0;
}