[Libvir] [PATCH 0/2] Re-organize generation / handling of capabilities data

Earlier today I started the 'simple' task of extending the QEMU driver to support Xenner for running Xen paravirt guests under KVM. This was at first glance easy because it basically looks like QEMU - in fact all we needed was to extend the capabilities XML for the QEMU driver to include data about Xen guests if Xenner is available. Unfortunately this was easier said than done... - The code generating the XML in qemu_driver.c was a mix of string formatting for the XML, and functional logic for determining runtime capabilities (kvm, kqemu, etc). - More runtime logic was in the qemu_conf.c file and stuff that should be runtime logic was static. I attempted to fix up the QEMU code for capabilities but it quickly turned into a horrible mess of spaghetti. Looking at the Xen driver, the situation was pretty much the same, but with the capabilities XML generation spread out over 3 files (xml.c, xen_internal.c and xend_internal.c). So I decided that we needed to have a internal API & structure to allow drivers to formally register & query their capabilities , and also add a central method for serializing it to XML. The following 2 patches implement this idea, and porting the Xen, QEMU and Test drivers to use it. This removes a lot of code duplication in XML formatting and makes the resulting code easier to follow, and should make it much quicker to adding capabilities info to new drivers too. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

This patch adds the files src/capabilities.{c,h} providing an internal API for dealing with capabilities data. All the struct's defined in the header map 1-to-1 onto the structure of the XML capabilities data. Since these definitions are internal only we are not stuck with ABI constraints on them. There are then 3 core sets of APIs: - Registration: adding host features, migration transports, NUMA cells, guest os types, guest domain types, and guest features - Querying: determining if an OS type is supported, and getting config params - Formatting: turning the virCapsPtr object into an XML document The implementation should be fairly self explanatory if you understand the overall structure of the capabilities XML already. NB, we don't call virRaiseError anywhere in this file - the only error that can occur is OOM, so we let the caller raise VIR_ERR_NO_MEMORY with their own specific context info. Makefile.am | 1 capabilities.c | 696 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ capabilities.h | 183 ++++++++++++++ 3 files changed, 880 insertions(+) Dan Index: src/Makefile.am =================================================================== RCS file: /data/cvs/libvirt/src/Makefile.am,v retrieving revision 1.70 diff -u -p -r1.70 Makefile.am --- src/Makefile.am 25 Feb 2008 13:55:56 -0000 1.70 +++ src/Makefile.am 26 Feb 2008 04:47:00 -0000 @@ -37,6 +37,7 @@ CLIENT_SOURCES = \ test.c test.h \ buf.c buf.h \ qparams.c qparams.h \ + capabilities.c capabilities.h \ xml.c xml.h \ event.c event.h \ xen_unified.c xen_unified.h \ Index: src/capabilities.c =================================================================== RCS file: src/capabilities.c diff -N src/capabilities.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/capabilities.c 26 Feb 2008 04:47:00 -0000 @@ -0,0 +1,696 @@ +/* + * capabilities.c: hypervisor capabilities + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * Copyright (C) 2006-2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include "capabilities.h" +#include "buf.h" + + +/** + * virCapabilitiesNew: + * @arch: host machine architecture + * @offlineMigrate: non-zero if offline migration is available + * @liveMigrate: non-zero if live migration is available + * + * Allocate a new capabilities object + */ +virCapsPtr +virCapabilitiesNew(const char *arch, + int offlineMigrate, + int liveMigrate) +{ + virCapsPtr caps; + + if ((caps = calloc(1, sizeof(*caps))) == NULL) + goto no_memory; + + if ((caps->host.arch = strdup(arch)) == NULL) + goto no_memory; + caps->host.offlineMigrate = offlineMigrate; + caps->host.liveMigrate = liveMigrate; + + return caps; + + no_memory: + virCapabilitiesFree(caps); + return NULL; +} + +static void +virCapabilitiesFreeHostNUMACell(virCapsHostNUMACellPtr cell) +{ + free(cell->cpus); + free(cell); +} + +static void +virCapabilitiesFreeGuestDomain(virCapsGuestDomainPtr dom) +{ + int i; + free(dom->info.emulator); + free(dom->info.loader); + for (i = 0 ; i < dom->info.nmachines ; i++) + free(dom->info.machines[i]); + free(dom->info.machines); + + free(dom); +} + +static void +virCapabilitiesFreeGuestFeature(virCapsGuestFeaturePtr feature) +{ + free(feature->name); + free(feature); +} + +static void +virCapabilitiesFreeGuest(virCapsGuestPtr guest) +{ + int i; + free(guest->ostype); + + free(guest->arch.defaultInfo.emulator); + free(guest->arch.defaultInfo.loader); + for (i = 0 ; i < guest->arch.defaultInfo.nmachines ; i++) + free(guest->arch.defaultInfo.machines[i]); + free(guest->arch.defaultInfo.machines); + + for (i = 0 ; i < guest->arch.ndomains ; i++) + virCapabilitiesFreeGuestDomain(guest->arch.domains[i]); + free(guest->arch.domains); + + for (i = 0 ; i < guest->nfeatures ; i++) + virCapabilitiesFreeGuestFeature(guest->features[i]); + free(guest->features); + + free(guest); +} + + +/** + * virCapabilitiesFree: + * @caps: object to free + * + * Free all memory associated with capabilities + */ +void +virCapabilitiesFree(virCapsPtr caps) { + int i; + + for (i = 0 ; i < caps->nguests ; i++) + virCapabilitiesFreeGuest(caps->guests[i]); + free(caps->guests); + + for (i = 0 ; i < caps->host.nfeatures ; i++) + free(caps->host.features[i]); + free(caps->host.features); + for (i = 0 ; i < caps->host.nnumaCell ; i++) + virCapabilitiesFreeHostNUMACell(caps->host.numaCell[i]); + free(caps->host.numaCell); + + free(caps->host.arch); + free(caps); +} + + +/** + * virCapabilitiesAddHostFeature: + * @caps: capabilities to extend + * @name: name of new feature + * + * Registers a new host CPU feature, eg 'pae', or 'vmx' + */ +int +virCapabilitiesAddHostFeature(virCapsPtr caps, + const char *name) +{ + char **features; + + if ((features = realloc(caps->host.features, + sizeof(*features) * (caps->host.nfeatures+1))) == NULL) + return -1; + caps->host.features = features; + + if ((caps->host.features[caps->host.nfeatures] = strdup(name)) == NULL) + return -1; + caps->host.nfeatures++; + + return 0; +} + + +/** + * virCapabilitiesAddHostMigrateTransport: + * @caps: capabilities to extend + * @name: name of migration transport + * + * Registers a new domain migration transport URI + */ +int +virCapabilitiesAddHostMigrateTransport(virCapsPtr caps, + const char *name) +{ + char **migrateTrans; + + if ((migrateTrans = realloc(caps->host.migrateTrans, + sizeof(*migrateTrans) * (caps->host.nmigrateTrans+1))) == NULL) + return -1; + caps->host.migrateTrans = migrateTrans; + + if ((caps->host.migrateTrans[caps->host.nmigrateTrans] = strdup(name)) == NULL) + return -1; + caps->host.nmigrateTrans++; + + return 0; +} + + +/** + * virCapabilitiesAddHostNUMACell: + * @caps: capabilities to extend + * @num: ID number of NUMA cell + * @ncpus: number of CPUs in cell + * @cpus: array of CPU ID numbers for cell + * + * Registers a new NUMA cell for a host, passing in a + * array of CPU IDs belonging to the cell + */ +int +virCapabilitiesAddHostNUMACell(virCapsPtr caps, + int num, + int ncpus, + const int *cpus) +{ + virCapsHostNUMACellPtr cell, *cells; + + if ((cells = realloc(caps->host.numaCell, + sizeof(*cells) * (caps->host.nnumaCell+1))) == NULL) + return -1; + caps->host.numaCell = cells; + + if ((cell = calloc(1, sizeof(cell))) == NULL) + return -1; + caps->host.numaCell[caps->host.nnumaCell] = cell; + + if ((caps->host.numaCell[caps->host.nnumaCell]->cpus = + malloc(ncpus * sizeof(*cpus))) == NULL) + return -1; + memcpy(caps->host.numaCell[caps->host.nnumaCell]->cpus, + cpus, + ncpus * sizeof(*cpus)); + + caps->host.numaCell[caps->host.nnumaCell]->ncpus = ncpus; + caps->host.numaCell[caps->host.nnumaCell]->num = num; + caps->host.nnumaCell++; + + return 0; +} + + +/** + * virCapabilitiesAddGuest: + * @caps: capabilities to extend + * @ostype: guest operating system type ('hvm' or 'xen') + * @arch: guest CPU architecture ('i686', or 'x86_64', etc) + * @wordsize: number of bits in CPU word + * @emulator: path to default device emulator for arch/ostype + * @loader: path to default BIOS loader for arch/ostype + * @nmachines: number of machine variants for emulator + * @machines: machine variants for emulator ('pc', or 'isapc', etc) + * + * Registers a new guest operating system. This should be + * followed by registration of at least one domain for + * running the guest + */ +virCapsGuestPtr +virCapabilitiesAddGuest(virCapsPtr caps, + const char *ostype, + const char *arch, + int wordsize, + const char *emulator, + const char *loader, + int nmachines, + const char *const *machines) +{ + virCapsGuestPtr guest, *guests; + int i; + + if ((guest = calloc(1, sizeof(*guest))) == NULL) + goto no_memory; + + if ((guest->ostype = strdup(ostype)) == NULL) + goto no_memory; + + if ((guest->arch.name = strdup(arch)) == NULL) + goto no_memory; + guest->arch.wordsize = wordsize; + + if (emulator && + (guest->arch.defaultInfo.emulator = strdup(emulator)) == NULL) + goto no_memory; + if (loader && + (guest->arch.defaultInfo.loader = strdup(loader)) == NULL) + goto no_memory; + if (nmachines) { + if ((guest->arch.defaultInfo.machines = + calloc(nmachines, sizeof(*guest->arch.defaultInfo.machines))) == NULL) + goto no_memory; + for (i = 0 ; i < nmachines ; i++) { + if ((guest->arch.defaultInfo.machines[i] = strdup(machines[i])) == NULL) + goto no_memory; + guest->arch.defaultInfo.nmachines++; + } + } + + if ((guests = realloc(caps->guests, + sizeof(*guests) * + (caps->nguests + 1))) == NULL) + goto no_memory; + caps->guests = guests; + caps->guests[caps->nguests] = guest; + caps->nguests++; + + return guest; + + no_memory: + virCapabilitiesFreeGuest(guest); + return NULL; +} + + +/** + * virCapabilitiesAddGuestDomain: + * @guest: guest to support + * @hvtype: hypervisor type ('xen', 'qemu', 'kvm') + * @emulator: specialized device emulator for domain + * @loader: specialized BIOS loader for domain + * @nmachines: number of machine variants for emulator + * @machines: specialized machine variants for emulator + * + * Registers a virtual domain capable of running a + * guest operating system + */ +virCapsGuestDomainPtr +virCapabilitiesAddGuestDomain(virCapsGuestPtr guest, + const char *hvtype, + const char *emulator, + const char *loader, + int nmachines, + const char *const *machines) +{ + virCapsGuestDomainPtr dom, *doms; + int i; + + if ((dom = calloc(1, sizeof(*dom))) == NULL) + goto no_memory; + + if ((dom->type = strdup(hvtype)) == NULL) + goto no_memory; + + if ((dom->type = strdup(hvtype)) == NULL) + goto no_memory; + + if (emulator && + (dom->info.emulator = strdup(emulator)) == NULL) + goto no_memory; + if (loader && + (dom->info.loader = strdup(loader)) == NULL) + goto no_memory; + if (nmachines) { + if ((dom->info.machines = + calloc(nmachines, sizeof(*dom->info.machines))) == NULL) + goto no_memory; + for (i = 0 ; i < nmachines ; i++) { + if ((dom->info.machines[i] = strdup(machines[i])) == NULL) + goto no_memory; + dom->info.nmachines++; + } + } + + if ((doms = realloc(guest->arch.domains, + sizeof(*doms) * + (guest->arch.ndomains + 1))) == NULL) + goto no_memory; + guest->arch.domains = doms; + guest->arch.domains[guest->arch.ndomains] = dom; + guest->arch.ndomains++; + + + return dom; + + no_memory: + virCapabilitiesFreeGuestDomain(dom); + return NULL; +} + + +/** + * virCapabilitiesAddGuestFeature: + * @guest: guest to associate feature with + * @name: name of feature ('pae', 'acpi', 'apic') + * @defaultOn: non-zero if it defaults to on + * @toggle: non-zero if its state can be toggled + * + * Registers a feature for a guest domain + */ +virCapsGuestFeaturePtr +virCapabilitiesAddGuestFeature(virCapsGuestPtr guest, + const char *name, + int defaultOn, + int toggle) +{ + virCapsGuestFeaturePtr feature, *features; + + if ((feature = calloc(1, sizeof(*feature))) == NULL) + goto no_memory; + + if ((feature->name = strdup(name)) == NULL) + goto no_memory; + feature->defaultOn = defaultOn; + feature->toggle = toggle; + + if ((features = realloc(guest->features, + sizeof(*features) * + (guest->nfeatures + 1))) == NULL) + goto no_memory; + guest->features = features; + guest->features[guest->nfeatures] = feature; + guest->nfeatures++; + + return feature; + + no_memory: + virCapabilitiesFreeGuestFeature(feature); + return NULL; +} + + +/** + * virCapabilitiesSupportsGuestOSType: + * @caps: capabilities to query + * @ostype: OS type to search for (eg 'hvm', 'xen') + * + * Returns non-zero if the capabilities support the + * requested operating system type + */ +extern int +virCapabilitiesSupportsGuestOSType(virCapsPtr caps, + const char *ostype) +{ + int i; + for (i = 0 ; i < caps->nguests ; i++) { + if (STREQ(caps->guests[i]->ostype, ostype)) + return 1; + } + return 0; +} + + +/** + * virCapabilitiesDefaultGuestArch: + * @caps: capabilities to query + * @ostype: OS type to search for + * + * Returns the first architecture able to run the + * requested operating system type + */ +extern const char * +virCapabilitiesDefaultGuestArch(virCapsPtr caps, + const char *ostype) +{ + int i; + for (i = 0 ; i < caps->nguests ; i++) { + if (STREQ(caps->guests[i]->ostype, ostype)) + return caps->guests[i]->arch.name; + } + return NULL; +} + +/** + * virCapabilitiesDefaultGuestMachine: + * @caps: capabilities to query + * @ostype: OS type to search for + * @arch: architecture to search for + * + * Returns the first machine variant associated with + * the requested operating system type and architecture + */ +extern const char * +virCapabilitiesDefaultGuestMachine(virCapsPtr caps, + const char *ostype, + const char *arch) +{ + int i; + for (i = 0 ; i < caps->nguests ; i++) { + if (STREQ(caps->guests[i]->ostype, ostype) && + STREQ(caps->guests[i]->arch.name, arch) && + caps->guests[i]->arch.defaultInfo.nmachines) + return caps->guests[i]->arch.defaultInfo.machines[0]; + } + return NULL; +} + +/** + * virCapabilitiesDefaultGuestMachine: + * @caps: capabilities to query + * @ostype: OS type to search for ('xen', 'hvm') + * @arch: architecture to search for + * @domain: domain type ('xen', 'qemu', 'kvm') + * + * Returns the first emulator path associated with + * the requested operating system type, architecture + * and domain type + */ +extern const char * +virCapabilitiesDefaultGuestEmulator(virCapsPtr caps, + const char *ostype, + const char *arch, + const char *domain) +{ + int i, j; + for (i = 0 ; i < caps->nguests ; i++) { + char *emulator; + if (STREQ(caps->guests[i]->ostype, ostype) && + STREQ(caps->guests[i]->arch.name, arch)) { + emulator = caps->guests[i]->arch.defaultInfo.emulator; + for (j = 0 ; j < caps->guests[i]->arch.ndomains ; j++) { + if (STREQ(caps->guests[i]->arch.domains[j]->type, domain)) { + if (caps->guests[i]->arch.domains[j]->info.emulator) + emulator = caps->guests[i]->arch.domains[j]->info.emulator; + } + } + return emulator; + } + } + return NULL; +} + + +/** + * virCapabilitiesFormatXML: + * @caps: capabilities to format + * + * Convert the capabilities object into an XML representation + * + * Returns the XML document as a string + */ +char * +virCapabilitiesFormatXML(virCapsPtr caps) +{ + virBuffer xml = { NULL, 0, 0 }; + int i, j, k; + + if (virBufferAddLit(&xml, "<capabilities>\n\n") < 0) + goto no_memory; + if (virBufferAddLit(&xml, " <host>\n") < 0) + goto no_memory; + if (virBufferAddLit(&xml, " <cpu>\n") < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " <arch>%s</arch>\n", + caps->host.arch) < 0) + goto no_memory; + + if (caps->host.nfeatures) { + if (virBufferAddLit(&xml, " <features>\n") < 0) + goto no_memory; + for (i = 0 ; i < caps->host.nfeatures ; i++) { + if (virBufferVSprintf(&xml, " <%s/>\n", + caps->host.features[i]) <0) + goto no_memory; + } + if (virBufferAddLit(&xml, " </features>\n") < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " </cpu>\n") < 0) + goto no_memory; + + if (caps->host.offlineMigrate) { + if (virBufferAddLit(&xml, " <migration_features>\n") < 0) + goto no_memory; + if (caps->host.liveMigrate && + virBufferAddLit(&xml, " <live/>\n") < 0) + goto no_memory; + if (caps->host.nmigrateTrans) { + if (virBufferAddLit(&xml, " <uri_transports>\n") < 0) + goto no_memory; + for (i = 0 ; i < caps->host.nmigrateTrans ; i++) { + if (virBufferVSprintf(&xml, " <uri_transport>%s</uri_transport>\n", + caps->host.migrateTrans[i]) < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " </uri_transports>\n") < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " </migration_features>\n") < 0) + goto no_memory; + } + + if (caps->host.nnumaCell) { + if (virBufferAddLit(&xml, " <topology>\n") < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " <cells num='%d'>\n", + caps->host.nnumaCell) < 0) + goto no_memory; + for (i = 0 ; i < caps->host.nnumaCell ; i++) { + if (virBufferVSprintf(&xml, " <cell id='%d'>\n", + caps->host.numaCell[i]->num) < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " <cpus num='%d'>\n", + caps->host.numaCell[i]->ncpus) < 0) + goto no_memory; + for (j = 0 ; j < caps->host.numaCell[i]->ncpus ; j++) + if (virBufferVSprintf(&xml, " <cpu id='%d'>\n", + caps->host.numaCell[i]->cpus[j]) < 0) + goto no_memory; + if (virBufferAddLit(&xml, " </cpus>\n") < 0) + goto no_memory; + if (virBufferAddLit(&xml, " </cell>\n") < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " </cells>\n") < 0) + goto no_memory; + if (virBufferAddLit(&xml, " </topology>\n") < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " </host>\n\n") < 0) + goto no_memory; + + + for (i = 0 ; i < caps->nguests ; i++) { + if (virBufferAddLit(&xml, " <guest>\n") < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " <os_type>%s</os_type>\n", + caps->guests[i]->ostype) < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " <arch name='%s'>\n", + caps->guests[i]->arch.name) < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " <wordsize>%d</wordsize>\n", + caps->guests[i]->arch.wordsize) < 0) + goto no_memory; + if (caps->guests[i]->arch.defaultInfo.emulator && + virBufferVSprintf(&xml, " <emulator>%s</emulator>\n", + caps->guests[i]->arch.defaultInfo.emulator) < 0) + goto no_memory; + if (caps->guests[i]->arch.defaultInfo.loader && + virBufferVSprintf(&xml, " <loader>%s</loader>\n", + caps->guests[i]->arch.defaultInfo.loader) < 0) + goto no_memory; + + for (j = 0 ; j < caps->guests[i]->arch.defaultInfo.nmachines ; j++) { + if (virBufferVSprintf(&xml, " <machine>%s</machine>\n", + caps->guests[i]->arch.defaultInfo.machines[j]) < 0) + goto no_memory; + } + + for (j = 0 ; j < caps->guests[i]->arch.ndomains ; j++) { + if (virBufferVSprintf(&xml, " <domain type='%s'>\n", + caps->guests[i]->arch.domains[j]->type) < 0) + goto no_memory; + if (caps->guests[i]->arch.domains[j]->info.emulator && + virBufferVSprintf(&xml, " <emulator>%s</emulator>\n", + caps->guests[i]->arch.domains[j]->info.emulator) < 0) + goto no_memory; + if (caps->guests[i]->arch.domains[j]->info.loader && + virBufferVSprintf(&xml, " <loader>%s</loader>\n", + caps->guests[i]->arch.domains[j]->info.loader) < 0) + goto no_memory; + + for (k = 0 ; k < caps->guests[i]->arch.domains[j]->info.nmachines ; k++) { + if (virBufferVSprintf(&xml, " <machine>%s</machine>\n", + caps->guests[i]->arch.domains[j]->info.machines[k]) < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " </domain>\n") < 0) + goto no_memory; + } + + if (virBufferAddLit(&xml, " </arch>\n") < 0) + goto no_memory; + + if (caps->guests[i]->nfeatures) { + if (virBufferAddLit(&xml, " <features>\n") < 0) + goto no_memory; + + for (j = 0 ; j < caps->guests[i]->nfeatures ; j++) { + if (STREQ(caps->guests[i]->features[j]->name, "pae") || + STREQ(caps->guests[i]->features[j]->name, "nonpae") || + STREQ(caps->guests[i]->features[j]->name, "ia64_be")) { + if (virBufferVSprintf(&xml, " <%s/>\n", + caps->guests[i]->features[j]->name) < 0) + goto no_memory; + } else { + if (virBufferVSprintf(&xml, " <%s default='%s' toggle='%s'/>\n", + caps->guests[i]->features[j]->name, + caps->guests[i]->features[j]->defaultOn ? "on" : "off", + caps->guests[i]->features[j]->toggle ? "yes" : "no") < 0) + goto no_memory; + } + } + + if (virBufferAddLit(&xml, " </features>\n") < 0) + goto no_memory; + } + + + if (virBufferAddLit(&xml, " </guest>\n\n") < 0) + goto no_memory; + } + + if (virBufferAddLit(&xml, "</capabilities>\n") < 0) + goto no_memory; + + return xml.content; + + no_memory: + free(xml.content); + return NULL; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ Index: src/capabilities.h =================================================================== RCS file: src/capabilities.h diff -N src/capabilities.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/capabilities.h 26 Feb 2008 04:47:00 -0000 @@ -0,0 +1,183 @@ +/* + * capabilities.h: hypervisor capabilities + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * Copyright (C) 2006-2008 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_CAPABILITIES_H +#define __VIR_CAPABILITIES_H + +#include <config.h> + + +typedef struct _virCapsGuestFeature virCapsGuestFeature; +typedef virCapsGuestFeature *virCapsGuestFeaturePtr; +struct _virCapsGuestFeature { + char *name; + int defaultOn; + int toggle; +}; + +typedef struct _virCapsGuestDomainInfo virCapsGuestDomainInfo; +typedef virCapsGuestDomainInfo *virCapsGuestDomainInfoPtr; +struct _virCapsGuestDomainInfo { + char *emulator; + char *loader; + int nmachines; + char **machines; +}; + +typedef struct _virCapsGuestDomain virCapsGuestDomain; +typedef virCapsGuestDomain *virCapsGuestDomainPtr; +struct _virCapsGuestDomain { + char *type; + virCapsGuestDomainInfo info; +}; + +typedef struct _virCapsGuestArch virCapsGuestArch; +typedef virCapsGuestArch *virCapsGuestArchptr; +struct _virCapsGuestArch { + char *name; + int wordsize; + virCapsGuestDomainInfo defaultInfo; + int ndomains; + virCapsGuestDomainPtr *domains; +}; + +typedef struct _virCapsGuest virCapsGuest; +typedef virCapsGuest *virCapsGuestPtr; +struct _virCapsGuest { + char *ostype; + virCapsGuestArch arch; + int nfeatures; + virCapsGuestFeaturePtr *features; +}; + +typedef struct _virCapsHostNUMACell virCapsHostNUMACell; +typedef virCapsHostNUMACell *virCapsHostNUMACellPtr; +struct _virCapsHostNUMACell { + int num; + int ncpus; + int *cpus; +}; + +typedef struct _virCapsHost virCapsHost; +typedef virCapsHost *virCapsHostPtr; +struct _virCapsHost { + char *arch; + int nfeatures; + char **features; + int offlineMigrate; + int liveMigrate; + int nmigrateTrans; + char **migrateTrans; + int nnumaCell; + virCapsHostNUMACellPtr *numaCell; +}; + +typedef struct _virCaps virCaps; +typedef virCaps* virCapsPtr; +struct _virCaps { + virCapsHost host; + int nguests; + virCapsGuestPtr *guests; +}; + + +extern virCapsPtr +virCapabilitiesNew(const char *arch, + int offlineMigrate, + int liveMigrate); + +extern void +virCapabilitiesFree(virCapsPtr caps); + + +extern int +virCapabilitiesAddHostFeature(virCapsPtr caps, + const char *name); + +extern int +virCapabilitiesAddHostMigrateTransport(virCapsPtr caps, + const char *name); + + +extern int +virCapabilitiesAddHostNUMACell(virCapsPtr caps, + int num, + int ncpus, + const int *cpus); + + + +extern virCapsGuestPtr +virCapabilitiesAddGuest(virCapsPtr caps, + const char *ostype, + const char *arch, + int wordsize, + const char *emulator, + const char *loader, + int nmachines, + const char *const *machines); + +extern virCapsGuestDomainPtr +virCapabilitiesAddGuestDomain(virCapsGuestPtr guest, + const char *hvtype, + const char *emulator, + const char *loader, + int nmachines, + const char *const *machines); + +extern virCapsGuestFeaturePtr +virCapabilitiesAddGuestFeature(virCapsGuestPtr guest, + const char *name, + int defaultOn, + int toggle); + +extern int +virCapabilitiesSupportsGuestOSType(virCapsPtr caps, + const char *ostype); +extern const char * +virCapabilitiesDefaultGuestArch(virCapsPtr caps, + const char *ostype); +extern const char * +virCapabilitiesDefaultGuestMachine(virCapsPtr caps, + const char *ostype, + const char *arch); +extern const char * +virCapabilitiesDefaultGuestEmulator(virCapsPtr caps, + const char *ostype, + const char *arch, + const char *domain); + +extern char * +virCapabilitiesFormatXML(virCapsPtr caps); + + +#endif /* __VIR_CAPABILITIES_H */ + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

