vmm: Add a device file interface for creating and destroying VMs

This supersedes the sysctl interface, which has the limitations of being
root-only and not supporting automatic resource destruction, i.e., we
cannot easily destroy VMs automatically when bhyve terminates.

For now, two ioctls are implemented VMMCTL_VM_CREATE and
VMMCTL_VM_DESTROY.  Eventually I would like to support tying a VM's
lifetime to that of the descriptor, so that it is automatically
destroyed when the descriptor is closed.  However, this will require
some work in bhyve: when the guest wants to reboot, bhyve exits with a
status that indicates that it is to be restarted.  This is incompatible
with the idea of tying a VM's lifetime to that of a descriptor, since we
want to avoid creating and destroying a VM across each reboot (as this
involves freeing all of the guest memory, among other things).  One
possible design would be to decompose bhyve into two processes, a parent
which handles reboots, and a child which runs in capability mode and
handles guest execution.

In any case, this gets us closer to addressing the shortcomings
mentioned above.

Reviewed by:	jhb
Differential Revision:	https://reviews.freebsd.org/D47028
This commit is contained in:
Mark Johnston 2024-11-05 01:36:06 +00:00
parent 8b54d874c7
commit a97f683fe3
4 changed files with 99 additions and 4 deletions

View File

@ -465,7 +465,9 @@ vmm_handler(module_t mod, int what, void *arg)
switch (what) {
case MOD_LOAD:
if (vmm_is_hw_supported()) {
vmmdev_init();
error = vmmdev_init();
if (error != 0)
break;
error = vmm_init();
if (error == 0)
vmm_initialized = 1;

View File

@ -362,7 +362,9 @@ vmm_handler(module_t mod, int what, void *arg)
switch (what) {
case MOD_LOAD:
/* TODO: if (vmm_is_hw_supported()) { */
vmmdev_init();
error = vmmdev_init();
if (error != 0)
break;
error = vmm_init();
if (error == 0)
vmm_initialized = true;

View File

@ -8,6 +8,7 @@
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/ioccom.h>
#include <sys/jail.h>
#include <sys/kernel.h>
@ -917,11 +918,88 @@ SYSCTL_PROC(_hw_vmm, OID_AUTO, create,
NULL, 0, sysctl_vmm_create, "A",
NULL);
void
static int
vmmctl_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
{
int error;
error = vmm_priv_check(td->td_ucred);
if (error != 0)
return (error);
if ((flags & FWRITE) == 0)
return (EPERM);
return (0);
}
static int
vmmctl_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
struct thread *td)
{
int error;
switch (cmd) {
case VMMCTL_VM_CREATE: {
struct vmmctl_vm_create *vmc;
vmc = (struct vmmctl_vm_create *)data;
vmc->name[VM_MAX_NAMELEN] = '\0';
for (size_t i = 0; i < nitems(vmc->reserved); i++) {
if (vmc->reserved[i] != 0) {
error = EINVAL;
return (error);
}
}
error = vmmdev_create(vmc->name, td->td_ucred);
break;
}
case VMMCTL_VM_DESTROY: {
struct vmmctl_vm_destroy *vmd;
vmd = (struct vmmctl_vm_destroy *)data;
vmd->name[VM_MAX_NAMELEN] = '\0';
for (size_t i = 0; i < nitems(vmd->reserved); i++) {
if (vmd->reserved[i] != 0) {
error = EINVAL;
return (error);
}
}
error = vmmdev_lookup_and_destroy(vmd->name, td->td_ucred);
break;
}
default:
error = ENOTTY;
break;
}
return (error);
}
static struct cdevsw vmmctlsw = {
.d_name = "vmmctl",
.d_version = D_VERSION,
.d_open = vmmctl_open,
.d_ioctl = vmmctl_ioctl,
};
int
vmmdev_init(void)
{
struct cdev *cdev;
int error;
error = make_dev_p(MAKEDEV_CHECKNAME, &cdev, &vmmctlsw, NULL,
UID_ROOT, GID_WHEEL, 0600, "vmmctl");
if (error)
return (error);
pr_allow_flag = prison_add_allow(NULL, "vmm", NULL,
"Allow use of vmm in a jail.");
return (0);
}
int

View File

@ -18,7 +18,7 @@ struct thread;
struct vm;
struct vcpu;
void vmmdev_init(void);
int vmmdev_init(void);
int vmmdev_cleanup(void);
int vmmdev_machdep_ioctl(struct vm *vm, struct vcpu *vcpu, u_long cmd,
caddr_t data, int fflag, struct thread *td);
@ -54,4 +54,17 @@ extern const size_t vmmdev_machdep_ioctl_count;
#endif /* _KERNEL */
struct vmmctl_vm_create {
char name[VM_MAX_NAMELEN + 1];
int reserved[16];
};
struct vmmctl_vm_destroy {
char name[VM_MAX_NAMELEN + 1];
int reserved[16];
};
#define VMMCTL_VM_CREATE _IOWR('V', 0, struct vmmctl_vm_create)
#define VMMCTL_VM_DESTROY _IOWR('V', 1, struct vmmctl_vm_destroy)
#endif /* _DEV_VMM_DEV_H_ */