[libvirt] [PATCH v2 2/6] cpu: Optionally forbid fallback CPU models

Jiri Denemark jdenemar at redhat.com
Thu Jan 12 11:02:56 UTC 2012


In case a hypervisor doesn't support the exact CPU model requested by a
domain XML, we automatically fallback to a closest CPU model the
hypervisor supports (and make sure we add/remove any additional features
if needed). This patch adds 'fallback' attribute to model element, which
can be used to disable this automatic fallback.
---
Notes:
    Version 2:
    - grammar

 docs/formatdomain.html.in                          |   12 +++-
 docs/schemas/domaincommon.rng                      |    8 ++
 src/conf/cpu_conf.c                                |   38 ++++++++-
 src/conf/cpu_conf.h                                |   10 +++
 src/cpu/cpu_x86.c                                  |   17 ++++-
 src/qemu/qemu_command.c                            |    1 +
 tests/cputest.c                                    |    2 +
 tests/cputestdata/x86-baseline-1-result.xml        |    2 +-
 tests/cputestdata/x86-baseline-2-result.xml        |    2 +-
 .../cputestdata/x86-baseline-no-vendor-result.xml  |    2 +-
 .../x86-baseline-some-vendors-result.xml           |    2 +-
 tests/cputestdata/x86-guest-nofallback.xml         |   18 ++++
 .../cputestdata/x86-host+guest,model486-result.xml |    2 +-
 .../x86-host+guest,models,Penryn-result.xml        |    2 +-
 .../x86-host+guest,models,qemu64-result.xml        |    2 +-
 tests/cputestdata/x86-host+guest,models-result.xml |    2 +-
 tests/cputestdata/x86-host+guest-result.xml        |    2 +-
 tests/cputestdata/x86-host+guest.xml               |    2 +-
 tests/cputestdata/x86-host+min.xml                 |    2 +-
 .../cputestdata/x86-host+nehalem-force-result.xml  |    2 +-
 tests/cputestdata/x86-host+pentium3.xml            |    2 +-
 .../x86-host+strict-force-extra-result.xml         |    2 +-
 .../x86-host-better+pentium3,core2duo-result.xml   |    2 +-
 .../x86-host-better+pentium3,pentium3-result.xml   |    2 +-
 .../x86-host-better+pentium3-result.xml            |    2 +-
 tests/cputestdata/x86-host-worse+guest-result.xml  |    2 +-
 tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml |    2 +-
 .../qemuxml2argv-cpu-exact2-nofallback.args        |    4 +
 .../qemuxml2argv-cpu-exact2-nofallback.xml         |   35 ++++++++
 .../qemuxml2argv-cpu-fallback.args                 |   19 +++++
 .../qemuxml2argvdata/qemuxml2argv-cpu-fallback.xml |   25 ++++++
 .../qemuxml2argv-cpu-nofallback.xml                |   25 ++++++
 tests/qemuxml2argvtest.c                           |   84 ++++++++++++-------
 .../qemuxml2xmlout-graphics-spice-timeout.xml      |   86 ++++++++++++++++++++
 tests/qemuxml2xmltest.c                            |    2 +-
 tests/testutilsqemu.c                              |    1 +
 36 files changed, 367 insertions(+), 58 deletions(-)
 create mode 100644 tests/cputestdata/x86-guest-nofallback.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.xml
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-nofallback.xml
 create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 42e23a1..8961fed 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -559,7 +559,7 @@
 <pre>
   ...
   <cpu match='exact'>
-    <model>core2duo</model>
+    <model fallback='allow'>core2duo</model>
     <vendor>Intel</vendor>
     <topology sockets='1' cores='2' threads='1'/>
     <feature policy='disable' name='lahf_lm'/>
@@ -609,7 +609,15 @@
       <dd>The content of the <code>model</code> element specifies CPU model
         requested by the guest. The list of available CPU models and their
         definition can be found in <code>cpu_map.xml</code> file installed
-        in libvirt's data directory.</dd>
+        in libvirt's data directory. If a hypervisor is not able to use the
+        exact CPU model, libvirt automatically falls back to a closest model
+        supported by the hypervisor while maintaining the list of CPU
+        features. <span class="since">Since 0.9.10</span>, an optional
+        <code>fallback</code> attribute can be used to forbid this behavior,
+        in which case an attempt to start a domain requesting unsupported
+        CPU model will fail. Supported values for <code>fallback</code>
+        attribute are: <code>allow</code> (this is the default), and
+        <code>forbid</code>.</dd>
 
       <dt><code>vendor</code></dt>
       <dd><span class="since">Since 0.8.3</span> the content of the
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index e93ae77..a3ad3d3 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2459,6 +2459,14 @@
 
   <define name="cpuModel">
     <element name="model">
