[libvirt] [PATCH 0/6] Enhancements in CPU selection

The main goal of this series is to provide an easy way to say that a guest CPU should match host. Details can be found in individual patches. Jiri Denemark (6): tests: Print XML file name in verbose CPU test cpu: Optionally forbid fallback CPU models Add support for cpu mode attribute cpu: Update guest CPU in host-* mode Taint domains configured with cpu mode=host-passthrough qemu: Add support for host CPU modes docs/formatdomain.html.in | 12 +- docs/schemas/domaincommon.rng | 32 +++ src/conf/capabilities.c | 2 +- src/conf/cpu_conf.c | 264 +++++++++++++++----- src/conf/cpu_conf.h | 38 +++- src/conf/domain_conf.c | 5 +- src/conf/domain_conf.h | 1 + src/cpu/cpu.c | 2 +- src/cpu/cpu_x86.c | 47 ++++- src/libvirt_private.syms | 3 + src/qemu/qemu_capabilities.c | 5 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 96 +++++--- src/qemu/qemu_domain.c | 15 +- tests/cputest.c | 22 ++- tests/cputestdata/x86-baseline-1-result.xml | 4 +- tests/cputestdata/x86-baseline-2-result.xml | 4 +- .../cputestdata/x86-baseline-no-vendor-result.xml | 4 +- .../x86-baseline-some-vendors-result.xml | 4 +- tests/cputestdata/x86-guest-nofallback.xml | 18 ++ .../cputestdata/x86-host+guest,model486-result.xml | 4 +- .../x86-host+guest,models,Penryn-result.xml | 4 +- .../x86-host+guest,models,qemu64-result.xml | 4 +- tests/cputestdata/x86-host+guest,models-result.xml | 4 +- tests/cputestdata/x86-host+guest-result.xml | 4 +- tests/cputestdata/x86-host+guest.xml | 4 +- ...6-host+host+host-model,models,Penryn-result.xml | 19 ++ .../cputestdata/x86-host+host-model-nofallback.xml | 19 ++ tests/cputestdata/x86-host+host-model.xml | 18 ++ tests/cputestdata/x86-host+host-passthrough.xml | 18 ++ tests/cputestdata/x86-host+min.xml | 4 +- .../cputestdata/x86-host+nehalem-force-result.xml | 4 +- tests/cputestdata/x86-host+pentium3.xml | 4 +- .../x86-host+strict-force-extra-result.xml | 4 +- .../x86-host-better+pentium3,core2duo-result.xml | 4 +- .../x86-host-better+pentium3,pentium3-result.xml | 4 +- .../x86-host-better+pentium3-result.xml | 4 +- tests/cputestdata/x86-host-model-nofallback.xml | 4 + tests/cputestdata/x86-host-model.xml | 1 + tests/cputestdata/x86-host-passthrough.xml | 1 + tests/cputestdata/x86-host-worse+guest-result.xml | 4 +- tests/qemuhelptest.c | 21 +- tests/qemuxml2argvdata/qemu-lib.sh | 50 ++++ tests/qemuxml2argvdata/qemu-supported-cpus.sh | 15 ++ tests/qemuxml2argvdata/qemu.sh | 51 +---- 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-host-model-fallback.args | 19 ++ .../qemuxml2argv-cpu-host-model-fallback.xml | 19 ++ .../qemuxml2argv-cpu-host-model-nofallback.xml | 21 ++ .../qemuxml2argv-cpu-host-model.args | 19 ++ .../qemuxml2argv-cpu-host-model.xml | 19 ++ .../qemuxml2argv-cpu-host-passthrough.args | 19 ++ .../qemuxml2argv-cpu-host-passthrough.xml | 19 ++ .../qemuxml2argv-cpu-nofallback.xml | 25 ++ .../qemuxml2argv-cpu-qemu-host-passthrough.xml | 19 ++ tests/qemuxml2argvtest.c | 91 +++++--- .../qemuxml2xmlout-graphics-spice-timeout.xml | 86 +++++++ tests/qemuxml2xmltest.c | 2 +- tests/testutilsqemu.c | 2 + 63 files changed, 1053 insertions(+), 244 deletions(-) create mode 100644 tests/cputestdata/x86-guest-nofallback.xml create mode 100644 tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml create mode 100644 tests/cputestdata/x86-host+host-model-nofallback.xml create mode 100644 tests/cputestdata/x86-host+host-model.xml create mode 100644 tests/cputestdata/x86-host+host-passthrough.xml create mode 100644 tests/cputestdata/x86-host-model-nofallback.xml create mode 100644 tests/cputestdata/x86-host-model.xml create mode 100644 tests/cputestdata/x86-host-passthrough.xml create mode 100644 tests/qemuxml2argvdata/qemu-lib.sh create mode 100755 tests/qemuxml2argvdata/qemu-supported-cpus.sh 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-host-model-fallback.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-nofallback.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-passthrough.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-passthrough.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-nofallback.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-qemu-host-passthrough.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml -- 1.7.8.2

It's not totally obvious that a failure in CPU guest data(x86): host/guest (models, pref="qemu64") test means one needs to fix x86-host+guest,models,qemu64-result.xml where the expected XML is stored. Better to provide a nice hint in verbose mode for failed tests. --- tests/cputest.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/tests/cputest.c b/tests/cputest.c index 36b3eb4..5b7b951 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -180,6 +180,8 @@ cpuTestCompareXML(const char *arch, goto cleanup; if (STRNEQ(expected, actual)) { + if (virTestGetVerbose()) + fprintf(stderr, "\nCompared to %s-%s.xml", arch, name); virtTestDifference(stderr, expected, actual); goto cleanup; } -- 1.7.8.2

On 01/06/2012 08:04 AM, Jiri Denemark wrote:
It's not totally obvious that a failure in CPU guest data(x86): host/guest (models, pref="qemu64") test means one needs to fix x86-host+guest,models,qemu64-result.xml where the expected XML is stored. Better to provide a nice hint in verbose mode for failed tests. --- tests/cputest.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/tests/cputest.c b/tests/cputest.c index 36b3eb4..5b7b951 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -180,6 +180,8 @@ cpuTestCompareXML(const char *arch, goto cleanup;
if (STRNEQ(expected, actual)) { + if (virTestGetVerbose()) + fprintf(stderr, "\nCompared to %s-%s.xml", arch, name);
I'm guessing this helped you debug later patches in the series :) ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

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. --- 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 18b7e22..b135ce6 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> 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 353faea..ff535a8 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2458,6 +2458,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 69bf868..334c1a4 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3430,6 +3430,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 69e2612..5c20bdf 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 @@ -614,17 +631,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); @@ -638,6 +655,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 0a8a28e..49b2284 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"); @@ -206,6 +205,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.2

On 01/06/2012 08:04 AM, Jiri Denemark wrote:
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. --- 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 +
The meat of the patch, followed by lots of mechanical fallout...
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 +
I guess adding the new attribute on output even if it matches the default when the attribute was omitted on input is reasonable.
@@ -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> optional
grammar: s/0.9.10 optional/0.9.10, an optional/ I'm not sure whether the ',' in the above replacement belongs inside or outside the <span>. ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

