bhyve/snapshot: switch to nvlist for snapshot requests

Switch to using an nvlist with nvlist_send()/nvlist_recv() to
communicate from bhyvectl(8) to bhyve(8).

The idea is that a bhyve process receives a command with with a set of
arguments. The nvlist here is structured to reflect that premise.

For example, to snapshot the vm, the expected nvlist looks like:

    { cmd=START_CHECKPOINT, filename="filename" }

Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D33977
This commit is contained in:
Robert Wing 2022-02-09 08:11:57 -09:00
parent a35bdd4489
commit edfb339d38
4 changed files with 41 additions and 60 deletions

View File

@ -1325,7 +1325,7 @@ vm_vcpu_resume(struct vmctx *ctx)
}
static int
vm_checkpoint(struct vmctx *ctx, char *checkpoint_file, bool stop_vm)
vm_checkpoint(struct vmctx *ctx, const char *checkpoint_file, bool stop_vm)
{
int fd_checkpoint = 0, kdata_fd = 0;
int ret = 0;
@ -1440,17 +1440,23 @@ vm_checkpoint(struct vmctx *ctx, char *checkpoint_file, bool stop_vm)
return (error);
}
int
handle_message(struct ipc_message *imsg, struct vmctx *ctx)
static int
handle_message(struct vmctx *ctx, nvlist_t *nvl)
{
int err;
int err, cmd;
switch (imsg->code) {
case START_CHECKPOINT:
err = vm_checkpoint(ctx, imsg->data.op.snapshot_filename, false);
break;
if (!nvlist_exists_number(nvl, "cmd"))
return (-1);
cmd = nvlist_get_number(nvl, "cmd");
switch (cmd) {
case START_SUSPEND:
err = vm_checkpoint(ctx, imsg->data.op.snapshot_filename, true);
case START_CHECKPOINT:
if (!nvlist_exists_string(nvl, "filename"))
err = -1;
else
err = vm_checkpoint(ctx, nvlist_get_string(nvl, "filename"),
cmd == START_SUSPEND ? true : false);
break;
default:
EPRINTLN("Unrecognized checkpoint operation\n");
@ -1460,6 +1466,7 @@ handle_message(struct ipc_message *imsg, struct vmctx *ctx)
if (err != 0)
EPRINTLN("Unable to perform the requested operation\n");
nvlist_destroy(nvl);
return (err);
}
@ -1469,25 +1476,18 @@ handle_message(struct ipc_message *imsg, struct vmctx *ctx)
void *
checkpoint_thread(void *param)
{
struct ipc_message imsg;
struct checkpoint_thread_info *thread_info;
ssize_t n;
nvlist_t *nvl;
pthread_set_name_np(pthread_self(), "checkpoint thread");
thread_info = (struct checkpoint_thread_info *)param;
for (;;) {
n = recvfrom(thread_info->socket_fd, &imsg, sizeof(imsg), 0, NULL, 0);
/*
* slight sanity check: see if there's enough data to at
* least determine the type of message.
*/
if (n >= sizeof(imsg.code))
handle_message(&imsg, thread_info->ctx);
nvl = nvlist_recv(thread_info->socket_fd, 0);
if (nvl != NULL)
handle_message(thread_info->ctx, nvl);
else
EPRINTLN("Failed to receive message: %s\n",
n == -1 ? strerror(errno) : "unknown error");
EPRINTLN("nvlist_recv() failed: %s", strerror(errno));
}
return (NULL);

View File

@ -60,31 +60,12 @@ struct restore_state {
ucl_object_t *meta_root_obj;
};
/* Filename that will be used for save/restore */
struct checkpoint_op {
char snapshot_filename[MAX_SNAPSHOT_FILENAME];
};
/* Messages that a bhyve process understands. */
enum ipc_opcode {
START_CHECKPOINT,
START_SUSPEND,
};
/*
* The type of message and associated data to
* send to a bhyve process.
*/
struct ipc_message {
enum ipc_opcode code;
union {
/*
* message specific structures
*/
struct checkpoint_op op;
} data;
};
struct checkpoint_thread_info {
struct vmctx *ctx;
int socket_fd;

View File

@ -17,6 +17,7 @@ WARNS?= 3
CFLAGS+= -I${SRCTOP}/sys/amd64/vmm
.if ${MK_BHYVE_SNAPSHOT} != "no"
LIBADD+= nv
CFLAGS+= -DBHYVE_SNAPSHOT
# usr.sbin/bhyve/snapshot.h needs ucl header

View File

@ -33,10 +33,13 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/cpuset.h>
#include <sys/errno.h>
#include <sys/mman.h>
#include <sys/cpuset.h>
#include <sys/nv.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
@ -57,9 +60,6 @@ __FBSDID("$FreeBSD$");
#include <machine/vmm_dev.h>
#include <vmmapi.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "amd/vmcb.h"
#include "intel/vmcs.h"
@ -1684,10 +1684,9 @@ show_memseg(struct vmctx *ctx)
#ifdef BHYVE_SNAPSHOT
static int
send_message(struct vmctx *ctx, void *data, size_t len)
send_message(struct vmctx *ctx, nvlist_t *nvl)
{
struct sockaddr_un addr;
ssize_t len_sent;
int err, socket_fd;
char vmname_buf[MAX_VMNAME];
@ -1709,14 +1708,16 @@ send_message(struct vmctx *ctx, void *data, size_t len)
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s%s", BHYVE_RUN_DIR, vmname_buf);
len_sent = sendto(socket_fd, data, len, 0,
(struct sockaddr *)&addr, sizeof(struct sockaddr_un));
if (len_sent < 0) {
perror("Failed to send message to bhyve vm");
err = -1;
if (connect(socket_fd, (struct sockaddr *)&addr, SUN_LEN(&addr)) != 0) {
perror("connect() failed");
err = errno;
goto done;
}
if (nvlist_send(socket_fd, nvl) < 0)
perror("nvlist_send() failed");
nvlist_destroy(nvl);
done:
if (socket_fd > 0)
close(socket_fd);
@ -1726,15 +1727,13 @@ send_message(struct vmctx *ctx, void *data, size_t len)
static int
snapshot_request(struct vmctx *ctx, const char *file, enum ipc_opcode code)
{
struct ipc_message imsg;
size_t length;
nvlist_t *nvl;
imsg.code = code;
strlcpy(imsg.data.op.snapshot_filename, file, MAX_SNAPSHOT_FILENAME);
nvl = nvlist_create(0);
nvlist_add_number(nvl, "cmd", code);
nvlist_add_string(nvl, "filename", file);
length = offsetof(struct ipc_message, data) + sizeof(imsg.data.op);
return (send_message(ctx, (void *)&imsg, length));
return (send_message(ctx, nvl));
}
#endif