[libvirt] [PATCH v2 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 | 63 +++++- docs/schemas/domaincommon.rng | 37 +++- 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 | 6 +- src/qemu/qemu_capabilities.h | 9 +- 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, 1112 insertions(+), 250 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.3

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. --- Notes: Version 2: - no change 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.3

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

On 01/12/2012 04:02 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. --- Notes: Version 2: - grammar
+++ b/docs/formatdomain.html.in @@ -559,7 +559,7 @@ <pre> ... <cpu match='exact'> - <model>core2duo</model> + <model fallback='allow'>core2duo</model> <vendor>Intel</vendor> <topology sockets='1' cores='2' threads='1'/> <feature policy='disable' name='lahf_lm'/> @@ -609,7 +609,15 @@ <dd>The content of the <code>model</code> element specifies CPU model requested by the guest. The list of available CPU models and their definition can be found in <code>cpu_map.xml</code> file installed - in libvirt's data directory.</dd> + in libvirt's data directory. If a hypervisor is not able to use the + exact CPU model, libvirt automatically falls back to a closest model + supported by the hypervisor while maintaining the list of CPU + features. <span class="since">Since 0.9.10</span>, an optional + <code>fallback</code> attribute can be used to forbid this behavior, + in which case an attempt to start a domain requesting unsupported
s/unsupported/an &/
+ CPU model will fail. Supported values for <code>fallback</code> + attribute are: <code>allow</code> (this is the default), and + <code>forbid</code>.</dd>
ACK with that nit fixed. -- 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> <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> --- Notes: Version 2: - added documentation - fixed XML examples and schema docs/formatdomain.html.in | 51 +++++++ docs/schemas/domaincommon.rng | 29 ++++- 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 + 28 files changed, 236 insertions(+), 70 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 8961fed..bdb182d 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -566,6 +566,17 @@ </cpu> ...</pre> +<pre> + <cpu mode='host-model'> + <model fallback='forbid'/> + <topology sockets='1' cores='2' threads='1'/> + </cpu> + ...</pre> + +<pre> + <cpu mode='host-passthrough'/> + ...</pre> + <p> In case no restrictions need to be put on CPU model and its features, a simpler <code>cpu</code> element can be used. @@ -603,6 +614,46 @@ <span class="since">Since 0.8.5</span> the <code>match</code> attribute can be omitted and will default to <code>exact</code>. + + <span class="since">Since 0.9.10</span>, an optional <code>mode</code> + attribute may be used to make it easier to configure a guest CPU to be + as close to host CPU as possible. Possible values for the + <code>mode</code> attribute are: + + <dl> + <dt><code>custom</code></dt> + <dd>In this mode, the <code>cpu</code> element describes the CPU + that should be presented to the guest. This is the default value + when no <code>mode</code> attribute is specified.</dd> + <dt><code>host-model</code></dt> + <dd>The <code>host-model</code> mode is essentially a shortcut to + copying host CPU definition from capabilities XML into domain XML. + Since the CPU definition is copied just before starting a domain, + exactly the same XML can be used on different hosts while still + providing the best guest CPU each host supports. Neither + <code>match</code> attribute nor any <code>feature</code> elements + can be used in this mode. Specifying CPU model is not supported + either, but <code>model</code>'s <code>fallback</code> attribute may + still be used. Libvirt does not model every aspect of each CPU so + the guest CPU will not match the host CPU exactly. On the other + hand, the ABI provided to the guest is reproducible. During + migration, complete CPU model definition is transferred to the + destination host so the migrated guest will see exactly the same CPU + model even if the destination host contains more capable CPUs.</dd> + <dt><code>host-passthrough</code></dt> + <dd>With this mode, the CPU visible to the guest should be exactly + the same as the host CPU even in the aspects that libvirt does not + understand. Though the downside of this mode is that the guest + environment cannot be reproduced on different hardware. Thus, if you + hit any bugs, you are on your own. Neither <code>model</code> nor + <code>feature</code> elements are allowed in this mode.</dd> + </dl> + + In both <code>host-model</code> and <code>host-passthrough</code> + mode, the real (approximate in <code>host-passthrough</code> mode) CPU + definition which would be used on current host can be determined by + specifying <code>VIR_DOMAIN_XML_UPDATE_CPU</code> flag when calling + <code>virDomainGetXMLDesc</code> API. </dd> <dt><code>model</code></dt> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index a3ad3d3..d8eacf8 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2426,6 +2426,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"/> @@ -2447,6 +2461,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> @@ -2467,7 +2491,10 @@ </choice> </attribute> </optional> - <text/> + <choice> + <text/> + <empty/> + </choice> </element> </define> 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 180dd2b..173351b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -11639,7 +11639,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.3

On 01/12/2012 04:02 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:
--- Notes: Version 2: - added documentation - fixed XML examples and schema
Thanks, that's what I was waiting for in v1.
+++ b/docs/formatdomain.html.in
+ <dt><code>host-model</code></dt> + <dd>The <code>host-model</code> mode is essentially a shortcut to + copying host CPU definition from capabilities XML into domain XML. + Since the CPU definition is copied just before starting a domain, + exactly the same XML can be used on different hosts while still + providing the best guest CPU each host supports. Neither + <code>match</code> attribute nor any <code>feature</code> elements + can be used in this mode. Specifying CPU model is not supported + either, but <code>model</code>'s <code>fallback</code> attribute may + still be used. Libvirt does not model every aspect of each CPU so + the guest CPU will not match the host CPU exactly. On the other + hand, the ABI provided to the guest is reproducible. During + migration, complete CPU model definition is transferred to the + destination host so the migrated guest will see exactly the same CPU + model even if the destination host contains more capable CPUs.</dd>
Question - if I start on a less-powerful CPU, then live migrate to a more powerful CPU, then restart the guest, did the migration lock me in to the less-powerful capabilities, or does restarting the guest then pick up on the more-powerful capabilities? I'm guessing the former (once you migrate, you want to be locked in), because otherwise, the act of migration followed by guest reboot would make Windows guests susceptible to reactivation. In which case, I think rewording the last sentence might help: During migration, or after using the VIR_DOMAIN_XML_UPDATE_CPU flag to virDomainGetXMLDesc, the XML is persistently rewritten to the CPU model definition that was in use when the guest was started, so that subsequent boots of the guest, even when migrated to a destination host with a more capable CPU, will see the same CPU features as on the first boot. Then again, you mention this flag later on, so maybe it is sufficient to use: Upon migration, the XML is persistently rewritten to the CPU model definition that was in use when the guest was started, so that subsequent boots of the guest, even where the destination has a more capable CPU, will see the same CPU features as on the first boot.
+ <dt><code>host-passthrough</code></dt> + <dd>With this mode, the CPU visible to the guest should be exactly + the same as the host CPU even in the aspects that libvirt does not + understand. Though the downside of this mode is that the guest
s/Though the/The/
+ environment cannot be reproduced on different hardware. Thus, if you + hit any bugs, you are on your own. Neither <code>model</code> nor + <code>feature</code> elements are allowed in this mode.</dd> + </dl> + + In both <code>host-model</code> and <code>host-passthrough</code> + mode, the real (approximate in <code>host-passthrough</code> mode) CPU + definition which would be used on current host can be determined by + specifying <code>VIR_DOMAIN_XML_UPDATE_CPU</code> flag when calling + <code>virDomainGetXMLDesc</code> API.
ACK with the doc nits addressed. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Mon, Jan 16, 2012 at 13:38:00 -0700, Eric Blake wrote:
On 01/12/2012 04:02 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:
--- Notes: Version 2: - added documentation - fixed XML examples and schema
Thanks, that's what I was waiting for in v1.
+++ b/docs/formatdomain.html.in
+ <dt><code>host-model</code></dt> + <dd>The <code>host-model</code> mode is essentially a shortcut to + copying host CPU definition from capabilities XML into domain XML. + Since the CPU definition is copied just before starting a domain, + exactly the same XML can be used on different hosts while still + providing the best guest CPU each host supports. Neither + <code>match</code> attribute nor any <code>feature</code> elements + can be used in this mode. Specifying CPU model is not supported + either, but <code>model</code>'s <code>fallback</code> attribute may + still be used. Libvirt does not model every aspect of each CPU so + the guest CPU will not match the host CPU exactly. On the other + hand, the ABI provided to the guest is reproducible. During + migration, complete CPU model definition is transferred to the + destination host so the migrated guest will see exactly the same CPU + model even if the destination host contains more capable CPUs.</dd>
Question - if I start on a less-powerful CPU, then live migrate to a more powerful CPU, then restart the guest, did the migration lock me in to the less-powerful capabilities, or does restarting the guest then pick up on the more-powerful capabilities? I'm guessing the former (once you migrate, you want to be locked in), because otherwise, the act of migration followed by guest reboot would make Windows guests susceptible to reactivation. In which case, I think rewording the last sentence might help:
It depends what do you mean by guest restart :-) Restarting guest OS within the same qemu process certainly doesn't change anything. However, the CPU may change if you shut the domain down and start it again. The updated CPU is not persistently stored anywhere even if you ask libvirt to define the domain on destination. The inactive XML on destination will be the same as the one on source. The main benefit of host-* CPU modes is that they give you the semantics of "anywhere you start me, I'll use the best of your CPUs", be it after migration or manual copying of the XML. It is only assured not to change while the guest is running even after it's migrated. Those who want stability may use the custom mode we already support for ~2 years. Do you suggest any changes so that it's more obvious from the docs? Thanks for your comments. Jirka

