[libvirt] [RESEND PATCH V2 0/6] libxl: Add support for UEFI using OVMF

This is essentially a V2 of https://www.redhat.com/archives/libvir-list/2016-April/msg01358.html To avoid code duplication in that series, I proposed adding a virFirmware object that could be used by multiple drivers https://www.redhat.com/archives/libvir-list/2016-May/msg01370.html mprivozn ACK'ed that series, but I deferred committing it until 1.3.5 was released since it's not all that useful without accompanying use by another driver. This series includes all the patches rebased and tested against latest git master. Note: I sent this series yesterday, but int-mx.corp.redhat.com rejected 0/6 and 3/6 with "550 5.1.1 <libvir-list redhat com>... User unknown (in reply to RCPT TO command)". I'm resending in hopes that all patches make it through this time. Jim Fehlig (6): driver config: Introduce virFirmware object libxl: add default firmwares to driver config object libxl: introduce libxl_capabilities.{ch} libxl: implement connectGetDomainCapabilities xenconfig: support bios=ovmf xl.cfg libxl: Add support for ovmf firmware po/POTFILES.in | 2 + src/Makefile.am | 12 +- src/libvirt_private.syms | 6 + src/libxl/libxl_capabilities.c | 598 +++++++++++++++++++++ src/libxl/libxl_capabilities.h | 57 ++ src/libxl/libxl_conf.c | 448 +-------------- src/libxl/libxl_conf.h | 22 +- src/libxl/libxl_domain.c | 1 + src/libxl/libxl_driver.c | 75 +++ src/qemu/qemu_capabilities.c | 22 +- src/qemu/qemu_capabilities.h | 5 +- src/qemu/qemu_conf.c | 127 +---- src/qemu/qemu_conf.h | 7 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_process.c | 6 +- src/util/virfirmware.c | 137 +++++ src/util/virfirmware.h | 51 ++ src/xenconfig/xen_xl.c | 50 +- tests/Makefile.am | 5 + tests/domaincapsschemadata/libxl-xenfv.xml | 68 +++ tests/domaincapsschemadata/libxl-xenpv.xml | 58 ++ tests/domaincapstest.c | 64 ++- 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 + 28 files changed, 1417 insertions(+), 578 deletions(-) create mode 100644 src/libxl/libxl_capabilities.c create mode 100644 src/libxl/libxl_capabilities.h create mode 100644 src/util/virfirmware.c create mode 100644 src/util/virfirmware.h create mode 100644 tests/domaincapsschemadata/libxl-xenfv.xml create mode 100644 tests/domaincapsschemadata/libxl-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.8.4

