[libvirt] [PATCH 03/12] Introduce /domain/cpu/@check XML attribute

Jiri Denemark jdenemar at redhat.com
Tue Mar 14 16:57:42 UTC 2017


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




More information about the libvir-list mailing list