PowerISA allows processors to run VMs in binary compatibility ("compat")
mode supporting an older version of ISA.
Eg,in compatibility mode, a POWER8 host can run a "Power7" VM,conforming
to PowerISA v2.06, while a POWER7 host can run a "POWER6" VM, conforming
to PowerISA v2.05.
QEMU has recently added support to explicitly denote a VM running in
compatibility mode through commit 6d9412ea. Now, a "compat" mode VM can
be run by invoking this qemu commandline on a POWER8 host:
-cpu host,compat=power7
as against the older specification of "-cpu power7".
However, running in compatibility mode is not identical to running
natively on an older processor. Hence the virtualization stack needs to
explicitly provide for a compat-mode VM.
This patch allows libvirt to extend the "fallback" semantics of cpu model to
describe this new mode for PowerKVM guests.
Additionally with the new scheme of things, qemu doesn't provide a way to query
for the supported compat models and models returned when querying with '-cpu ?'
are no longer valid. Hence removing the check cpuModelIsAllowed() for now.
When a user wants to request a power7 vm to run in compatibility mode on
a Power8 host, this can be described in XML as follows :
<cpu mode='custom' match='exact'>
<model fallback='compat'>power7</model>
</cpu>
An alternative approach could be to leave the libvirt XML intact, and merely
change the backend qemu command generation when the VM-requested cpu
does not match the host processor.
Looking forward to suggestions on how this can best be implemented..
Signed-off-by: Li Zhang <zhlcindy(a)linux.vnet.ibm.com>
Signed-off-by: Pradipta Kr. Banerjee <bpradip(a)in.ibm.com>
Signed-off-by: Prerna Saxena <prerna(a)linux.vnet.ibm.com>
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index ebdaa19..2f41bd7 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -47,7 +47,8 @@ VIR_ENUM_IMPL(virCPUMatch, VIR_CPU_MATCH_LAST,
VIR_ENUM_IMPL(virCPUFallback, VIR_CPU_FALLBACK_LAST,
"allow",
- "forbid")
+ "forbid",
+ "compat")
VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST,
"force",
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index 8c932ce..50354f2 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -65,6 +65,7 @@ VIR_ENUM_DECL(virCPUMatch)
typedef enum {
VIR_CPU_FALLBACK_ALLOW,
VIR_CPU_FALLBACK_FORBID,
+ VIR_CPU_FALLBACK_COMPAT,
VIR_CPU_FALLBACK_LAST
} virCPUFallback;
diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c
index b220448..218c013 100644
--- a/src/cpu/cpu_powerpc.c
+++ b/src/cpu/cpu_powerpc.c
@@ -457,8 +457,8 @@ ppcCompare(virCPUDefPtr host,
static int
ppcDecode(virCPUDefPtr cpu,
const virCPUData *data,
- const char **models,
- unsigned int nmodels,
+ const char **models ATTRIBUTE_UNUSED,
+ unsigned int nmodels ATTRIBUTE_UNUSED,
const char *preferred ATTRIBUTE_UNUSED,
unsigned int flags)
{
@@ -478,13 +478,6 @@ ppcDecode(virCPUDefPtr cpu,
goto cleanup;
}
- if (!cpuModelIsAllowed(model->name, models, nmodels)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("CPU model %s is not supported by hypervisor"),
- model->name);
- goto cleanup;
- }
-
if (VIR_STRDUP(cpu->model, model->name) < 0 ||
(model->vendor && VIR_STRDUP(cpu->vendor,
model->vendor->name) < 0)) {
goto cleanup;
@@ -498,7 +491,6 @@ ppcDecode(virCPUDefPtr cpu,
return ret;
}
-
static void
ppcDataFree(virCPUDataPtr data)
{
@@ -561,8 +553,8 @@ ppcUpdate(virCPUDefPtr guest,
static virCPUDefPtr
ppcBaseline(virCPUDefPtr *cpus,
unsigned int ncpus,
- const char **models,
- unsigned int nmodels,
+ const char **models ATTRIBUTE_UNUSED,
+ unsigned int nmodels ATTRIBUTE_UNUSED,
unsigned int flags)
{
struct ppc_map *map = NULL;
@@ -582,13 +574,6 @@ ppcBaseline(virCPUDefPtr *cpus,
goto error;
}
- if (!cpuModelIsAllowed(model->name, models, nmodels)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("CPU model %s is not supported by hypervisor"),
- model->name);
- goto error;
- }
-
for (i = 0; i < ncpus; i++) {
const struct ppc_vendor *vnd;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 1d5bce6..94e9b78 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6176,7 +6176,9 @@ qemuBuildCpuArgStr(virQEMUDriverPtr driver,
*hasHwVirt = hasSVM > 0 ? true : false;
}
- if (cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) {
+ if ((cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) ||
+ ((cpu->mode == VIR_CPU_MODE_HOST_MODEL) &&
+ (def->os.arch == VIR_ARCH_PPC64))) {
const char *mode = virCPUModeTypeToString(cpu->mode);
if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_HOST)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -6208,7 +6210,13 @@ qemuBuildCpuArgStr(virQEMUDriverPtr driver,
if (cpuDecode(guest, data, (const char **)cpus, ncpus, preferred) < 0)
goto cleanup;
- virBufferAdd(&buf, guest->model, -1);
+ if (def->os.arch == VIR_ARCH_PPC64 &&
+ cpu->fallback == VIR_CPU_FALLBACK_COMPAT) {
+ virBufferAddLit(&buf, "host");
+ virBufferAsprintf(&buf, ",compat=%s", guest->model);
+ } else
+ virBufferAdd(&buf, guest->model, -1);
+
if (guest->vendor_id)
virBufferAsprintf(&buf, ",vendor=%s",
guest->vendor_id);
for (i = 0; i < guest->nfeatures; i++) {
--
Prerna Saxena
Linux Technology Centre,
IBM Systems and Technology Lab,
Bangalore, India