The virQEMUDriverConfig object contains lists of loader:nvram pairs to advertise firmwares supported by by the driver, and qemu_conf.c contains code to populate the lists, all of which is useful for other drivers too. To avoid code duplication, introduce a virFirmware object to encapsulate firmware details and switch the qemu driver to use it. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 6 ++ src/qemu/qemu_capabilities.c | 22 +++---- src/qemu/qemu_capabilities.h | 5 +- src/qemu/qemu_conf.c | 127 ++++++--------------------------------- src/qemu/qemu_conf.h | 7 +-- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_process.c | 6 +- src/util/virfirmware.c | 137 +++++++++++++++++++++++++++++++++++++++++++ src/util/virfirmware.h | 51 ++++++++++++++++ tests/domaincapstest.c | 3 +- 12 files changed, 237 insertions(+), 131 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 2a6fae4..85adaf3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -194,6 +194,7 @@ src/util/virerror.h src/util/vireventpoll.c src/util/virfile.c src/util/virfirewall.c +src/util/virfirmware.c src/util/virhash.c src/util/virhook.c src/util/virhostdev.c diff --git a/src/Makefile.am b/src/Makefile.am index 8c83b0c..9c4eb41 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -114,6 +114,7 @@ UTIL_SOURCES = \ util/virfile.c util/virfile.h \ util/virfirewall.c util/virfirewall.h \ util/virfirewallpriv.h \ + util/virfirmware.c util/virfirmware.h \ util/virgettext.c util/virgettext.h \ util/virgic.c util/virgic.h \ util/virhash.c util/virhash.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 42f664c..236cf52 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1562,6 +1562,12 @@ virFirewallStartRollback; virFirewallStartTransaction; +# util/virfirmware.h +virFirmwareFreeList; +virFirmwareParse; +virFirmwareParseList; + + # util/virgettext.h virGettextInitialize; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 00f6b40..c865784 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4071,18 +4071,18 @@ virQEMUCapsGetDefaultMachine(virQEMUCapsPtr qemuCaps) static int virQEMUCapsFillDomainLoaderCaps(virDomainCapsLoaderPtr capsLoader, - char **loader, - size_t nloader) + virFirmwarePtr *firmwares, + size_t nfirmwares) { size_t i; capsLoader->supported = true; - if (VIR_ALLOC_N(capsLoader->values.values, nloader) < 0) + if (VIR_ALLOC_N(capsLoader->values.values, nfirmwares) < 0) return -1; - for (i = 0; i < nloader; i++) { - const char *filename = loader[i]; + for (i = 0; i < nfirmwares; i++) { + const char *filename = firmwares[i]->name; if (!virFileExists(filename)) { VIR_DEBUG("loader filename=%s does not exist", filename); @@ -4111,13 +4111,13 @@ virQEMUCapsFillDomainLoaderCaps(virDomainCapsLoaderPtr capsLoader, static int virQEMUCapsFillDomainOSCaps(virDomainCapsOSPtr os, - char **loader, - size_t nloader) + virFirmwarePtr *firmwares, + size_t nfirmwares) { virDomainCapsLoaderPtr capsLoader = &os->loader; os->supported = true; - if (virQEMUCapsFillDomainLoaderCaps(capsLoader, loader, nloader) < 0) + if (virQEMUCapsFillDomainLoaderCaps(capsLoader, firmwares, nfirmwares) < 0) return -1; return 0; } @@ -4330,8 +4330,8 @@ virQEMUCapsFillDomainFeatureGICCaps(virQEMUCapsPtr qemuCaps, int virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps, virQEMUCapsPtr qemuCaps, - char **loader, - size_t nloader) + virFirmwarePtr *firmwares, + size_t nfirmwares) { virDomainCapsOSPtr os = &domCaps->os; virDomainCapsDeviceDiskPtr disk = &domCaps->disk; @@ -4342,7 +4342,7 @@ virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps, domCaps->maxvcpus = maxvcpus; - if (virQEMUCapsFillDomainOSCaps(os, loader, nloader) < 0 || + if (virQEMUCapsFillDomainOSCaps(os, firmwares, nfirmwares) < 0 || virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, domCaps->machine, disk) < 0 || virQEMUCapsFillDomainDeviceGraphicsCaps(qemuCaps, graphics) < 0 || diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index e273f2a..d33ba00 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -29,6 +29,7 @@ # include "vircommand.h" # include "qemu_monitor.h" # include "domain_capabilities.h" +# include "virfirmware.h" /* * Internal flags to keep track of qemu command line capabilities @@ -491,7 +492,7 @@ int virQEMUCapsInitGuestFromBinary(virCapsPtr caps, int virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps, virQEMUCapsPtr qemuCaps, - char **loader, - size_t nloader); + virFirmwarePtr *firmwares, + size_t nfirmwares); #endif /* __QEMU_CAPABILITIES_H__*/ diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index d4c34c9..6dfa738 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -124,47 +124,6 @@ void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def) } -static int ATTRIBUTE_UNUSED -virQEMUDriverConfigLoaderNVRAMParse(virQEMUDriverConfigPtr cfg, - const char *list) -{ - int ret = -1; - char **token; - size_t i, j; - - if (!(token = virStringSplit(list, ":", 0))) - goto cleanup; - - for (i = 0; token[i]; i += 2) { - if (!token[i] || !token[i + 1] || - STREQ(token[i], "") || STREQ(token[i + 1], "")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Invalid --with-loader-nvram list: %s"), - list); - goto cleanup; - } - } - - if (i) { - if (VIR_ALLOC_N(cfg->loader, i / 2) < 0 || - VIR_ALLOC_N(cfg->nvram, i / 2) < 0) - goto cleanup; - cfg->nloader = i / 2; - - for (j = 0; j < i / 2; j++) { - if (VIR_STRDUP(cfg->loader[j], token[2 * j]) < 0 || - VIR_STRDUP(cfg->nvram[j], token[2 * j + 1]) < 0) - goto cleanup; - } - } - - ret = 0; - cleanup: - virStringFreeList(token); - return ret; -} - - #define VIR_QEMU_OVMF_LOADER_PATH "/usr/share/OVMF/OVMF_CODE.fd" #define VIR_QEMU_OVMF_NVRAM_PATH "/usr/share/OVMF/OVMF_VARS.fd" #define VIR_QEMU_AAVMF_LOADER_PATH "/usr/share/AAVMF/AAVMF_CODE.fd" @@ -327,20 +286,22 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged) cfg->stdioLogD = true; #ifdef DEFAULT_LOADER_NVRAM - if (virQEMUDriverConfigLoaderNVRAMParse(cfg, DEFAULT_LOADER_NVRAM) < 0) + if (virFirmwareParseList(DEFAULT_LOADER_NVRAM, + &cfg->firmwares, + &cfg->nfirmwares) < 0) goto error; #else - - if (VIR_ALLOC_N(cfg->loader, 2) < 0 || - VIR_ALLOC_N(cfg->nvram, 2) < 0) + if (VIR_ALLOC_N(cfg->firmwares, 2) < 0) + goto error; + cfg->nfirmwares = 2; + if (VIR_ALLOC(cfg->firmwares[0]) < 0 || VIR_ALLOC(cfg->firmwares[1]) < 0) goto error; - cfg->nloader = 2; - if (VIR_STRDUP(cfg->loader[0], VIR_QEMU_AAVMF_LOADER_PATH) < 0 || - VIR_STRDUP(cfg->nvram[0], VIR_QEMU_AAVMF_NVRAM_PATH) < 0 || - VIR_STRDUP(cfg->loader[1], VIR_QEMU_OVMF_LOADER_PATH) < 0 || - VIR_STRDUP(cfg->nvram[1], VIR_QEMU_OVMF_NVRAM_PATH) < 0) + if (VIR_STRDUP(cfg->firmwares[0]->name, VIR_QEMU_AAVMF_LOADER_PATH) < 0 || + VIR_STRDUP(cfg->firmwares[0]->nvram, VIR_QEMU_AAVMF_NVRAM_PATH) < 0 || + VIR_STRDUP(cfg->firmwares[1]->name, VIR_QEMU_OVMF_LOADER_PATH) < 0 || + VIR_STRDUP(cfg->firmwares[1]->nvram, VIR_QEMU_OVMF_NVRAM_PATH) < 0) goto error; #endif @@ -397,13 +358,7 @@ static void virQEMUDriverConfigDispose(void *obj) VIR_FREE(cfg->lockManagerName); - while (cfg->nloader) { - VIR_FREE(cfg->loader[cfg->nloader - 1]); - VIR_FREE(cfg->nvram[cfg->nloader - 1]); - cfg->nloader--; - } - VIR_FREE(cfg->loader); - VIR_FREE(cfg->nvram); + virFirmwareFreeList(cfg->firmwares, cfg->nfirmwares); } @@ -427,43 +382,6 @@ virQEMUDriverConfigHugeTLBFSInit(virHugeTLBFSPtr hugetlbfs, } -static int -virQEMUDriverConfigNVRAMParse(const char *str, - char **loader, - char **nvram) -{ - int ret = -1; - char **token; - - if (!(token = virStringSplit(str, ":", 0))) - goto cleanup; - - if (token[0]) { - virSkipSpaces((const char **) &token[0]); - if (token[1]) - virSkipSpaces((const char **) &token[1]); - } - - /* Exactly two tokens are expected */ - if (!token[0] || !token[1] || token[2] || - STREQ(token[0], "") || STREQ(token[1], "")) { - virReportError(VIR_ERR_CONF_SYNTAX, - _("Invalid nvram format: '%s'"), - str); - goto cleanup; - } - - if (VIR_STRDUP(*loader, token[0]) < 0 || - VIR_STRDUP(*nvram, token[1]) < 0) - goto cleanup; - - ret = 0; - cleanup: - virStringFreeList(token); - return ret; -} - - int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, const char *filename) { @@ -855,14 +773,7 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, CHECK_TYPE("nvram", VIR_CONF_LIST); - while (cfg->nloader) { - VIR_FREE(cfg->loader[cfg->nloader - 1]); - VIR_FREE(cfg->nvram[cfg->nloader - 1]); - cfg->nloader--; - } - VIR_FREE(cfg->loader); - VIR_FREE(cfg->nvram); - + virFirmwareFreeList(cfg->firmwares, cfg->nfirmwares); /* Calc length and check items */ for (len = 0, pp = p->list; pp; len++, pp = pp->next) { if (pp->type != VIR_CONF_STRING) { @@ -872,16 +783,14 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, } } - if (len && - (VIR_ALLOC_N(cfg->loader, len) < 0 || - VIR_ALLOC_N(cfg->nvram, len) < 0)) + if (len && VIR_ALLOC_N(cfg->firmwares, len) < 0) goto cleanup; - cfg->nloader = len; + cfg->nfirmwares = len; for (i = 0, pp = p->list; pp; i++, pp = pp->next) { - if (virQEMUDriverConfigNVRAMParse(pp->str, - &cfg->loader[i], - &cfg->nvram[i]) < 0) + if (VIR_ALLOC(cfg->firmwares[i]) < 0) + goto cleanup; + if (virFirmwareParse(pp->str, cfg->firmwares[i]) < 0) goto cleanup; } } diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index e830b40..a09c81d 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -48,6 +48,7 @@ # include "virclosecallbacks.h" # include "virhostdev.h" # include "virfile.h" +# include "virfirmware.h" # ifdef CPU_SETSIZE /* Linux */ # define QEMUD_CPUMASK_LEN CPU_SETSIZE @@ -178,10 +179,8 @@ struct _virQEMUDriverConfig { bool logTimestamp; bool stdioLogD; - /* Pairs of loader:nvram paths. The list is @nloader items long */ - char **loader; - char **nvram; - size_t nloader; + virFirmwarePtr *firmwares; + size_t nfirmwares; }; /* Main driver state */ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e70d3ce..45f6a82 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -18511,7 +18511,7 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, goto cleanup; if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps, - cfg->loader, cfg->nloader) < 0) + cfg->firmwares, cfg->nfirmwares) < 0) goto cleanup; ret = virDomainCapsFormat(domCaps); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 7d61ecd..659ec29 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3724,9 +3724,9 @@ qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg, master_nvram_path = loader->templt; if (!loader->templt) { size_t i; - for (i = 0; i < cfg->nloader; i++) { - if (STREQ(cfg->loader[i], loader->path)) { - master_nvram_path = cfg->nvram[i]; + for (i = 0; i < cfg->nfirmwares; i++) { + if (STREQ(cfg->firmwares[i]->name, loader->path)) { + master_nvram_path = cfg->firmwares[i]->nvram; break; } } diff --git a/src/util/virfirmware.c b/src/util/virfirmware.c new file mode 100644 index 0000000..6b20c06 --- /dev/null +++ b/src/util/virfirmware.c @@ -0,0 +1,137 @@ +/* + * virfirmware.c: Definition of firmware object and supporting functions + * + * 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 "viralloc.h" +#include "virerror.h" +#include "virfirmware.h" +#include "virlog.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util.firmware"); + + +static void +virFirmwareFree(virFirmwarePtr firmware) +{ + if (!firmware) + return; + + VIR_FREE(firmware->name); + VIR_FREE(firmware->nvram); + VIR_FREE(firmware); +} + + +void +virFirmwareFreeList(virFirmwarePtr *firmwares, size_t nfirmwares) +{ + size_t i; + + for (i = 0; i < nfirmwares; i++) + virFirmwareFree(firmwares[i]); + + VIR_FREE(firmwares); +} + + +int +virFirmwareParse(const char *str, virFirmwarePtr firmware) +{ + int ret = -1; + char **token; + + if (!(token = virStringSplit(str, ":", 0))) + goto cleanup; + + if (token[0]) { + virSkipSpaces((const char **) &token[0]); + if (token[1]) + virSkipSpaces((const char **) &token[1]); + } + + /* Exactly two tokens are expected */ + if (!token[0] || !token[1] || token[2] || + STREQ(token[0], "") || STREQ(token[1], "")) { + virReportError(VIR_ERR_CONF_SYNTAX, + _("Invalid nvram format: '%s'"), + str); + goto cleanup; + } + + if (VIR_STRDUP(firmware->name, token[0]) < 0 || + VIR_STRDUP(firmware->nvram, token[1]) < 0) + goto cleanup; + + ret = 0; + cleanup: + virStringFreeList(token); + return ret; +} + + +int +virFirmwareParseList(const char *list, + virFirmwarePtr **firmwares, + size_t *nfirmwares) +{ + int ret = -1; + char **token; + size_t i, j; + + if (!(token = virStringSplit(list, ":", 0))) + goto cleanup; + + for (i = 0; token[i]; i += 2) { + if (!token[i] || !token[i + 1] || + STREQ(token[i], "") || STREQ(token[i + 1], "")) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid --with-loader-nvram list: %s"), + list); + goto cleanup; + } + } + + if (i) { + if (VIR_ALLOC_N(*firmwares, i / 2) < 0) + goto cleanup; + *nfirmwares = i / 2; + + for (j = 0; j < i / 2; j++) { + virFirmwarePtr *fws = *firmwares; + + if (VIR_ALLOC(fws[j]) < 0) + goto cleanup; + if (VIR_STRDUP(fws[j]->name, token[2 * j]) < 0 || + VIR_STRDUP(fws[j]->nvram, token[2 * j + 1]) < 0) + goto cleanup; + } + } + + ret = 0; + cleanup: + virStringFreeList(token); + return ret; +} diff --git a/src/util/virfirmware.h b/src/util/virfirmware.h new file mode 100644 index 0000000..682a865 --- /dev/null +++ b/src/util/virfirmware.h @@ -0,0 +1,51 @@ +/* + * virfirmware.h: Declaration of firmware object and supporting functions + * + * 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 __VIR_FIRMWARE_H__ +# define __VIR_FIRMWARE_H__ + +# include "internal.h" + +typedef struct _virFirmware virFirmware; +typedef virFirmware *virFirmwarePtr; + +struct _virFirmware { + char *name; + char *nvram; +}; + + +void +virFirmwareFreeList(virFirmwarePtr *firmwares, size_t nfirmwares); + +int +virFirmwareParse(const char *str, virFirmwarePtr firmware) + ATTRIBUTE_NONNULL(2); + +int +virFirmwareParseList(const char *list, + virFirmwarePtr **firmwares, + size_t *nfirmwares) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + + +#endif /* __VIR_FIRMWARE_H__ */ diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index e1d0671..83ce0e5 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -128,7 +128,8 @@ fillQemuCaps(virDomainCapsPtr domCaps, goto cleanup; if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps, - cfg->loader, cfg->nloader) < 0) + cfg->firmwares, + cfg->nfirmwares) < 0) goto cleanup; /* The function above tries to query host's KVM & VFIO capabilities by -- 2.8.4