Yes, this all looks good. Another advantage of doing this is that we can be sure that the capabilities XML generated by each driver will have the same schema. Rich. -- Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into Xen guests. http://et.redhat.com/~rjones/virt-p2v

On Tue, Feb 26, 2008 at 09:39:49AM +0000, Richard W.M. Jones wrote:
Yes, this all looks good.
Another advantage of doing this is that we can be sure that the capabilities XML generated by each driver will have the same schema.
Yes indeed - this is a very good benefit, particularly as we extend the capabilities with more data like NUMA / migration / etc. At some point I think it'd be interesting to do a similar refactoring for domains. So we could have an internal virDomainDefPtr to store the definitions and a generic XML formatter / XML parser shared by all drivers. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Tue, Feb 26, 2008 at 12:52:32PM +0000, Daniel P. Berrange wrote:
On Tue, Feb 26, 2008 at 09:39:49AM +0000, Richard W.M. Jones wrote:
Yes, this all looks good.
Another advantage of doing this is that we can be sure that the capabilities XML generated by each driver will have the same schema.
Yes indeed - this is a very good benefit, particularly as we extend the capabilities with more data like NUMA / migration / etc. At some point I think it'd be interesting to do a similar refactoring for domains. So we could have an internal virDomainDefPtr to store the definitions and a generic XML formatter / XML parser shared by all drivers.
Yes I think that has been on the back of everybody's mind since the beginning, but we were not confident enough in the set of properties doing it internally would be good, then at some point we may even expose it in the API, but there is no hurry. On the other hand cleaning up the domain code mess (incredible how simple things become complex as the code is extended) with new internal structures and APIs in the same way would be a really great thing. But that should probably wait a little bit I feel we are too close to the next release for this, Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

