qemu: Add support for host CPU modes

This adds support for host-model and host-passthrough CPU modes to qemu
driver. The host-passthrough mode is mapped to -cpu host.
This commit is contained in:
Jiri Denemark 2011-12-21 13:47:17 +01:00
parent c8506d6662
commit e7201afdf7
17 changed files with 311 additions and 94 deletions

View File

@ -187,6 +187,7 @@ virCPUDefFormatBuf;
virCPUDefFree;
virCPUDefFreeModel;
virCPUDefParseXML;
virCPUModeTypeToString;
# datatypes.h

View File

@ -145,9 +145,10 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"no-acpi",
"fsdev-readonly",
"virtio-blk-pci.scsi",
"virtio-blk-pci.scsi", /* 80 */
"blk-sg-io",
"drive-copy-on-read",
"cpu-host",
);
struct qemu_feature_flags {
@ -1184,6 +1185,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

View File

@ -121,6 +121,7 @@ enum qemuCapsFlags {
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_DRIVE_COPY_ON_READ = 82, /* -drive copy-on-read */
QEMU_CAPS_CPU_HOST = 83, /* support for -cpu host */
QEMU_CAPS_LAST, /* this must always be the last item */
};

View File

@ -3458,10 +3458,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;
@ -3471,7 +3473,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)
@ -3482,18 +3498,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;
@ -3502,39 +3512,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 = '-';
else
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;
virBufferAsprintf(&buf, ",%c%s", sign, guest->features[i].name);
if (cpu->match == VIR_CPU_MATCH_MINIMUM)
preferred = host->model;
else
preferred = cpu->model;
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
*
@ -3565,6 +3591,7 @@ cleanup:
if (guest)
cpuDataFree(guest->arch, data);
virCPUDefFree(guest);
virCPUDefFree(cpu);
if (cpus) {
for (i = 0; i < ncpus; i++)
@ -3787,7 +3814,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) {

View File

@ -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,
@ -593,7 +598,8 @@ mymain(void)
QEMU_CAPS_NO_ACPI,
QEMU_CAPS_VIRTIO_BLK_SCSI,
QEMU_CAPS_VIRTIO_BLK_SG_IO,
QEMU_CAPS_DRIVE_COPY_ON_READ);
QEMU_CAPS_DRIVE_COPY_ON_READ,
QEMU_CAPS_CPU_HOST);
DO_TEST("qemu-1.0", 1000000, 0, 0,
QEMU_CAPS_VNC_COLON,
QEMU_CAPS_NO_REBOOT,
@ -659,7 +665,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;
}

View File

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

View File

@ -0,0 +1,15 @@
#! /bin/sh
. $(dirname $0)/qemu-lib.sh
case $* in
"-M ?")
faked_machine
;;
"-cpu ?")
faked_cpu | grep -Fv '['
;;
*)
real_qemu "$@"
;;
esac

View File

@ -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 ?")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -690,6 +690,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);