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;

Reply via email to