On Tue, Feb 26, 2008 at 08:24:53AM -0500, Daniel Veillard wrote:
On Tue, Feb 26, 2008 at 12:52:32PM +0000, Daniel P. Berrange wrote:
On Tue, Feb 26, 2008 at 09:39:49AM +0000, Richard W.M. Jones wrote:
Yes, this all looks good.
Another advantage of doing this is that we can be sure that the capabilities XML generated by each driver will have the same schema.
Yes indeed - this is a very good benefit, particularly as we extend the capabilities with more data like NUMA / migration / etc. At some point I think it'd be interesting to do a similar refactoring for domains. So we could have an internal virDomainDefPtr to store the definitions and a generic XML formatter / XML parser shared by all drivers.
Yes I think that has been on the back of everybody's mind since the beginning, but we were not confident enough in the set of properties doing it internally would be good, then at some point we may even expose it in the API, but there is no hurry.
Yes, if we keep the structs internal we can still change it at will. At worst we'd get compile errors for the drivers which could be trivially fixed.
On the other hand cleaning up the domain code mess (incredible how simple things become complex as the code is extended) with new internal structures and APIs in the same way would be a really great thing. But that should probably wait a little bit I feel we are too close to the next release for this,
Absolutely - i wasn't suggesting that we do it right now - there's plenty of other things to worry about first :-) The existing qemud_conf.h file contains a reasonable starting point for internal VM API, but would need a fair bit more work to be generic enough for the container based drivers. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