+      <optional>
+        <attribute name="fallback">
+          <choice>
+            <value>allow</value>
+            <value>forbid</value>
+          </choice>
+        </attribute>
+      </optional>
       <text/>
     </element>
   </define>
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 348299b..c8e29e4 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -44,6 +44,10 @@ VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST,
               "exact",
               "strict")
 
+VIR_ENUM_IMPL(virCPUFallback, VIR_CPU_FALLBACK_LAST,
+              "allow",
+              "forbid")
+
 VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST,
               "force",
               "require",
@@ -97,6 +101,7 @@ virCPUDefCopy(const virCPUDefPtr cpu)
 
     copy->type = cpu->type;
     copy->match = cpu->match;
+    copy->fallback = cpu->fallback;
     copy->sockets = cpu->sockets;
     copy->cores = cpu->cores;
     copy->threads = cpu->threads;
@@ -209,6 +214,21 @@ virCPUDefParseXML(const xmlNodePtr node,
         goto error;
     }
 
+    if (def->model && def->type == VIR_CPU_TYPE_GUEST) {
+        const char *fallback;
+
+        fallback = virXPathString("string(./model[1]/@fallback)", ctxt);
+        if (fallback) {
+            def->fallback = virCPUFallbackTypeFromString(fallback);
+            VIR_FREE(fallback);
+            if (def->fallback < 0) {
+                virCPUReportError(VIR_ERR_XML_ERROR, "%s",
+                                  _("Invalid fallback attribute"));
+                goto error;
+            }
+        }
+    }
+
     def->vendor = virXPathString("string(./vendor[1])", ctxt);
     if (def->vendor && !def->model) {
         virCPUReportError(VIR_ERR_INTERNAL_ERROR,
@@ -455,8 +475,22 @@ virCPUDefFormatBuf(virBufferPtr buf,
         return -1;
     }
 
-    if (def->model)
-        virBufferAsprintf(buf, "<model>%s</model>\n", def->model);
+    if (def->model) {
+        virBufferAddLit(buf, "<model");
+        if (def->type == VIR_CPU_TYPE_GUEST) {
+            const char *fallback;
+
+            fallback = virCPUFallbackTypeToString(def->fallback);
+            if (!fallback) {
+                virCPUReportError(VIR_ERR_INTERNAL_ERROR,
+                                  _("Unexpected CPU fallback value: %d"),
+                                  def->fallback);
+                return -1;
+            }
+            virBufferAsprintf(buf, " fallback='%s'", fallback);
+        }
+        virBufferAsprintf(buf, ">%s</model>\n", def->model);
+    }
 
     if (def->vendor) {
         virBufferAsprintf(buf, "<vendor>%s</vendor>\n", def->vendor);
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index efff473..0c50f90 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -48,6 +48,15 @@ enum virCPUMatch {
 
 VIR_ENUM_DECL(virCPUMatch)
 
+enum virCPUFallback {
+    VIR_CPU_FALLBACK_ALLOW,
+    VIR_CPU_FALLBACK_FORBID,
+
+    VIR_CPU_FALLBACK_LAST
+};
+
+VIR_ENUM_DECL(virCPUFallback)
+
 enum virCPUFeaturePolicy {
     VIR_CPU_FEATURE_FORCE,
     VIR_CPU_FEATURE_REQUIRE,
@@ -83,6 +92,7 @@ struct _virCPUDef {
     int match;          /* enum virCPUMatch */
     char *arch;
     char *model;
+    int fallback;       /* enum virCPUFallback */
     char *vendor;
     unsigned int sockets;
     unsigned int cores;
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 4a4272e..ad2d5cd 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -1294,8 +1294,21 @@ x86Decode(virCPUDefPtr cpu,
         }
 
         if (!allowed) {
-            VIR_DEBUG("CPU model %s not allowed by hypervisor; ignoring",
-                      candidate->name);
+            if (preferred && STREQ(candidate->name, preferred)) {
+                if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
+                    virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("CPU model %s is not supported by hypervisor"),
+                            preferred);
+                    goto out;
+                } else {
+                    VIR_WARN("Preferred CPU model %s not allowed by"
+                             " hypervisor; closest supported model will be"
+                             " used", preferred);
+                }
+            } else {
+                VIR_DEBUG("CPU model %s not allowed by hypervisor; ignoring",
+                          candidate->name);
+            }
             goto next;
         }
 
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index d051305..4d7842e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3481,6 +3481,7 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
             preferred = def->cpu->model;
 
         guest->type = VIR_CPU_TYPE_GUEST;
+        guest->fallback = def->cpu->fallback;
         if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
             goto cleanup;
 
diff --git a/tests/cputest.c b/tests/cputest.c
index 5b7b951..2dd89f2 100644
--- a/tests/cputest.c
+++ b/tests/cputest.c
@@ -287,6 +287,7 @@ cpuTestGuestData(const void *arg)
 
     guest->type = VIR_CPU_TYPE_GUEST;
     guest->match = VIR_CPU_MATCH_EXACT;
+    guest->fallback = cpu->fallback;
     if (cpuDecode(guest, guestData, data->models,
                   data->nmodels, data->preferred) < 0) {
         if (data->result < 0) {
@@ -620,6 +621,7 @@ mymain(void)
     DO_TEST_GUESTDATA("x86", "host", "guest", models, "Penryn", 0);
     DO_TEST_GUESTDATA("x86", "host", "guest", models, "qemu64", 0);
     DO_TEST_GUESTDATA("x86", "host", "guest", nomodel, NULL, -1);
+    DO_TEST_GUESTDATA("x86", "host", "guest-nofallback", models, "Penryn", -1);
 
     free(map);
     return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
diff --git a/tests/cputestdata/x86-baseline-1-result.xml b/tests/cputestdata/x86-baseline-1-result.xml
index e376f74..99e43d0 100644
--- a/tests/cputestdata/x86-baseline-1-result.xml
+++ b/tests/cputestdata/x86-baseline-1-result.xml
@@ -1,5 +1,5 @@
 <cpu match='exact'>
-  <model>Conroe</model>
+  <model fallback='allow'>Conroe</model>
   <vendor>Intel</vendor>
   <feature policy='disable' name='lahf_lm'/>
 </cpu>
diff --git a/tests/cputestdata/x86-baseline-2-result.xml b/tests/cputestdata/x86-baseline-2-result.xml
index 3fd0551..76c13aa 100644
--- a/tests/cputestdata/x86-baseline-2-result.xml
+++ b/tests/cputestdata/x86-baseline-2-result.xml
@@ -1,4 +1,4 @@
 <cpu match='exact'>
-  <model>core2duo</model>
+  <model fallback='allow'>core2duo</model>
   <feature policy='disable' name='nx'/>
 </cpu>
diff --git a/tests/cputestdata/x86-baseline-no-vendor-result.xml b/tests/cputestdata/x86-baseline-no-vendor-result.xml
index 0fc0892..8b97d2c 100644
--- a/tests/cputestdata/x86-baseline-no-vendor-result.xml
+++ b/tests/cputestdata/x86-baseline-no-vendor-result.xml
@@ -1,5 +1,5 @@
 <cpu match='exact'>
-  <model>Opteron_G2</model>
+  <model fallback='allow'>Opteron_G2</model>
   <feature policy='disable' name='svm'/>
   <feature policy='disable' name='rdtscp'/>
 </cpu>
diff --git a/tests/cputestdata/x86-baseline-some-vendors-result.xml b/tests/cputestdata/x86-baseline-some-vendors-result.xml
index 2ddfcc5..bac0e5d 100644
--- a/tests/cputestdata/x86-baseline-some-vendors-result.xml
+++ b/tests/cputestdata/x86-baseline-some-vendors-result.xml
@@ -1,3 +1,3 @@
 <cpu match='exact'>
-  <model>Opteron_G1</model>
+  <model fallback='allow'>Opteron_G1</model>
 </cpu>
diff --git a/tests/cputestdata/x86-guest-nofallback.xml b/tests/cputestdata/x86-guest-nofallback.xml
new file mode 100644
index 0000000..babe47d
--- /dev/null
+++ b/tests/cputestdata/x86-guest-nofallback.xml
@@ -0,0 +1,18 @@
+<cpu match='exact'>
+  <model fallback='forbid'>Penryn</model>
+  <topology sockets='2' cores='4' threads='1'/>
+  <!--feature name='sse4.1' policy='optional'/-->
+  <feature name='dca' policy='optional'/>
+  <feature name='xtpr' policy='optional'/>
+  <feature name='sse4.2' policy='optional'/>
+  <feature name='3dnow' policy='optional'/>
+  <feature name='ssse3' policy='optional'/>
+  <feature name='vmx' policy='disable'/>
+  <feature name='ds_cpl' policy='disable'/>
+  <feature name='sse' policy='disable'/>
+  <feature name='monitor' policy='force'/>
+  <feature name='pbe' policy='force'/>
+  <feature name='3dnowext' policy='force'/>
+  <feature name='svm' policy='force'/>
+  <feature name='popcnt' policy='forbid'/>
+</cpu>
diff --git a/tests/cputestdata/x86-host+guest,model486-result.xml b/tests/cputestdata/x86-host+guest,model486-result.xml
index fb1bb4b..9fd67eb 100644
--- a/tests/cputestdata/x86-host+guest,model486-result.xml
+++ b/tests/cputestdata/x86-host+guest,model486-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>486</model>
+  <model fallback='allow'>486</model>
   <feature policy='require' name='svm'/>
   <feature policy='require' name='lahf_lm'/>
   <feature policy='require' name='3dnowext'/>
diff --git a/tests/cputestdata/x86-host+guest,models,Penryn-result.xml b/tests/cputestdata/x86-host+guest,models,Penryn-result.xml
index 9559465..9ae11c9 100644
--- a/tests/cputestdata/x86-host+guest,models,Penryn-result.xml
+++ b/tests/cputestdata/x86-host+guest,models,Penryn-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>Nehalem</model>
+  <model fallback='allow'>Nehalem</model>
   <feature policy='require' name='svm'/>
   <feature policy='require' name='3dnowext'/>
   <feature policy='require' name='dca'/>
diff --git a/tests/cputestdata/x86-host+guest,models,qemu64-result.xml b/tests/cputestdata/x86-host+guest,models,qemu64-result.xml
index b41863e..7582ddc 100644
--- a/tests/cputestdata/x86-host+guest,models,qemu64-result.xml
+++ b/tests/cputestdata/x86-host+guest,models,qemu64-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>qemu64</model>
+  <model fallback='allow'>qemu64</model>
   <feature policy='require' name='lahf_lm'/>
   <feature policy='require' name='3dnowext'/>
   <feature policy='require' name='sse4.1'/>
diff --git a/tests/cputestdata/x86-host+guest,models-result.xml b/tests/cputestdata/x86-host+guest,models-result.xml
index 9559465..9ae11c9 100644
--- a/tests/cputestdata/x86-host+guest,models-result.xml
+++ b/tests/cputestdata/x86-host+guest,models-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>Nehalem</model>
+  <model fallback='allow'>Nehalem</model>
   <feature policy='require' name='svm'/>
   <feature policy='require' name='3dnowext'/>
   <feature policy='require' name='dca'/>
diff --git a/tests/cputestdata/x86-host+guest-result.xml b/tests/cputestdata/x86-host+guest-result.xml
index 544a388..e596c43 100644
--- a/tests/cputestdata/x86-host+guest-result.xml
+++ b/tests/cputestdata/x86-host+guest-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>Penryn</model>
+  <model fallback='allow'>Penryn</model>
   <feature policy='require' name='svm'/>
   <feature policy='require' name='3dnowext'/>
   <feature policy='require' name='dca'/>
diff --git a/tests/cputestdata/x86-host+guest.xml b/tests/cputestdata/x86-host+guest.xml
index c3fca87..2a786fd 100644
--- a/tests/cputestdata/x86-host+guest.xml
+++ b/tests/cputestdata/x86-host+guest.xml
@@ -1,5 +1,5 @@
 <cpu match='exact'>
-  <model>Penryn</model>
+  <model fallback='allow'>Penryn</model>
   <topology sockets='2' cores='4' threads='1'/>
   <feature policy='require' name='dca'/>
   <feature policy='require' name='xtpr'/>
diff --git a/tests/cputestdata/x86-host+min.xml b/tests/cputestdata/x86-host+min.xml
index d22c7b6..fe55058 100644
--- a/tests/cputestdata/x86-host+min.xml
+++ b/tests/cputestdata/x86-host+min.xml
@@ -1,5 +1,5 @@
 <cpu match='exact'>
-  <model>Penryn</model>
+  <model fallback='allow'>Penryn</model>
   <feature policy='require' name='dca'/>
   <feature policy='require' name='xtpr'/>
   <feature policy='require' name='tm2'/>
diff --git a/tests/cputestdata/x86-host+nehalem-force-result.xml b/tests/cputestdata/x86-host+nehalem-force-result.xml
index 162685f..41e7356 100644
--- a/tests/cputestdata/x86-host+nehalem-force-result.xml
+++ b/tests/cputestdata/x86-host+nehalem-force-result.xml
@@ -1,4 +1,4 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>Nehalem</model>
+  <model fallback='allow'>Nehalem</model>
 </cpu>
diff --git a/tests/cputestdata/x86-host+pentium3.xml b/tests/cputestdata/x86-host+pentium3.xml
index d141d9e..e122ba5 100644
--- a/tests/cputestdata/x86-host+pentium3.xml
+++ b/tests/cputestdata/x86-host+pentium3.xml
@@ -1,5 +1,5 @@
 <cpu match='exact'>
-  <model>pentium3</model>
+  <model fallback='allow'>pentium3</model>
   <feature policy='require' name='lahf_lm'/>
   <feature policy='require' name='lm'/>
   <feature policy='require' name='nx'/>
diff --git a/tests/cputestdata/x86-host+strict-force-extra-result.xml b/tests/cputestdata/x86-host+strict-force-extra-result.xml
index e47933c..f3d52a1 100644
--- a/tests/cputestdata/x86-host+strict-force-extra-result.xml
+++ b/tests/cputestdata/x86-host+strict-force-extra-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>Penryn</model>
+  <model fallback='allow'>Penryn</model>
   <feature policy='require' name='3dnow'/>
   <feature policy='require' name='dca'/>
   <feature policy='require' name='xtpr'/>
diff --git a/tests/cputestdata/x86-host-better+pentium3,core2duo-result.xml b/tests/cputestdata/x86-host-better+pentium3,core2duo-result.xml
index c2d8ddd..5d4528b 100644
--- a/tests/cputestdata/x86-host-better+pentium3,core2duo-result.xml
+++ b/tests/cputestdata/x86-host-better+pentium3,core2duo-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>core2duo</model>
+  <model fallback='allow'>core2duo</model>
   <feature policy='require' name='lahf_lm'/>
   <feature policy='require' name='popcnt'/>
   <feature policy='require' name='sse4.2'/>
diff --git a/tests/cputestdata/x86-host-better+pentium3,pentium3-result.xml b/tests/cputestdata/x86-host-better+pentium3,pentium3-result.xml
index 6e246a8..1530a07 100644
--- a/tests/cputestdata/x86-host-better+pentium3,pentium3-result.xml
+++ b/tests/cputestdata/x86-host-better+pentium3,pentium3-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>pentium3</model>
+  <model fallback='allow'>pentium3</model>
   <feature policy='require' name='lahf_lm'/>
   <feature policy='require' name='lm'/>
   <feature policy='require' name='nx'/>
diff --git a/tests/cputestdata/x86-host-better+pentium3-result.xml b/tests/cputestdata/x86-host-better+pentium3-result.xml
index b918363..917d63f 100644
--- a/tests/cputestdata/x86-host-better+pentium3-result.xml
+++ b/tests/cputestdata/x86-host-better+pentium3-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>Nehalem</model>
+  <model fallback='allow'>Nehalem</model>
   <feature policy='require' name='dca'/>
   <feature policy='require' name='xtpr'/>
   <feature policy='require' name='tm2'/>
diff --git a/tests/cputestdata/x86-host-worse+guest-result.xml b/tests/cputestdata/x86-host-worse+guest-result.xml
index 036177a..78e170a 100644
--- a/tests/cputestdata/x86-host-worse+guest-result.xml
+++ b/tests/cputestdata/x86-host-worse+guest-result.xml
@@ -1,6 +1,6 @@
 <cpu match='exact'>
   <arch>x86_64</arch>
-  <model>Penryn</model>
+  <model fallback='allow'>Penryn</model>
   <feature policy='require' name='svm'/>
   <feature policy='require' name='3dnowext'/>
   <feature policy='require' name='monitor'/>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml
index d6db442..b5fd49c 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml
@@ -9,7 +9,7 @@
     <boot dev='network'/>
   </os>
   <cpu match='exact'>
-    <model>qemu64</model>
+    <model fallback='allow'>qemu64</model>
     <feature policy='disable' name='svm'/>
     <feature policy='disable' name='lm'/>
     <feature policy='disable' name='nx'/>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.args
new file mode 100644
index 0000000..198d0d8
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.args
@@ -0,0 +1,4 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test ./qemu.sh -S -M pc \
+-cpu core2duo,+lahf_lm,+3dnowext,+xtpr,+ds_cpl,+tm,+ht,+ds,-nx -m 214 -smp 6 \
+-nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot n -net \
+none -serial none -parallel none -usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.xml
new file mode 100644
index 0000000..11de634
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.xml
@@ -0,0 +1,35 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219100</memory>
+  <currentMemory>219100</currentMemory>
+  <vcpu>6</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='network'/>
+  </os>
+  <cpu match='exact'>
+    <model fallback='forbid'>core2duo</model>
+    <feature name='lahf_lm' policy='require'/>
+    <feature name='xtpr' policy='require'/>
+    <feature name='cx16' policy='disable'/>
+    <feature name='tm2' policy='disable'/>
+    <feature name='ds_cpl' policy='require'/>
+    <feature name='pbe' policy='disable'/>
+    <feature name='tm' policy='optional'/>
+    <feature name='ht' policy='require'/>
+    <feature name='ss' policy='disable'/>
+    <feature name='ds' policy='require'/>
+    <feature name='nx' policy='disable'/>
+    <feature name='3dnowext' policy='force'/>
+    <feature name='sse4a' policy='optional'/>
+    <feature name='wdt' policy='forbid'/>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+      <emulator>/./qemu.sh</emulator>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.args
new file mode 100644
index 0000000..658f141
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.args
@@ -0,0 +1,19 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+./qemu.sh \
+-S \
+-M pc \
+-cpu Penryn,-sse4.1 \
+-m 214 \
+-smp 6 \
+-nographic \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-boot n \
+-net none \
+-serial none \
+-parallel none \
+-usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.xml
new file mode 100644
index 0000000..7bd28a8
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.xml
@@ -0,0 +1,25 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219100</memory>
+  <currentMemory>219100</currentMemory>
+  <vcpu>6</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='network'/>
+  </os>
+  <cpu match='exact'>
+    <model>Westmere</model>
+    <feature policy='disable' name='sse4.1'/>
+    <feature policy='disable' name='sse4.2'/>
+    <feature policy='disable' name='popcnt'/>
+    <feature policy='disable' name='aes'/>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+      <emulator>/./qemu.sh</emulator>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-nofallback.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-nofallback.xml
new file mode 100644
index 0000000..7f1f09a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-nofallback.xml
@@ -0,0 +1,25 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219100</memory>
+  <currentMemory>219100</currentMemory>
+  <vcpu>6</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='network'/>
+  </os>
+  <cpu match='exact'>
+    <model fallback='forbid'>Westmere</model>
+    <feature policy='disable' name='sse4.1'/>
+    <feature policy='disable' name='sse4.2'/>
+    <feature policy='disable' name='popcnt'/>
+    <feature policy='disable' name='aes'/>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+      <emulator>/./qemu.sh</emulator>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index d87654c..f944d82 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -84,7 +84,8 @@ static int testCompareXMLToArgvFiles(const char *xml,
                                      const char *migrateFrom,
                                      int migrateFd,
                                      bool json,
-                                     bool expectError)
+                                     bool expectError,
+                                     bool expectFailure)
 {
     char *expectargv = NULL;
     int len;
@@ -98,19 +99,13 @@ static int testCompareXMLToArgvFiles(const char *xml,
     virCommandPtr cmd = NULL;
 
     if (!(conn = virGetConnect()))
-        goto fail;
+        goto out;
     conn->secretDriver = &fakeSecretDriver;
 
-    len = virtTestLoadFile(cmdline, &expectargv);
-    if (len < 0)
-        goto fail;
-    if (len && expectargv[len - 1] == '\n')
-        expectargv[len - 1] = '\0';
-
     if (!(vmdef = virDomainDefParseFile(driver.caps, xml,
                                         QEMU_EXPECTED_VIRT_TYPES,
                                         VIR_DOMAIN_XML_INACTIVE)))
-        goto fail;
+        goto out;
 
     /*
      * For test purposes, we may want to fake emulator's output by providing
@@ -124,12 +119,12 @@ static int testCompareXMLToArgvFiles(const char *xml,
      */
     if (vmdef->emulator && STRPREFIX(vmdef->emulator, "/.")) {
         if (!(emulator = strdup(vmdef->emulator + 1)))
-            goto fail;
+            goto out;
         free(vmdef->emulator);
         vmdef->emulator = NULL;
         if (virAsprintf(&vmdef->emulator, "%s/qemuxml2argvdata/%s",
                         abs_srcdir, emulator) < 0)
-            goto fail;
+            goto out;
     }
 
     if (qemuCapsGet(extraFlags, QEMU_CAPS_DOMID))
@@ -149,15 +144,15 @@ static int testCompareXMLToArgvFiles(const char *xml,
                     QEMU_CAPS_LAST);
 
     if (qemudCanonicalizeMachine(&driver, vmdef) < 0)
-        goto fail;
+        goto out;
 
     if (qemuCapsGet(extraFlags, QEMU_CAPS_DEVICE)) {
         qemuDomainPCIAddressSetPtr pciaddrs;
         if (!(pciaddrs = qemuDomainPCIAddressSetCreate(vmdef)))
-            goto fail;
+            goto out;
 
         if (qemuAssignDevicePCISlots(vmdef, pciaddrs) < 0)
-            goto fail;
+            goto out;
 
         qemuDomainPCIAddressSetFree(pciaddrs);
     }
@@ -176,18 +171,27 @@ static int testCompareXMLToArgvFiles(const char *xml,
     }
 
     if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0)
-        goto fail;
+        goto out;
 
     if (!(cmd = qemuBuildCommandLine(conn, &driver,
                                      vmdef, &monitor_chr, json, extraFlags,
                                      migrateFrom, migrateFd, NULL,
-                                     VIR_NETDEV_VPORT_PROFILE_OP_NO_OP)))
-        goto fail;
+                                     VIR_NETDEV_VPORT_PROFILE_OP_NO_OP))) {
+        if (expectFailure) {
+            ret = 0;
+            virResetLastError();
+        }
+        goto out;
+    } else if (expectFailure) {
+        if (virTestGetDebug())
+            fprintf(stderr, "qemuBuildCommandLine should have failed\n");
+        goto out;
+    }
 
     if (!!virGetLastError() != expectError) {
         if (virTestGetDebug() && (log = virtTestLogContentAndReset()))
             fprintf(stderr, "\n%s", log);
-        goto fail;
+        goto out;
     }
 
     if (expectError) {
@@ -196,25 +200,31 @@ static int testCompareXMLToArgvFiles(const char *xml,
     }
 
     if (!(actualargv = virCommandToString(cmd)))
-        goto fail;
+        goto out;
 
     if (emulator) {
         /* Skip the abs_srcdir portion of replacement emulator.  */
         char *start_skip = strstr(actualargv, abs_srcdir);
         char *end_skip = strstr(actualargv, emulator);
         if (!start_skip || !end_skip)
-            goto fail;
+            goto out;
         memmove(start_skip, end_skip, strlen(end_skip) + 1);
     }
 
+    len = virtTestLoadFile(cmdline, &expectargv);
+    if (len < 0)
+        goto out;
+    if (len && expectargv[len - 1] == '\n')
+        expectargv[len - 1] = '\0';
+
     if (STRNEQ(expectargv, actualargv)) {
         virtTestDifference(stderr, expectargv, actualargv);
-        goto fail;
+        goto out;
     }
 
     ret = 0;
 
- fail:
+out:
     free(log);
     free(emulator);
     free(expectargv);
@@ -232,6 +242,7 @@ struct testInfo {
     const char *migrateFrom;
     int migrateFd;
     bool expectError;
+    bool expectFailure;
 };
 
 static int
@@ -252,7 +263,8 @@ testCompareXMLToArgvHelper(const void *data)
                                        info->migrateFrom, info->migrateFd,
                                        qemuCapsGet(info->extraFlags,
                                                    QEMU_CAPS_MONITOR_JSON),
-                                       info->expectError);
+                                       info->expectError,
+                                       info->expectFailure);
 
 cleanup:
     free(xml);
@@ -291,10 +303,12 @@ mymain(void)
         return EXIT_FAILURE;
     }
 
-# define DO_TEST_FULL(name, migrateFrom, migrateFd, expectError, ...)   \
+# define DO_TEST_FULL(name, migrateFrom, migrateFd,                     \
+                      expectError, expectFailure, ...)                  \
     do {                                                                \
         struct testInfo info = {                                        \
-            name, NULL, migrateFrom, migrateFd, expectError             \
+            name, NULL, migrateFrom, migrateFd,                         \
+            expectError, expectFailure                                  \
         };                                                              \
         if (!(info.extraFlags = qemuCapsNew()))                         \
             return EXIT_FAILURE;                                        \
@@ -306,7 +320,10 @@ mymain(void)
     } while (0)
 
 # define DO_TEST(name, expectError, ...)                                \
