Recently, bhyve got UEFI support that eliminates necessity of having two-step process of starting a VM, i.e. loading OS using loader like bhyveloader or grub and then calling bhyve itself. >From user perspective usage looks the following: if a domain XML contains the '<bootloader>' element and it's value is a path to non-executable file, then it's treated as a path to bootrom file and external loader is not execute. All the existing behavior remains the same, e.g. if bootloader is not specified, bhyveloader is used. If loader is specified and it points to an executable file, it's executed before running bhyve. Implementation consists of two major parts: * Add probing for capability by checking if the current bhyve binary accepts '-l bootrom' argument meaning that UEFI is supported * virBhyveProcessBuildBhyveCmd is extended with 'external_loader' argument. If it decides (based on the schema described above) that external loader is not needed, it sets it to false. All the related code changed accordingly to act based on value of external_loader. --- src/bhyve/bhyve_capabilities.c | 11 ++++ src/bhyve/bhyve_capabilities.h | 1 + src/bhyve/bhyve_command.c | 20 +++++++- src/bhyve/bhyve_command.h | 1 + src/bhyve/bhyve_driver.c | 15 +++--- src/bhyve/bhyve_process.c | 58 ++++++++++++---------- .../bhyvexml2argvdata/bhyvexml2argv-bhyveload.args | 3 ++ .../bhyvexml2argv-bhyveload.ldargs | 1 + .../bhyvexml2argvdata/bhyvexml2argv-bhyveload.xml | 24 +++++++++ tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.args | 4 ++ tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.xml | 23 +++++++++ tests/bhyvexml2argvmock.c | 13 +++++ tests/bhyvexml2argvtest.c | 39 ++++++++------- 13 files changed, 162 insertions(+), 51 deletions(-) create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.args create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.ldargs create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.xml create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.args create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.xml diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c index d2970a2..fbdd63c 100644 --- a/src/bhyve/bhyve_capabilities.c +++ b/src/bhyve/bhyve_capabilities.c @@ -166,6 +166,17 @@ virBhyveProbeCaps(unsigned int *caps) if (strstr(help, "-u:") != NULL) *caps |= BHYVE_CAP_RTC_UTC; + virCommandFree(cmd); + + cmd = virCommandNew(binary); + virCommandAddArgList(cmd, "-l", "bootrom", NULL); + if (virCommandRun(cmd, &exit) < 0) { + ret = -1; + goto out; + } + if (exit == 1) + *caps |= BHYVE_CAP_BOOTROM; + out: VIR_FREE(help); virCommandFree(cmd); diff --git a/src/bhyve/bhyve_capabilities.h b/src/bhyve/bhyve_capabilities.h index 0eb22a4..25dfb2c 100644 --- a/src/bhyve/bhyve_capabilities.h +++ b/src/bhyve/bhyve_capabilities.h @@ -33,6 +33,7 @@ typedef enum { typedef enum { BHYVE_CAP_RTC_UTC = 1, + BHYVE_CAP_BOOTROM = 2, } virBhyveCapsFlags; int virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps); diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index 6576029..10d504e 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -216,7 +216,9 @@ bhyveBuildDiskArgStr(const virDomainDef *def ATTRIBUTE_UNUSED, virCommandPtr virBhyveProcessBuildBhyveCmd(virConnectPtr conn, - virDomainDefPtr def, bool dryRun) + virDomainDefPtr def, + bool *external_loader, + bool dryRun) { /* * /usr/sbin/bhyve -c 2 -m 256 -AI -H -P \ @@ -230,6 +232,22 @@ virBhyveProcessBuildBhyveCmd(virConnectPtr conn, virCommandPtr cmd = virCommandNew(BHYVE); + /* Check what loader to use */ + if ((def->os.bootloader != NULL) && + (!virFileIsExecutable(def->os.bootloader))) { + *external_loader = false; + if ((bhyveDriverGetCaps(conn) & BHYVE_CAP_BOOTROM) == 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Installed bhyve binary does not support " + "bootrom")); + goto error; + } + virCommandAddArg(cmd, "-l"); + virCommandAddArgFormat(cmd, "bootrom,%s", def->os.bootloader); + } else { + *external_loader = true; + } + /* CPUs */ virCommandAddArg(cmd, "-c"); virCommandAddArgFormat(cmd, "%d", def->vcpus); diff --git a/src/bhyve/bhyve_command.h b/src/bhyve/bhyve_command.h index 22a959d..20a3bf0 100644 --- a/src/bhyve/bhyve_command.h +++ b/src/bhyve/bhyve_command.h @@ -32,6 +32,7 @@ virCommandPtr virBhyveProcessBuildBhyveCmd(virConnectPtr conn, virDomainDefPtr def, + bool *external_loader, bool dryRun); virCommandPtr diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 4840a0e..7290251 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -698,6 +698,7 @@ bhyveConnectDomainXMLToNative(virConnectPtr conn, virDomainDefPtr def = NULL; virCommandPtr cmd = NULL, loadcmd = NULL; virCapsPtr caps = NULL; + bool external_loader = NULL; char *ret = NULL; virCheckFlags(0, NULL); @@ -721,15 +722,17 @@ bhyveConnectDomainXMLToNative(virConnectPtr conn, if (bhyveDomainAssignAddresses(def, NULL) < 0) goto cleanup; - if (!(loadcmd = virBhyveProcessBuildLoadCmd(conn, def, "<device.map>", - NULL))) + if (!(cmd = virBhyveProcessBuildBhyveCmd(conn, def, &external_loader, true))) goto cleanup; - if (!(cmd = virBhyveProcessBuildBhyveCmd(conn, def, true))) - goto cleanup; + if (external_loader) { + if (!(loadcmd = virBhyveProcessBuildLoadCmd(conn, def, "<device.map>", + NULL))) + goto cleanup; - virBufferAdd(&buf, virCommandToString(loadcmd), -1); - virBufferAddChar(&buf, '\n'); + virBufferAdd(&buf, virCommandToString(loadcmd), -1); + virBufferAddChar(&buf, '\n'); + } virBufferAdd(&buf, virCommandToString(cmd), -1); if (virBufferCheckError(&buf) < 0) diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index 284641a..d62cccd 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -114,6 +114,7 @@ virBhyveProcessStart(virConnectPtr conn, virCommandPtr load_cmd = NULL; bhyveConnPtr privconn = conn->privateData; int ret = -1, rc; + bool external_loader = NULL; if (virAsprintf(&logfile, "%s/%s.log", BHYVE_LOG_DIR, vm->def->name) < 0) @@ -150,6 +151,7 @@ virBhyveProcessStart(virConnectPtr conn, /* Call bhyve to start the VM */ if (!(cmd = virBhyveProcessBuildBhyveCmd(conn, vm->def, + &external_loader, false))) goto cleanup; @@ -159,38 +161,40 @@ virBhyveProcessStart(virConnectPtr conn, virCommandSetPidFile(cmd, privconn->pidfile); virCommandDaemonize(cmd); - /* Now bhyve command is constructed, meaning the - * domain is ready to be started, so we can build - * and execute bhyveload command */ - rc = virBhyveFormatDevMapFile(vm->def->name, &devmap_file); - if (rc < 0) - goto cleanup; - - if (!(load_cmd = virBhyveProcessBuildLoadCmd(conn, vm->def, devmap_file, - &devicemap))) - goto cleanup; - virCommandSetOutputFD(load_cmd, &logfd); - virCommandSetErrorFD(load_cmd, &logfd); + if (external_loader) { + /* Now bhyve command is constructed, meaning the + * domain is ready to be started, so we can build + * and execute bhyveload command */ + rc = virBhyveFormatDevMapFile(vm->def->name, &devmap_file); + if (rc < 0) + goto cleanup; - if (devicemap != NULL) { - rc = virFileWriteStr(devmap_file, devicemap, 0644); - if (rc) { - virReportSystemError(errno, - _("Cannot write device.map '%s'"), - devmap_file); + if (!(load_cmd = virBhyveProcessBuildLoadCmd(conn, vm->def, devmap_file, + &devicemap))) goto cleanup; + virCommandSetOutputFD(load_cmd, &logfd); + virCommandSetErrorFD(load_cmd, &logfd); + + if (devicemap != NULL) { + rc = virFileWriteStr(devmap_file, devicemap, 0644); + if (rc) { + virReportSystemError(errno, + _("Cannot write device.map '%s'"), + devmap_file); + goto cleanup; + } } - } - /* Log generated command line */ - virCommandWriteArgLog(load_cmd, logfd); - if ((pos = lseek(logfd, 0, SEEK_END)) < 0) - VIR_WARN("Unable to seek to end of logfile: %s", - virStrerror(errno, ebuf, sizeof(ebuf))); + /* Log generated command line */ + virCommandWriteArgLog(load_cmd, logfd); + if ((pos = lseek(logfd, 0, SEEK_END)) < 0) + VIR_WARN("Unable to seek to end of logfile: %s", + virStrerror(errno, ebuf, sizeof(ebuf))); - VIR_DEBUG("Loading domain '%s'", vm->def->name); - if (virCommandRun(load_cmd, NULL) < 0) - goto cleanup; + VIR_DEBUG("Loading domain '%s'", vm->def->name); + if (virCommandRun(load_cmd, NULL) < 0) + goto cleanup; + } /* Now we can start the domain */ VIR_DEBUG("Starting domain '%s'", vm->def->name); diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.args b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.args new file mode 100644 index 0000000..118735e --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.args @@ -0,0 +1,3 @@ +/usr/sbin/bhyve -c 1 -m 214 -u -H -P -s 0:0,hostbridge \ +-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \ +-s 2:0,ahci-hd,/tmp/freebsd.img bhyve diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.ldargs b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.ldargs new file mode 100644 index 0000000..56f7fb3 --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.ldargs @@ -0,0 +1 @@ +/usr/sbin/bhyveload -foo diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.xml new file mode 100644 index 0000000..9dac10c --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-bhyveload.xml @@ -0,0 +1,24 @@ +<domain type='bhyve'> + <name>bhyve</name> + <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid> + <memory>219136</memory> + <vcpu>1</vcpu> + <bootloader>/usr/sbin/bhyveload</bootloader> + <bootloader_args>-foo</bootloader_args> + <os> + <type>hvm</type> + </os> + <devices> + <disk type='file'> + <driver name='file' type='raw'/> + <source file='/tmp/freebsd.img'/> + <target dev='hda' bus='sata'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </disk> + <interface type='bridge'> + <model type='virtio'/> + <source bridge="virbr0"/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </interface> + </devices> +</domain> diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.args b/tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.args new file mode 100644 index 0000000..d46ffab --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.args @@ -0,0 +1,4 @@ +/usr/sbin/bhyve -l bootrom,/path/to/rom.fd \ +-c 1 -m 214 -u -H -P -s 0:0,hostbridge \ +-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \ +-s 2:0,ahci-hd,/tmp/freebsd.img bhyve diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.xml new file mode 100644 index 0000000..2da80c5 --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-bootrom.xml @@ -0,0 +1,23 @@ +<domain type='bhyve'> + <name>bhyve</name> + <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid> + <memory>219136</memory> + <vcpu>1</vcpu> + <bootloader>/path/to/rom.fd</bootloader> + <os> + <type>hvm</type> + </os> + <devices> + <disk type='file'> + <driver name='file' type='raw'/> + <source file='/tmp/freebsd.img'/> + <target dev='hda' bus='sata'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </disk> + <interface type='bridge'> + <model type='virtio'/> + <source bridge="virbr0"/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </interface> + </devices> +</domain> diff --git a/tests/bhyvexml2argvmock.c b/tests/bhyvexml2argvmock.c index 41058ca..797dc20 100644 --- a/tests/bhyvexml2argvmock.c +++ b/tests/bhyvexml2argvmock.c @@ -1,5 +1,6 @@ #include <config.h> +#include "virfile.h" #include "virstring.h" #include "virnetdev.h" #include "virnetdevtap.h" @@ -48,3 +49,15 @@ int virNetDevSetOnline(const char *ifname ATTRIBUTE_UNUSED, { return 0; } + +bool virFileIsExecutable(const char *file) +{ + if (STREQ(file, "/fizz_buzz_bazz")) + return true; + else if (STREQ(file, "/usr/local/sbin/grub-bhyve")) + return true; + else if (STREQ(file, "/usr/sbin/bhyveload")) + return true; + + return false; +} diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c index 3e57a78..2ff1ae3 100644 --- a/tests/bhyvexml2argvtest.c +++ b/tests/bhyvexml2argvtest.c @@ -23,6 +23,7 @@ static int testCompareXMLToArgvFiles(const char *xml, virDomainDefPtr vmdef = NULL; virCommandPtr cmd = NULL, ldcmd = NULL; virConnectPtr conn; + bool external_loader = NULL; int ret = -1; if (!(conn = virGetConnect())) @@ -34,33 +35,35 @@ static int testCompareXMLToArgvFiles(const char *xml, conn->privateData = &driver; - if (!(cmd = virBhyveProcessBuildBhyveCmd(conn, vmdef, false))) + if (!(cmd = virBhyveProcessBuildBhyveCmd(conn, vmdef, &external_loader, false))) goto out; if (!(actualargv = virCommandToString(cmd))) goto out; - if (!(ldcmd = virBhyveProcessBuildLoadCmd(conn, vmdef, "<device.map>", - &actualdm))) - goto out; - - if (actualdm != NULL) - virTrimSpaces(actualdm, NULL); - - if (!(actualld = virCommandToString(ldcmd))) - goto out; + if (external_loader) { + if (!(ldcmd = virBhyveProcessBuildLoadCmd(conn, vmdef, "<device.map>", + &actualdm))) + goto out; - if (virtTestCompareToFile(actualargv, cmdline) < 0) - goto out; + if (actualdm != NULL) + virTrimSpaces(actualdm, NULL); - if (virtTestCompareToFile(actualld, ldcmdline) < 0) - goto out; + if (!(actualld = virCommandToString(ldcmd))) + goto out; - if (virFileExists(dmcmdline) || actualdm) { - if (virtTestCompareToFile(actualdm, dmcmdline) < 0) + if (virtTestCompareToFile(actualld, ldcmdline) < 0) goto out; + + if (virFileExists(dmcmdline) || actualdm) { + if (virtTestCompareToFile(actualdm, dmcmdline) < 0) + goto out; + } } + if (virtTestCompareToFile(actualargv, cmdline) < 0) + goto out; + ret = 0; out: @@ -118,7 +121,7 @@ mymain(void) } while (0) driver.grubcaps = BHYVE_GRUB_CAP_CONSDEV; - driver.bhyvecaps = BHYVE_CAP_RTC_UTC; + driver.bhyvecaps = BHYVE_CAP_RTC_UTC | BHYVE_CAP_BOOTROM; DO_TEST("base"); DO_TEST("acpiapic"); @@ -130,8 +133,10 @@ mymain(void) DO_TEST("grub-defaults"); DO_TEST("grub-bootorder"); DO_TEST("grub-bootorder2"); + DO_TEST("bhyveload"); DO_TEST("bhyveload-explicitargs"); DO_TEST("custom-loader"); + DO_TEST("bootrom"); DO_TEST("disk-cdrom-grub"); DO_TEST("serial-grub"); DO_TEST("localtime"); -- 2.6.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list