cpu: Optionally forbid fallback CPU models

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.
This commit is contained in:
Jiri Denemark 2011-12-21 14:27:16 +01:00
parent 23cf79f07e
commit a6f88cbd2d
36 changed files with 368 additions and 59 deletions

View File

@ -559,7 +559,7 @@
<pre> <pre>
... ...
&lt;cpu match='exact'&gt; &lt;cpu match='exact'&gt;
&lt;model&gt;core2duo&lt;/model&gt; &lt;model fallback='allow'&gt;core2duo&lt;/model&gt;
&lt;vendor&gt;Intel&lt;/vendor&gt; &lt;vendor&gt;Intel&lt;/vendor&gt;
&lt;topology sockets='1' cores='2' threads='1'/&gt; &lt;topology sockets='1' cores='2' threads='1'/&gt;
&lt;feature policy='disable' name='lahf_lm'/&gt; &lt;feature policy='disable' name='lahf_lm'/&gt;
@ -609,7 +609,15 @@
<dd>The content of the <code>model</code> element specifies CPU model <dd>The content of the <code>model</code> element specifies CPU model
requested by the guest. The list of available CPU models and their requested by the guest. The list of available CPU models and their
definition can be found in <code>cpu_map.xml</code> file installed 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 an 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> <dt><code>vendor</code></dt>
<dd><span class="since">Since 0.8.3</span> the content of the <dd><span class="since">Since 0.8.3</span> the content of the

View File

@ -2571,6 +2571,14 @@
<define name="cpuModel"> <define name="cpuModel">
<element name="model"> <element name="model">
<optional>
<attribute name="fallback">
<choice>
<value>allow</value>
<value>forbid</value>
</choice>
</attribute>
</optional>
<text/> <text/>
</element> </element>
</define> </define>

View File