On 01/16/2012 01:59 PM, Jiri Denemark wrote:
On Mon, Jan 16, 2012 at 13:38:00 -0700, Eric Blake wrote:
On 01/12/2012 04:02 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:
+ <dt><code>host-model</code></dt> + <dd>The <code>host-model</code> mode is essentially a shortcut to + copying host CPU definition from capabilities XML into domain XML. + Since the CPU definition is copied just before starting a domain, + exactly the same XML can be used on different hosts while still + providing the best guest CPU each host supports. Neither + <code>match</code> attribute nor any <code>feature</code> elements + can be used in this mode. Specifying CPU model is not supported + either, but <code>model</code>'s <code>fallback</code> attribute may + still be used. Libvirt does not model every aspect of each CPU so + the guest CPU will not match the host CPU exactly. On the other + hand, the ABI provided to the guest is reproducible. During + migration, complete CPU model definition is transferred to the + destination host so the migrated guest will see exactly the same CPU + model even if the destination host contains more capable CPUs.</dd>
Question - if I start on a less-powerful CPU, then live migrate to a more powerful CPU, then restart the guest, did the migration lock me in to the less-powerful capabilities, or does restarting the guest then pick up on the more-powerful capabilities? I'm guessing the former (once you migrate, you want to be locked in), because otherwise, the act of migration followed by guest reboot would make Windows guests susceptible to reactivation. In which case, I think rewording the last sentence might help:
It depends what do you mean by guest restart :-) Restarting guest OS within the same qemu process certainly doesn't change anything. However, the CPU may change if you shut the domain down and start it again. The updated CPU is not persistently stored anywhere even if you ask libvirt to define the domain on destination. The inactive XML on destination will be the same as the one on source. The main benefit of host-* CPU modes is that they give you the semantics of "anywhere you start me, I'll use the best of your CPUs", be it after migration or manual copying of the XML. It is only assured not to change while the guest is running even after it's migrated. Those who want stability may use the custom mode we already support for ~2 years.
Do you suggest any changes so that it's more obvious from the docs?
How about: custom In this mode, the <code>cpu</code> element describes the CPU that should be presented to the guest. This is the default when no <code>mode</code> attribute is specified. This mode makes it so that a persistent guest will see the same hardware, and thus avoid the need for operating system reactivation, no matter what host the guest is booted on. host-model The <code>host-model</code> mode is essentially a shortcut to copying host CPU definition from capabilities XML into domain XML. Since the CPU definition is copied just before starting a domain, exactly the same XML can be used on different hosts while still providing the best guest CPU each host supports. Neither <code>match</code> attribute nor any <code>feature</code> elements can be used in this mode. Specifying CPU model is not supported either, but <code>model</code>'s <code>fallback</code> attribute may still be used. Libvirt does not model every aspect of each CPU so the guest CPU will not match the host CPU exactly. On the other hand, the ABI provided to the guest is reproducible. During migration, complete CPU model definition is transferred to the destination host so the migrated guest will see exactly the same CPU model even if the destination host contains more capable CPUs for the running instance of the guest; but shutting down and restarting the guest may present different hardware to the guest according to the capabilities of the new host, and thus trigger an operating system reactivation. host-passthrough ... In both <code>host-model</code> and <code>host-passthrough</code> mode, the real (approximate in <code>host-passthrough</code> mode) CPU definition which would be used on current host can be determined by specifying <code>VIR_DOMAIN_XML_UPDATE_CPU</code> flag when calling <code>virDomainGetXMLDesc</code>. When running a guest that might be prone to operating system reactivation when presented with different hardware, and which will be migrated between hosts with different capabilities, you can use this output to rewrite XML to the <code>custom</code> mode for more robust migration. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

