From 6b159239cc476a4f24bc1e9faa62b8e6aea26c08 Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Fri, 17 Jun 2016 09:45:48 +0200 Subject: [PATCH] cpu: Introduce virCPUTranslate 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 --- 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 e6f6335ff5..748b6f92a5 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 dac7688126..6a21bfa53f 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 f424f7205f..a45427ad80 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2643,6 +2643,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; + } + + virCPUDefStealModel(cpu, translated); + ret = 0; + + cleanup: + virCPUDefFree(translated); + x86ModelFree(model); + return ret; +} + + struct cpuArchDriver cpuDriverX86 = { .name = "x86", .arch = archs, @@ -2663,4 +2713,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 6dfab8284a..09fd024c22 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -981,6 +981,7 @@ cpuGetModels; cpuGuestData; cpuHasFeature; cpuNodeData; +virCPUTranslate; virCPUUpdate;