[libvirt] [PATCH 37/41] cpu: Introduce virCPUTranslate

Jiri Denemark jdenemar at redhat.com
Fri Aug 12 13:33:31 UTC 2016


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




More information about the libvir-list mailing list