VIR_DOMAIN_XML_UPDATE_CPU flag for virDomainGetXMLDesc may be used to get updated custom mode guest CPU definition in case it depends on host CPU. This patch implements the same behavior for host-model and host-passtrhough CPU modes. --- Notes: Version 2: - more verbose commit message 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 ca4beb1..ac2a892 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 6b03c62..a25f4df 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.3

On 01/12/2012 04:02 AM, Jiri Denemark wrote:
VIR_DOMAIN_XML_UPDATE_CPU flag for virDomainGetXMLDesc may be used to get updated custom mode guest CPU definition in case it depends on host CPU. This patch implements the same behavior for host-model and host-passtrhough CPU modes.
s/passtrhough/passthrough/
--- Notes: Version 2: - more verbose commit message
ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

There are several reasons for doing this: - the CPU specification is out of libvirt's control so we cannot guarantee stable guest ABI - not every feature of a CPU may actually work as expected when advertised directly to a guest - migration between two machines with exactly the same CPU may work but no guarantees can be made - this mode is not supported and it's use is at one's own risk --- Notes: Version 2: - more verbose commit message 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 173351b..982a7de 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 3d5d4f8..606af17 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 a25f4df..cfe0ece 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.3

On 01/12/2012 04:02 AM, Jiri Denemark wrote:
There are several reasons for doing this:
- the CPU specification is out of libvirt's control so we cannot guarantee stable guest ABI - not every feature of a CPU may actually work as expected when advertised directly to a guest - migration between two machines with exactly the same CPU may work but no guarantees can be made - this mode is not supported and it's use is at one's own risk
s/it's/its/
--- Notes: Version 2: - more verbose commit message
Per your rebuttal on v1, I agree that we can defer documentation of tainting to a later patch (it's a pre-existing problem, that your patch didn't make any worse, although fixing it will now involve more text). Therefore, I'm okay giving ACK, but I'm hoping that we have taint documentation by 0.9.10 (and I may be able to step in and help provide some). -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

