[PATCH 0/9] bhyve: session mode support
This series implements user session support (bhyve:///session) for the bhyve driver. Roman Bogorodskiy (9): bhyve: move paths to driver configuration bhyve: capabilities: probe monitor mode support bhyve: initial unprivileged mode support bhyve: implement virDomainReset() bhyve: implement process management for monitor mode bhyve: implement reconnect for unprivileged mode bhyve: cleanup IPC sockets bhyve: bhyvexml2argvtest: test unprivileged mode docs: drvbhyve: document session mode docs/drvbhyve.rst | 24 ++- src/bhyve/bhyve_capabilities.c | 29 +++ src/bhyve/bhyve_capabilities.h | 2 + src/bhyve/bhyve_command.c | 32 +++ src/bhyve/bhyve_command.h | 6 + src/bhyve/bhyve_conf.c | 47 +++- src/bhyve/bhyve_conf.h | 2 +- src/bhyve/bhyve_domain.c | 30 ++- src/bhyve/bhyve_domain.h | 4 +- src/bhyve/bhyve_driver.c | 173 ++++++++++----- src/bhyve/bhyve_process.c | 201 ++++++++++++++---- src/bhyve/bhyve_process.h | 5 + src/bhyve/bhyve_utils.h | 13 +- .../bhyvexml2argv-uefi-unprivileged.args | 14 ++ tests/bhyvexml2argvtest.c | 35 ++- tests/bhyvexml2xmltest.c | 4 +- 16 files changed, 506 insertions(+), 115 deletions(-) create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-uefi-unprivileged.args -- 2.55.0
Currently, bhyve driver uses mainly constants for path, e.g. BHYVE_CONFIG_DIR. Move these paths to the driver configuration object. This is a preparation work for the session mode support which uses different paths. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_conf.c | 12 +++++++ src/bhyve/bhyve_domain.c | 7 ++-- src/bhyve/bhyve_domain.h | 4 ++- src/bhyve/bhyve_driver.c | 76 ++++++++++++++++++++++----------------- src/bhyve/bhyve_process.c | 24 +++++++------ src/bhyve/bhyve_utils.h | 10 +++--- 6 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/bhyve/bhyve_conf.c b/src/bhyve/bhyve_conf.c index f9a657f402..e0439af6fa 100644 --- a/src/bhyve/bhyve_conf.c +++ b/src/bhyve/bhyve_conf.c @@ -57,12 +57,19 @@ virBhyveDriverConfigNew(void) if (!(cfg = virObjectNew(virBhyveDriverConfigClass))) return NULL; + cfg->configBaseDir = g_strdup(SYSCONFDIR "/libvirt"); + cfg->firmwareDir = g_strdup(DATADIR "/uefi-firmware"); cfg->libDir = g_strdup_printf("%s/lib/libvirt/bhyve", LOCALSTATEDIR); cfg->nvramDir = g_strdup_printf("%s/nvram", cfg->libDir); cfg->ubootPath = g_strdup(DATADIR "/u-boot/u-boot-bhyve-arm64/u-boot.bin"); + cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir); + cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", cfg->configBaseDir); + cfg->stateDir = g_strdup_printf("%s/libvirt/bhyve", RUNSTATEDIR); + cfg->logDir = g_strdup_printf("%s/log/libvirt/bhyve", LOCALSTATEDIR); + cfg->bhyveloadTimeout = 300; cfg->bhyveloadTimeoutKill = 15; @@ -114,9 +121,14 @@ virBhyveDriverConfigDispose(void *obj) { struct _virBhyveDriverConfig *cfg = obj; + g_free(cfg->autostartDir); + g_free(cfg->configBaseDir); + g_free(cfg->configDir); g_free(cfg->firmwareDir); g_free(cfg->libDir); + g_free(cfg->logDir); g_free(cfg->nvramDir); + g_free(cfg->stateDir); g_free(cfg->ubootPath); } diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 3ecb1d52cb..3588557979 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -799,14 +799,15 @@ virBhyveDomainObjStopWorker(virDomainObj *dom) } int -bhyveDomainNamePathsCleanup(const char *name, +bhyveDomainNamePathsCleanup(virBhyveDriverConfig *cfg, + const char *name, bool bestEffort) { g_autofree char *cfg_file = NULL; g_autofree char *autostart_link = NULL; - cfg_file = virDomainConfigFile(BHYVE_CONFIG_DIR, name); - autostart_link = virDomainConfigFile(BHYVE_AUTOSTART_DIR, name); + cfg_file = virDomainConfigFile(cfg->configDir, name); + autostart_link = virDomainConfigFile(cfg->autostartDir, name); if (virFileExists(cfg_file) && unlink(cfg_file) < 0) { diff --git a/src/bhyve/bhyve_domain.h b/src/bhyve/bhyve_domain.h index c9fa776651..1bf6bace71 100644 --- a/src/bhyve/bhyve_domain.h +++ b/src/bhyve/bhyve_domain.h @@ -54,7 +54,9 @@ extern virXMLNamespace virBhyveDriverDomainXMLNamespace; int virBhyveDomainObjStartWorker(virDomainObj *dom); void virBhyveDomainObjStopWorker(virDomainObj *dom); -int bhyveDomainNamePathsCleanup(const char *name, bool bestEffort); +int bhyveDomainNamePathsCleanup(virBhyveDriverConfig *cfg, + const char *name, + bool bestEffort); int bhyveValidateLifecycleAction(virDomainLifecycleAction onPoweroff, virDomainLifecycleAction onReboot, virDomainLifecycleAction onCrash); diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index cf4e918472..7e8cc572e4 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -387,10 +387,12 @@ bhyveDomainGetAutostart(virDomainPtr domain, int *autostart) static int bhyveDomainSetAutostart(virDomainPtr domain, int autostart) { + struct _bhyveConn *privconn = domain->conn->privateData; virDomainObj *vm; char *configFile = NULL; char *autostartLink = NULL; int ret = -1; + g_autoptr(virBhyveDriverConfig) cfg = NULL; if (!(vm = bhyveDomObjFromDomain(domain))) goto cleanup; @@ -406,15 +408,17 @@ bhyveDomainSetAutostart(virDomainPtr domain, int autostart) autostart = (autostart != 0); + cfg = virBhyveDriverGetConfig(privconn); + if (vm->autostart != autostart) { - configFile = virDomainConfigFile(BHYVE_CONFIG_DIR, vm->def->name); - autostartLink = virDomainConfigFile(BHYVE_AUTOSTART_DIR, vm->def->name); + configFile = virDomainConfigFile(cfg->configDir, vm->def->name); + autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name); if (autostart) { - if (g_mkdir_with_parents(BHYVE_AUTOSTART_DIR, 0777) < 0) { + if (g_mkdir_with_parents(cfg->autostartDir, 0777) < 0) { virReportSystemError(errno, _("cannot create autostart directory %1$s"), - BHYVE_AUTOSTART_DIR); + cfg->autostartDir); goto cleanup; } @@ -541,6 +545,7 @@ bhyveDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flag virDomainObj *vm = NULL; virObjectEvent *event = NULL; g_autoptr(virCaps) caps = NULL; + g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(privconn); unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE | VIR_DOMAIN_DEF_PARSE_ABI_UPDATE; @@ -579,7 +584,7 @@ bhyveDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flag vm->persistent = 1; if (virDomainDefSave(vm->newDef ? vm->newDef : vm->def, - privconn->xmlopt, BHYVE_CONFIG_DIR) < 0) { + privconn->xmlopt, cfg->configDir) < 0) { virDomainObjListRemove(privconn->domains, vm); goto cleanup; } @@ -612,6 +617,7 @@ bhyveDomainUndefineFlags(virDomainPtr domain, unsigned int flags) virObjectEvent *event = NULL; virDomainObj *vm; g_autofree char *nvram_path = NULL; + g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(privconn); int ret = -1; virCheckFlags(VIR_DOMAIN_UNDEFINE_NVRAM | @@ -656,8 +662,8 @@ bhyveDomainUndefineFlags(virDomainPtr domain, unsigned int flags) } } - if (virDomainDeleteConfig(BHYVE_CONFIG_DIR, - BHYVE_AUTOSTART_DIR, + if (virDomainDeleteConfig(cfg->configDir, + cfg->autostartDir, vm) < 0) goto cleanup; @@ -1268,6 +1274,7 @@ bhyveDomainSetMetadata(virDomainPtr dom, virConnectPtr conn = dom->conn; struct _bhyveConn *privconn = conn->privateData; virDomainObj *vm; + g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(privconn); int ret = -1; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | @@ -1280,8 +1287,8 @@ bhyveDomainSetMetadata(virDomainPtr dom, goto cleanup; ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, - privconn->xmlopt, BHYVE_STATE_DIR, - BHYVE_CONFIG_DIR, flags); + privconn->xmlopt, cfg->stateDir, + cfg->configDir, flags); if (ret == 0) { virObjectEvent *ev = NULL; @@ -1370,13 +1377,13 @@ bhyveStateCleanup(void) virObjectUnref(bhyve_driver->xmlopt); virSysinfoDefFree(bhyve_driver->hostsysinfo); virObjectUnref(bhyve_driver->domainEventState); - virObjectUnref(bhyve_driver->config); virPortAllocatorRangeFree(bhyve_driver->remotePorts); if (bhyve_driver->lockFD != -1) - virPidFileRelease(BHYVE_STATE_DIR, "driver", bhyve_driver->lockFD); + virPidFileRelease(bhyve_driver->config->stateDir, "driver", bhyve_driver->lockFD); virMutexDestroy(&bhyve_driver->lock); + virObjectUnref(bhyve_driver->config); VIR_FREE(bhyve_driver->pidfile); VIR_FREE(bhyve_driver); @@ -1391,6 +1398,7 @@ bhyveStateInitialize(bool privileged, void *opaque G_GNUC_UNUSED) { virDomainDriverAutoStartConfig autostartCfg; + virBhyveDriverConfig *cfg; if (root != NULL) { virReportError(VIR_ERR_INVALID_ARG, "%s", @@ -1435,40 +1443,40 @@ bhyveStateInitialize(bool privileged, bhyve_driver->hostsysinfo = virSysinfoRead(); - if (!(bhyve_driver->config = virBhyveDriverConfigNew())) + if (!(bhyve_driver->config = cfg = virBhyveDriverConfigNew())) goto cleanup; if (virBhyveLoadDriverConfig(bhyve_driver->config, SYSCONFDIR "/libvirt/bhyve.conf") < 0) goto cleanup; - if (g_mkdir_with_parents(BHYVE_LOG_DIR, 0777) < 0) { + if (g_mkdir_with_parents(cfg->logDir, 0777) < 0) { virReportSystemError(errno, _("Failed to mkdir %1$s"), - BHYVE_LOG_DIR); + cfg->logDir); goto cleanup; } - if (g_mkdir_with_parents(BHYVE_STATE_DIR, 0777) < 0) { + if (g_mkdir_with_parents(cfg->stateDir, 0777) < 0) { virReportSystemError(errno, _("Failed to mkdir %1$s"), - BHYVE_STATE_DIR); + cfg->stateDir); goto cleanup; } if ((bhyve_driver->lockFD = - virPidFileAcquire(BHYVE_STATE_DIR, "driver", getpid())) < 0) + virPidFileAcquire(cfg->stateDir, "driver", getpid())) < 0) goto cleanup; if (virDomainObjListLoadAllConfigs(bhyve_driver->domains, - BHYVE_STATE_DIR, + cfg->stateDir, NULL, true, bhyve_driver->xmlopt, NULL, NULL) < 0) goto cleanup; if (virDomainObjListLoadAllConfigs(bhyve_driver->domains, - BHYVE_CONFIG_DIR, - BHYVE_AUTOSTART_DIR, false, + cfg->configDir, + cfg->autostartDir, false, bhyve_driver->xmlopt, NULL, NULL) < 0) goto cleanup; @@ -1476,7 +1484,7 @@ bhyveStateInitialize(bool privileged, virBhyveProcessReconnectAll(bhyve_driver); autostartCfg = (virDomainDriverAutoStartConfig) { - .stateDir = BHYVE_STATE_DIR, + .stateDir = cfg->stateDir, .callback = bhyveAutostartDomain, .opaque = bhyve_driver, }; @@ -2335,6 +2343,7 @@ bhyveDomainSetMemoryParameters(virDomainPtr domain, virDomainDef *persistentDef = NULL; virDomainObj *vm = NULL; int ret = -1; + g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(privconn); unsigned long long hard_limit = 0; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | @@ -2373,14 +2382,14 @@ bhyveDomainSetMemoryParameters(virDomainPtr domain, goto endjob; def->mem.hard_limit = hard_limit; - if (virDomainObjSave(vm, privconn->xmlopt, BHYVE_STATE_DIR) < 0) + if (virDomainObjSave(vm, privconn->xmlopt, cfg->stateDir) < 0) VIR_WARN("Failed to save status on vm %s", vm->def->name); } if (persistentDef) { persistentDef->mem.hard_limit = hard_limit; - if (virDomainDefSave(persistentDef, privconn->xmlopt, BHYVE_CONFIG_DIR) < 0) + if (virDomainDefSave(persistentDef, privconn->xmlopt, cfg->configDir) < 0) goto endjob; } @@ -2697,6 +2706,7 @@ bhyveDomainRenameCallback(virDomainObj *vm, g_autofree char *old_dom_name = NULL; g_autofree char *new_dom_cfg_file = NULL; g_autofree char *new_dom_autostart_link = NULL; + g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(privconn); virCheckFlags(0, ret); @@ -2708,13 +2718,13 @@ bhyveDomainRenameCallback(virDomainObj *vm, new_dom_name = g_strdup(new_name); - new_dom_cfg_file = virDomainConfigFile(BHYVE_CONFIG_DIR, new_dom_name); + new_dom_cfg_file = virDomainConfigFile(cfg->configDir, new_dom_name); - if (bhyveDomainNamePathsCleanup(new_name, false) < 0) + if (bhyveDomainNamePathsCleanup(cfg, new_name, false) < 0) goto cleanup; if (vm->autostart) { - new_dom_autostart_link = virDomainConfigFile(BHYVE_AUTOSTART_DIR, new_dom_name); + new_dom_autostart_link = virDomainConfigFile(cfg->autostartDir, new_dom_name); if (symlink(new_dom_cfg_file, new_dom_autostart_link) < 0) { virReportSystemError(errno, @@ -2728,7 +2738,7 @@ bhyveDomainRenameCallback(virDomainObj *vm, old_dom_name = g_steal_pointer(&vm->def->name); vm->def->name = g_steal_pointer(&new_dom_name); - if (virDomainDefSave(vm->def, privconn->xmlopt, BHYVE_CONFIG_DIR) < 0) + if (virDomainDefSave(vm->def, privconn->xmlopt, cfg->configDir) < 0) goto cleanup; event_old = virDomainEventLifecycleNew(vm->def->id, old_dom_name, vm->def->uuid, @@ -2750,9 +2760,9 @@ bhyveDomainRenameCallback(virDomainObj *vm, } virErrorPreserveLast(&err); - bhyveDomainNamePathsCleanup(new_dom_name, true); + bhyveDomainNamePathsCleanup(cfg, new_dom_name, true); } else { - bhyveDomainNamePathsCleanup(old_dom_name, true); + bhyveDomainNamePathsCleanup(cfg, old_dom_name, true); } virErrorRestore(&err); @@ -2865,6 +2875,7 @@ bhyveDomainSetLifecycleAction(virDomainPtr domain, virDomainObj *vm = NULL; virDomainDef *def = NULL; virDomainDef *persistentDef = NULL; + g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(privconn); int ret = -1; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | @@ -2893,7 +2904,7 @@ bhyveDomainSetLifecycleAction(virDomainPtr domain, bhyveDomainModifyLifecycleAction(def, type, action); if (virDomainObjSave(vm, privconn->xmlopt, - BHYVE_STATE_DIR) < 0) + cfg->stateDir) < 0) goto endjob; } @@ -2901,7 +2912,7 @@ bhyveDomainSetLifecycleAction(virDomainPtr domain, bhyveDomainModifyLifecycleAction(persistentDef, type, action); if (virDomainDefSave(persistentDef, privconn->xmlopt, - BHYVE_CONFIG_DIR) < 0) + cfg->configDir) < 0) goto endjob; } @@ -2923,6 +2934,7 @@ bhyveDomainAgentSetResponseTimeout(virDomainPtr domain, virDomainObj *vm = NULL; bhyveDomainObjPrivate *priv = NULL; struct _bhyveConn *privconn = domain->conn->privateData; + g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(privconn); int ret = -1; virCheckFlags(0, -1); @@ -2950,7 +2962,7 @@ bhyveDomainAgentSetResponseTimeout(virDomainPtr domain, priv->agentTimeout = timeout; if (virDomainObjIsActive(vm)) { - if (virDomainObjSave(vm, privconn->xmlopt, BHYVE_STATE_DIR) < 0) + if (virDomainObjSave(vm, privconn->xmlopt, cfg->stateDir) < 0) VIR_WARN("Failed to save status on vm %s", vm->def->name); } diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index 65cf61c578..4144f8230e 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -32,6 +32,7 @@ #include <net/if.h> #include <net/if_tap.h> +#include "bhyve_conf.h" #include "bhyve_device.h" #include "bhyve_driver.h" #include "bhyve_capabilities.h" @@ -98,9 +99,12 @@ bhyveNetCleanup(virDomainObj *vm) } static void -virBhyveFormatDevMapFile(const char *vm_name, char **fn_out) +virBhyveFormatDevMapFile(virBhyveDriverConfig *cfg, + const char *vm_name, + char **fn_out) { - *fn_out = g_strdup_printf("%s/grub_bhyve-%s-device.map", BHYVE_STATE_DIR, vm_name); + *fn_out = g_strdup_printf("%s/grub_bhyve-%s-device.map", + cfg->stateDir, vm_name); } static int @@ -307,8 +311,9 @@ virBhyveProcessStartImpl(struct _bhyveConn *driver, virTimeBackOffVar timebackoff; int ret = -1, rc; bool vmm_appeared = false; + g_autoptr(virBhyveDriverConfig) cfg = virBhyveDriverGetConfig(driver); - logfile = g_strdup_printf("%s/%s.log", BHYVE_LOG_DIR, vm->def->name); + logfile = g_strdup_printf("%s/%s.log", cfg->logDir, vm->def->name); if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { virReportSystemError(errno, @@ -318,7 +323,7 @@ virBhyveProcessStartImpl(struct _bhyveConn *driver, } VIR_FREE(driver->pidfile); - if (!(driver->pidfile = virPidFileBuildPath(BHYVE_STATE_DIR, + if (!(driver->pidfile = virPidFileBuildPath(cfg->stateDir, vm->def->name))) { virReportSystemError(errno, "%s", _("Failed to build pidfile path")); @@ -351,7 +356,7 @@ virBhyveProcessStartImpl(struct _bhyveConn *driver, * domain is ready to be started, so we can build * and execute bhyveload command */ - virBhyveFormatDevMapFile(vm->def->name, &devmap_file); + virBhyveFormatDevMapFile(cfg, vm->def->name, &devmap_file); if (!(load_cmd = virBhyveProcessBuildLoadCmd(driver, vm->def, devmap_file, &devicemap))) @@ -417,8 +422,7 @@ virBhyveProcessStartImpl(struct _bhyveConn *driver, if (virBhyveDomainObjStartWorker(vm) < 0) goto cleanup; - if (virDomainObjSave(vm, driver->xmlopt, - BHYVE_STATE_DIR) < 0) + if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) goto cleanup; if (bhyveSetResourceLimits(driver, vm) < 0) @@ -729,8 +733,8 @@ virBhyveProcessStopImpl(struct _bhyveConn *driver, if (vm_started) bhyveProcessStopHook(driver, vm, VIR_HOOK_BHYVE_OP_RELEASE); - virPidFileDelete(BHYVE_STATE_DIR, vm->def->name); - bhyveProcessRemoveDomainStatus(BHYVE_STATE_DIR, vm->def->name); + virPidFileDelete(driver->config->stateDir, vm->def->name); + bhyveProcessRemoveDomainStatus(driver->config->stateDir, vm->def->name); if (restoreDef) virDomainObjRemoveTransientDef(vm); @@ -891,7 +895,7 @@ virBhyveProcessReconnect(virDomainObj *vm, VIR_DOMAIN_SHUTOFF_UNKNOWN); virDomainObjRemoveTransientDef(vm); ignore_value(virDomainObjSave(vm, data->driver->xmlopt, - BHYVE_STATE_DIR)); + data->driver->config->stateDir)); } virObjectUnlock(vm); diff --git a/src/bhyve/bhyve_utils.h b/src/bhyve/bhyve_utils.h index 19369047fe..5d04b42195 100644 --- a/src/bhyve/bhyve_utils.h +++ b/src/bhyve/bhyve_utils.h @@ -29,18 +29,18 @@ #include "hypervisor/virclosecallbacks.h" #include "virportallocator.h" -#define BHYVE_AUTOSTART_DIR SYSCONFDIR "/libvirt/bhyve/autostart" -#define BHYVE_CONFIG_DIR SYSCONFDIR "/libvirt/bhyve" -#define BHYVE_STATE_DIR RUNSTATEDIR "/libvirt/bhyve" -#define BHYVE_LOG_DIR LOCALSTATEDIR "/log/libvirt/bhyve" - typedef struct _virBhyveDriverConfig virBhyveDriverConfig; struct _virBhyveDriverConfig { virObject parent; + char *autostartDir; + char *configBaseDir; + char *configDir; char *firmwareDir; char *libDir; + char *logDir; char *nvramDir; + char *stateDir; char *ubootPath; -- 2.55.0
In order to start unprivileged VMs, bhyve(8) requires using the monitor mode, which is enabled by the '-M' argument. In monitor mode bhyve runs a monitor process and a VM process. We already know the monitor process ID, but we also need to know the VM process ID (e.g. for reconnecting or shutting it down with a signal). Thus, also probe the bhyvectl(8)'s "--get-vm-pid" argument, which returns a VM's PID. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_capabilities.c | 29 +++++++++++++++++++++++++++++ src/bhyve/bhyve_capabilities.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c index 85988a2ce8..e21f01e982 100644 --- a/src/bhyve/bhyve_capabilities.c +++ b/src/bhyve/bhyve_capabilities.c @@ -263,6 +263,9 @@ bhyveProbeCapsFromHelp(unsigned int *caps, char *binary) if (strstr(help, "-n:") != NULL) *caps |= BHYVE_CAP_NUMA; + if (strstr(help, "-M:") != NULL) + *caps |= BHYVE_CAP_MONITOR; + return 0; } @@ -357,6 +360,29 @@ bhyveProbeCapsRctl(unsigned int *caps) return; } +static int +bhyveProbeCapsBhyvectl(unsigned int *caps) +{ + g_autofree char *binary = virFindFileInPath("bhyvectl"); + g_autofree char *help = NULL; + g_autoptr(virCommand) cmd = NULL; + int exit; + + if (!binary) + return 0; + + cmd = virCommandNew(binary); + virCommandAddArg(cmd, "--help"); + virCommandSetErrorBuffer(cmd, &help); + if (virCommandRun(cmd, &exit) < 0) + return -1; + + if (strstr(help, "--get-vm-pid") != NULL) + *caps |= BHYVE_CAP_GET_VMPID; + + return 0; +} + int virBhyveProbeCaps(unsigned int *caps) { @@ -379,6 +405,9 @@ virBhyveProbeCaps(unsigned int *caps) if ((ret = bhyveProbeCapsVNCPassword(caps, binary))) goto out; + if ((ret = bhyveProbeCapsBhyvectl(caps))) + goto out; + bhyveProbeCapsRctl(caps); out: diff --git a/src/bhyve/bhyve_capabilities.h b/src/bhyve/bhyve_capabilities.h index 0302b68e22..c790c57ba7 100644 --- a/src/bhyve/bhyve_capabilities.h +++ b/src/bhyve/bhyve_capabilities.h @@ -58,6 +58,8 @@ typedef enum { BHYVE_CAP_ACPI = 1 << 12, BHYVE_CAP_NUMA = 1 << 13, BHYVE_CAP_RCTL = 1 << 14, + BHYVE_CAP_MONITOR = 1 << 15, + BHYVE_CAP_GET_VMPID = 1 << 16, } virBhyveCapsFlags; int virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps); -- 2.55.0
- Add support for the 'bhyve:///session' connection URL for running in unprivileged mode. - Use bhyve monitor mode ('-M') and a per-user runtime directory. - Require monitor mode and VM PID query support for session mode. - Use user configuration directories instead of system-wide directories. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_command.c | 7 ++++++ src/bhyve/bhyve_conf.c | 42 ++++++++++++++++++++++++++--------- src/bhyve/bhyve_conf.h | 2 +- src/bhyve/bhyve_domain.c | 9 +++++++- src/bhyve/bhyve_driver.c | 46 ++++++++++++++++++++++++++------------- src/bhyve/bhyve_process.c | 2 +- src/bhyve/bhyve_utils.h | 2 ++ tests/bhyvexml2argvtest.c | 4 +++- tests/bhyvexml2xmltest.c | 2 +- 9 files changed, 86 insertions(+), 30 deletions(-) diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index f0a87cffea..41c3767c3e 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -1100,6 +1100,13 @@ virBhyveProcessBuildBhyveCmd(struct _bhyveConn *driver, virDomainDef *def, unsigned nvcpus = virDomainDefGetVcpus(def); size_t ncells = virDomainNumaGetNodeCount(def->numa); + /* Monitor mode */ + if (!driver->privileged) { + virCommandAddArg(cmd, "-M"); + virCommandAddArg(cmd, "-o"); + virCommandAddArgFormat(cmd, "rundir=%s", driver->config->stateDir); + } + /* CPUs */ virCommandAddArg(cmd, "-c"); if (def->cpu && def->cpu->sockets) { diff --git a/src/bhyve/bhyve_conf.c b/src/bhyve/bhyve_conf.c index e0439af6fa..182dd24a60 100644 --- a/src/bhyve/bhyve_conf.c +++ b/src/bhyve/bhyve_conf.c @@ -25,6 +25,7 @@ #include "viralloc.h" #include "virlog.h" #include "virstring.h" +#include "virutil.h" #include "bhyve_conf.h" #include "bhyve_domain.h" #include "configmake.h" @@ -47,7 +48,7 @@ static int virBhyveConfigOnceInit(void) VIR_ONCE_GLOBAL_INIT(virBhyveConfig); struct _virBhyveDriverConfig * -virBhyveDriverConfigNew(void) +virBhyveDriverConfigNew(bool privileged) { struct _virBhyveDriverConfig *cfg; @@ -57,18 +58,39 @@ virBhyveDriverConfigNew(void) if (!(cfg = virObjectNew(virBhyveDriverConfigClass))) return NULL; - cfg->configBaseDir = g_strdup(SYSCONFDIR "/libvirt"); + if (privileged) { + cfg->configBaseDir = g_strdup(SYSCONFDIR "/libvirt"); - cfg->firmwareDir = g_strdup(DATADIR "/uefi-firmware"); - cfg->libDir = g_strdup_printf("%s/lib/libvirt/bhyve", LOCALSTATEDIR); - cfg->nvramDir = g_strdup_printf("%s/nvram", cfg->libDir); + cfg->firmwareDir = g_strdup(DATADIR "/uefi-firmware"); + cfg->libDir = g_strdup_printf("%s/lib/libvirt/bhyve", LOCALSTATEDIR); + cfg->nvramDir = g_strdup_printf("%s/nvram", cfg->libDir); - cfg->ubootPath = g_strdup(DATADIR "/u-boot/u-boot-bhyve-arm64/u-boot.bin"); + cfg->ubootPath = g_strdup(DATADIR "/u-boot/u-boot-bhyve-arm64/u-boot.bin"); - cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir); - cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", cfg->configBaseDir); - cfg->stateDir = g_strdup_printf("%s/libvirt/bhyve", RUNSTATEDIR); - cfg->logDir = g_strdup_printf("%s/log/libvirt/bhyve", LOCALSTATEDIR); + cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir); + cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", cfg->configBaseDir); + cfg->stateDir = g_strdup_printf("%s/libvirt/bhyve", RUNSTATEDIR); + cfg->logDir = g_strdup_printf("%s/log/libvirt/bhyve", LOCALSTATEDIR); + } else { + g_autofree char *rundir = NULL; + g_autofree char *cachedir = NULL; + + cfg->configBaseDir = virGetUserConfigDirectory(); + + cachedir = virGetUserCacheDirectory(); + rundir = virGetUserRuntimeDirectory(); + + cfg->firmwareDir = g_strdup(DATADIR "/uefi-firmware"); + cfg->libDir = g_strdup_printf("%s/bhyve/lib", cfg->configBaseDir); + cfg->nvramDir = g_strdup_printf("%s/bhyve/nvram", cfg->configBaseDir); + + cfg->ubootPath = g_strdup(DATADIR "/u-boot/u-boot-bhyve-arm64/u-boot.bin"); + + cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir); + cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", cfg->configBaseDir); + cfg->stateDir = g_strdup_printf("%s/bhyve/run", rundir); + cfg->logDir = g_strdup_printf("%s/bhyve/log", cachedir); + } cfg->bhyveloadTimeout = 300; cfg->bhyveloadTimeoutKill = 15; diff --git a/src/bhyve/bhyve_conf.h b/src/bhyve/bhyve_conf.h index d895f66bb7..70c6b1f6ed 100644 --- a/src/bhyve/bhyve_conf.h +++ b/src/bhyve/bhyve_conf.h @@ -23,7 +23,7 @@ #include "bhyve_utils.h" -struct _virBhyveDriverConfig *virBhyveDriverConfigNew(void); +struct _virBhyveDriverConfig *virBhyveDriverConfigNew(bool privileged); struct _virBhyveDriverConfig *virBhyveDriverGetConfig(struct _bhyveConn *driver); int virBhyveLoadDriverConfig(struct _virBhyveDriverConfig *cfg, const char *filename); diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 3588557979..2513573e98 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -555,9 +555,10 @@ bhyveValidateDomainLifecycleAction(const virDomainDef *def) static int bhyveDomainDefValidate(const virDomainDef *def, - void *opaque G_GNUC_UNUSED, + void *opaque, void *parseOpaque G_GNUC_UNUSED) { + struct _bhyveConn *driver = opaque; size_t i; size_t ncells; virStorageSource *src = NULL; @@ -640,6 +641,12 @@ bhyveDomainDefValidate(const virDomainDef *def, return -1; } + if (!driver->privileged && !def->os.loader) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("only UEFI boot is supported in unprivileged mode")); + return -1; + } + if (bhyveValidateDomainLifecycleAction(def) < 0) return -1; diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 7e8cc572e4..f48543e205 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -211,7 +211,8 @@ bhyveConnectURIProbe(char **uri) if (bhyve_driver == NULL) return 0; - *uri = g_strdup("bhyve:///system"); + *uri = g_strdup(bhyve_driver->privileged ? + "bhyve:///system" : "bhyve:///session"); return 1; } @@ -224,19 +225,17 @@ bhyveConnectOpen(virConnectPtr conn, { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); - if (STRNEQ(conn->uri->path, "/system")) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected bhyve URI path '%1$s', try bhyve:///system"), - conn->uri->path); - return VIR_DRV_OPEN_ERROR; - } - if (bhyve_driver == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("bhyve state driver is not active")); return VIR_DRV_OPEN_ERROR; } + if (!virConnectValidateURIPath(conn->uri->path, + "bhyve", + bhyve_driver->privileged)) + return VIR_DRV_OPEN_ERROR; + if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; @@ -1398,6 +1397,7 @@ bhyveStateInitialize(bool privileged, void *opaque G_GNUC_UNUSED) { virDomainDriverAutoStartConfig autostartCfg; + g_autofree char *configFile = NULL; virBhyveDriverConfig *cfg; if (root != NULL) { @@ -1406,13 +1406,9 @@ bhyveStateInitialize(bool privileged, return -1; } - if (!privileged) { - VIR_INFO("Not running privileged, disabling driver"); - return VIR_DRV_STATE_INIT_SKIPPED; - } - bhyve_driver = g_new0(bhyveConn, 1); + bhyve_driver->privileged = privileged; bhyve_driver->lockFD = -1; if (virMutexInit(&bhyve_driver->lock) < 0) { VIR_FREE(bhyve_driver); @@ -1425,6 +1421,18 @@ bhyveStateInitialize(bool privileged, if (virBhyveProbeCaps(&bhyve_driver->bhyvecaps) < 0) goto cleanup; + if (!privileged && !(bhyveDriverGetBhyveCaps(bhyve_driver) & BHYVE_CAP_MONITOR)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("bhyve does not support monitor mode, cannot run unprivileged")); + goto cleanup; + } + + if (!privileged && !(bhyveDriverGetBhyveCaps(bhyve_driver) & BHYVE_CAP_GET_VMPID)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("bhyvectl does not support querying the VM PID, cannot run unprivileged")); + goto cleanup; + } + if (virBhyveProbeGrubCaps(&bhyve_driver->grubcaps) < 0) goto cleanup; @@ -1443,10 +1451,11 @@ bhyveStateInitialize(bool privileged, bhyve_driver->hostsysinfo = virSysinfoRead(); - if (!(bhyve_driver->config = cfg = virBhyveDriverConfigNew())) + if (!(bhyve_driver->config = cfg = virBhyveDriverConfigNew(privileged))) goto cleanup; - if (virBhyveLoadDriverConfig(bhyve_driver->config, SYSCONFDIR "/libvirt/bhyve.conf") < 0) + configFile = g_build_filename(cfg->configBaseDir, "bhyve.conf", NULL); + if (virBhyveLoadDriverConfig(cfg, configFile) < 0) goto cleanup; if (g_mkdir_with_parents(cfg->logDir, 0777) < 0) { @@ -1463,6 +1472,13 @@ bhyveStateInitialize(bool privileged, goto cleanup; } + if (g_mkdir_with_parents(cfg->nvramDir, 0777) < 0) { + virReportSystemError(errno, + _("Failed to mkdir %1$s"), + cfg->nvramDir); + goto cleanup; + } + if ((bhyve_driver->lockFD = virPidFileAcquire(cfg->stateDir, "driver", getpid())) < 0) goto cleanup; diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index 4144f8230e..c42d9ec092 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -537,7 +537,7 @@ bhyvePrepareNVRAMFile(bhyveConn *driver G_GNUC_UNUSED, if (virFileRewrite(loader->nvram->path, S_IRUSR | S_IWUSR, - 0, 0, + -1, -1, bhyvePrepareNVRAMHelper, &data) < 0) { return -1; diff --git a/src/bhyve/bhyve_utils.h b/src/bhyve/bhyve_utils.h index 5d04b42195..8a6ca25b47 100644 --- a/src/bhyve/bhyve_utils.h +++ b/src/bhyve/bhyve_utils.h @@ -70,6 +70,8 @@ struct _bhyveConn { unsigned bhyvecaps; unsigned grubcaps; + + bool privileged; }; typedef struct _bhyveConn bhyveConn; diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c index 95969a641b..06af9dec8a 100644 --- a/tests/bhyvexml2argvtest.c +++ b/tests/bhyvexml2argvtest.c @@ -162,7 +162,7 @@ mymain(void) if (!(driver.remotePorts = virPortAllocatorRangeNew("display", 5900, 65535))) return EXIT_FAILURE; - if (!(driver.config = virBhyveDriverConfigNew())) + if (!(driver.config = virBhyveDriverConfigNew(true))) return EXIT_FAILURE; VIR_FREE(driver.config->firmwareDir); @@ -174,6 +174,8 @@ mymain(void) driver.config->bhyveloadTimeout = 0; driver.config->bhyveloadTimeoutKill = 0; + driver.privileged = true; + # define DO_TEST_FULL(name, flags) \ do { \ static struct testInfo info = { \ diff --git a/tests/bhyvexml2xmltest.c b/tests/bhyvexml2xmltest.c index 336278ce1c..92710b3f0f 100644 --- a/tests/bhyvexml2xmltest.c +++ b/tests/bhyvexml2xmltest.c @@ -67,7 +67,7 @@ mymain(void) if ((driver.xmlopt = virBhyveDriverCreateXMLConf(&driver)) == NULL) return EXIT_FAILURE; - if (!(driver.config = virBhyveDriverConfigNew())) + if (!(driver.config = virBhyveDriverConfigNew(true))) return EXIT_FAILURE; VIR_FREE(driver.config->firmwareDir); -- 2.55.0
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_command.c | 12 ++++++++++++ src/bhyve/bhyve_command.h | 3 +++ src/bhyve/bhyve_driver.c | 28 ++++++++++++++++++++++++++++ src/bhyve/bhyve_process.c | 11 +++++++++++ src/bhyve/bhyve_process.h | 3 +++ 5 files changed, 57 insertions(+) diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index 41c3767c3e..e3133c4b62 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -1346,6 +1346,18 @@ virBhyveProcessBuildDestroyCmd(struct _bhyveConn *driver G_GNUC_UNUSED, return cmd; } +virCommand * +virBhyveProcessBuildResetCmd(struct _bhyveConn *driver G_GNUC_UNUSED, + virDomainDef *def) +{ + virCommand *cmd = virCommandNew("bhyvectl"); + + virCommandAddArg(cmd, "--force-reset"); + virCommandAddArgPair(cmd, "--vm", def->name); + + return cmd; +} + static void virAppendBootloaderArgs(virCommand *cmd, virDomainDef *def) { diff --git a/src/bhyve/bhyve_command.h b/src/bhyve/bhyve_command.h index 45c6a1a57c..e946090411 100644 --- a/src/bhyve/bhyve_command.h +++ b/src/bhyve/bhyve_command.h @@ -40,3 +40,6 @@ virBhyveProcessBuildDestroyCmd(struct _bhyveConn *driver, virCommand * virBhyveProcessBuildLoadCmd(struct _bhyveConn *driver, virDomainDef *def, const char *devmap_file, char **devicesmap_out); + +virCommand * +virBhyveProcessBuildResetCmd(struct _bhyveConn *driver, virDomainDef *def); diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index f48543e205..3058420bae 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -3201,6 +3201,33 @@ bhyveDomainGetGuestInfo(virDomainPtr domain, goto cleanup; } + +static int +bhyveDomainReset(virDomainPtr domain, unsigned int flags) +{ + virDomainObj *vm; + struct _bhyveConn *privconn = domain->conn->privateData; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(vm = bhyveDomObjFromDomain(domain))) + goto cleanup; + + if (virDomainResetEnsureACL(domain->conn, vm->def) < 0) + goto cleanup; + + if (virDomainObjCheckActive(vm) < 0) + goto cleanup; + + ret = virBhyveProcessReset(privconn, vm); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + + static virHypervisorDriver bhyveHypervisorDriver = { .name = "bhyve", .connectURIProbe = bhyveConnectURIProbe, @@ -3282,6 +3309,7 @@ static virHypervisorDriver bhyveHypervisorDriver = { .domainAgentSetResponseTimeout = bhyveDomainAgentSetResponseTimeout, /* 12.7.0 */ .domainGetGuestInfo = bhyveDomainGetGuestInfo, /* 12.7.0 */ .domainSetLifecycleAction = bhyveDomainSetLifecycleAction, /* 12.8.0 */ + .domainReset = bhyveDomainReset, /* 12.9.0 */ }; diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index c42d9ec092..170889f651 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -788,6 +788,17 @@ virBhyveProcessRestart(struct _bhyveConn *driver, return 0; } +int +virBhyveProcessReset(struct _bhyveConn *driver, virDomainObj *vm) +{ + g_autoptr(virCommand) cmd = virBhyveProcessBuildResetCmd(driver, vm->def); + + if (virCommandRun(cmd, NULL) < 0) + return -1; + + return 0; +} + int virBhyveGetDomainTotalCpuStats(virDomainObj *vm, unsigned long long *cpustats) diff --git a/src/bhyve/bhyve_process.h b/src/bhyve/bhyve_process.h index 339e5d429a..832925851c 100644 --- a/src/bhyve/bhyve_process.h +++ b/src/bhyve/bhyve_process.h @@ -50,6 +50,9 @@ int virBhyveProcessStop(struct _bhyveConn *driver, int virBhyveProcessRestart(struct _bhyveConn *driver, virDomainObj *vm); +int virBhyveProcessReset(struct _bhyveConn *driver, + virDomainObj *vm); + int virBhyveProcessShutdown(virDomainObj *vm); int virBhyveGetDomainTotalCpuStats(virDomainObj *vm, -- 2.55.0
In monitor mode, bhyve(8) has two processes per VM: the monitor process and a VM process. The process started by the libvirt driver is a monitor process, and its PID is stored as vm->pid. To obtain a VM process ID, use "bhyvectl --get-vm-pid". We need this VM for shutting down a domain by signal and querying process-specific statistics. RCTL operations require privileges, so resource limits are not supported in unprivileged mode. Reject RCTL-backed domain configuration and memory parameter operations instead of applying them to the VM child. Do not persist the VM process ID as it may change, for example when a domain reboots. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_command.c | 14 +++++ src/bhyve/bhyve_command.h | 3 ++ src/bhyve/bhyve_domain.c | 14 +++-- src/bhyve/bhyve_driver.c | 25 ++++++++- src/bhyve/bhyve_process.c | 107 ++++++++++++++++++++++++++++++++++---- src/bhyve/bhyve_process.h | 2 + tests/bhyvexml2argvtest.c | 8 +++ tests/bhyvexml2xmltest.c | 2 + 8 files changed, 159 insertions(+), 16 deletions(-) diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index e3133c4b62..6b7431ddaf 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -1358,6 +1358,20 @@ virBhyveProcessBuildResetCmd(struct _bhyveConn *driver G_GNUC_UNUSED, return cmd; } +virCommand * +virBhyveProcessBuildGetVMPidCmd(struct _bhyveConn *driver, + virDomainDef *def) +{ + virCommand *cmd = virCommandNew("bhyvectl"); + + virCommandAddArg(cmd, "--get-vm-pid"); + virCommandAddArgPair(cmd, "--vm", def->name); + if (!driver->privileged) + virCommandAddArgPair(cmd, "--rundir", driver->config->stateDir); + + return cmd; +} + static void virAppendBootloaderArgs(virCommand *cmd, virDomainDef *def) { diff --git a/src/bhyve/bhyve_command.h b/src/bhyve/bhyve_command.h index e946090411..2ee3f3a607 100644 --- a/src/bhyve/bhyve_command.h +++ b/src/bhyve/bhyve_command.h @@ -43,3 +43,6 @@ virBhyveProcessBuildLoadCmd(struct _bhyveConn *driver, virDomainDef *def, virCommand * virBhyveProcessBuildResetCmd(struct _bhyveConn *driver, virDomainDef *def); + +virCommand * +virBhyveProcessBuildGetVMPidCmd(struct _bhyveConn *driver, virDomainDef *def); diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 2513573e98..584257edba 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -636,9 +636,17 @@ bhyveDomainDefValidate(const virDomainDef *def, if (virMemoryLimitIsSet(def->mem.soft_limit) || virMemoryLimitIsSet(def->mem.swap_hard_limit) || def->mem.min_guarantee) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only 'hard_limit' memory tuning parameter is supported by bhyve")); - return -1; + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only 'hard_limit' memory tuning parameter is supported by bhyve")); + return -1; + } + + if (!driver->privileged && + (def->blkio.ndevices > 0 || + virMemoryLimitIsSet(def->mem.hard_limit))) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("resource limits are not supported in unprivileged mode")); + return -1; } if (!driver->privileged && !def->os.loader) { diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 3058420bae..4c4ba9b0ba 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -1906,6 +1906,7 @@ bhyveDomainMemoryStats(virDomainPtr domain, unsigned long long rss; size_t i = 0; int ret = -1; + pid_t pid; virCheckFlags(0, -1); @@ -1918,7 +1919,10 @@ bhyveDomainMemoryStats(virDomainPtr domain, if (virDomainMemoryStatsEnsureACL(domain->conn, vm->def) < 0) goto cleanup; - if (virProcessGetStatInfo(NULL, NULL, NULL, NULL, &rss, vm->pid, 0) < 0) { + if ((pid = virBhyveProcessGetBhyvePid(vm)) < 0) + goto cleanup; + + if (virProcessGetStatInfo(NULL, NULL, NULL, NULL, &rss, pid, 0) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("cannot get RSS for domain")); } else { @@ -1964,6 +1968,7 @@ bhyveDomainBlockStats(virDomainPtr domain, virDomainObj *vm; int ret = -1; g_autofree struct kinfo_proc *p = NULL; + pid_t pid; if (!(vm = bhyveDomObjFromDomain(domain))) goto cleanup; @@ -1974,7 +1979,10 @@ bhyveDomainBlockStats(virDomainPtr domain, if (virDomainBlockStatsEnsureACL(domain->conn, vm->def) < 0) goto cleanup; - if ((p = bhyveDomainProcGetInfo(vm->pid)) == NULL) + if ((pid = virBhyveProcessGetBhyvePid(vm)) < 0) + goto cleanup; + + if ((p = bhyveDomainProcGetInfo(pid)) == NULL) goto cleanup; stats->rd_req = p->ki_rusage.ru_inblock; @@ -2305,6 +2313,7 @@ bhyveDomainGetMemoryParameters(virDomainPtr domain, int *nparams, unsigned int flags) { + struct _bhyveConn *privconn = domain->conn->privateData; virDomainObj *vm = NULL; virDomainDef *persistentDef = NULL; int ret = -1; @@ -2320,6 +2329,12 @@ bhyveDomainGetMemoryParameters(virDomainPtr domain, if (virDomainGetMemoryParametersEnsureACL(domain->conn, vm->def) < 0) goto cleanup; + if (!privconn->privileged) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("memory parameters are not supported in unprivileged mode")); + goto cleanup; + } + if (virDomainObjGetDefs(vm, flags, NULL, &persistentDef) < 0) goto cleanup; @@ -2378,6 +2393,12 @@ bhyveDomainSetMemoryParameters(virDomainPtr domain, if (virDomainSetMemoryParametersEnsureACL(domain->conn, vm->def, flags) < 0) goto cleanup; + if (!privconn->privileged) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("memory parameters are not supported in unprivileged mode")); + goto cleanup; + } + if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) goto cleanup; diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index 170889f651..0dc7d18289 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -138,6 +138,78 @@ bhyveProcessStopHook(struct _bhyveConn *driver, VIR_HOOK_SUBOP_END, NULL, xml, NULL); } +static pid_t +bhyveProcessQueryVMPid(virDomainObj *vm) +{ + bhyveDomainObjPrivate *priv = vm->privateData; + g_autoptr(virCommand) cmd = NULL; + g_autofree char *output = NULL; + const char *pidstr; + char *end = NULL; + pid_t pid; + + cmd = virBhyveProcessBuildGetVMPidCmd(priv->driver, vm->def); + virCommandSetOutputBuffer(cmd, &output); + + if (virCommandRun(cmd, NULL) < 0) + return -1; + + virStringTrimOptionalNewline(output); + if (!STRPREFIX(output, "vm pid:\t")) + goto malformed; + + pidstr = output + strlen("vm pid:\t"); + if (virStrToLong_i(pidstr, &end, 10, &pid) < 0 || + pid <= 0 || *end != '\0') + goto malformed; + + return pid; + + malformed: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse bhyvectl output: %1$s"), output); + return -1; +} + + +static int +bhyveProcessWaitForVMPid(virDomainObj *vm) +{ + virTimeBackOffVar timebackoff; + + if (virTimeBackOffStart(&timebackoff, 1, 5000) < 0) + return -1; + + while (virTimeBackOffWait(&timebackoff)) { + if (bhyveProcessQueryVMPid(vm) > 0) + return 0; + + virResetLastError(); + } + + return bhyveProcessQueryVMPid(vm) < 0 ? -1 : 0; +} + + +pid_t +virBhyveProcessGetBhyvePid(virDomainObj *vm) +{ + bhyveDomainObjPrivate *priv = vm->privateData; + + if (vm->pid == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid PID %1$d for VM"), + (int)vm->pid); + return -1; + } + + if (priv->driver->privileged) + return vm->pid; + + return bhyveProcessQueryVMPid(vm); +} + + static int bhyveSetResourceLimits(struct _bhyveConn *driver, virDomainObj *vm) { @@ -147,6 +219,12 @@ bhyveSetResourceLimits(struct _bhyveConn *driver, virDomainObj *vm) !virMemoryLimitIsSet(vm->def->mem.hard_limit)) return 0; + if (!driver->privileged) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("resource limits are not supported in unprivileged mode")); + return -1; + } + if ((bhyveDriverGetBhyveCaps(driver) & BHYVE_CAP_RCTL) == 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Cannot set resource limits: RACCT/RCTL is either not supported or not enabled")); @@ -156,7 +234,8 @@ bhyveSetResourceLimits(struct _bhyveConn *driver, virDomainObj *vm) if (vm->def->blkio.ndevices == 1) { device = &vm->def->blkio.devices[0]; - bhyveRctlSetIoLimits(vm->pid, device); + if (bhyveRctlSetIoLimits(vm->pid, device) < 0) + return -1; } /* rctl(8) uses bytes for these values and def->mem.* uses kibibytes */ @@ -414,6 +493,10 @@ virBhyveProcessStartImpl(struct _bhyveConn *driver, goto cleanup; } + /* /dev/vmm can appear before the monitor mode IPC socket is ready. */ + if (!driver->privileged && bhyveProcessWaitForVMPid(vm) < 0) + goto cleanup; + vm->def->id = vm->pid; virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); if ((priv->mon = bhyveMonitorOpen(vm, driver)) == NULL) @@ -754,20 +837,18 @@ virBhyveProcessStop(struct _bhyveConn *driver, int virBhyveProcessShutdown(virDomainObj *vm) { - if (vm->pid == 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Invalid PID %1$d for VM"), - (int)vm->pid); + pid_t pid; + + if ((pid = virBhyveProcessGetBhyvePid(vm)) < 0) return -1; - } /* Bhyve tries to perform ACPI shutdown when it receives * SIGTERM signal. So we just issue SIGTERM here and rely * on the bhyve monitor to clean things up if process disappears. */ - if (virProcessKill(vm->pid, SIGTERM) != 0) { - VIR_WARN("Failed to terminate bhyve process for VM '%s': %s", - vm->def->name, virGetLastErrorMessage()); + if (virProcessKill(pid, SIGTERM) != 0) { + VIR_WARN("Failed to terminate bhyve process for VM '%s' (pid: %d): %s", + vm->def->name, (int)pid, virGetLastErrorMessage()); return -1; } @@ -808,6 +889,10 @@ virBhyveGetDomainTotalCpuStats(virDomainObj *vm, g_autofree char *errbuf = g_new0(char, _POSIX2_LINE_MAX); int nprocs; int ret = -1; + pid_t pid; + + if ((pid = virBhyveProcessGetBhyvePid(vm)) < 0) + return -1; if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) { virReportError(VIR_ERR_SYSTEM_ERROR, @@ -817,11 +902,11 @@ virBhyveGetDomainTotalCpuStats(virDomainObj *vm, } - kp = kvm_getprocs(kd, KERN_PROC_PID, vm->pid, &nprocs); + kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs); if (kp == NULL || nprocs != 1) { virReportError(VIR_ERR_SYSTEM_ERROR, _("Unable to obtain information about pid: %1$d"), - (int)vm->pid); + (int)pid); goto cleanup; } diff --git a/src/bhyve/bhyve_process.h b/src/bhyve/bhyve_process.h index 832925851c..2f0ce21167 100644 --- a/src/bhyve/bhyve_process.h +++ b/src/bhyve/bhyve_process.h @@ -55,6 +55,8 @@ int virBhyveProcessReset(struct _bhyveConn *driver, int virBhyveProcessShutdown(virDomainObj *vm); +pid_t virBhyveProcessGetBhyvePid(virDomainObj *vm); + int virBhyveGetDomainTotalCpuStats(virDomainObj *vm, unsigned long long *cpustats); diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c index 06af9dec8a..f7676142af 100644 --- a/tests/bhyvexml2argvtest.c +++ b/tests/bhyvexml2argvtest.c @@ -21,6 +21,7 @@ typedef enum { FLAG_EXPECT_FAILURE = 1 << 0, FLAG_EXPECT_PARSE_ERROR = 1 << 1, FLAG_EXPECT_PREPARE_ERROR = 1 << 2, + FLAG_UNPRIVILEGED = 1 << 3, } virBhyveXMLToArgvTestFlags; static int testCompareXMLToArgvFiles(const char *xml, @@ -141,6 +142,8 @@ testCompareXMLToArgvHelper(const void *data) dmargs = g_strdup_printf("%s/bhyvexml2argvdata/%s/bhyvexml2argv-%s.devmap", abs_srcdir, arch, info->name); + driver.privileged = !(info->flags & FLAG_UNPRIVILEGED); + return testCompareXMLToArgvFiles(xml, args, ldargs, dmargs, info->flags); } @@ -192,6 +195,9 @@ mymain(void) # define DO_TEST_FAILURE(name) \ DO_TEST_FULL(name, FLAG_EXPECT_FAILURE) +# define DO_TEST_UNPRIVILEGED_FAILURE(name) \ + DO_TEST_FULL(name, FLAG_EXPECT_FAILURE | FLAG_UNPRIVILEGED) + # define DO_TEST_PARSE_ERROR(name) \ DO_TEST_FULL(name, FLAG_EXPECT_PARSE_ERROR) @@ -295,6 +301,7 @@ mymain(void) DO_TEST("virtio-scsi"); DO_TEST("vcpupin"); DO_TEST("blkiotune"); + DO_TEST_UNPRIVILEGED_FAILURE("blkiotune"); DO_TEST_FAILURE("blkiotune-invalid-device"); DO_TEST_FAILURE("blkiotune-multiple-devices"); DO_TEST_FAILURE("blkiotune-weight"); @@ -307,6 +314,7 @@ mymain(void) DO_TEST_FAILURE("virtio-console-invalid-name"); DO_TEST_FAILURE("virtio-console-invalid-path"); DO_TEST("memtune"); + DO_TEST_UNPRIVILEGED_FAILURE("memtune"); DO_TEST_FAILURE("memtune-unsupported-params"); DO_TEST("sysinfo-smbios"); diff --git a/tests/bhyvexml2xmltest.c b/tests/bhyvexml2xmltest.c index 92710b3f0f..96c2e7a3a4 100644 --- a/tests/bhyvexml2xmltest.c +++ b/tests/bhyvexml2xmltest.c @@ -64,6 +64,8 @@ mymain(void) if ((driver.caps = virBhyveCapsBuild()) == NULL) return EXIT_FAILURE; + driver.privileged = true; + if ((driver.xmlopt = virBhyveDriverCreateXMLConf(&driver)) == NULL) return EXIT_FAILURE; -- 2.55.0
In unprivileged mode, libvirt tracks the bhyve monitor process while 'bhyvectl --get-vm-pid' reports the child process executing the VM. Keep the existing process title validation for privileged mode. In unprivileged mode, query the VM PID and require the VM process to be a child of the tracked monitor process. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_process.c | 44 +++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index 0dc7d18289..811ed4204d 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -933,7 +933,8 @@ virBhyveProcessReconnect(virDomainObj *vm, struct kinfo_proc *kp; int nprocs; char **proc_argv; - char *expected_proctitle = NULL; + g_autofree char *expected_proctitle = NULL; + pid_t bhyvePid; bhyveDomainObjPrivate *priv = vm->privateData; g_autoptr(virConnect) conn = NULL; size_t i; @@ -951,22 +952,30 @@ virBhyveProcessReconnect(virDomainObj *vm, if (kp == NULL || nprocs != 1) goto cleanup; - expected_proctitle = g_strdup_printf("bhyve: %s", vm->def->name); - - proc_argv = kvm_getargv(data->kd, kp, 0); - if (proc_argv && proc_argv[0]) { - if (STREQ(expected_proctitle, proc_argv[0])) { - ret = 0; - priv->mon = bhyveMonitorOpen(vm, data->driver); - if (vm->def->ngraphics == 1 && - vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { - int vnc_port = vm->def->graphics[0]->data.vnc.port; - if (virPortAllocatorSetUsed(vnc_port) < 0) { - VIR_WARN("Failed to mark VNC port '%d' as used by '%s'", - vnc_port, vm->def->name); - } - } - } + if (data->driver->privileged) { + expected_proctitle = g_strdup_printf("bhyve: %s", vm->def->name); + proc_argv = kvm_getargv(data->kd, kp, 0); + if (!proc_argv || !proc_argv[0] || + STRNEQ(expected_proctitle, proc_argv[0])) + goto cleanup; + } else { + if ((bhyvePid = bhyveProcessQueryVMPid(vm)) < 0) + goto cleanup; + + kp = kvm_getprocs(data->kd, KERN_PROC_PID, bhyvePid, &nprocs); + if (kp == NULL || nprocs != 1 || (pid_t)kp->ki_ppid != vm->pid) + goto cleanup; + } + + ret = 0; + priv->mon = bhyveMonitorOpen(vm, data->driver); + if (vm->def->ngraphics == 1 && + vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) { + int vnc_port = vm->def->graphics[0]->data.vnc.port; + if (virPortAllocatorSetUsed(vnc_port) < 0) { + VIR_WARN("Failed to mark VNC port '%d' as used by '%s'", + vnc_port, vm->def->name); + } } for (i = 0; i < vm->def->nnets; i++) { @@ -995,7 +1004,6 @@ virBhyveProcessReconnect(virDomainObj *vm, } virObjectUnlock(vm); - VIR_FREE(expected_proctitle); return ret; } -- 2.55.0
bhyve does not clean up its IPC sockets after exiting. It's not an issue because the existing socket does not prevent it from starting again, but it is still better to remove them on exit. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_command.c | 5 ++--- src/bhyve/bhyve_conf.c | 3 +++ src/bhyve/bhyve_process.c | 15 +++++++++++++++ src/bhyve/bhyve_utils.h | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index 6b7431ddaf..69fe04c577 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -1104,7 +1104,7 @@ virBhyveProcessBuildBhyveCmd(struct _bhyveConn *driver, virDomainDef *def, if (!driver->privileged) { virCommandAddArg(cmd, "-M"); virCommandAddArg(cmd, "-o"); - virCommandAddArgFormat(cmd, "rundir=%s", driver->config->stateDir); + virCommandAddArgFormat(cmd, "rundir=%s", driver->config->bhyveRunDir); } /* CPUs */ @@ -1366,8 +1366,7 @@ virBhyveProcessBuildGetVMPidCmd(struct _bhyveConn *driver, virCommandAddArg(cmd, "--get-vm-pid"); virCommandAddArgPair(cmd, "--vm", def->name); - if (!driver->privileged) - virCommandAddArgPair(cmd, "--rundir", driver->config->stateDir); + virCommandAddArgPair(cmd, "--rundir", driver->config->bhyveRunDir); return cmd; } diff --git a/src/bhyve/bhyve_conf.c b/src/bhyve/bhyve_conf.c index 182dd24a60..68bd22f00a 100644 --- a/src/bhyve/bhyve_conf.c +++ b/src/bhyve/bhyve_conf.c @@ -70,6 +70,7 @@ virBhyveDriverConfigNew(bool privileged) cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir); cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", cfg->configBaseDir); cfg->stateDir = g_strdup_printf("%s/libvirt/bhyve", RUNSTATEDIR); + cfg->bhyveRunDir = g_strdup(RUNSTATEDIR "/bhyve"); cfg->logDir = g_strdup_printf("%s/log/libvirt/bhyve", LOCALSTATEDIR); } else { g_autofree char *rundir = NULL; @@ -89,6 +90,7 @@ virBhyveDriverConfigNew(bool privileged) cfg->configDir = g_strdup_printf("%s/bhyve", cfg->configBaseDir); cfg->autostartDir = g_strdup_printf("%s/bhyve/autostart", cfg->configBaseDir); cfg->stateDir = g_strdup_printf("%s/bhyve/run", rundir); + cfg->bhyveRunDir = g_strdup(cfg->stateDir); cfg->logDir = g_strdup_printf("%s/bhyve/log", cachedir); } @@ -151,6 +153,7 @@ virBhyveDriverConfigDispose(void *obj) g_free(cfg->logDir); g_free(cfg->nvramDir); g_free(cfg->stateDir); + g_free(cfg->bhyveRunDir); g_free(cfg->ubootPath); } diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c index 811ed4204d..b0cd03c389 100644 --- a/src/bhyve/bhyve_process.c +++ b/src/bhyve/bhyve_process.c @@ -718,6 +718,20 @@ bhyveProcessRemoveDomainStatus(const char *statusDir, } } +static void +bhyveProcessRemoveIPCSocket(struct _bhyveConn *driver, + const char *name) +{ + g_autofree char *path = g_strdup_printf("%s/%s", + driver->config->bhyveRunDir, + name); + + if (unlink(path) < 0 && errno != ENOENT) { + VIR_WARN("Failed to remove bhyve IPC socket for %s: %s", + name, g_strerror(errno)); + } +} + /** * @driver: bhyve driver * @vm: domain object @@ -818,6 +832,7 @@ virBhyveProcessStopImpl(struct _bhyveConn *driver, bhyveProcessStopHook(driver, vm, VIR_HOOK_BHYVE_OP_RELEASE); virPidFileDelete(driver->config->stateDir, vm->def->name); bhyveProcessRemoveDomainStatus(driver->config->stateDir, vm->def->name); + bhyveProcessRemoveIPCSocket(driver, vm->def->name); if (restoreDef) virDomainObjRemoveTransientDef(vm); diff --git a/src/bhyve/bhyve_utils.h b/src/bhyve/bhyve_utils.h index 8a6ca25b47..db2789fe02 100644 --- a/src/bhyve/bhyve_utils.h +++ b/src/bhyve/bhyve_utils.h @@ -41,6 +41,7 @@ struct _virBhyveDriverConfig { char *logDir; char *nvramDir; char *stateDir; + char *bhyveRunDir; char *ubootPath; -- 2.55.0
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- .../bhyvexml2argv-uefi-unprivileged.args | 14 +++++++++++ tests/bhyvexml2argvtest.c | 23 +++++++++++++++---- 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-uefi-unprivileged.args diff --git a/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-uefi-unprivileged.args b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-uefi-unprivileged.args new file mode 100644 index 0000000000..fd55fb4a76 --- /dev/null +++ b/tests/bhyvexml2argvdata/x86_64/bhyvexml2argv-uefi-unprivileged.args @@ -0,0 +1,14 @@ +bhyve \ +-M \ +-o rundir=/path/to/bhyve/run \ +-c 1 \ +-m 214 \ +-u \ +-H \ +-P \ +-s 0:0,hostbridge \ +-l bootrom,/path/to/test.fd \ +-s 1:0,lpc \ +-s 2:0,ahci,hd:/tmp/freebsd.img \ +-s 3:0,virtio-net,faketapdev,mac=52:54:00:00:00:00 \ +bhyve diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c index f7676142af..8aae49643b 100644 --- a/tests/bhyvexml2argvtest.c +++ b/tests/bhyvexml2argvtest.c @@ -120,6 +120,7 @@ static int testCompareXMLToArgvFiles(const char *xml, struct testInfo { const char *name; + const char *argsSuffix; unsigned int flags; }; @@ -135,8 +136,8 @@ testCompareXMLToArgvHelper(const void *data) xml = g_strdup_printf("%s/bhyvexml2argvdata/%s/bhyvexml2argv-%s.xml", abs_srcdir, arch, info->name); - args = g_strdup_printf("%s/bhyvexml2argvdata/%s/bhyvexml2argv-%s.args", - abs_srcdir, arch, info->name); + args = g_strdup_printf("%s/bhyvexml2argvdata/%s/bhyvexml2argv-%s%s.args", + abs_srcdir, arch, info->name, info->argsSuffix); ldargs = g_strdup_printf("%s/bhyvexml2argvdata/%s/bhyvexml2argv-%s.ldargs", abs_srcdir, arch, info->name); dmargs = g_strdup_printf("%s/bhyvexml2argvdata/%s/bhyvexml2argv-%s.devmap", @@ -171,24 +172,29 @@ mymain(void) VIR_FREE(driver.config->firmwareDir); VIR_FREE(driver.config->nvramDir); VIR_FREE(driver.config->ubootPath); + VIR_FREE(driver.config->bhyveRunDir); driver.config->firmwareDir = g_steal_pointer(&fakefirmwaredir); driver.config->nvramDir = g_steal_pointer(&fakenvramdir); driver.config->ubootPath = g_steal_pointer(&fakeubootpath); + driver.config->bhyveRunDir = g_strdup("/path/to/bhyve/run"); driver.config->bhyveloadTimeout = 0; driver.config->bhyveloadTimeoutKill = 0; driver.privileged = true; -# define DO_TEST_FULL(name, flags) \ +# define DO_TEST_FULL_OUTPUT(name, suffix, flags) \ do { \ static struct testInfo info = { \ - name, (flags) \ + name, suffix, (flags) \ }; \ - if (virTestRun("BHYVE XML-2-ARGV " name, \ + if (virTestRun("BHYVE XML-2-ARGV " name suffix, \ testCompareXMLToArgvHelper, &info) < 0) \ ret = -1; \ } while (0) +# define DO_TEST_FULL(name, flags) \ + DO_TEST_FULL_OUTPUT(name, "", flags) + # define DO_TEST(name) \ DO_TEST_FULL(name, 0) @@ -198,6 +204,9 @@ mymain(void) # define DO_TEST_UNPRIVILEGED_FAILURE(name) \ DO_TEST_FULL(name, FLAG_EXPECT_FAILURE | FLAG_UNPRIVILEGED) +# define DO_TEST_UNPRIVILEGED(name) \ + DO_TEST_FULL_OUTPUT(name, "-unprivileged", FLAG_UNPRIVILEGED) + # define DO_TEST_PARSE_ERROR(name) \ DO_TEST_FULL(name, FLAG_EXPECT_PARSE_ERROR) @@ -213,6 +222,7 @@ mymain(void) BHYVE_CAP_NVME | BHYVE_CAP_NUMA; DO_TEST("base"); + DO_TEST_UNPRIVILEGED_FAILURE("base"); DO_TEST("wired"); DO_TEST("acpiapic"); driver.bhyvecaps &= ~BHYVE_CAP_ACPI; @@ -224,6 +234,7 @@ mymain(void) DO_TEST("console"); DO_TEST("console-master-slave-not-specified"); DO_TEST("grub-defaults"); + DO_TEST_UNPRIVILEGED_FAILURE("grub-defaults"); DO_TEST("grub-bootorder"); DO_TEST("grub-bootorder2"); DO_TEST("bhyveload-bootorder"); @@ -234,6 +245,7 @@ mymain(void) DO_TEST_FAILURE("bhyveload-bootorder4"); DO_TEST_PARSE_ERROR("bhyveload-bootorder5"); DO_TEST("custom-loader"); + DO_TEST_UNPRIVILEGED_FAILURE("custom-loader"); DO_TEST("disk-cdrom-grub"); DO_TEST("serial-grub"); DO_TEST("localtime"); @@ -241,6 +253,7 @@ mymain(void) DO_TEST("passthru"); DO_TEST("passthru-multiple-devs"); DO_TEST("uefi"); + DO_TEST_UNPRIVILEGED("uefi"); DO_TEST("uefi-nvram"); DO_TEST("uefi-nvram-template-set"); DO_TEST("uefi-nvram-template-and-source-set"); -- 2.55.0
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- docs/drvbhyve.rst | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/docs/drvbhyve.rst b/docs/drvbhyve.rst index 3c14e3e2bb..a322f6d1f4 100644 --- a/docs/drvbhyve.rst +++ b/docs/drvbhyve.rst @@ -32,15 +32,35 @@ Additional information on bhyve could be obtained on Connections to the Bhyve driver ------------------------------- -The libvirt bhyve driver is a single-instance privileged driver. Some sample -connection URIs are: +The libvirt bhyve driver is a multi-instance driver, providing a single system +wide privileged driver (the "system" instance), and per-user unprivileged +drivers (the "session" instance). The URI driver protocol is "bhyve". Some +example connection URIs for the libvirt driver are: :: + bhyve:///session (local access to per-user instance) + bhyve+unix:///session (local access to per-user instance) + bhyve:///system (local access) bhyve+unix:///system (local access) bhyve+ssh://root@example.com/system (remote access, SSH tunnelled) +The per-user instance connection is supported :since:`since 12.9.0`. It requires +bhyve monitor mode support (``bhyve -M``) and the ``--get-vm-pid`` option +support in ``bhyvectl(8)``. At the moment these features are only available on +FreeBSD -CURRENT. + +Session mode +------------ + +The per-user instance has some limitations and requirements: + +* User needs permission to access ``/dev/vmmctl``. +* It supports only UEFI boot; ``bhyveload``, ``grub-bhyve`` and other external + loaders are not supported. +* Memory and block I/O tuning are not supported. + Example guest domain XML configurations --------------------------------------- -- 2.55.0
participants (1)
-
Roman Bogorodskiy