Prefer firmwares specified via --with-loader-nvram configure option. If none are specified, use the Xen-provided default firmwares found in LIBXL_FIRMWARE_DIR. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_conf.c | 21 +++++++++++++++++++++ src/libxl/libxl_conf.h | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index a64b4c1..b347b8c 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -104,6 +104,7 @@ libxlDriverConfigDispose(void *obj) VIR_FREE(cfg->saveDir); VIR_FREE(cfg->autoDumpDir); VIR_FREE(cfg->lockManagerName); + virFirmwareFreeList(cfg->firmwares, cfg->nfirmwares); } @@ -1777,6 +1778,26 @@ libxlDriverConfigNew(void) goto error; } +#ifdef DEFAULT_LOADER_NVRAM + if (virFirmwareParseList(DEFAULT_LOADER_NVRAM, + &cfg->firmwares, + &cfg->nfirmwares) < 0) + goto error; + +#else + if (VIR_ALLOC_N(cfg->firmwares, 2) < 0) + goto error; + cfg->nfirmwares = 2; + if (VIR_ALLOC(cfg->firmwares[0]) < 0 || VIR_ALLOC(cfg->firmwares[1]) < 0) + goto error; + + if (VIR_STRDUP(cfg->firmwares[0]->name, + LIBXL_FIRMWARE_DIR "/hvmloader") < 0 || + VIR_STRDUP(cfg->firmwares[1]->name, + LIBXL_FIRMWARE_DIR "/ovmf.bin") < 0) + goto error; +#endif + return cfg; error: diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index c5b9429..e55717a 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 "virfirmware.h" # define LIBXL_DRIVER_NAME "xenlight" # define LIBXL_VNC_PORT_MIN 5900 @@ -107,6 +108,9 @@ struct _libxlDriverConfig { char *libDir; char *saveDir; char *autoDumpDir; + + virFirmwarePtr *firmwares; + size_t nfirmwares; }; -- 2.8.4