This adds support for host-model and host-passthrough CPU modes to qemu driver. The host-passthrough mode is mapped to -cpu host. --- Notes: Version 2: - more verbose commit messages - portability fixes in shell scripts src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 6 +- src/qemu/qemu_capabilities.h | 9 +- 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, 314 insertions(+), 97 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 ac2a892..a64e9ae 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 6842cfe..61cdfb9 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -145,8 +145,9 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "no-acpi", "fsdev-readonly", - "virtio-blk-pci.scsi", + "virtio-blk-pci.scsi", /* 80 */ "blk-sg-io", + "cpu-host", ); struct qemu_feature_flags { @@ -1181,6 +1182,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 d47177c..17ef99c 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -113,13 +113,14 @@ enum qemuCapsFlags { QEMU_CAPS_NO_SHUTDOWN = 74, /* usable -no-shutdown */ QEMU_CAPS_DRIVE_CACHE_UNSAFE = 75, /* Is cache=unsafe supported? */ - QEMU_CAPS_PCI_ROMBAR = 76, /* -device rombar=0|1 */ + QEMU_CAPS_PCI_ROMBAR = 76, /* -device rombar=0|1 */ 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_FSDEV_READONLY = 79, /* -fsdev readonly supported */ - QEMU_CAPS_VIRTIO_BLK_SCSI = 80, /* virtio-blk-pci.scsi */ - QEMU_CAPS_VIRTIO_BLK_SG_IO = 81, /* support for SG_IO commands, reportedly added in 0.11 */ + QEMU_CAPS_VIRTIO_BLK_SCSI = 80, /* virtio-blk-pci.scsi */ + QEMU_CAPS_VIRTIO_BLK_SG_IO = 81, /* support for SG_IO commands, reportedly added in 0.11 */ + QEMU_CAPS_CPU_HOST = 82, /* 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 4d7842e..b11a48e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3428,10 +3428,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; @@ -3441,7 +3443,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) @@ -3452,18 +3468,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; @@ -3472,39 +3482,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 * @@ -3535,6 +3561,7 @@ cleanup: if (guest) cpuDataFree(guest->arch, data); virCPUDefFree(guest); + virCPUDefFree(cpu); if (cpus) { for (i = 0; i < ncpus; i++) @@ -3757,7 +3784,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 1ef0d9b..87d3729 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -330,7 +330,8 @@ mymain(void) QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, QEMU_CAPS_NO_ACPI, - QEMU_CAPS_VIRTIO_BLK_SG_IO); + QEMU_CAPS_VIRTIO_BLK_SG_IO, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.12.1.2-rhel60", 12001, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -378,7 +379,8 @@ mymain(void) QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, QEMU_CAPS_NO_ACPI, - QEMU_CAPS_VIRTIO_BLK_SG_IO); + QEMU_CAPS_VIRTIO_BLK_SG_IO, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.12.3", 12003, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -419,7 +421,8 @@ mymain(void) QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, QEMU_CAPS_NO_ACPI, - QEMU_CAPS_VIRTIO_BLK_SG_IO); + QEMU_CAPS_VIRTIO_BLK_SG_IO, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.13.0", 13000, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -476,7 +479,8 @@ mymain(void) QEMU_CAPS_NO_SHUTDOWN, QEMU_CAPS_PCI_ROMBAR, QEMU_CAPS_NO_ACPI, - QEMU_CAPS_VIRTIO_BLK_SG_IO); + QEMU_CAPS_VIRTIO_BLK_SG_IO, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-kvm-0.12.1.2-rhel61", 12001, 1, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -530,7 +534,8 @@ mymain(void) QEMU_CAPS_PCI_ROMBAR, QEMU_CAPS_NO_ACPI, QEMU_CAPS_VIRTIO_BLK_SCSI, - QEMU_CAPS_VIRTIO_BLK_SG_IO); + QEMU_CAPS_VIRTIO_BLK_SG_IO, + 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, @@ -592,7 +597,8 @@ mymain(void) QEMU_CAPS_PCI_ROMBAR, QEMU_CAPS_NO_ACPI, QEMU_CAPS_VIRTIO_BLK_SCSI, - QEMU_CAPS_VIRTIO_BLK_SG_IO); + QEMU_CAPS_VIRTIO_BLK_SG_IO, + QEMU_CAPS_CPU_HOST); DO_TEST("qemu-1.0", 1000000, 0, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, @@ -658,7 +664,8 @@ mymain(void) QEMU_CAPS_NO_ACPI, QEMU_CAPS_FSDEV_READONLY, QEMU_CAPS_VIRTIO_BLK_SCSI, - QEMU_CAPS_VIRTIO_BLK_SG_IO); + QEMU_CAPS_VIRTIO_BLK_SG_IO, + 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..ed3ae94 --- /dev/null +++ b/tests/qemuxml2argvdata/qemu-supported-cpus.sh @@ -0,0 +1,15 @@ +#! /bin/sh + +. $(dirname $0)/qemu-lib.sh + +case $* in +"-M ?") + faked_machine + ;; +"-cpu ?") + faked_cpu | grep -Fv '[' + ;; +*) + real_qemu "$@" + ;; +esac diff --git a/tests/qemuxml2argvdata/qemu.sh b/tests/qemuxml2argvdata/qemu.sh index 6d5d354..38da0b3 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 -} +. $(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 f944d82..9e2f925 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -671,6 +671,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.3

On 01/12/2012 04:03 AM, Jiri Denemark wrote:
This adds support for host-model and host-passthrough CPU modes to qemu driver. The host-passthrough mode is mapped to -cpu host. --- Notes: Version 2: - more verbose commit messages - portability fixes in shell scripts
+++ b/src/qemu/qemu_capabilities.h @@ -113,13 +113,14 @@ enum qemuCapsFlags { QEMU_CAPS_NO_SHUTDOWN = 74, /* usable -no-shutdown */
QEMU_CAPS_DRIVE_CACHE_UNSAFE = 75, /* Is cache=unsafe supported? */ - QEMU_CAPS_PCI_ROMBAR = 76, /* -device rombar=0|1 */ + QEMU_CAPS_PCI_ROMBAR = 76, /* -device rombar=0|1 */ 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_FSDEV_READONLY = 79, /* -fsdev readonly supported */
Hmm, this is the second time I've seen a patch that touches some, but not all, of the whitespace inconsistencies earlier in the enum (note that QEMU_CAPS_PCI_ROMBAR uses space while QEMU_CAPS_NO_ACPI uses tab, which means that when you add the prefix of a diff file, the alignment looks screwy). We probably ought to separate whitespace normalization of the enum into a separate patch, and let this one just focus on adding the new value of QEMU_CAPS_CPU_HOST.
- QEMU_CAPS_VIRTIO_BLK_SCSI = 80, /* virtio-blk-pci.scsi */ - QEMU_CAPS_VIRTIO_BLK_SG_IO = 81, /* support for SG_IO commands, reportedly added in 0.11 */ + QEMU_CAPS_VIRTIO_BLK_SCSI = 80, /* virtio-blk-pci.scsi */ + QEMU_CAPS_VIRTIO_BLK_SG_IO = 81, /* support for SG_IO commands, reportedly added in 0.11 */ + QEMU_CAPS_CPU_HOST = 82, /* support for -cpu host */
QEMU_CAPS_LAST, /* this must always be the last item */ };
At any rate, the rest of the patch is sane, and you addressed my comments from v1, so ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Thu, Jan 12, 2012 at 12:02:54 +0100, Jiri Denemark wrote:
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
Thanks for your review, Eric. I incorporated your comments and pushed the beast. Jirka
participants (2)
-
Eric Blake
-
Jiri Denemark