[libvirt] [PATCH 0/4] libxl: Add support for UEFI using OVMF

This series adds support for UEFI, via OVMF, to the libxl driver. Patch1 moves the capabilities code from libxl_conf.{ch} to the new files libxl_capabilities.{ch}. Patch2 implements connectGetDomainCapabilities, allowing advertisement of the default OVMF firmware path. Patch3 implements conversion of xl.cfg <-> libvirt domXML. And patch4 finally maps the relevant virDomainLoaderDef fields to libxl_domain_build_info. Jim Fehlig (4): libxl: introduce libxl_capabilities.{ch} libxl: implement connectGetDomainCapabilities xenconfig: support bios=ovmf xl.cfg libxl: Add support for ovmf firmware po/POTFILES.in | 1 + src/Makefile.am | 11 +- src/libxl/libxl_capabilities.c | 557 +++++++++++++++++++++ src/libxl/libxl_capabilities.h | 54 ++ src/libxl/libxl_conf.c | 423 +--------------- src/libxl/libxl_conf.h | 18 +- src/libxl/libxl_domain.c | 1 + src/libxl/libxl_driver.c | 69 +++ src/xenconfig/xen_xl.c | 50 +- tests/Makefile.am | 5 + tests/domaincapsschemadata/domaincaps-xenfv.xml | 51 ++ tests/domaincapsschemadata/domaincaps-xenpv.xml | 44 ++ tests/domaincapstest.c | 33 ++ tests/testutilsxen.h | 1 + tests/xlconfigdata/test-fullvirt-ovmf-override.cfg | 27 + tests/xlconfigdata/test-fullvirt-ovmf-override.xml | 58 +++ tests/xlconfigdata/test-fullvirt-ovmf.cfg | 26 + tests/xlconfigdata/test-fullvirt-ovmf.xml | 58 +++ tests/xlconfigtest.c | 2 + 19 files changed, 1046 insertions(+), 443 deletions(-) create mode 100644 src/libxl/libxl_capabilities.c create mode 100644 src/libxl/libxl_capabilities.h create mode 100644 tests/domaincapsschemadata/domaincaps-xenfv.xml create mode 100644 tests/domaincapsschemadata/domaincaps-xenpv.xml create mode 100644 tests/xlconfigdata/test-fullvirt-ovmf-override.cfg create mode 100644 tests/xlconfigdata/test-fullvirt-ovmf-override.xml create mode 100644 tests/xlconfigdata/test-fullvirt-ovmf.cfg create mode 100644 tests/xlconfigdata/test-fullvirt-ovmf.xml -- 2.1.4