On 06/09/2016 08:46 AM, Jim Fehlig wrote:
Prefer firmwares specified via --with-loader-nvram configure option. If none are specified, use the Xen-provided default firmwares found in LIBXL_FIRMWARE_DIR.
Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_conf.c | 21 +++++++++++++++++++++ src/libxl/libxl_conf.h | 4 ++++ 2 files changed, 25 insertions(+)
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index a64b4c1..b347b8c 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -104,6 +104,7 @@ libxlDriverConfigDispose(void *obj) VIR_FREE(cfg->saveDir); VIR_FREE(cfg->autoDumpDir); VIR_FREE(cfg->lockManagerName); + virFirmwareFreeList(cfg->firmwares, cfg->nfirmwares); }
@@ -1777,6 +1778,26 @@ libxlDriverConfigNew(void) goto error; }
+#ifdef DEFAULT_LOADER_NVRAM + if (virFirmwareParseList(DEFAULT_LOADER_NVRAM, + &cfg->firmwares, + &cfg->nfirmwares) < 0) + goto error; + +#else + if (VIR_ALLOC_N(cfg->firmwares, 2) < 0) + goto error; + cfg->nfirmwares = 2; + if (VIR_ALLOC(cfg->firmwares[0]) < 0 || VIR_ALLOC(cfg->firmwares[1]) < 0) + goto error; + + if (VIR_STRDUP(cfg->firmwares[0]->name, + LIBXL_FIRMWARE_DIR "/hvmloader") < 0 || + VIR_STRDUP(cfg->firmwares[1]->name, + LIBXL_FIRMWARE_DIR "/ovmf.bin") < 0) + goto error; +#endif +
I'm going to rework this hunk a bit in V3 since hvmloader should always be present in cfg->firmwares. Regards, Jim

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 | 458 +++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_capabilities.h | 50 +++++ src/libxl/libxl_conf.c | 419 ------------------------------------- src/libxl/libxl_conf.h | 18 +- src/libxl/libxl_domain.c | 1 + src/libxl/libxl_driver.c | 1 + 8 files changed, 517 insertions(+), 440 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 85adaf3..b609714 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -75,6 +75,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 9c4eb41..9e7fe75 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -826,10 +826,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..aef2c2d --- /dev/null +++ b/src/libxl/libxl_capabilities.c @@ -0,0 +1,458 @@ +/* + * 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 "virfile.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) { + if (!virFileExists(def->emulator)) + goto cleanup; + + 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 b347b8c..c3d4f67 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); @@ -164,346 +148,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,41 +549,6 @@ libxlDiskSetDiscard(libxl_device_disk *x_disk, int discard) #endif } - -#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) { - if (!virFileExists(def->emulator)) - goto cleanup; - - 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, @@ -2059,34 +1668,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 e55717a..6547056 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -40,6 +40,7 @@ # include "virhostdev.h" # include "locking/lock_manager.h" # include "virfirmware.h" +# include "libxl_capabilities.h" # define LIBXL_DRIVER_NAME "xenlight" # define LIBXL_VNC_PORT_MIN 5900 @@ -48,10 +49,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" @@ -62,13 +59,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; @@ -181,12 +171,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 4a21f68..223862a 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 2ab08ac..afc5ac3 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.8.4

Add domain capabilities for PV and HVM domains. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_capabilities.c | 140 +++++++++++++++++++++++++++++ src/libxl/libxl_capabilities.h | 7 ++ src/libxl/libxl_driver.c | 74 +++++++++++++++ tests/Makefile.am | 5 ++ tests/domaincapsschemadata/libxl-xenfv.xml | 68 ++++++++++++++ tests/domaincapsschemadata/libxl-xenpv.xml | 58 ++++++++++++ tests/domaincapstest.c | 61 +++++++++++++ tests/testutilsxen.h | 1 + 8 files changed, 414 insertions(+) diff --git a/src/libxl/libxl_capabilities.c b/src/libxl/libxl_capabilities.c index aef2c2d..45f0988 100644 --- a/src/libxl/libxl_capabilities.c +++ b/src/libxl/libxl_capabilities.c @@ -30,8 +30,10 @@ #include "virerror.h" #include "virfile.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" @@ -396,6 +398,109 @@ libxlCapsInitGuests(libxl_ctx *ctx, virCapsPtr caps) return 0; } +static int +libxlMakeDomainOSCaps(const char *machine, + virDomainCapsOSPtr os, + virFirmwarePtr *firmwares, + size_t nfirmwares) +{ + virDomainCapsLoaderPtr capsLoader = &os->loader; + size_t i; + + os->supported = true; + + if (STREQ(machine, "xenpv")) + return 0; + + capsLoader->supported = true; + if (VIR_ALLOC_N(capsLoader->values.values, nfirmwares) < 0) + return -1; + + for (i = 0; i < nfirmwares; i++) { + if (VIR_STRDUP(capsLoader->values.values[capsLoader->values.nvalues], + firmwares[i]->name) < 0) + return -1; + capsLoader->values.nvalues++; + } + + VIR_DOMAIN_CAPS_ENUM_SET(capsLoader->type, + VIR_DOMAIN_LOADER_TYPE_ROM, + VIR_DOMAIN_LOADER_TYPE_PFLASH); + VIR_DOMAIN_CAPS_ENUM_SET(capsLoader->readonly, + VIR_TRISTATE_BOOL_YES); + + return 0; +} + +static int +libxlMakeDomainDeviceDiskCaps(virDomainCapsDeviceDiskPtr dev) +{ + dev->supported = true; + + VIR_DOMAIN_CAPS_ENUM_SET(dev->diskDevice, + VIR_DOMAIN_DISK_DEVICE_DISK, + VIR_DOMAIN_DISK_DEVICE_CDROM); + + VIR_DOMAIN_CAPS_ENUM_SET(dev->bus, + VIR_DOMAIN_DISK_BUS_IDE, + VIR_DOMAIN_DISK_BUS_SCSI, + VIR_DOMAIN_DISK_BUS_XEN); + + return 0; +} + +static int +libxlMakeDomainDeviceGraphicsCaps(virDomainCapsDeviceGraphicsPtr dev) +{ + dev->supported = true; + + VIR_DOMAIN_CAPS_ENUM_SET(dev->type, + VIR_DOMAIN_GRAPHICS_TYPE_SDL, + VIR_DOMAIN_GRAPHICS_TYPE_VNC, + VIR_DOMAIN_GRAPHICS_TYPE_SPICE); + + return 0; +} + +static int +libxlMakeDomainDeviceVideoCaps(virDomainCapsDeviceVideoPtr dev) +{ + dev->supported = true; + + VIR_DOMAIN_CAPS_ENUM_SET(dev->modelType, + VIR_DOMAIN_VIDEO_TYPE_VGA, + VIR_DOMAIN_VIDEO_TYPE_CIRRUS, + VIR_DOMAIN_VIDEO_TYPE_XEN); + + return 0; +} + +static int +libxlMakeDomainDeviceHostdevCaps(virDomainCapsDeviceHostdevPtr dev) +{ + dev->supported = true; + /* VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES is for containers only */ + VIR_DOMAIN_CAPS_ENUM_SET(dev->mode, + VIR_DOMAIN_HOSTDEV_MODE_SUBSYS); + + VIR_DOMAIN_CAPS_ENUM_SET(dev->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(dev->subsysType, + VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI); + + /* No virDomainHostdevCapsType for libxl */ + virDomainCapsEnumClear(&dev->capsType); + + virDomainCapsEnumClear(&dev->pciBackend); + VIR_DOMAIN_CAPS_ENUM_SET(dev->pciBackend, + VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN); + return 0; +} + virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx) { @@ -424,6 +529,41 @@ 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, + virFirmwarePtr *firmwares, + size_t nfirmwares) +{ + virDomainCapsOSPtr os = &domCaps->os; + virDomainCapsDeviceDiskPtr disk = &domCaps->disk; + virDomainCapsDeviceGraphicsPtr graphics = &domCaps->graphics; + virDomainCapsDeviceVideoPtr video = &domCaps->video; + 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, firmwares, nfirmwares) < 0 || + libxlMakeDomainDeviceDiskCaps(disk) < 0 || + libxlMakeDomainDeviceGraphicsCaps(graphics) < 0 || + libxlMakeDomainDeviceVideoCaps(video) < 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..992b780 100644 --- a/src/libxl/libxl_capabilities.h +++ b/src/libxl/libxl_capabilities.h @@ -27,6 +27,8 @@ # include "virobject.h" # include "capabilities.h" +# include "domain_capabilities.h" +# include "virfirmware.h" # ifndef LIBXL_FIRMWARE_DIR @@ -45,6 +47,11 @@ virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx); int +libxlMakeDomainCapabilities(virDomainCapsPtr domCaps, + virFirmwarePtr *firmwares, + size_t nfirmwares); + +int libxlDomainGetEmulatorType(const virDomainDef *def); #endif /* LIBXL_CAPABILITIES_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index afc5ac3..82b8b83 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -5562,6 +5562,79 @@ libxlDomainInterfaceAddresses(virDomainPtr dom, } +static char * +libxlConnectGetDomainCapabilities(virConnectPtr conn, + const char *emulatorbin, + const char *arch_str, + const char *machine, + const char *virttype_str, + unsigned int flags) +{ + libxlDriverPrivatePtr driver = conn->privateData; + libxlDriverConfigPtr cfg; + 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; + + cfg = libxlDriverConfigGet(driver); + + 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, cfg->firmwares, + cfg->nfirmwares) < 0) + goto cleanup; + + ret = virDomainCapsFormat(domCaps); + + cleanup: + virObjectUnref(domCaps); + virObjectUnref(cfg); + return ret; +} + + static virHypervisorDriver libxlHypervisorDriver = { .name = LIBXL_DRIVER_NAME, .connectOpen = libxlConnectOpen, /* 0.9.0 */ @@ -5663,6 +5736,7 @@ static virHypervisorDriver libxlHypervisorDriver = { .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */ .nodeGetSecurityModel = libxlNodeGetSecurityModel, /* 1.2.16 */ .domainInterfaceAddresses = libxlDomainInterfaceAddresses, /* 1.3.5 */ + .connectGetDomainCapabilities = libxlConnectGetDomainCapabilities, /* 1.3.5 */ }; static virConnectDriver libxlConnectDriver = { diff --git a/tests/Makefile.am b/tests/Makefile.am index 839af26..480f034 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -930,6 +930,11 @@ domaincapstest_SOURCES += testutilsqemu.c testutilsqemu.h domaincapstest_LDADD += $(qemu_LDADDS) $(GNULIB_LIBS) endif WITH_QEMU +if WITH_LIBXL +domaincapstest_SOURCES += testutilsxen.c testutilsxen.h +domaincapstest_LDADD += ../src/libvirt_driver_libxl_impl.la +endif WITH_LIBXL + if WITH_LIBVIRTD libvirtdconftest_SOURCES = \ libvirtdconftest.c testutils.h testutils.c \ diff --git a/tests/domaincapsschemadata/libxl-xenfv.xml b/tests/domaincapsschemadata/libxl-xenfv.xml new file mode 100644 index 0000000..9436ef8 --- /dev/null +++ b/tests/domaincapsschemadata/libxl-xenfv.xml @@ -0,0 +1,68 @@ +<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> + <value>pflash</value> + </enum> + <enum name='readonly'> + <value>yes</value> + </enum> + </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> + <graphics supported='yes'> + <enum name='type'> + <value>sdl</value> + <value>vnc</value> + <value>spice</value> + </enum> + </graphics> + <video supported='yes'> + <enum name='modelType'> + <value>vga</value> + <value>cirrus</value> + <value>xen</value> + </enum> + </video> + <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/libxl-xenpv.xml b/tests/domaincapsschemadata/libxl-xenpv.xml new file mode 100644 index 0000000..ab00a28 --- /dev/null +++ b/tests/domaincapsschemadata/libxl-xenpv.xml @@ -0,0 +1,58 @@ +<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> + <graphics supported='yes'> + <enum name='type'> + <value>sdl</value> + <value>vnc</value> + <value>spice</value> + </enum> + </graphics> + <video supported='yes'> + <enum name='modelType'> + <value>vga</value> + <value>cirrus</value> + <value>xen</value> + </enum> + </video> + <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 83ce0e5..9fb2c97 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -162,10 +162,41 @@ fillQemuCaps(virDomainCapsPtr domCaps, #endif /* WITH_QEMU */ +#ifdef WITH_LIBXL +# include "testutilsxen.h" + +static int +fillXenCaps(virDomainCapsPtr domCaps) +{ + virFirmwarePtr *firmwares; + int ret = -1; + + if (VIR_ALLOC_N(firmwares, 2) < 0) + return ret; + + if (VIR_ALLOC(firmwares[0]) < 0 || VIR_ALLOC(firmwares[1]) < 0) + goto cleanup; + if (VIR_STRDUP(firmwares[0]->name, "/usr/lib/xen/boot/hvmloader") < 0 || + VIR_STRDUP(firmwares[1]->name, "/usr/lib/xen/boot/ovmf.bin") < 0) + goto cleanup; + + if (libxlMakeDomainCapabilities(domCaps, firmwares, 2) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virFirmwareFreeList(firmwares, 2); + return ret; +} +#endif /* WITH_LIBXL */ + + enum testCapsType { CAPS_NONE, CAPS_ALL, CAPS_QEMU, + CAPS_LIBXL, }; struct testData { @@ -213,6 +244,13 @@ test_virDomainCapsFormat(const void *opaque) goto cleanup; #endif break; + + case CAPS_LIBXL: +#if WITH_LIBXL + if (fillXenCaps(domCaps) < 0) + goto cleanup; +#endif + break; } if (!(domCapsXML = virDomainCapsFormat(domCaps))) @@ -280,6 +318,20 @@ mymain(void) VIR_FREE(name); \ } while (0) +#define DO_TEST_LIBXL(Name, Emulator, Machine, Arch, Type) \ + do { \ + struct testData data = { \ + .name = Name, \ + .emulator = Emulator, \ + .machine = Machine, \ + .arch = Arch, \ + .type = Type, \ + .capsType = CAPS_LIBXL, \ + }; \ + if (virTestRun(Name, test_virDomainCapsFormat, &data) < 0) \ + ret = -1; \ + } while (0) + DO_TEST("basic", "/bin/emulatorbin", "my-machine-type", "x86_64", VIR_DOMAIN_VIRT_UML, CAPS_NONE); DO_TEST("full", "/bin/emulatorbin", "my-machine-type", @@ -313,6 +365,15 @@ mymain(void) #endif /* WITH_QEMU */ +#if WITH_LIBXL + + DO_TEST_LIBXL("libxl-xenpv", "/usr/bin/qemu-system-x86_64", + "xenpv", "x86_64", VIR_DOMAIN_VIRT_XEN); + DO_TEST_LIBXL("libxl-xenfv", "/usr/bin/qemu-system-x86_64", + "xenfv", "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.8.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 9e7fe75..8fd4382 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1149,7 +1149,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 9b8306f..bbe53ee 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; + } } } @@ -535,6 +561,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..435a791 --- /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' vram='8192' 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..b6980e6 --- /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' vram='8192' heads='1' primary='yes'/> + </video> + </devices> +</domain> diff --git a/tests/xlconfigtest.c b/tests/xlconfigtest.c index 62bb144..474697b 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.8.4

On 09.06.2016 16:46, Jim Fehlig wrote:
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(-)
Looking good, but just one small nit.
diff --git a/src/xenconfig/xen_xl.c b/src/xenconfig/xen_xl.c index 9b8306f..bbe53ee 100644 --- a/src/xenconfig/xen_xl.c +++ b/src/xenconfig/xen_xl.c
@@ -535,6 +561,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")) {
On my system LIBXL_FIRMWARE_DIR is: $ pkg-config --variable=xenfirmwaredir xenlight /usr/libexec/xen/boot
+ if (xenConfigSetString(conf, "bios_override", + def->os.loader->path) < 0)
and since "bios_override" is set only if it points somewhere else ...
+ 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..435a791 --- /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' vram='8192' 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"
I have got: bios_override = "/usr/lib/xen/boot/ovmf.bin" here. And thus the test fails for me. I'm not sure how test what you're trying to test here though.
+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" ]
Michal

Michal Privoznik wrote:
On 09.06.2016 16:46, Jim Fehlig wrote:
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(-)
Looking good, but just one small nit.
diff --git a/src/xenconfig/xen_xl.c b/src/xenconfig/xen_xl.c index 9b8306f..bbe53ee 100644 --- a/src/xenconfig/xen_xl.c +++ b/src/xenconfig/xen_xl.c
@@ -535,6 +561,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")) {
On my system LIBXL_FIRMWARE_DIR is:
$ pkg-config --variable=xenfirmwaredir xenlight /usr/libexec/xen/boot
+ if (xenConfigSetString(conf, "bios_override", + def->os.loader->path) < 0)
and since "bios_override" is set only if it points somewhere else ...
+ 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..435a791 --- /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' vram='8192' 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"
I have got:
bios_override = "/usr/lib/xen/boot/ovmf.bin"
Actually, I need to remove handling of bios_override since that config item is part of Anthony's "Load BIOS via toolstack instead of been embedded in hvmloader" series that is not yet committed to xen.git. Specifically, it is introduced in 5/14 here http://lists.xen.org/archives/html/xen-devel/2016-03/msg01628.html
here. And thus the test fails for me. I'm not sure how test what you're trying to test here though.
You bring up a point here that I'm not quite sure how to handle. LIBXL_FIRMWARE_DIR can certainly be different between Xen installations, depending on configuration options selected when building Xen. But currently all the various data files under tests/ are "hard-coded". E.g. tests/xlconfigdata/test-fullvirt-ovmf.xml introduced in this patch contains <loader readonly='yes' type='pflash'>/usr/lib/xen/boot/ovmf.bin</loader> but it should really contain <loader readonly='yes' type='pflash'>LIBXL_FIRMWARE_DIR/ovmf.bin</loader> How should test data files which depend on values discovered at build time be handled? Should they be created at build time from e.g. tests/xlconfigdata/test-fullvirt-ovmf.xml.in? Is there a better trick for substituting values discovered at build time in test data files? Thanks a lot for taking a look at this work! Regards, Jim

