[libvirt] [PATCH v2 0/9] New public API for computing baseline CPU

Version 2 changes: - rebased (mainly for conn argument removal) - swapped array and number of elements in array parameters - fixed absolute paths in generated RPC code - added python bindings for virConnectBaselineCPU - fixed uninitialized variable in cpuDecode, which wasn't revealed by gcc :-( This series introduces a new virConnectBaselineCPU() API call for computing baseline CPU model from a set of host CPU definitions. The call accepts a list of <cpu>...</cpu> xml definitions taken from host capabilities and returns an xml description of a guest CPU which is supported by all hosts. virsh is little bit less picky and accepts a file containing host CPU definitions. It doesn't care what is outside of the <cpu/> tag, which allows for concatenating outputs of virsh capabilities from several hosts and feeding the result to virsh cpu-baseline. This series can also be found on cpu-baseline branch of git://gitorious.org/~jirka/libvirt/jirka-staging.git In practice it works like this: # virsh cpu-baseline /dev/stdin >guest-cpu <<EOF <capabilities> <host> <cpu> <arch>x86_64</arch> <model>core2duo</model> <topology sockets='1' cores='2' threads='1'/> <feature name='lahf_lm'/> <feature name='xtpr'/> <feature name='cx16'/> <feature name='tm2'/> <feature name='est'/> <feature name='vmx'/> </cpu> </host> </capabilities> <cpu> <arch>i686</arch> <model>pentiumpro</model> <topology sockets='1' cores='2' threads='1'/> <feature name='vme'/> <feature name='pse36'/> <feature name='pni'/> <feature name='monitor'/> <feature name='ssse3'/> </cpu> <cpu> <arch>x86_64</arch> <model>phenom</model> </cpu> EOF # cat guest-cpu <cpu match='exact'> <model>qemu32</model> <feature policy='require' name='monitor'/> <feature policy='require' name='pse36'/> </cpu> Jiri Denemark (9): Functions for computing baseline CPU from a set of host CPUs Implement cpuArchBaseline in generic CPU driver Implement cpuArchBaseline in x86 CPU driver virConnectBaselineCPU public API Internal driver API for virConnectBaselineCPU virConnectBaselineCPU public API implementation Wire protocol format and dispatcher for virConnectBaselineCPU Implement cpuBaseline in remote and qemu drivers cpu-baseline command for virsh daemon/remote.c | 25 +++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++ daemon/remote_dispatch_ret.h | 1 + daemon/remote_dispatch_table.h | 5 ++ include/libvirt/libvirt.h.in | 18 +++++ python/generator.py | 1 + python/libvirt-override-api.xml | 7 ++ python/libvirt-override.c | 52 +++++++++++++++ src/cpu/cpu.c | 123 ++++++++++++++++++++++++++++++++++- src/cpu/cpu.h | 21 ++++++- src/cpu/cpu_generic.c | 104 +++++++++++++++++++++++++++++- src/cpu/cpu_x86.c | 88 ++++++++++++++++++++++++- src/driver.h | 6 ++ src/esx/esx_driver.c | 1 + src/libvirt.c | 57 ++++++++++++++++ src/libvirt_private.syms | 2 + src/libvirt_public.syms | 1 + src/lxc/lxc_driver.c | 1 + src/opennebula/one_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 14 ++++ src/remote/remote_driver.c | 32 +++++++++ src/remote/remote_protocol.c | 22 ++++++ src/remote/remote_protocol.h | 20 ++++++ src/remote/remote_protocol.x | 18 +++++- src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/xen/xen_driver.c | 1 + tools/virsh.c | 72 ++++++++++++++++++++ tools/virsh.pod | 8 ++ 33 files changed, 709 insertions(+), 6 deletions(-)

Baseline CPU is the best CPU which can be used for a guest on any of the hosts. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu.c | 123 +++++++++++++++++++++++++++++++++++++++++++++- src/cpu/cpu.h | 21 ++++++++- src/cpu/cpu_generic.c | 3 +- src/cpu/cpu_x86.c | 3 +- src/libvirt_private.syms | 2 + 5 files changed, 148 insertions(+), 4 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index e9ecc98..501a00c 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -1,7 +1,7 @@ /* * cpu.c: internal functions for CPU manipulation * - * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009--2010 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,6 +23,7 @@ #include <config.h> +#include "memory.h" #include "xml.h" #include "cpu.h" #include "cpu_x86.h" @@ -237,3 +238,123 @@ cpuGuestData(virCPUDefPtr host, return driver->guestData(host, guest, data); } + + +char * +cpuBaselineXML(const char **xmlCPUs, + unsigned int ncpus, + const char **models, + unsigned int nmodels) +{ + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + virCPUDefPtr *cpus = NULL; + virCPUDefPtr cpu = NULL; + char *cpustr; + unsigned int i; + + if (xmlCPUs == NULL && ncpus != 0) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("nonzero ncpus doesn't match with NULL xmlCPUs")); + return NULL; + } + + if (ncpus < 1) { + virCPUReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given")); + return NULL; + } + + if (VIR_ALLOC_N(cpus, ncpus)) + goto no_memory; + + for (i = 0; i < ncpus; i++) { + doc = xmlParseMemory(xmlCPUs[i], strlen(xmlCPUs[i])); + if (doc == NULL || (ctxt = xmlXPathNewContext(doc)) == NULL) + goto no_memory; + + ctxt->node = xmlDocGetRootElement(doc); + + cpus[i] = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_HOST); + if (cpus[i] == NULL) + goto error; + + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + ctxt = NULL; + doc = NULL; + } + + if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels))) + goto error; + + cpustr = virCPUDefFormat(cpu, "", 0); + +cleanup: + if (cpus) { + for (i = 0; i < ncpus; i++) + virCPUDefFree(cpus[i]); + VIR_FREE(cpus); + } + virCPUDefFree(cpu); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + + return cpustr; + +no_memory: + virReportOOMError(); +error: + cpustr = NULL; + goto cleanup; +} + + +virCPUDefPtr +cpuBaseline(virCPUDefPtr *cpus, + unsigned int ncpus, + const char **models, + unsigned int nmodels) +{ + struct cpuArchDriver *driver; + virCPUDefPtr cpu; + + if (cpus == NULL && ncpus != 0) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("nonzero ncpus doesn't match with NULL cpus")); + return NULL; + } + + if (ncpus < 1) { + virCPUReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given")); + return NULL; + } + + if (models == NULL && nmodels != 0) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("nonzero nmodels doesn't match with NULL models")); + return NULL; + } + + if ((driver = cpuGetSubDriver(cpus[0]->arch)) == NULL) + return NULL; + + if (driver->baseline == NULL) { + virCPUReportError(VIR_ERR_NO_SUPPORT, + _("cannot compute baseline CPU of %s architecture"), + cpus[0]->arch); + return NULL; + } + + if ((cpu = driver->baseline(cpus, ncpus, models, nmodels))) { + int i; + + cpu->type = VIR_CPU_TYPE_GUEST; + cpu->match = VIR_CPU_MATCH_EXACT; + VIR_FREE(cpu->arch); + + for (i = 0; i < cpu->nfeatures; i++) + cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE; + } + + return cpu; +} diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 7ee0ce6..c8d961d 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -1,7 +1,7 @@ /* * cpu.h: internal functions for CPU manipulation * - * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009--2010 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -70,6 +70,12 @@ typedef virCPUCompareResult virCPUDefPtr guest, union cpuData **data); +typedef virCPUDefPtr +(*cpuArchBaseline) (virCPUDefPtr *cpus, + unsigned int ncpus, + const char **models, + unsigned int nmodels); + struct cpuArchDriver { const char *name; @@ -81,6 +87,7 @@ struct cpuArchDriver { cpuArchDataFree free; cpuArchNodeData nodeData; cpuArchGuestData guestData; + cpuArchBaseline baseline; }; @@ -119,4 +126,16 @@ cpuGuestData(virCPUDefPtr host, virCPUDefPtr guest, union cpuData **data); +extern char * +cpuBaselineXML(const char **xmlCPUs, + unsigned int ncpus, + const char **models, + unsigned int nmodels); + +extern virCPUDefPtr +cpuBaseline (virCPUDefPtr *cpus, + unsigned int ncpus, + const char **models, + unsigned int nmodels); + #endif /* __VIR_CPU_H__ */ diff --git a/src/cpu/cpu_generic.c b/src/cpu/cpu_generic.c index 566fed0..eac314d 100644 --- a/src/cpu/cpu_generic.c +++ b/src/cpu/cpu_generic.c @@ -118,5 +118,6 @@ struct cpuArchDriver cpuDriverGeneric = { .encode = NULL, .free = NULL, .nodeData = NULL, - .guestData = NULL + .guestData = NULL, + .baseline = NULL, }; diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index c6ed078..a6db86d 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1205,5 +1205,6 @@ struct cpuArchDriver cpuDriverX86 = { #else .nodeData = NULL, #endif - .guestData = x86GuestData + .guestData = x86GuestData, + .baseline = NULL, }; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7573af3..aa826d6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -72,6 +72,8 @@ virCgroupSetFreezerState; # cpu.h +cpuBaseline; +cpuBaselineXML; cpuCompare; cpuCompareXML; cpuDataFree; -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:51PM +0100, Jiri Denemark wrote:
Baseline CPU is the best CPU which can be used for a guest on any of the hosts.
[...]
+char * +cpuBaselineXML(const char **xmlCPUs, + unsigned int ncpus, + const char **models, + unsigned int nmodels) +{ + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + virCPUDefPtr *cpus = NULL; + virCPUDefPtr cpu = NULL; + char *cpustr; + unsigned int i; + + if (xmlCPUs == NULL && ncpus != 0) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("nonzero ncpus doesn't match with NULL xmlCPUs")); + return NULL; + } + + if (ncpus < 1) { + virCPUReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given")); + return NULL; + } + + if (VIR_ALLOC_N(cpus, ncpus)) + goto no_memory; + + for (i = 0; i < ncpus; i++) { + doc = xmlParseMemory(xmlCPUs[i], strlen(xmlCPUs[i])); + if (doc == NULL || (ctxt = xmlXPathNewContext(doc)) == NULL) + goto no_memory;
Hum, no, doc == NULL might come from parsing error, raising an OOMError in that case sounds weird, unless you're 100% sure this is well formed XML...
+ ctxt->node = xmlDocGetRootElement(doc); + + cpus[i] = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_HOST); + if (cpus[i] == NULL) + goto error; + + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + ctxt = NULL; + doc = NULL; + } + + if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels))) + goto error; + + cpustr = virCPUDefFormat(cpu, "", 0); + +cleanup: + if (cpus) { + for (i = 0; i < ncpus; i++) + virCPUDefFree(cpus[i]); + VIR_FREE(cpus); + } + virCPUDefFree(cpu); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + + return cpustr; + +no_memory: + virReportOOMError(); +error: + cpustr = NULL; + goto cleanup; +}
Otherwise looks fine, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