The mode can be either of "custom" (default), "host-model", "host-passthrough". The semantics of each mode is described in the following examples: - guest CPU is a default model with specified topology: <cpu mode='custom'> <topology sockets='1' cores='2' threads='1'/> </cpu> - guest CPU matches selected model: <cpu mode='custom' match='exact'> <model>core2duo</model> </cpu> - guest CPU should be a copy of host CPU as advertised by capabilities XML (this is a short cut for manually copying host CPU specification from capabilities to domain XML): <cpu mode='host-model'/> In case a hypervisor does not support the exact host model, libvirt automatically falls back to a closest supported CPU model and removes/adds features to match host. This behavior can be disabled by <cpu mode='host-model'> <model fallback='forbid'/> </cpu> - the same as previous returned by virDomainGetXMLDesc with VIR_DOMAIN_XML_UPDATE_CPU flag: <cpu mode='host-model' match='exact'> <model fallback='allow'>Penryn</model> --+ <vendor>Intel</vendor> | <topology sockets='2' cores='4' threads='1'/> + copied from <feature policy='require' name='dca'/> | capabilities XML <feature policy='require' name='xtpr'/> | ... --+ </cpu> - guest CPU should be exactly the same as host CPU even in the aspects libvirt doesn't model (such domain cannot be migrated unless both hosts contain exactly the same CPUs): <cpu mode='host-passthrough'/> - the same as previous returned by virDomainGetXMLDesc with VIR_DOMAIN_XML_UPDATE_CPU flag: <cpu mode='host-passthrough' match='minimal'> <model>Penryn</model> --+ copied from caps <vendor>Intel</vendor> | XML but doesn't <topology sockets='2' cores='4' threads='1'/> | describe all <feature policy='require' name='dca'/> | aspects of the <feature policy='require' name='xtpr'/> | actual guest CPU ... --+ </cpu> --- Oh man, I just realized I forgot to update documentation. I'll transform this commit message into a proper documentation in the next version of this series. But it shouldn't be a showstopper for normal review :-) docs/schemas/domaincommon.rng | 24 +++ src/conf/capabilities.c | 2 +- src/conf/cpu_conf.c | 159 ++++++++++++++------ src/conf/cpu_conf.h | 20 ++- src/conf/domain_conf.c | 2 +- src/cpu/cpu.c | 2 +- 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 +- .../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 +- .../qemuxml2xmlout-graphics-spice-timeout.xml | 2 +- tests/testutilsqemu.c | 1 + 27 files changed, 181 insertions(+), 69 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index ff535a8..3d7482d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2425,6 +2425,20 @@ </interleave> </group> <group> + <ref name="cpuMode"/> + <interleave> + <optional> + <ref name="cpuModel"/> + </optional> + <optional> + <ref name="cpuNuma"/> + </optional> + </interleave> + </group> + <group> + <optional> + <ref name="cpuMode"/> + </optional> <ref name="cpuMatch"/> <interleave> <ref name="cpuModel"/> @@ -2446,6 +2460,16 @@ </element> </define> + <define name="cpuMode"> + <attribute name="mode"> + <choice> + <value>custom</value> + <value>host-model</value> + <value>host-passthrough</value> + </choice> + </attribute> + </define> + <define name="cpuMatch"> <attribute name="match"> <choice> diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index ac050df..ed0ae99 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -691,7 +691,7 @@ virCapabilitiesFormatXML(virCapsPtr caps) } virBufferAdjustIndent(&xml, 6); - virCPUDefFormatBuf(&xml, caps->host.cpu); + virCPUDefFormatBuf(&xml, caps->host.cpu, 0); virBufferAdjustIndent(&xml, -6); virBufferAddLit(&xml, " </cpu>\n"); diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index c8e29e4..31862e2 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -39,6 +39,11 @@ VIR_ENUM_IMPL(virCPU, VIR_CPU_TYPE_LAST, "host", "guest", "auto") +VIR_ENUM_IMPL(virCPUMode, VIR_CPU_MODE_LAST, + "custom", + "host-model", + "host-passthrough") + VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST, "minimum", "exact", @@ -100,6 +105,7 @@ virCPUDefCopy(const virCPUDefPtr cpu) copy->nfeatures_max = cpu->nfeatures; copy->type = cpu->type; + copy->mode = cpu->mode; copy->match = cpu->match; copy->fallback = cpu->fallback; copy->sockets = cpu->sockets; @@ -151,6 +157,7 @@ virCPUDefParseXML(const xmlNodePtr node, xmlNodePtr *nodes = NULL; int n; unsigned int i; + char *cpuMode; if (!xmlStrEqual(node->name, BAD_CAST "cpu")) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, @@ -173,10 +180,35 @@ virCPUDefParseXML(const xmlNodePtr node, goto error; } def->type = VIR_CPU_TYPE_HOST; - } else + } else { def->type = VIR_CPU_TYPE_GUEST; - } else + } + } else { def->type = mode; + } + + if ((cpuMode = virXMLPropString(node, "mode"))) { + if (def->type == VIR_CPU_TYPE_HOST) { + VIR_FREE(cpuMode); + virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Attribute mode is only allowed for guest CPU")); + goto error; + } else { + def->mode = virCPUModeTypeFromString(cpuMode); + VIR_FREE(cpuMode); + + if (def->mode < 0) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Invalid mode attribute")); + goto error; + } + } + } else { + if (def->type == VIR_CPU_TYPE_HOST) + def->mode = -1; + else + def->mode = VIR_CPU_MODE_CUSTOM; + } if (def->type == VIR_CPU_TYPE_GUEST) { char *match = virXMLPropString(node, "match"); @@ -214,7 +246,9 @@ virCPUDefParseXML(const xmlNodePtr node, goto error; } - if (def->model && def->type == VIR_CPU_TYPE_GUEST) { + if (def->type == VIR_CPU_TYPE_GUEST && + def->mode != VIR_CPU_MODE_HOST_PASSTHROUGH && + virXPathBoolean("boolean(./model[1]/@fallback)", ctxt)) { const char *fallback; fallback = virXPathString("string(./model[1]/@fallback)", ctxt); @@ -311,9 +345,9 @@ virCPUDefParseXML(const xmlNodePtr node, "%s", _("Invalid CPU feature policy")); goto error; } - } - else + } else { policy = -1; + } if (!(name = virXMLPropString(nodes[i], "name")) || *name == 0) { VIR_FREE(name); @@ -407,11 +441,12 @@ error: char * -virCPUDefFormat(virCPUDefPtr def) +virCPUDefFormat(virCPUDefPtr def, + unsigned int flags) { virBuffer buf = VIR_BUFFER_INITIALIZER; - if (virCPUDefFormatBufFull(&buf, def) < 0) + if (virCPUDefFormatBufFull(&buf, def, flags) < 0) goto cleanup; if (virBufferError(&buf)) @@ -429,29 +464,44 @@ cleanup: int virCPUDefFormatBufFull(virBufferPtr buf, - virCPUDefPtr def) + virCPUDefPtr def, + unsigned int flags) { if (!def) return 0; - if (def->type == VIR_CPU_TYPE_GUEST && def->model) { - const char *match; - if (!(match = virCPUMatchTypeToString(def->match))) { - virCPUReportError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected CPU match policy %d"), def->match); - return -1; + virBufferAddLit(buf, "<cpu"); + if (def->type == VIR_CPU_TYPE_GUEST) { + const char *tmp; + + if (def->mode != VIR_CPU_MODE_CUSTOM || def->model) { + if (!(tmp = virCPUModeTypeToString(def->mode))) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected CPU mode %d"), def->mode); + return -1; + } + virBufferAsprintf(buf, " mode='%s'", tmp); } - virBufferAsprintf(buf, "<cpu match='%s'>\n", match); - } else { - virBufferAddLit(buf, "<cpu>\n"); + if (def->model && + (def->mode == VIR_CPU_MODE_CUSTOM || + (flags & VIR_DOMAIN_XML_UPDATE_CPU))) { + if (!(tmp = virCPUMatchTypeToString(def->match))) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected CPU match policy %d"), + def->match); + return -1; + } + virBufferAsprintf(buf, " match='%s'", tmp); + } } + virBufferAddLit(buf, ">\n"); if (def->arch) virBufferAsprintf(buf, " <arch>%s</arch>\n", def->arch); virBufferAdjustIndent(buf, 2); - if (virCPUDefFormatBuf(buf, def) < 0) + if (virCPUDefFormatBuf(buf, def, flags) < 0) return -1; virBufferAdjustIndent(buf, -2); @@ -462,22 +512,31 @@ virCPUDefFormatBufFull(virBufferPtr buf, int virCPUDefFormatBuf(virBufferPtr buf, - virCPUDefPtr def) + virCPUDefPtr def, + unsigned int flags) { unsigned int i; + bool formatModel; + bool formatFallback; if (!def) return 0; + formatModel = (def->mode == VIR_CPU_MODE_CUSTOM || + (flags & VIR_DOMAIN_XML_UPDATE_CPU)); + formatFallback = (def->type == VIR_CPU_TYPE_GUEST && + (def->mode == VIR_CPU_MODE_HOST_MODEL || + (def->mode == VIR_CPU_MODE_CUSTOM && def->model))); + if (!def->model && def->nfeatures) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Non-empty feature list specified without CPU model")); return -1; } - if (def->model) { + if ((formatModel && def->model) || formatFallback) { virBufferAddLit(buf, "<model"); - if (def->type == VIR_CPU_TYPE_GUEST) { + if (formatFallback) { const char *fallback; fallback = virCPUFallbackTypeToString(def->fallback); @@ -489,12 +548,15 @@ virCPUDefFormatBuf(virBufferPtr buf, } virBufferAsprintf(buf, " fallback='%s'", fallback); } - virBufferAsprintf(buf, ">%s</model>\n", def->model); + if (formatModel && def->model) { + virBufferAsprintf(buf, ">%s</model>\n", def->model); + } else { + virBufferAddLit(buf, "/>\n"); + } } - if (def->vendor) { + if (formatModel && def->vendor) virBufferAsprintf(buf, "<vendor>%s</vendor>\n", def->vendor); - } if (def->sockets && def->cores && def->threads) { virBufferAddLit(buf, "<topology"); @@ -504,29 +566,32 @@ virCPUDefFormatBuf(virBufferPtr buf, virBufferAddLit(buf, "/>\n"); } - for (i = 0 ; i < def->nfeatures ; i++) { - virCPUFeatureDefPtr feature = def->features + i; + if (formatModel) { + for (i = 0 ; i < def->nfeatures ; i++) { + virCPUFeatureDefPtr feature = def->features + i; - if (!feature->name) { - virCPUReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing CPU feature name")); - return -1; - } - - if (def->type == VIR_CPU_TYPE_GUEST) { - const char *policy; - - policy = virCPUFeaturePolicyTypeToString(feature->policy); - if (!policy) { + if (!feature->name) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected CPU feature policy %d"), feature->policy); + "%s", _("Missing CPU feature name")); return -1; } - virBufferAsprintf(buf, "<feature policy='%s' name='%s'/>\n", - policy, feature->name); - } else { - virBufferAsprintf(buf, "<feature name='%s'/>\n", - feature->name); + + if (def->type == VIR_CPU_TYPE_GUEST) { + const char *policy; + + policy = virCPUFeaturePolicyTypeToString(feature->policy); + if (!policy) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected CPU feature policy %d"), + feature->policy); + return -1; + } + virBufferAsprintf(buf, "<feature policy='%s' name='%s'/>\n", + policy, feature->name); + } else { + virBufferAsprintf(buf, "<feature name='%s'/>\n", + feature->name); + } } } @@ -603,6 +668,14 @@ virCPUDefIsEqual(virCPUDefPtr src, goto cleanup; } + if (src->mode != dst->mode) { + virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target CPU mode %s does not match source %s"), + virCPUModeTypeToString(dst->mode), + virCPUModeTypeToString(src->mode)); + goto cleanup; + } + if (STRNEQ_NULLABLE(src->arch, dst->arch)) { virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Target CPU arch %s does not match source %s"), diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 0c50f90..4b0b35b 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -38,6 +38,16 @@ enum virCPUType { VIR_ENUM_DECL(virCPU) +enum virCPUMode { + VIR_CPU_MODE_CUSTOM, + VIR_CPU_MODE_HOST_MODEL, + VIR_CPU_MODE_HOST_PASSTHROUGH, + + VIR_CPU_MODE_LAST +}; + +VIR_ENUM_DECL(virCPUMode) + enum virCPUMatch { VIR_CPU_MATCH_MINIMUM, VIR_CPU_MATCH_EXACT, @@ -89,6 +99,7 @@ typedef struct _virCPUDef virCPUDef; typedef virCPUDef *virCPUDefPtr; struct _virCPUDef { int type; /* enum virCPUType */ + int mode; /* enum virCPUMode */ int match; /* enum virCPUMatch */ char *arch; char *model; @@ -123,14 +134,17 @@ virCPUDefIsEqual(virCPUDefPtr src, virCPUDefPtr dst); char * -virCPUDefFormat(virCPUDefPtr def); +virCPUDefFormat(virCPUDefPtr def, + unsigned int flags); int virCPUDefFormatBuf(virBufferPtr buf, - virCPUDefPtr def); + virCPUDefPtr def, + unsigned int flags); int virCPUDefFormatBufFull(virBufferPtr buf, - virCPUDefPtr def); + virCPUDefPtr def, + unsigned int flags); int virCPUDefAddFeature(virCPUDefPtr cpu, diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7327667..ae007b1 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -11648,7 +11648,7 @@ virDomainDefFormatInternal(virDomainDefPtr def, } virBufferAdjustIndent(buf, 2); - if (virCPUDefFormatBufFull(buf, def->cpu) < 0) + if (virCPUDefFormatBufFull(buf, def->cpu, flags) < 0) goto cleanup; virBufferAdjustIndent(buf, -2); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index e4149e2..1f39934 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -322,7 +322,7 @@ cpuBaselineXML(const char **xmlCPUs, if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels))) goto error; - cpustr = virCPUDefFormat(cpu); + cpustr = virCPUDefFormat(cpu, 0); cleanup: if (cpus) { diff --git a/tests/cputest.c b/tests/cputest.c index 2dd89f2..d8c1713 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -176,7 +176,7 @@ cpuTestCompareXML(const char *arch, if (virtTestLoadFile(xml, &expected) < 0) goto cleanup; - if (!(actual = virCPUDefFormat(cpu))) + if (!(actual = virCPUDefFormat(cpu, 0))) goto cleanup; if (STRNEQ(expected, actual)) { diff --git a/tests/cputestdata/x86-baseline-1-result.xml b/tests/cputestdata/x86-baseline-1-result.xml index 99e43d0..96c4f43 100644 --- a/tests/cputestdata/x86-baseline-1-result.xml +++ b/tests/cputestdata/x86-baseline-1-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <model fallback='allow'>Conroe</model> <vendor>Intel</vendor> <feature policy='disable' name='lahf_lm'/> diff --git a/tests/cputestdata/x86-baseline-2-result.xml b/tests/cputestdata/x86-baseline-2-result.xml index 76c13aa..a11352d 100644 --- a/tests/cputestdata/x86-baseline-2-result.xml +++ b/tests/cputestdata/x86-baseline-2-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <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 8b97d2c..a14bb7e 100644 --- a/tests/cputestdata/x86-baseline-no-vendor-result.xml +++ b/tests/cputestdata/x86-baseline-no-vendor-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <model fallback='allow'>Opteron_G2</model> <feature policy='disable' name='svm'/> <feature policy='disable' name='rdtscp'/> diff --git a/tests/cputestdata/x86-baseline-some-vendors-result.xml b/tests/cputestdata/x86-baseline-some-vendors-result.xml index bac0e5d..2927611 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'> +<cpu mode='custom' match='exact'> <model fallback='allow'>Opteron_G1</model> </cpu> diff --git a/tests/cputestdata/x86-host+guest,model486-result.xml b/tests/cputestdata/x86-host+guest,model486-result.xml index 9fd67eb..e21c8b8 100644 --- a/tests/cputestdata/x86-host+guest,model486-result.xml +++ b/tests/cputestdata/x86-host+guest,model486-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>486</model> <feature policy='require' name='svm'/> diff --git a/tests/cputestdata/x86-host+guest,models,Penryn-result.xml b/tests/cputestdata/x86-host+guest,models,Penryn-result.xml index 9ae11c9..6a31dcd 100644 --- a/tests/cputestdata/x86-host+guest,models,Penryn-result.xml +++ b/tests/cputestdata/x86-host+guest,models,Penryn-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>Nehalem</model> <feature policy='require' name='svm'/> diff --git a/tests/cputestdata/x86-host+guest,models,qemu64-result.xml b/tests/cputestdata/x86-host+guest,models,qemu64-result.xml index 7582ddc..1f15d6e 100644 --- a/tests/cputestdata/x86-host+guest,models,qemu64-result.xml +++ b/tests/cputestdata/x86-host+guest,models,qemu64-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>qemu64</model> <feature policy='require' name='lahf_lm'/> diff --git a/tests/cputestdata/x86-host+guest,models-result.xml b/tests/cputestdata/x86-host+guest,models-result.xml index 9ae11c9..6a31dcd 100644 --- a/tests/cputestdata/x86-host+guest,models-result.xml +++ b/tests/cputestdata/x86-host+guest,models-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>Nehalem</model> <feature policy='require' name='svm'/> diff --git a/tests/cputestdata/x86-host+guest-result.xml b/tests/cputestdata/x86-host+guest-result.xml index e596c43..9d37dec 100644 --- a/tests/cputestdata/x86-host+guest-result.xml +++ b/tests/cputestdata/x86-host+guest-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>Penryn</model> <feature policy='require' name='svm'/> diff --git a/tests/cputestdata/x86-host+guest.xml b/tests/cputestdata/x86-host+guest.xml index 2a786fd..137a3d6 100644 --- a/tests/cputestdata/x86-host+guest.xml +++ b/tests/cputestdata/x86-host+guest.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <model fallback='allow'>Penryn</model> <topology sockets='2' cores='4' threads='1'/> <feature policy='require' name='dca'/> diff --git a/tests/cputestdata/x86-host+min.xml b/tests/cputestdata/x86-host+min.xml index fe55058..8101151 100644 --- a/tests/cputestdata/x86-host+min.xml +++ b/tests/cputestdata/x86-host+min.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <model fallback='allow'>Penryn</model> <feature policy='require' name='dca'/> <feature policy='require' name='xtpr'/> diff --git a/tests/cputestdata/x86-host+nehalem-force-result.xml b/tests/cputestdata/x86-host+nehalem-force-result.xml index 41e7356..000bc0d 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'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>Nehalem</model> </cpu> diff --git a/tests/cputestdata/x86-host+pentium3.xml b/tests/cputestdata/x86-host+pentium3.xml index e122ba5..d46525c 100644 --- a/tests/cputestdata/x86-host+pentium3.xml +++ b/tests/cputestdata/x86-host+pentium3.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <model fallback='allow'>pentium3</model> <feature policy='require' name='lahf_lm'/> <feature policy='require' name='lm'/> diff --git a/tests/cputestdata/x86-host+strict-force-extra-result.xml b/tests/cputestdata/x86-host+strict-force-extra-result.xml index f3d52a1..68db412 100644 --- a/tests/cputestdata/x86-host+strict-force-extra-result.xml +++ b/tests/cputestdata/x86-host+strict-force-extra-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>Penryn</model> <feature policy='require' name='3dnow'/> diff --git a/tests/cputestdata/x86-host-better+pentium3,core2duo-result.xml b/tests/cputestdata/x86-host-better+pentium3,core2duo-result.xml index 5d4528b..0c436d9 100644 --- a/tests/cputestdata/x86-host-better+pentium3,core2duo-result.xml +++ b/tests/cputestdata/x86-host-better+pentium3,core2duo-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>core2duo</model> <feature policy='require' name='lahf_lm'/> diff --git a/tests/cputestdata/x86-host-better+pentium3,pentium3-result.xml b/tests/cputestdata/x86-host-better+pentium3,pentium3-result.xml index 1530a07..1e4f488 100644 --- a/tests/cputestdata/x86-host-better+pentium3,pentium3-result.xml +++ b/tests/cputestdata/x86-host-better+pentium3,pentium3-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>pentium3</model> <feature policy='require' name='lahf_lm'/> diff --git a/tests/cputestdata/x86-host-better+pentium3-result.xml b/tests/cputestdata/x86-host-better+pentium3-result.xml index 917d63f..07be0f7 100644 --- a/tests/cputestdata/x86-host-better+pentium3-result.xml +++ b/tests/cputestdata/x86-host-better+pentium3-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>Nehalem</model> <feature policy='require' name='dca'/> diff --git a/tests/cputestdata/x86-host-worse+guest-result.xml b/tests/cputestdata/x86-host-worse+guest-result.xml index 78e170a..441259f 100644 --- a/tests/cputestdata/x86-host-worse+guest-result.xml +++ b/tests/cputestdata/x86-host-worse+guest-result.xml @@ -1,4 +1,4 @@ -<cpu match='exact'> +<cpu mode='custom' match='exact'> <arch>x86_64</arch> <model fallback='allow'>Penryn</model> <feature policy='require' name='svm'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml index caa5f0a..ac72822 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml @@ -15,7 +15,7 @@ <apic/> <pae/> </features> - <cpu match='exact'> + <cpu mode='custom' match='exact'> <model fallback='allow'>core2duo</model> <vendor>Intel</vendor> <topology sockets='1' cores='2' threads='1'/> diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index c6adec9..8e621fe 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -112,6 +112,7 @@ virCapsPtr testQemuCapsInit(void) { }; static virCPUDef host_cpu = { VIR_CPU_TYPE_HOST, /* type */ + 0, /* mode */ 0, /* match */ (char *) "x86_64", /* arch */ (char *) "core2duo", /* model */ -- 1.7.8.2

On 01/06/2012 08:04 AM, Jiri Denemark wrote:
The mode can be either of "custom" (default), "host-model", "host-passthrough". The semantics of each mode is described in the following examples:
<snip> nice examples
--- Oh man, I just realized I forgot to update documentation. I'll transform this commit message into a proper documentation in the next version of this series. But it shouldn't be a showstopper for normal review :-)
And you were on a roll, too, since 2/6 touched docs. At any rate, I agree with your sentiment that I can review the code, even though we should wait for the patch to docs/formatdomain.html.in before pushing anything. I also agree with your assessment that the commit message is a fine start for documenting the new feature.
tests/cputestdata/x86-baseline-1-result.xml | 2 +- tests/cputestdata/x86-baseline-2-result.xml | 2 +-
Another round of lots of mechanical fallout by outputting the default attribute value, even when it was omittedon input. And whereas the attribute in 2/6 was just a boolean, here it is a tri-state, so I agree that outputting the mode always makes the most sense.
+++ b/docs/schemas/domaincommon.rng @@ -2425,6 +2425,20 @@ </interleave> </group> <group> + <ref name="cpuMode"/> + <interleave> + <optional> + <ref name="cpuModel"/> + </optional> + <optional> + <ref name="cpuNuma"/> + </optional> + </interleave> + </group> + <group> + <optional> + <ref name="cpuMode"/> + </optional> <ref name="cpuMatch"/> <interleave> <ref name="cpuModel"/> @@ -2446,6 +2460,16 @@ </element> </define>
+ <define name="cpuMode"> + <attribute name="mode"> + <choice> + <value>custom</value> + <value>host-model</value> + <value>host-passthrough</value> + </choice> + </attribute> + </define>
Your RNG does not match your commit message, in two places. 1. You called out this arrangement as valid: <cpu mode='custom'> <topology sockets='1' cores='2' threads='1'/> </cpu> but your added <group> lacks <ref name="cpuTopology">, and the existing group that includes cpuTopology lacks the new cpuMode. Here, I think the solution is to add an optional <ref name="cpuTopology"/> in your added second group. 2. You called out this arrangement as valid: <cpu mode='host-model'> <model fallback='forbid'/> </cpu> but cpuModel has mandatory <text/> contents. Here, I think the solution might be to change cpuModel to use this definition (if fallback=forbid, then the text is optional; otherwise, text is mandatory but fallback=allow is default and therefore optional): <define name="cpuModel"> <element name="model"> <choice> <group> <attribute name="fallback"> <value>forbid</value> </attribute> <choice> <text/> <empty/> </choice> </group> <group> <optional> <attribute name="fallback"> <value>allow</value> </attribute> </optional> <text/> </group> </choice> </element> </define>
@@ -173,10 +180,35 @@ virCPUDefParseXML(const xmlNodePtr node, goto error; } def->type = VIR_CPU_TYPE_HOST; - } else + } else { def->type = VIR_CPU_TYPE_GUEST; - } else + } + } else { def->type = mode; + }
Thanks for the style cleanups while in the area.
@@ -504,29 +566,32 @@ virCPUDefFormatBuf(virBufferPtr buf, virBufferAddLit(buf, "/>\n"); }
- for (i = 0 ; i < def->nfeatures ; i++) { - virCPUFeatureDefPtr feature = def->features + i; + if (formatModel) { + for (i = 0 ; i < def->nfeatures ; i++) {
I almost would have written this as: for (i = 0; formatModel && i < def->nfeatures; i++) { to avoid reindenting the for loop. But that's cosmetics; the transformation looked correct as you did it. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Sat, Jan 07, 2012 at 07:06:31 -0700, Eric Blake wrote:
On 01/06/2012 08:04 AM, Jiri Denemark wrote:
The mode can be either of "custom" (default), "host-model", "host-passthrough". The semantics of each mode is described in the following examples: ...
Your RNG does not match your commit message, in two places.
1. You called out this arrangement as valid: <cpu mode='custom'> <topology sockets='1' cores='2' threads='1'/> </cpu> but your added <group> lacks <ref name="cpuTopology">, and the existing group that includes cpuTopology lacks the new cpuMode. Here, I think the solution is to add an optional <ref name="cpuTopology"/> in your added second group.
Oh, my bad, there should be no mode attribute in this example since it would be ignored anyway :-)
2. You called out this arrangement as valid: <cpu mode='host-model'> <model fallback='forbid'/> </cpu> but cpuModel has mandatory <text/> contents. Here, I think the solution might be to change cpuModel to use this definition (if fallback=forbid, then the text is optional; otherwise, text is mandatory but fallback=allow is default and therefore optional):
<define name="cpuModel"> <element name="model"> <choice> <group> <attribute name="fallback"> <value>forbid</value> </attribute> <choice> <text/> <empty/> </choice> </group> <group> <optional> <attribute name="fallback"> <value>allow</value> </attribute> </optional> <text/> </group> </choice> </element> </define>
It's a bit more complicated since <model fallback='allow'/> is perfectly valid within <cpu mode='host-model'/> since it's just explicitly stating the default value. However, expressing the reality in RNG schema is would make it very complicated and unreadable and also given that we don't do so in other areas of the schema, I just marked the text in model element as optional.
@@ -504,29 +566,32 @@ virCPUDefFormatBuf(virBufferPtr buf, virBufferAddLit(buf, "/>\n"); }
- for (i = 0 ; i < def->nfeatures ; i++) { - virCPUFeatureDefPtr feature = def->features + i; + if (formatModel) { + for (i = 0 ; i < def->nfeatures ; i++) {
I almost would have written this as:
for (i = 0; formatModel && i < def->nfeatures; i++) {
to avoid reindenting the for loop. But that's cosmetics; the transformation looked correct as you did it.
Heh, I don't really want to sacrifice readability to a smaller patch :-) Jirka

--- src/conf/cpu_conf.c | 75 +++++++++++++++----- src/conf/cpu_conf.h | 8 ++ src/cpu/cpu_x86.c | 30 +++++++- src/libvirt_private.syms | 2 + src/qemu/qemu_domain.c | 12 ++-- tests/cputest.c | 18 ++++-- ...6-host+host+host-model,models,Penryn-result.xml | 19 +++++ .../cputestdata/x86-host+host-model-nofallback.xml | 19 +++++ tests/cputestdata/x86-host+host-model.xml | 18 +++++ tests/cputestdata/x86-host+host-passthrough.xml | 18 +++++ tests/cputestdata/x86-host-model-nofallback.xml | 4 + tests/cputestdata/x86-host-model.xml | 1 + tests/cputestdata/x86-host-passthrough.xml | 1 + 13 files changed, 194 insertions(+), 31 deletions(-) create mode 100644 tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml create mode 100644 tests/cputestdata/x86-host+host-model-nofallback.xml create mode 100644 tests/cputestdata/x86-host+host-model.xml create mode 100644 tests/cputestdata/x86-host+host-passthrough.xml create mode 100644 tests/cputestdata/x86-host-model-nofallback.xml create mode 100644 tests/cputestdata/x86-host-model.xml create mode 100644 tests/cputestdata/x86-host-passthrough.xml diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 31862e2..018d571 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -61,6 +61,19 @@ VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST, "forbid") +void ATTRIBUTE_NONNULL(1) +virCPUDefFreeModel(virCPUDefPtr def) +{ + unsigned int i; + + VIR_FREE(def->model); + VIR_FREE(def->vendor); + + for (i = 0; i < def->nfeatures; i++) + VIR_FREE(def->features[i].name); + VIR_FREE(def->features); +} + void virCPUDefFree(virCPUDefPtr def) { @@ -69,13 +82,8 @@ virCPUDefFree(virCPUDefPtr def) if (!def) return; - VIR_FREE(def->model); VIR_FREE(def->arch); - VIR_FREE(def->vendor); - - for (i = 0 ; i < def->nfeatures ; i++) - VIR_FREE(def->features[i].name); - VIR_FREE(def->features); + virCPUDefFreeModel(def); for (i = 0 ; i < def->ncells ; i++) { VIR_FREE(def->cells[i].cpumask); @@ -87,6 +95,42 @@ virCPUDefFree(virCPUDefPtr def) } +int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) +virCPUDefCopyModel(virCPUDefPtr dst, + const virCPUDefPtr src, + bool resetPolicy) +{ + unsigned int i; + + if ((src->model && !(dst->model = strdup(src->model))) + || (src->vendor && !(dst->vendor = strdup(src->vendor))) + || VIR_ALLOC_N(dst->features, src->nfeatures) < 0) + goto no_memory; + dst->nfeatures_max = dst->nfeatures = src->nfeatures; + + for (i = 0; i < dst->nfeatures; i++) { + if (dst->type != src->type && resetPolicy) { + if (dst->type == VIR_CPU_TYPE_HOST) + dst->features[i].policy = -1; + else if (src->features[i].policy == -1) + dst->features[i].policy = VIR_CPU_FEATURE_REQUIRE; + else + dst->features[i].policy = src->features[i].policy; + } else { + dst->features[i].policy = src->features[i].policy; + } + + if (!(dst->features[i].name = strdup(src->features[i].name))) + goto no_memory; + } + + return 0; + +no_memory: + virReportOOMError(); + return -1; +} + virCPUDefPtr virCPUDefCopy(const virCPUDefPtr cpu) { @@ -96,13 +140,8 @@ virCPUDefCopy(const virCPUDefPtr cpu) if (!cpu) return NULL; - if (VIR_ALLOC(copy) < 0 - || (cpu->arch && !(copy->arch = strdup(cpu->arch))) - || (cpu->model && !(copy->model = strdup(cpu->model))) - || (cpu->vendor && !(copy->vendor = strdup(cpu->vendor))) - || VIR_ALLOC_N(copy->features, cpu->nfeatures) < 0) + if (VIR_ALLOC(copy) < 0) goto no_memory; - copy->nfeatures_max = cpu->nfeatures; copy->type = cpu->type; copy->mode = cpu->mode; @@ -111,13 +150,12 @@ virCPUDefCopy(const virCPUDefPtr cpu) copy->sockets = cpu->sockets; copy->cores = cpu->cores; copy->threads = cpu->threads; - copy->nfeatures = cpu->nfeatures; - for (i = 0; i < copy->nfeatures; i++) { - copy->features[i].policy = cpu->features[i].policy; - if (!(copy->features[i].name = strdup(cpu->features[i].name))) - goto no_memory; - } + if (cpu->arch && !(copy->arch = strdup(cpu->arch))) + goto no_memory; + + if (virCPUDefCopyModel(copy, cpu, false) < 0) + goto error; if (cpu->ncells) { if (VIR_ALLOC_N(copy->cells, cpu->ncells) < 0) @@ -144,6 +182,7 @@ virCPUDefCopy(const virCPUDefPtr cpu) no_memory: virReportOOMError(); +error: virCPUDefFree(copy); return NULL; } diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 4b0b35b..f8b7bf9 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -118,9 +118,17 @@ struct _virCPUDef { }; +void ATTRIBUTE_NONNULL(1) +virCPUDefFreeModel(virCPUDefPtr def); + void virCPUDefFree(virCPUDefPtr def); +int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) +virCPUDefCopyModel(virCPUDefPtr dst, + const virCPUDefPtr src, + bool resetPolicy); + virCPUDefPtr virCPUDefCopy(const virCPUDefPtr cpu); diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index ad2d5cd..308604b 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1686,8 +1686,8 @@ error: static int -x86Update(virCPUDefPtr guest, - const virCPUDefPtr host) +x86UpdateCustom(virCPUDefPtr guest, + const virCPUDefPtr host) { int ret = -1; unsigned int i; @@ -1731,6 +1731,32 @@ cleanup: return ret; } +static int +x86Update(virCPUDefPtr guest, + const virCPUDefPtr host) +{ + switch ((enum virCPUMode) guest->mode) { + case VIR_CPU_MODE_CUSTOM: + return x86UpdateCustom(guest, host); + + case VIR_CPU_MODE_HOST_MODEL: + case VIR_CPU_MODE_HOST_PASSTHROUGH: + if (guest->mode == VIR_CPU_MODE_HOST_MODEL) + guest->match = VIR_CPU_MATCH_EXACT; + else + guest->match = VIR_CPU_MATCH_MINIMUM; + virCPUDefFreeModel(guest); + return virCPUDefCopyModel(guest, host, true); + + case VIR_CPU_MODE_LAST: + break; + } + + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected CPU mode: %d"), guest->mode); + return -1; +} + static int x86HasFeature(const union cpuData *data, const char *name) { diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ac2c52e..9f29ef5 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -181,9 +181,11 @@ cpuUpdate; # cpu_conf.h virCPUDefAddFeature; virCPUDefCopy; +virCPUDefCopyModel; virCPUDefFormat; virCPUDefFormatBuf; virCPUDefFree; +virCPUDefFreeModel; virCPUDefParseXML; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index c5b08f9..0bbc276 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1050,20 +1050,20 @@ char *qemuDomainDefFormatXML(struct qemud_driver *driver, { char *ret = NULL; virCPUDefPtr cpu = NULL; - virCPUDefPtr def_cpu; - - def_cpu = def->cpu; + virCPUDefPtr def_cpu = def->cpu; /* Update guest CPU requirements according to host CPU */ - if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) && def_cpu && def_cpu->model) { + if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) && + def_cpu && + (def_cpu->mode != VIR_CPU_MODE_CUSTOM || def_cpu->model)) { if (!driver->caps || !driver->caps->host.cpu) { qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", _("cannot get host CPU capabilities")); goto cleanup; } - if (!(cpu = virCPUDefCopy(def_cpu)) - || cpuUpdate(cpu, driver->caps->host.cpu)) + if (!(cpu = virCPUDefCopy(def_cpu)) || + cpuUpdate(cpu, driver->caps->host.cpu) < 0) goto cleanup; def->cpu = cpu; } diff --git a/tests/cputest.c b/tests/cputest.c index d8c1713..938e087 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -162,7 +162,8 @@ error: static int cpuTestCompareXML(const char *arch, const virCPUDefPtr cpu, - const char *name) + const char *name, + unsigned int flags) { char *xml = NULL; char *expected = NULL; @@ -176,7 +177,7 @@ cpuTestCompareXML(const char *arch, if (virtTestLoadFile(xml, &expected) < 0) goto cleanup; - if (!(actual = virCPUDefFormat(cpu, 0))) + if (!(actual = virCPUDefFormat(cpu, flags))) goto cleanup; if (STRNEQ(expected, actual)) { @@ -310,7 +311,7 @@ cpuTestGuestData(const void *arg) } result = virBufferContentAndReset(&buf); - ret = cpuTestCompareXML(data->arch, guest, result); + ret = cpuTestCompareXML(data->arch, guest, result, 0); cleanup: VIR_FREE(result); @@ -354,7 +355,7 @@ cpuTestBaseline(const void *arg) if (virAsprintf(&result, "%s-result", data->name) < 0) goto cleanup; - if (cpuTestCompareXML(data->arch, baseline, result) < 0) + if (cpuTestCompareXML(data->arch, baseline, result, 0) < 0) goto cleanup; for (i = 0; i < ncpus; i++) { @@ -406,7 +407,8 @@ cpuTestUpdate(const void *arg) if (virAsprintf(&result, "%s+%s", data->host, data->name) < 0) goto cleanup; - ret = cpuTestCompareXML(data->arch, cpu, result); + ret = cpuTestCompareXML(data->arch, cpu, result, + VIR_DOMAIN_XML_UPDATE_CPU); cleanup: virCPUDefFree(host); @@ -592,6 +594,9 @@ mymain(void) DO_TEST_UPDATE("x86", "host", "min", IDENTICAL); DO_TEST_UPDATE("x86", "host", "pentium3", IDENTICAL); DO_TEST_UPDATE("x86", "host", "guest", SUPERSET); + DO_TEST_UPDATE("x86", "host", "host-model", IDENTICAL); + DO_TEST_UPDATE("x86", "host", "host-model-nofallback", IDENTICAL); + DO_TEST_UPDATE("x86", "host", "host-passthrough", IDENTICAL); /* computing baseline CPUs */ DO_TEST_BASELINE("x86", "incompatible-vendors", -1); @@ -622,6 +627,9 @@ mymain(void) 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); + DO_TEST_GUESTDATA("x86", "host", "host+host-model", models, "Penryn", 0); + DO_TEST_GUESTDATA("x86", "host", "host+host-model-nofallback", + models, "Penryn", -1); free(map); return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); diff --git a/tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml b/tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml new file mode 100644 index 0000000..e2b7f5b --- /dev/null +++ b/tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml @@ -0,0 +1,19 @@ +<cpu mode='custom' match='exact'> + <arch>x86_64</arch> + <model fallback='allow'>core2duo</model> + <feature policy='require' name='lahf_lm'/> + <feature policy='require' name='sse4.1'/> + <feature policy='require' name='dca'/> + <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> diff --git a/tests/cputestdata/x86-host+host-model-nofallback.xml b/tests/cputestdata/x86-host+host-model-nofallback.xml new file mode 100644 index 0000000..bbb68fb --- /dev/null +++ b/tests/cputestdata/x86-host+host-model-nofallback.xml @@ -0,0 +1,19 @@ +<cpu mode='host-model' match='exact'> + <model fallback='forbid'>Penryn</model> + <vendor>Intel</vendor> + <topology sockets='1' cores='2' threads='1'/> + <feature policy='require' name='dca'/> + <feature policy='require' name='xtpr'/> + <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='monitor'/> + <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'/> + <feature policy='require' name='vme'/> +</cpu> diff --git a/tests/cputestdata/x86-host+host-model.xml b/tests/cputestdata/x86-host+host-model.xml new file mode 100644 index 0000000..c1014e2 --- /dev/null +++ b/tests/cputestdata/x86-host+host-model.xml @@ -0,0 +1,18 @@ +<cpu mode='host-model' match='exact'> + <model fallback='allow'>Penryn</model> + <vendor>Intel</vendor> + <feature policy='require' name='dca'/> + <feature policy='require' name='xtpr'/> + <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='monitor'/> + <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'/> + <feature policy='require' name='vme'/> +</cpu> diff --git a/tests/cputestdata/x86-host+host-passthrough.xml b/tests/cputestdata/x86-host+host-passthrough.xml new file mode 100644 index 0000000..721fae5 --- /dev/null +++ b/tests/cputestdata/x86-host+host-passthrough.xml @@ -0,0 +1,18 @@ +<cpu mode='host-passthrough' match='minimum'> + <model>Penryn</model> + <vendor>Intel</vendor> + <feature policy='require' name='dca'/> + <feature policy='require' name='xtpr'/> + <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='monitor'/> + <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'/> + <feature policy='require' name='vme'/> +</cpu> diff --git a/tests/cputestdata/x86-host-model-nofallback.xml b/tests/cputestdata/x86-host-model-nofallback.xml new file mode 100644 index 0000000..4e42eb4 --- /dev/null +++ b/tests/cputestdata/x86-host-model-nofallback.xml @@ -0,0 +1,4 @@ +<cpu mode='host-model'> + <model fallback='forbid'/> + <topology sockets='1' cores='2' threads='1'/> +</cpu> diff --git a/tests/cputestdata/x86-host-model.xml b/tests/cputestdata/x86-host-model.xml new file mode 100644 index 0000000..fd50c03 --- /dev/null +++ b/tests/cputestdata/x86-host-model.xml @@ -0,0 +1 @@ +<cpu mode='host-model'/> diff --git a/tests/cputestdata/x86-host-passthrough.xml b/tests/cputestdata/x86-host-passthrough.xml new file mode 100644 index 0000000..655c7a7 --- /dev/null +++ b/tests/cputestdata/x86-host-passthrough.xml @@ -0,0 +1 @@ +<cpu mode='host-passthrough'/> -- 1.7.8.2

On 01/06/2012 08:04 AM, Jiri Denemark wrote:
---
A little light on the commit message, perhaps.
src/conf/cpu_conf.c | 75 +++++++++++++++----- src/conf/cpu_conf.h | 8 ++ src/cpu/cpu_x86.c | 30 +++++++- src/libvirt_private.syms | 2 + src/qemu/qemu_domain.c | 12 ++-- tests/cputest.c | 18 ++++-- ...6-host+host+host-model,models,Penryn-result.xml | 19 +++++ .../cputestdata/x86-host+host-model-nofallback.xml | 19 +++++ tests/cputestdata/x86-host+host-model.xml | 18 +++++ tests/cputestdata/x86-host+host-passthrough.xml | 18 +++++ tests/cputestdata/x86-host-model-nofallback.xml | 4 + tests/cputestdata/x86-host-model.xml | 1 + tests/cputestdata/x86-host-passthrough.xml | 1 + 13 files changed, 194 insertions(+), 31 deletions(-) create mode 100644 tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml create mode 100644 tests/cputestdata/x86-host+host-model-nofallback.xml create mode 100644 tests/cputestdata/x86-host+host-model.xml create mode 100644 tests/cputestdata/x86-host+host-passthrough.xml create mode 100644 tests/cputestdata/x86-host-model-nofallback.xml create mode 100644 tests/cputestdata/x86-host-model.xml create mode 100644 tests/cputestdata/x86-host-passthrough.xml
But overall it looked sane, and I didn't spot anything obviously wrong. ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

--- src/conf/domain_conf.c | 3 ++- src/conf/domain_conf.h | 1 + src/qemu/qemu_domain.c | 3 +++ 3 files changed, 6 insertions(+), 1 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index ae007b1..dce2f5a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -75,7 +75,8 @@ VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST, "high-privileges", "shell-scripts", "disk-probing", - "external-launch"); + "external-launch", + "host-cpu"); VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST, "qemu", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index cd882bb..eba277b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1513,6 +1513,7 @@ enum virDomainTaintFlags { VIR_DOMAIN_TAINT_SHELL_SCRIPTS, /* Network configuration using opaque shell scripts */ VIR_DOMAIN_TAINT_DISK_PROBING, /* Relying on potentially unsafe disk format probing */ VIR_DOMAIN_TAINT_EXTERNAL_LAUNCH, /* Externally launched guest domain */ + VIR_DOMAIN_TAINT_HOST_CPU, /* Host CPU passthrough in use */ VIR_DOMAIN_TAINT_LAST }; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0bbc276..0b76bed 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1143,6 +1143,9 @@ void qemuDomainObjCheckTaint(struct qemud_driver *driver, qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_CUSTOM_ARGV, logFD); } + if (obj->def->cpu && obj->def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) + qemuDomainObjTaint(driver, obj, VIR_DOMAIN_TAINT_HOST_CPU, logFD); + for (i = 0 ; i < obj->def->ndisks ; i++) qemuDomainObjCheckDiskTaint(driver, obj, obj->def->disks[i], logFD); -- 1.7.8.2

On 01/06/2012 08:04 AM, Jiri Denemark wrote:
--- src/conf/domain_conf.c | 3 ++- src/conf/domain_conf.h | 1 + src/qemu/qemu_domain.c | 3 +++ 3 files changed, 6 insertions(+), 1 deletions(-)
Aargh - 'git grep taint docs/*.in' turned up nothing, so we don't have any documentation of tainting. That would be a nice thing to add before this patch, along with mentioning each category of taint (including this new category). But I agree that using host-passthrough is a reason for taint - if current qemu does not fully model the host, then upgrading to a newer version of qemu that adds new modeling features will pass through new capabilities to the guest, and that is a guest-visible ABI change (in particular, it might cause a Windows reactivation). Since we try to promise stability, but the passthrough puts us at the mercy of what qemu upgrades implement, declaring taint seems like an appropriate reaction to warn the user of the potential for problems. Maybe you should include something like the above paragraph as justification in your commit message. Your code additions look sane, but I'd feel more comfortable with docs as well. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Sat, Jan 07, 2012 at 07:21:02 -0700, Eric Blake wrote:
On 01/06/2012 08:04 AM, Jiri Denemark wrote:
--- src/conf/domain_conf.c | 3 ++- src/conf/domain_conf.h | 1 + src/qemu/qemu_domain.c | 3 +++ 3 files changed, 6 insertions(+), 1 deletions(-)
Aargh - 'git grep taint docs/*.in' turned up nothing, so we don't have any documentation of tainting. That would be a nice thing to add before this patch, along with mentioning each category of taint (including this new category).
Good idea. Unfortunately, I couldn't find a good place for such documentation since tainting is not very visible to users. It results in a warning message want to document. Any ideas where would be the best place to document tainting? And could that be actually done as a follow up patch instead? :-) Jirka

On Wed, Jan 11, 2012 at 10:42:39AM +0100, Jiri Denemark wrote:
On Sat, Jan 07, 2012 at 07:21:02 -0700, Eric Blake wrote:
On 01/06/2012 08:04 AM, Jiri Denemark wrote:
--- src/conf/domain_conf.c | 3 ++- src/conf/domain_conf.h | 1 + src/qemu/qemu_domain.c | 3 +++ 3 files changed, 6 insertions(+), 1 deletions(-)
Aargh - 'git grep taint docs/*.in' turned up nothing, so we don't have any documentation of tainting. That would be a nice thing to add before this patch, along with mentioning each category of taint (including this new category).
Good idea. Unfortunately, I couldn't find a good place for such documentation since tainting is not very visible to users. It results in a warning message want to document. Any ideas where would be the best place to document tainting? And could that be actually done as a follow up patch instead? :-)
I can't think of any existing page that is really relevant. Perhaps time to start a new one ? Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 5 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 97 +++++++++++++------- tests/qemuhelptest.c | 21 +++-- tests/qemuxml2argvdata/qemu-lib.sh | 50 ++++++++++ tests/qemuxml2argvdata/qemu-supported-cpus.sh | 15 +++ tests/qemuxml2argvdata/qemu.sh | 51 +---------- .../qemuxml2argv-cpu-host-model-fallback.args | 19 ++++ .../qemuxml2argv-cpu-host-model-fallback.xml | 19 ++++ .../qemuxml2argv-cpu-host-model-nofallback.xml | 21 ++++ .../qemuxml2argv-cpu-host-model.args | 19 ++++ .../qemuxml2argv-cpu-host-model.xml | 19 ++++ .../qemuxml2argv-cpu-host-passthrough.args | 19 ++++ .../qemuxml2argv-cpu-host-passthrough.xml | 19 ++++ .../qemuxml2argv-cpu-qemu-host-passthrough.xml | 19 ++++ tests/qemuxml2argvtest.c | 7 ++ 17 files changed, 310 insertions(+), 92 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemu-lib.sh create mode 100755 tests/qemuxml2argvdata/qemu-supported-cpus.sh create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-nofallback.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-passthrough.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-host-passthrough.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-qemu-host-passthrough.xml diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9f29ef5..61c2e3a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -187,6 +187,7 @@ virCPUDefFormatBuf; virCPUDefFree; virCPUDefFreeModel; virCPUDefParseXML; +virCPUModeTypeToString; # datatypes.h diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 43c7578..6e450fb 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -144,6 +144,8 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "ich9-ahci", "no-acpi", "fsdev-readonly", + + "cpu-host", /* 80 */ ); struct qemu_feature_flags { @@ -1175,6 +1177,9 @@ qemuCapsComputeCmdFlags(const char *help, */ if (version >= 12000) qemuCapsSet(flags, QEMU_CAPS_PCI_ROMBAR); + + if (version >= 11000) + qemuCapsSet(flags, QEMU_CAPS_CPU_HOST); } /* We parse the output of 'qemu -help' to get the QEMU diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index c759baf..b5a89b9 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -117,6 +117,7 @@ enum qemuCapsFlags { QEMU_CAPS_ICH9_AHCI = 77, /* -device ich9-ahci */ QEMU_CAPS_NO_ACPI = 78, /* -no-acpi */ QEMU_CAPS_FSDEV_READONLY =79, /* -fsdev readonly supported */ + QEMU_CAPS_CPU_HOST = 80, /* support for -cpu host */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 334c1a4..ab89e6b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3377,10 +3377,12 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver, virBitmapPtr qemuCaps, const struct utsname *ut, char **opt, - bool *hasHwVirt) + bool *hasHwVirt, + bool migrating) { const virCPUDefPtr host = driver->caps->host.cpu; virCPUDefPtr guest = NULL; + virCPUDefPtr cpu = NULL; unsigned int ncpus = 0; const char **cpus = NULL; union cpuData *data = NULL; @@ -3390,7 +3392,21 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver, *hasHwVirt = false; - if (def->cpu && def->cpu->model) { + if (def->cpu && + (def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) { + if (!(cpu = virCPUDefCopy(def->cpu))) + goto cleanup; + if (cpu->mode != VIR_CPU_MODE_CUSTOM && + !migrating && + cpuUpdate(cpu, host) < 0) + goto cleanup; + } + + if (cpu) { + virCPUCompareResult cmp; + const char *preferred; + int hasSVM; + if (host && qemuCapsProbeCPUModels(emulator, qemuCaps, host->arch, &ncpus, &cpus) < 0) @@ -3401,18 +3417,12 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver, _("CPU specification not supported by hypervisor")); goto cleanup; } - } - if (ncpus > 0 && host) { - virCPUCompareResult cmp; - const char *preferred; - int hasSVM; - - cmp = cpuGuestData(host, def->cpu, &data); + cmp = cpuGuestData(host, cpu, &data); switch (cmp) { case VIR_CPU_COMPARE_INCOMPATIBLE: - qemuReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("guest CPU is not compatible with host CPU")); + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("guest CPU is not compatible with host CPU")); /* fall through */ case VIR_CPU_COMPARE_ERROR: goto cleanup; @@ -3421,39 +3431,55 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver, break; } - if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(host->arch))) - goto no_memory; - - if (def->cpu->match == VIR_CPU_MATCH_MINIMUM) - preferred = host->model; - else - 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; - /* Only 'svm' requires --enable-nesting. The nested * 'vmx' patches now simply hook off the CPU features */ - hasSVM = cpuHasFeature(guest->arch, data, "svm"); + hasSVM = cpuHasFeature(host->arch, data, "svm"); if (hasSVM < 0) goto cleanup; *hasHwVirt = hasSVM > 0 ? true : false; - virBufferAdd(&buf, guest->model, -1); - for (i = 0; i < guest->nfeatures; i++) { - char sign; - if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE) - sign = '-'; + if (cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) { + const char *mode = virCPUModeTypeToString(cpu->mode); + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_CPU_HOST)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU mode '%s' is not supported by QEMU" + " binary"), mode); + goto cleanup; + } + if (def->virtType != VIR_DOMAIN_VIRT_KVM) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU mode '%s' is only supported with kvm"), + mode); + goto cleanup; + } + virBufferAddLit(&buf, "host"); + } else { + if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(host->arch))) + goto no_memory; + + if (cpu->match == VIR_CPU_MATCH_MINIMUM) + preferred = host->model; else - sign = '+'; + preferred = cpu->model; - virBufferAsprintf(&buf, ",%c%s", sign, guest->features[i].name); + guest->type = VIR_CPU_TYPE_GUEST; + guest->fallback = cpu->fallback; + if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0) + goto cleanup; + + virBufferAdd(&buf, guest->model, -1); + for (i = 0; i < guest->nfeatures; i++) { + char sign; + if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE) + sign = '-'; + else + sign = '+'; + + virBufferAsprintf(&buf, ",%c%s", sign, guest->features[i].name); + } } - } - else { + } else { /* * Need to force a 32-bit guest CPU type if * @@ -3484,6 +3510,7 @@ cleanup: if (guest) cpuDataFree(guest->arch, data); virCPUDefFree(guest); + virCPUDefFree(cpu); if (cpus) { for (i = 0; i < ncpus; i++) @@ -3706,7 +3733,7 @@ qemuBuildCommandLine(virConnectPtr conn, virCommandAddArgList(cmd, "-M", def->os.machine, NULL); if (qemuBuildCpuArgStr(driver, def, emulator, qemuCaps, - &ut, &cpu, &hasHwVirt) < 0) + &ut, &cpu, &hasHwVirt, !!migrateFrom) < 0) goto error; if (cpu) { diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index 60155e7..def11db 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -329,7 +329,8 @@ mymain(void) QEMU_CAPS_DRIVE_AIO, QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, - QEMU_CAPS_NO_ACPI); + QEMU_CAPS_NO_ACPI, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.12.1.2-rhel60", 12001, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -376,7 +377,8 @@ mymain(void) QEMU_CAPS_USB_HUB, QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, - QEMU_CAPS_NO_ACPI); + QEMU_CAPS_NO_ACPI, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.12.3", 12003, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -416,7 +418,8 @@ mymain(void) QEMU_CAPS_DRIVE_AIO, QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, - QEMU_CAPS_NO_ACPI); + QEMU_CAPS_NO_ACPI, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.13.0", 13000, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -472,7 +475,8 @@ mymain(void) QEMU_CAPS_USB_HUB, QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, - QEMU_CAPS_NO_ACPI); + QEMU_CAPS_NO_ACPI, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.12.1.2-rhel61", 12001, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -524,7 +528,8 @@ mymain(void) QEMU_CAPS_USB_HUB, QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, - QEMU_CAPS_NO_ACPI); + QEMU_CAPS_NO_ACPI, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.12.1.2-rhel62-beta", 12001, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -584,7 +589,8 @@ mymain(void) QEMU_CAPS_USB_HUB, QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, - QEMU_CAPS_NO_ACPI); + QEMU_CAPS_NO_ACPI, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-1.0", 1000000, 0, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -648,7 +654,8 @@ mymain(void) QEMU_CAPS_PCI_ROMBAR, QEMU_CAPS_ICH9_AHCI, QEMU_CAPS_NO_ACPI, - QEMU_CAPS_FSDEV_READONLY); + QEMU_CAPS_FSDEV_READONLY, + QEMU_CAPS_CPU_HOST); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tests/qemuxml2argvdata/qemu-lib.sh b/tests/qemuxml2argvdata/qemu-lib.sh new file mode 100644 index 0000000..ba19119 --- /dev/null +++ b/tests/qemuxml2argvdata/qemu-lib.sh @@ -0,0 +1,50 @@ +candidates="/usr/bin/qemu-kvm + /usr/libexec/qemu-kvm + /usr/bin/qemu-system-x86_64 + /usr/bin/qemu" +qemu= +for candidate in $candidates; do + if test -x $candidate; then + qemu=$candidate + break + fi +done + +real_qemu() +{ + if test x$qemu != x; then + exec $qemu "$@" + else + return 1 + fi +} + +faked_machine() +{ + echo "pc" +} + +faked_cpu() +{ + cat <<EOF +x86 Opteron_G3 +x86 Opteron_G2 +x86 Opteron_G1 +x86 Nehalem +x86 Penryn +x86 Conroe +x86 [n270] +x86 [athlon] +x86 [pentium3] +x86 [pentium2] +x86 [pentium] +x86 [486] +x86 [coreduo] +x86 [qemu32] +x86 [kvm64] +x86 [core2duo] +x86 [phenom] +x86 [qemu64] +x86 [host] +EOF +} diff --git a/tests/qemuxml2argvdata/qemu-supported-cpus.sh b/tests/qemuxml2argvdata/qemu-supported-cpus.sh new file mode 100755 index 0000000..c4c14d9 --- /dev/null +++ b/tests/qemuxml2argvdata/qemu-supported-cpus.sh @@ -0,0 +1,15 @@ +#! /bin/sh + +source $(dirname $0)/qemu-lib.sh + +case $* in +"-M ?") + faked_machine + ;; +"-cpu ?") + faked_cpu | fgrep -v '[' + ;; +*) + real_qemu "$@" + ;; +esac diff --git a/tests/qemuxml2argvdata/qemu.sh b/tests/qemuxml2argvdata/qemu.sh index 6d5d354..bbf5a16 100755 --- a/tests/qemuxml2argvdata/qemu.sh +++ b/tests/qemuxml2argvdata/qemu.sh @@ -1,55 +1,6 @@ #! /bin/sh -candidates="/usr/bin/qemu-kvm - /usr/libexec/qemu-kvm - /usr/bin/qemu-system-x86_64 - /usr/bin/qemu" -qemu= -for candidate in $candidates; do - if test -x $candidate; then - qemu=$candidate - break - fi -done - -real_qemu() -{ - if test x$qemu != x; then - exec $qemu "$@" - else - return 1 - fi -} - -faked_machine() -{ - echo "pc" -} - -faked_cpu() -{ - cat <<EOF -x86 Opteron_G3 -x86 Opteron_G2 -x86 Opteron_G1 -x86 Nehalem -x86 Penryn -x86 Conroe -x86 [n270] -x86 [athlon] -x86 [pentium3] -x86 [pentium2] -x86 [pentium] -x86 [486] -x86 [coreduo] -x86 [qemu32] -x86 [kvm64] -x86 [core2duo] -x86 [phenom] -x86 [qemu64] -x86 [host] -EOF -} +source $(dirname $0)/qemu-lib.sh case $* in "-M ?") diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.args new file mode 100644 index 0000000..ac8ab1a --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.args @@ -0,0 +1,19 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +./qemu-supported-cpus.sh \ +-S \ +-M pc \ +-cpu Penryn,+xtpr,+tm2,+est,+vmx,+ds_cpl,+monitor,+pbe,+tm,+ht,+ss,+acpi,+ds,+vme,-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-host-model-fallback.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.xml new file mode 100644 index 0000000..afb16f9 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.xml @@ -0,0 +1,19 @@ +<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 mode='host-model'/> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/./qemu-supported-cpus.sh</emulator> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-nofallback.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-nofallback.xml new file mode 100644 index 0000000..c2ded11 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-nofallback.xml @@ -0,0 +1,21 @@ +<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 mode='host-model'> + <model fallback='forbid'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/./qemu-supported-cpus.sh</emulator> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.args new file mode 100644 index 0000000..cf7eb2a --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.args @@ -0,0 +1,19 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +./qemu.sh \ +-S \ +-M pc \ +-cpu core2duo,+lahf_lm,+xtpr,+cx16,+tm2,+est,+vmx,+ds_cpl,+pbe,+tm,+ht,+ss,+acpi,+ds \ +-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-host-model.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.xml new file mode 100644 index 0000000..96b046c --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model.xml @@ -0,0 +1,19 @@ +<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 mode='host-model'/> + <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-host-passthrough.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-passthrough.args new file mode 100644 index 0000000..c63ecce --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-passthrough.args @@ -0,0 +1,19 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +./qemu.sh \ +-S \ +-M pc \ +-cpu host \ +-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-host-passthrough.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-passthrough.xml new file mode 100644 index 0000000..2d75025 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-passthrough.xml @@ -0,0 +1,19 @@ +<domain type='kvm'> + <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 mode='host-passthrough'/> + <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-qemu-host-passthrough.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-qemu-host-passthrough.xml new file mode 100644 index 0000000..a7123ce --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-qemu-host-passthrough.xml @@ -0,0 +1,19 @@ +<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 mode='host-passthrough'/> + <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 5c20bdf..9edb960 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -661,6 +661,13 @@ mymain(void) DO_TEST("cpu-strict1", false, NONE); DO_TEST("cpu-numa1", false, NONE); DO_TEST("cpu-numa2", false, QEMU_CAPS_SMP_TOPOLOGY); + DO_TEST("cpu-host-model", false, NONE); + DO_TEST("cpu-host-model-fallback", false, NONE); + DO_TEST_FAILURE("cpu-host-model-nofallback", NONE); + DO_TEST("cpu-host-passthrough", false, QEMU_CAPS_KVM, QEMU_CAPS_CPU_HOST); + DO_TEST_FAILURE("cpu-host-passthrough", NONE); + DO_TEST_FAILURE("cpu-qemu-host-passthrough", + QEMU_CAPS_KVM, QEMU_CAPS_CPU_HOST); DO_TEST("memtune", false, QEMU_CAPS_NAME); DO_TEST("blkiotune", false, QEMU_CAPS_NAME); -- 1.7.8.2

On 01/06/2012 08:04 AM, Jiri Denemark wrote:
---
Also a bit light on the commit message.
src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 5 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 97 +++++++++++++------- tests/qemuhelptest.c | 21 +++-- tests/qemuxml2argvdata/qemu-lib.sh | 50 ++++++++++ tests/qemuxml2argvdata/qemu-supported-cpus.sh | 15 +++ tests/qemuxml2argvdata/qemu.sh | 51 +----------
Thanks for enhancing the testsuite; as time-consuming as it is, it always has a good payout in preventing regressions.
diff --git a/tests/qemuxml2argvdata/qemu-lib.sh b/tests/qemuxml2argvdata/qemu-lib.sh new file mode 100644
Should this be chmod +x?
diff --git a/tests/qemuxml2argvdata/qemu-supported-cpus.sh b/tests/qemuxml2argvdata/qemu-supported-cpus.sh new file mode 100755 index 0000000..c4c14d9 --- /dev/null +++ b/tests/qemuxml2argvdata/qemu-supported-cpus.sh @@ -0,0 +1,15 @@ +#! /bin/sh + +source $(dirname $0)/qemu-lib.sh
I guess since you are sourcing the file, it doesn't matter if it the helper file is executable; it is just division of labor. s/source/./ (the spelled-out name is a bash extension not guaranteed by POSIX).
+ +case $* in +"-M ?") + faked_machine + ;; +"-cpu ?") + faked_cpu | fgrep -v '['
fgrep is not standard (although it's likely to exist on all platforms where qemu exists). In isolation, [ doesn't need shell quoting (although seeing quotes around a grep script makes it obvious what pattern you are looking for). I'd use either: faked_cpu | grep -Fv '[' faked_cpu | grep -v '\['
diff --git a/tests/qemuxml2argvdata/qemu.sh b/tests/qemuxml2argvdata/qemu.sh index 6d5d354..bbf5a16 100755 --- a/tests/qemuxml2argvdata/qemu.sh +++ b/tests/qemuxml2argvdata/qemu.sh @@ -1,55 +1,6 @@ #! /bin/sh
+source $(dirname $0)/qemu-lib.sh
Again, s/source/./ -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Jiri Denemark