On 09.06.2016 19:06, Jim Fehlig wrote:
Michal Privoznik wrote:
On 09.06.2016 16:46, Jim Fehlig wrote:
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(-)
Looking good, but just one small nit.
diff --git a/src/xenconfig/xen_xl.c b/src/xenconfig/xen_xl.c index 9b8306f..bbe53ee 100644 --- a/src/xenconfig/xen_xl.c +++ b/src/xenconfig/xen_xl.c
@@ -535,6 +561,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")) {
On my system LIBXL_FIRMWARE_DIR is:
$ pkg-config --variable=xenfirmwaredir xenlight /usr/libexec/xen/boot
+ if (xenConfigSetString(conf, "bios_override", + def->os.loader->path) < 0)
and since "bios_override" is set only if it points somewhere else ...
+ 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..435a791 --- /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' vram='8192' 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"
I have got:
bios_override = "/usr/lib/xen/boot/ovmf.bin"
Actually, I need to remove handling of bios_override since that config item is part of Anthony's "Load BIOS via toolstack instead of been embedded in hvmloader" series that is not yet committed to xen.git. Specifically, it is introduced in 5/14 here
http://lists.xen.org/archives/html/xen-devel/2016-03/msg01628.html
here. And thus the test fails for me. I'm not sure how test what you're trying to test here though.
You bring up a point here that I'm not quite sure how to handle. LIBXL_FIRMWARE_DIR can certainly be different between Xen installations, depending on configuration options selected when building Xen. But currently all the various data files under tests/ are "hard-coded". E.g. tests/xlconfigdata/test-fullvirt-ovmf.xml introduced in this patch contains
<loader readonly='yes' type='pflash'>/usr/lib/xen/boot/ovmf.bin</loader>
but it should really contain
<loader readonly='yes' type='pflash'>LIBXL_FIRMWARE_DIR/ovmf.bin</loader>
Yes. this is what I had in mind, thank you for writing it down.
How should test data files which depend on values discovered at build time be handled?
Good question. I don't think we have such case in our test suite yet. So it's up to us to walk the path for others :)
Should they be created at build time from e.g. tests/xlconfigdata/test-fullvirt-ovmf.xml.in?
Not a bad idea. This will definitely work thus it can be our fall back if other approaches fail.
Is there a better trick for substituting values discovered at build time in test data files?
Well, I'm thinking of fixing the path in the testsuite. In xlconfigtest depending on mode either testCompareParseXML or testCompareFormatXML is called. For the simplicity of explanation assume just the former one, the latter would be similar. In the testCompareParseXML, the domain XML is parsed and xl config is then produced from it. What if we introduced a boolean that if set would mangle^Wfix the boot loader path just before we try to produce xl config from it? Then, testCompareHelper would merely just pass the boolean from testInfo struct. Thus we would need new macro, say DO_TEST_FIX_LOADER (I know, terrible name) which would set the boolean in the struct. All other macros would then leave the boolean unset (=false). I know this is not a terrific idea, because if one would open the XML, the corresponding config would not be its exact copy. Or even better, in the XML there would be <loader>LIBXL_FIRMWARE_DIR/ovmf.bin</loader> and if the boolean is set, it would just replace LIBXL_FIRMWARE_DIR with the actual value of the macro (virStringReplace). This way it would be obvious even in the XML that some post processing is happening in the test. Michal

