git: 04811d46d3f2 - main - bhyve: Generalize the IPC thread
Bojan Novković <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.cvs.src,gmane.os.freebsd.current.scm |
|---|---|
| Message-ID | <[email protected]> |
The branch main has been updated by bnovkov: URL: https://cgit.FreeBSD.org/src/commit/?id=04811d46d3f2176af245f6d5e7e06b422f5d6216 commit 04811d46d3f2176af245f6d5e7e06b422f5d6216 Author: Bojan Novković <[email protected]> AuthorDate: 2025-11-18 11:59:01 +0000 Commit: Bojan Novković <[email protected]> CommitDate: 2026-08-23 12:02:49 +0000 bhyve: Generalize the IPC thread Move the code for the snapshotting IPC thread into a separate file and define macros for adding new IPC commands. No functional change intended. Reviewed by: rew Differential Revision: https://reviews.freebsd.org/D54650 --- usr.sbin/bhyve/Makefile | 1 + usr.sbin/bhyve/aarch64/bhyverun_machdep.c | 2 + usr.sbin/bhyve/amd64/bhyverun_machdep.c | 3 +- usr.sbin/bhyve/bhyverun.c | 9 +- usr.sbin/bhyve/ipc.c | 194 ++++++++++++++++++++++++++++++ usr.sbin/bhyve/ipc.h | 17 +-- usr.sbin/bhyve/riscv/bhyverun_machdep.c | 2 + usr.sbin/bhyve/snapshot.c | 131 ++------------------ usr.sbin/bhyve/snapshot.h | 1 - 9 files changed, 220 insertions(+), 140 deletions(-) diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index b86c56991039..eb7cfe7b602e 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -32,6 +32,7 @@ SRCS= \ ctl_util.c \ hda_codec.c \ iov.c \ + ipc.c \ mem.c \ mevent.c \ net_backend_netmap.c \ diff --git a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c index 56390719471b..1f13ad38dedb 100644 --- a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c +++ b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c @@ -49,6 +49,7 @@ #include "debug.h" #include "fdt.h" #include "mem.h" +#include "ipc.h" #include "pci_emul.h" #include "pci_irq.h" #include "rtc_pl031.h" @@ -87,6 +88,7 @@ bhyve_init_config(void) set_config_bool("acpi_tables", false); set_config_bool("acpi_tables_in_memory", false); set_config_value("memory.size", "256M"); + set_config_value("rundir", BHYVE_RUN_DIR); } void diff --git a/usr.sbin/bhyve/amd64/bhyverun_machdep.c b/usr.sbin/bhyve/amd64/bhyverun_machdep.c index 50085c928fde..ea1bad0d4eaa 100644 --- a/usr.sbin/bhyve/amd64/bhyverun_machdep.c +++ b/usr.sbin/bhyve/amd64/bhyverun_machdep.c @@ -46,6 +46,7 @@ #include "e820.h" #include "fwctl.h" #include "ioapic.h" +#include "ipc.h" #include "inout.h" #include "kernemu_dev.h" #include "mptbl.h" @@ -68,9 +69,7 @@ bhyve_init_config(void) set_config_bool("x86.strictmsr", true); set_config_bool("x86.verbosemsr", false); set_config_value("lpc.fwcfg", "bhyve"); -#ifdef BHYVE_SNAPSHOT set_config_value("rundir", BHYVE_RUN_DIR); -#endif } void diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index 339cf5071906..aa1a28f406e0 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -82,6 +82,7 @@ #ifdef BHYVE_GDB #include "gdb.h" #endif +#include "ipc.h" #include "mem.h" #include "mevent.h" #include "pci_emul.h" @@ -1107,13 +1108,11 @@ main(int argc, char *argv[]) */ setproctitle("%s", vmname); -#ifdef BHYVE_SNAPSHOT /* - * checkpointing thread for communication with bhyvectl + * Thread for handling bhyvectl commands. */ - if (init_checkpoint_thread(ctx, get_config_value("rundir")) != 0) - errx(EX_OSERR, "Failed to start checkpoint thread"); -#endif + if (init_ipc_thread(ctx, get_config_value("rundir")) != 0) + errx(EX_OSERR, "Failed to start IPC thread"); #ifndef WITHOUT_CAPSICUM caph_cache_catpages(); diff --git a/usr.sbin/bhyve/ipc.c b/usr.sbin/bhyve/ipc.c new file mode 100644 index 000000000000..cdf07e18ed3f --- /dev/null +++ b/usr.sbin/bhyve/ipc.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016 Flavius Anton + * Copyright (c) 2016 Mihai Tiganus + * Copyright (c) 2016-2019 Mihai Carabas + * Copyright (c) 2017-2019 Darius Mihai + * Copyright (c) 2017-2019 Elena Mihailescu + * Copyright (c) 2018-2019 Sergiu Weisz + * Copyright (c) 2025 Bojan Novković <[email protected]> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "ipc.h" + +#ifndef WITHOUT_CAPSICUM +#include <sys/capsicum.h> +#endif +#include <sys/types.h> +#include <sys/linker_set.h> +#include <sys/socket.h> +#include <sys/un.h> + +#ifndef WITHOUT_CAPSICUM +#include <capsicum_helpers.h> +#endif +#include <sys/cpuset.h> +#include <sys/ioctl.h> + +#include <machine/vmm.h> +#include <machine/vmm_snapshot.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <pthread.h> +#include <pthread_np.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> +#include <vmmapi.h> + +#include "bhyverun.h" +#include "debug.h" + +#define IPC_COMMAND_FOREACH(pvar, set) SET_FOREACH(pvar, set) + +SET_DECLARE(ipc_cmd_set, struct ipc_command); + +static struct ipc_thread_ctx { + struct vmctx *vmctx; + int sockfd; +} thr_ctx; + +static nvlist_t * +handle_message(struct vmctx *ctx, nvlist_t *nvl) +{ + const char *cmd; + struct ipc_command **ipc_cmd; + + cmd = nvlist_get_string(nvl, "cmd"); + IPC_COMMAND_FOREACH(ipc_cmd, ipc_cmd_set) + { + if (strcmp(cmd, (*ipc_cmd)->name) == 0) + return ((*ipc_cmd)->handler(ctx, nvl)); + } + + return (NULL); +} + +/* + * Listen for commands from bhyvectl. + */ +static void * +ipc_thread(void *param) +{ + int fd; + nvlist_t *nvl, *reply; + const char *cmdname; + struct ipc_thread_ctx *ctx; + + pthread_set_name_np(pthread_self(), "IPC thread"); + ctx = (struct ipc_thread_ctx *)param; + while ((fd = accept(ctx->sockfd, NULL, NULL)) != -1) { + nvl = nvlist_recv(fd, 0); + if (nvl == NULL) { + EPRINTLN("%s: nvlist_recv() failed: %s", __func__, + strerror(errno)); + close(fd); + continue; + } + + cmdname = nvlist_get_string(nvl, "cmd"); + if (cmdname == NULL) { + nvlist_add_string(nvl, "error", "missing command name"); + nvlist_send(fd, nvl); + nvlist_destroy(nvl); + close(fd); + continue; + } + reply = handle_message(ctx->vmctx, nvl); + if (reply == NULL) { + reply = nvlist_create(0); + nvlist_add_stringf(reply, "error", "command '%s' not found", + cmdname); + } + /* The handler should set the error message if need be. */ + nvlist_send(fd, reply); + + nvlist_destroy(nvl); + nvlist_destroy(reply); + close(fd); + } + + return (NULL); +} + +/* + * Create the listening socket for IPC with bhyvectl. + */ +int +init_ipc_thread(struct vmctx *ctx, const char *bhyve_run_dir) +{ + struct sockaddr_un addr; + pthread_t ipc_pthread; + int socket_fd; + int err, ret; +#ifndef WITHOUT_CAPSICUM + cap_rights_t rights; +#endif + + memset(&addr, 0, sizeof(addr)); + + socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (socket_fd < 0) { + EPRINTLN("Socket creation failed: %s", strerror(errno)); + err = -1; + goto fail; + } + + addr.sun_family = AF_UNIX; + + ret = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", + bhyve_run_dir, vm_get_name(ctx)); + if ((ret < 0) || ((size_t)ret >= sizeof(addr.sun_path))) { + EPRINTLN("%s: error setting socket path (%d)", __func__, ret); + err = -1; + goto fail; + } + + addr.sun_len = SUN_LEN(&addr); + unlink(addr.sun_path); + + if (bind(socket_fd, (struct sockaddr *)&addr, addr.sun_len) != 0) { + EPRINTLN("Failed to bind socket \"%s\": %s\n", + addr.sun_path, strerror(errno)); + err = -1; + goto fail; + } + + if (listen(socket_fd, 10) < 0) { + EPRINTLN("ipc socket listen: %s\n", strerror(errno)); + err = errno; + goto fail; + } + +#ifndef WITHOUT_CAPSICUM + cap_rights_init(&rights, CAP_ACCEPT, CAP_READ, CAP_RECV, CAP_WRITE, + CAP_SEND, CAP_GETSOCKOPT); + + if (caph_rights_limit(socket_fd, &rights) == -1) + errx(EX_OSERR, "Unable to apply rights for sandbox"); +#endif + memset(&thr_ctx, 0, sizeof(thr_ctx)); + thr_ctx.vmctx = ctx; + thr_ctx.sockfd = socket_fd; + + err = pthread_create(&ipc_pthread, NULL, ipc_thread, + &thr_ctx); + if (err != 0) + goto fail; + + return (0); +fail: + if (socket_fd > 0) + close(socket_fd); + unlink(addr.sun_path); + + return (err); +} diff --git a/usr.sbin/bhyve/ipc.h b/usr.sbin/bhyve/ipc.h index d7a3a173e068..36063e47b61d 100644 --- a/usr.sbin/bhyve/ipc.h +++ b/usr.sbin/bhyve/ipc.h @@ -33,18 +33,19 @@ #include <sys/linker_set.h> #include <sys/nv.h> +#define BHYVE_RUN_DIR "/var/run/bhyve/" + +struct vmctx; + struct ipc_command { const char *name; - int (*handler)(struct vmctx *ctx, const nvlist_t *nvl); + nvlist_t *(*handler)(struct vmctx *ctx, const nvlist_t *nvl); }; -#define IPC_COMMAND(set, name, function) \ - static struct ipc_command name ## _ipc_command = \ - { #name, function }; \ - DATA_SET(set, name ## _ipc_command) - -#define IPC_COMMAND_FOREACH(pvar, set) SET_FOREACH(pvar, set) +#define IPC_COMMAND(name, function) \ + static struct ipc_command name##_ipc_command = { #name, function }; \ + DATA_SET(ipc_cmd_set, name##_ipc_command) -SET_DECLARE(ipc_cmd_set, struct ipc_command); +int init_ipc_thread(struct vmctx *ctx, const char *bhyve_run_dir); #endif /* _IPC_H_ */ diff --git a/usr.sbin/bhyve/riscv/bhyverun_machdep.c b/usr.sbin/bhyve/riscv/bhyverun_machdep.c index 8efaa2aa4124..b467ff9f52d9 100644 --- a/usr.sbin/bhyve/riscv/bhyverun_machdep.c +++ b/usr.sbin/bhyve/riscv/bhyverun_machdep.c @@ -51,6 +51,7 @@ #include "config.h" #include "debug.h" #include "fdt.h" +#include "ipc.h" #include "mem.h" #include "pci_emul.h" #include "pci_irq.h" @@ -82,6 +83,7 @@ bhyve_init_config(void) set_config_bool("acpi_tables", false); set_config_bool("acpi_tables_in_memory", false); set_config_value("memory.size", "256M"); + set_config_value("rundir", BHYVE_RUN_DIR); } void diff --git a/usr.sbin/bhyve/snapshot.c b/usr.sbin/bhyve/snapshot.c index fdb5941bf1d0..1d3d337ec9b7 100644 --- a/usr.sbin/bhyve/snapshot.c +++ b/usr.sbin/bhyve/snapshot.c @@ -1331,56 +1331,13 @@ done: return (error); } -static int -handle_message(struct vmctx *ctx, nvlist_t *nvl) -{ - const char *cmd; - struct ipc_command **ipc_cmd; - - if (!nvlist_exists_string(nvl, "cmd")) - return (EINVAL); - - cmd = nvlist_get_string(nvl, "cmd"); - IPC_COMMAND_FOREACH(ipc_cmd, ipc_cmd_set) { - if (strcmp(cmd, (*ipc_cmd)->name) == 0) - return ((*ipc_cmd)->handler(ctx, nvl)); - } - - return (EOPNOTSUPP); -} - -/* - * Listen for commands from bhyvectl - */ -void * -checkpoint_thread(void *param) -{ - int fd; - struct checkpoint_thread_info *thread_info; - nvlist_t *nvl; - - pthread_set_name_np(pthread_self(), "checkpoint thread"); - thread_info = (struct checkpoint_thread_info *)param; - - while ((fd = accept(thread_info->socket_fd, NULL, NULL)) != -1) { - nvl = nvlist_recv(fd, 0); - if (nvl != NULL) - handle_message(thread_info->ctx, nvl); - else - EPRINTLN("nvlist_recv() failed: %s", strerror(errno)); - - close(fd); - nvlist_destroy(nvl); - } - - return (NULL); -} - -static int +static nvlist_t * vm_do_checkpoint(struct vmctx *ctx, const nvlist_t *nvl) { int error; + nvlist_t *reply; + reply = nvlist_create(0); if (!nvlist_exists_string(nvl, "filename") || !nvlist_exists_bool(nvl, "suspend") || !nvlist_exists_descriptor(nvl, "fddir")) @@ -1390,86 +1347,12 @@ vm_do_checkpoint(struct vmctx *ctx, const nvlist_t *nvl) nvlist_get_descriptor(nvl, "fddir"), nvlist_get_string(nvl, "filename"), nvlist_get_bool(nvl, "suspend")); + if (error != 0) + nvlist_add_string(reply, "error", strerror(error)); - return (error); -} -IPC_COMMAND(ipc_cmd_set, checkpoint, vm_do_checkpoint); - -/* - * Create the listening socket for IPC with bhyvectl - */ -int -init_checkpoint_thread(struct vmctx *ctx, const char *bhyve_run_dir) -{ - struct checkpoint_thread_info *checkpoint_info = NULL; - struct sockaddr_un addr; - int socket_fd; - pthread_t checkpoint_pthread; - int err, ret; -#ifndef WITHOUT_CAPSICUM - cap_rights_t rights; -#endif - - memset(&addr, 0, sizeof(addr)); - - socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (socket_fd < 0) { - EPRINTLN("Socket creation failed: %s", strerror(errno)); - err = -1; - goto fail; - } - - addr.sun_family = AF_UNIX; - - ret = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", - bhyve_run_dir, vm_get_name(ctx)); - if ((ret < 0) || ((size_t)ret >= sizeof(addr.sun_path))) { - EPRINTLN("%s: error setting socket path (%d)", __func__, ret); - err = -1; - goto fail; - } - - addr.sun_len = SUN_LEN(&addr); - unlink(addr.sun_path); - - if (bind(socket_fd, (struct sockaddr *)&addr, addr.sun_len) != 0) { - EPRINTLN("Failed to bind socket \"%s\": %s\n", - addr.sun_path, strerror(errno)); - err = -1; - goto fail; - } - - if (listen(socket_fd, 10) < 0) { - EPRINTLN("ipc socket listen: %s\n", strerror(errno)); - err = errno; - goto fail; - } - -#ifndef WITHOUT_CAPSICUM - cap_rights_init(&rights, CAP_ACCEPT, CAP_READ, CAP_RECV, CAP_WRITE, - CAP_SEND, CAP_GETSOCKOPT); - - if (caph_rights_limit(socket_fd, &rights) == -1) - errx(EX_OSERR, "Unable to apply rights for sandbox"); -#endif - checkpoint_info = calloc(1, sizeof(*checkpoint_info)); - checkpoint_info->ctx = ctx; - checkpoint_info->socket_fd = socket_fd; - - err = pthread_create(&checkpoint_pthread, NULL, checkpoint_thread, - checkpoint_info); - if (err != 0) - goto fail; - - return (0); -fail: - free(checkpoint_info); - if (socket_fd > 0) - close(socket_fd); - unlink(addr.sun_path); - - return (err); + return (reply); } +IPC_COMMAND(checkpoint, vm_do_checkpoint); void vm_snapshot_buf_err(const char *bufname, const enum vm_snapshot_op op) diff --git a/usr.sbin/bhyve/snapshot.h b/usr.sbin/bhyve/snapshot.h index 5c71640f3f09..eb66edd61f56 100644 --- a/usr.sbin/bhyve/snapshot.h +++ b/usr.sbin/bhyve/snapshot.h @@ -40,7 +40,6 @@ #include <libxo/xo.h> #include <ucl.h> -#define BHYVE_RUN_DIR "/var/run/bhyve/" #define MAX_SNAPSHOT_FILENAME PATH_MAX struct vmctx;