git: ed60e5710e74 - main - bhyvectl: support querying VM pid
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 19 Sep 2026 16:19:52 UTC
The branch main has been updated by novel:
URL: https://cgit.FreeBSD.org/src/commit/?id=ed60e5710e7489651c2829f220d1e87b3ed7429a
commit ed60e5710e7489651c2829f220d1e87b3ed7429a
Author: Roman Bogorodskiy <novel@FreeBSD.org>
AuthorDate: 2026-08-22 08:50:00 +0000
Commit: Roman Bogorodskiy <novel@FreeBSD.org>
CommitDate: 2026-09-19 16:19:35 +0000
bhyvectl: support querying VM pid
Extend bhyvectl(8) to support querying VM pid using the
`--get-vm-pid` flag.
This is useful in monitor mode when the VM pid differs
from the main bhyve(8) process run by the user. Knowing the VM pid
is necessary, for example, to query process resource usage or
trigger ACPI shutdown with SIGTERM.
Of course, it could be obtained by matching the monitor process
children by the process title, but it's a little more complex
and fragile than it could be.
Implement that by adding the "get_vm_pid" IPC command,
and using it to implement `bhyvectl --get-vm-pid`, which
prints the VM PID.
When the VM PID is not known, ESRCH is returned.
Reviewed by: bnovkov (previous iteration without man changes)
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D59108
---
usr.sbin/bhyve/bhyve_config.5 | 2 +-
usr.sbin/bhyve/ipc.c | 11 ++++++++
usr.sbin/bhyvectl/Makefile | 3 +--
usr.sbin/bhyvectl/bhyvectl.8 | 8 ++++--
usr.sbin/bhyvectl/bhyvectl.c | 60 ++++++++++++++++++++++++++++++++++++-------
5 files changed, 70 insertions(+), 14 deletions(-)
diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5
index 37a740aec3ec..55742b6fd5a8 100644
--- a/usr.sbin/bhyve/bhyve_config.5
+++ b/usr.sbin/bhyve/bhyve_config.5
@@ -232,7 +232,7 @@ Configuration can specify up to 255 strings.
.It Va rundir Ta String Ta Pa /var/run/bhyve/ Ta
Path to the runtime directory for
.Xr bhyve 8
-to store its service files, such as the checkpoint socket.
+to store its service files, such as the IPC socket.
Overriding this path is useful when running
.Xr bhyve 8
as an unprivileged user.
diff --git a/usr.sbin/bhyve/ipc.c b/usr.sbin/bhyve/ipc.c
index cdf07e18ed3f..ba938e99aeb5 100644
--- a/usr.sbin/bhyve/ipc.c
+++ b/usr.sbin/bhyve/ipc.c
@@ -56,6 +56,17 @@ static struct ipc_thread_ctx {
int sockfd;
} thr_ctx;
+static nvlist_t *
+ipc_get_vm_pid(struct vmctx *ctx __unused, const nvlist_t *nvl __unused)
+{
+ nvlist_t *reply;
+
+ reply = nvlist_create(0);
+ nvlist_add_number(reply, "pid", getpid());
+ return (reply);
+}
+IPC_COMMAND(get_vm_pid, ipc_get_vm_pid);
+
static nvlist_t *
handle_message(struct vmctx *ctx, nvlist_t *nvl)
{
diff --git a/usr.sbin/bhyvectl/Makefile b/usr.sbin/bhyvectl/Makefile
index 8cfb1169e585..829e5a5734e7 100644
--- a/usr.sbin/bhyvectl/Makefile
+++ b/usr.sbin/bhyvectl/Makefile
@@ -10,12 +10,11 @@ PACKAGE= bhyve
MAN= bhyvectl.8
-LIBADD= vmmapi util
+LIBADD= vmmapi util nv
CFLAGS+= -I${.CURDIR} -I${SRCTOP}/sys/amd64/vmm
.if ${MK_BHYVE_SNAPSHOT} != "no"
-LIBADD+= nv
CFLAGS+= -DBHYVE_SNAPSHOT
# usr.sbin/bhyve/snapshot.h needs ucl header
diff --git a/usr.sbin/bhyvectl/bhyvectl.8 b/usr.sbin/bhyvectl/bhyvectl.8
index b999230cfd73..366fc2e8b3ef 100644
--- a/usr.sbin/bhyvectl/bhyvectl.8
+++ b/usr.sbin/bhyvectl/bhyvectl.8
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 8, 2026
+.Dd September 11, 2026
.Dt BHYVECTL 8
.Os
.Sh NAME
@@ -37,6 +37,7 @@
.Op Fl -create
.Op Fl -destroy
.Op Fl -get-stats
+.Op Fl -get-vm-pid
.Op Fl -inject-nmi
.Op Fl -force-reset
.Op Fl -force-poweroff
@@ -61,6 +62,9 @@ Create the specified VM.
Destroy the specified VM.
.It Fl -get-stats
Retrieve statistics for the specified VM.
+.It Fl -get-vm-pid
+Print the process ID of the bhyve process running the specified VM.
+In monitor mode, this is the child process executing the VM.
.It Fl -inject-nmi
Inject a non-maskable interrupt (NMI) into the VM.
.It Fl -force-reset
@@ -79,7 +83,7 @@ Save a snapshot of a virtual machine similar to
The virtual machine will terminate after the snapshot has been
saved.
.It Fl -rundir= Ns Ar <path>
-Specify path to the directory containing the checkpoint socket.
+Specify path to the directory containing the bhyve IPC socket.
If not specified,
.Pa /var/run/bhyve
is used.
diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c
index ba2518267b14..3f67daa7be21 100644
--- a/usr.sbin/bhyvectl/bhyvectl.c
+++ b/usr.sbin/bhyvectl/bhyvectl.c
@@ -72,6 +72,7 @@ static int get_active_cpus, get_debug_cpus, get_suspended_cpus;
static uint64_t memsize;
static int run;
static int get_cpu_topology;
+static int get_vm_pid;
#ifdef BHYVE_SNAPSHOT
static int vm_suspend_opt;
#endif
@@ -87,8 +88,8 @@ enum {
#ifdef BHYVE_SNAPSHOT
SET_CHECKPOINT_FILE,
SET_SUSPEND_FILE,
- SET_RUNDIR,
#endif
+ SET_RUNDIR,
OPT_LAST,
};
@@ -137,11 +138,12 @@ setup_options(void)
{ "get-debug-cpus", NO_ARG, &get_debug_cpus, 1 },
{ "get-suspended-cpus", NO_ARG, &get_suspended_cpus, 1 },
{ "get-cpu-topology", NO_ARG, &get_cpu_topology, 1 },
+ { "get-vm-pid", NO_ARG, &get_vm_pid, 1 },
#ifdef BHYVE_SNAPSHOT
{ "checkpoint", REQ_ARG, 0, SET_CHECKPOINT_FILE},
{ "suspend", REQ_ARG, 0, SET_SUSPEND_FILE},
- { "rundir", REQ_ARG, 0, SET_RUNDIR},
#endif
+ { "rundir", REQ_ARG, 0, SET_RUNDIR},
};
return (bhyvectl_opts(common_opts, nitems(common_opts)));
@@ -158,8 +160,8 @@ usage(const struct option *opts)
#ifdef BHYVE_SNAPSHOT
[SET_CHECKPOINT_FILE] = "filename",
[SET_SUSPEND_FILE] = "filename",
- [SET_RUNDIR] = "path",
#endif
+ [SET_RUNDIR] = "path",
};
(void)fprintf(stderr, "Usage: %s --vm=<vmname>\n", progname);
for (const struct option *o = opts; o->name; o++) {
@@ -255,12 +257,13 @@ show_memseg(struct vmctx *ctx)
}
static int __unused
-ipc_send_message(const char *vmname, nvlist_t *request, const char *rundir)
+ipc_send_message(const char *vmname, nvlist_t *request, const char *rundir,
+ nvlist_t **replyp)
{
int err = 0, socket_fd, ret;
struct sockaddr_un addr;
const char* errmsg;
- nvlist_t *reply;
+ nvlist_t *reply = NULL;
socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (socket_fd < 0) {
@@ -292,22 +295,54 @@ ipc_send_message(const char *vmname, nvlist_t *request, const char *rundir)
request = NULL;
if (reply == NULL) {
perror("nvlist_xfer() failed");
+ err = errno;
goto done;
}
if (nvlist_exists_string(reply, "error")) {
errmsg = nvlist_get_string(reply, "error");
- fprintf(stderr, "%s: IPC command failed: %s\n", __func__, errmsg);
+ fprintf(stderr, "%s: IPC command failed: %s\n",
+ __func__, errmsg);
err = -1;
+ } else if (replyp != NULL) {
+ *replyp = reply;
+ reply = NULL;
}
done:
if (request != NULL)
nvlist_destroy(request);
+ if (reply != NULL)
+ nvlist_destroy(reply);
if (socket_fd >= 0)
close(socket_fd);
return (err);
}
+static int
+vm_pid_request(const char *vmname, const char *rundir, pid_t *pid)
+{
+ nvlist_t *nvl, *reply;
+ int error;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "cmd", "get_vm_pid");
+ error = ipc_send_message(vmname, nvl, rundir, &reply);
+ if (error == -1)
+ error = EOPNOTSUPP;
+ else if (error == ENOENT || error == ECONNREFUSED)
+ error = ESRCH;
+ if (error == 0) {
+ if (nvlist_exists_number(reply, "pid"))
+ *pid = (pid_t)nvlist_get_number(reply, "pid");
+ else
+ error = EPROTO;
+ nvlist_destroy(reply);
+ }
+ if (error != 0)
+ errno = error;
+ return (error);
+}
+
#ifdef BHYVE_SNAPSHOT
static int
open_directory(const char *file)
@@ -340,7 +375,7 @@ snapshot_request(const char *vmname, char *file, bool suspend, const char *rundi
nvlist_add_bool(nvl, "suspend", suspend);
nvlist_move_descriptor(nvl, "fddir", fd);
- return (ipc_send_message(vmname, nvl, rundir));
+ return (ipc_send_message(vmname, nvl, rundir, NULL));
}
#endif
@@ -402,11 +437,10 @@ main(int argc, char *argv[])
vm_suspend_opt = (ch == SET_SUSPEND_FILE);
break;
+#endif
case SET_RUNDIR:
rundir = optarg;
break;
-
-#endif
default:
usage(opts);
}
@@ -536,6 +570,14 @@ main(int argc, char *argv[])
"maxcpus=%hu\n", sockets, cores, threads, maxcpus);
}
+ if (!error && get_vm_pid) {
+ pid_t pid;
+
+ error = vm_pid_request(vmname, rundir, &pid);
+ if (!error)
+ printf("vm pid:\t%d\n", pid);
+ }
+
if (!error && run) {
struct vm_exit vmexit;
cpuset_t cpuset;