+ for (i = 0; i < ncpus; i++) { + doc = xmlParseMemory(xmlCPUs[i], strlen(xmlCPUs[i])); + if (doc == NULL || (ctxt = xmlXPathNewContext(doc)) == NULL) + goto no_memory;
Hum, no, doc == NULL might come from parsing error, raising an OOMError in that case sounds weird, unless you're 100% sure this is well formed XML...
Hmm, right. If you don't mind I will address this separately together with similar older code. Jirka

On Thu, Feb 11, 2010 at 07:45:40PM +0100, Jiri Denemark wrote:
+ for (i = 0; i < ncpus; i++) { + doc = xmlParseMemory(xmlCPUs[i], strlen(xmlCPUs[i])); + if (doc == NULL || (ctxt = xmlXPathNewContext(doc)) == NULL) + goto no_memory;
Hum, no, doc == NULL might come from parsing error, raising an OOMError in that case sounds weird, unless you're 100% sure this is well formed XML...
Hmm, right. If you don't mind I will address this separately together with similar older code.
Yeah, sure ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_generic.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 101 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu_generic.c b/src/cpu/cpu_generic.c index eac314d..113af2f 100644 --- a/src/cpu/cpu_generic.c +++ b/src/cpu/cpu_generic.c @@ -2,7 +2,7 @@ * cpu_generic.c: CPU manipulation driver for architectures which are not * handled by their own driver * - * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009--2010 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,7 @@ #include <config.h> +#include "memory.h" #include "hash.h" #include "cpu.h" #include "cpu_generic.h" @@ -109,6 +110,104 @@ cleanup: } +static virCPUDefPtr +genericBaseline(virCPUDefPtr *cpus, + unsigned int ncpus, + const char **models, + unsigned int nmodels) +{ + virCPUDefPtr cpu = NULL; + virCPUFeatureDefPtr features = NULL; + unsigned int nfeatures; + unsigned int count; + unsigned int i, j; + + if (models) { + bool found = false; + for (i = 0; i < nmodels; i++) { + if (STREQ(cpus[0]->model, models[i])) { + found = true; + break; + } + } + if (!found) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model '%s' is not support by hypervisor"), + cpus[0]->model); + goto error; + } + } + + if (VIR_ALLOC(cpu) < 0 || + !(cpu->arch = strdup(cpus[0]->arch)) || + !(cpu->model = strdup(cpus[0]->model)) || + VIR_ALLOC_N(features, cpus[0]->nfeatures) < 0) + goto no_memory; + + cpu->type = VIR_CPU_TYPE_HOST; + + count = nfeatures = cpus[0]->nfeatures; + for (i = 0; i < nfeatures; i++) + features[i].name = cpus[0]->features[i].name; + + for (i = 1; i < ncpus; i++) { + virHashTablePtr hash; + + if (STRNEQ(cpu->arch, cpus[i]->arch)) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("CPUs have incompatible architectures: '%s' != '%s'"), + cpu->arch, cpus[i]->arch); + goto error; + } + + if (STRNEQ(cpu->model, cpus[i]->model)) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU models don't match: '%s' != '%s'"), + cpu->model, cpus[i]->model); + goto error; + } + + if (!(hash = genericHashFeatures(cpus[i]))) + goto no_memory; + + for (j = 0; j < nfeatures; j++) { + if (features[j].name && + !virHashLookup(hash, features[j].name)) { + features[j].name = NULL; + count--; + } + } + + virHashFree(hash, NULL); + } + + if (VIR_ALLOC_N(cpu->features, count) < 0) + goto no_memory; + cpu->nfeatures = count; + + j = 0; + for (i = 0; i < nfeatures; i++) { + if (!features[i].name) + continue; + + if (!(cpu->features[j++].name = strdup(features[i].name))) + goto no_memory; + } + +cleanup: + VIR_FREE(features); + + return cpu; + +no_memory: + virReportOOMError(); +error: + virCPUDefFree(cpu); + cpu = NULL; + goto cleanup; +} + + struct cpuArchDriver cpuDriverGeneric = { .name = "generic", .arch = NULL, @@ -119,5 +218,5 @@ struct cpuArchDriver cpuDriverGeneric = { .free = NULL, .nodeData = NULL, .guestData = NULL, - .baseline = NULL, + .baseline = genericBaseline, }; -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:52PM +0100, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_generic.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 101 insertions(+), 2 deletions(-)
[...]
+ if (!found) { + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model '%s' is not support by hypervisor"), + cpus[0]->model);
that's where the previous patch to po/POTFILES.in came from :-) ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_x86.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 86 insertions(+), 1 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index a6db86d..2194c32 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -137,6 +137,17 @@ x86cpuidClearBits(struct cpuX86cpuid *cpuid, } +static inline void +x86cpuidAndBits(struct cpuX86cpuid *cpuid, + const struct cpuX86cpuid *mask) +{ + cpuid->eax &= mask->eax; + cpuid->ebx &= mask->ebx; + cpuid->ecx &= mask->ecx; + cpuid->edx &= mask->edx; +} + + static struct cpuX86cpuid * x86DataCpuid(const union cpuData *data, uint32_t function) @@ -477,6 +488,27 @@ x86ModelSubtract(struct x86_model *model1, } +static void +x86ModelIntersect(struct x86_model *model1, + const struct x86_model *model2) +{ + int i; + struct cpuX86cpuid *cpuid; + + for (i = 0; i < model1->ncpuid; i++) { + struct cpuX86cpuid *intersection = model1->cpuid + i; + + cpuid = x86cpuidFind(model2->cpuid, + model2->ncpuid, + intersection->function); + if (cpuid != NULL) + x86cpuidAndBits(intersection, cpuid); + else + x86cpuidClearBits(intersection, intersection); + } +} + + static int x86ModelAdd(struct x86_model *model1, const struct x86_model *model2) @@ -1192,6 +1224,59 @@ error: #endif +static virCPUDefPtr +x86Baseline(virCPUDefPtr *cpus, + unsigned int ncpus, + const char **models, + unsigned int nmodels) +{ + struct x86_map *map = NULL; + struct x86_model *base_model = NULL; + union cpuData *data = NULL; + virCPUDefPtr cpu = NULL; + unsigned int i; + + if (!(map = x86LoadMap())) + goto error; + + if (!(base_model = x86ModelFromCPU(cpus[0], map, 0))) + goto error; + + if (VIR_ALLOC(cpu) < 0 || + !(cpu->arch = strdup(cpus[0]->arch))) + goto no_memory; + + for (i = 1; i < ncpus; i++) { + struct x86_model *model; + if (!(model = x86ModelFromCPU(cpus[i], map, 0))) + goto error; + + x86ModelIntersect(base_model, model); + x86ModelFree(model); + } + + if (!(data = x86DataFromModel(base_model))) + goto no_memory; + + if (x86Decode(cpu, data, models, nmodels) < 0) + goto error; + +cleanup: + x86DataFree(data); + x86ModelFree(base_model); + x86MapFree(map); + + return cpu; + +no_memory: + virReportOOMError(); +error: + virCPUDefFree(cpu); + cpu = NULL; + goto cleanup; +} + + struct cpuArchDriver cpuDriverX86 = { .name = "x86", .arch = archs, @@ -1206,5 +1291,5 @@ struct cpuArchDriver cpuDriverX86 = { .nodeData = NULL, #endif .guestData = x86GuestData, - .baseline = NULL, + .baseline = x86Baseline, }; -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:53PM +0100, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_x86.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 86 insertions(+), 1 deletions(-)
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index a6db86d..2194c32 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -137,6 +137,17 @@ x86cpuidClearBits(struct cpuX86cpuid *cpuid, }
+static inline void +x86cpuidAndBits(struct cpuX86cpuid *cpuid, + const struct cpuX86cpuid *mask) +{ + cpuid->eax &= mask->eax; + cpuid->ebx &= mask->ebx; + cpuid->ecx &= mask->ecx; + cpuid->edx &= mask->edx; +} +
Minor point ... Why forcing to inline and hence inflate code size and confuse debuggers ? That doesn't sound a time critical operation, isn't it ? True for other inlined functions in that module though ... ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt.h.in | 18 +++++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 7 +++++ python/libvirt-override.c | 52 +++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 79 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 99a5c45..260505e 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1769,6 +1769,24 @@ int virConnectCompareCPU(virConnectPtr conn, unsigned int flags); +/** + * virConnectBaselineCPU: + * + * @conn: virConnect connection + * @ncpus: number of CPUs in xmlCPUs + * @xmlCPUs: array of XML descriptions of host CPUs + * @flags: fine-tuning flags + * + * Computes the most feature-rich CPU which is compatible with all given + * host CPUs. + * + * Returns XML description of the computed CPU or NULL on error. + */ +char *virConnectBaselineCPU(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index 4182219..37c0169 100755 --- a/python/generator.py +++ b/python/generator.py @@ -308,6 +308,7 @@ skip_impl = ( 'virEventRegisterImpl', 'virNodeListDevices', 'virNodeDeviceListCaps', + 'virConnectBaselineCPU', ) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 3d8f46c..76a6fd5 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -231,5 +231,12 @@ <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> <return type='str *' info='the list of Names of None in case of error'/> </function> + <function name='virConnectBaselineCPU' file='python'> + <info>Computes the most feature-rich CPU which is compatible with all given host CPUs.</info> + <return type='char *' info='XML description of the computed CPU or NULL on error.'/> + <arg name='conn' type='virConnectPtr' info='virConnect connection'/> + <arg name='xmlCPUs' type='const char **' info='array of XML descriptions of host CPUs'/> + <arg name='flags' type='unsigned int' info='fine-tuning flags, currently unused, pass 0.'/> + </function> </symbols> </api> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index d90a763..a71766a 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -2019,6 +2019,57 @@ libvirt_virConnectListDefinedInterfaces(PyObject *self ATTRIBUTE_UNUSED, return(py_retval); } + +static PyObject * +libvirt_virConnectBaselineCPU(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *pyobj_conn; + PyObject *list; + virConnectPtr conn; + unsigned int flags; + const char **xmlcpus = NULL; + int ncpus = 0; + char *base_cpu; + PyObject *pybase_cpu; + + if (!PyArg_ParseTuple(args, (char *)"OOi:virConnectBaselineCPU", + &pyobj_conn, &list, &flags)) + return(NULL); + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + if (PyList_Check(list)) { + int i; + + ncpus = PyList_Size(list); + if ((xmlcpus = malloc(ncpus * sizeof(*xmlcpus))) == NULL) + return VIR_PY_INT_FAIL; + + for (i = 0; i < ncpus; i++) { + xmlcpus[i] = PyString_AsString(PyList_GetItem(list, i)); + if (xmlcpus[i] == NULL) + return VIR_PY_INT_FAIL; + } + } + + LIBVIRT_BEGIN_ALLOW_THREADS; + base_cpu = virConnectBaselineCPU(conn, xmlcpus, ncpus, flags); + LIBVIRT_END_ALLOW_THREADS; + + free(xmlcpus); + + if (base_cpu == NULL) + return VIR_PY_INT_FAIL; + + pybase_cpu = PyString_FromString(base_cpu); + free(base_cpu); + + if (pybase_cpu == NULL) + return VIR_PY_INT_FAIL; + + return pybase_cpu; +} + + /******************************************* * Helper functions to avoid importing modules * for every callback @@ -2734,6 +2785,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virSecretSetValue", libvirt_virSecretSetValue, METH_VARARGS, NULL}, {(char *) "virConnectListInterfaces", libvirt_virConnectListInterfaces, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedInterfaces", libvirt_virConnectListDefinedInterfaces, METH_VARARGS, NULL}, + {(char *) "virConnectBaselineCPU", libvirt_virConnectBaselineCPU, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index aa062e4..152aae4 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -353,6 +353,7 @@ LIBVIRT_0.7.7 { global: virDomainAttachDeviceFlags; virDomainDetachDeviceFlags; + virConnectBaselineCPU; } LIBVIRT_0.7.5; # .... define new API here using predicted next version number .... -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:54PM +0100, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- include/libvirt/libvirt.h.in | 18 +++++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 7 +++++ python/libvirt-override.c | 52 +++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 5 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 99a5c45..260505e 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1769,6 +1769,24 @@ int virConnectCompareCPU(virConnectPtr conn, unsigned int flags);
+/** + * virConnectBaselineCPU: + * + * @conn: virConnect connection + * @ncpus: number of CPUs in xmlCPUs + * @xmlCPUs: array of XML descriptions of host CPUs + * @flags: fine-tuning flags + * + * Computes the most feature-rich CPU which is compatible with all given + * host CPUs. + * + * Returns XML description of the computed CPU or NULL on error. + */ +char *virConnectBaselineCPU(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index 4182219..37c0169 100755 --- a/python/generator.py +++ b/python/generator.py @@ -308,6 +308,7 @@ skip_impl = ( 'virEventRegisterImpl', 'virNodeListDevices', 'virNodeDeviceListCaps', + 'virConnectBaselineCPU', )
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 3d8f46c..76a6fd5 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -231,5 +231,12 @@ <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> <return type='str *' info='the list of Names of None in case of error'/> </function> + <function name='virConnectBaselineCPU' file='python'> + <info>Computes the most feature-rich CPU which is compatible with all given host CPUs.</info> + <return type='char *' info='XML description of the computed CPU or NULL on error.'/> + <arg name='conn' type='virConnectPtr' info='virConnect connection'/> + <arg name='xmlCPUs' type='const char **' info='array of XML descriptions of host CPUs'/> + <arg name='flags' type='unsigned int' info='fine-tuning flags, currently unused, pass 0.'/> + </function> </symbols> </api> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index d90a763..a71766a 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -2019,6 +2019,57 @@ libvirt_virConnectListDefinedInterfaces(PyObject *self ATTRIBUTE_UNUSED, return(py_retval); }
+ +static PyObject * +libvirt_virConnectBaselineCPU(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) { + PyObject *pyobj_conn; + PyObject *list; + virConnectPtr conn; + unsigned int flags; + const char **xmlcpus = NULL; + int ncpus = 0; + char *base_cpu; + PyObject *pybase_cpu; + + if (!PyArg_ParseTuple(args, (char *)"OOi:virConnectBaselineCPU", + &pyobj_conn, &list, &flags)) + return(NULL); + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + if (PyList_Check(list)) { + int i; + + ncpus = PyList_Size(list); + if ((xmlcpus = malloc(ncpus * sizeof(*xmlcpus))) == NULL) + return VIR_PY_INT_FAIL; + + for (i = 0; i < ncpus; i++) { + xmlcpus[i] = PyString_AsString(PyList_GetItem(list, i)); + if (xmlcpus[i] == NULL) + return VIR_PY_INT_FAIL; + } + } + + LIBVIRT_BEGIN_ALLOW_THREADS; + base_cpu = virConnectBaselineCPU(conn, xmlcpus, ncpus, flags); + LIBVIRT_END_ALLOW_THREADS; + + free(xmlcpus); + + if (base_cpu == NULL) + return VIR_PY_INT_FAIL; + + pybase_cpu = PyString_FromString(base_cpu); + free(base_cpu); + + if (pybase_cpu == NULL) + return VIR_PY_INT_FAIL; + + return pybase_cpu; +} + + /******************************************* * Helper functions to avoid importing modules * for every callback @@ -2734,6 +2785,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virSecretSetValue", libvirt_virSecretSetValue, METH_VARARGS, NULL}, {(char *) "virConnectListInterfaces", libvirt_virConnectListInterfaces, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedInterfaces", libvirt_virConnectListDefinedInterfaces, METH_VARARGS, NULL}, + {(char *) "virConnectBaselineCPU", libvirt_virConnectBaselineCPU, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} };
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index aa062e4..152aae4 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -353,6 +353,7 @@ LIBVIRT_0.7.7 { global: virDomainAttachDeviceFlags; virDomainDetachDeviceFlags; + virConnectBaselineCPU; } LIBVIRT_0.7.5;
# .... define new API here using predicted next version number ....
Looks fine though maybe a bit complex, it's the first time we add an API taking a list of XML instances. But I guess with the expected use case that's not a bad choice, we will gather the XML from the set of nodes in the cluster. ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/driver.h | 6 ++++++ src/esx/esx_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/opennebula/one_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/xen/xen_driver.c | 1 + 12 files changed, 17 insertions(+), 0 deletions(-) diff --git a/src/driver.h b/src/driver.h index 08fe816..fe21ea3 100644 --- a/src/driver.h +++ b/src/driver.h @@ -367,6 +367,11 @@ typedef int (*virDrvCPUCompare)(virConnectPtr conn, const char *cpu, unsigned int flags); +typedef char * + (*virDrvCPUBaseline)(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags); /** * _virDriver: @@ -458,6 +463,7 @@ struct _virDriver { virDrvDomainIsActive domainIsActive; virDrvDomainIsPersistent domainIsPersistent; virDrvCPUCompare cpuCompare; + virDrvCPUBaseline cpuBaseline; }; typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 535ec43..e125a09 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -3403,6 +3403,7 @@ static virDriver esxDriver = { esxDomainIsActive, /* domainIsActive */ esxDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 1a73ca6..679e936 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2449,6 +2449,7 @@ static virDriver lxcDriver = { lxcDomainIsActive, lxcDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; static virStateDriver lxcStateDriver = { diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c index b41c418..57825d5 100644 --- a/src/opennebula/one_driver.c +++ b/src/opennebula/one_driver.c @@ -785,6 +785,7 @@ static virDriver oneDriver = { NULL, /* domainIsActive */ NULL, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; static virStateDriver oneStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 5c07857..68d0398 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1537,6 +1537,7 @@ static virDriver openvzDriver = { openvzDomainIsActive, openvzDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index eef1cc7..1e8ed30 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -1653,6 +1653,7 @@ virDriver phypDriver = { NULL, /* domainIsActive */ NULL, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; int diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0d77d57..e053be8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8577,6 +8577,7 @@ static virDriver qemuDriver = { qemuDomainIsActive, qemuDomainIsPersistent, qemuCPUCompare, /* cpuCompare */ + NULL, /* cpuBaseline */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index e17db3d..05dea04 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8977,6 +8977,7 @@ static virDriver remote_driver = { remoteDomainIsActive, /* domainIsActive */ remoteDomainIsPersistent, /* domainIsPersistent */ remoteCPUCompare, /* cpuCompare */ + NULL, /* cpuBaseline */ }; static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index a17217a..4c2bf05 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5241,6 +5241,7 @@ static virDriver testDriver = { testDomainIsActive, /* domainIsActive */ testDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 541ff9a..5049c92 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1916,6 +1916,7 @@ static virDriver umlDriver = { umlDomainIsActive, umlDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 0965021..68dffd2 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -7060,6 +7060,7 @@ virDriver NAME(Driver) = { vboxDomainIsActive, vboxDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index d5a0d00..700682c 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -1903,6 +1903,7 @@ static virDriver xenUnifiedDriver = { xenUnifiedDomainIsActive, xenUnifiedDomainisPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ }; /** -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:55PM +0100, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/driver.h | 6 ++++++ src/esx/esx_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/opennebula/one_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/xen/xen_driver.c | 1 + 12 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/src/driver.h b/src/driver.h index 08fe816..fe21ea3 100644 --- a/src/driver.h +++ b/src/driver.h @@ -367,6 +367,11 @@ typedef int (*virDrvCPUCompare)(virConnectPtr conn, const char *cpu, unsigned int flags); +typedef char * + (*virDrvCPUBaseline)(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags);
/** * _virDriver: @@ -458,6 +463,7 @@ struct _virDriver { virDrvDomainIsActive domainIsActive; virDrvDomainIsPersistent domainIsPersistent; virDrvCPUCompare cpuCompare; + virDrvCPUBaseline cpuBaseline; };
typedef int diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 535ec43..e125a09 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -3403,6 +3403,7 @@ static virDriver esxDriver = { esxDomainIsActive, /* domainIsActive */ esxDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 1a73ca6..679e936 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2449,6 +2449,7 @@ static virDriver lxcDriver = { lxcDomainIsActive, lxcDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
static virStateDriver lxcStateDriver = { diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c index b41c418..57825d5 100644 --- a/src/opennebula/one_driver.c +++ b/src/opennebula/one_driver.c @@ -785,6 +785,7 @@ static virDriver oneDriver = { NULL, /* domainIsActive */ NULL, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
static virStateDriver oneStateDriver = { diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 5c07857..68d0398 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1537,6 +1537,7 @@ static virDriver openvzDriver = { openvzDomainIsActive, openvzDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
int openvzRegister(void) { diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index eef1cc7..1e8ed30 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -1653,6 +1653,7 @@ virDriver phypDriver = { NULL, /* domainIsActive */ NULL, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
int diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0d77d57..e053be8 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8577,6 +8577,7 @@ static virDriver qemuDriver = { qemuDomainIsActive, qemuDomainIsPersistent, qemuCPUCompare, /* cpuCompare */ + NULL, /* cpuBaseline */ };
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index e17db3d..05dea04 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8977,6 +8977,7 @@ static virDriver remote_driver = { remoteDomainIsActive, /* domainIsActive */ remoteDomainIsPersistent, /* domainIsPersistent */ remoteCPUCompare, /* cpuCompare */ + NULL, /* cpuBaseline */ };
static virNetworkDriver network_driver = { diff --git a/src/test/test_driver.c b/src/test/test_driver.c index a17217a..4c2bf05 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5241,6 +5241,7 @@ static virDriver testDriver = { testDomainIsActive, /* domainIsActive */ testDomainIsPersistent, /* domainIsPersistent */ NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
static virNetworkDriver testNetworkDriver = { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 541ff9a..5049c92 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1916,6 +1916,7 @@ static virDriver umlDriver = { umlDomainIsActive, umlDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 0965021..68dffd2 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -7060,6 +7060,7 @@ virDriver NAME(Driver) = { vboxDomainIsActive, vboxDomainIsPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
virNetworkDriver NAME(NetworkDriver) = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index d5a0d00..700682c 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -1903,6 +1903,7 @@ static virDriver xenUnifiedDriver = { xenUnifiedDomainIsActive, xenUnifiedDomainisPersistent, NULL, /* cpuCompare */ + NULL, /* cpuBaseline */ };
/**
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/libvirt.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 57 insertions(+), 0 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index f9ff881..0c3271c 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11090,3 +11090,60 @@ error: virDispatchError(conn); return VIR_CPU_COMPARE_ERROR; } + + +/** + * virConnectBaselineCPU: + * + * @conn: virConnect connection + * @xmlCPUs: array of XML descriptions of host CPUs + * @ncpus: number of CPUs in xmlCPUs + * @flags: fine-tuning flags, currently unused, pass 0. + * + * Computes the most feature-rich CPU which is compatible with all given + * host CPUs. + * + * Returns XML description of the computed CPU or NULL on error. + */ +char * +virConnectBaselineCPU(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + unsigned int i; + + VIR_DEBUG("conn=%p, xmlCPUs=%p, ncpus=%u, flags=%u", + conn, xmlCPUs, ncpus, flags); + if (xmlCPUs) { + for (i = 0; i < ncpus; i++) + VIR_DEBUG("xmlCPUs[%u]=%s", i, xmlCPUs[i]); + } + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return NULL; + } + if (xmlCPUs == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->driver->cpuBaseline) { + char *cpu; + + cpu = conn->driver->cpuBaseline(conn, xmlCPUs, ncpus, flags); + if (!cpu) + goto error; + return cpu; + } + + virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return NULL; +} -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:56PM +0100, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/libvirt.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c index f9ff881..0c3271c 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11090,3 +11090,60 @@ error: virDispatchError(conn); return VIR_CPU_COMPARE_ERROR; } + + +/** + * virConnectBaselineCPU: + * + * @conn: virConnect connection + * @xmlCPUs: array of XML descriptions of host CPUs + * @ncpus: number of CPUs in xmlCPUs + * @flags: fine-tuning flags, currently unused, pass 0. + * + * Computes the most feature-rich CPU which is compatible with all given + * host CPUs. + * + * Returns XML description of the computed CPU or NULL on error. + */ +char * +virConnectBaselineCPU(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + unsigned int i; + + VIR_DEBUG("conn=%p, xmlCPUs=%p, ncpus=%u, flags=%u", + conn, xmlCPUs, ncpus, flags); + if (xmlCPUs) { + for (i = 0; i < ncpus; i++) + VIR_DEBUG("xmlCPUs[%u]=%s", i, xmlCPUs[i]);
Hum ... what if xmlCPUs[i] == NULL ... we should not crash there maybe this should be tested and that loop being done after VIR_IS_CONNECT(conn) check and xmlCPUs == NULL check
+ } + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return NULL; + } + if (xmlCPUs == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + if (conn->driver->cpuBaseline) { + char *cpu; + + cpu = conn->driver->cpuBaseline(conn, xmlCPUs, ncpus, flags); + if (!cpu) + goto error; + return cpu; + } + + virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return NULL; +}
ACK once the potential crash on entry is fixed. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

+char * +virConnectBaselineCPU(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + unsigned int i; + + VIR_DEBUG("conn=%p, xmlCPUs=%p, ncpus=%u, flags=%u", + conn, xmlCPUs, ncpus, flags); + if (xmlCPUs) { + for (i = 0; i < ncpus; i++) + VIR_DEBUG("xmlCPUs[%u]=%s", i, xmlCPUs[i]);
Hum ... what if xmlCPUs[i] == NULL ... we should not crash there maybe this should be tested and that loop being done after VIR_IS_CONNECT(conn) check and xmlCPUs == NULL check
I think it's better to keep it just after the first debug print as the purpose of this loop is to print detailed data about arguments passed to virConnectBaselineCPU(). However, we shouldn't really crash there. I think xmlCPUs[i] ? xmlCPUs[i] : "(null)" or just printing only non-NULL strings is sufficient. Jirka

On 02/11/2010 02:20 PM, Jiri Denemark wrote:
+char * +virConnectBaselineCPU(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + unsigned int i; + + VIR_DEBUG("conn=%p, xmlCPUs=%p, ncpus=%u, flags=%u", + conn, xmlCPUs, ncpus, flags); + if (xmlCPUs) { + for (i = 0; i < ncpus; i++) + VIR_DEBUG("xmlCPUs[%u]=%s", i, xmlCPUs[i]);
Hum ... what if xmlCPUs[i] == NULL ... we should not crash there maybe this should be tested and that loop being done after VIR_IS_CONNECT(conn) check and xmlCPUs == NULL check
I think it's better to keep it just after the first debug print as the purpose of this loop is to print detailed data about arguments passed to virConnectBaselineCPU(). However, we shouldn't really crash there. I think
xmlCPUs[i] ? xmlCPUs[i] : "(null)"
Well, in Linux, printf("%s", NULL) is generally safe (it prints "(null"). However, that is not portable, so there is a wrapper or something in the libvirt code that does "safe" printing of NULL pointers. I can't quite remember exactly what it's called, but take a look around. -- Chris Lalancette

I think it's better to keep it just after the first debug print as the purpose of this loop is to print detailed data about arguments passed to virConnectBaselineCPU(). However, we shouldn't really crash there. I think
xmlCPUs[i] ? xmlCPUs[i] : "(null)"
Well, in Linux, printf("%s", NULL) is generally safe (it prints "(null"). However, that is not portable, so there is a wrapper or something in the libvirt code that does "safe" printing of NULL pointers. I can't quite remember exactly what it's called, but take a look around.
Thanks for the hint, it's NULLSTR(s) macro in internal.h, I'll use that. Jirka

On Thu, Feb 11, 2010 at 08:20:29PM +0100, Jiri Denemark wrote:
+char * +virConnectBaselineCPU(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + unsigned int i; + + VIR_DEBUG("conn=%p, xmlCPUs=%p, ncpus=%u, flags=%u", + conn, xmlCPUs, ncpus, flags); + if (xmlCPUs) { + for (i = 0; i < ncpus; i++) + VIR_DEBUG("xmlCPUs[%u]=%s", i, xmlCPUs[i]);
Hum ... what if xmlCPUs[i] == NULL ... we should not crash there maybe this should be tested and that loop being done after VIR_IS_CONNECT(conn) check and xmlCPUs == NULL check
I think it's better to keep it just after the first debug print as the purpose of this loop is to print detailed data about arguments passed to virConnectBaselineCPU(). However, we shouldn't really crash there. I think
xmlCPUs[i] ? xmlCPUs[i] : "(null)"
or just printing only non-NULL strings is sufficient.
either is fine, no specific opinion :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- daemon/remote.c | 25 +++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_ret.h | 1 + daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_protocol.c | 22 ++++++++++++++++++++++ src/remote/remote_protocol.h | 20 ++++++++++++++++++++ src/remote/remote_protocol.x | 18 +++++++++++++++++- 8 files changed, 99 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index ba3c670..eacc6f9 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5365,6 +5365,31 @@ remoteDispatchCpuCompare(struct qemud_server *server ATTRIBUTE_UNUSED, } +static int +remoteDispatchCpuBaseline(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *err, + remote_cpu_baseline_args *args, + remote_cpu_baseline_ret *ret) +{ + char *cpu; + + cpu = virConnectBaselineCPU(conn, + (const char **) args->xmlCPUs.xmlCPUs_val, + args->xmlCPUs.xmlCPUs_len, + args->flags); + if (cpu == NULL) { + remoteDispatchConnError(err, conn); + return -1; + } + + ret->cpu = cpu; + return 0; +} + + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index c098c8e..86a881e 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -137,3 +137,4 @@ remote_domain_memory_stats_args val_remote_domain_memory_stats_args; remote_domain_attach_device_flags_args val_remote_domain_attach_device_flags_args; remote_domain_detach_device_flags_args val_remote_domain_detach_device_flags_args; + remote_cpu_baseline_args val_remote_cpu_baseline_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index 4b6bd4c..be67f9a 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -50,6 +50,14 @@ static int remoteDispatchClose( remote_error *err, void *args, void *ret); +static int remoteDispatchCpuBaseline( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_cpu_baseline_args *args, + remote_cpu_baseline_ret *ret); static int remoteDispatchCpuCompare( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_ret.h b/daemon/remote_dispatch_ret.h index d7811de..5c6a78f 100644 --- a/daemon/remote_dispatch_ret.h +++ b/daemon/remote_dispatch_ret.h @@ -117,3 +117,4 @@ remote_get_lib_version_ret val_remote_get_lib_version_ret; remote_cpu_compare_ret val_remote_cpu_compare_ret; remote_domain_memory_stats_ret val_remote_domain_memory_stats_ret; + remote_cpu_baseline_ret val_remote_cpu_baseline_ret; diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index 89719f6..428057a 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -812,3 +812,8 @@ .args_filter = (xdrproc_t) xdr_remote_domain_detach_device_flags_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* CpuBaseline => 162 */ + .fn = (dispatch_fn) remoteDispatchCpuBaseline, + .args_filter = (xdrproc_t) xdr_remote_cpu_baseline_args, + .ret_filter = (xdrproc_t) xdr_remote_cpu_baseline_ret, +}, diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 90ecf09..164eca5 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -2938,6 +2938,28 @@ xdr_remote_cpu_compare_ret (XDR *xdrs, remote_cpu_compare_ret *objp) } bool_t +xdr_remote_cpu_baseline_args (XDR *xdrs, remote_cpu_baseline_args *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->xmlCPUs.xmlCPUs_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->xmlCPUs.xmlCPUs_len, REMOTE_CPU_BASELINE_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_cpu_baseline_ret (XDR *xdrs, remote_cpu_baseline_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->cpu)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index db574a8..0344077 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -48,6 +48,7 @@ typedef remote_nonnull_string *remote_string; #define REMOTE_SECURITY_DOI_MAX VIR_SECURITY_DOI_BUFLEN #define REMOTE_SECRET_VALUE_MAX 65536 #define REMOTE_SECRET_UUID_LIST_MAX 16384 +#define REMOTE_CPU_BASELINE_MAX 256 typedef char remote_uuid[VIR_UUID_BUFLEN]; @@ -1663,6 +1664,20 @@ struct remote_cpu_compare_ret { int result; }; typedef struct remote_cpu_compare_ret remote_cpu_compare_ret; + +struct remote_cpu_baseline_args { + struct { + u_int xmlCPUs_len; + remote_nonnull_string *xmlCPUs_val; + } xmlCPUs; + u_int flags; +}; +typedef struct remote_cpu_baseline_args remote_cpu_baseline_args; + +struct remote_cpu_baseline_ret { + remote_nonnull_string cpu; +}; +typedef struct remote_cpu_baseline_ret remote_cpu_baseline_ret; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1 @@ -1828,6 +1843,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MEMORY_STATS = 159, REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160, REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, + REMOTE_PROC_CPU_BASELINE = 162, }; typedef enum remote_procedure remote_procedure; @@ -2132,6 +2148,8 @@ extern bool_t xdr_remote_interface_is_active_args (XDR *, remote_interface_is_a extern bool_t xdr_remote_interface_is_active_ret (XDR *, remote_interface_is_active_ret*); extern bool_t xdr_remote_cpu_compare_args (XDR *, remote_cpu_compare_args*); extern bool_t xdr_remote_cpu_compare_ret (XDR *, remote_cpu_compare_ret*); +extern bool_t xdr_remote_cpu_baseline_args (XDR *, remote_cpu_baseline_args*); +extern bool_t xdr_remote_cpu_baseline_ret (XDR *, remote_cpu_baseline_ret*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -2410,6 +2428,8 @@ extern bool_t xdr_remote_interface_is_active_args (); extern bool_t xdr_remote_interface_is_active_ret (); extern bool_t xdr_remote_cpu_compare_args (); extern bool_t xdr_remote_cpu_compare_ret (); +extern bool_t xdr_remote_cpu_baseline_args (); +extern bool_t xdr_remote_cpu_baseline_ret (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 98953a9..432359d 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -155,6 +155,11 @@ const REMOTE_SECRET_VALUE_MAX = 65536; */ const REMOTE_SECRET_UUID_LIST_MAX = 16384; +/* + * Upper limit on list of CPUs accepted when computing a baseline CPU. + */ +const REMOTE_CPU_BASELINE_MAX = 256; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -1473,6 +1478,16 @@ struct remote_cpu_compare_ret { }; +struct remote_cpu_baseline_args { + remote_nonnull_string xmlCPUs<REMOTE_CPU_BASELINE_MAX>; + unsigned flags; +}; + +struct remote_cpu_baseline_ret { + remote_nonnull_string cpu; +}; + + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -1656,7 +1671,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MEMORY_STATS = 159, REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160, - REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161 + REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, + REMOTE_PROC_CPU_BASELINE = 162 /* * Notice how the entries are grouped in sets of 10 ? -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:57PM +0100, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- daemon/remote.c | 25 +++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_ret.h | 1 + daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_protocol.c | 22 ++++++++++++++++++++++ src/remote/remote_protocol.h | 20 ++++++++++++++++++++ src/remote/remote_protocol.x | 18 +++++++++++++++++- 8 files changed, 99 insertions(+), 1 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c index ba3c670..eacc6f9 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5365,6 +5365,31 @@ remoteDispatchCpuCompare(struct qemud_server *server ATTRIBUTE_UNUSED, }
+static int +remoteDispatchCpuBaseline(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *err, + remote_cpu_baseline_args *args, + remote_cpu_baseline_ret *ret) +{ + char *cpu; + + cpu = virConnectBaselineCPU(conn, + (const char **) args->xmlCPUs.xmlCPUs_val, + args->xmlCPUs.xmlCPUs_len, + args->flags); + if (cpu == NULL) { + remoteDispatchConnError(err, conn); + return -1; + } + + ret->cpu = cpu; + return 0; +} + + /*----- Helpers. -----*/
/* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index c098c8e..86a881e 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -137,3 +137,4 @@ remote_domain_memory_stats_args val_remote_domain_memory_stats_args; remote_domain_attach_device_flags_args val_remote_domain_attach_device_flags_args; remote_domain_detach_device_flags_args val_remote_domain_detach_device_flags_args; + remote_cpu_baseline_args val_remote_cpu_baseline_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index 4b6bd4c..be67f9a 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -50,6 +50,14 @@ static int remoteDispatchClose( remote_error *err, void *args, void *ret); +static int remoteDispatchCpuBaseline( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_cpu_baseline_args *args, + remote_cpu_baseline_ret *ret); static int remoteDispatchCpuCompare( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_ret.h b/daemon/remote_dispatch_ret.h index d7811de..5c6a78f 100644 --- a/daemon/remote_dispatch_ret.h +++ b/daemon/remote_dispatch_ret.h @@ -117,3 +117,4 @@ remote_get_lib_version_ret val_remote_get_lib_version_ret; remote_cpu_compare_ret val_remote_cpu_compare_ret; remote_domain_memory_stats_ret val_remote_domain_memory_stats_ret; + remote_cpu_baseline_ret val_remote_cpu_baseline_ret; diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index 89719f6..428057a 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -812,3 +812,8 @@ .args_filter = (xdrproc_t) xdr_remote_domain_detach_device_flags_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* CpuBaseline => 162 */ + .fn = (dispatch_fn) remoteDispatchCpuBaseline, + .args_filter = (xdrproc_t) xdr_remote_cpu_baseline_args, + .ret_filter = (xdrproc_t) xdr_remote_cpu_baseline_ret, +}, diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 90ecf09..164eca5 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -2938,6 +2938,28 @@ xdr_remote_cpu_compare_ret (XDR *xdrs, remote_cpu_compare_ret *objp) }
bool_t +xdr_remote_cpu_baseline_args (XDR *xdrs, remote_cpu_baseline_args *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->xmlCPUs.xmlCPUs_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->xmlCPUs.xmlCPUs_len, REMOTE_CPU_BASELINE_MAX, + sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_cpu_baseline_ret (XDR *xdrs, remote_cpu_baseline_ret *objp) +{ + + if (!xdr_remote_nonnull_string (xdrs, &objp->cpu)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) {
diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index db574a8..0344077 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -48,6 +48,7 @@ typedef remote_nonnull_string *remote_string; #define REMOTE_SECURITY_DOI_MAX VIR_SECURITY_DOI_BUFLEN #define REMOTE_SECRET_VALUE_MAX 65536 #define REMOTE_SECRET_UUID_LIST_MAX 16384 +#define REMOTE_CPU_BASELINE_MAX 256
typedef char remote_uuid[VIR_UUID_BUFLEN];
@@ -1663,6 +1664,20 @@ struct remote_cpu_compare_ret { int result; }; typedef struct remote_cpu_compare_ret remote_cpu_compare_ret; + +struct remote_cpu_baseline_args { + struct { + u_int xmlCPUs_len; + remote_nonnull_string *xmlCPUs_val; + } xmlCPUs; + u_int flags; +}; +typedef struct remote_cpu_baseline_args remote_cpu_baseline_args; + +struct remote_cpu_baseline_ret { + remote_nonnull_string cpu; +}; +typedef struct remote_cpu_baseline_ret remote_cpu_baseline_ret; #define REMOTE_PROGRAM 0x20008086 #define REMOTE_PROTOCOL_VERSION 1
@@ -1828,6 +1843,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MEMORY_STATS = 159, REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160, REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, + REMOTE_PROC_CPU_BASELINE = 162, }; typedef enum remote_procedure remote_procedure;
@@ -2132,6 +2148,8 @@ extern bool_t xdr_remote_interface_is_active_args (XDR *, remote_interface_is_a extern bool_t xdr_remote_interface_is_active_ret (XDR *, remote_interface_is_active_ret*); extern bool_t xdr_remote_cpu_compare_args (XDR *, remote_cpu_compare_args*); extern bool_t xdr_remote_cpu_compare_ret (XDR *, remote_cpu_compare_ret*); +extern bool_t xdr_remote_cpu_baseline_args (XDR *, remote_cpu_baseline_args*); +extern bool_t xdr_remote_cpu_baseline_ret (XDR *, remote_cpu_baseline_ret*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); @@ -2410,6 +2428,8 @@ extern bool_t xdr_remote_interface_is_active_args (); extern bool_t xdr_remote_interface_is_active_ret (); extern bool_t xdr_remote_cpu_compare_args (); extern bool_t xdr_remote_cpu_compare_ret (); +extern bool_t xdr_remote_cpu_baseline_args (); +extern bool_t xdr_remote_cpu_baseline_ret (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 98953a9..432359d 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -155,6 +155,11 @@ const REMOTE_SECRET_VALUE_MAX = 65536; */ const REMOTE_SECRET_UUID_LIST_MAX = 16384;
+/* + * Upper limit on list of CPUs accepted when computing a baseline CPU. + */ +const REMOTE_CPU_BASELINE_MAX = 256; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN];
@@ -1473,6 +1478,16 @@ struct remote_cpu_compare_ret { };
+struct remote_cpu_baseline_args { + remote_nonnull_string xmlCPUs<REMOTE_CPU_BASELINE_MAX>; + unsigned flags; +}; + +struct remote_cpu_baseline_ret { + remote_nonnull_string cpu; +}; + + /*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */ @@ -1656,7 +1671,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MEMORY_STATS = 159, REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160,
- REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161 + REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, + REMOTE_PROC_CPU_BASELINE = 162
/* * Notice how the entries are grouped in sets of 10 ?
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 15 ++++++++++++++- src/remote/remote_driver.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e053be8..2a07a30 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8499,6 +8499,19 @@ qemuCPUCompare(virConnectPtr conn, return ret; } +static char * +qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags ATTRIBUTE_UNUSED) +{ + char *cpu; + + cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0); + + return cpu; +} + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -8577,7 +8590,7 @@ static virDriver qemuDriver = { qemuDomainIsActive, qemuDomainIsPersistent, qemuCPUCompare, /* cpuCompare */ - NULL, /* cpuBaseline */ + qemuCPUBaseline, /* cpuBaseline */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 05dea04..5dda414 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7587,6 +7587,37 @@ done: return rv; } + +static char * +remoteCPUBaseline(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + struct private_data *priv = conn->privateData; + remote_cpu_baseline_args args; + remote_cpu_baseline_ret ret; + char *cpu = NULL; + + remoteDriverLock(priv); + + args.xmlCPUs.xmlCPUs_len = ncpus; + args.xmlCPUs.xmlCPUs_val = (char **) xmlCPUs; + args.flags = flags; + + memset(&ret, 0, sizeof (ret)); + if (call(conn, priv, 0, REMOTE_PROC_CPU_BASELINE, + (xdrproc_t) xdr_remote_cpu_baseline_args, (char *) &args, + (xdrproc_t) xdr_remote_cpu_baseline_ret, (char *) &ret) == -1) + goto done; + + cpu = ret.cpu; + +done: + remoteDriverUnlock(priv); + return cpu; +} + /*----------------------------------------------------------------------*/ @@ -8977,7 +9008,7 @@ static virDriver remote_driver = { remoteDomainIsActive, /* domainIsActive */ remoteDomainIsPersistent, /* domainIsPersistent */ remoteCPUCompare, /* cpuCompare */ - NULL, /* cpuBaseline */ + remoteCPUBaseline, /* cpuBaseline */ }; static virNetworkDriver network_driver = { -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:58PM +0100, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_driver.c | 15 ++++++++++++++- src/remote/remote_driver.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e053be8..2a07a30 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8499,6 +8499,19 @@ qemuCPUCompare(virConnectPtr conn, return ret; }
+static char * +qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags ATTRIBUTE_UNUSED) +{ + char *cpu; + + cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0); + + return cpu; +} + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -8577,7 +8590,7 @@ static virDriver qemuDriver = { qemuDomainIsActive, qemuDomainIsPersistent, qemuCPUCompare, /* cpuCompare */ - NULL, /* cpuBaseline */ + qemuCPUBaseline, /* cpuBaseline */ };
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 05dea04..5dda414 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7587,6 +7587,37 @@ done: return rv; }
+ +static char * +remoteCPUBaseline(virConnectPtr conn, + const char **xmlCPUs, + unsigned int ncpus, + unsigned int flags) +{ + struct private_data *priv = conn->privateData; + remote_cpu_baseline_args args; + remote_cpu_baseline_ret ret; + char *cpu = NULL; + + remoteDriverLock(priv); + + args.xmlCPUs.xmlCPUs_len = ncpus; + args.xmlCPUs.xmlCPUs_val = (char **) xmlCPUs; + args.flags = flags; + + memset(&ret, 0, sizeof (ret)); + if (call(conn, priv, 0, REMOTE_PROC_CPU_BASELINE, + (xdrproc_t) xdr_remote_cpu_baseline_args, (char *) &args, + (xdrproc_t) xdr_remote_cpu_baseline_ret, (char *) &ret) == -1) + goto done; + + cpu = ret.cpu; + +done: + remoteDriverUnlock(priv); + return cpu; +} + /*----------------------------------------------------------------------*/
@@ -8977,7 +9008,7 @@ static virDriver remote_driver = { remoteDomainIsActive, /* domainIsActive */ remoteDomainIsPersistent, /* domainIsPersistent */ remoteCPUCompare, /* cpuCompare */ - NULL, /* cpuBaseline */ + remoteCPUBaseline, /* cpuBaseline */ };
static virNetworkDriver network_driver = {
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 8 ++++++ 2 files changed, 80 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 7db48d9..8337477 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -7025,6 +7025,77 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) return ret; } +/* + * "cpu-baseline" command + */ +static const vshCmdInfo info_cpu_baseline[] = { + {"help", gettext_noop("compute baseline CPU")}, + {"desc", gettext_noop("Compute baseline CPU for a set of given CPUs.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_cpu_baseline[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing XML CPU descriptions")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) +{ + char *from; + int found; + int ret = TRUE; + char *buffer; + char *p; + char *result = NULL; + const char **list = NULL; + unsigned int count = 0; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + from = vshCommandOptString(cmd, "file", &found); + if (!found) + return FALSE; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + p = buffer; + while ((p = strstr(p, "<cpu>"))) { + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = p; + + if ((p = strstr(p, "</cpu>"))) { + p += strlen("</cpu>"); + if (*p != '\0') { + *p = '\0'; + p++; + } + } + } + + if (count == 0) { + vshError(ctl, _("No host CPU specified in '%s'"), from); + ret = FALSE; + goto cleanup; + } + + result = virConnectBaselineCPU(ctl->conn, list, count, 0); + + if (result) + vshPrint(ctl, "%s", result); + else + ret = FALSE; + +cleanup: + VIR_FREE(result); + VIR_FREE(list); + VIR_FREE(buffer); + + return ret; +} + /* Common code for the edit / net-edit / pool-edit functions which follow. */ static char * editWriteToTempFile (vshControl *ctl, const char *doc) @@ -7396,6 +7467,7 @@ static const vshCmdDef commands[] = { #ifndef WIN32 {"console", cmdConsole, opts_console, info_console}, #endif + {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline}, {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare}, {"create", cmdCreate, opts_create, info_create}, {"start", cmdStart, opts_start, info_start}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 10f622f..8f6df19 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -213,6 +213,14 @@ crashed. Prints the available amount of memory on the machine or within a NUMA cell if I<cellno> is provided. +=item B<cpu-baseline> I<FILE> + +Compute baseline CPU which will be supported by all host CPUs given in <file>. +The list of host CPUs is built by extracting all <cpu> elements from the +<file>. Thus, the <file> can contain either a set of <cpu> elements separated +by new lines or even a set of complete <capabilities> elements printed by +B<capabilities> command. + =item B<cpu-compare> I<FILE> Compare CPU definition from XML <file> with host CPU. The XML <file> may -- 1.6.6.1

On Thu, Feb 11, 2010 at 04:43:59PM +0100, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tools/virsh.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 8 ++++++ 2 files changed, 80 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index 7db48d9..8337477 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -7025,6 +7025,77 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) return ret; }
+/* + * "cpu-baseline" command + */ +static const vshCmdInfo info_cpu_baseline[] = { + {"help", gettext_noop("compute baseline CPU")}, + {"desc", gettext_noop("Compute baseline CPU for a set of given CPUs.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_cpu_baseline[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing XML CPU descriptions")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) +{ + char *from; + int found; + int ret = TRUE; + char *buffer; + char *p; + char *result = NULL; + const char **list = NULL; + unsigned int count = 0; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + from = vshCommandOptString(cmd, "file", &found); + if (!found) + return FALSE; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + p = buffer; + while ((p = strstr(p, "<cpu>"))) { + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = p; + + if ((p = strstr(p, "</cpu>"))) { + p += strlen("</cpu>"); + if (*p != '\0') { + *p = '\0'; + p++; + } + } + }
Aye aye aye ... I understand what you're trying to do but I think this is a bit weird ... I think we should be able to come with an alternative, cleaner based on parsing the content as an XML well balanced fragment and then reserialize all cpu elements found. Your scheme would explode for example if we tried to add a <cpu> element as one possible child of <cpu> or if we added attributes to <cpu>, it's too fragile. I can think the other parts can be commited independantly anyway.
+ if (count == 0) { + vshError(ctl, _("No host CPU specified in '%s'"), from); + ret = FALSE; + goto cleanup; + } + + result = virConnectBaselineCPU(ctl->conn, list, count, 0); + + if (result) + vshPrint(ctl, "%s", result); + else + ret = FALSE; + +cleanup: + VIR_FREE(result); + VIR_FREE(list); + VIR_FREE(buffer); + + return ret; +} + /* Common code for the edit / net-edit / pool-edit functions which follow. */ static char * editWriteToTempFile (vshControl *ctl, const char *doc) @@ -7396,6 +7467,7 @@ static const vshCmdDef commands[] = { #ifndef WIN32 {"console", cmdConsole, opts_console, info_console}, #endif + {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline}, {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare}, {"create", cmdCreate, opts_create, info_create}, {"start", cmdStart, opts_start, info_start}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 10f622f..8f6df19 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -213,6 +213,14 @@ crashed. Prints the available amount of memory on the machine or within a NUMA cell if I<cellno> is provided.
+=item B<cpu-baseline> I<FILE> + +Compute baseline CPU which will be supported by all host CPUs given in <file>. +The list of host CPUs is built by extracting all <cpu> elements from the +<file>. Thus, the <file> can contain either a set of <cpu> elements separated +by new lines or even a set of complete <capabilities> elements printed by +B<capabilities> command. + =item B<cpu-compare> I<FILE>
Compare CPU definition from XML <file> with host CPU. The XML <file> may -- 1.6.6.1
Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

+ if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + p = buffer; + while ((p = strstr(p, "<cpu>"))) { + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = p; + + if ((p = strstr(p, "</cpu>"))) { + p += strlen("</cpu>"); + if (*p != '\0') { + *p = '\0'; + p++; + } + } + }
Aye aye aye ... I understand what you're trying to do but I think this is a bit weird ... I think we should be able to come with an alternative, cleaner based on parsing the content as an XML well balanced fragment and then reserialize all cpu elements found. Your scheme would explode for example if we tried to add a <cpu> element as one possible child of <cpu> or if we added attributes to <cpu>, it's too fragile. I can think the other parts can be commited independantly anyway.
Yeah, it's ugly but I wanted to avoid the complexity of parsing XML and formating back to a string. And I still don't think it is a good idea. Maybe I could extend virsh to support variable number of arguments and take each CPU definition from its own file. Jirka

On Thu, Feb 11, 2010 at 08:49:54PM +0100, Jiri Denemark wrote:
+ if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + p = buffer; + while ((p = strstr(p, "<cpu>"))) { + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = p; + + if ((p = strstr(p, "</cpu>"))) { + p += strlen("</cpu>"); + if (*p != '\0') { + *p = '\0'; + p++; + } + } + }
Aye aye aye ... I understand what you're trying to do but I think this is a bit weird ... I think we should be able to come with an alternative, cleaner based on parsing the content as an XML well balanced fragment and then reserialize all cpu elements found. Your scheme would explode for example if we tried to add a <cpu> element as one possible child of <cpu> or if we added attributes to <cpu>, it's too fragile. I can think the other parts can be commited independantly anyway.
Yeah, it's ugly but I wanted to avoid the complexity of parsing XML and formating back to a string. And I still don't think it is a good idea. Maybe I
Not that hard. The harder is to get libvirt to accept something like a concatenation ---------------- <cpu> ... </cpu> <cpu> ... </cpu> ---------------- But I know how to do it (nut never pretend it's XML :-)
could extend virsh to support variable number of arguments and take each CPU definition from its own file.
virsh being a shell tool, it's easy in a shell to concatenate multiple input but very hard to split out pieces from XML fragment, so the current suggestion is IMHO the simplest for users, but the way it's done need to be refined a bit ;-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Feb 11, 2010 at 09:37:58PM +0100, Daniel Veillard wrote:
On Thu, Feb 11, 2010 at 08:49:54PM +0100, Jiri Denemark wrote:
+ if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + p = buffer; + while ((p = strstr(p, "<cpu>"))) { + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = p; + + if ((p = strstr(p, "</cpu>"))) { + p += strlen("</cpu>"); + if (*p != '\0') { + *p = '\0'; + p++; + } + } + }
Aye aye aye ... I understand what you're trying to do but I think this is a bit weird ... I think we should be able to come with an alternative, cleaner based on parsing the content as an XML well balanced fragment and then reserialize all cpu elements found. Your scheme would explode for example if we tried to add a <cpu> element as one possible child of <cpu> or if we added attributes to <cpu>, it's too fragile. I can think the other parts can be commited independantly anyway.
Yeah, it's ugly but I wanted to avoid the complexity of parsing XML and formating back to a string. And I still don't think it is a good idea. Maybe I
Not that hard. The harder is to get libvirt to accept something like a concatenation
---------------- <cpu> ... </cpu> <cpu> ... </cpu> ----------------
But I know how to do it (nut never pretend it's XML :-)
Isn't there anyway to get the XML parser to stop processing input once it has parsed one complete document, without consuming the rest of the data in the file. eg
<cpu> ... </cpu>
Make it stop here ^^^ Then, invoke it again to parse the next document in the file
<cpu> ... </cpu>
And so on.... Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Fri, Feb 12, 2010 at 11:05:54AM +0000, Daniel P. Berrange wrote:
On Thu, Feb 11, 2010 at 09:37:58PM +0100, Daniel Veillard wrote:
On Thu, Feb 11, 2010 at 08:49:54PM +0100, Jiri Denemark wrote:
+ if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + p = buffer; + while ((p = strstr(p, "<cpu>"))) { + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = p; + + if ((p = strstr(p, "</cpu>"))) { + p += strlen("</cpu>"); + if (*p != '\0') { + *p = '\0'; + p++; + } + } + }
Aye aye aye ... I understand what you're trying to do but I think this is a bit weird ... I think we should be able to come with an alternative, cleaner based on parsing the content as an XML well balanced fragment and then reserialize all cpu elements found. Your scheme would explode for example if we tried to add a <cpu> element as one possible child of <cpu> or if we added attributes to <cpu>, it's too fragile. I can think the other parts can be commited independantly anyway.
Yeah, it's ugly but I wanted to avoid the complexity of parsing XML and formating back to a string. And I still don't think it is a good idea. Maybe I
Not that hard. The harder is to get libvirt to accept something like a concatenation
---------------- <cpu> ... </cpu> <cpu> ... </cpu> ----------------
But I know how to do it (nut never pretend it's XML :-)
Isn't there anyway to get the XML parser to stop processing input once it has parsed one complete document, without consuming the rest of the data in the file. eg
No, http://www.w3.org/TR/REC-xml/#NT-document [1] document ::= prolog element Misc* Misc* means the XML parser has to continue feeding it's input until being told that's over. XML is not suitable for concatenation
<cpu> ... </cpu>
Make it stop here ^^^
Then, invoke it again to parse the next document in the file
<cpu> ... </cpu>
And so on....
there is a workaround, parsing as a well balanced chunk, http://xmlsoft.org/html/libxml-parser.html#xmlParseBalancedChunkMemory I will provide a revised version of patch 9 once the 8 others patches are applied. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

I'm not saying it's any easier to read, but from an XML standpoint it's far cleaner. It still accepts random concatenation of files with <cpu> being defined, note that the XPath query will only pick top <cpu> in case there is some recursion (//cpu[not(ancestor::cpu)] does the trick :) It works as previously: paphio:~/libvirt/tools -> ./virsh cpu-baseline baseline <cpu match='exact'> <model>qemu32</model> <feature policy='require' name='monitor'/> <feature policy='require' name='pse36'/> </cpu> paphio:~/libvirt/tools -> with baseline containing the weird concatenation shown in 0/9 :-) Daniel diff --git a/tools/virsh.c b/tools/virsh.c index 7db48d9..95f5801 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -34,6 +34,7 @@ #include <libxml/parser.h> #include <libxml/tree.h> #include <libxml/xpath.h> +#include <libxml/xmlsave.h> #ifdef HAVE_READLINE_READLINE_H #include <readline/readline.h> @@ -7025,6 +7026,121 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) return ret; } +/* + * "cpu-baseline" command + */ +static const vshCmdInfo info_cpu_baseline[] = { + {"help", gettext_noop("compute baseline CPU")}, + {"desc", gettext_noop("Compute baseline CPU for a set of given CPUs.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_cpu_baseline[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing XML CPU descriptions")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) +{ + char *from; + int found; + int ret = TRUE; + char *buffer; + char *p; + char *result = NULL; + const char **list = NULL; + unsigned int count = 0; + xmlDocPtr doc = NULL; + xmlNodePtr node_list, cur; + xmlXPathContextPtr ctxt = NULL; + xmlSaveCtxtPtr sctxt = NULL; + xmlBufferPtr buf = NULL; + xmlXPathObjectPtr obj = NULL; + int res, i; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + from = vshCommandOptString(cmd, "file", &found); + if (!found) + return FALSE; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return FALSE; + + doc = xmlNewDoc(NULL); + if (doc == NULL) + goto no_memory; + + res = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, buffer, &node_list); + if (res != 0) { + vshError(ctl, _("Failed to parse XML fragment %s"), from); + ret = FALSE; + goto cleanup; + } + + xmlAddChildList((xmlNodePtr) doc, node_list); + + ctxt = xmlXPathNewContext(doc); + if (!ctxt) + goto no_memory; + + obj = xmlXPathEval(BAD_CAST "//cpu[not(ancestor::cpu)]", ctxt); + if ((obj == NULL) || (obj->nodesetval == NULL) || + (obj->nodesetval->nodeTab == NULL)) + goto cleanup; + + for (i = 0;i < obj->nodesetval->nodeNr;i++) { + buf = xmlBufferCreate(); + if (buf == NULL) + goto no_memory; + sctxt = xmlSaveToBuffer(buf, NULL, 0); + if (sctxt == NULL) + goto no_memory; + + xmlSaveTree(sctxt, obj->nodesetval->nodeTab[i]); + xmlSaveClose(sctxt); + + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = (char *) buf->content; + buf->content = NULL; + xmlBufferFree(buf); + buf = NULL; + } + + if (count == 0) { + vshError(ctl, _("No host CPU specified in '%s'"), from); + ret = FALSE; + goto cleanup; + } + + result = virConnectBaselineCPU(ctl->conn, list, count, 0); + + if (result) + vshPrint(ctl, "%s", result); + else + ret = FALSE; + +cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + VIR_FREE(result); + if ((list != NULL) && (count > 0)) { + for (i = 0;i < count;i++) + VIR_FREE(list[i]); + } + VIR_FREE(list); + VIR_FREE(buffer); + + return ret; + +no_memory: + vshError(ctl, "%s", _("Out of memory")); + ret = FALSE; +} + /* Common code for the edit / net-edit / pool-edit functions which follow. */ static char * editWriteToTempFile (vshControl *ctl, const char *doc) @@ -7396,6 +7512,7 @@ static const vshCmdDef commands[] = { #ifndef WIN32 {"console", cmdConsole, opts_console, info_console}, #endif + {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline}, {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare}, {"create", cmdCreate, opts_create, info_create}, {"start", cmdStart, opts_start, info_start}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 10f622f..8f6df19 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -213,6 +213,14 @@ crashed. Prints the available amount of memory on the machine or within a NUMA cell if I<cellno> is provided. +=item B<cpu-baseline> I<FILE> + +Compute baseline CPU which will be supported by all host CPUs given in <file>. +The list of host CPUs is built by extracting all <cpu> elements from the +<file>. Thus, the <file> can contain either a set of <cpu> elements separated +by new lines or even a set of complete <capabilities> elements printed by +B<capabilities> command. + =item B<cpu-compare> I<FILE> Compare CPU definition from XML <file> with host CPU. The XML <file> may -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

diff --git a/tools/virsh.c b/tools/virsh.c index 7db48d9..95f5801 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -7025,6 +7026,121 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) ... +static int +cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) +{ ... + for (i = 0;i < obj->nodesetval->nodeNr;i++) { + buf = xmlBufferCreate(); + if (buf == NULL) + goto no_memory; + sctxt = xmlSaveToBuffer(buf, NULL, 0); + if (sctxt == NULL) Hmm, we would leak buf here, wouldn't we? + goto no_memory; + + xmlSaveTree(sctxt, obj->nodesetval->nodeTab[i]); + xmlSaveClose(sctxt); + + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = (char *) buf->content; + buf->content = NULL; + buf = NULL; + } + + if (count == 0) { + vshError(ctl, _("No host CPU specified in '%s'"), from); + ret = FALSE; + goto cleanup; + } + + result = virConnectBaselineCPU(ctl->conn, list, count, 0); + + if (result) + vshPrint(ctl, "%s", result); + else + ret = FALSE; + +cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + VIR_FREE(result); + if ((list != NULL) && (count > 0)) { + for (i = 0;i < count;i++) + VIR_FREE(list[i]); + } + VIR_FREE(list); + VIR_FREE(buffer);
This would fix the leak: xmlBufferFree(buf);
+ return ret; + +no_memory: + vshError(ctl, "%s", _("Out of memory")); + ret = FALSE; +}
Except for the leak on error path, the patch looks good. ACK for the fixed version. Jirka

On Wed, Feb 17, 2010 at 12:40:49PM +0100, Jiri Denemark wrote:
diff --git a/tools/virsh.c b/tools/virsh.c index 7db48d9..95f5801 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -7025,6 +7026,121 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd) ... +static int +cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd) +{ ... + for (i = 0;i < obj->nodesetval->nodeNr;i++) { + buf = xmlBufferCreate(); + if (buf == NULL) + goto no_memory; + sctxt = xmlSaveToBuffer(buf, NULL, 0); + if (sctxt == NULL) Hmm, we would leak buf here, wouldn't we?
Ah right but I prefer to free it here before the goto
+ goto no_memory; + + xmlSaveTree(sctxt, obj->nodesetval->nodeTab[i]); + xmlSaveClose(sctxt); + + list = vshRealloc(ctl, list, sizeof(char *) * (count + 1)); + list[count++] = (char *) buf->content; + buf->content = NULL;
actually there is an xmlBufferFree(buf); here in my patch, it's needed to not leak in the loop.
+ buf = NULL; + } + + if (count == 0) { + vshError(ctl, _("No host CPU specified in '%s'"), from); + ret = FALSE; + goto cleanup; + } + + result = virConnectBaselineCPU(ctl->conn, list, count, 0); + + if (result) + vshPrint(ctl, "%s", result); + else + ret = FALSE; + +cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + VIR_FREE(result); + if ((list != NULL) && (count > 0)) { + for (i = 0;i < count;i++) + VIR_FREE(list[i]); + } + VIR_FREE(list); + VIR_FREE(buffer);
This would fix the leak: xmlBufferFree(buf);
I prefer to do it right before the goto instead.
+ return ret; + +no_memory: + vshError(ctl, "%s", _("Out of memory")); + ret = FALSE; +}
Except for the leak on error path, the patch looks good. ACK for the fixed version.
Okay, thanks, I pushed this ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Jiri Denemark (9): Functions for computing baseline CPU from a set of host CPUs Implement cpuArchBaseline in generic CPU driver Implement cpuArchBaseline in x86 CPU driver virConnectBaselineCPU public API Internal driver API for virConnectBaselineCPU virConnectBaselineCPU public API implementation Wire protocol format and dispatcher for virConnectBaselineCPU Implement cpuBaseline in remote and qemu drivers
I pushed the first 8 patches (above) from this series with the possible crash in 6/9 fixed using NULLSTR(xmlCPUs[i]). Other issues will be addressed separately. Jirka
participants (4)
-
Chris Lalancette
-
Daniel P. Berrange
-
Daniel Veillard
-
Jiri Denemark