[libvirt] Add GVirConfigDomainDiskDriver
by Christophe Fergeau
Hey,
I wanted to add support in libvirt-gconfig for the 'discard' attribute of
the disk driver node. If I follow the way the API is currently done, it
would be an additional method to GVirConfigDomainDisk. However, there are
quite a few attributes attached to the disk driver node, so I felt it was
preferrable to have a dedicated GVirConfigDomainDiskDriver class. This also
matches better other places of libvirt-gconfig API.
I've implemented support for most of the attributes of the disk driver node,
as a result the corresponding methods in GVirConfigDomainDisk have been deprecated.
Christophe
10 years, 10 months
[libvirt] [PATCH] virSecuritySELinuxSetFileconHelper: Don't fail on read-only NFS
by Michal Privoznik
https://bugzilla.redhat.com/show_bug.cgi?id=996543
When starting up a domain, the SELinux labeling is done depending on
current configuration. If the labeling fails we check for possible
causes, as not all labeling failures are fatal. For example, if the
labeled file is on NFS which lacks SELinux support, the file can still
be readable to qemu process. These cases are distinguished by the errno
code: NFS without SELinux support returns EOPNOTSUPP. However, we were
missing one scenario. In case there's a read-only disk on a read-only
NFS (and possibly any FS) and the labeling is just optional (not
explicitly requested in the XML) there's no need to make the labeling
error fatal. In other words, read-only file on read-only NFS can fail to
be labeled, but be readable at the same time.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/security/security_selinux.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 11c0c3b..c70ac77 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -896,13 +896,14 @@ virSecuritySELinuxSetFileconHelper(const char *path, char *tcon, bool optional)
freecon(econ);
}
- /* if the error complaint is related to an image hosted on
- * an nfs mount, or a usbfs/sysfs filesystem not supporting
- * labelling, then just ignore it & hope for the best.
- * The user hopefully set one of the necessary SELinux
- * virt_use_{nfs,usb,pci} boolean tunables to allow it...
+ /* If the error complaint is related to an image hosted on a (possibly
+ * read-only) NFS mount, or a usbfs/sysfs filesystem not supporting
+ * labelling, then just ignore it & hope for the best. The user
+ * hopefully sets one of the necessary SELinux virt_use_{nfs,usb,pci}
+ * boolean tunables to allow it ...
*/
- if (setfilecon_errno != EOPNOTSUPP && setfilecon_errno != ENOTSUP) {
+ if (setfilecon_errno != EOPNOTSUPP && setfilecon_errno != ENOTSUP &&
+ setfilecon_errno != EROFS) {
virReportSystemError(setfilecon_errno,
_("unable to set security context '%s' on '%s'"),
tcon, path);
--
1.8.5.2
10 years, 10 months
[libvirt] [PATCH v2] BSD: implement nodeGetCPUStats
by Roman Bogorodskiy
Implementation obtains CPU usage information using
kern.cp_time and kern.cp_times sysctl(8)s and reports
CPU utilization.
---
include/libvirt/libvirt.h.in | 8 ++++
src/nodeinfo.c | 104 +++++++++++++++++++++++++++++++++++++++++++
tools/virsh-host.c | 11 ++++-
3 files changed, 121 insertions(+), 2 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 018a5ce..88afe20 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -692,6 +692,14 @@ typedef enum {
#define VIR_NODE_CPU_STATS_IOWAIT "iowait"
/**
+ * VIR_NODE_CPU_STATS_INTR:
+ *
+ * The cumulative interrupt CPU time,
+ * since the node booting up (in nanoseconds).
+ */
+#define VIR_NODE_CPU_STATS_INTR "intr"
+
+/**
* VIR_NODE_CPU_STATS_UTILIZATION:
*
* The CPU utilization of a node.
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 05bc038..fd2f8c8 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -34,8 +34,10 @@
#include "conf/domain_conf.h"
#if defined(__FreeBSD__) || defined(__APPLE__)
+# include <sys/time.h>
# include <sys/types.h>
# include <sys/sysctl.h>
+# include <sys/resource.h>
#endif
#include "c-ctype.h"
@@ -99,8 +101,108 @@ appleFreebsdNodeGetMemorySize(unsigned long *memory)
#endif /* defined(__FreeBSD__) || defined(__APPLE__) */
#ifdef __FreeBSD__
+# define BSD_CPU_STATS_ALL 4
# define BSD_MEMORY_STATS_ALL 4
+# define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / (stathz ? stathz : hz))
+
+static int
+freebsdNodeGetCPUStats(int cpuNum,
+ virNodeCPUStatsPtr params,
+ int *nparams)
+{
+ const char *sysctl_name;
+ long *cpu_times;
+ struct clockinfo clkinfo;
+ size_t i, j, cpu_times_size, clkinfo_size;
+ int cpu_times_num, offset, hz, stathz, ret = -1;
+ struct field_cpu_map {
+ const char *field;
+ int idx[CPUSTATES];
+ } cpu_map[] = {
+ {VIR_NODE_CPU_STATS_KERNEL, {CP_SYS}},
+ {VIR_NODE_CPU_STATS_USER, {CP_USER, CP_NICE}},
+ {VIR_NODE_CPU_STATS_IDLE, {CP_IDLE}},
+ {VIR_NODE_CPU_STATS_INTR, {CP_INTR}},
+ {NULL, {0}}
+ };
+
+ if ((*nparams) == 0) {
+ *nparams = BSD_CPU_STATS_ALL;
+ return 0;
+ }
+
+ if ((*nparams) != BSD_CPU_STATS_ALL) {
+ virReportInvalidArg(*nparams,
+ _("nparams in %s must be equal to %d"),
+ __FUNCTION__, BSD_CPU_STATS_ALL);
+ return -1;
+ }
+
+ clkinfo_size = sizeof(clkinfo);
+ if (sysctlbyname("kern.clockrate", &clkinfo, &clkinfo_size, NULL, 0) < 0) {
+ virReportSystemError(errno,
+ _("sysctl failed for '%s'"),
+ "kern.clockrate");
+ return -1;
+ }
+
+ stathz = clkinfo.stathz;
+ hz = clkinfo.hz;
+
+ if (cpuNum == VIR_NODE_CPU_STATS_ALL_CPUS) {
+ sysctl_name = "kern.cp_time";
+ cpu_times_num = 1;
+ offset = 0;
+ } else {
+ sysctl_name = "kern.cp_times";
+ cpu_times_num = appleFreebsdNodeGetCPUCount();
+
+ if (cpuNum >= cpu_times_num) {
+ virReportInvalidArg(cpuNum,
+ _("Invalid cpuNum in %s"),
+ __FUNCTION__);
+ return -1;
+ }
+
+ offset = cpu_times_num * CPUSTATES;
+ }
+
+ cpu_times_size = sizeof(long) * cpu_times_num * CPUSTATES;
+
+ if (VIR_ALLOC_N(cpu_times, cpu_times_num * CPUSTATES) < 0)
+ goto cleanup;
+
+ if (sysctlbyname(sysctl_name, cpu_times, &cpu_times_size, NULL, 0) < 0) {
+ virReportSystemError(errno,
+ _("sysctl failed for '%s'"),
+ sysctl_name);
+ goto cleanup;
+ }
+
+ for (i = 0; cpu_map[i].field != NULL; i++) {
+ virNodeCPUStatsPtr param = ¶ms[i];
+
+ if (virStrcpyStatic(param->field, cpu_map[i].field) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Field '%s' too long for destination"),
+ cpu_map[i].field);
+ goto cleanup;
+ }
+
+ param->value = 0;
+ for (j = 0; j < ARRAY_CARDINALITY(cpu_map[i].idx); j++)
+ param->value += cpu_times[offset + cpu_map[i].idx[j]] * TICK_TO_NSEC;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(cpu_times);
+
+ return ret;
+}
+
static int
freebsdNodeGetMemoryStats(virNodeMemoryStatsPtr params,
int *nparams)
@@ -1066,6 +1168,8 @@ int nodeGetCPUStats(int cpuNum ATTRIBUTE_UNUSED,
return ret;
}
+#elif defined(__FreeBSD__)
+ return freebsdNodeGetCPUStats(cpuNum, params, nparams);
#else
virReportError(VIR_ERR_NO_SUPPORT, "%s",
_("node CPU stats not implemented on this platform"));
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
index 1d1bb97..ac41177 100644
--- a/tools/virsh-host.c
+++ b/tools/virsh-host.c
@@ -347,9 +347,10 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
unsigned long long sys;
unsigned long long idle;
unsigned long long iowait;
+ unsigned long long intr;
unsigned long long util;
} cpu_stats[2];
- double user_time, sys_time, idle_time, iowait_time, total_time;
+ double user_time, sys_time, idle_time, iowait_time, intr_time, total_time;
double usage;
if (vshCommandOptInt(cmd, "cpu", &cpuNum) < 0) {
@@ -390,6 +391,8 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
cpu_stats[i].idle = value;
} else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IOWAIT)) {
cpu_stats[i].iowait = value;
+ } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_INTR)) {
+ cpu_stats[i].intr = value;
} else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_UTILIZATION)) {
cpu_stats[i].util = value;
flag_utilization = true;
@@ -406,6 +409,7 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
vshPrint(ctl, "%-15s %20llu\n", _("system:"), cpu_stats[0].sys);
vshPrint(ctl, "%-15s %20llu\n", _("idle:"), cpu_stats[0].idle);
vshPrint(ctl, "%-15s %20llu\n", _("iowait:"), cpu_stats[0].iowait);
+ vshPrint(ctl, "%-15s %20llu\n", _("intr:"), cpu_stats[0].intr);
}
} else {
if (flag_utilization) {
@@ -418,7 +422,8 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
sys_time = cpu_stats[1].sys - cpu_stats[0].sys;
idle_time = cpu_stats[1].idle - cpu_stats[0].idle;
iowait_time = cpu_stats[1].iowait - cpu_stats[0].iowait;
- total_time = user_time + sys_time + idle_time + iowait_time;
+ intr_time = cpu_stats[1].intr - cpu_stats[0].intr;
+ total_time = user_time + sys_time + idle_time + iowait_time + intr_time;
usage = (user_time + sys_time) / total_time * 100;
@@ -432,6 +437,8 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
_("idle:"), idle_time / total_time * 100);
vshPrint(ctl, "%-15s %5.1lf%%\n",
_("iowait:"), iowait_time / total_time * 100);
+ vshPrint(ctl, "%-15s %5.1lf%%\n",
+ _("intr:"), intr_time / total_time * 100);
}
}
--
1.8.4.3
10 years, 10 months
[libvirt] [PATCH v2] bhyve: add a basic driver
by Roman Bogorodskiy
At this point it has a limited functionality and is highly
experimental. Supported domain operations are:
* define
* start
* destroy
It's only possible to have only one disk device and only one
network, which should be of type bridge.
---
configure.ac | 37 ++++
daemon/libvirtd.c | 9 +
include/libvirt/virterror.h | 1 +
po/POTFILES.in | 2 +
src/Makefile.am | 35 +++
src/bhyve/bhyve_driver.c | 514 ++++++++++++++++++++++++++++++++++++++++++++
src/bhyve/bhyve_driver.h | 28 +++
src/bhyve/bhyve_process.c | 393 +++++++++++++++++++++++++++++++++
src/bhyve/bhyve_process.h | 36 ++++
src/bhyve/bhyve_utils.h | 48 +++++
src/conf/domain_conf.c | 3 +-
src/conf/domain_conf.h | 1 +
src/driver.h | 1 +
src/libvirt.c | 3 +
src/util/virerror.c | 1 +
15 files changed, 1111 insertions(+), 1 deletion(-)
create mode 100644 src/bhyve/bhyve_driver.c
create mode 100644 src/bhyve/bhyve_driver.h
create mode 100644 src/bhyve/bhyve_process.c
create mode 100644 src/bhyve/bhyve_process.h
create mode 100644 src/bhyve/bhyve_utils.h
diff --git a/configure.ac b/configure.ac
index 2622dfd..edfe7d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -504,6 +504,10 @@ AC_ARG_WITH([parallels],
[AS_HELP_STRING([--with-parallels],
[add Parallels Cloud Server support @<:@default=check@:>@])])
m4_divert_text([DEFAULTS], [with_parallels=check])
+AC_ARG_WITH([bhyve],
+ [AS_HELP_STRING([--with-bhyve],
+ [add BHyVe support @<:@default=check@:>@])])
+m4_divert_text([DEFAULTS], [with_bhyve=check])
AC_ARG_WITH([test],
[AS_HELP_STRING([--with-test],
[add test driver support @<:@default=yes@:>@])])
@@ -1011,6 +1015,38 @@ fi
AM_CONDITIONAL([WITH_PARALLELS], [test "$with_parallels" = "yes"])
dnl
+dnl Checks for bhyve driver
+dnl
+
+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"])
+
+dnl
dnl check for shell that understands <> redirection without truncation,
dnl needed by src/qemu/qemu_monitor_{text,json}.c.
dnl
@@ -2582,6 +2618,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])
+AC_MSG_NOTICE([ Bhyve: $with_bhyve])
AC_MSG_NOTICE([ Test: $with_test])
AC_MSG_NOTICE([ Remote: $with_remote])
AC_MSG_NOTICE([ Network: $with_network])
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 49c42ad..b27c6fd 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -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
}
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index e31e9c4..7915bbb 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -121,6 +121,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
# endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 49dfc9c..b4f463b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,6 +8,8 @@ gnulib/lib/gai_strerror.c
gnulib/lib/regcomp.c
src/access/viraccessdriverpolkit.c
src/access/viraccessmanager.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
diff --git a/src/Makefile.am b/src/Makefile.am
index 57e163f..718bef4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -772,6 +772,13 @@ PARALLELS_DRIVER_SOURCES = \
parallels/parallels_storage.c \
parallels/parallels_network.c
+BHYVE_DRIVER_SOURCES = \
+ bhyve/bhyve_driver.h \
+ bhyve/bhyve_driver.c \
+ bhyve/bhyve_process.c \
+ bhyve/bhyve_process.h \
+ bhyve/bhyve_utils.h
+
NETWORK_DRIVER_SOURCES = \
network/bridge_driver.h network/bridge_driver.c \
network/bridge_driver_platform.h \
@@ -1308,6 +1315,33 @@ 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/conf \
+ $(AM_CFLAGS)
+libvirt_driver_bhyve_impl_la_LDFLAGS = $(AM_LDFLAGS)
+
+
+
+#noinst_LTLIBRARIES += libvirt_driver_bhyve.la
+#libvirt_la_BUILT_LIBADD += libvirt_driver_bhyve.la
+#libvirt_driver_bhyve_la_CFLAGS = \
+# -I$(top_srcdir)/src/conf $(AM_CFLAGS)
+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 +1676,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) \
diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c
new file mode 100644
index 0000000..ba62d1a
--- /dev/null
+++ b/src/bhyve/bhyve_driver.c
@@ -0,0 +1,514 @@
+/*
+ * bhyve_driver.c: core driver methods for managing bhyve guests
+ *
+ * Copyright (C) 2013 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 "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 "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;
+
+ bhyveDriverLock(privconn);
+ if ((xml = virCapabilitiesFormatXML(privconn->caps)) == NULL)
+ virReportOOMError();
+ bhyveDriverUnlock(privconn);
+
+ 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)
+ return VIR_DRV_OPEN_DECLINED;
+
+ 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;
+ }
+
+ conn->privateData = bhyve_driver;
+
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+static int
+bhyveConnectClose(virConnectPtr conn)
+{
+ bhyveConnPtr privconn = conn->privateData;
+
+ bhyveDriverLock(privconn);
+ virObjectUnref(privconn->caps);
+ virObjectUnref(privconn->xmlopt);
+ virObjectUnref(privconn->domains);
+ conn->privateData = NULL;
+
+ bhyveDriverUnlock(privconn);
+ virMutexDestroy(&privconn->lock);
+
+ VIR_FREE(privconn);
+ return 0;
+}
+
+static char *
+bhyveConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return virGetHostname();
+}
+
+static int
+bhyveConnectGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *hvVer)
+{
+ if (virParseVersionString("0.0.1", hvVer, true) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+bhyveDomainGetInfo(virDomainPtr domain ATTRIBUTE_UNUSED, virDomainInfoPtr info ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static virDomainPtr
+bhyveDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+ bhyveConnPtr privconn = conn->privateData;
+ virDomainPtr dom = NULL;
+ virDomainDefPtr def = NULL;
+ virDomainDefPtr oldDef = NULL;
+ virDomainObjPtr vm = NULL;
+
+ bhyveDriverLock(privconn);
+
+ if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
+ 1 << VIR_DOMAIN_VIRT_BHYVE,
+ VIR_DOMAIN_XML_INACTIVE)) == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Can't parse XML desc"));
+ goto cleanup;
+ }
+
+ if (!(vm = virDomainObjListAdd(privconn->domains, def,
+ privconn->xmlopt,
+ 0, &oldDef)))
+ goto cleanup;
+
+ VIR_INFO("Creating domain '%s'", vm->def->name);
+ 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);
+ if (vm)
+ virObjectUnlock(vm);
+
+ bhyveDriverUnlock(privconn);
+ return dom;
+}
+
+static int
+bhyveConnectListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+ bhyveConnPtr privconn = conn->privateData;
+ int n;
+
+ n = virDomainObjListGetActiveIDs(privconn->domains, ids, maxids,
+ NULL, NULL);
+
+ return n;
+}
+
+static int
+bhyveConnectNumOfDomains(virConnectPtr conn)
+{
+ bhyveConnPtr privconn = conn->privateData;
+ int count;
+
+ count = virDomainObjListNumOfDomains(privconn->domains, true,
+ NULL, NULL);
+
+ return count;
+}
+
+static int
+bhyveConnectListDefinedDomains(virConnectPtr conn, char **const names,
+ int maxnames)
+{
+ bhyveConnPtr privconn = conn->privateData;
+ int n;
+
+ memset(names, 0, sizeof(*names) * maxnames);
+ n = virDomainObjListGetInactiveNames(privconn->domains, names,
+ maxnames, NULL, NULL);
+
+ return n;
+}
+
+static int
+bhyveConnectNumOfDefinedDomains(virConnectPtr conn)
+{
+ bhyveConnPtr privconn = conn->privateData;
+ int count;
+
+ count = virDomainObjListNumOfDomains(privconn->domains, false,
+ NULL, NULL);
+
+ 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);
+
+ ret = virDomainObjListExport(privconn->domains, conn, domains,
+ NULL, 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;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+cleanup:
+ if (vm)
+ 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;
+ }
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+cleanup:
+ if (vm)
+ 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 (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:
+ if (vm)
+ 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;
+
+ ret = virBhyveProcessStop(privconn, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
+
+cleanup:
+ if (vm)
+ virObjectUnlock(vm);
+ return ret;
+}
+
+static int
+bhyveStateCleanup(void)
+{
+ VIR_INFO("bhyve state cleanup");
+
+ if (bhyve_driver == NULL)
+ return -1;
+
+ virObjectUnref(bhyve_driver->domains);
+
+ 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,
+ .connectClose = bhyveConnectClose,
+ .connectGetVersion = bhyveConnectGetVersion,
+ .connectGetHostname = bhyveConnectGetHostname,
+ .domainGetInfo = bhyveDomainGetInfo,
+ .connectGetCapabilities = bhyveConnectGetCapabilities,
+ .connectListDomains = bhyveConnectListDomains,
+ .connectNumOfDomains = bhyveConnectNumOfDomains,
+ .connectListAllDomains = bhyveConnectListAllDomains,
+ .connectListDefinedDomains = bhyveConnectListDefinedDomains,
+ .connectNumOfDefinedDomains = bhyveConnectNumOfDefinedDomains,
+ .domainCreate = bhyveDomainCreate,
+ .domainDestroy = bhyveDomainDestroy,
+ .domainLookupByUUID = bhyveDomainLookupByUUID,
+ .domainLookupByName = bhyveDomainLookupByName,
+ .domainDefineXML = bhyveDomainDefineXML,
+};
+
+
+static virStateDriver bhyveStateDriver = {
+ .name= "bhyve",
+ .stateInitialize = bhyveStateInitialize,
+ .stateCleanup = bhyveStateCleanup,
+};
+
+int
+bhyveRegister(void)
+{
+ virRegisterDriver(&bhyveDriver);
+ virRegisterStateDriver(&bhyveStateDriver);
+ return 0;
+}
diff --git a/src/bhyve/bhyve_driver.h b/src/bhyve/bhyve_driver.h
new file mode 100644
index 0000000..ffe91e5
--- /dev/null
+++ b/src/bhyve/bhyve_driver.h
@@ -0,0 +1,28 @@
+/*
+ * bhyve_driver.h: core driver methods for managing bhyve guests
+ *
+ * Copyright (C) 2013 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(a)gmail.com>
+ */
+
+#ifndef __BHYVE_DRIVER_H__
+# define __BHYVE_DRIVER_H__
+
+int bhyveRegister(void);
+
+#endif /* __BHYVE_DRIVER_H__ */
diff --git a/src/bhyve/bhyve_process.c b/src/bhyve/bhyve_process.c
new file mode 100644
index 0000000..d481d58
--- /dev/null
+++ b/src/bhyve/bhyve_process.c
@@ -0,0 +1,393 @@
+/*
+ * bhyve_process.c: bhyve process management
+ *
+ * Copyright (C) 2013 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_process.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
+
+static char*
+virTapGetRealDeviceName(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 too 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) {
+ 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)
+ goto cleanup;
+
+ if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0)
+ 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);
+ }
+ }
+
+cleanup:
+ VIR_FREE(devpath);
+ VIR_FORCE_CLOSE(fd);
+ closedir(dirp);
+ return ret;
+}
+
+static virCommandPtr
+virBhyveProcessBuildDestroyCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm)
+{
+ virCommandPtr cmd = virCommandNew(BHYVECTL);
+
+ virCommandAddArg(cmd, "--destroy");
+ virCommandAddArgPair(cmd, "--vm", vm->def->name);
+
+ return cmd;
+}
+
+static virCommandPtr
+virBhyveProcessBuildLoadCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm)
+{
+ virCommandPtr cmd;
+ virDomainDiskDefPtr disk = vm->def->disks[0];
+
+ cmd = virCommandNew(BHYVELOAD);
+
+ /* Memory */
+ virCommandAddArg(cmd, "-m");
+ virCommandAddArgFormat(cmd, "%llu",
+ VIR_DIV_UP(vm->def->mem.max_balloon, 1024));
+
+ /* Image path */
+ virCommandAddArg(cmd, "-d");
+ virCommandAddArgFormat(cmd, disk->src);
+
+ /* VM name */
+ virCommandAddArg(cmd, vm->def->name);
+
+ return cmd;
+}
+
+static 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 = NULL;
+ virDomainDiskDefPtr disk = vm->def->disks[0];
+ virDomainNetDefPtr net = NULL;
+ char *brname = NULL;
+ char *realifname = NULL;
+ int *tapfd = NULL;
+
+ if (vm->def->nnets > 1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Domain should have one and only one disk defined"));
+ return NULL;
+ } else if (vm->def->nnets == 1)
+ net = vm->def->nets[0];
+
+ if (net != NULL) {
+ int actualType = virDomainNetGetActualType(net);
+
+ if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+ if (VIR_STRDUP(brname, virDomainNetGetActualBridgeName(net)) < 0)
+ return NULL;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Network type %d is not supported"),
+ virDomainNetGetActualType(net));
+ return NULL;
+ }
+
+ 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 NULL;
+ }
+ }
+
+ if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
+ vm->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 NULL;
+ }
+ }
+
+ realifname = virTapGetRealDeviceName(net->ifname);
+
+ if (realifname == NULL) {
+ VIR_FREE(net->ifname);
+ VIR_FREE(brname);
+ return NULL;
+ }
+
+ VIR_INFO("%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 NULL;
+ }
+
+ 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 */
+ virCommandAddArg(cmd, "-A"); /* Create an ACPI table */
+ virCommandAddArg(cmd, "-I"); /* Present ioapic to the guest */
+ virCommandAddArg(cmd, "-H"); /* vmexit from guest on hlt */
+ virCommandAddArg(cmd, "-P"); /* vmexit from guest on pause */
+
+ /* Devices */
+ virCommandAddArg(cmd, "-s");
+ virCommandAddArg(cmd, "0:0,hostbridge");
+ virCommandAddArg(cmd, "-s");
+ virCommandAddArgFormat(cmd, "1:0,virtio-net,%s", realifname);
+ virCommandAddArg(cmd, "-s");
+ virCommandAddArgFormat(cmd, "2:0,ahci-hd,%s", disk->src);
+ virCommandAddArg(cmd, "-S");
+ virCommandAddArg(cmd, "31,uart");
+ virCommandAddArg(cmd, vm->def->name);
+
+ return cmd;
+}
+
+int
+virBhyveProcessStart(virConnectPtr conn,
+ bhyveConnPtr driver,
+ virDomainObjPtr vm,
+ virDomainRunningReason reason ATTRIBUTE_UNUSED)
+{
+ char *logfile = NULL;
+ int logfd = -1;
+ off_t pos = -1;
+ char ebuf[1024];
+ virCommandPtr cmd = NULL;
+ bhyveConnPtr privconn = conn->privateData;
+ int ret = -1, status;
+
+ if (vm->def->ndisks != 1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Domain should have one and only one disk defined"));
+ return -1;
+ }
+
+ 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;
+ }
+
+ /* Call bhyveload to load a VM */
+ if (!(cmd = virBhyveProcessBuildLoadCmd(driver,
+ vm)))
+ goto cleanup;
+ virCommandSetOutputFD(cmd, &logfd);
+ virCommandSetErrorFD(cmd, &logfd);
+
+ /* Log generated command line */
+ virCommandWriteArgLog(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_INFO("Loading domain '%s'", vm->def->name);
+ if (virCommandRun(cmd, &status) < 0)
+ goto cleanup;
+
+ if (status != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Guest failed to load: %d"), status);
+ goto cleanup;
+ }
+
+ virCommandFree(cmd);
+
+ 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);
+
+ VIR_INFO("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;
+ }
+ } else {
+ goto cleanup;
+ }
+
+cleanup:
+ VIR_FREE(logfile);
+ return ret;
+}
+
+int
+virBhyveProcessStop(bhyveConnPtr driver,
+ virDomainObjPtr vm,
+ virDomainShutoffReason reason ATTRIBUTE_UNUSED)
+{
+ size_t i;
+ int ret = -1;
+ int status;
+ virCommandPtr cmd = NULL;
+
+ /* First, try to kill 'bhyve' process */
+ if (virProcessKillPainfully(vm->pid, true) != 0)
+ VIR_WARN("Failed to gracefully stop bhyve VM '%s' (pid: %llu)",
+ vm->def->name,
+ (unsigned long long)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;
+
+cleanup:
+ virCommandFree(cmd);
+ return ret;
+}
diff --git a/src/bhyve/bhyve_process.h b/src/bhyve/bhyve_process.h
new file mode 100644
index 0000000..70afe0e
--- /dev/null
+++ b/src/bhyve/bhyve_process.h
@@ -0,0 +1,36 @@
+/*
+ * bhyve_process.h: bhyve process management
+ *
+ * Copyright (C) 2013 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__ */
diff --git a/src/bhyve/bhyve_utils.h b/src/bhyve/bhyve_utils.h
new file mode 100644
index 0000000..ed503cd
--- /dev/null
+++ b/src/bhyve/bhyve_utils.h
@@ -0,0 +1,48 @@
+/*
+ * bhyve_utils.h: bhyve utils
+ *
+ * Copyright (C) 2013 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__ */
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e65f3e3..928f5f5 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -122,7 +122,8 @@ VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
"hyperv",
"vbox",
"phyp",
- "parallels")
+ "parallels",
+ "bhyve")
VIR_ENUM_IMPL(virDomainBoot, VIR_DOMAIN_BOOT_LAST,
"fd",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 647d115..c82f598 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -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
};
diff --git a/src/driver.h b/src/driver.h
index b6927ea..556f91f 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -46,6 +46,7 @@ typedef enum {
VIR_DRV_LIBXL = 14,
VIR_DRV_HYPERV = 15,
VIR_DRV_PARALLELS = 16,
+ VIR_DRV_BHYVE = 17,
} virDrvNo;
diff --git a/src/libvirt.c b/src/libvirt.c
index b14af7e..b493f78 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -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
diff --git a/src/util/virerror.c b/src/util/virerror.c
index d9a9fc4..8f4d1c1 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -124,6 +124,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"Access Manager", /* 55 */
"Systemd",
+ "Bhyve",
)
--
1.8.3.2
10 years, 10 months
[libvirt] ANNOUNCE: libvirt 1.1.3.3 maintenance release
by Cole Robinson
libvirt 1.1.3.3 maintenance release is now available. This is
libvirt 1.1.3 with additional bugfixes that have accumulated
upstream since the initial release.
This release can be downloaded at:
http://libvirt.org/sources/stable_updates/libvirt-1.1.3.3.tar.gz
Changes in this version:
* virt-login-shell: fix regressions in behavior
* Fix race leading to crash when setting up dbus watches
* event: filter global events by domain:getattr ACL [CVE-2014-0028]
* Fix memory leak in virObjectEventCallbackListRemoveID()
* virDomainEventCallbackListFree: Don't leak @list->callbacks
* Really don't crash if a connection closes early
* Don't crash if a connection closes early
* qemu: Fix job usage in virDomainGetBlockIoTune
* qemu: Fix job usage in qemuDomainBlockCopy
* qemu: Fix job usage in qemuDomainBlockJobImpl
* qemu: Avoid using stale data in virDomainGetBlockInfo
* qemu: Do not access stale data in virDomainBlockStats
* qemu: clean up migration ports when migration cancelled
* qemu: Fix augeas support for migration ports
* qemu: Make migration port range configurable
* qemu: Avoid assigning unavailable migration ports
* libxl: avoid crashing if calling `virsh numatune' on inactive domain
* Fix crash in lxcDomainSetMemoryParameters
* CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
For info about past maintenance releases, see:
http://wiki.libvirt.org/page/Maintenance_Releases
Thanks,
Cole
10 years, 10 months
[libvirt] ANNOUNCE: libvirt 1.0.5.9 maintenance release
by Cole Robinson
libvirt 1.0.5.9 maintenance release is now available. This is
libvirt 1.0.5 with additional bugfixes that have accumulated
upstream since the initial release.
This release can be downloaded at:
http://libvirt.org/sources/stable_updates/libvirt-1.0.5.9.tar.gz
Changes in this version:
* Fix race leading to crash when setting up dbus watches
* Really don't crash if a connection closes early
* Don't crash if a connection closes early
* qemu: Fix job usage in virDomainGetBlockIoTune
* qemu: Fix job usage in qemuDomainBlockCopy
* qemu: Fix job usage in qemuDomainBlockJobImpl
* qemu: Avoid using stale data in virDomainGetBlockInfo
* qemu: Do not access stale data in virDomainBlockStats
* tests: be more explicit on qcow2 versions in virstoragetest
* qemu: clean up migration ports when migration cancelled
* qemu: Fix augeas support for migration ports
* qemu: Make migration port range configurable
* qemu: Avoid assigning unavailable migration ports
* Don't spam logs with "port 0 must be in range" errors
* Fix crash in lxcDomainSetMemoryParameters
* CVE-2013-6436: fix crash in lxcDomainGetMemoryParameters
For info about past maintenance releases, see:
http://wiki.libvirt.org/page/Maintenance_Releases
Thanks,
Cole
10 years, 10 months
[libvirt] ANNOUNCE: libvirt 0.9.12.3 maintenance release
by Guido Günther
libvirt 0.9.12.3 maintenance release is now available. This is libvirt
0.9.12 with additional bugfixes that have accumulated upstream since the
initial release. It fixes CVE-2013-6458 and CVE-2014-1447.
This release can be downloaded at:
http://libvirt.org/sources/stable_updates/libvirt-0.9.12.3.tar.gz
md5sum: 0f596bceec120df4cd5aecb8f0128d5d libvirt-0.9.12.3.tar.gz
sha1: 73e72812a3d3c1a096b515dc01803bdbff7c595a libvirt-0.9.12.3.tar.gz
sha256: 404afb7fdd23d8f36645cffc77fecfed40d60617f8bcae707ac3b9f7925fc0fb libvirt-0.9.12.3.tar.gz
Changes in this release:
Prepare for 0.9.12.3 (Guido Günther)
Really don't crash if a connection closes early (Jiri Denemark)
Don't crash if a connection closes early (Jiri Denemark)
qemu: Fix job usage in virDomainGetBlockIoTune (Jiri Denemark)
qemu: Fix job usage in qemuDomainBlockJobImpl (Jiri Denemark)
qemu: Avoid using stale data in virDomainGetBlockInfo (Jiri Denemark)
qemu: Do not access stale data in virDomainBlockStats (Jiri Denemark)
Introduce virReportError macro for general error reporting (Daniel P. Berrange)
string: test VIR_STRDUP (Eric Blake)
string: make VIR_STRDUP easier to use (Eric Blake)
virstring: Introduce VIR_STRDUP and VIR_STRNDUP (Michal Privoznik)
remote: fix regression in event deregistration (Zhou Yimin)
For info about past maintenance releases, see:
http://wiki.libvirt.org/page/Maintenance_Releases
Cheers,
-- Guido
10 years, 10 months
[libvirt] [libvirt-glib] config: Fix typo preventing clock removal from a domain
by Christophe Fergeau
Commit 1c8ce29 added a way to unset a GVirConfigDomainClock set on a
GVirConfigDomain by calling gvir_config_domain_set_clock() with a NULL
argument.
However, a typo in a g_return_if_fail precondition prevents this code from
ever being called: g_return_if_fail(clock != NULL) is used while it should
have been g_return_if_fail(clock == NULL) as in all other preconditions in
1c8ce29.
---
libvirt-gconfig/libvirt-gconfig-domain.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libvirt-gconfig/libvirt-gconfig-domain.c b/libvirt-gconfig/libvirt-gconfig-domain.c
index 3c28a4a..6cd2f86 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain.c
@@ -552,7 +552,7 @@ void gvir_config_domain_set_clock(GVirConfigDomain *domain,
GVirConfigDomainClock *klock)
{
g_return_if_fail(GVIR_CONFIG_IS_DOMAIN(domain));
- g_return_if_fail(klock != NULL || GVIR_CONFIG_IS_DOMAIN_CLOCK(klock));
+ g_return_if_fail(klock == NULL || GVIR_CONFIG_IS_DOMAIN_CLOCK(klock));
gvir_config_object_attach_replace(GVIR_CONFIG_OBJECT(domain),
"clock",
--
1.8.4.2
10 years, 10 months
[libvirt] [PATCHv2 0/6] remaining cleanups to libvirt.c
by Eric Blake
v2 of my patch series started here, after applying all patches
already reviewed in that thread:
https://www.redhat.com/archives/libvir-list/2013-December/msg01284.html
Patches 1-3 can be considered bug fixes (particularly patch 3),
so I'd like them in 1.2.1 if they get a favorable review. Patches
4-6 are less urgent, but might as well finish the work all within
one release.
Patch 1 comes from 5/24 in v1
Patch 2 is new
Patch 3 and 4 come from 23/24 in v1
Patch 5 is new
Patch 6 comes from 24/24 in v1
Eric Blake (6):
maint: don't leave garbage on early API exit
maint: avoid nested use of virConnect{Ref,Close}
maint: don't lose error on canceled migration
maint: clean up error reporting in migration
maint: simplify driver registration at startup
maint: replace remaining virLib*Error with better names
cfg.mk | 10 --
src/libvirt.c | 397 ++++++++++++++++++++-----------------------
src/lxc/lxc_process.c | 11 +-
src/qemu/qemu_driver.c | 12 +-
src/qemu/qemu_migration.c | 14 +-
src/qemu/qemu_process.c | 10 +-
src/storage/storage_driver.c | 5 +-
src/uml/uml_driver.c | 3 +-
8 files changed, 209 insertions(+), 253 deletions(-)
--
1.8.4.2
10 years, 10 months