Move capabilities code out of libxl_conf.{ch} and into new libxl_capabilities.{ch} files. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- po/POTFILES.in | 1 + src/Makefile.am | 9 +- src/libxl/libxl_capabilities.c | 454 +++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_capabilities.h | 50 +++++ src/libxl/libxl_conf.c | 415 ------------------------------------- src/libxl/libxl_conf.h | 18 +- src/libxl/libxl_domain.c | 1 + src/libxl/libxl_driver.c | 1 + 8 files changed, 513 insertions(+), 436 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 2f53079..e225782 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -74,6 +74,7 @@ src/libvirt-secret.c src/libvirt-storage.c src/libvirt-stream.c src/libvirt.c +src/libxl/libxl_capabilities.c src/libxl/libxl_conf.c src/libxl/libxl_domain.c src/libxl/libxl_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index ad1c0c3..90f6b51 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -824,10 +824,11 @@ XENAPI_DRIVER_SOURCES = \ xenapi/xenapi_driver_private.h \ xenapi/xenapi_utils.c xenapi/xenapi_utils.h -LIBXL_DRIVER_SOURCES = \ - libxl/libxl_conf.c libxl/libxl_conf.h \ - libxl/libxl_domain.c libxl/libxl_domain.h \ - libxl/libxl_driver.c libxl/libxl_driver.h \ +LIBXL_DRIVER_SOURCES = \ + libxl/libxl_conf.c libxl/libxl_conf.h \ + libxl/libxl_capabilities.c libxl/libxl_capabilities.h \ + libxl/libxl_domain.c libxl/libxl_domain.h \ + libxl/libxl_driver.c libxl/libxl_driver.h \ libxl/libxl_migration.c libxl/libxl_migration.h UML_DRIVER_SOURCES = \ diff --git a/src/libxl/libxl_capabilities.c b/src/libxl/libxl_capabilities.c new file mode 100644 index 0000000..6734b2a --- /dev/null +++ b/src/libxl/libxl_capabilities.c @@ -0,0 +1,454 @@ +/* + * libxl_capabilities.c: libxl capabilities generation + * + * Copyright (C) 2016 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Jim Fehlig <jfehlig@suse.com> + */ + +#include <config.h> + +#include <libxl.h> +#include <regex.h> + +#include "internal.h" +#include "virlog.h" +#include "virerror.h" +#include "viralloc.h" +#include "domain_conf.h" +#include "capabilities.h" +#include "vircommand.h" +#include "libxl_capabilities.h" + + +#define VIR_FROM_THIS VIR_FROM_LIBXL + +VIR_LOG_INIT("libxl.libxl_capabilities"); + +/* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */ +#define LIBXL_X86_FEATURE_PAE_MASK 0x40 + + +struct guest_arch { + virArch arch; + int bits; + int hvm; + int pae; + int nonpae; + int ia64_be; +}; + +#define XEN_CAP_REGEX "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(aarch64|armv7l|x86_32|x86_64|ia64|powerpc64)(p|be)?" + + +static int +libxlCapsInitHost(libxl_ctx *ctx, virCapsPtr caps) +{ + libxl_physinfo phy_info; + int host_pae; + + if (libxl_get_physinfo(ctx, &phy_info) != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to get node physical info from libxenlight")); + return -1; + } + + /* hw_caps is an array of 32-bit words whose meaning is listed in + * xen-unstable.hg/xen/include/asm-x86/cpufeature.h. Each feature + * is defined in the form X*32+Y, corresponding to the Y'th bit in + * the X'th 32-bit word of hw_cap. + */ + host_pae = phy_info.hw_cap[0] & LIBXL_X86_FEATURE_PAE_MASK; + if (host_pae && + virCapabilitiesAddHostFeature(caps, "pae") < 0) + return -1; + + if (virCapabilitiesSetNetPrefix(caps, LIBXL_GENERATED_PREFIX_XEN) < 0) + return -1; + + return 0; +} + +static int +libxlCapsInitNuma(libxl_ctx *ctx, virCapsPtr caps) +{ + libxl_numainfo *numa_info = NULL; + libxl_cputopology *cpu_topo = NULL; + int nr_nodes = 0, nr_cpus = 0; + virCapsHostNUMACellCPUPtr *cpus = NULL; + int *nr_cpus_node = NULL; + size_t i; + int ret = -1; + + /* Let's try to fetch all the topology information */ + numa_info = libxl_get_numainfo(ctx, &nr_nodes); + if (numa_info == NULL || nr_nodes == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("libxl_get_numainfo failed")); + goto cleanup; + } else { + cpu_topo = libxl_get_cpu_topology(ctx, &nr_cpus); + if (cpu_topo == NULL || nr_cpus == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("libxl_get_cpu_topology failed")); + goto cleanup; + } + } + + if (VIR_ALLOC_N(cpus, nr_nodes) < 0) + goto cleanup; + + if (VIR_ALLOC_N(nr_cpus_node, nr_nodes) < 0) + goto cleanup; + + /* For each node, prepare a list of CPUs belonging to that node */ + for (i = 0; i < nr_cpus; i++) { + int node = cpu_topo[i].node; + + if (cpu_topo[i].core == LIBXL_CPUTOPOLOGY_INVALID_ENTRY) + continue; + + nr_cpus_node[node]++; + + if (nr_cpus_node[node] == 1) { + if (VIR_ALLOC(cpus[node]) < 0) + goto cleanup; + } else { + if (VIR_REALLOC_N(cpus[node], nr_cpus_node[node]) < 0) + goto cleanup; + } + + /* Mapping between what libxl tells and what libvirt wants */ + cpus[node][nr_cpus_node[node]-1].id = i; + cpus[node][nr_cpus_node[node]-1].socket_id = cpu_topo[i].socket; + cpus[node][nr_cpus_node[node]-1].core_id = cpu_topo[i].core; + /* Allocate the siblings maps. We will be filling them later */ + cpus[node][nr_cpus_node[node]-1].siblings = virBitmapNew(nr_cpus); + if (!cpus[node][nr_cpus_node[node]-1].siblings) { + virReportOOMError(); + goto cleanup; + } + } + + /* Let's now populate the siblings bitmaps */ + for (i = 0; i < nr_cpus; i++) { + int node = cpu_topo[i].node; + size_t j; + + if (cpu_topo[i].core == LIBXL_CPUTOPOLOGY_INVALID_ENTRY) + continue; + + for (j = 0; j < nr_cpus_node[node]; j++) { + if (cpus[node][j].socket_id == cpu_topo[i].socket && + cpus[node][j].core_id == cpu_topo[i].core) + ignore_value(virBitmapSetBit(cpus[node][j].siblings, i)); + } + } + + for (i = 0; i < nr_nodes; i++) { + if (numa_info[i].size == LIBXL_NUMAINFO_INVALID_ENTRY) + continue; + + if (virCapabilitiesAddHostNUMACell(caps, i, + numa_info[i].size / 1024, + nr_cpus_node[i], cpus[i], + 0, NULL, + 0, NULL) < 0) { + virCapabilitiesClearHostNUMACellCPUTopology(cpus[i], + nr_cpus_node[i]); + goto cleanup; + } + + /* This is safe, as the CPU list is now stored in the NUMA cell */ + cpus[i] = NULL; + } + + ret = 0; + + cleanup: + if (ret != 0) { + for (i = 0; cpus && i < nr_nodes; i++) + VIR_FREE(cpus[i]); + virCapabilitiesFreeNUMAInfo(caps); + } + + VIR_FREE(cpus); + VIR_FREE(nr_cpus_node); + libxl_cputopology_list_free(cpu_topo, nr_cpus); + libxl_numainfo_list_free(numa_info, nr_nodes); + + return ret; +} + +static int +libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps) +{ + const libxl_version_info *ver_info; + int err; + regex_t regex; + char *str, *token; + regmatch_t subs[4]; + char *saveptr = NULL; + size_t i; + + struct guest_arch guest_archs[32]; + int nr_guest_archs = 0; + + memset(guest_archs, 0, sizeof(guest_archs)); + + if ((ver_info = libxl_get_version_info(ctx)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to get version info from libxenlight")); + return -1; + } + + if (!ver_info->capabilities) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to get capabilities from libxenlight")); + return -1; + } + + err = regcomp(®ex, XEN_CAP_REGEX, REG_EXTENDED); + if (err != 0) { + char error[100]; + regerror(err, ®ex, error, sizeof(error)); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to compile regex %s"), error); + return -1; + } + + /* Format of capabilities string is documented in the code in + * xen-unstable.hg/xen/arch/.../setup.c. + * + * It is a space-separated list of supported guest architectures. + * + * For x86: + * TYP-VER-ARCH[p] + * ^ ^ ^ ^ + * | | | +-- PAE supported + * | | +------- x86_32 or x86_64 + * | +----------- the version of Xen, eg. "3.0" + * +--------------- "xen" or "hvm" for para or full virt respectively + * + * For IA64: + * TYP-VER-ARCH[be] + * ^ ^ ^ ^ + * | | | +-- Big-endian supported + * | | +------- always "ia64" + * | +----------- the version of Xen, eg. "3.0" + * +--------------- "xen" or "hvm" for para or full virt respectively + */ + + /* Split capabilities string into tokens. strtok_r is OK here because + * we "own" the buffer. Parse out the features from each token. + */ + for (str = ver_info->capabilities, nr_guest_archs = 0; + nr_guest_archs < sizeof(guest_archs) / sizeof(guest_archs[0]) + && (token = strtok_r(str, " ", &saveptr)) != NULL; + str = NULL) { + if (regexec(®ex, token, sizeof(subs) / sizeof(subs[0]), + subs, 0) == 0) { + int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm"); + virArch arch; + int pae = 0, nonpae = 0, ia64_be = 0; + + if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) { + arch = VIR_ARCH_I686; + if (subs[3].rm_so != -1 && + STRPREFIX(&token[subs[3].rm_so], "p")) + pae = 1; + else + nonpae = 1; + } else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) { + arch = VIR_ARCH_X86_64; + } else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) { + arch = VIR_ARCH_ITANIUM; + if (subs[3].rm_so != -1 && + STRPREFIX(&token[subs[3].rm_so], "be")) + ia64_be = 1; + } else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) { + arch = VIR_ARCH_PPC64; + } else if (STRPREFIX(&token[subs[2].rm_so], "armv7l")) { + arch = VIR_ARCH_ARMV7L; + } else if (STRPREFIX(&token[subs[2].rm_so], "aarch64")) { + arch = VIR_ARCH_AARCH64; + } else { + continue; + } + + /* Search for existing matching (model,hvm) tuple */ + for (i = 0; i < nr_guest_archs; i++) { + if ((guest_archs[i].arch == arch) && + guest_archs[i].hvm == hvm) + break; + } + + /* Too many arch flavours - highly unlikely ! */ + if (i >= ARRAY_CARDINALITY(guest_archs)) + continue; + /* Didn't find a match, so create a new one */ + if (i == nr_guest_archs) + nr_guest_archs++; + + guest_archs[i].arch = arch; + guest_archs[i].hvm = hvm; + + /* Careful not to overwrite a previous positive + setting with a negative one here - some archs + can do both pae & non-pae, but Xen reports + separately capabilities so we're merging archs */ + if (pae) + guest_archs[i].pae = pae; + if (nonpae) + guest_archs[i].nonpae = nonpae; + if (ia64_be) + guest_archs[i].ia64_be = ia64_be; + } + } + regfree(®ex); + + for (i = 0; i < nr_guest_archs; ++i) { + virCapsGuestPtr guest; + char const *const xen_machines[] = {guest_archs[i].hvm ? "xenfv" : "xenpv"}; + virCapsGuestMachinePtr *machines; + + if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL) + return -1; + + if ((guest = virCapabilitiesAddGuest(caps, + guest_archs[i].hvm ? VIR_DOMAIN_OSTYPE_HVM : VIR_DOMAIN_OSTYPE_XEN, + guest_archs[i].arch, + LIBXL_EXECBIN_DIR "/qemu-system-i386", + (guest_archs[i].hvm ? + LIBXL_FIRMWARE_DIR "/hvmloader" : + NULL), + 1, + machines)) == NULL) { + virCapabilitiesFreeMachines(machines, 1); + return -1; + } + machines = NULL; + + if (virCapabilitiesAddGuestDomain(guest, + VIR_DOMAIN_VIRT_XEN, + NULL, + NULL, + 0, + NULL) == NULL) + return -1; + + if (guest_archs[i].pae && + virCapabilitiesAddGuestFeature(guest, + "pae", + 1, + 0) == NULL) + return -1; + + if (guest_archs[i].nonpae && + virCapabilitiesAddGuestFeature(guest, + "nonpae", + 1, + 0) == NULL) + return -1; + + if (guest_archs[i].ia64_be && + virCapabilitiesAddGuestFeature(guest, + "ia64_be", + 1, + 0) == NULL) + return -1; + + if (guest_archs[i].hvm) { + if (virCapabilitiesAddGuestFeature(guest, + "acpi", + 1, + 1) == NULL) + return -1; + + if (virCapabilitiesAddGuestFeature(guest, "apic", + 1, + 0) == NULL) + return -1; + + if (virCapabilitiesAddGuestFeature(guest, + "hap", + 1, + 1) == NULL) + return -1; + } + } + + return 0; +} + +virCapsPtr +libxlMakeCapabilities(libxl_ctx *ctx) +{ + virCapsPtr caps; + +#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME + if ((caps = virCapabilitiesNew(virArchFromHost(), false, false)) == NULL) +#else + if ((caps = virCapabilitiesNew(virArchFromHost(), true, true)) == NULL) +#endif + return NULL; + + if (libxlCapsInitHost(ctx, caps) < 0) + goto error; + + if (libxlCapsInitNuma(ctx, caps) < 0) + goto error; + + if (libxlCapsInitGuests(ctx, caps) < 0) + goto error; + + return caps; + + error: + virObjectUnref(caps); + return NULL; +} + +#define LIBXL_QEMU_DM_STR "Options specific to the Xen version:" + +int +libxlDomainGetEmulatorType(const virDomainDef *def) +{ + int ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN; + virCommandPtr cmd = NULL; + char *output = NULL; + + if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { + if (def->emulator) { + cmd = virCommandNew(def->emulator); + + virCommandAddArgList(cmd, "-help", NULL); + virCommandSetOutputBuffer(cmd, &output); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + if (strstr(output, LIBXL_QEMU_DM_STR)) + ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL; + } + } + + cleanup: + VIR_FREE(output); + virCommandFree(cmd); + return ret; +} diff --git a/src/libxl/libxl_capabilities.h b/src/libxl/libxl_capabilities.h new file mode 100644 index 0000000..df1c327 --- /dev/null +++ b/src/libxl/libxl_capabilities.h @@ -0,0 +1,50 @@ +/* + * libxl_capabilities.h: libxl capabilities generation + * + * Copyright (C) 2016 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Jim Fehlig <jfehlig@suse.com> + */ + +#ifndef LIBXL_CAPABILITIES_H +# define LIBXL_CAPABILITIES_H + +# include <libxl.h> + +# include "virobject.h" +# include "capabilities.h" + + +# ifndef LIBXL_FIRMWARE_DIR +# define LIBXL_FIRMWARE_DIR "/usr/lib/xen/boot" +# endif +# ifndef LIBXL_EXECBIN_DIR +# define LIBXL_EXECBIN_DIR "/usr/lib/xen/bin" +# endif + +/* Used for prefix of ifname of any network name generated dynamically + * by libvirt for Xen, and cannot be used for a persistent network name. */ +# define LIBXL_GENERATED_PREFIX_XEN "vif" + + +virCapsPtr +libxlMakeCapabilities(libxl_ctx *ctx); + +int +libxlDomainGetEmulatorType(const virDomainDef *def); + +#endif /* LIBXL_CAPABILITIES_H */ diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 30f2ce9..0db4afd 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -40,7 +40,6 @@ #include "virstring.h" #include "viralloc.h" #include "viruuid.h" -#include "capabilities.h" #include "vircommand.h" #include "libxl_domain.h" #include "libxl_conf.h" @@ -53,21 +52,6 @@ VIR_LOG_INIT("libxl.libxl_conf"); -/* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */ -#define LIBXL_X86_FEATURE_PAE_MASK 0x40 - - -struct guest_arch { - virArch arch; - int bits; - int hvm; - int pae; - int nonpae; - int ia64_be; -}; - -#define XEN_CAP_REGEX "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(aarch64|armv7l|x86_32|x86_64|ia64|powerpc64)(p|be)?" - static virClassPtr libxlDriverConfigClass; static void libxlDriverConfigDispose(void *obj); @@ -163,346 +147,6 @@ libxlActionFromVirLifecycleCrash(virDomainLifecycleCrashAction action) static int -libxlCapsInitHost(libxl_ctx *ctx, virCapsPtr caps) -{ - libxl_physinfo phy_info; - int host_pae; - - if (libxl_get_physinfo(ctx, &phy_info) != 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Failed to get node physical info from libxenlight")); - return -1; - } - - /* hw_caps is an array of 32-bit words whose meaning is listed in - * xen-unstable.hg/xen/include/asm-x86/cpufeature.h. Each feature - * is defined in the form X*32+Y, corresponding to the Y'th bit in - * the X'th 32-bit word of hw_cap. - */ - host_pae = phy_info.hw_cap[0] & LIBXL_X86_FEATURE_PAE_MASK; - if (host_pae && - virCapabilitiesAddHostFeature(caps, "pae") < 0) - return -1; - - if (virCapabilitiesSetNetPrefix(caps, LIBXL_GENERATED_PREFIX_XEN) < 0) - return -1; - - return 0; -} - -static int -libxlCapsInitNuma(libxl_ctx *ctx, virCapsPtr caps) -{ - libxl_numainfo *numa_info = NULL; - libxl_cputopology *cpu_topo = NULL; - int nr_nodes = 0, nr_cpus = 0; - virCapsHostNUMACellCPUPtr *cpus = NULL; - int *nr_cpus_node = NULL; - size_t i; - int ret = -1; - - /* Let's try to fetch all the topology information */ - numa_info = libxl_get_numainfo(ctx, &nr_nodes); - if (numa_info == NULL || nr_nodes == 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("libxl_get_numainfo failed")); - goto cleanup; - } else { - cpu_topo = libxl_get_cpu_topology(ctx, &nr_cpus); - if (cpu_topo == NULL || nr_cpus == 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("libxl_get_cpu_topology failed")); - goto cleanup; - } - } - - if (VIR_ALLOC_N(cpus, nr_nodes) < 0) - goto cleanup; - - if (VIR_ALLOC_N(nr_cpus_node, nr_nodes) < 0) - goto cleanup; - - /* For each node, prepare a list of CPUs belonging to that node */ - for (i = 0; i < nr_cpus; i++) { - int node = cpu_topo[i].node; - - if (cpu_topo[i].core == LIBXL_CPUTOPOLOGY_INVALID_ENTRY) - continue; - - nr_cpus_node[node]++; - - if (nr_cpus_node[node] == 1) { - if (VIR_ALLOC(cpus[node]) < 0) - goto cleanup; - } else { - if (VIR_REALLOC_N(cpus[node], nr_cpus_node[node]) < 0) - goto cleanup; - } - - /* Mapping between what libxl tells and what libvirt wants */ - cpus[node][nr_cpus_node[node]-1].id = i; - cpus[node][nr_cpus_node[node]-1].socket_id = cpu_topo[i].socket; - cpus[node][nr_cpus_node[node]-1].core_id = cpu_topo[i].core; - /* Allocate the siblings maps. We will be filling them later */ - cpus[node][nr_cpus_node[node]-1].siblings = virBitmapNew(nr_cpus); - if (!cpus[node][nr_cpus_node[node]-1].siblings) { - virReportOOMError(); - goto cleanup; - } - } - - /* Let's now populate the siblings bitmaps */ - for (i = 0; i < nr_cpus; i++) { - int node = cpu_topo[i].node; - size_t j; - - if (cpu_topo[i].core == LIBXL_CPUTOPOLOGY_INVALID_ENTRY) - continue; - - for (j = 0; j < nr_cpus_node[node]; j++) { - if (cpus[node][j].socket_id == cpu_topo[i].socket && - cpus[node][j].core_id == cpu_topo[i].core) - ignore_value(virBitmapSetBit(cpus[node][j].siblings, i)); - } - } - - for (i = 0; i < nr_nodes; i++) { - if (numa_info[i].size == LIBXL_NUMAINFO_INVALID_ENTRY) - continue; - - if (virCapabilitiesAddHostNUMACell(caps, i, - numa_info[i].size / 1024, - nr_cpus_node[i], cpus[i], - 0, NULL, - 0, NULL) < 0) { - virCapabilitiesClearHostNUMACellCPUTopology(cpus[i], - nr_cpus_node[i]); - goto cleanup; - } - - /* This is safe, as the CPU list is now stored in the NUMA cell */ - cpus[i] = NULL; - } - - ret = 0; - - cleanup: - if (ret != 0) { - for (i = 0; cpus && i < nr_nodes; i++) - VIR_FREE(cpus[i]); - virCapabilitiesFreeNUMAInfo(caps); - } - - VIR_FREE(cpus); - VIR_FREE(nr_cpus_node); - libxl_cputopology_list_free(cpu_topo, nr_cpus); - libxl_numainfo_list_free(numa_info, nr_nodes); - - return ret; -} - -static int -libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps) -{ - const libxl_version_info *ver_info; - int err; - regex_t regex; - char *str, *token; - regmatch_t subs[4]; - char *saveptr = NULL; - size_t i; - - struct guest_arch guest_archs[32]; - int nr_guest_archs = 0; - - memset(guest_archs, 0, sizeof(guest_archs)); - - if ((ver_info = libxl_get_version_info(ctx)) == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Failed to get version info from libxenlight")); - return -1; - } - - if (!ver_info->capabilities) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Failed to get capabilities from libxenlight")); - return -1; - } - - err = regcomp(®ex, XEN_CAP_REGEX, REG_EXTENDED); - if (err != 0) { - char error[100]; - regerror(err, ®ex, error, sizeof(error)); - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to compile regex %s"), error); - return -1; - } - - /* Format of capabilities string is documented in the code in - * xen-unstable.hg/xen/arch/.../setup.c. - * - * It is a space-separated list of supported guest architectures. - * - * For x86: - * TYP-VER-ARCH[p] - * ^ ^ ^ ^ - * | | | +-- PAE supported - * | | +------- x86_32 or x86_64 - * | +----------- the version of Xen, eg. "3.0" - * +--------------- "xen" or "hvm" for para or full virt respectively - * - * For IA64: - * TYP-VER-ARCH[be] - * ^ ^ ^ ^ - * | | | +-- Big-endian supported - * | | +------- always "ia64" - * | +----------- the version of Xen, eg. "3.0" - * +--------------- "xen" or "hvm" for para or full virt respectively - */ - - /* Split capabilities string into tokens. strtok_r is OK here because - * we "own" the buffer. Parse out the features from each token. - */ - for (str = ver_info->capabilities, nr_guest_archs = 0; - nr_guest_archs < sizeof(guest_archs) / sizeof(guest_archs[0]) - && (token = strtok_r(str, " ", &saveptr)) != NULL; - str = NULL) { - if (regexec(®ex, token, sizeof(subs) / sizeof(subs[0]), - subs, 0) == 0) { - int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm"); - virArch arch; - int pae = 0, nonpae = 0, ia64_be = 0; - - if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) { - arch = VIR_ARCH_I686; - if (subs[3].rm_so != -1 && - STRPREFIX(&token[subs[3].rm_so], "p")) - pae = 1; - else - nonpae = 1; - } else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) { - arch = VIR_ARCH_X86_64; - } else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) { - arch = VIR_ARCH_ITANIUM; - if (subs[3].rm_so != -1 && - STRPREFIX(&token[subs[3].rm_so], "be")) - ia64_be = 1; - } else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) { - arch = VIR_ARCH_PPC64; - } else if (STRPREFIX(&token[subs[2].rm_so], "armv7l")) { - arch = VIR_ARCH_ARMV7L; - } else if (STRPREFIX(&token[subs[2].rm_so], "aarch64")) { - arch = VIR_ARCH_AARCH64; - } else { - continue; - } - - /* Search for existing matching (model,hvm) tuple */ - for (i = 0; i < nr_guest_archs; i++) { - if ((guest_archs[i].arch == arch) && - guest_archs[i].hvm == hvm) - break; - } - - /* Too many arch flavours - highly unlikely ! */ - if (i >= ARRAY_CARDINALITY(guest_archs)) - continue; - /* Didn't find a match, so create a new one */ - if (i == nr_guest_archs) - nr_guest_archs++; - - guest_archs[i].arch = arch; - guest_archs[i].hvm = hvm; - - /* Careful not to overwrite a previous positive - setting with a negative one here - some archs - can do both pae & non-pae, but Xen reports - separately capabilities so we're merging archs */ - if (pae) - guest_archs[i].pae = pae; - if (nonpae) - guest_archs[i].nonpae = nonpae; - if (ia64_be) - guest_archs[i].ia64_be = ia64_be; - } - } - regfree(®ex); - - for (i = 0; i < nr_guest_archs; ++i) { - virCapsGuestPtr guest; - char const *const xen_machines[] = {guest_archs[i].hvm ? "xenfv" : "xenpv"}; - virCapsGuestMachinePtr *machines; - - if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL) - return -1; - - if ((guest = virCapabilitiesAddGuest(caps, - guest_archs[i].hvm ? VIR_DOMAIN_OSTYPE_HVM : VIR_DOMAIN_OSTYPE_XEN, - guest_archs[i].arch, - LIBXL_EXECBIN_DIR "/qemu-system-i386", - (guest_archs[i].hvm ? - LIBXL_FIRMWARE_DIR "/hvmloader" : - NULL), - 1, - machines)) == NULL) { - virCapabilitiesFreeMachines(machines, 1); - return -1; - } - machines = NULL; - - if (virCapabilitiesAddGuestDomain(guest, - VIR_DOMAIN_VIRT_XEN, - NULL, - NULL, - 0, - NULL) == NULL) - return -1; - - if (guest_archs[i].pae && - virCapabilitiesAddGuestFeature(guest, - "pae", - 1, - 0) == NULL) - return -1; - - if (guest_archs[i].nonpae && - virCapabilitiesAddGuestFeature(guest, - "nonpae", - 1, - 0) == NULL) - return -1; - - if (guest_archs[i].ia64_be && - virCapabilitiesAddGuestFeature(guest, - "ia64_be", - 1, - 0) == NULL) - return -1; - - if (guest_archs[i].hvm) { - if (virCapabilitiesAddGuestFeature(guest, - "acpi", - 1, - 1) == NULL) - return -1; - - if (virCapabilitiesAddGuestFeature(guest, "apic", - 1, - 0) == NULL) - return -1; - - if (virCapabilitiesAddGuestFeature(guest, - "hap", - 1, - 1) == NULL) - return -1; - } - } - - return 0; -} - -static int libxlMakeDomCreateInfo(libxl_ctx *ctx, virDomainDefPtr def, libxl_domain_create_info *c_info) @@ -905,37 +549,6 @@ libxlDiskSetDiscard(libxl_device_disk *x_disk, int discard) } -#define LIBXL_QEMU_DM_STR "Options specific to the Xen version:" - -int -libxlDomainGetEmulatorType(const virDomainDef *def) -{ - int ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN; - virCommandPtr cmd = NULL; - char *output = NULL; - - if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { - if (def->emulator) { - cmd = virCommandNew(def->emulator); - - virCommandAddArgList(cmd, "-help", NULL); - virCommandSetOutputBuffer(cmd, &output); - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - if (strstr(output, LIBXL_QEMU_DM_STR)) - ret = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL; - } - } - - cleanup: - VIR_FREE(output); - virCommandFree(cmd); - return ret; -} - - static char * libxlMakeNetworkDiskSrcStr(virStorageSourcePtr src, const char *username, @@ -2021,34 +1634,6 @@ libxlDriverNodeGetInfo(libxlDriverPrivatePtr driver, virNodeInfoPtr info) return ret; } -virCapsPtr -libxlMakeCapabilities(libxl_ctx *ctx) -{ - virCapsPtr caps; - -#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME - if ((caps = virCapabilitiesNew(virArchFromHost(), false, false)) == NULL) -#else - if ((caps = virCapabilitiesNew(virArchFromHost(), true, true)) == NULL) -#endif - return NULL; - - if (libxlCapsInitHost(ctx, caps) < 0) - goto error; - - if (libxlCapsInitNuma(ctx, caps) < 0) - goto error; - - if (libxlCapsInitGuests(ctx, caps) < 0) - goto error; - - return caps; - - error: - virObjectUnref(caps); - return NULL; -} - int libxlBuildDomainConfig(virPortAllocatorPtr graphicsports, virDomainDefPtr def, diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index 24e2911..984434a 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -39,6 +39,7 @@ # include "virchrdev.h" # include "virhostdev.h" # include "locking/lock_manager.h" +# include "libxl_capabilities.h" # define LIBXL_DRIVER_NAME "xenlight" # define LIBXL_VNC_PORT_MIN 5900 @@ -47,10 +48,6 @@ # define LIBXL_MIGRATION_PORT_MIN 49152 # define LIBXL_MIGRATION_PORT_MAX 49216 -/* Used for prefix of ifname of any network name generated dynamically - * by libvirt for Xen, and cannot be used for a persistent network name. */ -# define LIBXL_GENERATED_PREFIX_XEN "vif" - # define LIBXL_CONFIG_BASE_DIR SYSCONFDIR "/libvirt" # define LIBXL_CONFIG_DIR SYSCONFDIR "/libvirt/libxl" # define LIBXL_AUTOSTART_DIR LIBXL_CONFIG_DIR "/autostart" @@ -61,13 +58,6 @@ # define LIBXL_DUMP_DIR LIBXL_LIB_DIR "/dump" # define LIBXL_BOOTLOADER_PATH "pygrub" -# ifndef LIBXL_FIRMWARE_DIR -# define LIBXL_FIRMWARE_DIR "/usr/lib/xen/boot" -# endif -# ifndef LIBXL_EXECBIN_DIR -# define LIBXL_EXECBIN_DIR "/usr/lib/xen/bin" -# endif - typedef struct _libxlDriverPrivate libxlDriverPrivate; typedef libxlDriverPrivate *libxlDriverPrivatePtr; @@ -173,12 +163,6 @@ libxlDriverNodeGetInfo(libxlDriverPrivatePtr driver, int libxlDriverConfigLoadFile(libxlDriverConfigPtr cfg, const char *filename); -virCapsPtr -libxlMakeCapabilities(libxl_ctx *ctx); - -int -libxlDomainGetEmulatorType(const virDomainDef *def); - int libxlMakeDisk(virDomainDiskDefPtr l_dev, libxl_device_disk *x_dev); int diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 14a900c..b11f39d 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -26,6 +26,7 @@ #include <fcntl.h> #include "libxl_domain.h" +#include "libxl_capabilities.h" #include "viralloc.h" #include "viratomic.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index bf97c9c..b0df58c 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -45,6 +45,7 @@ #include "libxl_domain.h" #include "libxl_driver.h" #include "libxl_conf.h" +#include "libxl_capabilities.h" #include "libxl_migration.h" #include "xen_xm.h" #include "xen_sxpr.h" -- 2.1.4

Add domain capabilities for PV and HVM domains. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_capabilities.c | 103 ++++++++++++++++++++++++ src/libxl/libxl_capabilities.h | 4 + src/libxl/libxl_driver.c | 68 ++++++++++++++++ tests/Makefile.am | 5 ++ tests/domaincapsschemadata/domaincaps-xenfv.xml | 51 ++++++++++++ tests/domaincapsschemadata/domaincaps-xenpv.xml | 44 ++++++++++ tests/domaincapstest.c | 33 ++++++++ tests/testutilsxen.h | 1 + 8 files changed, 309 insertions(+) diff --git a/src/libxl/libxl_capabilities.c b/src/libxl/libxl_capabilities.c index 6734b2a..f5fa90e 100644 --- a/src/libxl/libxl_capabilities.c +++ b/src/libxl/libxl_capabilities.c @@ -29,8 +29,10 @@ #include "virlog.h" #include "virerror.h" #include "viralloc.h" +#include "virstring.h" #include "domain_conf.h" #include "capabilities.h" +#include "domain_capabilities.h" #include "vircommand.h" #include "libxl_capabilities.h" @@ -395,6 +397,76 @@ libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps) return 0; } +static int +libxlMakeDomainOSCaps(const char *machine, virDomainCapsOSPtr os) +{ + virDomainCapsLoaderPtr capsLoader = &os->loader; + + os->supported = true; + + if (STREQ(machine, "xenpv")) + return 0; + + capsLoader->supported = true; + if (VIR_ALLOC_N(capsLoader->values.values, 2) < 0) + return -1; + + if (VIR_STRDUP(capsLoader->values.values[0], + LIBXL_FIRMWARE_DIR "/hvmloader") < 0) + return -1; + if (VIR_STRDUP(capsLoader->values.values[1], + LIBXL_FIRMWARE_DIR "/ovmf.bin") < 0) + return -1; + capsLoader->values.nvalues = 2; + VIR_DOMAIN_CAPS_ENUM_SET(capsLoader->type, + VIR_DOMAIN_LOADER_TYPE_ROM); + + return 0; +} + +static int +libxlMakeDomainDeviceDiskCaps(virDomainCapsDeviceDiskPtr disk) +{ + disk->supported = true; + + VIR_DOMAIN_CAPS_ENUM_SET(disk->diskDevice, + VIR_DOMAIN_DISK_DEVICE_DISK, + VIR_DOMAIN_DISK_DEVICE_CDROM); + + VIR_DOMAIN_CAPS_ENUM_SET(disk->bus, + VIR_DOMAIN_DISK_BUS_IDE, + VIR_DOMAIN_DISK_BUS_SCSI, + VIR_DOMAIN_DISK_BUS_XEN); + + return 0; +} + +static int +libxlMakeDomainDeviceHostdevCaps(virDomainCapsDeviceHostdevPtr hostdev) +{ + hostdev->supported = true; + /* VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES is for containers only */ + VIR_DOMAIN_CAPS_ENUM_SET(hostdev->mode, + VIR_DOMAIN_HOSTDEV_MODE_SUBSYS); + + VIR_DOMAIN_CAPS_ENUM_SET(hostdev->startupPolicy, + VIR_DOMAIN_STARTUP_POLICY_DEFAULT, + VIR_DOMAIN_STARTUP_POLICY_MANDATORY, + VIR_DOMAIN_STARTUP_POLICY_REQUISITE, + VIR_DOMAIN_STARTUP_POLICY_OPTIONAL); + + VIR_DOMAIN_CAPS_ENUM_SET(hostdev->subsysType, + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI); + + /* No virDomainHostdevCapsType for libxl */ + virDomainCapsEnumClear(&hostdev->capsType); + + virDomainCapsEnumClear(&hostdev->pciBackend); + VIR_DOMAIN_CAPS_ENUM_SET(hostdev->pciBackend, + VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN); + return 0; +} + virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx) { @@ -423,6 +495,37 @@ libxlMakeCapabilities(libxl_ctx *ctx) return NULL; } + +/* + * Currently Xen has no interface to report maxvcpus supported + * for the various domain types (PV, HVM, PVH). HVM_MAX_VCPUS + * is defined in $xensrc/xen/include/public/hvm/hvm_info_table.h + * PV has no equivalent and is relunctantly set here until Xen + * can report such capabilities. + */ +#define HVM_MAX_VCPUS 128 +#define PV_MAX_VCPUS 512 + +int +libxlMakeDomainCapabilities(virDomainCapsPtr domCaps) +{ + virDomainCapsOSPtr os = &domCaps->os; + virDomainCapsDeviceDiskPtr disk = &domCaps->disk; + virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev; + + if (STREQ(domCaps->machine, "xenfv")) + domCaps->maxvcpus = HVM_MAX_VCPUS; + else + domCaps->maxvcpus = PV_MAX_VCPUS; + + if (libxlMakeDomainOSCaps(domCaps->machine, os) < 0 || + libxlMakeDomainDeviceDiskCaps(disk) < 0 || + libxlMakeDomainDeviceHostdevCaps(hostdev) < 0) + return -1; + return 0; +} + + #define LIBXL_QEMU_DM_STR "Options specific to the Xen version:" int diff --git a/src/libxl/libxl_capabilities.h b/src/libxl/libxl_capabilities.h index df1c327..b101ef0 100644 --- a/src/libxl/libxl_capabilities.h +++ b/src/libxl/libxl_capabilities.h @@ -27,6 +27,7 @@ # include "virobject.h" # include "capabilities.h" +# include "domain_capabilities.h" # ifndef LIBXL_FIRMWARE_DIR @@ -45,6 +46,9 @@ virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx); int +libxlMakeDomainCapabilities(virDomainCapsPtr domCaps); + +int libxlDomainGetEmulatorType(const virDomainDef *def); #endif /* LIBXL_CAPABILITIES_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index b0df58c..b3c3ab6 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -5421,6 +5421,73 @@ static int libxlNodeGetSecurityModel(virConnectPtr conn, return 0; } +static char * +libxlConnectGetDomainCapabilities(virConnectPtr conn, + const char *emulatorbin, + const char *arch_str, + const char *machine, + const char *virttype_str, + unsigned int flags) +{ + char *ret = NULL; + int virttype = VIR_DOMAIN_VIRT_XEN; + virDomainCapsPtr domCaps = NULL; + int arch = virArchFromHost(); /* virArch */ + + virCheckFlags(0, ret); + + if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0) + return ret; + + if (virttype_str && + (virttype = virDomainVirtTypeFromString(virttype_str)) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown virttype: %s"), + virttype_str); + goto cleanup; + } + + if (virttype != VIR_DOMAIN_VIRT_XEN) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown virttype: %s"), + virttype_str); + goto cleanup; + } + + if (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown architecture: %s"), + arch_str); + goto cleanup; + } + + if (emulatorbin == NULL) + emulatorbin = "/usr/bin/qemu-system-x86_64"; + + if (machine) { + if (STRNEQ(machine, "xenpv") && STRNEQ(machine, "xenfv")) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Xen only supports 'xenpv' and 'xenfv' machines")); + goto cleanup; + } + } else { + machine = "xenpv"; + } + + if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype))) + goto cleanup; + + if (libxlMakeDomainCapabilities(domCaps) < 0) + goto cleanup; + + ret = virDomainCapsFormat(domCaps); + + cleanup: + virObjectUnref(domCaps); + return ret; +} + + static virHypervisorDriver libxlHypervisorDriver = { .name = LIBXL_DRIVER_NAME, .connectOpen = libxlConnectOpen, /* 0.9.0 */ @@ -5521,6 +5588,7 @@ static virHypervisorDriver libxlHypervisorDriver = { .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */ .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */ .nodeGetSecurityModel = libxlNodeGetSecurityModel, /* 1.2.16 */ + .connectGetDomainCapabilities = libxlConnectGetDomainCapabilities, /* 1.3.4 */ }; static virConnectDriver libxlConnectDriver = { diff --git a/tests/Makefile.am b/tests/Makefile.am index db4f88b..f79b552 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -925,6 +925,11 @@ domaincapstest_SOURCES += testutilsqemu.c testutilsqemu.h domaincapstest_LDADD += $(qemu_LDADDS) $(GNULIB_LIBS) endif WITH_QEMU +if WITH_LIBXL +domaincapstest_SOURCES += testutilsxen.h +domaincapstest_LDADD += $(libxl_LDADDS) +endif WITH_LIBXL + if WITH_LIBVIRTD libvirtdconftest_SOURCES = \ libvirtdconftest.c testutils.h testutils.c \ diff --git a/tests/domaincapsschemadata/domaincaps-xenfv.xml b/tests/domaincapsschemadata/domaincaps-xenfv.xml new file mode 100644 index 0000000..205853c --- /dev/null +++ b/tests/domaincapsschemadata/domaincaps-xenfv.xml @@ -0,0 +1,51 @@ +<domainCapabilities> + <path>/usr/bin/qemu-system-x86_64</path> + <domain>xen</domain> + <machine>xenfv</machine> + <arch>x86_64</arch> + <vcpu max='128'/> + <os supported='yes'> + <loader supported='yes'> + <value>/usr/lib/xen/boot/hvmloader</value> + <value>/usr/lib/xen/boot/ovmf.bin</value> + <enum name='type'> + <value>rom</value> + </enum> + <enum name='readonly'/> + </loader> + </os> + <devices> + <disk supported='yes'> + <enum name='diskDevice'> + <value>disk</value> + <value>cdrom</value> + </enum> + <enum name='bus'> + <value>ide</value> + <value>scsi</value> + <value>xen</value> + </enum> + </disk> + <hostdev supported='yes'> + <enum name='mode'> + <value>subsystem</value> + </enum> + <enum name='startupPolicy'> + <value>default</value> + <value>mandatory</value> + <value>requisite</value> + <value>optional</value> + </enum> + <enum name='subsysType'> + <value>pci</value> + </enum> + <enum name='capsType'/> + <enum name='pciBackend'> + <value>xen</value> + </enum> + </hostdev> + </devices> + <features> + <gic supported='no'/> + </features> +</domainCapabilities> diff --git a/tests/domaincapsschemadata/domaincaps-xenpv.xml b/tests/domaincapsschemadata/domaincaps-xenpv.xml new file mode 100644 index 0000000..22341ba --- /dev/null +++ b/tests/domaincapsschemadata/domaincaps-xenpv.xml @@ -0,0 +1,44 @@ +<domainCapabilities> + <path>/usr/bin/qemu-system-x86_64</path> + <domain>xen</domain> + <machine>xenpv</machine> + <arch>x86_64</arch> + <vcpu max='512'/> + <os supported='yes'> + <loader supported='no'/> + </os> + <devices> + <disk supported='yes'> + <enum name='diskDevice'> + <value>disk</value> + <value>cdrom</value> + </enum> + <enum name='bus'> + <value>ide</value> + <value>scsi</value> + <value>xen</value> + </enum> + </disk> + <hostdev supported='yes'> + <enum name='mode'> + <value>subsystem</value> + </enum> + <enum name='startupPolicy'> + <value>default</value> + <value>mandatory</value> + <value>requisite</value> + <value>optional</value> + </enum> + <enum name='subsysType'> + <value>pci</value> + </enum> + <enum name='capsType'/> + <enum name='pciBackend'> + <value>xen</value> + </enum> + </hostdev> + </devices> + <features> + <gic supported='no'/> + </features> +</domainCapabilities> diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index b6f6ac8..f8d2026 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -137,6 +137,21 @@ fillQemuCaps(virDomainCapsPtr domCaps, #endif /* WITH_QEMU */ +#ifdef WITH_LIBXL +# include "testutilsxen.h" + +static int +fillXenCaps(virDomainCapsPtr domCaps, + void *opaque ATTRIBUTE_UNUSED) +{ + if (libxlMakeDomainCapabilities(domCaps) < 0) + return -1; + + return 0; +} +#endif /* WITH_LIBXL */ + + static virDomainCapsPtr buildVirDomainCaps(const char *emulatorbin, const char *machine, @@ -251,6 +266,24 @@ mymain(void) virObjectUnref(cfg); #endif /* WITH_QEMU */ +#ifdef WITH_LIBXL + +# define DO_TEST_LIBXL(Filename, Emulatorbin, Machine, Arch, Type) \ + do { \ + struct test_virDomainCapsFormatData data = {.filename = Filename, \ + .emulatorbin = Emulatorbin, .machine = Machine, .arch = Arch, \ + .type = Type, .fillFunc = fillXenCaps}; \ + if (virtTestRun(Filename, test_virDomainCapsFormat, &data) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST_LIBXL("xenpv", "/usr/bin/qemu-system-x86_64", + "xenpv", VIR_ARCH_X86_64, VIR_DOMAIN_VIRT_XEN); + DO_TEST_LIBXL("xenfv", "/usr/bin/qemu-system-x86_64", + "xenfv", VIR_ARCH_X86_64, VIR_DOMAIN_VIRT_XEN); + +#endif /* WITH_LIBXL */ + return ret; } diff --git a/tests/testutilsxen.h b/tests/testutilsxen.h index c78350d..8b997c3 100644 --- a/tests/testutilsxen.h +++ b/tests/testutilsxen.h @@ -2,6 +2,7 @@ # define _TESTUTILSXEN_H_ # include "capabilities.h" +# include "libxl/libxl_capabilities.h" virCapsPtr testXenCapsInit(void); -- 2.1.4

Add support to xenconfig for conversion of xl.cfg(5) bios config to/from libvirt domXml <loader> config. SeaBIOS is the default for HVM guests using upstream QEMU. ROMBIOS is the default when using the old qemu-dm. This patch allows specifying OVMF as an alternate firmware. Example xl.cfg: bios = "ovmf" Example domXML: <os> ... <loader readonly='yes' type='pflash'>/usr/lib/xen/boot/ovmf.bin</loader> </os> An alternate OVMF firmware (from the one advertised in domaincapabilities) can be specified with bios = "ovmf" bios_override = "/path/to/my/ovmf.bin" Note that currently, Xen does not support a separate nvram for non-volatile variables. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/Makefile.am | 2 +- src/xenconfig/xen_xl.c | 50 ++++++++++++++++--- tests/xlconfigdata/test-fullvirt-ovmf-override.cfg | 27 ++++++++++ tests/xlconfigdata/test-fullvirt-ovmf-override.xml | 58 ++++++++++++++++++++++ tests/xlconfigdata/test-fullvirt-ovmf.cfg | 26 ++++++++++ tests/xlconfigdata/test-fullvirt-ovmf.xml | 58 ++++++++++++++++++++++ tests/xlconfigtest.c | 2 + 7 files changed, 216 insertions(+), 7 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 90f6b51..50edda2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1147,7 +1147,7 @@ noinst_LTLIBRARIES += libvirt_xenconfig.la libvirt_la_BUILT_LIBADD += libvirt_xenconfig.la libvirt_xenconfig_la_LIBADD = $(LIBXL_LIBS) libvirt_xenconfig_la_CFLAGS = \ - -I$(srcdir)/conf $(AM_CFLAGS) + -I$(srcdir)/conf -I$(srcdir)/libxl $(AM_CFLAGS) libvirt_xenconfig_la_SOURCES = $(XENCONFIG_SOURCES) endif WITH_XENCONFIG diff --git a/src/xenconfig/xen_xl.c b/src/xenconfig/xen_xl.c index 889dd40..a8dbeba 100644 --- a/src/xenconfig/xen_xl.c +++ b/src/xenconfig/xen_xl.c @@ -33,6 +33,7 @@ #include "virstring.h" #include "virstoragefile.h" #include "xen_xl.h" +#include "libxl_capabilities.h" #define VIR_FROM_THIS VIR_FROM_XENXL @@ -103,15 +104,40 @@ xenParseXLOS(virConfPtr conf, virDomainDefPtr def, virCapsPtr caps) size_t i; if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { + const char *bios; + const char *alt_bios; const char *boot; - for (i = 0; i < caps->nguests; i++) { - if (caps->guests[i]->ostype == VIR_DOMAIN_OSTYPE_HVM && - caps->guests[i]->arch.id == def->os.arch) { - if (VIR_ALLOC(def->os.loader) < 0 || - VIR_STRDUP(def->os.loader->path, - caps->guests[i]->arch.defaultInfo.loader) < 0) + if (xenConfigGetString(conf, "bios", &bios, NULL) < 0) + return -1; + + if (xenConfigGetString(conf, "bios_override", &alt_bios, NULL) < 0) + return -1; + + if (bios && STREQ(bios, "ovmf")) { + if (VIR_ALLOC(def->os.loader) < 0) + return -1; + + def->os.loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH; + def->os.loader->readonly = VIR_TRISTATE_BOOL_YES; + + if (alt_bios) { + if (VIR_STRDUP(def->os.loader->path, alt_bios) < 0) return -1; + } else { + if (VIR_STRDUP(def->os.loader->path, + LIBXL_FIRMWARE_DIR "/ovmf.bin") < 0) + return -1; + } + } else { + for (i = 0; i < caps->nguests; i++) { + if (caps->guests[i]->ostype == VIR_DOMAIN_OSTYPE_HVM && + caps->guests[i]->arch.id == def->os.arch) { + if (VIR_ALLOC(def->os.loader) < 0 || + VIR_STRDUP(def->os.loader->path, + caps->guests[i]->arch.defaultInfo.loader) < 0) + return -1; + } } } @@ -536,6 +562,18 @@ xenFormatXLOS(virConfPtr conf, virDomainDefPtr def) if (xenConfigSetString(conf, "builder", "hvm") < 0) return -1; + if (def->os.loader && + def->os.loader->type == VIR_DOMAIN_LOADER_TYPE_PFLASH) { + if (xenConfigSetString(conf, "bios", "ovmf") < 0) + return -1; + + if (STRNEQ(def->os.loader->path, LIBXL_FIRMWARE_DIR "/ovmf.bin")) { + if (xenConfigSetString(conf, "bios_override", + def->os.loader->path) < 0) + return -1; + } + } + #ifdef LIBXL_HAVE_BUILDINFO_KERNEL if (def->os.kernel && xenConfigSetString(conf, "kernel", def->os.kernel) < 0) diff --git a/tests/xlconfigdata/test-fullvirt-ovmf-override.cfg b/tests/xlconfigdata/test-fullvirt-ovmf-override.cfg new file mode 100644 index 0000000..46bd684 --- /dev/null +++ b/tests/xlconfigdata/test-fullvirt-ovmf-override.cfg @@ -0,0 +1,27 @@ +name = "XenGuest2" +uuid = "c7a5fdb2-cdaf-9455-926a-d65c16db1809" +maxmem = 579 +memory = 394 +vcpus = 1 +pae = 1 +acpi = 1 +apic = 1 +viridian = 0 +rtc_timeoffset = 0 +localtime = 0 +on_poweroff = "destroy" +on_reboot = "restart" +on_crash = "restart" +device_model = "/usr/lib/xen/bin/qemu-dm" +sdl = 0 +vnc = 1 +vncunused = 1 +vnclisten = "127.0.0.1" +vif = [ "mac=00:16:3e:66:92:9c,bridge=xenbr1,script=vif-bridge,model=e1000" ] +parallel = "none" +serial = "none" +builder = "hvm" +bios = "ovmf" +bios_override = "/usr/share/qemu/ovmf-x86_64.bin" +boot = "d" +disk = [ "format=raw,vdev=hda,access=rw,backendtype=phy,target=/dev/HostVG/XenGuest2", "format=qcow2,vdev=hdb,access=rw,backendtype=qdisk,target=/var/lib/libvirt/images/XenGuest2-home", "format=raw,vdev=hdc,access=ro,backendtype=qdisk,devtype=cdrom,target=/root/boot.iso" ] diff --git a/tests/xlconfigdata/test-fullvirt-ovmf-override.xml b/tests/xlconfigdata/test-fullvirt-ovmf-override.xml new file mode 100644 index 0000000..81dca36 --- /dev/null +++ b/tests/xlconfigdata/test-fullvirt-ovmf-override.xml @@ -0,0 +1,58 @@ +<domain type='xen'> + <name>XenGuest2</name> + <uuid>c7a5fdb2-cdaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>592896</memory> + <currentMemory unit='KiB'>403456</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='xenfv'>hvm</type> + <loader readonly='yes' type='pflash'>/usr/share/qemu/ovmf-x86_64.bin</loader> + <boot dev='cdrom'/> + </os> + <features> + <acpi/> + <apic/> + <pae/> + </features> + <clock offset='variable' adjustment='0' basis='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <disk type='block' device='disk'> + <driver name='phy' type='raw'/> + <source dev='/dev/HostVG/XenGuest2'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/var/lib/libvirt/images/XenGuest2-home'/> + <target dev='hdb' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='1'/> + </disk> + <disk type='file' device='cdrom'> + <driver name='qemu' type='raw'/> + <source file='/root/boot.iso'/> + <target dev='hdc' bus='ide'/> + <readonly/> + <address type='drive' controller='0' bus='1' target='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + <interface type='bridge'> + <mac address='00:16:3e:66:92:9c'/> + <source bridge='xenbr1'/> + <script path='vif-bridge'/> + <model type='e1000'/> + </interface> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <video> + <model type='cirrus' heads='1' primary='yes'/> + </video> + </devices> +</domain> diff --git a/tests/xlconfigdata/test-fullvirt-ovmf.cfg b/tests/xlconfigdata/test-fullvirt-ovmf.cfg new file mode 100644 index 0000000..af0735e --- /dev/null +++ b/tests/xlconfigdata/test-fullvirt-ovmf.cfg @@ -0,0 +1,26 @@ +name = "XenGuest2" +uuid = "c7a5fdb2-cdaf-9455-926a-d65c16db1809" +maxmem = 579 +memory = 394 +vcpus = 1 +pae = 1 +acpi = 1 +apic = 1 +viridian = 0 +rtc_timeoffset = 0 +localtime = 0 +on_poweroff = "destroy" +on_reboot = "restart" +on_crash = "restart" +device_model = "/usr/lib/xen/bin/qemu-dm" +sdl = 0 +vnc = 1 +vncunused = 1 +vnclisten = "127.0.0.1" +vif = [ "mac=00:16:3e:66:92:9c,bridge=xenbr1,script=vif-bridge,model=e1000" ] +parallel = "none" +serial = "none" +builder = "hvm" +bios = "ovmf" +boot = "d" +disk = [ "format=raw,vdev=hda,access=rw,backendtype=phy,target=/dev/HostVG/XenGuest2", "format=qcow2,vdev=hdb,access=rw,backendtype=qdisk,target=/var/lib/libvirt/images/XenGuest2-home", "format=raw,vdev=hdc,access=ro,backendtype=qdisk,devtype=cdrom,target=/root/boot.iso" ] diff --git a/tests/xlconfigdata/test-fullvirt-ovmf.xml b/tests/xlconfigdata/test-fullvirt-ovmf.xml new file mode 100644 index 0000000..f4ad635 --- /dev/null +++ b/tests/xlconfigdata/test-fullvirt-ovmf.xml @@ -0,0 +1,58 @@ +<domain type='xen'> + <name>XenGuest2</name> + <uuid>c7a5fdb2-cdaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>592896</memory> + <currentMemory unit='KiB'>403456</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='xenfv'>hvm</type> + <loader readonly='yes' type='pflash'>/usr/lib/xen/boot/ovmf.bin</loader> + <boot dev='cdrom'/> + </os> + <features> + <acpi/> + <apic/> + <pae/> + </features> + <clock offset='variable' adjustment='0' basis='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/lib/xen/bin/qemu-dm</emulator> + <disk type='block' device='disk'> + <driver name='phy' type='raw'/> + <source dev='/dev/HostVG/XenGuest2'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/var/lib/libvirt/images/XenGuest2-home'/> + <target dev='hdb' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='1'/> + </disk> + <disk type='file' device='cdrom'> + <driver name='qemu' type='raw'/> + <source file='/root/boot.iso'/> + <target dev='hdc' bus='ide'/> + <readonly/> + <address type='drive' controller='0' bus='1' target='0' unit='0'/> + </disk> + <controller type='ide' index='0'/> + <interface type='bridge'> + <mac address='00:16:3e:66:92:9c'/> + <source bridge='xenbr1'/> + <script path='vif-bridge'/> + <model type='e1000'/> + </interface> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1'/> + </graphics> + <video> + <model type='cirrus' heads='1' primary='yes'/> + </video> + </devices> +</domain> diff --git a/tests/xlconfigtest.c b/tests/xlconfigtest.c index ba1bed0..31f40e6 100644 --- a/tests/xlconfigtest.c +++ b/tests/xlconfigtest.c @@ -219,6 +219,8 @@ mymain(void) DO_TEST_FORMAT("paravirt-cmdline-extra-root"); DO_TEST_FORMAT("paravirt-cmdline-bogus-extra-root"); DO_TEST("rbd-multihost-noauth"); + DO_TEST("fullvirt-ovmf"); + DO_TEST("fullvirt-ovmf-override"); #ifdef LIBXL_HAVE_BUILDINFO_USBDEVICE_LIST DO_TEST("fullvirt-multiusb"); -- 2.1.4

Populate libxl_domain_build_info struct with bios and firmware info from virDomainLoaderDef. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_conf.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 0db4afd..c8efeb7 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -394,6 +394,14 @@ libxlMakeDomBuildInfo(virDomainDefPtr def, return -1; #endif + if (def->os.loader && + def->os.loader->type == VIR_DOMAIN_LOADER_TYPE_PFLASH) { + b_info->u.hvm.bios = LIBXL_BIOS_TYPE_OVMF; + if (STRNEQ(def->os.loader->path, LIBXL_FIRMWARE_DIR "/ovmf.bin")) + if (VIR_STRDUP(b_info->u.hvm.firmware, def->os.loader->path) < 0) + return -1; + } + if (def->emulator) { if (!virFileExists(def->emulator)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, -- 2.1.4
participants (1)
-
Jim Fehlig