On 06/10/2016 01:47 AM, Michal Privoznik wrote:
On 09.06.2016 19:06, Jim Fehlig wrote:
You bring up a point here that I'm not quite sure how to handle. LIBXL_FIRMWARE_DIR can certainly be different between Xen installations, depending on configuration options selected when building Xen. But currently all the various data files under tests/ are "hard-coded". E.g. tests/xlconfigdata/test-fullvirt-ovmf.xml introduced in this patch contains
<loader readonly='yes' type='pflash'>/usr/lib/xen/boot/ovmf.bin</loader>
but it should really contain
<loader readonly='yes' type='pflash'>LIBXL_FIRMWARE_DIR/ovmf.bin</loader>
Yes. this is what I had in mind, thank you for writing it down.
How should test data files which depend on values discovered at build time be handled? Good question. I don't think we have such case in our test suite yet. So it's up to us to walk the path for others :)
Should they be created at build time from e.g. tests/xlconfigdata/test-fullvirt-ovmf.xml.in? Not a bad idea. This will definitely work thus it can be our fall back if other approaches fail.
Is there a better trick for substituting values discovered at build time in test data files? Well, I'm thinking of fixing the path in the testsuite. In xlconfigtest depending on mode either testCompareParseXML or testCompareFormatXML is called. For the simplicity of explanation assume just the former one, the latter would be similar.
In the testCompareParseXML, the domain XML is parsed and xl config is then produced from it. What if we introduced a boolean that if set would mangle^Wfix the boot loader path just before we try to produce xl config from it? Then, testCompareHelper would merely just pass the boolean from testInfo struct. Thus we would need new macro, say DO_TEST_FIX_LOADER (I know, terrible name) which would set the boolean in the struct. All other macros would then leave the boolean unset (=false).
I know this is not a terrific idea, because if one would open the XML, the corresponding config would not be its exact copy.
Or even better, in the XML there would be <loader>LIBXL_FIRMWARE_DIR/ovmf.bin</loader> and if the boolean is set, it would just replace LIBXL_FIRMWARE_DIR with the actual value of the macro (virStringReplace).
Ah, good idea. I'll give this a shot in V3.
This way it would be obvious even in the XML that some post processing is happening in the test.
Right. And I should be able to precede it with a comment in the XML to make it even more clear. Thanks for the ideas! Regards, Jim

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 c3d4f67..9877765 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -395,6 +395,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.8.4

