From: Don Dugger Date: Fri, 2 Aug 2013 19:08:19 +0000 (-0600) Subject: Add flag to BaselineCPU API to return detailed CPU features X-Git-Tag: v1.1.2-rc1~93 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d4952d36d0799ce4ce85a6ccfe143a72ed778bab;p=thirdparty%2Flibvirt.git Add flag to BaselineCPU API to return detailed CPU features Currently the virConnectBaselineCPU API does not expose the CPU features that are part of the CPU's model. This patch adds a new flag, VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, that causes the API to explicitly list all features that are part of that model. Signed-off-by: Don Dugger Signed-off-by: Eric Blake --- diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 52ac95d722..a47e33cc73 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4007,6 +4007,15 @@ int virConnectCompareCPU(virConnectPtr conn, unsigned int flags); +/** + * virConnectBaselineCPUFlags + * + * Flags when getting XML description of a computed CPU + */ +typedef enum { + VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES = (1 << 0), /* show all features */ +} virConnectBaselineCPUFlags; + /** * virConnectBaselineCPU: * diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 4124354e79..023ce2652a 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -167,7 +167,7 @@ cpuDecode(virCPUDefPtr cpu, return -1; } - return driver->decode(cpu, data, models, nmodels, preferred); + return driver->decode(cpu, data, models, nmodels, preferred, 0); } @@ -276,7 +276,8 @@ char * cpuBaselineXML(const char **xmlCPUs, unsigned int ncpus, const char **models, - unsigned int nmodels) + unsigned int nmodels, + unsigned int flags) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; @@ -323,7 +324,7 @@ cpuBaselineXML(const char **xmlCPUs, doc = NULL; } - if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels))) + if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels, flags))) goto error; cpustr = virCPUDefFormat(cpu, 0); @@ -350,7 +351,8 @@ virCPUDefPtr cpuBaseline(virCPUDefPtr *cpus, unsigned int ncpus, const char **models, - unsigned int nmodels) + unsigned int nmodels, + unsigned int flags) { struct cpuArchDriver *driver; size_t i; @@ -392,7 +394,7 @@ cpuBaseline(virCPUDefPtr *cpus, return NULL; } - return driver->baseline(cpus, ncpus, models, nmodels); + return driver->baseline(cpus, ncpus, models, nmodels, flags); } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 40034350ae..7f1d4bd027 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -53,7 +53,8 @@ typedef int const virCPUDataPtr data, const char **models, unsigned int nmodels, - const char *preferred); + const char *preferred, + unsigned int flags); typedef int (*cpuArchEncode) (virArch arch, @@ -81,7 +82,8 @@ typedef virCPUDefPtr (*cpuArchBaseline) (virCPUDefPtr *cpus, unsigned int ncpus, const char **models, - unsigned int nmodels); + unsigned int nmodels, + unsigned int flags); typedef int (*cpuArchUpdate) (virCPUDefPtr guest, @@ -149,13 +151,15 @@ extern char * cpuBaselineXML(const char **xmlCPUs, unsigned int ncpus, const char **models, - unsigned int nmodels); + unsigned int nmodels, + unsigned int flags); extern virCPUDefPtr cpuBaseline (virCPUDefPtr *cpus, unsigned int ncpus, const char **models, - unsigned int nmodels); + unsigned int nmodels, + unsigned int flags); extern int cpuUpdate (virCPUDefPtr guest, diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 25e25ba361..d1b2a99b17 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -44,8 +44,12 @@ ArmDecode(virCPUDefPtr cpu ATTRIBUTE_UNUSED, const virCPUDataPtr data ATTRIBUTE_UNUSED, const char **models ATTRIBUTE_UNUSED, unsigned int nmodels ATTRIBUTE_UNUSED, - const char *preferred ATTRIBUTE_UNUSED) + const char *preferred ATTRIBUTE_UNUSED, + unsigned int flags) { + + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1); + return 0; } diff --git a/src/cpu/cpu_generic.c b/src/cpu/cpu_generic.c index 2fe792ff63..1264da4981 100644 --- a/src/cpu/cpu_generic.c +++ b/src/cpu/cpu_generic.c @@ -113,7 +113,8 @@ static virCPUDefPtr genericBaseline(virCPUDefPtr *cpus, unsigned int ncpus, const char **models, - unsigned int nmodels) + unsigned int nmodels, + unsigned int flags) { virCPUDefPtr cpu = NULL; virCPUFeatureDefPtr features = NULL; @@ -121,6 +122,8 @@ genericBaseline(virCPUDefPtr *cpus, unsigned int count; size_t i, j; + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL); + if (!cpuModelIsAllowed(cpus[0]->model, models, nmodels)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("CPU model %s is not supported by hypervisor"), diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 55a4153489..647a8a11e2 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -304,12 +304,15 @@ ppcDecode(virCPUDefPtr cpu, const virCPUDataPtr data, const char **models, unsigned int nmodels, - const char *preferred ATTRIBUTE_UNUSED) + const char *preferred ATTRIBUTE_UNUSED, + unsigned int flags) { int ret = -1; struct ppc_map *map; const struct ppc_model *model; + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1); + if (data == NULL || (map = ppcLoadMap()) == NULL) return -1; @@ -377,7 +380,8 @@ static virCPUDefPtr ppcBaseline(virCPUDefPtr *cpus, unsigned int ncpus, const char **models, - unsigned int nmodels) + unsigned int nmodels, + unsigned int flags) { struct ppc_map *map = NULL; const struct ppc_model *model; @@ -385,6 +389,8 @@ ppcBaseline(virCPUDefPtr *cpus, virCPUDefPtr cpu = NULL; size_t i; + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL); + if (!(map = ppcLoadMap())) goto error; diff --git a/src/cpu/cpu_s390.c b/src/cpu/cpu_s390.c index cbfae42795..d997e06d9a 100644 --- a/src/cpu/cpu_s390.c +++ b/src/cpu/cpu_s390.c @@ -48,8 +48,12 @@ s390Decode(virCPUDefPtr cpu ATTRIBUTE_UNUSED, const virCPUDataPtr data ATTRIBUTE_UNUSED, const char **models ATTRIBUTE_UNUSED, unsigned int nmodels ATTRIBUTE_UNUSED, - const char *preferred ATTRIBUTE_UNUSED) + const char *preferred ATTRIBUTE_UNUSED, + unsigned int flags) { + + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1); + return 0; } diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index a388f0f2b8..41ce21fa76 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1319,13 +1319,42 @@ x86GuestData(virCPUDefPtr host, return x86Compute(host, guest, data, message); } +static int +x86AddFeatures(virCPUDefPtr cpu, + struct x86_map *map) +{ + const struct x86_model *candidate; + const struct x86_feature *feature = map->features; + + candidate = map->models; + while (candidate != NULL) { + if (STREQ(cpu->model, candidate->name)) + break; + candidate = candidate->next; + } + if (!candidate) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s not a known CPU model"), cpu->model); + return -1; + } + while (feature != NULL) { + if (x86DataIsSubset(candidate->data, feature->data) && + virCPUDefAddFeature(cpu, feature->name, + VIR_CPU_FEATURE_REQUIRE) < 0) + return -1; + feature = feature->next; + } + return 0; +} + static int x86Decode(virCPUDefPtr cpu, const struct cpuX86Data *data, const char **models, unsigned int nmodels, - const char *preferred) + const char *preferred, + unsigned int flags) { int ret = -1; struct x86_map *map; @@ -1334,6 +1363,8 @@ x86Decode(virCPUDefPtr cpu, virCPUDefPtr cpuModel = NULL; size_t i; + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1); + if (data == NULL || (map = x86LoadMap()) == NULL) return -1; @@ -1406,6 +1437,9 @@ x86Decode(virCPUDefPtr cpu, goto out; } + if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES && + x86AddFeatures(cpuModel, map) < 0) + goto out; cpu->model = cpuModel->model; cpu->vendor = cpuModel->vendor; cpu->nfeatures = cpuModel->nfeatures; @@ -1426,9 +1460,10 @@ x86DecodeCPUData(virCPUDefPtr cpu, const virCPUDataPtr data, const char **models, unsigned int nmodels, - const char *preferred) + const char *preferred, + unsigned int flags) { - return x86Decode(cpu, data->data.x86, models, nmodels, preferred); + return x86Decode(cpu, data->data.x86, models, nmodels, preferred, flags); } @@ -1674,7 +1709,8 @@ static virCPUDefPtr x86Baseline(virCPUDefPtr *cpus, unsigned int ncpus, const char **models, - unsigned int nmodels) + unsigned int nmodels, + unsigned int flags) { struct x86_map *map = NULL; struct x86_model *base_model = NULL; @@ -1755,7 +1791,7 @@ x86Baseline(virCPUDefPtr *cpus, if (vendor && x86DataAddCpuid(base_model->data, &vendor->cpuid) < 0) goto error; - if (x86Decode(cpu, base_model->data, models, nmodels, NULL) < 0) + if (x86Decode(cpu, base_model->data, models, nmodels, NULL, flags) < 0) goto error; if (!outputVendor) diff --git a/src/libvirt.c b/src/libvirt.c index 66e82485ae..07a3fd5022 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -18524,11 +18524,16 @@ error: * @conn: virConnect connection * @xmlCPUs: array of XML descriptions of host CPUs * @ncpus: number of CPUs in xmlCPUs - * @flags: extra flags; not used yet, so callers should always pass 0 + * @flags: bitwise-OR of virConnectBaselineCPUFlags * * Computes the most feature-rich CPU which is compatible with all given * host CPUs. * + * If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt + * will explicitly list all CPU features that are part of the host CPU, + * without this flag features that are part of the CPU model will not be + * listed. + * * Returns XML description of the computed CPU or NULL on error. */ char * diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2daafa8d16..2ad236e0e1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11056,12 +11056,12 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, { char *cpu = NULL; - virCheckFlags(0, NULL); + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL); if (virConnectBaselineCPUEnsureACL(conn) < 0) goto cleanup; - cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0); + cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags); cleanup: return cpu; diff --git a/tests/cputest.c b/tests/cputest.c index 2e5f0cdfb8..959cb9fdc4 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -75,6 +75,7 @@ struct data { const char *modelsName; unsigned int nmodels; const char *preferred; + unsigned int flags; int result; }; @@ -330,7 +331,7 @@ cpuTestBaseline(const void *arg) if (!(cpus = cpuTestLoadMultiXML(data->arch, data->name, &ncpus))) goto cleanup; - baseline = cpuBaseline(cpus, ncpus, NULL, 0); + baseline = cpuBaseline(cpus, ncpus, NULL, 0, data->flags); if (data->result < 0) { virResetLastError(); if (!baseline) @@ -510,12 +511,12 @@ mymain(void) } #define DO_TEST(arch, api, name, host, cpu, \ - models, nmodels, preferred, result) \ + models, nmodels, preferred, flags, result) \ do { \ static struct data data = { \ arch, api, host, cpu, models, \ models == NULL ? NULL : #models, \ - nmodels, preferred, result \ + nmodels, preferred, flags, result \ }; \ if (cpuTestRun(name, &data) < 0) \ ret = -1; \ @@ -524,31 +525,31 @@ mymain(void) #define DO_TEST_COMPARE(arch, host, cpu, result) \ DO_TEST(arch, API_COMPARE, \ host "/" cpu " (" #result ")", \ - host, cpu, NULL, 0, NULL, result) + host, cpu, NULL, 0, NULL, 0, result) #define DO_TEST_UPDATE(arch, host, cpu, result) \ do { \ DO_TEST(arch, API_UPDATE, \ cpu " on " host, \ - host, cpu, NULL, 0, NULL, 0); \ + host, cpu, NULL, 0, NULL, 0, 0); \ DO_TEST_COMPARE(arch, host, host "+" cpu, result); \ } while (0) -#define DO_TEST_BASELINE(arch, name, result) \ +#define DO_TEST_BASELINE(arch, name, flags, result) \ DO_TEST(arch, API_BASELINE, name, NULL, "baseline-" name, \ - NULL, 0, NULL, result) + NULL, 0, NULL, flags, result) #define DO_TEST_HASFEATURE(arch, host, feature, result) \ DO_TEST(arch, API_HAS_FEATURE, \ host "/" feature " (" #result ")", \ - host, feature, NULL, 0, NULL, result) + host, feature, NULL, 0, NULL, 0, result) #define DO_TEST_GUESTDATA(arch, host, cpu, models, preferred, result) \ DO_TEST(arch, API_GUEST_DATA, \ host "/" cpu " (" #models ", pref=" #preferred ")", \ host, cpu, models, \ models == NULL ? 0 : sizeof(models) / sizeof(char *), \ - preferred, result) + preferred, 0, result) /* host to host comparison */ DO_TEST_COMPARE("x86", "host", "host", VIR_CPU_COMPARE_IDENTICAL); @@ -593,11 +594,12 @@ mymain(void) DO_TEST_UPDATE("x86", "host", "host-passthrough", VIR_CPU_COMPARE_IDENTICAL); /* computing baseline CPUs */ - DO_TEST_BASELINE("x86", "incompatible-vendors", -1); - DO_TEST_BASELINE("x86", "no-vendor", 0); - DO_TEST_BASELINE("x86", "some-vendors", 0); - DO_TEST_BASELINE("x86", "1", 0); - DO_TEST_BASELINE("x86", "2", 0); + DO_TEST_BASELINE("x86", "incompatible-vendors", 0, -1); + DO_TEST_BASELINE("x86", "no-vendor", 0, 0); + DO_TEST_BASELINE("x86", "some-vendors", 0, 0); + DO_TEST_BASELINE("x86", "1", 0, 0); + DO_TEST_BASELINE("x86", "2", 0, 0); + DO_TEST_BASELINE("x86", "3", VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, 0); /* CPU features */ DO_TEST_HASFEATURE("x86", "host", "vmx", YES); diff --git a/tests/cputestdata/x86-baseline-3-result.xml b/tests/cputestdata/x86-baseline-3-result.xml new file mode 100644 index 0000000000..d196112b27 --- /dev/null +++ b/tests/cputestdata/x86-baseline-3-result.xml @@ -0,0 +1,35 @@ + + Westmere + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cputestdata/x86-baseline-3.xml b/tests/cputestdata/x86-baseline-3.xml new file mode 100644 index 0000000000..7654a1d65d --- /dev/null +++ b/tests/cputestdata/x86-baseline-3.xml @@ -0,0 +1,7 @@ + + + x86_64 + Westmere + + + diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 18fcb3eec3..13e30451a8 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -6157,6 +6157,10 @@ static const vshCmdOptDef opts_cpu_baseline[] = { .flags = VSH_OFLAG_REQ, .help = N_("file containing XML CPU descriptions") }, + {.name = "features", + .type = VSH_OT_BOOL, + .help = N_("Show features that are part of the CPU model type") + }, {.name = NULL} }; @@ -6168,6 +6172,7 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) char *buffer; char *result = NULL; const char **list = NULL; + unsigned int flags = 0; int count = 0; xmlDocPtr xml = NULL; @@ -6177,6 +6182,9 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) virBuffer buf = VIR_BUFFER_INITIALIZER; size_t i; + if (vshCommandOptBool(cmd, "features")) + flags |= VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES; + if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0) return false; @@ -6220,7 +6228,7 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) list[i] = vshStrdup(ctl, (const char *)xmlBufferContent(xml_buf)); } - result = virConnectBaselineCPU(ctl->conn, list, count, 0); + result = virConnectBaselineCPU(ctl->conn, list, count, flags); if (result) { vshPrint(ctl, "%s", result); diff --git a/tools/virsh.pod b/tools/virsh.pod index 3ff6da14a8..0ae51780d5 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -485,13 +485,16 @@ cell and the total free memory on the machine. Finally, with a numeric argument or with --cellno plus a cell number it will display the free memory for the specified cell only. -=item B I +=item B I [I<--features>] Compute baseline CPU which will be supported by all host CPUs given in . The list of host CPUs is built by extracting all elements from the . Thus, the can contain either a set of elements separated by new lines or even a set of complete elements printed by -B command. +B command. If I<--features> is specified then the +resulting XML description will explicitly include all features that make +up the CPU, without this option features that are part of the CPU model +will not be listed in the XML description. =item B I