-    DO_TEST_FULL(name, NULL, -1, expectError, __VA_ARGS__)
+    DO_TEST_FULL(name, NULL, -1, expectError, false, __VA_ARGS__)
+
+# define DO_TEST_FAILURE(name, ...)                                     \
+    DO_TEST_FULL(name, NULL, -1, false, true, __VA_ARGS__)
 
 # define NONE QEMU_CAPS_LAST
 
@@ -624,17 +641,17 @@ mymain(void)
     DO_TEST("hostdev-pci-address-device", false,
             QEMU_CAPS_PCIDEVICE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
 
-    DO_TEST_FULL("restore-v1", "stdio", 7, false,
+    DO_TEST_FULL("restore-v1", "stdio", 7, false, false,
             QEMU_CAPS_MIGRATE_KVM_STDIO);
-    DO_TEST_FULL("restore-v2", "stdio", 7, false,
+    DO_TEST_FULL("restore-v2", "stdio", 7, false, false,
             QEMU_CAPS_MIGRATE_QEMU_EXEC);
-    DO_TEST_FULL("restore-v2", "exec:cat", 7, false,
+    DO_TEST_FULL("restore-v2", "exec:cat", 7, false, false,
             QEMU_CAPS_MIGRATE_QEMU_EXEC);
-    DO_TEST_FULL("restore-v2-fd", "stdio", 7, false,
+    DO_TEST_FULL("restore-v2-fd", "stdio", 7, false, false,
             QEMU_CAPS_MIGRATE_QEMU_FD);
-    DO_TEST_FULL("restore-v2-fd", "fd:7", 7, false,
+    DO_TEST_FULL("restore-v2-fd", "fd:7", 7, false, false,
             QEMU_CAPS_MIGRATE_QEMU_FD);
-    DO_TEST_FULL("migrate", "tcp:10.0.0.1:5000", -1, false,
+    DO_TEST_FULL("migrate", "tcp:10.0.0.1:5000", -1, false, false,
             QEMU_CAPS_MIGRATE_QEMU_TCP);
 
     DO_TEST("qemu-ns", false, NONE);
@@ -648,6 +665,9 @@ mymain(void)
     DO_TEST("cpu-minimum2", false, NONE);
     DO_TEST("cpu-exact1", false, NONE);
     DO_TEST("cpu-exact2", false, NONE);
+    DO_TEST("cpu-exact2-nofallback", false, NONE);
+    DO_TEST("cpu-fallback", false, NONE);
+    DO_TEST_FAILURE("cpu-nofallback", NONE);
     DO_TEST("cpu-strict1", false, NONE);
     DO_TEST("cpu-numa1", false, NONE);
     DO_TEST("cpu-numa2", false, QEMU_CAPS_SMP_TOPOLOGY);
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml
new file mode 100644
index 0000000..caa5f0a
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml
@@ -0,0 +1,86 @@
+<domain type='qemu'>
+  <name>f14</name>
+  <uuid>553effab-b5e1-2d80-dfe3-da4344826c43</uuid>
+  <memory>1048576</memory>
+  <currentMemory>1048576</currentMemory>
+  <vcpu>2</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='cdrom'/>
+    <boot dev='hd'/>
+    <bootmenu enable='yes'/>
+  </os>
+  <features>
+    <acpi/>
+    <apic/>
+    <pae/>
+  </features>
+  <cpu match='exact'>
+    <model fallback='allow'>core2duo</model>
+    <vendor>Intel</vendor>
+    <topology sockets='1' cores='2' threads='1'/>
+    <feature policy='require' name='lahf_lm'/>
+    <feature policy='require' name='xtpr'/>
+    <feature policy='require' name='cx16'/>
+    <feature policy='require' name='tm2'/>
+    <feature policy='require' name='est'/>
+    <feature policy='require' name='vmx'/>
+    <feature policy='require' name='ds_cpl'/>
+    <feature policy='require' name='pbe'/>
+    <feature policy='require' name='tm'/>
+    <feature policy='require' name='ht'/>
+    <feature policy='require' name='ss'/>
+    <feature policy='require' name='acpi'/>
+    <feature policy='require' name='ds'/>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <emulator>/./qemu.sh</emulator>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='qcow2'/>
+      <source file='/var/lib/libvirt/images/f14.img'/>
+      <target dev='vda' bus='virtio'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </disk>
+    <disk type='file' device='cdrom'>
+      <driver name='qemu' type='raw'/>
+      <source file='/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso'/>
+      <target dev='hdc' bus='ide'/>
+      <readonly/>
+      <address type='drive' controller='0' bus='1' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='virtio-serial' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+    </controller>
+    <interface type='ethernet'>
+      <mac address='52:54:00:71:70:89'/>
+      <script path='/etc/qemu-ifup'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+    </interface>
+    <serial type='pty'>
+      <target port='0'/>
+    </serial>
+    <console type='pty'>
+      <target type='serial' port='0'/>
+    </console>
+    <input type='tablet' bus='usb'/>
+    <input type='mouse' bus='ps2'/>
+    <graphics type='spice' port='5900' autoport='no' passwd='sercet' passwdValidTo='2011-05-31T16:11:22' connected='disconnect'/>
+    <sound model='ac97'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </sound>
+    <video>
+      <model type='vga' vram='9216' heads='1'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+    </video>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 2cc1f7d..3c85c2f 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -147,7 +147,6 @@ mymain(void)
     DO_TEST("graphics-sdl-fullscreen");
     DO_TEST("graphics-spice");
     DO_TEST("graphics-spice-compression");
-    DO_TEST("graphics-spice-timeout");
     DO_TEST("graphics-spice-qxl-vga");
     DO_TEST("input-usbmouse");
     DO_TEST("input-usbtablet");
@@ -207,6 +206,7 @@ mymain(void)
     DO_TEST_DIFFERENT("console-virtio");
     DO_TEST_DIFFERENT("serial-target-port-auto");
     DO_TEST_DIFFERENT("graphics-listen-network2");
+    DO_TEST_DIFFERENT("graphics-spice-timeout");
 
     virCapabilitiesFree(driver.caps);
 
diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
index fa6422a..c6adec9 100644
--- a/tests/testutilsqemu.c
+++ b/tests/testutilsqemu.c
@@ -115,6 +115,7 @@ virCapsPtr testQemuCapsInit(void) {
         0,                      /* match */
         (char *) "x86_64",      /* arch */
         (char *) "core2duo",    /* model */
+        0,                      /* fallback */
         (char *) "Intel",       /* vendor */
         1,                      /* sockets */
         2,                      /* cores */
-- 
1.7.8.3




More information about the libvir-list mailing list