On 09.06.2016 16:46, Jim Fehlig wrote:
This is essentially a V2 of
https://www.redhat.com/archives/libvir-list/2016-April/msg01358.html
To avoid code duplication in that series, I proposed adding a virFirmware object that could be used by multiple drivers
https://www.redhat.com/archives/libvir-list/2016-May/msg01370.html
mprivozn ACK'ed that series, but I deferred committing it until 1.3.5 was released since it's not all that useful without accompanying use by another driver. This series includes all the patches rebased and tested against latest git master.
Note: I sent this series yesterday, but int-mx.corp.redhat.com rejected 0/6 and 3/6 with "550 5.1.1 <libvir-list redhat com>... User unknown (in reply to RCPT TO command)". I'm resending in hopes that all patches make it through this time.
Jim Fehlig (6): driver config: Introduce virFirmware object libxl: add default firmwares to driver config object libxl: introduce libxl_capabilities.{ch} libxl: implement connectGetDomainCapabilities xenconfig: support bios=ovmf xl.cfg libxl: Add support for ovmf firmware
po/POTFILES.in | 2 + src/Makefile.am | 12 +- src/libvirt_private.syms | 6 + src/libxl/libxl_capabilities.c | 598 +++++++++++++++++++++ src/libxl/libxl_capabilities.h | 57 ++ src/libxl/libxl_conf.c | 448 +-------------- src/libxl/libxl_conf.h | 22 +- src/libxl/libxl_domain.c | 1 + src/libxl/libxl_driver.c | 75 +++ src/qemu/qemu_capabilities.c | 22 +- src/qemu/qemu_capabilities.h | 5 +- src/qemu/qemu_conf.c | 127 +---- src/qemu/qemu_conf.h | 7 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_process.c | 6 +- src/util/virfirmware.c | 137 +++++ src/util/virfirmware.h | 51 ++ src/xenconfig/xen_xl.c | 50 +- tests/Makefile.am | 5 + tests/domaincapsschemadata/libxl-xenfv.xml | 68 +++ tests/domaincapsschemadata/libxl-xenpv.xml | 58 ++ tests/domaincapstest.c | 64 ++- 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 + 28 files changed, 1417 insertions(+), 578 deletions(-) create mode 100644 src/libxl/libxl_capabilities.c create mode 100644 src/libxl/libxl_capabilities.h create mode 100644 src/util/virfirmware.c create mode 100644 src/util/virfirmware.h create mode 100644 tests/domaincapsschemadata/libxl-xenfv.xml create mode 100644 tests/domaincapsschemadata/libxl-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
I'd ACK this as it looks very good. But there's small problem in 5/6 we should fix before pushing this. Michal
participants (2)
-
Jim Fehlig
-
Michal Privoznik