Page MenuHomeFreeBSD

D2505.1786482273.diff
No OneTemporary

Size
29 KB
Referenced Files
None
Subscribers
None

D2505.1786482273.diff

Index: share/examples/bhyve/guest.conf.sample
===================================================================
--- /dev/null
+++ share/examples/bhyve/guest.conf.sample
@@ -0,0 +1,26 @@
+name = "vm";
+cpus = 2;
+memory = 1024MB;
+console = "/dev/nmdm0001A";
+device [
+ {
+ slot = "0:0";
+ type = "hostbridge";
+ }
+ {
+ slot = "1:0";
+ type = "lpc";
+ }
+]
+acpi = true;
+vmexit_on_hlt = true;
+vmexit_on_pause = true;
+disk {
+ type = "virtio-blk";
+ path = "/path/to/image";
+}
+network {
+ type = "virtio-net";
+ name = "tap0";
+}
+
Index: usr.sbin/bhyve/Makefile
===================================================================
--- usr.sbin/bhyve/Makefile
+++ usr.sbin/bhyve/Makefile
@@ -14,6 +14,7 @@
bhyverun.c \
block_if.c \
consport.c \
+ config.c \
dbgport.c \
inout.c \
ioapic.c \
@@ -43,7 +44,8 @@
.PATH: ${.CURDIR}/../../sys/amd64/vmm
SRCS+= vmm_instruction_emul.c
-LIBADD= vmmapi md pthread
+CFLAGS+=-I${.CURDIR}/../../contrib/libucl/include
+LIBADD= vmmapi md pthread ucl
WARNS?= 2
Index: usr.sbin/bhyve/bhyve.8
===================================================================
--- usr.sbin/bhyve/bhyve.8
+++ usr.sbin/bhyve/bhyve.8
@@ -41,6 +41,8 @@
.Op Fl s Ar slot,emulation Ns Op , Ns Ar conf
.Op Fl U Ar uuid
.Ar vmname
+.Nm
+.Op Fl f Ar guest.conf
.Sh DESCRIPTION
.Nm
is a hypervisor that runs guest operating systems inside a
@@ -260,6 +262,8 @@
Alphanumeric name of the guest.
This should be the same as that created by
.Xr bhyveload 8 .
+.It Fl f
+Use a configuration file.
.El
.Sh EXAMPLES
The guest operating system must have been loaded with
@@ -308,6 +312,11 @@
-l com1,/dev/nmdm0A \\
-A -H -P -m 8G
.Ed
+.Pp
+To create a virtual machine using a configuration file:
+.Bd -literal -offset ident
+bhyve -f guest.conf
+.Ed
.Sh SEE ALSO
.Xr bhyve 4 ,
.Xr nmdm 4 ,
Index: usr.sbin/bhyve/bhyverun.c
===================================================================
--- usr.sbin/bhyve/bhyverun.c
+++ usr.sbin/bhyve/bhyverun.c
@@ -38,6 +38,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <err.h>
#include <libgen.h>
@@ -67,6 +68,9 @@
#include "spinup_ap.h"
#include "rtc.h"
+#include "config.h"
+#include <ucl.h>
+
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
#define MB (1024UL * 1024)
@@ -122,13 +126,14 @@
{
fprintf(stderr,
- "Usage: %s [-abehuwxACHPWY] [-c vcpus] [-g <gdb port>] [-l <lpc>]\n"
- " %*s [-m mem] [-p vcpu:hostcpu] [-s <pci>] [-U uuid] <vm>\n"
+ "Usage: %s [-abehuwxACHPWY] [-c vcpus] [-f <config-file>] [-g <gdb port>]\n"
+ " %*s [-l <lpc>] [-m mem] [-p vcpu:hostcpu] [-s <pci>] [-U uuid] <vm>\n"
" -a: local apic is in xAPIC mode (deprecated)\n"
" -A: create ACPI tables\n"
" -c: # cpus (default 1)\n"
" -C: include guest memory in core file\n"
" -e: exit on unhandled I/O access\n"
+ " -f: UCL config file to read\n"
" -g: gdb port\n"
" -h: help\n"
" -H: vmexit from the guest on hlt\n"
@@ -697,6 +702,9 @@
struct vmctx *ctx;
uint64_t rip;
size_t memsize;
+ struct config_entry *cb;
+ char *temp;
+ int slot, pci_err;
bvmcons = 0;
dump_guest_memory = 0;
@@ -706,8 +714,9 @@
memsize = 256 * MB;
mptgen = 1;
rtc_localtime = 1;
+ temp = NULL;
- while ((c = getopt(argc, argv, "abehuwxACHIPWYp:g:c:s:m:l:U:")) != -1) {
+ while ((c = getopt(argc, argv, "abehuwxACHIPWYp:f:g:c:s:m:l:U:")) != -1) {
switch (c) {
case 'a':
x2apic_mode = 0;
@@ -718,13 +727,74 @@
case 'b':
bvmcons = 1;
break;
+ case 'f':
+ cb = parse_conf(optarg);
+
+ vmname = cb->vmname;
+ guest_ncpus = cb->vcpus;
+
+ asprintf(&temp, "%zu", cb->memsize);
+ vm_parse_memsize(temp, &memsize);
+ free(temp);
+
+ asprintf(&temp, "com1,%s", cb->console);
+ lpc_device_parse(temp);
+ free(temp);
+
+ if (cb->pincpu && pincpu_parse(cb->pincpu) != 0) {
+ errx(EX_USAGE, "invalid vcpu pinning "
+ "configuration '%s'", cb->pincpu);
+ }
+
+ guest_uuid_str = cb->uuid;
+ gdb_port = cb->gdb_port;
+ acpi = cb->acpi;
+ dump_guest_memory = cb->dump_memory;
+ guest_vmexit_on_hlt = cb->vmexit_on_hlt;
+ guest_vmexit_on_pause = cb->vmexit_on_pause;
+ strictio = cb->strictio;
+ rtc_localtime = cb->rtc_localtime;
+ strictmsr = cb->strictmsr;
+ virtio_msix = cb->virtio_msix;
+ x2apic_mode = cb->x2apic_mode;
+ mptgen = cb->mptgen;
+
+ for (slot = 0; slot < cb->slot_count; slot++) {
+ if (strcasecmp(cb->slots[slot]->emul, "virtio-blk") == 0 ||
+ strcasecmp(cb->slots[slot]->emul, "ahci-hd") == 0) {
+ asprintf(&cb->slots[slot]->config, "%s%s%s%s",
+ cb->slots[slot]->disk.path,
+ (cb->slots[slot]->disk.nocache ? ",nocache" : ""),
+ (cb->slots[slot]->disk.sync ? ",sync" : ""),
+ (cb->slots[slot]->disk.ro ? ",ro" : ""));
+ } else if (strcasecmp(cb->slots[slot]->emul, "ahci-cd") == 0) {
+ asprintf(&cb->slots[slot]->config, "%s%s%s%s",
+ cb->slots[slot]->disk.path,
+ (cb->slots[slot]->disk.nocache ? ",nocache" : ""),
+ (cb->slots[slot]->disk.sync ? ",sync" : ""),
+ ",ro");
+ } else if (strcasecmp(cb->slots[slot]->emul, "virtio-net") == 0) {
+ asprintf(&cb->slots[slot]->config, "%s%s%s",
+ cb->slots[slot]->iface.name,
+ (cb->slots[slot]->iface.mac != NULL ? "," : ""),
+ (cb->slots[slot]->iface.mac != NULL ? cb->slots[slot]->iface.mac : ""));
+ }
+ pci_err = pci_create_slot(cb->slots[slot]->bnum,
+ cb->slots[slot]->snum,
+ cb->slots[slot]->fnum,
+ cb->slots[slot]->emul,
+ cb->slots[slot]->config);
+ if (pci_err != 0)
+ errx(1, "Failed to parse PCI configuration");
+ }
+ break;
case 'p':
- if (pincpu_parse(optarg) != 0) {
- errx(EX_USAGE, "invalid vcpu pinning "
- "configuration '%s'", optarg);
- }
+ if (pincpu_parse(optarg) != 0) {
+ errx(EX_USAGE, "invalid vcpu pinning "
+ "configuration '%s'", optarg);
+ }
break;
- case 'c':
+ case 'c':
guest_ncpus = atoi(optarg);
break;
case 'C':
@@ -786,7 +856,7 @@
mptgen = 0;
break;
case 'h':
- usage(0);
+ usage(0);
default:
usage(1);
}
@@ -794,11 +864,12 @@
argc -= optind;
argv += optind;
- if (argc != 1)
+ if (!vmname && argc > 0)
+ vmname = argv[0];
+
+ if (!vmname)
usage(1);
- vmname = argv[0];
-
ctx = vm_open(vmname);
if (ctx == NULL) {
perror("vm_open");
@@ -821,6 +892,7 @@
if (dump_guest_memory)
vm_set_memflags(ctx, VM_MEM_F_INCORE);
+
err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
if (err) {
fprintf(stderr, "Unable to setup memory (%d)\n", err);
@@ -876,8 +948,8 @@
/*
* Change the proc title to include the VM name.
*/
- setproctitle("%s", vmname);
-
+ setproctitle("%s", vmname);
+
/*
* Add CPU 0
*/
Index: usr.sbin/bhyve/config.h
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/config.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2015 Marcelo Araujo <araujo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <stdbool.h>
+
+#include <ucl.h>
+
+#define STR_SIZE 254
+#define NDISKS 32
+
+struct config_iface_entry {
+ char *name;
+ char *mac;
+};
+
+struct config_disk_entry {
+ char *path;
+ bool nocache;
+ bool sync;
+ bool ro;
+};
+
+struct config_slot_entry {
+ int bnum;
+ int snum;
+ int fnum;
+ char *emul;
+ char *config;
+ union {
+ struct config_iface_entry iface;
+ struct config_disk_entry disk;
+ };
+};
+
+struct config_entry {
+ char *vmname;
+ int vcpus;
+ size_t memsize;
+ char *console;
+ char *bootdisk; /* do not need? */
+ char *pincpu;
+ char *lpc_device;
+ char *uuid;
+ struct config_slot_entry *slots[255];
+ int slot_count;
+ int gdb_port;
+ bool acpi;
+ bool dump_memory;
+ bool vmexit_on_hlt;
+ bool vmexit_on_pause;
+ bool strictio;
+ bool rtc_localtime;
+ bool strictmsr;
+ bool virtio_msix;
+ bool x2apic_mode;
+ bool mptgen;
+};
+
+struct config_entry* parse_conf(char *config_file);
+int load_config(const char *fname);
+int check_config(struct config_entry *config);
+char* parse_string_safe(const ucl_object_t *obj, char *path);
+bool parse_pci_slot(const char *str, int *bnum, int *snum, int *fnum);
+
+void ucl_obj_dump(const ucl_object_t *obj, unsigned int shift);
Index: usr.sbin/bhyve/config.c
===================================================================
--- /dev/null
+++ usr.sbin/bhyve/config.c
@@ -0,0 +1,429 @@
+/*-
+ * Copyright (c) 2015 Marcelo Araujo <araujo@FreeBSD.org>
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <sysexits.h>
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "config.h"
+
+struct config_slot_entry sinit = {
+ 0,
+ 0,
+ 0,
+ NULL,
+ NULL
+};
+
+struct config_entry cinit = {
+ NULL,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ {NULL},
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+/*
+ * Check if the config file exist.
+ */
+int
+load_config(const char *fname)
+{
+ FILE *file;
+ if ((file = fopen(fname, "r"))) {
+ fclose(file);
+ return 0;
+ }
+
+ errx(EX_USAGE, "Config file does not exist: %s", fname);
+ return 1;
+}
+
+/*
+ * Check if the basic variables are setting in
+ * the config file.
+ */
+int
+check_config(struct config_entry *config)
+{
+ if (!config->vmname)
+ errx(EX_USAGE, "name not defined");
+ else if (!config->memsize)
+ errx(EX_USAGE, "memory not defined");
+ else if (!config->vcpus)
+ errx(EX_USAGE, "vcpus not defined");
+ /*
+ else if (!config->bootdisk)
+ errx(EX_USAGE, "no boot disk found");
+ */
+ else if (!config->console)
+ errx(EX_USAGE, "console not defined");
+
+ return (0);
+}
+
+/*
+ * Parse the config file.
+ */
+struct config_entry *
+parse_conf(char *config_file)
+{
+ struct config_entry *c = NULL;
+ const char *config = config_file;
+ struct ucl_parser *p = NULL;
+ ucl_object_t *obj = NULL;
+ const ucl_object_t *cur, *acur;
+ ucl_object_iter_t it = NULL, ait = NULL;
+ const char *key;
+ char *tmp;
+
+ if (load_config(config) == 1)
+ errx(EXIT_FAILURE, "No config file found: %s", config);
+
+ p = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE |
+ UCL_PARSER_NO_IMPLICIT_ARRAYS);
+ if (p == NULL)
+ errx(1, "Could not allocate ucl parser");
+
+ if (!ucl_parser_add_file(p, config)) {
+ if (errno != ENOENT)
+ errx(EXIT_FAILURE, "Parse error in file %s: %s",
+ config, ucl_parser_get_error(p));
+ ucl_parser_free(p);
+ }
+
+ obj = ucl_parser_get_object(p);
+ if (obj->type != UCL_OBJECT)
+ warnx("Invalid configuration format.\n");
+
+ c = malloc(sizeof(struct config_entry));
+ memcpy(c, &cinit, sizeof(struct config_entry));
+
+ it = ucl_object_iterate_new(obj);
+ while ((cur = ucl_object_iterate_safe(it, true)) != NULL) {
+ key = ucl_object_key(cur);
+ if (strcasecmp(key, "name") == 0)
+ c->vmname = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "cpus") == 0) {
+ if (!ucl_object_toint_safe(cur, (long *)&c->vcpus))
+ errx(EXIT_FAILURE, "Invalid number of CPUs specified");
+ } else if (strcasecmp(key, "memory") == 0) {
+ if (!ucl_object_toint_safe(cur, (size_t *)&c->memsize))
+ errx(EXIT_FAILURE, "Invalid amount of memory specified");
+ } else if (strcasecmp(key, "console") == 0)
+ c->console = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "bootdisk") == 0)
+ c->bootdisk = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "pincpu") == 0)
+ c->pincpu = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "lpc") == 0)
+ c->lpc_device = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "uuid") == 0)
+ c->uuid = parse_string_safe(cur, NULL);
+ else if (strcasecmp(key, "device") == 0) {
+ switch (ucl_object_type(cur)) {
+ case UCL_OBJECT:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ tmp = parse_string_safe(cur, ".slot");
+ parse_pci_slot(tmp,
+ &c->slots[c->slot_count]->bnum,
+ &c->slots[c->slot_count]->snum,
+ &c->slots[c->slot_count]->fnum);
+ c->slots[c->slot_count]->emul = parse_string_safe(cur, ".type");
+ c->slots[c->slot_count]->config = parse_string_safe(cur, ".config");
+ free(tmp);
+ c->slot_count++;
+ break;
+ case UCL_ARRAY:
+ ait = ucl_object_iterate_new(cur);
+ while ((acur = ucl_object_iterate_safe(ait, true)) != NULL) {
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ tmp = parse_string_safe(acur, ".slot");
+ parse_pci_slot(tmp,
+ &c->slots[c->slot_count]->bnum,
+ &c->slots[c->slot_count]->snum,
+ &c->slots[c->slot_count]->fnum);
+ c->slots[c->slot_count]->emul = parse_string_safe(acur, ".type");
+ c->slots[c->slot_count]->config = parse_string_safe(acur, ".config");
+ free(tmp);
+ c->slot_count++;
+ }
+ ucl_object_iterate_free(ait);
+ break;
+ case UCL_STRING:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->emul = parse_string_safe(cur, NULL);
+ c->slot_count++;
+ break;
+ default:
+ warnx("Error parsing disk contain");
+ }
+ } else if (strcasecmp(key, "network") == 0) {
+ switch (ucl_object_type(cur)) {
+ case UCL_OBJECT:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->emul = parse_string_safe(cur, ".type");
+ c->slots[c->slot_count]->iface.name = parse_string_safe(cur, ".name");
+ c->slots[c->slot_count]->iface.mac = parse_string_safe(cur, ".mac");
+ c->slots[c->slot_count]->bnum = c->slot_count;
+ c->slot_count++;
+ break;
+ case UCL_ARRAY:
+ ait = ucl_object_iterate_new(cur);
+ while ((acur = ucl_object_iterate_safe(ait, true)) != NULL) {
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->emul = parse_string_safe(acur, ".type");
+ c->slots[c->slot_count]->iface.name = parse_string_safe(acur, ".name");
+ c->slots[c->slot_count]->iface.mac = parse_string_safe(acur, ".mac");
+ c->slots[c->slot_count]->bnum = c->slot_count;
+ c->slot_count++;
+ }
+ ucl_object_iterate_free(ait);
+ break;
+ case UCL_STRING:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->iface.name = parse_string_safe(cur, NULL);
+ c->slots[c->slot_count]->bnum = c->slot_count;
+ c->slot_count++;
+ break;
+ default:
+ warnx("Error parsing disk contain");
+ }
+ } else if (strcasecmp(key, "disk") == 0) {
+ switch (ucl_object_type(cur)) {
+ case UCL_OBJECT:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->emul = parse_string_safe(cur, ".type");
+ c->slots[c->slot_count]->disk.path = parse_string_safe(cur, ".path");
+ ucl_object_toboolean_safe(ucl_lookup_path(cur, ".nocache"), &c->slots[c->slot_count]->disk.nocache);
+ ucl_object_toboolean_safe(ucl_lookup_path(cur, ".sync"), &c->slots[c->slot_count]->disk.sync);
+ ucl_object_toboolean_safe(ucl_lookup_path(cur, ".readonly"), &c->slots[c->slot_count]->disk.ro);
+ c->slots[c->slot_count]->bnum = c->slot_count;
+ c->slot_count++;
+ break;
+ case UCL_ARRAY:
+ ait = ucl_object_iterate_new(cur);
+ while ((acur = ucl_object_iterate_safe(ait, true)) != NULL) {
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->emul = parse_string_safe(acur, ".type");
+ c->slots[c->slot_count]->disk.path = parse_string_safe(acur, ".path");
+ ucl_object_toboolean_safe(ucl_lookup_path(acur, ".nocache"), &c->slots[c->slot_count]->disk.nocache);
+ ucl_object_toboolean_safe(ucl_lookup_path(acur, ".sync"), &c->slots[c->slot_count]->disk.sync);
+ ucl_object_toboolean_safe(ucl_lookup_path(acur, ".readonly"), &c->slots[c->slot_count]->disk.ro);
+ c->slots[c->slot_count]->bnum = c->slot_count;
+ c->slot_count++;
+ }
+ ucl_object_iterate_free(ait);
+ break;
+ case UCL_STRING:
+ c->slots[c->slot_count] = malloc(sizeof(struct config_slot_entry));
+ memcpy(c->slots[c->slot_count], &sinit, sizeof(struct config_slot_entry));
+ c->slots[c->slot_count]->disk.path = parse_string_safe(cur, NULL);
+ c->slots[c->slot_count]->bnum = c->slot_count;
+ c->slot_count++;
+ break;
+ default:
+ warnx("Error parsing disk contain");
+ }
+ } else if (strcasecmp(key, "gdbport") == 0) {
+ if (!ucl_object_toint_safe(cur, (long *)&c->gdb_port))
+ warnx("Invalid GDB port specified");
+ } else if (strcasecmp(key, "acpi") == 0)
+ ucl_object_toboolean_safe(cur, &c->acpi);
+ else if (strcasecmp(key, "dump_memory") == 0)
+ ucl_object_toboolean_safe(cur, &c->dump_memory);
+ else if (strcasecmp(key, "vmexit_on_hlt") == 0)
+ ucl_object_toboolean_safe(cur, &c->vmexit_on_hlt);
+ else if (strcasecmp(key, "vmexit_on_pause") == 0)
+ ucl_object_toboolean_safe(cur, &c->vmexit_on_pause);
+ else if (strcasecmp(key, "strictio") == 0)
+ ucl_object_toboolean_safe(cur, &c->strictio);
+ else if (strcasecmp(key, "rtc_localtime") == 0)
+ ucl_object_toboolean_safe(cur, &c->rtc_localtime);
+ else if (strcasecmp(key, "strictmsr") == 0)
+ ucl_object_toboolean_safe(cur, &c->strictmsr);
+ else if (strcasecmp(key, "virtio_msix") == 0)
+ ucl_object_toboolean_safe(cur, &c->virtio_msix);
+ else if (strcasecmp(key, "x2apic_mode") == 0)
+ ucl_object_toboolean_safe(cur, &c->x2apic_mode);
+ else if (strcasecmp(key, "mptgen") == 0)
+ ucl_object_toboolean_safe(cur, &c->mptgen);
+ }
+ ucl_object_iterate_free(it);
+
+ check_config(c);
+
+ if (p != NULL)
+ ucl_parser_free(p);
+ if (obj != NULL)
+ ucl_object_unref(obj);
+
+ return c;
+}
+
+char *
+parse_string_safe(const ucl_object_t *obj, char *path)
+{
+ const ucl_object_t *target = NULL;
+ char *str = NULL;
+
+ if (path != NULL)
+ target = ucl_lookup_path(obj, path);
+ else
+ target = obj;
+
+ if (target == NULL)
+ return NULL;
+
+ str = (char *)ucl_object_tostring(target);
+ if (str != NULL)
+ return strdup(str);
+
+ return (str);
+}
+
+bool
+parse_pci_slot(const char *str, int *bnum, int *snum, int *fnum)
+{
+ if (str == NULL)
+ return (false);
+ /* <bus>:<slot>:<func> */
+ if (sscanf(str, "%d:%d:%d", bnum, snum, fnum) != 3) {
+ *bnum = 0;
+ /* <slot>:<func> */
+ if (sscanf(str, "%d:%d", snum, fnum) != 2) {
+ *fnum = 0;
+ /* <slot> */
+ if (sscanf(str, "%d", snum) != 1) {
+ *snum = -1;
+ return (false);
+ }
+ }
+ }
+ return (true);
+}
+
+void
+ucl_obj_dump(const ucl_object_t *obj, unsigned int shift)
+{
+ int num = shift * 2 + 5;
+ char *pre = (char *) malloc (num * sizeof(char));
+ const ucl_object_t *cur, *tmp;
+ ucl_object_iter_t it = NULL, it_obj = NULL;
+
+ pre[--num] = 0x00;
+ while (num--)
+ pre[num] = 0x20;
+
+ tmp = obj;
+
+ while ((obj = ucl_iterate_object (tmp, &it, false))) {
+ printf ("%sucl object address: %p\n", pre + 4, obj);
+ if (obj->key != NULL) {
+ printf ("%skey: \"%s\"\n", pre, ucl_object_key (obj));
+ }
+ printf ("%sref: %u\n", pre, obj->ref);
+ printf ("%slen: %u\n", pre, obj->len);
+ printf ("%sprev: %p\n", pre, obj->prev);
+ printf ("%snext: %p\n", pre, obj->next);
+ if (ucl_object_type(obj) == UCL_OBJECT) {
+ printf ("%stype: UCL_OBJECT\n", pre);
+ printf ("%svalue: %p\n", pre, obj->value.ov);
+ it_obj = NULL;
+ while ((cur = ucl_iterate_object (obj, &it_obj, true))) {
+ ucl_obj_dump (cur, shift + 2);
+ }
+ }
+ else if (ucl_object_type(obj) == UCL_ARRAY) {
+ printf ("%stype: UCL_ARRAY\n", pre);
+ printf ("%svalue: %p\n", pre, obj->value.av);
+ it_obj = NULL;
+ while ((cur = ucl_iterate_object (obj, &it_obj, true))) {
+ ucl_obj_dump (cur, shift + 2);
+ }
+ }
+ else if (ucl_object_type(obj) == UCL_INT) {
+ printf ("%stype: UCL_INT\n", pre);
+ printf ("%svalue: %jd\n", pre, (intmax_t)ucl_object_toint (obj));
+ }
+ else if (ucl_object_type(obj) == UCL_FLOAT) {
+ printf ("%stype: UCL_FLOAT\n", pre);
+ printf ("%svalue: %f\n", pre, ucl_object_todouble (obj));
+ }
+ else if (ucl_object_type(obj) == UCL_STRING) {
+ printf ("%stype: UCL_STRING\n", pre);
+ printf ("%svalue: \"%s\"\n", pre, ucl_object_tostring (obj));
+ }
+ else if (ucl_object_type(obj) == UCL_BOOLEAN) {
+ printf ("%stype: UCL_BOOLEAN\n", pre);
+ printf ("%svalue: %s\n", pre, ucl_object_tostring_forced (obj));
+ }
+ else if (ucl_object_type(obj) == UCL_TIME) {
+ printf ("%stype: UCL_TIME\n", pre);
+ printf ("%svalue: %f\n", pre, ucl_object_todouble (obj));
+ }
+ else if (ucl_object_type(obj) == UCL_USERDATA) {
+ printf ("%stype: UCL_USERDATA\n", pre);
+ printf ("%svalue: %p\n", pre, obj->value.ud);
+ }
+ }
+
+ free (pre);
+}
\ No newline at end of file
Index: usr.sbin/bhyve/pci_emul.h
===================================================================
--- usr.sbin/bhyve/pci_emul.h
+++ usr.sbin/bhyve/pci_emul.h
@@ -227,6 +227,7 @@
int pci_msix_pba_bar(struct pci_devinst *pi);
int pci_msi_msgnum(struct pci_devinst *pi);
int pci_parse_slot(char *opt);
+int pci_create_slot(int bnum, int snum, int fnum, char *emul, char *config);
void pci_populate_msicap(struct msicap *cap, int msgs, int nextptr);
int pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum);
int pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,
Index: usr.sbin/bhyve/pci_emul.c
===================================================================
--- usr.sbin/bhyve/pci_emul.c
+++ usr.sbin/bhyve/pci_emul.c
@@ -166,8 +166,6 @@
int
pci_parse_slot(char *opt)
{
- struct businfo *bi;
- struct slotinfo *si;
char *emul, *config, *str, *cp;
int error, bnum, snum, fnum;
@@ -200,6 +198,26 @@
}
}
+ error = pci_create_slot(bnum, snum, fnum, emul, config);
+
+done:
+ if (error)
+ free(str);
+
+ return (error);
+}
+
+int
+pci_create_slot(int bnum, int snum, int fnum, char *emul, char *config)
+{
+ struct businfo *bi;
+ struct slotinfo *si;
+ char *opt;
+ int error;
+
+ error = -1;
+ asprintf(&opt, "%d:%d:%d,%s,%s", bnum, snum, fnum, emul, config);
+
if (bnum < 0 || bnum >= MAXBUSES || snum < 0 || snum >= MAXSLOTS ||
fnum < 0 || fnum >= MAXFUNCS) {
pci_parse_slot_usage(opt);
@@ -229,8 +247,7 @@
si->si_funcs[fnum].fi_param = config;
done:
- if (error)
- free(str);
+ free(opt);
return (error);
}
Index: usr.sbin/bhyveload/Makefile
===================================================================
--- usr.sbin/bhyveload/Makefile
+++ usr.sbin/bhyveload/Makefile
@@ -1,13 +1,17 @@
# $FreeBSD$
PROG= bhyveload
-SRCS= bhyveload.c
MAN= bhyveload.8
-LIBADD= vmmapi
+SRCS= bhyveload.c \
+ ${.CURDIR}/../bhyve/config.c
+
+LIBADD= vmmapi ucl
WARNS?= 3
CFLAGS+=-I${.CURDIR}/../../sys/boot/userboot
+CFLAGS+=-I${.CURDIR}/../bhyve
+CFLAGS+=-I${.CURDIR}/../../contrib/libucl/include
.include <bsd.prog.mk>
Index: usr.sbin/bhyveload/bhyveload.8
===================================================================
--- usr.sbin/bhyveload/bhyveload.8
+++ usr.sbin/bhyveload/bhyveload.8
@@ -41,6 +41,8 @@
.Op Fl h Ar host-path
.Op Fl m Ar mem-size
.Ar vmname
+.Nm
+.Op Fl f Ar guest.conf
.Sh DESCRIPTION
.Nm
is used to load a
@@ -111,6 +113,11 @@
The default value of
.Ar mem-size
is 256M.
+.It Fl f Ar guest.conf
+The
+.Ar guest.conf
+is the configuration file that contain all parameters
+necessary to load the guest.
.El
.Sh EXAMPLES
To create a virtual machine named
@@ -132,6 +139,10 @@
.Pa /dev/nmdm1B
.Pp
.Dl "bhyveload -m 256MB -h /usr/images/test -c /dev/nmdm1B test-vm"
+.Pp
+To create a virtual machine using a configuration file:
+.Pp
+.Dl "bhyveload -f guest.conf"
.Sh SEE ALSO
.Xr bhyve 4 ,
.Xr nmdm 4 ,
Index: usr.sbin/bhyveload/bhyveload.c
===================================================================
--- usr.sbin/bhyveload/bhyveload.c
+++ usr.sbin/bhyveload/bhyveload.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2011 NetApp, Inc.
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -82,6 +83,8 @@
#include <vmmapi.h>
+#include <config.h>
+
#include "userboot.h"
#define MB (1024 * 1024UL)
@@ -630,9 +633,10 @@
fprintf(stderr,
"usage: %s [-c <console-device>] [-d <disk-path>] [-e <name=value>]\n"
- " %*s [-h <host-path>] [-m mem-size] <vmname>\n",
+ " %*s [-f <config-file> [-h <host-path>] [-m mem-size]\n"
+ " %*s <vmname>\n",
progname,
- (int)strlen(progname), "");
+ (int)strlen(progname), (int)strlen(progname), "");
exit(1);
}
@@ -643,7 +647,7 @@
void (*func)(struct loader_callbacks *, void *, int, int);
uint64_t mem_size;
int opt, error, need_reinit;
-
+ struct config_entry config;
progname = basename(argv[0]);
mem_size = 256 * MB;
@@ -651,28 +655,45 @@
consin_fd = STDIN_FILENO;
consout_fd = STDOUT_FILENO;
- while ((opt = getopt(argc, argv, "c:d:e:h:m:")) != -1) {
+ while ((opt = getopt(argc, argv, "c:d:e:f:h:m:")) != -1) {
switch (opt) {
case 'c':
error = altcons_open(optarg);
if (error != 0)
errx(EX_USAGE, "Could not open '%s'", optarg);
break;
-
case 'd':
error = disk_open(optarg);
if (error != 0)
errx(EX_USAGE, "Could not open '%s'", optarg);
break;
-
case 'e':
addenv(optarg);
break;
-
+ case 'f':
+ if (load_config(optarg) == 0) {
+ config = parse_conf(optarg);
+ error = altcons_open(config.console);
+ if (error != 0)
+ errx(EX_USAGE, "Could not open console");
+ if (config.isofile)
+ error = disk_open(config.isofile);
+ else
+ error = disk_open(config.bootdisk);
+ if (error != 0 )
+ errx(EX_USAGE, "Could not open disk");
+ error = vm_parse_memsize(config.memsize, &mem_size);
+ if (error != 0)
+ errx(EX_USAGE, "Invalid memsize");
+ vmname = config.vmname;
+ } else {
+ errx(EX_USAGE, "Error to parse config file: %s", optarg);
+ exit (1);
+ }
+ break;
case 'h':
host_base = optarg;
break;
-
case 'm':
error = vm_parse_memsize(optarg, &mem_size);
if (error != 0)
@@ -686,10 +707,11 @@
argc -= optind;
argv += optind;
- if (argc != 1)
- usage();
+ if (!vmname && argc > 0)
+ vmname = argv[0];
- vmname = argv[0];
+ if (!vmname)
+ usage();
need_reinit = 0;
error = vm_create(vmname);

File Metadata

Mime Type
text/plain
Expires
Tue, Aug 11, 9:04 PM (32 s ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29397028
Default Alt Text
D2505.1786482273.diff (29 KB)

Event Timeline