@ -44,6 +44,10 @@ VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST,
"exact", "exact",
"strict") "strict")
VIR_ENUM_IMPL(virCPUFallback, VIR_CPU_FALLBACK_LAST,
"allow",
"forbid")
VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST, VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST,
"force", "force",
"require", "require",
@ -97,6 +101,7 @@ virCPUDefCopy(const virCPUDefPtr cpu)
copy->type = cpu->type; copy->type = cpu->type;
copy->match = cpu->match; copy->match = cpu->match;
copy->fallback = cpu->fallback;
copy->sockets = cpu->sockets; copy->sockets = cpu->sockets;
copy->cores = cpu->cores; copy->cores = cpu->cores;
copy->threads = cpu->threads; copy->threads = cpu->threads;
@ -209,6 +214,21 @@ virCPUDefParseXML(const xmlNodePtr node,
goto error; 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); def->vendor = virXPathString("string(./vendor[1])", ctxt);
if (def->vendor && !def->model) { if (def->vendor && !def->model) {
virCPUReportError(VIR_ERR_INTERNAL_ERROR, virCPUReportError(VIR_ERR_INTERNAL_ERROR,
@ -455,8 +475,22 @@ virCPUDefFormatBuf(virBufferPtr buf,
return -1; return -1;
} }
if (def->model) if (def->model) {
virBufferAsprintf(buf, "<model>%s</model>\n", 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) { if (def->vendor) {
virBufferAsprintf(buf, "<vendor>%s</vendor>\n", def->vendor); virBufferAsprintf(buf, "<vendor>%s</vendor>\n", def->vendor);

View File

@ -48,6 +48,15 @@ enum virCPUMatch {
VIR_ENUM_DECL(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 { enum virCPUFeaturePolicy {
VIR_CPU_FEATURE_FORCE, VIR_CPU_FEATURE_FORCE,
VIR_CPU_FEATURE_REQUIRE, VIR_CPU_FEATURE_REQUIRE,
@ -83,6 +92,7 @@ struct _virCPUDef {
int match; /* enum virCPUMatch */ int match; /* enum virCPUMatch */
char *arch; char *arch;
char *model; char *model;
int fallback; /* enum virCPUFallback */
char *vendor; char *vendor;
unsigned int sockets; unsigned int sockets;
unsigned int cores; unsigned int cores;

View File

@ -1294,8 +1294,21 @@ x86Decode(virCPUDefPtr cpu,
} }
if (!allowed) { if (!allowed) {
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", VIR_DEBUG("CPU model %s not allowed by hypervisor; ignoring",
candidate->name); candidate->name);
}
goto next; goto next;
} }

View File

@ -3511,6 +3511,7 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
preferred = def->cpu->model; preferred = def->cpu->model;
guest->type = VIR_CPU_TYPE_GUEST; guest->type = VIR_CPU_TYPE_GUEST;
guest->fallback = def->cpu->fallback;
if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0) if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
goto cleanup; goto cleanup;

View File

@ -287,6 +287,7 @@ cpuTestGuestData(const void *arg)
guest->type = VIR_CPU_TYPE_GUEST; guest->type = VIR_CPU_TYPE_GUEST;
guest->match = VIR_CPU_MATCH_EXACT; guest->match = VIR_CPU_MATCH_EXACT;
guest->fallback = cpu->fallback;
if (cpuDecode(guest, guestData, data->models, if (cpuDecode(guest, guestData, data->models,
data->nmodels, data->preferred) < 0) { data->nmodels, data->preferred) < 0) {
if (data->result < 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, "Penryn", 0);
DO_TEST_GUESTDATA("x86", "host", "guest", models, "qemu64", 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", nomodel, NULL, -1);
DO_TEST_GUESTDATA("x86", "host", "guest-nofallback", models, "Penryn", -1);
free(map); free(map);
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);

View File

@ -1,5 +1,5 @@
<cpu match='exact'> <cpu match='exact'>
<model>Conroe</model> <model fallback='allow'>Conroe</model>
<vendor>Intel</vendor> <vendor>Intel</vendor>
<feature policy='disable' name='lahf_lm'/> <feature policy='disable' name='lahf_lm'/>
</cpu> </cpu>

View File

@ -1,4 +1,4 @@
<cpu match='exact'> <cpu match='exact'>
<model>core2duo</model> <model fallback='allow'>core2duo</model>
<feature policy='disable' name='nx'/> <feature policy='disable' name='nx'/>
</cpu> </cpu>

View File

@ -1,5 +1,5 @@
<cpu match='exact'> <cpu match='exact'>
<model>Opteron_G2</model> <model fallback='allow'>Opteron_G2</model>
<feature policy='disable' name='svm'/> <feature policy='disable' name='svm'/>
<feature policy='disable' name='rdtscp'/> <feature policy='disable' name='rdtscp'/>
</cpu> </cpu>

View File

@ -1,3 +1,3 @@
<cpu match='exact'> <cpu match='exact'>
<model>Opteron_G1</model> <model fallback='allow'>Opteron_G1</model>
</cpu> </cpu>

View File

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

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>486</model> <model fallback='allow'>486</model>
<feature policy='require' name='svm'/> <feature policy='require' name='svm'/>
<feature policy='require' name='lahf_lm'/> <feature policy='require' name='lahf_lm'/>
<feature policy='require' name='3dnowext'/> <feature policy='require' name='3dnowext'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>Nehalem</model> <model fallback='allow'>Nehalem</model>
<feature policy='require' name='svm'/> <feature policy='require' name='svm'/>
<feature policy='require' name='3dnowext'/> <feature policy='require' name='3dnowext'/>
<feature policy='require' name='dca'/> <feature policy='require' name='dca'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>qemu64</model> <model fallback='allow'>qemu64</model>
<feature policy='require' name='lahf_lm'/> <feature policy='require' name='lahf_lm'/>
<feature policy='require' name='3dnowext'/> <feature policy='require' name='3dnowext'/>
<feature policy='require' name='sse4.1'/> <feature policy='require' name='sse4.1'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>Nehalem</model> <model fallback='allow'>Nehalem</model>
<feature policy='require' name='svm'/> <feature policy='require' name='svm'/>
<feature policy='require' name='3dnowext'/> <feature policy='require' name='3dnowext'/>
<feature policy='require' name='dca'/> <feature policy='require' name='dca'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>Penryn</model> <model fallback='allow'>Penryn</model>
<feature policy='require' name='svm'/> <feature policy='require' name='svm'/>
<feature policy='require' name='3dnowext'/> <feature policy='require' name='3dnowext'/>
<feature policy='require' name='dca'/> <feature policy='require' name='dca'/>

View File

@ -1,5 +1,5 @@
<cpu match='exact'> <cpu match='exact'>
<model>Penryn</model> <model fallback='allow'>Penryn</model>
<topology sockets='2' cores='4' threads='1'/> <topology sockets='2' cores='4' threads='1'/>
<feature policy='require' name='dca'/> <feature policy='require' name='dca'/>
<feature policy='require' name='xtpr'/> <feature policy='require' name='xtpr'/>

View File

@ -1,5 +1,5 @@
<cpu match='exact'> <cpu match='exact'>
<model>Penryn</model> <model fallback='allow'>Penryn</model>
<feature policy='require' name='dca'/> <feature policy='require' name='dca'/>
<feature policy='require' name='xtpr'/> <feature policy='require' name='xtpr'/>
<feature policy='require' name='tm2'/> <feature policy='require' name='tm2'/>

View File

@ -1,4 +1,4 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>Nehalem</model> <model fallback='allow'>Nehalem</model>
</cpu> </cpu>

View File

@ -1,5 +1,5 @@
<cpu match='exact'> <cpu match='exact'>
<model>pentium3</model> <model fallback='allow'>pentium3</model>
<feature policy='require' name='lahf_lm'/> <feature policy='require' name='lahf_lm'/>
<feature policy='require' name='lm'/> <feature policy='require' name='lm'/>
<feature policy='require' name='nx'/> <feature policy='require' name='nx'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>Penryn</model> <model fallback='allow'>Penryn</model>
<feature policy='require' name='3dnow'/> <feature policy='require' name='3dnow'/>
<feature policy='require' name='dca'/> <feature policy='require' name='dca'/>
<feature policy='require' name='xtpr'/> <feature policy='require' name='xtpr'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>core2duo</model> <model fallback='allow'>core2duo</model>
<feature policy='require' name='lahf_lm'/> <feature policy='require' name='lahf_lm'/>
<feature policy='require' name='popcnt'/> <feature policy='require' name='popcnt'/>
<feature policy='require' name='sse4.2'/> <feature policy='require' name='sse4.2'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>pentium3</model> <model fallback='allow'>pentium3</model>
<feature policy='require' name='lahf_lm'/> <feature policy='require' name='lahf_lm'/>
<feature policy='require' name='lm'/> <feature policy='require' name='lm'/>
<feature policy='require' name='nx'/> <feature policy='require' name='nx'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>Nehalem</model> <model fallback='allow'>Nehalem</model>
<feature policy='require' name='dca'/> <feature policy='require' name='dca'/>
<feature policy='require' name='xtpr'/> <feature policy='require' name='xtpr'/>
<feature policy='require' name='tm2'/> <feature policy='require' name='tm2'/>

View File

@ -1,6 +1,6 @@
<cpu match='exact'> <cpu match='exact'>
<arch>x86_64</arch> <arch>x86_64</arch>
<model>Penryn</model> <model fallback='allow'>Penryn</model>
<feature policy='require' name='svm'/> <feature policy='require' name='svm'/>
<feature policy='require' name='3dnowext'/> <feature policy='require' name='3dnowext'/>
<feature policy='require' name='monitor'/> <feature policy='require' name='monitor'/>

View File

@ -9,7 +9,7 @@
<boot dev='network'/> <boot dev='network'/>
</os> </os>
<cpu match='exact'> <cpu match='exact'>
<model>qemu64</model> <model fallback='allow'>qemu64</model>
<feature policy='disable' name='svm'/> <feature policy='disable' name='svm'/>
<feature policy='disable' name='lm'/> <feature policy='disable' name='lm'/>
<feature policy='disable' name='nx'/> <feature policy='disable' name='nx'/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -84,7 +84,8 @@ static int testCompareXMLToArgvFiles(const char *xml,
const char *migrateFrom, const char *migrateFrom,
int migrateFd, int migrateFd,
bool json, bool json,
bool expectError) bool expectError,
bool expectFailure)
{ {
char *expectargv = NULL; char *expectargv = NULL;
int len; int len;
@ -98,19 +99,13 @@ static int testCompareXMLToArgvFiles(const char *xml,
virCommandPtr cmd = NULL; virCommandPtr cmd = NULL;
if (!(conn = virGetConnect())) if (!(conn = virGetConnect()))
goto fail; goto out;
conn->secretDriver = &fakeSecretDriver; 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, if (!(vmdef = virDomainDefParseFile(driver.caps, xml,
QEMU_EXPECTED_VIRT_TYPES, QEMU_EXPECTED_VIRT_TYPES,
VIR_DOMAIN_XML_INACTIVE))) VIR_DOMAIN_XML_INACTIVE)))
goto fail; goto out;
/* /*
* For test purposes, we may want to fake emulator's output by providing * 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 (vmdef->emulator && STRPREFIX(vmdef->emulator, "/.")) {
if (!(emulator = strdup(vmdef->emulator + 1))) if (!(emulator = strdup(vmdef->emulator + 1)))
goto fail; goto out;
free(vmdef->emulator); free(vmdef->emulator);
vmdef->emulator = NULL; vmdef->emulator = NULL;
if (virAsprintf(&vmdef->emulator, "%s/qemuxml2argvdata/%s", if (virAsprintf(&vmdef->emulator, "%s/qemuxml2argvdata/%s",
abs_srcdir, emulator) < 0) abs_srcdir, emulator) < 0)
goto fail; goto out;
} }
if (qemuCapsGet(extraFlags, QEMU_CAPS_DOMID)) if (qemuCapsGet(extraFlags, QEMU_CAPS_DOMID))
@ -149,7 +144,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
QEMU_CAPS_LAST); QEMU_CAPS_LAST);
if (qemudCanonicalizeMachine(&driver, vmdef) < 0) if (qemudCanonicalizeMachine(&driver, vmdef) < 0)
goto fail; goto out;
if (qemuCapsGet(extraFlags, QEMU_CAPS_DEVICE)) { if (qemuCapsGet(extraFlags, QEMU_CAPS_DEVICE)) {
qemuDomainPCIAddressSetPtr pciaddrs; qemuDomainPCIAddressSetPtr pciaddrs;
@ -157,14 +152,14 @@ static int testCompareXMLToArgvFiles(const char *xml,
if (qemuDomainAssignSpaprVIOAddresses(vmdef)) { if (qemuDomainAssignSpaprVIOAddresses(vmdef)) {
if (expectError) if (expectError)
goto ok; goto ok;
goto fail; goto out;
} }
if (!(pciaddrs = qemuDomainPCIAddressSetCreate(vmdef))) if (!(pciaddrs = qemuDomainPCIAddressSetCreate(vmdef)))
goto fail; goto out;
if (qemuAssignDevicePCISlots(vmdef, pciaddrs) < 0) if (qemuAssignDevicePCISlots(vmdef, pciaddrs) < 0)
goto fail; goto out;
qemuDomainPCIAddressSetFree(pciaddrs); qemuDomainPCIAddressSetFree(pciaddrs);
} }
@ -183,35 +178,50 @@ static int testCompareXMLToArgvFiles(const char *xml,
} }
if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0) if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0)
goto fail; goto out;
if (!(cmd = qemuBuildCommandLine(conn, &driver, if (!(cmd = qemuBuildCommandLine(conn, &driver,
vmdef, &monitor_chr, json, extraFlags, vmdef, &monitor_chr, json, extraFlags,
migrateFrom, migrateFd, NULL, migrateFrom, migrateFd, NULL,
VIR_NETDEV_VPORT_PROFILE_OP_NO_OP))) VIR_NETDEV_VPORT_PROFILE_OP_NO_OP))) {
goto fail; 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 (!!virGetLastError() != expectError) {
if (virTestGetDebug() && (log = virtTestLogContentAndReset())) if (virTestGetDebug() && (log = virtTestLogContentAndReset()))
fprintf(stderr, "\n%s", log); fprintf(stderr, "\n%s", log);
goto fail; goto out;
} }
if (!(actualargv = virCommandToString(cmd))) if (!(actualargv = virCommandToString(cmd)))
goto fail; goto out;
if (emulator) { if (emulator) {
/* Skip the abs_srcdir portion of replacement emulator. */ /* Skip the abs_srcdir portion of replacement emulator. */
char *start_skip = strstr(actualargv, abs_srcdir); char *start_skip = strstr(actualargv, abs_srcdir);
char *end_skip = strstr(actualargv, emulator); char *end_skip = strstr(actualargv, emulator);
if (!start_skip || !end_skip) if (!start_skip || !end_skip)
goto fail; goto out;
memmove(start_skip, end_skip, strlen(end_skip) + 1); 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)) { if (STRNEQ(expectargv, actualargv)) {
virtTestDifference(stderr, expectargv, actualargv); virtTestDifference(stderr, expectargv, actualargv);
goto fail; goto out;
} }
ok: ok:
@ -222,7 +232,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
ret = 0; ret = 0;
fail: out:
free(log); free(log);
free(emulator); free(emulator);
free(expectargv); free(expectargv);
@ -240,6 +250,7 @@ struct testInfo {
const char *migrateFrom; const char *migrateFrom;
int migrateFd; int migrateFd;
bool expectError; bool expectError;
bool expectFailure;
}; };
static int static int
@ -260,7 +271,8 @@ testCompareXMLToArgvHelper(const void *data)
info->migrateFrom, info->migrateFd, info->migrateFrom, info->migrateFd,
qemuCapsGet(info->extraFlags, qemuCapsGet(info->extraFlags,
QEMU_CAPS_MONITOR_JSON), QEMU_CAPS_MONITOR_JSON),
info->expectError); info->expectError,
info->expectFailure);
cleanup: cleanup:
free(xml); free(xml);
@ -299,10 +311,12 @@ mymain(void)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
# define DO_TEST_FULL(name, migrateFrom, migrateFd, expectError, ...) \ # define DO_TEST_FULL(name, migrateFrom, migrateFd, \
expectError, expectFailure, ...) \
do { \ do { \
struct testInfo info = { \ struct testInfo info = { \
name, NULL, migrateFrom, migrateFd, expectError \ name, NULL, migrateFrom, migrateFd, \
expectError, expectFailure \
}; \ }; \
if (!(info.extraFlags = qemuCapsNew())) \ if (!(info.extraFlags = qemuCapsNew())) \
return EXIT_FAILURE; \ return EXIT_FAILURE; \
@ -314,7 +328,10 @@ mymain(void)
} while (0) } while (0)
# define DO_TEST(name, expectError, ...) \ # 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 # define NONE QEMU_CAPS_LAST
@ -643,17 +660,17 @@ mymain(void)
DO_TEST("hostdev-pci-address-device", false, DO_TEST("hostdev-pci-address-device", false,
QEMU_CAPS_PCIDEVICE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); 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); 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); 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); 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); 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); 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); QEMU_CAPS_MIGRATE_QEMU_TCP);
DO_TEST("qemu-ns", false, NONE); DO_TEST("qemu-ns", false, NONE);
@ -667,6 +684,9 @@ mymain(void)
DO_TEST("cpu-minimum2", false, NONE); DO_TEST("cpu-minimum2", false, NONE);
DO_TEST("cpu-exact1", false, NONE); DO_TEST("cpu-exact1", false, NONE);
DO_TEST("cpu-exact2", 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-strict1", false, NONE);
DO_TEST("cpu-numa1", false, NONE); DO_TEST("cpu-numa1", false, NONE);
DO_TEST("cpu-numa2", false, QEMU_CAPS_SMP_TOPOLOGY); DO_TEST("cpu-numa2", false, QEMU_CAPS_SMP_TOPOLOGY);

View File

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

View File

@ -149,7 +149,6 @@ mymain(void)
DO_TEST("graphics-sdl-fullscreen"); DO_TEST("graphics-sdl-fullscreen");
DO_TEST("graphics-spice"); DO_TEST("graphics-spice");
DO_TEST("graphics-spice-compression"); DO_TEST("graphics-spice-compression");
DO_TEST("graphics-spice-timeout");
DO_TEST("graphics-spice-qxl-vga"); DO_TEST("graphics-spice-qxl-vga");
DO_TEST("input-usbmouse"); DO_TEST("input-usbmouse");
DO_TEST("input-usbtablet"); DO_TEST("input-usbtablet");
@ -209,6 +208,7 @@ mymain(void)
DO_TEST_DIFFERENT("console-virtio"); DO_TEST_DIFFERENT("console-virtio");
DO_TEST_DIFFERENT("serial-target-port-auto"); DO_TEST_DIFFERENT("serial-target-port-auto");
DO_TEST_DIFFERENT("graphics-listen-network2"); DO_TEST_DIFFERENT("graphics-listen-network2");
DO_TEST_DIFFERENT("graphics-spice-timeout");
virCapabilitiesFree(driver.caps); virCapabilitiesFree(driver.caps);

View File

@ -115,6 +115,7 @@ virCapsPtr testQemuCapsInit(void) {
0, /* match */ 0, /* match */
(char *) "x86_64", /* arch */ (char *) "x86_64", /* arch */
(char *) "core2duo", /* model */ (char *) "core2duo", /* model */
0, /* fallback */
(char *) "Intel", /* vendor */ (char *) "Intel", /* vendor */
1, /* sockets */ 1, /* sockets */
2, /* cores */ 2, /* cores */