diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 3d16d5fada1df336c88573c97ee987d19d8bc841..4a3123e989706c6e42ab03029e95fda1473fd197 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1247,6 +1247,36 @@ Since 0.8.5 the match attribute can be omitted and will default to exact. + Sometimes the hypervisor is not able to create a virtual CPU exactly + matching the specification passed by libvirt. + Since 3.2.0, an optional check + 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 + check 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: + +
+
none
+
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. +
+ +
partial
+
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.
+ +
full
+
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.
+
+ Since 0.9.10, an optional mode 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 7cc9dd3d8351b194b0b87a7c45f323fbaa06082f..8189114e3c3032711e53aec2e1628790e71b31a7 100644 --- a/docs/schemas/cputypes.rng +++ b/docs/schemas/cputypes.rng @@ -23,6 +23,16 @@ + + + + none + partial + full + + + + diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 24d1edbddd6edec5d3eee9068977b71ef14563fc..fbedc9b1f92d5b20d3ab24ff0a9dce3d5236d1b1 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4504,6 +4504,9 @@ + + + diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 2724fa30a979927cef304793615bb0b91b630d3f..d7c8b8ff211eed7594ca57283c44924c4615db74 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,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 */ diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index cc3fbf0a45b95d23f5923f404000807ceb77b04e..9118f037ed20dca48ebe55809f3be3a361329620 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -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 */ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index eaf46b2a48412f3032c51d4c24a23a07b0ebc34a..6bbc6a2a7b4af2e03c5cfcddafbc682fc3502913 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -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; }