From 63bc5dd3e159e669425f5f931ba49d9a82830f0d Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 27 Feb 2008 04:35:08 +0000 Subject: [PATCH] Add formal internal capabilities API and update drivers to use it --- ChangeLog | 13 + proxy/Makefile.am | 3 +- src/Makefile.am | 1 + src/capabilities.c | 696 +++++++++++++++++++++++++ src/capabilities.h | 183 +++++++ src/qemu_conf.c | 252 ++++++--- src/qemu_conf.h | 19 +- src/qemu_driver.c | 193 +------ src/test.c | 87 ++-- src/util.c | 52 ++ src/util.h | 4 + src/xen_internal.c | 267 +++++----- src/xend_internal.c | 106 ++-- 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 +- 29 files changed, 1519 insertions(+), 703 deletions(-) create mode 100644 src/capabilities.c create mode 100644 src/capabilities.h diff --git a/ChangeLog b/ChangeLog index da1c3c1dfd..3d82e43443 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Tue Feb 26 23:16:00 EST 2006 Daniel P. Berrange + + * src/capabilities.h, src/capabilities.c, src/Makefile.am: + Add generic API for dealing with hypervisor capabilities + * src/qemu_conf.c, src/qemu_conf.h, src/qemu_driver.c: Switch + to using capabilities API. Add support for Xenner guests + * src/xen_internalc, src/xend_internal.c, src/xend_internal.h, + src/xml.h, src/xml.c, src/util.c, src/util.h, src/test.c: + Switch to using capabilities API + * tests/xencapstest.c, tests/xencapsdata/*.xml: Update for + changes to capabilities API + * proxy/Makefile.am: Link to capabilities.c and util.c + Tue Feb 26 18:38:00 UTC 2008 Richard W.M. Jones Implement virDomainBlockStats for QEMU/KVM. diff --git a/proxy/Makefile.am b/proxy/Makefile.am index 68e331744f..789a6429fa 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -13,7 +13,8 @@ libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xend_internal.c \ @top_srcdir@/src/xen_internal.c @top_srcdir@/src/virterror.c \ @top_srcdir@/src/sexpr.c @top_srcdir@/src/xml.c \ @top_srcdir@/src/xs_internal.c @top_srcdir@/src/buf.c \ - @top_srcdir@/src/util-lib.c \ + @top_srcdir@/src/capabilities.c \ + @top_srcdir@/src/util.c \ @top_srcdir@/src/uuid.c libvirt_proxy_LDFLAGS = $(WARN_CFLAGS) libvirt_proxy_DEPENDENCIES = diff --git a/src/Makefile.am b/src/Makefile.am index b2bc900e6e..02be9dbc0c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/capabilities.c b/src/capabilities.c new file mode 100644 index 0000000000..94f7d173aa --- /dev/null +++ b/src/capabilities.c @@ -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 + */ + +#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, "\n\n") < 0) + goto no_memory; + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " %s\n", + caps->host.arch) < 0) + goto no_memory; + + if (caps->host.nfeatures) { + if (virBufferAddLit(&xml, " \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, " \n") < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + + if (caps->host.offlineMigrate) { + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + if (caps->host.liveMigrate && + virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + if (caps->host.nmigrateTrans) { + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + for (i = 0 ; i < caps->host.nmigrateTrans ; i++) { + if (virBufferVSprintf(&xml, " %s\n", + caps->host.migrateTrans[i]) < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + } + + if (caps->host.nnumaCell) { + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " \n", + caps->host.nnumaCell) < 0) + goto no_memory; + for (i = 0 ; i < caps->host.nnumaCell ; i++) { + if (virBufferVSprintf(&xml, " \n", + caps->host.numaCell[i]->num) < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " \n", + caps->host.numaCell[i]->ncpus) < 0) + goto no_memory; + for (j = 0 ; j < caps->host.numaCell[i]->ncpus ; j++) + if (virBufferVSprintf(&xml, " \n", + caps->host.numaCell[i]->cpus[j]) < 0) + goto no_memory; + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " \n\n") < 0) + goto no_memory; + + + for (i = 0 ; i < caps->nguests ; i++) { + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " %s\n", + caps->guests[i]->ostype) < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " \n", + caps->guests[i]->arch.name) < 0) + goto no_memory; + if (virBufferVSprintf(&xml, " %d\n", + caps->guests[i]->arch.wordsize) < 0) + goto no_memory; + if (caps->guests[i]->arch.defaultInfo.emulator && + virBufferVSprintf(&xml, " %s\n", + caps->guests[i]->arch.defaultInfo.emulator) < 0) + goto no_memory; + if (caps->guests[i]->arch.defaultInfo.loader && + virBufferVSprintf(&xml, " %s\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, " %s\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, " \n", + caps->guests[i]->arch.domains[j]->type) < 0) + goto no_memory; + if (caps->guests[i]->arch.domains[j]->info.emulator && + virBufferVSprintf(&xml, " %s\n", + caps->guests[i]->arch.domains[j]->info.emulator) < 0) + goto no_memory; + if (caps->guests[i]->arch.domains[j]->info.loader && + virBufferVSprintf(&xml, " %s\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, " %s\n", + caps->guests[i]->arch.domains[j]->info.machines[k]) < 0) + goto no_memory; + } + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + } + + if (virBufferAddLit(&xml, " \n") < 0) + goto no_memory; + + if (caps->guests[i]->nfeatures) { + if (virBufferAddLit(&xml, " \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, " \n") < 0) + goto no_memory; + } + + + if (virBufferAddLit(&xml, " \n\n") < 0) + goto no_memory; + } + + if (virBufferAddLit(&xml, "\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: + */ diff --git a/src/capabilities.h b/src/capabilities.h new file mode 100644 index 0000000000..97bd06f2ef --- /dev/null +++ b/src/capabilities.h @@ -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 + */ + +#ifndef __VIR_CAPABILITIES_H +#define __VIR_CAPABILITIES_H + +#include + + +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: + */ diff --git a/src/qemu_conf.c b/src/qemu_conf.c index fc82a6d47c..8c10ba45c7 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -232,104 +232,186 @@ 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; + + 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; + + /* 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; + } + + 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; } -/* Return the default binary name for a particular architecture */ -static const char *qemudDefaultBinaryForArch(const char *arch) { +virCapsPtr qemudCapsInit(void) { + struct utsname utsname; + virCapsPtr caps; int i; - for (i = 0 ; qemudArchs[i].arch; i++) { - if (!strcmp(qemudArchs[i].arch, arch)) { - return qemudArchs[i].binary; - } + /* Really, this never fails - look at the man-page. */ + uname (&utsname); + + if ((caps = virCapabilitiesNew(utsname.machine, + 0, 0)) == NULL) + goto no_memory; + + 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; + } } + return caps; + + no_memory: + virCapabilitiesFree(caps); return NULL; } -/* 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; - - if (virtType == QEMUD_VIRT_KVM) - name = "qemu-kvm"; - else - name = qemudDefaultBinaryForArch(arch); - - if (!name) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot determin binary for architecture %s", arch); - return NULL; - } - - /* 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; - } - strcpy(path, "/usr/bin/"); - strcat(path, name); - return path; -} - static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) { pid_t child; @@ -429,31 +511,31 @@ static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) { } 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 *qemudParseXML(virConnectPtr conn, 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 *qemudParseXML(virConnectPtr conn, 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 *qemudParseXML(virConnectPtr conn, 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 *qemudParseXML(virConnectPtr conn, 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"); diff --git a/src/qemu_conf.h b/src/qemu_conf.h index 735da4885f..12aa6aeb33 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -31,6 +31,7 @@ #include "internal.h" #include "bridge.h" #include "iptables.h" +#include "capabilities.h" #include #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 *qemudFindNetworkByUUID(const struct qemud_driver *driver, 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 (virConnectPtr conn, 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 */ diff --git a/src/qemu_driver.c b/src/qemu_driver.c index bfa5e397d6..21f0fed85d 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -56,6 +56,7 @@ #include "qemu_conf.h" #include "nodeinfo.h" #include "stats_linux.h" +#include "capabilities.h" static int qemudShutdown(void); @@ -214,6 +215,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(); @@ -297,6 +302,8 @@ qemudShutdown(void) { if (!qemu_driver) return -1; + virCapabilitiesFree(qemu_driver->caps); + /* shutdown active VMs */ vm = qemu_driver->vms; while (vm) { @@ -1479,191 +1486,17 @@ static int qemudGetNodeInfo(virConnectPtr conn, return virNodeInfoPopulate(conn, nodeinfo); } -static int qemudGetFeatures(virBufferPtr xml, - const struct qemu_feature_flags *flags) { - int i, r; - if (flags == NULL) - return 0; +static char *qemudGetCapabilities(virConnectPtr conn) { + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; + char *xml; - r = virBufferAddLit(xml, "\ - \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, " \n"); - if (r == -1) return r; - } - if (nonpae) { - r = virBufferAddLit(xml, " \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, " \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; - - /* 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, - "\ -\n\ - \n\ - \n\ - %s\n\ - \n\ - \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\ - \n\ - hvm\n\ - \n\ - %d\n\ - /usr/bin/%s\n\ - \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, - "\ - %s\n", - qemudArchs[i].machines[j]); - if (r == -1) goto vir_buffer_failed; - } - - if (have_kqemu) { - r = virBufferAddLit (xml, - "\ - \n"); - if (r == -1) goto vir_buffer_failed; - } - if (have_kvm) { - r = virBufferAddLit (xml, - "\ - \n\ - /usr/bin/qemu-kvm\n\ - \n"); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, " \n"); - if (r == -1) goto vir_buffer_failed; - - r = qemudGetFeatures(xml, qemudArchs[i].fflags); - if (r == -1) goto vir_buffer_failed; - - r = virBufferAddLit (xml, " \n"); - if (r == -1) goto vir_buffer_failed; - - /* The "other" PC architecture needs emulation. */ - i = i ^ 1; - r = virBufferVSprintf (xml, - "\ -\n\ - \n\ - hvm\n\ - \n\ - %d\n\ - /usr/bin/%s\n\ - \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, - "\ - %s\n", - qemudArchs[i].machines[j]); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, " \n \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\ - \n\ - hvm\n\ - \n\ - %d\n\ - /usr/bin/%s\n\ - \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, - "\ - %s\n", - qemudArchs[i].machines[j]); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, " \n"); - if (r == -1) goto vir_buffer_failed; - - r = qemudGetFeatures(xml, qemudArchs[i].fflags); - if (r == -1) goto vir_buffer_failed; - - r = virBufferAddLit (xml, " \n"); - if (r == -1) goto vir_buffer_failed; - } - - /* Finish off. */ - r = virBufferAddLit (xml, - "\ -\n"); - if (r == -1) goto vir_buffer_failed; - - return virBufferContentAndFree(xml); + return xml; } diff --git a/src/test.c b/src/test.c index ce8cea8f8f..f401d7de21 100644 --- a/src/test.c +++ b/src/test.c @@ -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 conn, static char *testGetCapabilities (virConnectPtr conn) { - static char caps[] = "\ -\n\ - \n\ - \n\ - " TEST_MODEL "\n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ -\n\ - \n\ - linux\n\ - \n\ - " TEST_MODEL_WORDSIZE "\n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ - \n\ -\n\ -"; + 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 }; - char *caps_copy = strdup (caps); - if (!caps_copy) { - testError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, __FUNCTION__); - return NULL; - } - return caps_copy; + 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) diff --git a/src/util.c b/src/util.c index da1610a036..91a5f813a2 100644 --- a/src/util.c +++ b/src/util.c @@ -52,6 +52,7 @@ #define virLog(msg...) fprintf(stderr, msg) +#ifndef PROXY static void ReportError(virConnectPtr conn, virDomainPtr dom, @@ -601,6 +602,57 @@ __virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long * *result = val; return 0; } +#endif /* PROXY */ + +/** + * 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: diff --git a/src/util.h b/src/util.h index 4ababaecf3..4c12200c9f 100644 --- a/src/util.h +++ b/src/util.h @@ -79,4 +79,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__ */ diff --git a/src/xen_internal.c b/src/xen_internal.c index adee7e2ce7..9b1258fb11 100644 --- a/src/xen_internal.c +++ b/src/xen_internal.c @@ -47,6 +47,7 @@ #include #include "buf.h" +#include "capabilities.h" /* #define DEBUG */ /* @@ -2154,6 +2155,121 @@ xenHypervisorGetVersion(virConnectPtr conn, unsigned long *hvVer) 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(virConnectPtr conn, 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(virConnectPtr conn, } } - /* Construct the final XML. */ - xml = virBufferNew (1024); - if (!xml) { - virXenError(conn, VIR_ERR_NO_MEMORY, __FUNCTION__, 0); - return NULL; - } - r = virBufferVSprintf (xml, - "\ -\n\ - \n\ - \n\ - %s\n\ - \n", - hostmachine); - if (r == -1) goto vir_buffer_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; - 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, "\ - \n"); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, - "\ - \n\ - \n\ - \n\ - \n\ - \n\ - xenmigr\n\ - \n\ - \n\ - \n"); - if (r == -1) goto vir_buffer_failed; + virCapabilitiesFree(caps); + return xml; - if (sys_interface_version >= 4) { - topology = xenDaemonNodeGetTopology(conn, xml); - if (topology != 0) - goto topology_failed; - } - - for (i = 0; i < nr_guest_archs; ++i) { - r = virBufferVSprintf (xml, - "\ -\n\ - \n\ - %s\n\ - \n\ - %d\n\ - \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, - "\ - /usr/lib%s/xen/bin/qemu-dm\n\ - pc\n\ - isapc\n\ - /usr/lib/xen/boot/hvmloader\n", - guest_archs[i].bits == 64 ? "64" : ""); - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, - "\ - \n\ - \n"); - if (r == -1) goto vir_buffer_failed; - if (guest_archs[i].pae) { - r = virBufferAddLit (xml, - "\ - \n"); - if (r == -1) goto vir_buffer_failed; - } - if (guest_archs[i].nonpae) { - r = virBufferAddLit (xml, " \n"); - if (r == -1) goto vir_buffer_failed; - } - if (guest_archs[i].ia64_be) { - r = virBufferAddLit (xml, " \n"); - if (r == -1) goto vir_buffer_failed; - } - if (guest_archs[i].hvm) { - r = virBufferAddLit (xml, - " \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, - " \n"); - } else { - r = virBufferAddLit (xml, - " \n"); - } - if (r == -1) goto vir_buffer_failed; - } - r = virBufferAddLit (xml, "\ - \n\ - \n"); - if (r == -1) goto vir_buffer_failed; - } - - r = virBufferAddLit (xml, - "\ -\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; - - vir_buffer_failed: + no_memory: virXenError(conn, VIR_ERR_NO_MEMORY, __FUNCTION__, 0); - topology_failed: - virBufferFree (xml); + virCapabilitiesFree(caps); return NULL; } diff --git a/src/xend_internal.c b/src/xend_internal.c index bfd793557e..8bbc28f07c 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -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 sexpr *root, virNodeInfoPtr info) 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, - "\ - \n\ - \n", - numCells); - if (r < 0) goto vir_buffer_failed; - r = virParseXenCpuTopology(conn, xml, nodeToCpu, numCpus); - if (r < 0) goto error; + cpuset = malloc(numCpus * sizeof(*cpuset)); + if (cpuset == NULL) + goto memory_error; + cpuNums = malloc(numCpus * sizeof(*cpuNums)); + if (cpuNums == NULL) + goto memory_error; - r = virBufferAddLit (xml, "\ - \n\ - \n"); - if (r < 0) goto vir_buffer_failed; + 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, virNodeInfoPtr info) { /** * 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 conn, virBufferPtr xml) { 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); } diff --git a/src/xend_internal.h b/src/xend_internal.h index 624c04dc07..fb0306bd66 100644 --- a/src/xend_internal.h +++ b/src/xend_internal.h @@ -19,7 +19,7 @@ #include #include "libvirt/libvirt.h" -#include "buf.h" +#include "capabilities.h" #ifdef __cplusplus extern "C" { @@ -187,7 +187,7 @@ int xenDaemonOpen(virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int 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); diff --git a/src/xml.c b/src/xml.c index 8bf6330573..475772c73e 100644 --- a/src/xml.c +++ b/src/xml.c @@ -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" @@ -58,56 +59,6 @@ virXMLError(virConnectPtr conn, virErrorNumber error, const char *info, * * ************************************************************************/ #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 @@ -225,7 +176,7 @@ virParseCpuSet(virConnectPtr conn, const char **str, char sep, return (-1); cur = *str; - skipSpaces(&cur); + virSkipSpaces(&cur); if (*cur == 0) goto parse_error; @@ -251,7 +202,7 @@ virParseCpuSet(virConnectPtr conn, const char **str, char sep, 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 char **str, char sep, 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 char **str, char sep, 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 char **str, char sep, 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, "\ - \n\ - \n", cell, nb_cpus); -#ifdef STANDALONE - { - char *dump; - - dump = virSaveCpuSet(conn, cpuset, maxcpu); - if (dump != NULL) { - virBufferVSprintf(xml, " %s\n", - dump); - free(dump); - } else { - virBufferVSprintf(xml, " %s\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, "\ - \n", cpu); - if (ret < 0) - goto memory_error; - } - } - ret = virBufferAddLit(xml, "\ - \n\ - \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: diff --git a/src/xml.h b/src/xml.h index af87abc504..f196b27252 100644 --- a/src/xml.h +++ b/src/xml.h @@ -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, diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 56067443fc..f4b3e32d34 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -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); } diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 1be0e464a0..f37f948360 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -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); } diff --git a/tests/xencapsdata/xen-i686-pae-hvm.xml b/tests/xencapsdata/xen-i686-pae-hvm.xml index 8bff3bd56f..42b099c9b4 100644 --- a/tests/xencapsdata/xen-i686-pae-hvm.xml +++ b/tests/xencapsdata/xen-i686-pae-hvm.xml @@ -1,4 +1,5 @@ + i686 @@ -16,9 +17,12 @@ xen - + 32 - + /usr/lib/xen/bin/qemu-dm + xenpv + + @@ -27,13 +31,13 @@ hvm - + 32 - /usr/lib/xen/bin/qemu-dm - pc - isapc /usr/lib/xen/boot/hvmloader + xenfv + + @@ -42,4 +46,5 @@ + diff --git a/tests/xencapsdata/xen-i686-pae.xml b/tests/xencapsdata/xen-i686-pae.xml index 03deb989a4..a6cec8a617 100644 --- a/tests/xencapsdata/xen-i686-pae.xml +++ b/tests/xencapsdata/xen-i686-pae.xml @@ -1,4 +1,5 @@ + i686 @@ -16,12 +17,16 @@ xen - + 32 - + /usr/lib/xen/bin/qemu-dm + xenpv + + + diff --git a/tests/xencapsdata/xen-i686.xml b/tests/xencapsdata/xen-i686.xml index 6f25a1d35c..907121215f 100644 --- a/tests/xencapsdata/xen-i686.xml +++ b/tests/xencapsdata/xen-i686.xml @@ -1,9 +1,8 @@ + i686 - - @@ -15,12 +14,16 @@ xen - + 32 - + /usr/lib/xen/bin/qemu-dm + xenpv + + + diff --git a/tests/xencapsdata/xen-ia64-be-hvm.xml b/tests/xencapsdata/xen-ia64-be-hvm.xml index 426ccfac56..732b693727 100644 --- a/tests/xencapsdata/xen-ia64-be-hvm.xml +++ b/tests/xencapsdata/xen-ia64-be-hvm.xml @@ -1,9 +1,8 @@ + ia64 - - @@ -15,9 +14,12 @@ xen - + 64 - + /usr/lib/xen/bin/qemu-dm + xenpv + + @@ -26,13 +28,13 @@ hvm - + 64 - - /usr/lib64/xen/bin/qemu-dm - pc - isapc + /usr/lib/xen/bin/qemu-dm /usr/lib/xen/boot/hvmloader + xenfv + + @@ -40,4 +42,5 @@ + diff --git a/tests/xencapsdata/xen-ia64-be.xml b/tests/xencapsdata/xen-ia64-be.xml index 125448a0cb..4f133ec60d 100644 --- a/tests/xencapsdata/xen-ia64-be.xml +++ b/tests/xencapsdata/xen-ia64-be.xml @@ -1,9 +1,8 @@ + ia64 - - @@ -15,12 +14,16 @@ xen - + 64 - + /usr/lib/xen/bin/qemu-dm + xenpv + + + diff --git a/tests/xencapsdata/xen-ia64-hvm.xml b/tests/xencapsdata/xen-ia64-hvm.xml index 730db4b0c0..ef48a95e39 100644 --- a/tests/xencapsdata/xen-ia64-hvm.xml +++ b/tests/xencapsdata/xen-ia64-hvm.xml @@ -1,9 +1,8 @@ + ia64 - - @@ -15,27 +14,29 @@ xen - + 64 - + /usr/lib/xen/bin/qemu-dm + xenpv + + - - hvm - + 64 - - /usr/lib64/xen/bin/qemu-dm - pc - isapc + /usr/lib/xen/bin/qemu-dm /usr/lib/xen/boot/hvmloader + xenfv + + + diff --git a/tests/xencapsdata/xen-ia64.xml b/tests/xencapsdata/xen-ia64.xml index 12266dd3bd..5570f4dfd9 100644 --- a/tests/xencapsdata/xen-ia64.xml +++ b/tests/xencapsdata/xen-ia64.xml @@ -1,9 +1,8 @@ + ia64 - - @@ -15,11 +14,13 @@ xen - + 64 - + /usr/lib/xen/bin/qemu-dm + xenpv + + - - + diff --git a/tests/xencapsdata/xen-ppc64.xml b/tests/xencapsdata/xen-ppc64.xml index 96e566fc89..627d79c141 100644 --- a/tests/xencapsdata/xen-ppc64.xml +++ b/tests/xencapsdata/xen-ppc64.xml @@ -1,9 +1,8 @@ + ppc64 - - @@ -15,11 +14,13 @@ xen - + 64 - + /usr/lib/xen/bin/qemu-dm + xenpv + + - - + diff --git a/tests/xencapsdata/xen-x86_64-hvm.xml b/tests/xencapsdata/xen-x86_64-hvm.xml index c7fa802f27..52c12c616e 100644 --- a/tests/xencapsdata/xen-x86_64-hvm.xml +++ b/tests/xencapsdata/xen-x86_64-hvm.xml @@ -1,4 +1,5 @@ + x86_64 @@ -16,23 +17,24 @@ xen - + 64 - + /usr/lib64/xen/bin/qemu-dm + xenpv + + - - hvm - + 32 - - /usr/lib/xen/bin/qemu-dm - pc - isapc + /usr/lib64/xen/bin/qemu-dm /usr/lib/xen/boot/hvmloader + xenfv + + @@ -44,17 +46,18 @@ hvm - + 64 - /usr/lib64/xen/bin/qemu-dm - pc - isapc /usr/lib/xen/boot/hvmloader + xenfv + + + diff --git a/tests/xencapsdata/xen-x86_64.xml b/tests/xencapsdata/xen-x86_64.xml index 7c73d0ece5..0faa43c791 100644 --- a/tests/xencapsdata/xen-x86_64.xml +++ b/tests/xencapsdata/xen-x86_64.xml @@ -1,4 +1,5 @@ + x86_64 @@ -16,11 +17,13 @@ xen - + 64 - + /usr/lib64/xen/bin/qemu-dm + xenpv + + - - + diff --git a/tests/xencapstest.c b/tests/xencapstest.c index 1307d80af7..ff9ed33362 100644 --- a/tests/xencapstest.c +++ b/tests/xencapstest.c @@ -50,7 +50,8 @@ static int testCompareFiles(const char *hostmachine, 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);