This patch refactors the Xen, QEMU and Test drivers to use the new API for dealing with capabilities data. Xen: the code for turning NUMA SEXPR into XML previously split between the xml.c and xend_internal.c file. Since the capabilities APIs now deal with all XML generation, the only code remaining is parsing the SEXPR and calling the appropriate capabilities API. So the stuff from xml.c was moved into the xend_internal.c file and simplified significantly. The xen_internal.c code for generating the domain capabilities XML from XenD capabilities strings has been changed to just call virCapabilitiesAddXXXX and then just do an API call to the resulting virCapsPtr object to XML. The Xen capabilities test suite data files needing some minor edits to deal with enhanced data for Xen. In particular the paravirt guests info now has an <emulator> tag present, since this config param is not HVM specific. There is also some whitespace change / element re-ordering. It also fixes the machine list to match actual Xen usage. It also fixes the bug where 32-on-64 guests would be given /usr/lib/xen instead of the correct /usr/lib64/xen path for the emulator QEMU: the code in qemu_driver.c no longer does anything wrt to formatting XML. It simply invokes the appropriate API to turn virCapsPtr into an XML document. The virCapsPtr object is built when the QEMU driver first starts up by calling qemudCapsInit() in qemud_conf.c. This code is much more dynamic and will check for presence of KVM, KQEMU and validate the presence of each QEMU binary. It also adds support for Xenner which lets you run Xen paravirt guests under KVM. This requires /dev/kvm and a copy of /usr/bin/xenner - the latter is ARGV compatible with QEMU, so no other QEMU driver changes are needed. An application (such as virt-install) using capabilities XML should see presence of Xenner in the XML and just do the right thing automatically. src/qemu_conf.c | 248 +++++++++++++++++++++--------- src/qemu_conf.h | 19 -- src/qemu_driver.c | 193 +---------------------- src/test.c | 89 ++++++----- src/util.c | 51 ++++++ src/util.h | 4 src/xen_internal.c | 267 ++++++++++++++++----------------- src/xend_internal.c | 110 +++++++++---- src/xend_internal.h | 4 src/xml.c | 169 -------------------- src/xml.h | 4 tests/qemuxml2argvtest.c | 4 tests/qemuxml2xmltest.c | 4 tests/xencapsdata/xen-i686-pae-hvm.xml | 17 +- tests/xencapsdata/xen-i686-pae.xml | 9 - tests/xencapsdata/xen-i686.xml | 11 - tests/xencapsdata/xen-ia64-be-hvm.xml | 21 +- tests/xencapsdata/xen-ia64-be.xml | 11 - tests/xencapsdata/xen-ia64-hvm.xml | 23 +- tests/xencapsdata/xen-ia64.xml | 13 - tests/xencapsdata/xen-ppc64.xml | 13 - tests/xencapsdata/xen-x86_64-hvm.xml | 29 +-- tests/xencapsdata/xen-x86_64.xml | 11 - tests/xencapstest.c | 3 24 files changed, 624 insertions(+), 703 deletions(-) Dan Index: src/qemu_conf.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_conf.c,v retrieving revision 1.37 diff -u -p -r1.37 qemu_conf.c --- src/qemu_conf.c 22 Feb 2008 15:55:04 -0000 1.37 +++ src/qemu_conf.c 26 Feb 2008 04:47:03 -0000 @@ -232,102 +232,184 @@ void qemudFreeVM(struct qemud_vm *vm) { /* The list of possible machine types for various architectures, as supported by QEMU - taken from 'qemu -M ?' for each arch */ -static const char *const arch_info_x86_machines[] = { - "pc", "isapc", NULL +static const char *const arch_info_hvm_x86_machines[] = { + "pc", "isapc" }; -static const char *const arch_info_mips_machines[] = { - "mips", NULL +static const char *const arch_info_hvm_mips_machines[] = { + "mips" }; -static const char *const arch_info_sparc_machines[] = { - "sun4m", NULL +static const char *const arch_info_hvm_sparc_machines[] = { + "sun4m" }; -static const char *const arch_info_ppc_machines[] = { - "g3bw", "mac99", "prep", NULL +static const char *const arch_info_hvm_ppc_machines[] = { + "g3bw", "mac99", "prep" +}; + +static const char *const arch_info_xen_x86_machines[] = { + "xenner" +}; + +struct qemu_feature_flags { + const char *name; + const int default_on; + const int toggle; +}; + +struct qemu_arch_info { + const char *arch; + int wordsize; + const char *const *machines; + int nmachines; + const char *binary; + const struct qemu_feature_flags *flags; + int nflags; }; /* Feature flags for the architecture info */ static const struct qemu_feature_flags const arch_info_i686_flags [] = { - { "pae", 1, 1 }, + { "pae", 1, 0 }, + { "nonpae", 1, 0 }, { "acpi", 1, 1 }, { "apic", 1, 0 }, - { NULL, -1, -1 } }; static const struct qemu_feature_flags const arch_info_x86_64_flags [] = { { "acpi", 1, 1 }, { "apic", 1, 0 }, - { NULL, -1, -1 } }; /* The archicture tables for supported QEMU archs */ -const struct qemu_arch_info const qemudArchs[] = { - /* i686 must be in position 0 */ - { "i686", 32, arch_info_x86_machines, "qemu", arch_info_i686_flags }, - /* x86_64 must be in position 1 */ - { "x86_64", 64, arch_info_x86_machines, "qemu-system-x86_64", arch_info_x86_64_flags }, - { "mips", 32, arch_info_mips_machines, "qemu-system-mips", NULL }, - { "mipsel", 32, arch_info_mips_machines, "qemu-system-mipsel", NULL }, - { "sparc", 32, arch_info_sparc_machines, "qemu-system-sparc", NULL }, - { "ppc", 32, arch_info_ppc_machines, "qemu-system-ppc", NULL }, - { NULL, -1, NULL, NULL, NULL } +static const struct qemu_arch_info const arch_info_hvm[] = { + { "i686", 32, arch_info_hvm_x86_machines, 2, + "/usr/bin/qemu", arch_info_i686_flags, 4 }, + { "x86_64", 64, arch_info_hvm_x86_machines, 2, + "/usr/bin/qemu-system-x86_64", arch_info_x86_64_flags, 2 }, + { "mips", 32, arch_info_hvm_mips_machines, 1, + "/usr/bin/qemu-system-mips", NULL, 0 }, + { "mipsel", 32, arch_info_hvm_mips_machines, 1, + "/usr/bin/qemu-system-mipsel", NULL, 0 }, + { "sparc", 32, arch_info_hvm_sparc_machines, 1, + "/usr/bin/qemu-system-sparc", NULL, 0 }, + { "ppc", 32, arch_info_hvm_ppc_machines, 3, + "/usr/bin/qemu-system-ppc", NULL, 0 }, }; -/* Return the default architecture if none is explicitly requested*/ -static const char *qemudDefaultArch(void) { - return qemudArchs[0].arch; -} +static const struct qemu_arch_info const arch_info_xen[] = { + { "i686", 32, arch_info_xen_x86_machines, 1, + "/usr/bin/xenner", arch_info_i686_flags, 4 }, + { "x86_64", 64, arch_info_xen_x86_machines, 1, + "/usr/bin/xenner", arch_info_x86_64_flags, 2 }, +}; -/* Return the default machine type for a given architecture */ -static const char *qemudDefaultMachineForArch(const char *arch) { +static int +qemudCapsInitGuest(virCapsPtr caps, + const char *hostmachine, + const struct qemu_arch_info *info, + int hvm) { + virCapsGuestPtr guest; int i; - for (i = 0; qemudArchs[i].arch; i++) { - if (!strcmp(qemudArchs[i].arch, arch)) { - return qemudArchs[i].machines[0]; - } - } + if ((guest = virCapabilitiesAddGuest(caps, + hvm ? "hvm" : "xen", + info->arch, + info->wordsize, + info->binary, + NULL, + info->nmachines, + info->machines)) == NULL) + return -1; - return NULL; -} + if (hvm) { + /* Check for existance of base emulator */ + if (access(info->binary, X_OK) == 0 && + virCapabilitiesAddGuestDomain(guest, + "qemu", + NULL, + NULL, + 0, + NULL) == NULL) + return -1; -/* Return the default binary name for a particular architecture */ -static const char *qemudDefaultBinaryForArch(const char *arch) { - int i; + /* If guest & host match, then we can accelerate */ + if (STREQ(info->arch, hostmachine)) { + if (access("/dev/kqemu", F_OK) == 0 && + virCapabilitiesAddGuestDomain(guest, + "kqemu", + NULL, + NULL, + 0, + NULL) == NULL) + return -1; + + if (access("/dev/kvm", F_OK) == 0 && + virCapabilitiesAddGuestDomain(guest, + "kvm", + "/usr/bin/qemu-kvm", + NULL, + 0, + NULL) == NULL) + return -1; + } + } else { + if (virCapabilitiesAddGuestDomain(guest, + "kvm", + NULL, + NULL, + 0, + NULL) == NULL) + return -1; + } - for (i = 0 ; qemudArchs[i].arch; i++) { - if (!strcmp(qemudArchs[i].arch, arch)) { - return qemudArchs[i].binary; + if (info->nflags) { + for (i = 0 ; i < info->nflags ; i++) { + if (virCapabilitiesAddGuestFeature(guest, + info->flags[i].name, + info->flags[i].default_on, + info->flags[i].toggle) == NULL) + return -1; } } - return NULL; + return 0; } -/* Find the fully qualified path to the binary for an architecture */ -static char *qemudLocateBinaryForArch(virConnectPtr conn, - int virtType, const char *arch) { - const char *name; - char *path; +virCapsPtr qemudCapsInit(void) { + struct utsname utsname; + virCapsPtr caps; + int i; - if (virtType == QEMUD_VIRT_KVM) - name = "qemu-kvm"; - else - name = qemudDefaultBinaryForArch(arch); + /* Really, this never fails - look at the man-page. */ + uname (&utsname); - if (!name) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot determin binary for architecture %s", arch); - return NULL; - } + if ((caps = virCapabilitiesNew(utsname.machine, + 0, 0)) == NULL) + goto no_memory; - /* XXX lame. should actually use $PATH ... */ - path = malloc(strlen(name) + strlen("/usr/bin/") + 1); - if (!path) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "path"); - return NULL; + for (i = 0 ; i < (sizeof(arch_info_hvm)/sizeof(arch_info_hvm[0])) ; i++) + if (qemudCapsInitGuest(caps, + utsname.machine, + &arch_info_hvm[i], 1) < 0) + goto no_memory; + + if (access("/usr/bin/xenner", X_OK) == 0 && + access("/dev/kvm", F_OK) == 0) { + for (i = 0 ; i < (sizeof(arch_info_xen)/sizeof(arch_info_xen[0])) ; i++) + /* Allow Xen 32-on-32, 32-on-64 and 64-on-64 */ + if (STREQ(arch_info_xen[i].arch, utsname.machine) || + (STREQ(utsname.machine, "x86_64") && + STREQ(arch_info_xen[i].arch, "i686"))) { + if (qemudCapsInitGuest(caps, + utsname.machine, + &arch_info_xen[i], 0) < 0) + goto no_memory; + } } - strcpy(path, "/usr/bin/"); - strcat(path, name); - return path; + + return caps; + + no_memory: + virCapabilitiesFree(caps); + return NULL; } @@ -429,31 +511,31 @@ static int qemudExtractVersionInfo(const } int qemudExtractVersion(virConnectPtr conn, - struct qemud_driver *driver ATTRIBUTE_UNUSED) { - char *binary = NULL; + struct qemud_driver *driver) { + const char *binary; struct stat sb; int ignored; if (driver->qemuVersion > 0) return 0; - if (!(binary = qemudLocateBinaryForArch(conn, QEMUD_VIRT_QEMU, "i686"))) + if ((binary = virCapabilitiesDefaultGuestEmulator(driver->caps, + "hvm", + "i686", + "qemu")) == NULL) return -1; if (stat(binary, &sb) < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "Cannot find QEMU binary %s: %s", binary, strerror(errno)); - free(binary); return -1; } if (qemudExtractVersionInfo(binary, &driver->qemuVersion, &ignored) < 0) { - free(binary); return -1; } - free(binary); return 0; } @@ -1086,7 +1168,7 @@ static struct qemud_vm_def *qemudParseXM qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, NULL); goto error; } - if (strcmp((const char *)obj->stringval, "hvm")) { + if (!virCapabilitiesSupportsGuestOSType(driver->caps, (const char*)obj->stringval)) { qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, "%s", obj->stringval); goto error; } @@ -1097,7 +1179,11 @@ static struct qemud_vm_def *qemudParseXM obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1]/@arch)", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) || (obj->stringval[0] == 0)) { - const char *defaultArch = qemudDefaultArch(); + const char *defaultArch = virCapabilitiesDefaultGuestArch(driver->caps, def->os.type); + if (defaultArch == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "unsupported architecture"); + goto error; + } if (strlen(defaultArch) >= (QEMUD_OS_TYPE_MAX_LEN-1)) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "architecture type too long"); goto error; @@ -1115,9 +1201,11 @@ static struct qemud_vm_def *qemudParseXM obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1]/@machine)", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) || (obj->stringval[0] == 0)) { - const char *defaultMachine = qemudDefaultMachineForArch(def->os.arch); - if (!defaultMachine) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "unsupported arch %s", def->os.arch); + const char *defaultMachine = virCapabilitiesDefaultGuestMachine(driver->caps, + def->os.type, + def->os.arch); + if (defaultMachine == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "unsupported architecture"); goto error; } if (strlen(defaultMachine) >= (QEMUD_OS_MACHINE_MAX_LEN-1)) { @@ -1205,12 +1293,18 @@ static struct qemud_vm_def *qemudParseXM obj = xmlXPathEval(BAD_CAST "string(/domain/devices/emulator[1])", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) || (obj->stringval[0] == 0)) { - char *tmp = qemudLocateBinaryForArch(conn, def->virtType, def->os.arch); - if (!tmp) { + const char *type = (def->virtType == QEMUD_VIRT_QEMU ? "qemu" : + def->virtType == QEMUD_VIRT_KQEMU ? "kqemu": + "kvm"); + const char *emulator = virCapabilitiesDefaultGuestEmulator(driver->caps, + def->os.type, + def->os.arch, + type); + if (!emulator) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "unsupported guest type"); goto error; } - strcpy(def->os.binary, tmp); - free(tmp); + strcpy(def->os.binary, emulator); } else { if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s", "emulator path too long"); Index: src/qemu_conf.h =================================================================== RCS file: /data/cvs/libvirt/src/qemu_conf.h,v retrieving revision 1.17 diff -u -p -r1.17 qemu_conf.h --- src/qemu_conf.h 29 Jan 2008 18:15:54 -0000 1.17 +++ src/qemu_conf.h 26 Feb 2008 04:47:03 -0000 @@ -31,6 +31,7 @@ #include "internal.h" #include "bridge.h" #include "iptables.h" +#include "capabilities.h" #include <netinet/in.h> #define qemudDebug(fmt, ...) do {} while(0) @@ -314,6 +315,8 @@ struct qemud_driver { unsigned int vncTLSx509verify : 1; char *vncTLSx509certdir; char vncListen[BR_INET_ADDR_MAXLEN]; + + virCapsPtr caps; }; @@ -351,6 +354,8 @@ struct qemud_network *qemudFindNetworkBy struct qemud_network *qemudFindNetworkByName(const struct qemud_driver *driver, const char *name); +virCapsPtr qemudCapsInit (void); + int qemudExtractVersion (virConnectPtr conn, struct qemud_driver *driver); int qemudBuildCommandLine (virConnectPtr conn, @@ -418,20 +423,6 @@ char * qemudGenerateNetworkXML struct qemud_network *network, struct qemud_network_def *def); -struct qemu_feature_flags { - const char *name; - const int default_on; - const int toggle; -}; - -struct qemu_arch_info { - const char *arch; - int wordsize; - const char *const *machines; - const char *binary; - const struct qemu_feature_flags *fflags; -}; -extern const struct qemu_arch_info const qemudArchs[]; #endif /* WITH_QEMU */ Index: src/qemu_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_driver.c,v retrieving revision 1.54 diff -u -p -r1.54 qemu_driver.c --- src/qemu_driver.c 22 Feb 2008 16:26:13 -0000 1.54 +++ src/qemu_driver.c 26 Feb 2008 04:47:05 -0000 @@ -56,6 +56,7 @@ #include "qemu_conf.h" #include "nodeinfo.h" #include "stats_linux.h" +#include "capabilities.h" static int qemudShutdown(void); @@ -211,6 +212,10 @@ qemudStartup(void) { goto out_of_memory; free(base); + base = NULL; + + if ((qemu_driver->caps = qemudCapsInit()) == NULL) + goto out_of_memory; if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) { qemudShutdown(); @@ -294,6 +299,8 @@ qemudShutdown(void) { if (!qemu_driver) return -1; + virCapabilitiesFree(qemu_driver->caps); + /* shutdown active VMs */ vm = qemu_driver->vms; while (vm) { @@ -1456,191 +1463,17 @@ static int qemudGetNodeInfo(virConnectPt return virNodeInfoPopulate(conn, nodeinfo); } -static int qemudGetFeatures(virBufferPtr xml, - const struct qemu_feature_flags *flags) { - int i, r; - - if (flags == NULL) - return 0; - r = virBufferAddLit(xml, "\ - <features>\n"); - if (r == -1) return r; - for (i = 0; flags[i].name; ++i) { - if (STREQ(flags[i].name, "pae")) { - int pae = flags[i].default_on || flags[i].toggle; - int nonpae = flags[i].toggle; - if (pae) { - r = virBufferAddLit(xml, " <pae/>\n"); - if (r == -1) return r; - } - if (nonpae) { - r = virBufferAddLit(xml, " <nonpae/>\n"); - if (r == -1) return r; - } - } else { - r = virBufferVSprintf(xml, " <%s default='%s' toggle='%s'/>\n", - flags[i].name, - flags[i].default_on ? "on" : "off", - flags[i].toggle ? "yes" : "no"); - if (r == -1) return r; - } - } - r = virBufferAddLit(xml, " </features>\n"); - return r; -} - -static char *qemudGetCapabilities(virConnectPtr conn ATTRIBUTE_UNUSED) { - struct utsname utsname; - int i, j, r; - int have_kqemu = 0; - int have_kvm = 0; - virBufferPtr xml; - - /* Really, this never fails - look at the man-page. */ - uname (&utsname); - - have_kqemu = access ("/dev/kqemu", F_OK) == 0; - have_kvm = access ("/dev/kvm", F_OK) == 0; +static char *qemudGetCapabilities(virConnectPtr conn) { + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; + char *xml; - /* Construct the XML. */ - xml = virBufferNew (1024); - if (!xml) { - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL); + if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "capabilities"); return NULL; } - r = virBufferVSprintf (xml, - "\ -<capabilities>\n\ - <host>\n\ - <cpu>\n\ - <arch>%s</arch>\n\ - </cpu>\n\ - </host>\n", - utsname.machine); - if (r == -1) { - vir_buffer_failed: - virBufferFree (xml); - qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL); - return NULL; - } - - i = -1; - if (strcmp (utsname.machine, "i686") == 0) i = 0; - else if (strcmp (utsname.machine, "x86_64") == 0) i = 1; - if (i >= 0) { - /* For the default (PC-like) guest, qemudArchs[0] or [1]. */ - r = virBufferVSprintf (xml, - "\ -\n\ - <guest>\n\ - <os_type>hvm</os_type>\n\ - <arch name=\"%s\">\n\ - <wordsize>%d</wordsize>\n\ - <emulator>/usr/bin/%s</emulator>\n\ - <domain type=\"qemu\"/>\n", - qemudArchs[i].arch, - qemudArchs[i].wordsize, - qemudArchs[i].binary); - if (r == -1) goto vir_buffer_failed; - - for (j = 0; qemudArchs[i].machines[j]; ++j) { - r = virBufferVSprintf (xml, - "\ - <machine>%s</machine>\n", - qemudArchs[i].machines[j]); - if (r == -1) goto vir_buffer_failed; - } - - if (have_kqemu) { - r = virBufferAddLit (xml, - "\ - <domain type=\"kqemu\"/>\n"); - if (r == -1) goto vir_buffer_failed; - } - if (have_kvm) { - r = virBufferAddLit (xml, - "\ - <domain type=\"kvm\">\n\ - <emulator>/usr/bin/qemu-kvm</emulator>\n\ - </domain>\n"); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, " </arch>\n"); - if (r == -1) goto vir_buffer_failed; - - r = qemudGetFeatures(xml, qemudArchs[i].fflags); - if (r == -1) goto vir_buffer_failed; - - r = virBufferAddLit (xml, " </guest>\n"); - if (r == -1) goto vir_buffer_failed; - - /* The "other" PC architecture needs emulation. */ - i = i ^ 1; - r = virBufferVSprintf (xml, - "\ -\n\ - <guest>\n\ - <os_type>hvm</os_type>\n\ - <arch name=\"%s\">\n\ - <wordsize>%d</wordsize>\n\ - <emulator>/usr/bin/%s</emulator>\n\ - <domain type=\"qemu\"/>\n", - qemudArchs[i].arch, - qemudArchs[i].wordsize, - qemudArchs[i].binary); - if (r == -1) goto vir_buffer_failed; - for (j = 0; qemudArchs[i].machines[j]; ++j) { - r = virBufferVSprintf (xml, - "\ - <machine>%s</machine>\n", - qemudArchs[i].machines[j]); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, " </arch>\n </guest>\n"); - if (r == -1) goto vir_buffer_failed; - } - - /* The non-PC architectures, qemudArchs[>=2]. */ - for (i = 2; qemudArchs[i].arch; ++i) { - r = virBufferVSprintf (xml, - "\ -\n\ - <guest>\n\ - <os_type>hvm</os_type>\n\ - <arch name=\"%s\">\n\ - <wordsize>%d</wordsize>\n\ - <emulator>/usr/bin/%s</emulator>\n\ - <domain type=\"qemu\"/>\n", - qemudArchs[i].arch, - qemudArchs[i].wordsize, - qemudArchs[i].binary); - if (r == -1) goto vir_buffer_failed; - for (j = 0; qemudArchs[i].machines[j]; ++j) { - r = virBufferVSprintf (xml, - "\ - <machine>%s</machine>\n", - qemudArchs[i].machines[j]); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, " </arch>\n"); - if (r == -1) goto vir_buffer_failed; - - r = qemudGetFeatures(xml, qemudArchs[i].fflags); - if (r == -1) goto vir_buffer_failed; - - r = virBufferAddLit (xml, " </guest>\n"); - if (r == -1) goto vir_buffer_failed; - } - - /* Finish off. */ - r = virBufferAddLit (xml, - "\ -</capabilities>\n"); - if (r == -1) goto vir_buffer_failed; - - return virBufferContentAndFree(xml); + return xml; } Index: src/test.c =================================================================== RCS file: /data/cvs/libvirt/src/test.c,v retrieving revision 1.66 diff -u -p -r1.66 test.c --- src/test.c 22 Feb 2008 15:55:04 -0000 1.66 +++ src/test.c 26 Feb 2008 04:47:06 -0000 @@ -44,6 +44,7 @@ #include "buf.h" #include "util.h" #include "uuid.h" +#include "capabilities.h" /* Flags that determine the action to take on a shutdown or crash of a domain */ @@ -119,7 +120,7 @@ typedef struct _testConn testConn; typedef struct _testConn *testConnPtr; #define TEST_MODEL "i686" -#define TEST_MODEL_WORDSIZE "32" +#define TEST_MODEL_WORDSIZE 32 static const virNodeInfo defaultNodeInfo = { TEST_MODEL, @@ -978,38 +979,60 @@ static int testNodeGetInfo(virConnectPtr static char *testGetCapabilities (virConnectPtr conn) { - static char caps[] = "\ -<capabilities>\n\ - <host>\n\ - <cpu>\n\ - <arch>" TEST_MODEL "</arch>\n\ - <features>\n\ - <pae/>\n\ - <nonpae/>\n\ - </features>\n\ - </cpu>\n\ - </host>\n\ -\n\ - <guest>\n\ - <os_type>linux</os_type>\n\ - <arch name=\"" TEST_MODEL "\">\n\ - <wordsize>" TEST_MODEL_WORDSIZE "</wordsize>\n\ - <domain type=\"test\"/>\n\ - </arch>\n\ - <features>\n\ - <pae/>\n\ - <nonpae/>\n\ - </features>\n\ - </guest>\n\ -</capabilities>\n\ -"; - - char *caps_copy = strdup (caps); - if (!caps_copy) { - testError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, __FUNCTION__); - return NULL; - } - return caps_copy; + virCapsPtr caps; + virCapsGuestPtr guest; + char *xml; + int cell1[] = { 0, 2, 4, 6, 8, 10, 12, 14 }; + int cell2[] = { 1, 3, 5, 7, 9, 11, 13, 15 }; + + if ((caps = virCapabilitiesNew(TEST_MODEL, 0, 0)) == NULL) + goto no_memory; + + if (virCapabilitiesAddHostFeature(caps, "pae") < 0) + goto no_memory; + if (virCapabilitiesAddHostFeature(caps ,"nonpae") < 0) + goto no_memory; + + if (virCapabilitiesAddHostNUMACell(caps, 0, 8, cell1) < 0) + goto no_memory; + if (virCapabilitiesAddHostNUMACell(caps, 1, 8, cell2) < 0) + goto no_memory; + + if ((guest = virCapabilitiesAddGuest(caps, + "linux", + TEST_MODEL, + TEST_MODEL_WORDSIZE, + NULL, + NULL, + 0, + NULL)) == NULL) + goto no_memory; + + if (virCapabilitiesAddGuestDomain(guest, + "test", + NULL, + NULL, + 0, + NULL) == NULL) + goto no_memory; + + + if (virCapabilitiesAddGuestFeature(guest, "pae", 1, 1) == NULL) + goto no_memory; + if (virCapabilitiesAddGuestFeature(guest ,"nonpae", 1, 1) == NULL) + goto no_memory; + + if ((xml = virCapabilitiesFormatXML(caps)) == NULL) + goto no_memory; + + virCapabilitiesFree(caps); + + return xml; + + no_memory: + virCapabilitiesFree(caps); + testError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, __FUNCTION__); + return NULL; } static int testNumOfDomains(virConnectPtr conn) Index: src/util.c =================================================================== RCS file: /data/cvs/libvirt/src/util.c,v retrieving revision 1.21 diff -u -p -r1.21 util.c --- src/util.c 22 Feb 2008 15:53:13 -0000 1.21 +++ src/util.c 26 Feb 2008 04:47:07 -0000 @@ -593,6 +593,57 @@ __virStrToLong_ull(char const *s, char * return 0; } + +/** + * virSkipSpaces: + * @str: pointer to the char pointer used + * + * Skip potential blanks, this includes space tabs, line feed, + * carriage returns and also '\\' which can be erronously emitted + * by xend + */ +void +virSkipSpaces(const char **str) +{ + const char *cur = *str; + + while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || + (*cur == '\r') || (*cur == '\\')) + cur++; + *str = cur; +} + +/** + * virParseNumber: + * @str: pointer to the char pointer used + * + * Parse an unsigned number + * + * Returns the unsigned number or -1 in case of error. @str will be + * updated to skip the number. + */ +int +virParseNumber(const char **str) +{ + int ret = 0; + const char *cur = *str; + + if ((*cur < '0') || (*cur > '9')) + return (-1); + + while ((*cur >= '0') && (*cur <= '9')) { + unsigned int c = *cur - '0'; + + if ((ret > INT_MAX / 10) || + ((ret == INT_MAX / 10) && (c > INT_MAX % 10))) + return (-1); + ret = ret * 10 + c; + cur++; + } + *str = cur; + return (ret); +} + /* * Local variables: * indent-tabs-mode: nil Index: src/util.h =================================================================== RCS file: /data/cvs/libvirt/src/util.h,v retrieving revision 1.10 diff -u -p -r1.10 util.h --- src/util.h 22 Feb 2008 15:53:13 -0000 1.10 +++ src/util.h 26 Feb 2008 04:47:07 -0000 @@ -76,4 +76,8 @@ int __virStrToLong_ull(char const *s, unsigned long long *result); #define virStrToLong_ull(s,e,b,r) __virStrToLong_ull((s),(e),(b),(r)) +void virSkipSpaces(const char **str); +int virParseNumber(const char **str); + + #endif /* __VIR_UTIL_H__ */ Index: src/xen_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xen_internal.c,v retrieving revision 1.112 diff -u -p -r1.112 xen_internal.c --- src/xen_internal.c 7 Feb 2008 10:43:14 -0000 1.112 +++ src/xen_internal.c 26 Feb 2008 04:47:09 -0000 @@ -47,6 +47,7 @@ #include <xen/sched.h> #include "buf.h" +#include "capabilities.h" /* #define DEBUG */ /* @@ -2154,6 +2155,121 @@ xenHypervisorGetVersion(virConnectPtr co return(0); } +struct guest_arch { + const char *model; + int bits; + int hvm; + int pae; + int nonpae; + int ia64_be; +}; + + +static virCapsPtr +xenHypervisorBuildCapabilities(virConnectPtr conn, + const char *hostmachine, + int host_pae, + char *hvm_type, + struct guest_arch *guest_archs, + int nr_guest_archs) { + virCapsPtr caps; + int i; + int hv_major = hv_version >> 16; + int hv_minor = hv_version & 0xFFFF; + + if ((caps = virCapabilitiesNew(hostmachine, 1, 1)) == NULL) + goto no_memory; + if (hvm_type && STRNEQ(hvm_type, "") && + virCapabilitiesAddHostFeature(caps, hvm_type) < 0) + goto no_memory; + if (host_pae && + virCapabilitiesAddHostFeature(caps, "pae") < 0) + goto no_memory; + + + if (virCapabilitiesAddHostMigrateTransport(caps, + "xenmigr") < 0) + goto no_memory; + + + if (sys_interface_version >= 4) { + if (xenDaemonNodeGetTopology(conn, caps) != 0) { + virCapabilitiesFree(caps); + return NULL; + } + } + + for (i = 0; i < nr_guest_archs; ++i) { + virCapsGuestPtr guest; + const char const *machines[] = { guest_archs[i].hvm ? "xenfv" : "xenpv" }; + + if ((guest = virCapabilitiesAddGuest(caps, + guest_archs[i].hvm ? "hvm" : "xen", + guest_archs[i].model, + guest_archs[i].bits, + (STREQ(hostmachine, "x86_64") ? + "/usr/lib64/xen/bin/qemu-dm" : + "/usr/lib/xen/bin/qemu-dm"), + (guest_archs[i].hvm ? + "/usr/lib/xen/boot/hvmloader" : + NULL), + 1, + machines)) == NULL) + goto no_memory; + + if (virCapabilitiesAddGuestDomain(guest, + "xen", + NULL, + NULL, + 0, + NULL) == NULL) + goto no_memory; + + if (guest_archs[i].pae && + virCapabilitiesAddGuestFeature(guest, + "pae", + 1, + 0) == NULL) + goto no_memory; + + if (guest_archs[i].nonpae && + virCapabilitiesAddGuestFeature(guest, + "nonpae", + 1, + 0) == NULL) + goto no_memory; + + if (guest_archs[i].ia64_be && + virCapabilitiesAddGuestFeature(guest, + "ia64_be", + 1, + 0) == NULL) + goto no_memory; + + if (guest_archs[i].hvm) { + if (virCapabilitiesAddGuestFeature(guest, + "acpi", + 1, 1) == NULL) + goto no_memory; + + // In Xen 3.1.0, APIC is always on and can't be toggled + if (virCapabilitiesAddGuestFeature(guest, + "apic", + 1, + (hv_major > 3 && + hv_minor > 0 ? + 0 : 1)) == NULL) + goto no_memory; + } + } + + return caps; + + no_memory: + virCapabilitiesFree(caps); + return NULL; +} + /** * xenHypervisorGetCapabilities: * @conn: pointer to the connection block @@ -2170,25 +2286,17 @@ xenHypervisorMakeCapabilitiesXML(virConn char line[1024], *str, *token; regmatch_t subs[4]; char *saveptr = NULL; - int i, r, topology; + int i; char hvm_type[4] = ""; /* "vmx" or "svm" (or "" if not in CPU). */ int host_pae = 0; - struct guest_arch { - const char *model; - int bits; - int hvm; - int pae; - int nonpae; - int ia64_be; - } guest_archs[32]; + struct guest_arch guest_archs[32]; int nr_guest_archs = 0; - virBufferPtr xml; - char *xml_str; + char *xml; - int hv_major = hv_version >> 16; - int hv_minor = hv_version & 0xFFFF; + + virCapsPtr caps = NULL; memset(guest_archs, 0, sizeof(guest_archs)); @@ -2306,129 +2414,22 @@ xenHypervisorMakeCapabilitiesXML(virConn } } - /* Construct the final XML. */ - xml = virBufferNew (1024); - if (!xml) { - virXenError(conn, VIR_ERR_NO_MEMORY, __FUNCTION__, 0); - return NULL; - } - r = virBufferVSprintf (xml, - "\ -<capabilities>\n\ - <host>\n\ - <cpu>\n\ - <arch>%s</arch>\n\ - <features>\n", - hostmachine); - if (r == -1) goto vir_buffer_failed; - - if (strcmp (hvm_type, "") != 0) { - r = virBufferVSprintf (xml, - "\ - <%s/>\n", - hvm_type); - if (r == -1) goto vir_buffer_failed; - } - if (host_pae) { - r = virBufferAddLit (xml, "\ - <pae/>\n"); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, - "\ - </features>\n\ - </cpu>\n\ - <migration_features>\n\ - <live/>\n\ - <uri_transports>\n\ - <uri_transport>xenmigr</uri_transport>\n\ - </uri_transports>\n\ - </migration_features>\n\ - </host>\n"); - if (r == -1) goto vir_buffer_failed; - - if (sys_interface_version >= 4) { - topology = xenDaemonNodeGetTopology(conn, xml); - if (topology != 0) - goto topology_failed; - } + if ((caps = xenHypervisorBuildCapabilities(conn, + hostmachine, + host_pae, + hvm_type, + guest_archs, + nr_guest_archs)) == NULL) + goto no_memory; + if ((xml = virCapabilitiesFormatXML(caps)) == NULL) + goto no_memory; - for (i = 0; i < nr_guest_archs; ++i) { - r = virBufferVSprintf (xml, - "\ -\n\ - <guest>\n\ - <os_type>%s</os_type>\n\ - <arch name=\"%s\">\n\ - <wordsize>%d</wordsize>\n\ - <domain type=\"xen\"></domain>\n", - guest_archs[i].hvm ? "hvm" : "xen", - guest_archs[i].model, - guest_archs[i].bits); - if (r == -1) goto vir_buffer_failed; - if (guest_archs[i].hvm) { - r = virBufferVSprintf (xml, - "\ - <emulator>/usr/lib%s/xen/bin/qemu-dm</emulator>\n\ - <machine>pc</machine>\n\ - <machine>isapc</machine>\n\ - <loader>/usr/lib/xen/boot/hvmloader</loader>\n", - guest_archs[i].bits == 64 ? "64" : ""); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, - "\ - </arch>\n\ - <features>\n"); - if (r == -1) goto vir_buffer_failed; - if (guest_archs[i].pae) { - r = virBufferAddLit (xml, - "\ - <pae/>\n"); - if (r == -1) goto vir_buffer_failed; - } - if (guest_archs[i].nonpae) { - r = virBufferAddLit (xml, " <nonpae/>\n"); - if (r == -1) goto vir_buffer_failed; - } - if (guest_archs[i].ia64_be) { - r = virBufferAddLit (xml, " <ia64_be/>\n"); - if (r == -1) goto vir_buffer_failed; - } - if (guest_archs[i].hvm) { - r = virBufferAddLit (xml, - " <acpi default='on' toggle='yes'/>\n"); - if (r == -1) goto vir_buffer_failed; - // In Xen 3.1.0, APIC is always on and can't be toggled - if (hv_major >= 3 && hv_minor > 0) { - r = virBufferAddLit (xml, - " <apic default='off' toggle='no'/>\n"); - } else { - r = virBufferAddLit (xml, - " <apic default='on' toggle='yes'/>\n"); - } - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, "\ - </features>\n\ - </guest>\n"); - if (r == -1) goto vir_buffer_failed; - } - - r = virBufferAddLit (xml, - "\ -</capabilities>\n"); - if (r == -1) goto vir_buffer_failed; - xml_str = strdup (xml->content); - if (!xml_str) goto vir_buffer_failed; - virBufferFree (xml); - - return xml_str; + virCapabilitiesFree(caps); + return xml; - vir_buffer_failed: + no_memory: virXenError(conn, VIR_ERR_NO_MEMORY, __FUNCTION__, 0); - topology_failed: - virBufferFree (xml); + virCapabilitiesFree(caps); return NULL; } Index: src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.171 diff -u -p -r1.171 xend_internal.c --- src/xend_internal.c 20 Feb 2008 15:29:13 -0000 1.171 +++ src/xend_internal.c 26 Feb 2008 04:47:11 -0000 @@ -39,6 +39,7 @@ #include "sexpr.h" #include "xml.h" #include "buf.h" +#include "capabilities.h" #include "uuid.h" #include "xen_unified.h" #include "xend_internal.h" @@ -1952,59 +1953,104 @@ sexpr_to_xend_node_info(const struct sex return (0); } + /** - * sexpr_to_xend_topology_xml: + * sexpr_to_xend_topology * @root: an S-Expression describing a node + * @caps: capability info * - * Internal routine creating an XML string with the values from - * the node root provided. + * Internal routine populating capability info with + * NUMA node mapping details * * Returns 0 in case of success, -1 in case of error */ static int -sexpr_to_xend_topology_xml(virConnectPtr conn, const struct sexpr *root, - virBufferPtr xml) +sexpr_to_xend_topology(virConnectPtr conn, + const struct sexpr *root, + virCapsPtr caps) { const char *nodeToCpu; - int numCells = 0; + const char *cur; + char *cpuset = NULL; + int *cpuNums = NULL; + int cell, cpu, nb_cpus; + int n = 0; int numCpus; - int r; nodeToCpu = sexpr_node(root, "node/node_to_cpu"); if (nodeToCpu == NULL) { virXendError(conn, VIR_ERR_INTERNAL_ERROR, _("failed to parse topology information")); - goto error; + return -1; } - numCells = sexpr_int(root, "node/nr_nodes"); numCpus = sexpr_int(root, "node/nr_cpus"); - /* start filling in xml */ - r = virBufferVSprintf (xml, - "\ - <topology>\n\ - <cells num='%d'>\n", - numCells); - if (r < 0) goto vir_buffer_failed; - - r = virParseXenCpuTopology(conn, xml, nodeToCpu, numCpus); - if (r < 0) goto error; - - r = virBufferAddLit (xml, "\ - </cells>\n\ - </topology>\n"); - if (r < 0) goto vir_buffer_failed; + + cpuset = malloc(numCpus * sizeof(*cpuset)); + if (cpuset == NULL) + goto memory_error; + cpuNums = malloc(numCpus * sizeof(*cpuNums)); + if (cpuNums == NULL) + goto memory_error; + + cur = nodeToCpu; + while (*cur != 0) { + /* + * Find the next NUMA cell described in the xend output + */ + cur = strstr(cur, "node"); + if (cur == NULL) + break; + cur += 4; + cell = virParseNumber(&cur); + if (cell < 0) + goto parse_error; + virSkipSpaces(&cur); + if (*cur != ':') + goto parse_error; + cur++; + virSkipSpaces(&cur); + if (!strncmp(cur, "no cpus", 7)) { + nb_cpus = 0; + for (cpu = 0; cpu < numCpus; cpu++) + cpuset[cpu] = 0; + } else { + nb_cpus = virParseCpuSet(conn, &cur, 'n', cpuset, numCpus); + if (nb_cpus < 0) + goto error; + } + + for (n = 0, cpu = 0; cpu < numCpus; cpu++) + if (cpuset[cpu] == 1) + cpuNums[n++] = cpu; + + if (virCapabilitiesAddHostNUMACell(caps, + cell, + nb_cpus, + cpuNums) < 0) + goto memory_error; + } + free(cpuNums); + free(cpuset); return (0); + parse_error: + virXendError(conn, VIR_ERR_XEN_CALL, _("topology syntax error")); + error: + free(cpuNums); + free(cpuset); -vir_buffer_failed: - virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate new buffer")); + return (-1); -error: + memory_error: + free(cpuNums); + free(cpuset); + virXendError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer")); return (-1); } + #ifndef PROXY /** * sexpr_to_domain: @@ -2720,13 +2766,15 @@ xenDaemonNodeGetInfo(virConnectPtr conn, /** * xenDaemonNodeGetTopology: * @conn: pointer to the Xen Daemon block + * @caps: capabilities info * * This method retrieves a node's topology information. * * Returns -1 in case of error, 0 otherwise. */ int -xenDaemonNodeGetTopology(virConnectPtr conn, virBufferPtr xml) { +xenDaemonNodeGetTopology(virConnectPtr conn, + virCapsPtr caps) { int ret = -1; struct sexpr *root; @@ -2735,17 +2783,17 @@ xenDaemonNodeGetTopology(virConnectPtr c return (-1); } - if (xml == NULL) { + if (caps == NULL) { virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return (-1); - } + } root = sexpr_get(conn, "/xend/node/"); if (root == NULL) { return (-1); } - ret = sexpr_to_xend_topology_xml(conn, root, xml); + ret = sexpr_to_xend_topology(conn, root, caps); sexpr_free(root); return (ret); } Index: src/xend_internal.h =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.h,v retrieving revision 1.38 diff -u -p -r1.38 xend_internal.h --- src/xend_internal.h 5 Feb 2008 19:27:37 -0000 1.38 +++ src/xend_internal.h 26 Feb 2008 04:47:12 -0000 @@ -19,7 +19,7 @@ #include <stdbool.h> #include "libvirt/libvirt.h" -#include "buf.h" +#include "capabilities.h" #ifdef __cplusplus extern "C" { @@ -187,7 +187,7 @@ int xenDaemonOpen(virConnectPtr conn, xm int xenDaemonClose(virConnectPtr conn); int xenDaemonGetVersion(virConnectPtr conn, unsigned long *hvVer); int xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info); -int xenDaemonNodeGetTopology(virConnectPtr conn, virBufferPtr xml); +int xenDaemonNodeGetTopology(virConnectPtr conn, virCapsPtr caps); int xenDaemonDomainSuspend(virDomainPtr domain); int xenDaemonDomainResume(virDomainPtr domain); int xenDaemonDomainShutdown(virDomainPtr domain); Index: src/xml.c =================================================================== RCS file: /data/cvs/libvirt/src/xml.c,v retrieving revision 1.112 diff -u -p -r1.112 xml.c --- src/xml.c 20 Feb 2008 15:29:13 -0000 1.112 +++ src/xml.c 26 Feb 2008 04:47:13 -0000 @@ -26,6 +26,7 @@ #include "sexpr.h" #include "xml.h" #include "buf.h" +#include "util.h" #include "xs_internal.h" /* for xenStoreDomainGetNetworkID */ #include "xen_unified.h" @@ -59,56 +60,6 @@ virXMLError(virConnectPtr conn, virError ************************************************************************/ #if WITH_XEN /** - * skipSpaces: - * @str: pointer to the char pointer used - * - * Skip potential blanks, this includes space tabs, line feed, - * carriage returns and also '\\' which can be erronously emitted - * by xend - */ -static void -skipSpaces(const char **str) -{ - const char *cur = *str; - - while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || - (*cur == '\r') || (*cur == '\\')) - cur++; - *str = cur; -} - -/** - * parseNumber: - * @str: pointer to the char pointer used - * - * Parse an unsigned number - * - * Returns the unsigned number or -1 in case of error. @str will be - * updated to skip the number. - */ -static int -parseNumber(const char **str) -{ - int ret = 0; - const char *cur = *str; - - if ((*cur < '0') || (*cur > '9')) - return (-1); - - while ((*cur >= '0') && (*cur <= '9')) { - unsigned int c = *cur - '0'; - - if ((ret > INT_MAX / 10) || - ((ret == INT_MAX / 10) && (c > INT_MAX % 10))) - return (-1); - ret = ret * 10 + c; - cur++; - } - *str = cur; - return (ret); -} - -/** * parseCpuNumber: * @str: pointer to the char pointer used * @maxcpu: maximum CPU number allowed @@ -225,7 +176,7 @@ virParseCpuSet(virConnectPtr conn, const return (-1); cur = *str; - skipSpaces(&cur); + virSkipSpaces(&cur); if (*cur == 0) goto parse_error; @@ -251,7 +202,7 @@ virParseCpuSet(virConnectPtr conn, const start = parseCpuNumber(&cur, maxcpu); if (start < 0) goto parse_error; - skipSpaces(&cur); + virSkipSpaces(&cur); if ((*cur == ',') || (*cur == 0) || (*cur == sep)) { if (neg) { if (cpuset[start] == 1) { @@ -268,7 +219,7 @@ virParseCpuSet(virConnectPtr conn, const if (neg) goto parse_error; cur++; - skipSpaces(&cur); + virSkipSpaces(&cur); last = parseCpuNumber(&cur, maxcpu); if (last < start) goto parse_error; @@ -278,11 +229,11 @@ virParseCpuSet(virConnectPtr conn, const ret++; } } - skipSpaces(&cur); + virSkipSpaces(&cur); } if (*cur == ',') { cur++; - skipSpaces(&cur); + virSkipSpaces(&cur); neg = 0; } else if ((*cur == 0) || (*cur == sep)) { break; @@ -298,114 +249,6 @@ virParseCpuSet(virConnectPtr conn, const return (-1); } -/** - * virParseXenCpuTopology: - * @conn: connection - * @xml: XML output buffer - * @str: the topology string - * @maxcpu: number of elements available in @cpuset - * - * Parse a Xend CPU topology string and build the associated XML - * format. - * - * Returns 0 in case of success, -1 in case of error - */ -int -virParseXenCpuTopology(virConnectPtr conn, virBufferPtr xml, - const char *str, int maxcpu) -{ - const char *cur; - char *cpuset = NULL; - int cell, cpu, nb_cpus; - int ret; - - if ((str == NULL) || (xml == NULL) || (maxcpu <= 0) || (maxcpu > 100000)) - return (-1); - - cpuset = malloc(maxcpu * sizeof(*cpuset)); - if (cpuset == NULL) - goto memory_error; - - cur = str; - while (*cur != 0) { - /* - * Find the next NUMA cell described in the xend output - */ - cur = strstr(cur, "node"); - if (cur == NULL) - break; - cur += 4; - cell = parseNumber(&cur); - if (cell < 0) - goto parse_error; - skipSpaces(&cur); - if (*cur != ':') - goto parse_error; - cur++; - skipSpaces(&cur); - if (!strncmp(cur, "no cpus", 7)) { - nb_cpus = 0; - for (cpu = 0; cpu < maxcpu; cpu++) - cpuset[cpu] = 0; - } else { - nb_cpus = virParseCpuSet(conn, &cur, 'n', cpuset, maxcpu); - if (nb_cpus < 0) - goto error; - } - - /* - * add xml for all cpus associated with that cell - */ - ret = virBufferVSprintf(xml, "\ - <cell id='%d'>\n\ - <cpus num='%d'>\n", cell, nb_cpus); -#ifdef STANDALONE - { - char *dump; - - dump = virSaveCpuSet(conn, cpuset, maxcpu); - if (dump != NULL) { - virBufferVSprintf(xml, " <dump>%s</dump>\n", - dump); - free(dump); - } else { - virBufferVSprintf(xml, " <error>%s</error>\n", - "Failed to dump CPU set"); - } - } -#endif - if (ret < 0) - goto memory_error; - for (cpu = 0; cpu < maxcpu; cpu++) { - if (cpuset[cpu] == 1) { - ret = virBufferVSprintf(xml, "\ - <cpu id='%d'/>\n", cpu); - if (ret < 0) - goto memory_error; - } - } - ret = virBufferAddLit(xml, "\ - </cpus>\n\ - </cell>\n"); - if (ret < 0) - goto memory_error; - - } - free(cpuset); - return (0); - - parse_error: - virXMLError(conn, VIR_ERR_XEN_CALL, _("topology syntax error"), 0); - error: - free(cpuset); - - return (-1); - - memory_error: - free(cpuset); - virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0); - return (-1); -} /** * virConvertCpuSet: Index: src/xml.h =================================================================== RCS file: /data/cvs/libvirt/src/xml.h,v retrieving revision 1.21 diff -u -p -r1.21 xml.h --- src/xml.h 30 Nov 2007 22:51:55 -0000 1.21 +++ src/xml.h 26 Feb 2008 04:47:13 -0000 @@ -33,10 +33,6 @@ int virXPathNodeSet (const char *xpath, xmlNodePtr **list); #if WITH_XEN -int virParseXenCpuTopology(virConnectPtr conn, - virBufferPtr xml, - const char *str, - int maxcpu); int virParseCpuSet (virConnectPtr conn, const char **str, char sep, Index: tests/qemuxml2argvtest.c =================================================================== RCS file: /data/cvs/libvirt/tests/qemuxml2argvtest.c,v retrieving revision 1.12 diff -u -p -r1.12 qemuxml2argvtest.c --- tests/qemuxml2argvtest.c 29 Jan 2008 18:15:54 -0000 1.12 +++ tests/qemuxml2argvtest.c 26 Feb 2008 04:47:13 -0000 @@ -125,6 +125,8 @@ main(int argc, char **argv) if (!abs_top_srcdir) return 1; + driver.caps = qemudCapsInit(); + if (virtTestRun("QEMU XML-2-ARGV minimal", 1, testCompareXMLToArgvHelper, "minimal") < 0) ret = -1; @@ -190,6 +192,8 @@ main(int argc, char **argv) ret = -1; + virCapabilitiesFree(driver.caps); + exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); } Index: tests/qemuxml2xmltest.c =================================================================== RCS file: /data/cvs/libvirt/tests/qemuxml2xmltest.c,v retrieving revision 1.10 diff -u -p -r1.10 qemuxml2xmltest.c --- tests/qemuxml2xmltest.c 29 Jan 2008 18:15:54 -0000 1.10 +++ tests/qemuxml2xmltest.c 26 Feb 2008 04:47:13 -0000 @@ -88,6 +88,9 @@ main(int argc, char **argv) if (!abs_top_srcdir) return 1; + + driver.caps = qemudCapsInit(); + if (virtTestRun("QEMU XML-2-ARGV minimal", 1, testCompareXMLToXMLHelper, "minimal") < 0) ret = -1; @@ -152,6 +155,7 @@ main(int argc, char **argv) 1, testCompareXMLToXMLHelper, "net-user") < 0) ret = -1; + virCapabilitiesFree(driver.caps); exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); } Index: tests/xencapstest.c =================================================================== RCS file: /data/cvs/libvirt/tests/xencapstest.c,v retrieving revision 1.9 diff -u -p -r1.9 xencapstest.c --- tests/xencapstest.c 29 Jan 2008 18:15:54 -0000 1.9 +++ tests/xencapstest.c 26 Feb 2008 04:47:13 -0000 @@ -50,7 +50,8 @@ static int testCompareFiles(const char * if (!(actualxml = xenHypervisorMakeCapabilitiesXML(NULL, hostmachine, fp1, fp2))) goto fail; - if (getenv("DEBUG_TESTS")) { + if (getenv("DEBUG_TESTS") && + STRNEQ(expectxml, actualxml)) { printf("In test file %s:\n", capabilities); printf("Expect %d '%s'\n", (int)strlen(expectxml), expectxml); printf("Actual %d '%s'\n", (int)strlen(actualxml), actualxml); Index: tests/xencapsdata/xen-i686-pae-hvm.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-i686-pae-hvm.xml,v retrieving revision 1.3 diff -u -p -r1.3 xen-i686-pae-hvm.xml --- tests/xencapsdata/xen-i686-pae-hvm.xml 21 Aug 2007 09:38:00 -0000 1.3 +++ tests/xencapsdata/xen-i686-pae-hvm.xml 26 Feb 2008 04:47:13 -0000 @@ -1,4 +1,5 @@ <capabilities> + <host> <cpu> <arch>i686</arch> @@ -16,9 +17,12 @@ <guest> <os_type>xen</os_type> - <arch name="i686"> + <arch name='i686'> <wordsize>32</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> <features> <pae/> @@ -27,13 +31,13 @@ <guest> <os_type>hvm</os_type> - <arch name="i686"> + <arch name='i686'> <wordsize>32</wordsize> - <domain type="xen"></domain> <emulator>/usr/lib/xen/bin/qemu-dm</emulator> - <machine>pc</machine> - <machine>isapc</machine> <loader>/usr/lib/xen/boot/hvmloader</loader> + <machine>xenfv</machine> + <domain type='xen'> + </domain> </arch> <features> <pae/> @@ -42,4 +46,5 @@ <apic default='on' toggle='yes'/> </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-i686-pae.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-i686-pae.xml,v retrieving revision 1.2 diff -u -p -r1.2 xen-i686-pae.xml --- tests/xencapsdata/xen-i686-pae.xml 21 Aug 2007 09:38:00 -0000 1.2 +++ tests/xencapsdata/xen-i686-pae.xml 26 Feb 2008 04:47:13 -0000 @@ -1,4 +1,5 @@ <capabilities> + <host> <cpu> <arch>i686</arch> @@ -16,12 +17,16 @@ <guest> <os_type>xen</os_type> - <arch name="i686"> + <arch name='i686'> <wordsize>32</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> <features> <pae/> </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-i686.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-i686.xml,v retrieving revision 1.2 diff -u -p -r1.2 xen-i686.xml --- tests/xencapsdata/xen-i686.xml 21 Aug 2007 09:38:00 -0000 1.2 +++ tests/xencapsdata/xen-i686.xml 26 Feb 2008 04:47:13 -0000 @@ -1,9 +1,8 @@ <capabilities> + <host> <cpu> <arch>i686</arch> - <features> - </features> </cpu> <migration_features> <live/> @@ -15,12 +14,16 @@ <guest> <os_type>xen</os_type> - <arch name="i686"> + <arch name='i686'> <wordsize>32</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> <features> <nonpae/> </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-ia64-be-hvm.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-ia64-be-hvm.xml,v retrieving revision 1.3 diff -u -p -r1.3 xen-ia64-be-hvm.xml --- tests/xencapsdata/xen-ia64-be-hvm.xml 21 Aug 2007 09:38:00 -0000 1.3 +++ tests/xencapsdata/xen-ia64-be-hvm.xml 26 Feb 2008 04:47:13 -0000 @@ -1,9 +1,8 @@ <capabilities> + <host> <cpu> <arch>ia64</arch> - <features> - </features> </cpu> <migration_features> <live/> @@ -15,9 +14,12 @@ <guest> <os_type>xen</os_type> - <arch name="ia64"> + <arch name='ia64'> <wordsize>64</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> <features> <ia64_be/> @@ -26,13 +28,13 @@ <guest> <os_type>hvm</os_type> - <arch name="ia64"> + <arch name='ia64'> <wordsize>64</wordsize> - <domain type="xen"></domain> - <emulator>/usr/lib64/xen/bin/qemu-dm</emulator> - <machine>pc</machine> - <machine>isapc</machine> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> <loader>/usr/lib/xen/boot/hvmloader</loader> + <machine>xenfv</machine> + <domain type='xen'> + </domain> </arch> <features> <ia64_be/> @@ -40,4 +42,5 @@ <apic default='on' toggle='yes'/> </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-ia64-be.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-ia64-be.xml,v retrieving revision 1.2 diff -u -p -r1.2 xen-ia64-be.xml --- tests/xencapsdata/xen-ia64-be.xml 21 Aug 2007 09:38:00 -0000 1.2 +++ tests/xencapsdata/xen-ia64-be.xml 26 Feb 2008 04:47:13 -0000 @@ -1,9 +1,8 @@ <capabilities> + <host> <cpu> <arch>ia64</arch> - <features> - </features> </cpu> <migration_features> <live/> @@ -15,12 +14,16 @@ <guest> <os_type>xen</os_type> - <arch name="ia64"> + <arch name='ia64'> <wordsize>64</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> <features> <ia64_be/> </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-ia64-hvm.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-ia64-hvm.xml,v retrieving revision 1.3 diff -u -p -r1.3 xen-ia64-hvm.xml --- tests/xencapsdata/xen-ia64-hvm.xml 21 Aug 2007 09:38:00 -0000 1.3 +++ tests/xencapsdata/xen-ia64-hvm.xml 26 Feb 2008 04:47:13 -0000 @@ -1,9 +1,8 @@ <capabilities> + <host> <cpu> <arch>ia64</arch> - <features> - </features> </cpu> <migration_features> <live/> @@ -15,27 +14,29 @@ <guest> <os_type>xen</os_type> - <arch name="ia64"> + <arch name='ia64'> <wordsize>64</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> - <features> - </features> </guest> <guest> <os_type>hvm</os_type> - <arch name="ia64"> + <arch name='ia64'> <wordsize>64</wordsize> - <domain type="xen"></domain> - <emulator>/usr/lib64/xen/bin/qemu-dm</emulator> - <machine>pc</machine> - <machine>isapc</machine> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> <loader>/usr/lib/xen/boot/hvmloader</loader> + <machine>xenfv</machine> + <domain type='xen'> + </domain> </arch> <features> <acpi default='on' toggle='yes'/> <apic default='on' toggle='yes'/> </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-ia64.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-ia64.xml,v retrieving revision 1.2 diff -u -p -r1.2 xen-ia64.xml --- tests/xencapsdata/xen-ia64.xml 21 Aug 2007 09:38:00 -0000 1.2 +++ tests/xencapsdata/xen-ia64.xml 26 Feb 2008 04:47:13 -0000 @@ -1,9 +1,8 @@ <capabilities> + <host> <cpu> <arch>ia64</arch> - <features> - </features> </cpu> <migration_features> <live/> @@ -15,11 +14,13 @@ <guest> <os_type>xen</os_type> - <arch name="ia64"> + <arch name='ia64'> <wordsize>64</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> - <features> - </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-ppc64.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-ppc64.xml,v retrieving revision 1.2 diff -u -p -r1.2 xen-ppc64.xml --- tests/xencapsdata/xen-ppc64.xml 21 Aug 2007 09:38:00 -0000 1.2 +++ tests/xencapsdata/xen-ppc64.xml 26 Feb 2008 04:47:13 -0000 @@ -1,9 +1,8 @@ <capabilities> + <host> <cpu> <arch>ppc64</arch> - <features> - </features> </cpu> <migration_features> <live/> @@ -15,11 +14,13 @@ <guest> <os_type>xen</os_type> - <arch name="ppc64"> + <arch name='ppc64'> <wordsize>64</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> - <features> - </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-x86_64-hvm.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-x86_64-hvm.xml,v retrieving revision 1.3 diff -u -p -r1.3 xen-x86_64-hvm.xml --- tests/xencapsdata/xen-x86_64-hvm.xml 21 Aug 2007 09:38:00 -0000 1.3 +++ tests/xencapsdata/xen-x86_64-hvm.xml 26 Feb 2008 04:47:13 -0000 @@ -1,4 +1,5 @@ <capabilities> + <host> <cpu> <arch>x86_64</arch> @@ -16,23 +17,24 @@ <guest> <os_type>xen</os_type> - <arch name="x86_64"> + <arch name='x86_64'> <wordsize>64</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib64/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> - <features> - </features> </guest> <guest> <os_type>hvm</os_type> - <arch name="i686"> + <arch name='i686'> <wordsize>32</wordsize> - <domain type="xen"></domain> - <emulator>/usr/lib/xen/bin/qemu-dm</emulator> - <machine>pc</machine> - <machine>isapc</machine> + <emulator>/usr/lib64/xen/bin/qemu-dm</emulator> <loader>/usr/lib/xen/boot/hvmloader</loader> + <machine>xenfv</machine> + <domain type='xen'> + </domain> </arch> <features> <pae/> @@ -44,17 +46,18 @@ <guest> <os_type>hvm</os_type> - <arch name="x86_64"> + <arch name='x86_64'> <wordsize>64</wordsize> - <domain type="xen"></domain> <emulator>/usr/lib64/xen/bin/qemu-dm</emulator> - <machine>pc</machine> - <machine>isapc</machine> <loader>/usr/lib/xen/boot/hvmloader</loader> + <machine>xenfv</machine> + <domain type='xen'> + </domain> </arch> <features> <acpi default='on' toggle='yes'/> <apic default='on' toggle='yes'/> </features> </guest> + </capabilities> Index: tests/xencapsdata/xen-x86_64.xml =================================================================== RCS file: /data/cvs/libvirt/tests/xencapsdata/xen-x86_64.xml,v retrieving revision 1.2 diff -u -p -r1.2 xen-x86_64.xml --- tests/xencapsdata/xen-x86_64.xml 21 Aug 2007 09:38:00 -0000 1.2 +++ tests/xencapsdata/xen-x86_64.xml 26 Feb 2008 04:47:13 -0000 @@ -1,4 +1,5 @@ <capabilities> + <host> <cpu> <arch>x86_64</arch> @@ -16,11 +17,13 @@ <guest> <os_type>xen</os_type> - <arch name="x86_64"> + <arch name='x86_64'> <wordsize>64</wordsize> - <domain type="xen"></domain> + <emulator>/usr/lib64/xen/bin/qemu-dm</emulator> + <machine>xenpv</machine> + <domain type='xen'> + </domain> </arch> - <features> - </features> </guest> + </capabilities> -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Tue, Feb 26, 2008 at 05:13:51AM +0000, Daniel P. Berrange wrote:
This patch refactors the Xen, QEMU and Test drivers to use the new API for dealing with capabilities data.
Yes, +1 to this patch as well. Rich. -- Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top

On Tue, Feb 26, 2008 at 04:57:56AM +0000, Daniel P. Berrange wrote:
So I decided that we needed to have a internal API & structure to allow drivers to formally register & query their capabilities , and also add a central method for serializing it to XML. The following 2 patches implement this idea, and porting the Xen, QEMU and Test drivers to use it.
This removes a lot of code duplication in XML formatting and makes the resulting code easier to follow, and should make it much quicker to adding capabilities info to new drivers too.
Much needed change. +1 for the general idea, I'll follow up with any detailed comments in the patch messages. Rich. -- Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top

On Tue, Feb 26, 2008 at 04:57:56AM +0000, Daniel P. Berrange wrote:
Earlier today I started the 'simple' task of extending the QEMU driver to support Xenner for running Xen paravirt guests under KVM. This was at first glance easy because it basically looks like QEMU - in fact all we needed was to extend the capabilities XML for the QEMU driver to include data about Xen guests if Xenner is available.
Unfortunately this was easier said than done...
- The code generating the XML in qemu_driver.c was a mix of string formatting for the XML, and functional logic for determining runtime capabilities (kvm, kqemu, etc). - More runtime logic was in the qemu_conf.c file and stuff that should be runtime logic was static.
I attempted to fix up the QEMU code for capabilities but it quickly turned into a horrible mess of spaghetti.
Looking at the Xen driver, the situation was pretty much the same, but with the capabilities XML generation spread out over 3 files (xml.c, xen_internal.c and xend_internal.c).
So I decided that we needed to have a internal API & structure to allow drivers to formally register & query their capabilities , and also add a central method for serializing it to XML. The following 2 patches implement this idea, and porting the Xen, QEMU and Test drivers to use it.
This removes a lot of code duplication in XML formatting and makes the resulting code easier to follow, and should make it much quicker to adding capabilities info to new drivers too.
Okay I looked at both patches (too bad diff can't spot blocks moved from one file to another) they look fine to me. This really is a good cleanup, there are some changes included which seems a bit unrelated but fine too, +1 Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

On Tue, Feb 26, 2008 at 08:29:54AM -0500, Daniel Veillard wrote:
On Tue, Feb 26, 2008 at 04:57:56AM +0000, Daniel P. Berrange wrote:
Earlier today I started the 'simple' task of extending the QEMU driver to support Xenner for running Xen paravirt guests under KVM. This was at first glance easy because it basically looks like QEMU - in fact all we needed was to extend the capabilities XML for the QEMU driver to include data about Xen guests if Xenner is available.
Unfortunately this was easier said than done...
- The code generating the XML in qemu_driver.c was a mix of string formatting for the XML, and functional logic for determining runtime capabilities (kvm, kqemu, etc). - More runtime logic was in the qemu_conf.c file and stuff that should be runtime logic was static.
I attempted to fix up the QEMU code for capabilities but it quickly turned into a horrible mess of spaghetti.
Looking at the Xen driver, the situation was pretty much the same, but with the capabilities XML generation spread out over 3 files (xml.c, xen_internal.c and xend_internal.c).
So I decided that we needed to have a internal API & structure to allow drivers to formally register & query their capabilities , and also add a central method for serializing it to XML. The following 2 patches implement this idea, and porting the Xen, QEMU and Test drivers to use it.
This removes a lot of code duplication in XML formatting and makes the resulting code easier to follow, and should make it much quicker to adding capabilities info to new drivers too.
Okay I looked at both patches (too bad diff can't spot blocks moved from one file to another) they look fine to me. This really is a good cleanup, there are some changes included which seems a bit unrelated but fine too,
+1
This is all committed now. Regards, Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Richard W.M. Jones