The API is supposed to make sure the provided CPU definition does not
use a CPU model which is not supported by the hypervisor (if at all
possible, of course).
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
src/cpu/cpu.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
src/cpu/cpu.h | 14 ++++++++++++
src/cpu/cpu_x86.c | 51 +++++++++++++++++++++++++++++++++++++++++
src/libvirt_private.syms | 1 +
4 files changed, 125 insertions(+)
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index f3eb211..e215304 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -809,3 +809,62 @@ cpuGetModels(virArch arch, char ***models)
return driver->getModels(models);
}
+
+
+/**
+ * virCPUTranslate:
+ *
+ * @arch: CPU architecture
+ * @cpu: CPU definition to be translated
+ * @models: NULL-terminated list of allowed CPU models (NULL if all are allowed)
+ * @nmodels: number of CPU models in @models
+ *
+ * Translates @cpu model (if allowed by @cpu->fallback) to a closest CPU model
+ * from @models list.
+ *
+ * The function does nothing (and returns 0) if @cpu does not have to be
+ * translated.
+ *
+ * Returns -1 on error, 0 on success.
+ */
+int
+virCPUTranslate(virArch arch,
+ virCPUDefPtr cpu,
+ char **models,
+ unsigned int nmodels)
+{
+ struct cpuArchDriver *driver;
+
+ VIR_DEBUG("arch=%s, cpu=%p, model=%s, models=%p, nmodels=%u",
+ virArchToString(arch), cpu, NULLSTR(cpu->model), models, nmodels);
+
+ if (!(driver = cpuGetSubDriver(arch)))
+ return -1;
+
+ if (cpu->mode == VIR_CPU_MODE_HOST_MODEL ||
+ cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH)
+ return 0;
+
+ if (cpuModelIsAllowed(cpu->model, (const char **) models, nmodels))
+ return 0;
+
+ if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("CPU model %s is not supported by hypervisor"),
+ cpu->model);
+ return -1;
+ }
+
+ if (!driver->translate) {
+ virReportError(VIR_ERR_NO_SUPPORT,
+ _("cannot translate CPU model %s to a supported
model"),
+ cpu->model);
+ return -1;
+ }
+
+ if (driver->translate(cpu, (const char **) models, nmodels) < 0)
+ return -1;
+
+ VIR_DEBUG("model=%s", NULLSTR(cpu->model));
+ return 0;
+}
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index f4bb51d..b8036b2 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -103,6 +103,11 @@ typedef virCPUDataPtr
typedef int
(*cpuArchGetModels) (char ***models);
+typedef int
+(*virCPUArchTranslate)(virCPUDefPtr cpu,
+ const char **models,
+ unsigned int nmodels);
+
struct cpuArchDriver {
const char *name;
const virArch *arch;
@@ -119,6 +124,7 @@ struct cpuArchDriver {
cpuArchDataFormat dataFormat;
cpuArchDataParse dataParse;
cpuArchGetModels getModels;
+ virCPUArchTranslate translate;
};
@@ -202,6 +208,14 @@ cpuModelIsAllowed(const char *model,
int
cpuGetModels(virArch arch, char ***models);
+int
+virCPUTranslate(virArch arch,
+ virCPUDefPtr cpu,
+ char **models,
+ unsigned int nmodels)
+ ATTRIBUTE_NONNULL(2);
+
+
/* cpuDataFormat and cpuDataParse are implemented for unit tests only and
* have no real-life usage
*/
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index c867f83..69b081d 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -2642,6 +2642,56 @@ x86GetModels(char ***models)
}
+static int
+virCPUx86Translate(virCPUDefPtr cpu,
+ const char **models,
+ unsigned int nmodels)
+{
+ virCPUDefPtr translated = NULL;
+ virCPUx86MapPtr map;
+ virCPUx86ModelPtr model = NULL;
+ size_t i;
+ int ret = -1;
+
+ if (!(map = virCPUx86GetMap()))
+ goto cleanup;
+
+ if (!(model = x86ModelFromCPU(cpu, map, -1)))
+ goto cleanup;
+
+ if (model->vendor &&
+ virCPUx86DataAddCPUID(&model->data, &model->vendor->cpuid) <
0)
+ goto cleanup;
+
+ if (x86DataAddSignature(&model->data, model->signature) < 0)
+ goto cleanup;
+
+ if (!(translated = virCPUDefCopyWithoutModel(cpu)))
+ goto cleanup;
+
+ if (VIR_STRDUP(translated->vendor, cpu->vendor) < 0 ||
+ VIR_STRDUP(translated->vendor_id, cpu->vendor_id) < 0)
+ goto cleanup;
+
+ if (x86Decode(translated, &model->data, models, nmodels, NULL, 0) < 0)
+ goto cleanup;
+
+ for (i = 0; i < cpu->nfeatures; i++) {
+ virCPUFeatureDefPtr f = cpu->features + i;
+ if (virCPUDefUpdateFeature(translated, f->name, f->policy) < 0)
+ goto cleanup;
+ }
+
+ virCPUDefMoveModel(cpu, translated);
+ ret = 0;
+
+ cleanup:
+ virCPUDefFree(translated);
+ x86ModelFree(model);
+ return ret;
+}
+
+
struct cpuArchDriver cpuDriverX86 = {
.name = "x86",
.arch = archs,
@@ -2662,4 +2712,5 @@ struct cpuArchDriver cpuDriverX86 = {
.dataFormat = x86CPUDataFormat,
.dataParse = x86CPUDataParse,
.getModels = x86GetModels,
+ .translate = virCPUx86Translate,
};
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ef04ce4..1f50499 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -971,6 +971,7 @@ cpuGetModels;
cpuGuestData;
cpuHasFeature;
cpuNodeData;
+virCPUTranslate;
virCPUUpdate;
--
2.9.2