mirror of https://gitee.com/openkylin/libvirt.git
bhyve: add a basic driver
At this point it has a limited functionality and is highly experimental. Supported domain operations are: * define * start * destroy * dumpxml * dominfo It's only possible to have only one disk device and only one network, which should be of type bridge.
This commit is contained in:
parent
cffa51b81d
commit
0eb4a5f4f1
|
@ -1047,6 +1047,12 @@ if test "$with_parallels" = "yes"; then
|
|||
fi
|
||||
AM_CONDITIONAL([WITH_PARALLELS], [test "$with_parallels" = "yes"])
|
||||
|
||||
dnl
|
||||
dnl Checks for bhyve driver
|
||||
dnl
|
||||
|
||||
LIBVIRT_DRIVER_CHECK_BHYVE
|
||||
|
||||
dnl
|
||||
dnl check for shell that understands <> redirection without truncation,
|
||||
dnl needed by src/qemu/qemu_monitor_{text,json}.c.
|
||||
|
@ -2705,6 +2711,7 @@ AC_MSG_NOTICE([ PHYP: $with_phyp])
|
|||
AC_MSG_NOTICE([ ESX: $with_esx])
|
||||
AC_MSG_NOTICE([ Hyper-V: $with_hyperv])
|
||||
AC_MSG_NOTICE([Parallels: $with_parallels])
|
||||
LIBVIRT_DRIVER_RESULT_BHYVE
|
||||
AC_MSG_NOTICE([ Test: $with_test])
|
||||
AC_MSG_NOTICE([ Remote: $with_remote])
|
||||
AC_MSG_NOTICE([ Network: $with_network])
|
||||
|
|
|
@ -77,6 +77,9 @@
|
|||
# ifdef WITH_VBOX
|
||||
# include "vbox/vbox_driver.h"
|
||||
# endif
|
||||
# ifdef WITH_BHYVE
|
||||
# include "bhyve/bhyve_driver.h"
|
||||
# endif
|
||||
# ifdef WITH_NETWORK
|
||||
# include "network/bridge_driver.h"
|
||||
# endif
|
||||
|
@ -405,6 +408,9 @@ static void daemonInitialize(void)
|
|||
# ifdef WITH_VBOX
|
||||
virDriverLoadModule("vbox");
|
||||
# endif
|
||||
# ifdef WITH_BHYVE
|
||||
virDriverLoadModule("bhyve");
|
||||
# endif
|
||||
#else
|
||||
# ifdef WITH_NETWORK
|
||||
networkRegister();
|
||||
|
@ -442,6 +448,9 @@ static void daemonInitialize(void)
|
|||
# ifdef WITH_VBOX
|
||||
vboxRegister();
|
||||
# endif
|
||||
# ifdef WITH_BHYVE
|
||||
bhyveRegister();
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ typedef enum {
|
|||
|
||||
VIR_FROM_ACCESS = 55, /* Error from access control manager */
|
||||
VIR_FROM_SYSTEMD = 56, /* Error from systemd code */
|
||||
VIR_FROM_BHYVE = 57, /* Error from bhyve driver */
|
||||
|
||||
# ifdef VIR_ENUM_SENTINELS
|
||||
VIR_ERR_DOMAIN_LAST
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
dnl The bhyve driver
|
||||
dnl
|
||||
dnl Copyright (C) 2014 Roman Bogorodskiy
|
||||
dnl
|
||||
dnl This library is free software; you can redistribute it and/or
|
||||
dnl modify it under the terms of the GNU Lesser General Public
|
||||
dnl License as published by the Free Software Foundation; either
|
||||
dnl version 2.1 of the License, or (at your option) any later version.
|
||||
dnl
|
||||
dnl This library is distributed in the hope that it will be useful,
|
||||
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
dnl Lesser General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU Lesser General Public
|
||||
dnl License along with this library. If not, see
|
||||
dnl <http://www.gnu.org/licenses/>.
|
||||
dnl
|
||||
|
||||
AC_DEFUN([LIBVIRT_DRIVER_CHECK_BHYVE],[
|
||||
AC_ARG_WITH([bhyve],
|
||||
[AS_HELP_STRING([--with-bhyve],
|
||||
[add BHyVe support @<:@default=check@:>@])])
|
||||
m4_divert_text([DEFAULTS], [with_bhyve=check])
|
||||
|
||||
if test "$with_bhyve" != "no"; then
|
||||
AC_PATH_PROG([BHYVE], [bhyve], [], [$PATH:/usr/sbin])
|
||||
AC_PATH_PROG([BHYVECTL], [bhyvectl], [], [$PATH:/usr/sbin])
|
||||
AC_PATH_PROG([BHYVELOAD], [bhyveload], [], [$PATH:/usr/sbin/])
|
||||
|
||||
if test -z "$BHYVE" || test -z "$BHYVECTL" \
|
||||
test -z "$BHYVELOAD" || test "$with_freebsd" = "no"; then
|
||||
if test "$with_bhyve" = "check"; then
|
||||
with_bhyve="no"
|
||||
else
|
||||
AC_MSG_ERROR([The bhyve driver cannot be enabled])
|
||||
fi
|
||||
else
|
||||
with_bhyve="yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$with_bhyve" = "yes"; then
|
||||
AC_DEFINE_UNQUOTED([WITH_BHYVE], 1, [whether bhyve driver is enabled])
|
||||
AC_DEFINE_UNQUOTED([BHYVE], ["$BHYVE"],
|
||||
[Location of the bhyve tool])
|
||||
AC_DEFINE_UNQUOTED([BHYVECTL], ["$BHYVECTL"],
|
||||
[Location of the bhyvectl tool])
|
||||
AC_DEFINE_UNQUOTED([BHYVELOAD], ["$BHYVELOAD"],
|
||||
[Location of the bhyveload tool])
|
||||
fi
|
||||
AM_CONDITIONAL([WITH_BHYVE], [test "$with_bhyve" = "yes"])
|
||||
])
|
||||
|
||||
AC_DEFUN([LIBVIRT_DRIVER_RESULT_BHYVE],[
|
||||
AC_MSG_NOTICE([ Bhyve: $with_bhyve])
|
||||
])
|
|
@ -8,6 +8,9 @@ gnulib/lib/gai_strerror.c
|
|||
gnulib/lib/regcomp.c
|
||||
src/access/viraccessdriverpolkit.c
|
||||
src/access/viraccessmanager.c
|
||||
src/bhyve/bhyve_command.c
|
||||
src/bhyve/bhyve_driver.c
|
||||
src/bhyve/bhyve_process.c
|
||||
src/conf/capabilities.c
|
||||
src/conf/cpu_conf.c
|
||||
src/conf/device_conf.c
|
||||
|
|
|
@ -512,6 +512,7 @@ DRIVER_SOURCE_FILES = \
|
|||
$(NULL)
|
||||
|
||||
STATEFUL_DRIVER_SOURCE_FILES = \
|
||||
$(BHYVE_DRIVER_SOURCES) \
|
||||
$(INTERFACE_DRIVER_SOURCES) \
|
||||
$(LIBXL_DRIVER_SOURCES) \
|
||||
$(LXC_DRIVER_SOURCES) \
|
||||
|
@ -772,6 +773,16 @@ PARALLELS_DRIVER_SOURCES = \
|
|||
parallels/parallels_storage.c \
|
||||
parallels/parallels_network.c
|
||||
|
||||
BHYVE_DRIVER_SOURCES = \
|
||||
bhyve/bhyve_command.c \
|
||||
bhyve/bhyve_command.h \
|
||||
bhyve/bhyve_driver.h \
|
||||
bhyve/bhyve_driver.c \
|
||||
bhyve/bhyve_process.c \
|
||||
bhyve/bhyve_process.h \
|
||||
bhyve/bhyve_utils.h \
|
||||
$(NULL)
|
||||
|
||||
NETWORK_DRIVER_SOURCES = \
|
||||
network/bridge_driver.h network/bridge_driver.c \
|
||||
network/bridge_driver_platform.h \
|
||||
|
@ -1308,6 +1319,26 @@ libvirt_driver_parallels_la_CFLAGS = \
|
|||
libvirt_driver_parallels_la_SOURCES = $(PARALLELS_DRIVER_SOURCES)
|
||||
endif WITH_PARALLELS
|
||||
|
||||
if WITH_BHYVE
|
||||
noinst_LTLIBRARIES += libvirt_driver_bhyve_impl.la
|
||||
libvirt_driver_bhyve_la_SOURCES =
|
||||
libvirt_driver_bhyve_la_LIBADD = libvirt_driver_bhyve_impl.la
|
||||
if WITH_DRIVER_MODULES
|
||||
mod_LTLIBRARIES += libvirt_driver_bhyve.la
|
||||
libvirt_driver_bhyve_la_LIBADD += ../gnulib/lib/libgnu.la
|
||||
libvirt_driver_bhyve_la_LDFLAGS = -module -avoid-version $(AM_LDFLAGS)
|
||||
else ! WITH_DRIVER_MODULES
|
||||
noinst_LTLIBRARIES += libvirt_driver_bhyve.la
|
||||
endif ! WITH_DRIVER_MODULES
|
||||
|
||||
libvirt_driver_bhyve_impl_la_CFLAGS = \
|
||||
-I$(top_srcdir)/src/access \
|
||||
-I$(top_srcdir)/src/conf \
|
||||
$(AM_CFLAGS)
|
||||
libvirt_driver_bhyve_impl_la_LDFLAGS = $(AM_LDFLAGS)
|
||||
libvirt_driver_bhyve_impl_la_SOURCES = $(BHYVE_DRIVER_SOURCES)
|
||||
endif WITH_BHYVE
|
||||
|
||||
if WITH_NETWORK
|
||||
noinst_LTLIBRARIES += libvirt_driver_network_impl.la
|
||||
libvirt_driver_network_la_SOURCES =
|
||||
|
@ -1642,6 +1673,7 @@ EXTRA_DIST += \
|
|||
$(HYPERV_DRIVER_SOURCES) \
|
||||
$(HYPERV_DRIVER_EXTRA_DIST) \
|
||||
$(PARALLELS_DRIVER_SOURCES) \
|
||||
$(BHYVE_DRIVER_SOURCES) \
|
||||
$(NETWORK_DRIVER_SOURCES) \
|
||||
$(INTERFACE_DRIVER_SOURCES) \
|
||||
$(STORAGE_DRIVER_SOURCES) \
|
||||
|
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* bhyve_process.c: bhyve command generation
|
||||
*
|
||||
* Copyright (C) 2014 Roman Bogorodskiy
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_tap.h>
|
||||
|
||||
#include "bhyve_command.h"
|
||||
#include "viralloc.h"
|
||||
#include "virfile.h"
|
||||
#include "virstring.h"
|
||||
#include "virlog.h"
|
||||
#include "virnetdev.h"
|
||||
#include "virnetdevbridge.h"
|
||||
#include "virnetdevtap.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_BHYVE
|
||||
|
||||
static char*
|
||||
virBhyveTapGetRealDeviceName(char *name)
|
||||
{
|
||||
/* This is an ugly hack, because if we rename
|
||||
* tap device to vnet%d, its device name will be
|
||||
* still /dev/tap%d, and bhyve tries to open /dev/tap%d,
|
||||
* so we have to find the real name
|
||||
*/
|
||||
char *ret = NULL;
|
||||
struct dirent *dp;
|
||||
char *devpath = NULL;
|
||||
int fd;
|
||||
|
||||
DIR *dirp = opendir("/dev");
|
||||
if (dirp == NULL) {
|
||||
virReportSystemError(errno,
|
||||
_("Failed to opendir path '%s'"),
|
||||
"/dev");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (STRPREFIX(dp->d_name, "tap")) {
|
||||
struct ifreq ifr;
|
||||
if (virAsprintf(&devpath, "/dev/%s", dp->d_name) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if ((fd = open(devpath, O_RDWR)) < 0) {
|
||||
virReportSystemError(errno, _("Unable to open '%s'"), devpath);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to query tap interface name"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (STREQ(name, ifr.ifr_name)) {
|
||||
/* we can ignore the return value
|
||||
* because we still have nothing
|
||||
* to do but return;
|
||||
*/
|
||||
ignore_value(VIR_STRDUP(ret, dp->d_name));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
VIR_FREE(devpath);
|
||||
VIR_FORCE_CLOSE(fd);
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
if (errno != 0)
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to iterate over TAP devices"));
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(devpath);
|
||||
VIR_FORCE_CLOSE(fd);
|
||||
closedir(dirp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveBuildNetArgStr(const virDomainDef *def, virCommandPtr cmd)
|
||||
{
|
||||
virDomainNetDefPtr net = NULL;
|
||||
char *brname = NULL;
|
||||
char *realifname = NULL;
|
||||
int *tapfd = NULL;
|
||||
|
||||
if (def->nnets != 1) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("domain should have one and only one net defined"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
net = def->nets[0];
|
||||
|
||||
if (net) {
|
||||
int actualType = virDomainNetGetActualType(net);
|
||||
|
||||
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
|
||||
if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("Network type %d is not supported"),
|
||||
virDomainNetGetActualType(net));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!net->ifname ||
|
||||
STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
|
||||
strchr(net->ifname, '%')) {
|
||||
VIR_FREE(net->ifname);
|
||||
if (VIR_STRDUP(net->ifname, VIR_NET_GENERATED_PREFIX "%d") < 0) {
|
||||
VIR_FREE(brname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
|
||||
def->uuid, tapfd, 1,
|
||||
virDomainNetGetActualVirtPortProfile(net),
|
||||
virDomainNetGetActualVlan(net),
|
||||
VIR_NETDEV_TAP_CREATE_IFUP | VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
|
||||
VIR_FREE(net->ifname);
|
||||
VIR_FREE(brname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
realifname = virBhyveTapGetRealDeviceName(net->ifname);
|
||||
|
||||
if (realifname == NULL) {
|
||||
VIR_FREE(net->ifname);
|
||||
VIR_FREE(brname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_DEBUG("%s -> %s", net->ifname, realifname);
|
||||
/* hack on top of other hack: we need to set
|
||||
* interface to 'UP' again after re-opening to find its
|
||||
* name
|
||||
*/
|
||||
if (virNetDevSetOnline(net->ifname, true) != 0) {
|
||||
VIR_FREE(net->ifname);
|
||||
VIR_FREE(brname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandAddArgList(cmd, "-s", "0:0,hostbridge", NULL);
|
||||
virCommandAddArg(cmd, "-s");
|
||||
virCommandAddArgFormat(cmd, "1:0,virtio-net,%s", realifname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveBuildDiskArgStr(const virDomainDef *def, virCommandPtr cmd)
|
||||
{
|
||||
virDomainDiskDefPtr disk;
|
||||
|
||||
if (def->ndisks != 1) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("domain should have one and only one disk defined"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
disk = def->disks[0];
|
||||
|
||||
if (disk->bus != VIR_DOMAIN_DISK_BUS_SATA) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("unsupported disk bus type"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("unsupported disk device"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (disk->type != VIR_DOMAIN_DISK_TYPE_FILE) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("unsupported disk type"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandAddArg(cmd, "-s");
|
||||
virCommandAddArgFormat(cmd, "2:0,ahci-hd,%s", disk->src);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virCommandPtr
|
||||
virBhyveProcessBuildBhyveCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
|
||||
virDomainObjPtr vm)
|
||||
{
|
||||
/*
|
||||
* /usr/sbin/bhyve -c 2 -m 256 -AI -H -P \
|
||||
* -s 0:0,hostbridge \
|
||||
* -s 1:0,virtio-net,tap0 \
|
||||
* -s 2:0,ahci-hd,${IMG} \
|
||||
* -S 31,uart,stdio \
|
||||
* vm0
|
||||
*/
|
||||
virCommandPtr cmd = virCommandNew(BHYVE);
|
||||
|
||||
/* CPUs */
|
||||
virCommandAddArg(cmd, "-c");
|
||||
virCommandAddArgFormat(cmd, "%d", vm->def->vcpus);
|
||||
|
||||
/* Memory */
|
||||
virCommandAddArg(cmd, "-m");
|
||||
virCommandAddArgFormat(cmd, "%llu",
|
||||
VIR_DIV_UP(vm->def->mem.max_balloon, 1024));
|
||||
|
||||
/* Options */
|
||||
if (vm->def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_DOMAIN_FEATURE_STATE_ON)
|
||||
virCommandAddArg(cmd, "-A"); /* Create an ACPI table */
|
||||
if (vm->def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_DOMAIN_FEATURE_STATE_ON)
|
||||
virCommandAddArg(cmd, "-I"); /* Present ioapic to the guest */
|
||||
|
||||
/* Clarification about -H and -P flags from Peter Grehan:
|
||||
* -H and -P flags force the guest to exit when it executes IA32 HLT and PAUSE
|
||||
* instructions respectively.
|
||||
*
|
||||
* For the HLT exit, bhyve uses that to infer that the guest is idling and can
|
||||
* be put to sleep until an external event arrives. If this option is not used,
|
||||
* the guest will always use 100% of CPU on the host.
|
||||
*
|
||||
* The PAUSE exit is most useful when there are large numbers of guest VMs running,
|
||||
* since it forces the guest to exit when it spins on a lock acquisition.
|
||||
*/
|
||||
virCommandAddArg(cmd, "-H"); /* vmexit from guest on hlt */
|
||||
virCommandAddArg(cmd, "-P"); /* vmexit from guest on pause */
|
||||
|
||||
/* Devices */
|
||||
if (bhyveBuildNetArgStr(vm->def, cmd) < 0)
|
||||
goto error;
|
||||
if (bhyveBuildDiskArgStr(vm->def, cmd) < 0)
|
||||
goto error;
|
||||
virCommandAddArg(cmd, vm->def->name);
|
||||
|
||||
return cmd;
|
||||
|
||||
error:
|
||||
virCommandFree(cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virCommandPtr
|
||||
virBhyveProcessBuildDestroyCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
|
||||
virDomainObjPtr vm)
|
||||
{
|
||||
virCommandPtr cmd = virCommandNew(BHYVECTL);
|
||||
|
||||
virCommandAddArg(cmd, "--destroy");
|
||||
virCommandAddArgPair(cmd, "--vm", vm->def->name);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
virCommandPtr
|
||||
virBhyveProcessBuildLoadCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
|
||||
virDomainObjPtr vm)
|
||||
{
|
||||
virCommandPtr cmd;
|
||||
virDomainDiskDefPtr disk;
|
||||
|
||||
if (vm->def->ndisks != 1) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("domain should have one and only one disk defined"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
disk = vm->def->disks[0];
|
||||
|
||||
if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("unsupported disk device"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (disk->type != VIR_DOMAIN_DISK_TYPE_FILE) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("unsupported disk type"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmd = virCommandNew(BHYVELOAD);
|
||||
|
||||
/* Memory */
|
||||
virCommandAddArg(cmd, "-m");
|
||||
virCommandAddArgFormat(cmd, "%llu",
|
||||
VIR_DIV_UP(vm->def->mem.max_balloon, 1024));
|
||||
|
||||
/* Image path */
|
||||
virCommandAddArg(cmd, "-d");
|
||||
virCommandAddArg(cmd, disk->src);
|
||||
|
||||
/* VM name */
|
||||
virCommandAddArg(cmd, vm->def->name);
|
||||
|
||||
return cmd;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* bhyve_process.c: bhyve command generation
|
||||
*
|
||||
* Copyright (C) 2014 Roman Bogorodskiy
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BHYVE_COMMAND_H__
|
||||
# define __BHYVE_COMMAND_H__
|
||||
|
||||
# include "bhyve_utils.h"
|
||||
|
||||
# include "domain_conf.h"
|
||||
# include "vircommand.h"
|
||||
|
||||
virCommandPtr virBhyveProcessBuildBhyveCmd(bhyveConnPtr,
|
||||
virDomainObjPtr vm);
|
||||
|
||||
virCommandPtr
|
||||
virBhyveProcessBuildDestroyCmd(bhyveConnPtr driver,
|
||||
virDomainObjPtr vm);
|
||||
|
||||
virCommandPtr
|
||||
virBhyveProcessBuildLoadCmd(bhyveConnPtr driver,
|
||||
virDomainObjPtr vm);
|
||||
|
||||
#endif /* __BHYVE_COMMAND_H__ */
|
|
@ -0,0 +1,612 @@
|
|||
/*
|
||||
* bhyve_driver.c: core driver methods for managing bhyve guests
|
||||
*
|
||||
* Copyright (C) 2014 Roman Bogorodskiy
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Roman Bogorodskiy
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "virerror.h"
|
||||
#include "datatypes.h"
|
||||
#include "virbuffer.h"
|
||||
#include "viruuid.h"
|
||||
#include "capabilities.h"
|
||||
#include "configmake.h"
|
||||
#include "viralloc.h"
|
||||
#include "network_conf.h"
|
||||
#include "interface_conf.h"
|
||||
#include "domain_audit.h"
|
||||
#include "domain_conf.h"
|
||||
#include "snapshot_conf.h"
|
||||
#include "fdstream.h"
|
||||
#include "storage_conf.h"
|
||||
#include "node_device_conf.h"
|
||||
#include "virxml.h"
|
||||
#include "virthread.h"
|
||||
#include "virlog.h"
|
||||
#include "virfile.h"
|
||||
#include "virtypedparam.h"
|
||||
#include "virrandom.h"
|
||||
#include "virstring.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "viraccessapicheck.h"
|
||||
|
||||
#include "bhyve_driver.h"
|
||||
#include "bhyve_process.h"
|
||||
#include "bhyve_utils.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_BHYVE
|
||||
|
||||
bhyveConnPtr bhyve_driver = NULL;
|
||||
|
||||
void
|
||||
bhyveDriverLock(bhyveConnPtr driver)
|
||||
{
|
||||
virMutexLock(&driver->lock);
|
||||
}
|
||||
|
||||
void
|
||||
bhyveDriverUnlock(bhyveConnPtr driver)
|
||||
{
|
||||
virMutexUnlock(&driver->lock);
|
||||
}
|
||||
|
||||
static virCapsPtr
|
||||
bhyveBuildCapabilities(void)
|
||||
{
|
||||
virCapsPtr caps;
|
||||
virCapsGuestPtr guest;
|
||||
|
||||
if ((caps = virCapabilitiesNew(virArchFromHost(),
|
||||
0, 0)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((guest = virCapabilitiesAddGuest(caps, "hvm",
|
||||
VIR_ARCH_X86_64,
|
||||
"bhyve",
|
||||
NULL, 0, NULL)) == NULL)
|
||||
goto error;
|
||||
|
||||
if (virCapabilitiesAddGuestDomain(guest,
|
||||
"bhyve", NULL, NULL, 0, NULL) == NULL)
|
||||
goto error;
|
||||
|
||||
return caps;
|
||||
|
||||
error:
|
||||
virObjectUnref(caps);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
bhyveConnectGetCapabilities(virConnectPtr conn)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
char *xml;
|
||||
|
||||
if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
|
||||
return NULL;
|
||||
|
||||
if ((xml = virCapabilitiesFormatXML(privconn->caps)) == NULL)
|
||||
virReportOOMError();
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
static virDomainObjPtr
|
||||
bhyveDomObjFromDomain(virDomainPtr domain)
|
||||
{
|
||||
virDomainObjPtr vm;
|
||||
bhyveConnPtr privconn = domain->conn->privateData;
|
||||
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||
|
||||
vm = virDomainObjListFindByUUID(privconn->domains, domain->uuid);
|
||||
if (!vm) {
|
||||
virUUIDFormat(domain->uuid, uuidstr);
|
||||
virReportError(VIR_ERR_NO_DOMAIN,
|
||||
_("no domain with matching uuid '%s' (%s)"),
|
||||
uuidstr, domain->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
static virDrvOpenStatus
|
||||
bhyveConnectOpen(virConnectPtr conn,
|
||||
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
||||
unsigned int flags)
|
||||
{
|
||||
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
|
||||
|
||||
if (conn->uri == NULL) {
|
||||
if (bhyve_driver == NULL)
|
||||
return VIR_DRV_OPEN_DECLINED;
|
||||
|
||||
if (!(conn->uri = virURIParse("bhyve:///system")))
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
} else {
|
||||
if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "bhyve"))
|
||||
return VIR_DRV_OPEN_DECLINED;
|
||||
|
||||
if (conn->uri->server)
|
||||
return VIR_DRV_OPEN_DECLINED;
|
||||
|
||||
if (!STREQ_NULLABLE(conn->uri->path, "/system")) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unexpected bhyve URI path '%s', try bhyve:///system"),
|
||||
conn->uri->path);
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
|
||||
if (bhyve_driver == NULL) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("bhyve state driver is not active"));
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (virConnectOpenEnsureACL(conn) < 0)
|
||||
return VIR_DRV_OPEN_ERROR;
|
||||
|
||||
conn->privateData = bhyve_driver;
|
||||
|
||||
return VIR_DRV_OPEN_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveConnectClose(virConnectPtr conn)
|
||||
{
|
||||
conn->privateData = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
bhyveConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (virConnectGetHostnameEnsureACL(conn) < 0)
|
||||
return NULL;
|
||||
|
||||
return virGetHostname();
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
|
||||
{
|
||||
struct utsname ver;
|
||||
|
||||
if (virConnectGetVersionEnsureACL(conn) < 0)
|
||||
return -1;
|
||||
|
||||
uname(&ver);
|
||||
|
||||
if (virParseVersionString(ver.release, version, true) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown release: %s"), ver.release);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
|
||||
{
|
||||
virDomainObjPtr vm;
|
||||
int ret = -1;
|
||||
|
||||
if (!(vm = bhyveDomObjFromDomain(domain)))
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainGetInfoEnsureACL(domain->conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
info->state = virDomainObjGetState(vm, NULL);
|
||||
info->maxMem = vm->def->mem.max_balloon;
|
||||
info->nrVirtCpu = vm->def->vcpus;
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveDomainGetState(virDomainPtr domain,
|
||||
int *state,
|
||||
int *reason,
|
||||
unsigned int flags)
|
||||
{
|
||||
virDomainObjPtr vm;
|
||||
int ret = -1;
|
||||
|
||||
virCheckFlags(0, -1);
|
||||
|
||||
if (!(vm = bhyveDomObjFromDomain(domain)))
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainGetStateEnsureACL(domain->conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
*state = virDomainObjGetState(vm, reason);
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
bhyveDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
|
||||
{
|
||||
virDomainObjPtr vm;
|
||||
char *ret = NULL;
|
||||
|
||||
if (!(vm = bhyveDomObjFromDomain(domain)))
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainGetXMLDescEnsureACL(domain->conn, vm->def, flags) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = virDomainDefFormat(vm->def, flags);
|
||||
|
||||
cleanup:
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static virDomainPtr
|
||||
bhyveDomainDefineXML(virConnectPtr conn, const char *xml)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
virDomainPtr dom = NULL;
|
||||
virDomainDefPtr def = NULL;
|
||||
virDomainDefPtr oldDef = NULL;
|
||||
virDomainObjPtr vm = NULL;
|
||||
|
||||
if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
|
||||
1 << VIR_DOMAIN_VIRT_BHYVE,
|
||||
VIR_DOMAIN_XML_INACTIVE)) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainDefineXMLEnsureACL(conn, def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!(vm = virDomainObjListAdd(privconn->domains, def,
|
||||
privconn->xmlopt,
|
||||
0, &oldDef)))
|
||||
goto cleanup;
|
||||
def = NULL;
|
||||
|
||||
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
||||
if (dom)
|
||||
dom->id = vm->def->id;
|
||||
|
||||
if (virDomainSaveConfig(BHYVE_CONFIG_DIR, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
virDomainDefFree(def);
|
||||
virObjectUnlock(vm);
|
||||
|
||||
return dom;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveConnectListDomains(virConnectPtr conn, int *ids, int maxids)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
int n;
|
||||
|
||||
if (virConnectListDomainsEnsureACL(conn) < 0)
|
||||
return -1;
|
||||
|
||||
n = virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
|
||||
virConnectListDomainsCheckACL, conn);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveConnectNumOfDomains(virConnectPtr conn)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
int count;
|
||||
|
||||
if (virConnectNumOfDomainsEnsureACL(conn) < 0)
|
||||
return -1;
|
||||
|
||||
count = virDomainObjListNumOfDomains(privconn->domains, true,
|
||||
virConnectNumOfDomainsCheckACL, conn);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveConnectListDefinedDomains(virConnectPtr conn, char **const names,
|
||||
int maxnames)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
int n;
|
||||
|
||||
if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
|
||||
return -1;
|
||||
|
||||
memset(names, 0, sizeof(*names) * maxnames);
|
||||
n = virDomainObjListGetInactiveNames(privconn->domains, names,
|
||||
maxnames, virConnectListDefinedDomainsCheckACL, conn);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveConnectNumOfDefinedDomains(virConnectPtr conn)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
int count;
|
||||
|
||||
if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
|
||||
return -1;
|
||||
|
||||
count = virDomainObjListNumOfDomains(privconn->domains, false,
|
||||
virConnectNumOfDefinedDomainsCheckACL, conn);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveConnectListAllDomains(virConnectPtr conn,
|
||||
virDomainPtr **domains,
|
||||
unsigned int flags)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
int ret = -1;
|
||||
|
||||
virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
|
||||
|
||||
if (virConnectListAllDomainsEnsureACL(conn) < 0)
|
||||
return -1;
|
||||
|
||||
ret = virDomainObjListExport(privconn->domains, conn, domains,
|
||||
virConnectListAllDomainsCheckACL, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static virDomainPtr
|
||||
bhyveDomainLookupByUUID(virConnectPtr conn,
|
||||
const unsigned char *uuid)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
virDomainObjPtr vm;
|
||||
virDomainPtr dom = NULL;
|
||||
|
||||
vm = virDomainObjListFindByUUID(privconn->domains, uuid);
|
||||
|
||||
if (!vm) {
|
||||
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||
virUUIDFormat(uuid, uuidstr);
|
||||
virReportError(VIR_ERR_NO_DOMAIN,
|
||||
_("No domain with matching uuid '%s'"), uuidstr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
||||
if (dom)
|
||||
dom->id = vm->def->id;
|
||||
|
||||
cleanup:
|
||||
virObjectUnlock(vm);
|
||||
return dom;
|
||||
}
|
||||
|
||||
static virDomainPtr bhyveDomainLookupByName(virConnectPtr conn,
|
||||
const char *name)
|
||||
{
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
virDomainObjPtr vm;
|
||||
virDomainPtr dom = NULL;
|
||||
|
||||
vm = virDomainObjListFindByName(privconn->domains, name);
|
||||
|
||||
if (!vm) {
|
||||
virReportError(VIR_ERR_NO_DOMAIN,
|
||||
_("no domain with matching name '%s'"), name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
|
||||
if (dom)
|
||||
dom->id = vm->def->id;
|
||||
|
||||
cleanup:
|
||||
virObjectUnlock(vm);
|
||||
return dom;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveDomainCreate(virDomainPtr dom)
|
||||
{
|
||||
bhyveConnPtr privconn = dom->conn->privateData;
|
||||
virDomainObjPtr vm;
|
||||
int ret = -1;
|
||||
|
||||
if (!(vm = bhyveDomObjFromDomain(dom)))
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainCreateEnsureACL(dom->conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainObjIsActive(vm)) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
"%s", _("Domain is already running"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = virBhyveProcessStart(dom->conn, privconn, vm,
|
||||
VIR_DOMAIN_RUNNING_BOOTED);
|
||||
|
||||
cleanup:
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveDomainDestroy(virDomainPtr dom)
|
||||
{
|
||||
bhyveConnPtr privconn = dom->conn->privateData;
|
||||
virDomainObjPtr vm;
|
||||
int ret = -1;
|
||||
|
||||
if (!(vm = bhyveDomObjFromDomain(dom)))
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainDestroyEnsureACL(dom->conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = virBhyveProcessStop(privconn, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
|
||||
|
||||
cleanup:
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveStateCleanup(void)
|
||||
{
|
||||
VIR_DEBUG("bhyve state cleanup");
|
||||
|
||||
if (bhyve_driver == NULL)
|
||||
return -1;
|
||||
|
||||
virObjectUnref(bhyve_driver->domains);
|
||||
virObjectUnref(bhyve_driver->caps);
|
||||
virObjectUnref(bhyve_driver->xmlopt);
|
||||
|
||||
virMutexDestroy(&bhyve_driver->lock);
|
||||
VIR_FREE(bhyve_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bhyveStateInitialize(bool priveleged ATTRIBUTE_UNUSED,
|
||||
virStateInhibitCallback callback ATTRIBUTE_UNUSED,
|
||||
void *opaque ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (!priveleged) {
|
||||
VIR_INFO("Not running priveleged, disabling driver");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC(bhyve_driver) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virMutexInit(&bhyve_driver->lock) < 0) {
|
||||
VIR_FREE(bhyve_driver);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(bhyve_driver->caps = bhyveBuildCapabilities()))
|
||||
goto cleanup;
|
||||
|
||||
if (!(bhyve_driver->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL)))
|
||||
goto cleanup;
|
||||
|
||||
if (!(bhyve_driver->domains = virDomainObjListNew()))
|
||||
goto cleanup;
|
||||
|
||||
if (virFileMakePath(BHYVE_LOG_DIR) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("Failed to mkdir %s"),
|
||||
BHYVE_LOG_DIR);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virFileMakePath(BHYVE_STATE_DIR) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("Failed to mkdir %s"),
|
||||
BHYVE_LOG_DIR);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virDomainObjListLoadAllConfigs(bhyve_driver->domains,
|
||||
BHYVE_CONFIG_DIR,
|
||||
NULL, 0,
|
||||
bhyve_driver->caps,
|
||||
bhyve_driver->xmlopt,
|
||||
1 << VIR_DOMAIN_VIRT_BHYVE,
|
||||
NULL, NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
bhyveStateCleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static virDriver bhyveDriver = {
|
||||
.no = VIR_DRV_BHYVE,
|
||||
.name = "bhyve",
|
||||
.connectOpen = bhyveConnectOpen, /* 1.2.2 */
|
||||
.connectClose = bhyveConnectClose, /* 1.2.2 */
|
||||
.connectGetVersion = bhyveConnectGetVersion, /* 1.2.2 */
|
||||
.connectGetHostname = bhyveConnectGetHostname, /* 1.2.2 */
|
||||
.domainGetInfo = bhyveDomainGetInfo, /* 1.2.2 */
|
||||
.domainGetState = bhyveDomainGetState, /* 1.2.2 */
|
||||
.connectGetCapabilities = bhyveConnectGetCapabilities, /* 1.2.2 */
|
||||
.connectListDomains = bhyveConnectListDomains, /* 1.2.2 */
|
||||
.connectNumOfDomains = bhyveConnectNumOfDomains, /* 1.2.2 */
|
||||
.connectListAllDomains = bhyveConnectListAllDomains, /* 1.2.2 */
|
||||
.connectListDefinedDomains = bhyveConnectListDefinedDomains, /* 1.2.2 */
|
||||
.connectNumOfDefinedDomains = bhyveConnectNumOfDefinedDomains, /* 1.2.2 */
|
||||
.domainCreate = bhyveDomainCreate, /* 1.2.2 */
|
||||
.domainDestroy = bhyveDomainDestroy, /* 1.2.2 */
|
||||
.domainLookupByUUID = bhyveDomainLookupByUUID, /* 1.2.2 */
|
||||
.domainLookupByName = bhyveDomainLookupByName, /* 1.2.2 */
|
||||
.domainDefineXML = bhyveDomainDefineXML, /* 1.2.2 */
|
||||
.domainGetXMLDesc = bhyveDomainGetXMLDesc, /* 1.2.2 */
|
||||
};
|
||||
|
||||
|
||||
static virStateDriver bhyveStateDriver = {
|
||||
.name = "bhyve",
|
||||
.stateInitialize = bhyveStateInitialize,
|
||||
.stateCleanup = bhyveStateCleanup,
|
||||
};
|
||||
|
||||
int
|
||||
bhyveRegister(void)
|
||||
{
|
||||
virRegisterDriver(&bhyveDriver);
|
||||
virRegisterStateDriver(&bhyveStateDriver);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* bhyve_driver.h: core driver methods for managing bhyve guests
|
||||
*
|
||||
* Copyright (C) 2014 Roman Bogorodskiy
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Roman Bogorodskiy <bogorodskiy@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __BHYVE_DRIVER_H__
|
||||
# define __BHYVE_DRIVER_H__
|
||||
|
||||
int bhyveRegister(void);
|
||||
|
||||
#endif /* __BHYVE_DRIVER_H__ */
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* bhyve_process.c: bhyve process management
|
||||
*
|
||||
* Copyright (C) 2014 Roman Bogorodskiy
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_tap.h>
|
||||
|
||||
#include "bhyve_process.h"
|
||||
#include "bhyve_command.h"
|
||||
#include "datatypes.h"
|
||||
#include "virerror.h"
|
||||
#include "virlog.h"
|
||||
#include "virfile.h"
|
||||
#include "viralloc.h"
|
||||
#include "vircommand.h"
|
||||
#include "virstring.h"
|
||||
#include "virpidfile.h"
|
||||
#include "virprocess.h"
|
||||
#include "virnetdev.h"
|
||||
#include "virnetdevbridge.h"
|
||||
#include "virnetdevtap.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_BHYVE
|
||||
|
||||
int
|
||||
virBhyveProcessStart(virConnectPtr conn,
|
||||
bhyveConnPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainRunningReason reason)
|
||||
{
|
||||
char *logfile = NULL;
|
||||
int logfd = -1;
|
||||
off_t pos = -1;
|
||||
char ebuf[1024];
|
||||
virCommandPtr cmd = NULL;
|
||||
virCommandPtr load_cmd = NULL;
|
||||
bhyveConnPtr privconn = conn->privateData;
|
||||
int ret = -1, status;
|
||||
|
||||
if (virAsprintf(&logfile, "%s/%s.log",
|
||||
BHYVE_LOG_DIR, vm->def->name) < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT,
|
||||
S_IRUSR | S_IWUSR)) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("Failed to open '%s'"),
|
||||
logfile);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
VIR_FREE(privconn->pidfile);
|
||||
if (!(privconn->pidfile = virPidFileBuildPath(BHYVE_STATE_DIR,
|
||||
vm->def->name))) {
|
||||
virReportSystemError(errno,
|
||||
"%s", _("Failed to build pidfile path"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (unlink(privconn->pidfile) < 0 &&
|
||||
errno != ENOENT) {
|
||||
virReportSystemError(errno,
|
||||
_("Cannot remove state PID file %s"),
|
||||
privconn->pidfile);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Call bhyve to start the VM */
|
||||
if (!(cmd = virBhyveProcessBuildBhyveCmd(driver,
|
||||
vm)))
|
||||
goto cleanup;
|
||||
|
||||
virCommandSetOutputFD(cmd, &logfd);
|
||||
virCommandSetErrorFD(cmd, &logfd);
|
||||
virCommandWriteArgLog(cmd, logfd);
|
||||
virCommandSetPidFile(cmd, privconn->pidfile);
|
||||
virCommandDaemonize(cmd);
|
||||
|
||||
/* Now bhyve command is constructed, meaning the
|
||||
* domain is ready to be started, so we can build
|
||||
* and execute bhyveload command */
|
||||
if (!(load_cmd = virBhyveProcessBuildLoadCmd(driver, vm)))
|
||||
goto cleanup;
|
||||
virCommandSetOutputFD(load_cmd, &logfd);
|
||||
virCommandSetErrorFD(load_cmd, &logfd);
|
||||
|
||||
/* Log generated command line */
|
||||
virCommandWriteArgLog(load_cmd, logfd);
|
||||
if ((pos = lseek(logfd, 0, SEEK_END)) < 0)
|
||||
VIR_WARN("Unable to seek to end of logfile: %s",
|
||||
virStrerror(errno, ebuf, sizeof(ebuf)));
|
||||
|
||||
VIR_DEBUG("Loading domain '%s'", vm->def->name);
|
||||
if (virCommandRun(load_cmd, &status) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (status != 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Guest failed to load: %d"), status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Now we can start the domain */
|
||||
VIR_DEBUG("Starting domain '%s'", vm->def->name);
|
||||
ret = virCommandRun(cmd, NULL);
|
||||
|
||||
if (ret == 0) {
|
||||
if (virPidFileReadPath(privconn->pidfile, &vm->pid) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Domain %s didn't show up"), vm->def->name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
vm->def->id = vm->pid;
|
||||
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (ret < 0) {
|
||||
virCommandPtr destroy_cmd;
|
||||
if ((destroy_cmd = virBhyveProcessBuildDestroyCmd(driver, vm)) != NULL) {
|
||||
virCommandSetOutputFD(load_cmd, &logfd);
|
||||
virCommandSetErrorFD(load_cmd, &logfd);
|
||||
ignore_value(virCommandRun(destroy_cmd, NULL));
|
||||
virCommandFree(destroy_cmd);
|
||||
}
|
||||
}
|
||||
|
||||
virCommandFree(load_cmd);
|
||||
virCommandFree(cmd);
|
||||
VIR_FREE(logfile);
|
||||
VIR_FORCE_CLOSE(logfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
virBhyveProcessStop(bhyveConnPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainShutoffReason reason ATTRIBUTE_UNUSED)
|
||||
{
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
int status;
|
||||
virCommandPtr cmd = NULL;
|
||||
|
||||
if (!virDomainObjIsActive(vm)) {
|
||||
VIR_DEBUG("VM '%s' not active", vm->def->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vm->pid <= 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Invalid PID %d for VM"),
|
||||
(int)vm->pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* First, try to kill 'bhyve' process */
|
||||
if (virProcessKillPainfully(vm->pid, true) != 0)
|
||||
VIR_WARN("Failed to gracefully stop bhyve VM '%s' (pid: %d)",
|
||||
vm->def->name,
|
||||
(int)vm->pid);
|
||||
|
||||
for (i = 0; i < vm->def->nnets; i++) {
|
||||
virDomainNetDefPtr net = vm->def->nets[i];
|
||||
int actualType = virDomainNetGetActualType(net);
|
||||
|
||||
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
|
||||
ignore_value(virNetDevBridgeRemovePort(
|
||||
virDomainNetGetActualBridgeName(net),
|
||||
net->ifname));
|
||||
ignore_value(virNetDevTapDelete(net->ifname));
|
||||
}
|
||||
}
|
||||
|
||||
/* No matter if shutdown was successful or not, we
|
||||
* need to unload the VM */
|
||||
if (!(cmd = virBhyveProcessBuildDestroyCmd(driver, vm)))
|
||||
goto cleanup;
|
||||
|
||||
if (virCommandRun(cmd, &status) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (status != 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Guest failed to stop: %d"), status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
|
||||
vm->pid = -1;
|
||||
vm->def->id = -1;
|
||||
|
||||
cleanup:
|
||||
virCommandFree(cmd);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* bhyve_process.h: bhyve process management
|
||||
*
|
||||
* Copyright (C) 2014 Roman Bogorodskiy
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BHYVE_PROCESS_H__
|
||||
# define __BHYVE_PROCESS_H__
|
||||
|
||||
# include "bhyve_utils.h"
|
||||
|
||||
int virBhyveProcessStart(virConnectPtr conn,
|
||||
bhyveConnPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainRunningReason reason);
|
||||
|
||||
int virBhyveProcessStop(bhyveConnPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainShutoffReason reason);
|
||||
|
||||
#endif /* __BHYVE_PROCESS_H__ */
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* bhyve_utils.h: bhyve utils
|
||||
*
|
||||
* Copyright (C) 2014 Roman Bogorodskiy
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BHYVE_UTILS_H__
|
||||
# define __BHYVE_UTILS_H__
|
||||
|
||||
# include "driver.h"
|
||||
# include "domain_conf.h"
|
||||
# include "configmake.h"
|
||||
# include "virthread.h"
|
||||
|
||||
# define BHYVE_CONFIG_DIR SYSCONFDIR "/libvirt/bhyve"
|
||||
# define BHYVE_STATE_DIR LOCALSTATEDIR "/run/libvirt/bhyve"
|
||||
# define BHYVE_LOG_DIR LOCALSTATEDIR "/log/libvirt/bhyve"
|
||||
|
||||
struct _bhyveConn {
|
||||
virMutex lock;
|
||||
virDomainObjListPtr domains;
|
||||
virCapsPtr caps;
|
||||
virDomainXMLOptionPtr xmlopt;
|
||||
char *pidfile;
|
||||
};
|
||||
|
||||
typedef struct _bhyveConn bhyveConn;
|
||||
typedef struct _bhyveConn *bhyveConnPtr;
|
||||
|
||||
void bhyveDriverLock(bhyveConnPtr driver);
|
||||
void bhyveDriverUnlock(bhyveConnPtr driver);
|
||||
|
||||
#endif /* __BHYVE_UTILS_H__ */
|
|
@ -123,7 +123,8 @@ VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
|
|||
"hyperv",
|
||||
"vbox",
|
||||
"phyp",
|
||||
"parallels")
|
||||
"parallels",
|
||||
"bhyve")
|
||||
|
||||
VIR_ENUM_IMPL(virDomainBoot, VIR_DOMAIN_BOOT_LAST,
|
||||
"fd",
|
||||
|
|
|
@ -196,6 +196,7 @@ enum virDomainVirtType {
|
|||
VIR_DOMAIN_VIRT_VBOX,
|
||||
VIR_DOMAIN_VIRT_PHYP,
|
||||
VIR_DOMAIN_VIRT_PARALLELS,
|
||||
VIR_DOMAIN_VIRT_BHYVE,
|
||||
|
||||
VIR_DOMAIN_VIRT_LAST
|
||||
};
|
||||
|
|
|
@ -47,6 +47,7 @@ typedef enum {
|
|||
VIR_DRV_LIBXL = 14,
|
||||
VIR_DRV_HYPERV = 15,
|
||||
VIR_DRV_PARALLELS = 16,
|
||||
VIR_DRV_BHYVE = 17,
|
||||
} virDrvNo;
|
||||
|
||||
|
||||
|
|
|
@ -96,6 +96,9 @@
|
|||
#ifdef WITH_PARALLELS
|
||||
# include "parallels/parallels_driver.h"
|
||||
#endif
|
||||
#ifdef WITH_BHYVE
|
||||
# include "bhyve/bhyve_driver.h"
|
||||
#endif
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||
|
||||
|
|
|
@ -124,6 +124,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
|
|||
|
||||
"Access Manager", /* 55 */
|
||||
"Systemd",
|
||||
"Bhyve",
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue