Add a new xen driver based on libxenlight [1], which is the primary
toolstack starting with Xen 4.1.0. The driver is stateful and runs
privileged only.
Like the existing xen-unified driver, the libxenlight driver is
accessed with xen:// URI. Driver selection is based on the status
of xend. If xend is running, the libxenlight driver will not load
and xen:// connections are handled by xen-unified. If xend is not
running *and* the libxenlight driver is available, xen://
connections are deferred to the libxenlight driver.
V6:
- Address several code style issues noted by Daniel Veillard
- Make drive work with xen:/// URI
- Hold domain object reference while domain is injected in
libvirt event loop. Race found and fixed by Markus Groß.
V5:
- Ensure events are unregistered when domain private data
is destroyed. Discovered and fixed by Markus Groß.
V4:
- Handle restart of libvirtd, reconnecting to previously
started domains
- Rebased to current master
- Tested against Xen 4.1 RC7-pre (c/s 22961:c5d121fd35c0)
V3:
- Reserve vnc port within driver when autoport=yes
V2:
- Update to Xen 4.1 RC6-pre (c/s 22940:5a4710640f81)
- Rebased to current master
- Plug memory leaks found by Stefano Stabellini and valgrind
- Handle SHUTDOWN_crash domain death event
[1]
http://lists.xensource.com/archives/html/xen-devel/2009-11/msg00436.html
---
cfg.mk | 1 +
configure.ac | 48 ++
daemon/Makefile.am | 4 +
daemon/libvirtd.c | 6 +
include/libvirt/virterror.h | 1 +
libvirt.spec.in | 15 +-
po/POTFILES.in | 2 +
src/Makefile.am | 32 +
src/driver.h | 3 +-
src/libvirt.c | 4 +
src/libxl/libxl_conf.c | 898 ++++++++++++++++++++++++++
src/libxl/libxl_conf.h | 91 +++
src/libxl/libxl_driver.c | 1457 +++++++++++++++++++++++++++++++++++++++++++
src/libxl/libxl_driver.h | 27 +
src/util/virterror.c | 3 +
src/xen/xen_driver.c | 28 +
16 files changed, 2618 insertions(+), 2 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index c12f199..2076173 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -403,6 +403,7 @@ msg_gen_function += virXenStoreError
msg_gen_function += virXendError
msg_gen_function += vmwareError
msg_gen_function += xenapiSessionErrorHandler
+msg_gen_function += libxlError
msg_gen_function += xenUnifiedError
msg_gen_function += xenXMError
msg_gen_function += VIR_ERROR
diff --git a/configure.ac b/configure.ac
index e2b2b24..9d8862c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -263,6 +263,8 @@ AC_ARG_WITH([phyp],
AC_HELP_STRING([--with-phyp], [add PHYP support
@<:@default=check@:>@]),[],[with_phyp=check])
AC_ARG_WITH([xenapi],
AC_HELP_STRING([--with-xenapi], [add XenAPI support
@<:@default=check@:>@]),[],[with_xenapi=check])
+AC_ARG_WITH([libxl],
+ AC_HELP_STRING([--with-libxl], [add libxenlight support
@<:@default=check@:>@]),[],[with_libxl=check])
AC_ARG_WITH([vbox],
AC_HELP_STRING([--with-vbox=@<:@PFX@:>@],
[VirtualBox XPCOMC location @<:@default=yes@:>@]),[],
@@ -497,6 +499,46 @@ fi
AC_SUBST([LIBXENSERVER_CFLAGS])
AC_SUBST([LIBXENSERVER_LIBS])
+old_LIBS="$LIBS"
+old_CFLAGS="$CFLAGS"
+LIBXL_LIBS=""
+LIBXL_CFLAGS=""
+dnl search for libxl, aka libxenlight
+fail=0
+if test "$with_libxl" != "no" ; then
+ if test "$with_libxl" != "yes" && test
"$with_libxl" != "check" ; then
+ LIBXL_CFLAGS="-I$with_libxl/include"
+ LIBXL_LIBS="-L$with_libxl"
+ fi
+ CFLAGS="$CFLAGS $LIBXL_CFLAGS"
+ LIBS="$LIBS $LIBXL_LIBS"
+ AC_CHECK_LIB([xenlight], [libxl_ctx_init], [
+ with_libxl=yes
+ LIBXL_LIBS="$LIBXL_LIBS -lxenlight -lxenstore -lxenctrl -lxenguest -luuid
-lutil -lblktapctl"
+ ],[
+ if test "$with_libxl" = "yes"; then
+ fail=1
+ fi
+ with_libxl=no
+ ],[
+ -lxenstore -lxenctrl -lxenguest -luuid -lutil -lblktapctl
+ ])
+fi
+
+LIBS="$old_LIBS"
+CFLAGS="$old_CFLAGS"
+
+if test $fail = 1; then
+ AC_MSG_ERROR([You must install the libxl Library to compile libxenlight driver with
-lxl])
+fi
+
+if test "$with_libxl" = "yes"; then
+ AC_DEFINE_UNQUOTED([WITH_LIBXL], 1, [whether libxenlight driver is enabled])
+fi
+AM_CONDITIONAL([WITH_LIBXL], [test "$with_libxl" = "yes"])
+
+AC_SUBST([LIBXL_CFLAGS])
+AC_SUBST([LIBXL_LIBS])
old_LIBS="$LIBS"
old_CFLAGS="$CFLAGS"
@@ -2370,6 +2412,7 @@ AC_MSG_NOTICE([ OpenVZ: $with_openvz])
AC_MSG_NOTICE([ VMware: $with_vmware])
AC_MSG_NOTICE([ VBox: $with_vbox])
AC_MSG_NOTICE([ XenAPI: $with_xenapi])
+AC_MSG_NOTICE([xenlight: $with_libxl])
AC_MSG_NOTICE([ LXC: $with_lxc])
AC_MSG_NOTICE([ PHYP: $with_phyp])
AC_MSG_NOTICE([ ONE: $with_one])
@@ -2479,6 +2522,11 @@ AC_MSG_NOTICE([ xenapi: $LIBXENSERVER_CFLAGS $LIBXENSERVER_LIBS])
else
AC_MSG_NOTICE([ xenapi: no])
fi
+if test "$with_libxl" = "yes" ; then
+AC_MSG_NOTICE([ libxenlight: $LIBXL_CFLAGS $LIBXL_LIBS])
+else
+AC_MSG_NOTICE([ libxenlight: no])
+fi
if test "$with_hal" = "yes" ; then
AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS])
else
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 15e8129..9e3a557 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -106,6 +106,10 @@ if WITH_LXC
libvirtd_LDADD += ../src/libvirt_driver_lxc.la
endif
+if WITH_LIBXL
+ libvirtd_LDADD += ../src/libvirt_driver_libxl.la
+endif
+
if WITH_UML
libvirtd_LDADD += ../src/libvirt_driver_uml.la
endif
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index dc6fab4..7818316 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -81,6 +81,9 @@
# ifdef WITH_LXC
# include "lxc/lxc_driver.h"
# endif
+# ifdef WITH_LIBXL
+# include "libxl/libxl_driver.h"
+# endif
# ifdef WITH_UML
# include "uml/uml_driver.h"
# endif
@@ -943,6 +946,9 @@ static struct qemud_server *qemudInitialize(void) {
# ifdef WITH_NWFILTER
nwfilterRegister();
# endif
+# ifdef WITH_LIBXL
+ libxlRegister();
+# endif
# ifdef WITH_QEMU
qemuRegister();
# endif
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 6b8c789..1d8275b 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -80,6 +80,7 @@ typedef enum {
VIR_FROM_STREAMS = 38, /* Error from I/O streams */
VIR_FROM_VMWARE = 39, /* Error from VMware driver */
VIR_FROM_EVENT = 40, /* Error from event loop impl */
+ VIR_FROM_LIBXL = 41, /* Error from libxenlight driver */
} virErrorDomain;
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 1946a15..988ea4e 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -45,6 +45,7 @@
%define with_vbox 0%{!?_without_vbox:%{server_drivers}}
%define with_uml 0%{!?_without_uml:%{server_drivers}}
%define with_xenapi 0%{!?_without_xenapi:%{server_drivers}}
+%define with_libxl 0%{!?_without_libxl:%{server_drivers}}
# XXX this shouldn't be here, but it mistakenly links into libvirtd
%define with_one 0%{!?_without_one:%{server_drivers}}
@@ -96,7 +97,7 @@
%endif
# RHEL doesn't ship OpenVZ, VBox, UML, OpenNebula, PowerHypervisor,
-# VMWare, or libxenserver (xenapi)
+# VMWare, libxenserver (xenapi), or libxenlight (Xen 4.1 and newer)
%if 0%{?rhel}
%define with_openvz 0
%define with_vbox 0
@@ -105,6 +106,7 @@
%define with_phyp 0
%define with_vmware 0
%define with_xenapi 0
+%define with_libxl 0
%endif
# RHEL-5 has restricted QEMU to x86_64 only and is too old for LXC
@@ -493,6 +495,10 @@ of recent versions of Linux (and other OSes).
%define _without_xenapi --without-xenapi
%endif
+%if ! %{with_libxl}
+%define _without_libxl --without-libxl
+%endif
+
%if ! %{with_sasl}
%define _without_sasl --without-sasl
%endif
@@ -872,6 +878,9 @@ fi
%dir %attr(0700, root, root) %{_localstatedir}/log/libvirt/qemu/
%dir %attr(0700, root, root) %{_localstatedir}/log/libvirt/lxc/
%dir %attr(0700, root, root) %{_localstatedir}/log/libvirt/uml/
+%if %{with_libxl}
+%dir %attr(0700, root, root) %{_localstatedir}/log/libvirt/libxl/
+%endif
%config(noreplace) %{_sysconfdir}/logrotate.d/libvirtd
%if %{with_qemu}
@@ -912,6 +921,10 @@ fi
%dir %{_localstatedir}/run/libvirt/uml/
%dir %attr(0700, root, root) %{_localstatedir}/lib/libvirt/uml/
%endif
+%if %{with_libxl}
+%dir %{_localstatedir}/run/libvirt/libxl/
+%dir %attr(0700, root, root) %{_localstatedir}/lib/libvirt/libxl/
+%endif
%if %{with_network}
%dir %{_localstatedir}/run/libvirt/network/
%dir %attr(0700, root, root) %{_localstatedir}/lib/libvirt/network/
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1ed2765..4bd2b13 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -34,6 +34,8 @@ src/lxc/lxc_conf.c
src/lxc/lxc_controller.c
src/lxc/lxc_driver.c
src/lxc/veth.c
+src/libxl/libxl_driver.c
+src/libxl/libxl_conf.c
src/network/bridge_driver.c
src/node_device/node_device_driver.c
src/node_device/node_device_hal.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 645119e..c3729a6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -298,6 +298,10 @@ XENAPI_DRIVER_SOURCES = \
xenapi/xenapi_driver_private.h \
xenapi/xenapi_utils.c xenapi/xenapi_utils.h
+LIBXL_DRIVER_SOURCES = \
+ libxl/libxl_conf.c libxl/libxl_conf.h \
+ libxl/libxl_driver.c libxl/libxl_driver.h
+
UML_DRIVER_SOURCES = \
uml/uml_conf.c uml/uml_conf.h \
uml/uml_driver.c uml/uml_driver.h
@@ -692,6 +696,25 @@ endif
libvirt_driver_xenapi_la_SOURCES = $(XENAPI_DRIVER_SOURCES)
endif
+if WITH_LIBXL
+if WITH_DRIVER_MODULES
+mod_LTLIBRARIES += libvirt_driver_libxl.la
+else
+noinst_LTLIBRARIES += libvirt_driver_libxl.la
+# Stateful, so linked to daemon instead
+#libvirt_la_BUILT_LIBADD += libvirt_driver_libxl.la
+endif
+libvirt_driver_libxl_la_CFLAGS = $(LIBXL_CFLAGS) \
+ -I@top_srcdir@/src/conf $(AM_CFLAGS)
+libvirt_driver_libxl_la_LDFLAGS = $(AM_LDFLAGS)
+libvirt_driver_libxl_la_LIBADD = $(LIBXL_LIBS)
+if WITH_DRIVER_MODULES
+libvirt_driver_libxl_la_LIBADD += ../gnulib/lib/libgnu.la
+libvirt_driver_libxl_la_LDFLAGS += -module -avoid-version
+endif
+libvirt_driver_libxl_la_SOURCES = $(LIBXL_DRIVER_SOURCES)
+endif
+
if WITH_QEMU
if WITH_DRIVER_MODULES
mod_LTLIBRARIES += libvirt_driver_qemu.la
@@ -1005,6 +1028,7 @@ EXTRA_DIST += \
$(PHYP_DRIVER_SOURCES) \
$(VBOX_DRIVER_SOURCES) \
$(XENAPI_DRIVER_SOURCES) \
+ $(LIBXL_DRIVER_SOURCES) \
$(ESX_DRIVER_SOURCES) \
$(ESX_DRIVER_EXTRA_DIST) \
$(NETWORK_DRIVER_SOURCES) \
@@ -1259,6 +1283,10 @@ if WITH_LXC
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lxc"
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/lxc"
endif
+if WITH_LIBXL
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/libxl"
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/libxl"
+endif
if WITH_UML
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/uml"
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/uml"
@@ -1296,6 +1324,10 @@ if WITH_LXC
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/lxc" ||:
rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/lxc" ||:
endif
+if WITH_LIBXL
+ rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/libxl" ||:
+ rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/libxl" ||:
+endif
if WITH_UML
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/uml" ||:
rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/uml" ||:
diff --git a/src/driver.h b/src/driver.h
index 6a83325..f03d290 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -27,7 +27,8 @@ typedef enum {
VIR_DRV_ESX = 10,
VIR_DRV_PHYP = 11,
VIR_DRV_XENAPI = 12,
- VIR_DRV_VMWARE = 13
+ VIR_DRV_VMWARE = 13,
+ VIR_DRV_LIBXL = 14,
} virDrvNo;
diff --git a/src/libvirt.c b/src/libvirt.c
index 0ecff74..33bb17c 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -912,6 +912,10 @@ virGetVersion(unsigned long *libVer, const char *type,
if (STRCASEEQ(type, "LXC"))
*typeVer = LIBVIR_VERSION_NUMBER;
# endif
+# if WITH_LIBXL
+ if (STRCASEEQ(type, "xenlight"))
+ *typeVer = LIBVIR_VERSION_NUMBER;
+# endif
# if WITH_PHYP
if (STRCASEEQ(type, "phyp"))
*typeVer = LIBVIR_VERSION_NUMBER;
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
new file mode 100644
index 0000000..9dc35fc
--- /dev/null
+++ b/src/libxl/libxl_conf.c
@@ -0,0 +1,898 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#include <config.h>
+
+#include <regex.h>
+#include <libxl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+
+#include "internal.h"
+#include "logging.h"
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "files.h"
+#include "memory.h"
+#include "uuid.h"
+#include "capabilities.h"
+#include "libxl_driver.h"
+#include "libxl_conf.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_LIBXL
+
+/* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */
+#define LIBXL_X86_FEATURE_PAE_MASK 0x40
+
+
+struct guest_arch {
+ const char *model;
+ int bits;
+ int hvm;
+ int pae;
+ int nonpae;
+ int ia64_be;
+};
+
+static const char *xen_cap_re =
"(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(x86_32|x86_64|ia64|powerpc64)(p|be)?";
+static regex_t xen_cap_rec;
+
+
+static int
+libxlNextFreeVncPort(libxlDriverPrivatePtr driver, int startPort)
+{
+ int i;
+
+ for (i = startPort ; i < LIBXL_VNC_PORT_MAX; i++) {
+ int fd;
+ int reuse = 1;
+ struct sockaddr_in addr;
+ bool used = false;
+
+ if (virBitmapGetBit(driver->reservedVNCPorts,
+ i - LIBXL_VNC_PORT_MIN, &used) < 0)
+ VIR_DEBUG("virBitmapGetBit failed on bit %d", i -
LIBXL_VNC_PORT_MIN);
+
+ if (used)
+ continue;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(i);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ return -1;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse))
< 0) {
+ VIR_FORCE_CLOSE(fd);
+ break;
+ }
+
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
+ /* Not in use, lets grab it */
+ VIR_FORCE_CLOSE(fd);
+ /* Add port to bitmap of reserved ports */
+ if (virBitmapSetBit(driver->reservedVNCPorts,
+ i - LIBXL_VNC_PORT_MIN) < 0) {
+ VIR_DEBUG("virBitmapSetBit failed on bit %d",
+ i - LIBXL_VNC_PORT_MIN);
+ }
+ return i;
+ }
+ VIR_FORCE_CLOSE(fd);
+
+ if (errno == EADDRINUSE) {
+ /* In use, try next */
+ continue;
+ }
+ /* Some other bad failure, get out.. */
+ break;
+ }
+ return -1;
+}
+
+static virCapsPtr
+libxlBuildCapabilities(const char *hostmachine,
+ int host_pae,
+ struct guest_arch *guest_archs,
+ int nr_guest_archs)
+{
+ virCapsPtr caps;
+ int i;
+
+ if ((caps = virCapabilitiesNew(hostmachine, 1, 1)) == NULL)
+ goto no_memory;
+
+ virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x00, 0x16, 0x3e });
+
+ if (host_pae &&
+ virCapabilitiesAddHostFeature(caps, "pae") < 0)
+ goto no_memory;
+
+ for (i = 0; i < nr_guest_archs; ++i) {
+ virCapsGuestPtr guest;
+ char const *const xen_machines[] = {guest_archs[i].hvm ? "xenfv" :
"xenpv"};
+ virCapsGuestMachinePtr *machines;
+
+ if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL)
+ goto no_memory;
+
+ if ((guest = virCapabilitiesAddGuest(caps,
+ guest_archs[i].hvm ? "hvm" :
"xen",
+ guest_archs[i].model,
+ guest_archs[i].bits,
+ (STREQ(hostmachine, "x86_64") ?
+ "/usr/lib64/xen/bin/qemu-dm" :
+ "/usr/lib/xen/bin/qemu-dm"),
+ (guest_archs[i].hvm ?
+ "/usr/lib/xen/boot/hvmloader" :
+ NULL),
+ 1,
+ machines)) == NULL) {
+ virCapabilitiesFreeMachines(machines, 1);
+ goto no_memory;
+ }
+ machines = NULL;
+
+ if (virCapabilitiesAddGuestDomain(guest,
+ "xen",
+ NULL,
+ NULL,
+ 0,
+ NULL) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].pae &&
+ virCapabilitiesAddGuestFeature(guest,
+ "pae",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].nonpae &&
+ virCapabilitiesAddGuestFeature(guest,
+ "nonpae",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].ia64_be &&
+ virCapabilitiesAddGuestFeature(guest,
+ "ia64_be",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].hvm) {
+ if (virCapabilitiesAddGuestFeature(guest,
+ "acpi",
+ 1,
+ 1) == NULL)
+ goto no_memory;
+
+ if (virCapabilitiesAddGuestFeature(guest, "apic",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (virCapabilitiesAddGuestFeature(guest,
+ "hap",
+ 0,
+ 1) == NULL)
+ goto no_memory;
+ }
+ }
+
+ caps->defaultConsoleTargetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
+
+ return caps;
+
+ no_memory:
+ virCapabilitiesFree(caps);
+ return NULL;
+}
+
+static virCapsPtr
+libxlMakeCapabilitiesInternal(const char *hostmachine,
+ libxl_physinfo *phy_info,
+ char *capabilities)
+{
+ char *str, *token;
+ regmatch_t subs[4];
+ char *saveptr = NULL;
+ int i;
+
+ int host_pae = 0;
+ struct guest_arch guest_archs[32];
+ int nr_guest_archs = 0;
+ virCapsPtr caps = NULL;
+
+ memset(guest_archs, 0, sizeof(guest_archs));
+
+ /* hw_caps is an array of 32-bit words whose meaning is listed in
+ * xen-unstable.hg/xen/include/asm-x86/cpufeature.h. Each feature
+ * is defined in the form X*32+Y, corresponding to the Y'th bit in
+ * the X'th 32-bit word of hw_cap.
+ */
+ host_pae = phy_info->hw_cap[0] & LIBXL_X86_FEATURE_PAE_MASK;
+
+ /* Format of capabilities string is documented in the code in
+ * xen-unstable.hg/xen/arch/.../setup.c.
+ *
+ * It is a space-separated list of supported guest architectures.
+ *
+ * For x86:
+ * TYP-VER-ARCH[p]
+ * ^ ^ ^ ^
+ * | | | +-- PAE supported
+ * | | +------- x86_32 or x86_64
+ * | +----------- the version of Xen, eg. "3.0"
+ * +--------------- "xen" or "hvm" for para or full virt
respectively
+ *
+ * For IA64:
+ * TYP-VER-ARCH[be]
+ * ^ ^ ^ ^
+ * | | | +-- Big-endian supported
+ * | | +------- always "ia64"
+ * | +----------- the version of Xen, eg. "3.0"
+ * +--------------- "xen" or "hvm" for para or full virt
respectively
+ */
+
+ /* Split capabilities string into tokens. strtok_r is OK here because
+ * we "own" the buffer. Parse out the features from each token.
+ */
+ for (str = capabilities, nr_guest_archs = 0;
+ nr_guest_archs < sizeof(guest_archs) / sizeof(guest_archs[0])
+ && (token = strtok_r(str, " ", &saveptr)) !=
NULL;
+ str = NULL) {
+ if (regexec(&xen_cap_rec, token, sizeof(subs) / sizeof(subs[0]),
+ subs, 0) == 0) {
+ int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
+ const char *model;
+ int bits, pae = 0, nonpae = 0, ia64_be = 0;
+
+ if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
+ model = "i686";
+ bits = 32;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "p"))
+ pae = 1;
+ else
+ nonpae = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
+ model = "x86_64";
+ bits = 64;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
+ model = "ia64";
+ bits = 64;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "be"))
+ ia64_be = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
+ model = "ppc64";
+ bits = 64;
+ } else {
+ continue;
+ }
+
+ /* Search for existing matching (model,hvm) tuple */
+ for (i = 0 ; i < nr_guest_archs ; i++) {
+ if (STREQ(guest_archs[i].model, model) &&
+ guest_archs[i].hvm == hvm) {
+ break;
+ }
+ }
+
+ /* Too many arch flavours - highly unlikely ! */
+ if (i >= ARRAY_CARDINALITY(guest_archs))
+ continue;
+ /* Didn't find a match, so create a new one */
+ if (i == nr_guest_archs)
+ nr_guest_archs++;
+
+ guest_archs[i].model = model;
+ guest_archs[i].bits = bits;
+ guest_archs[i].hvm = hvm;
+
+ /* Careful not to overwrite a previous positive
+ setting with a negative one here - some archs
+ can do both pae & non-pae, but Xen reports
+ separately capabilities so we're merging archs */
+ if (pae)
+ guest_archs[i].pae = pae;
+ if (nonpae)
+ guest_archs[i].nonpae = nonpae;
+ if (ia64_be)
+ guest_archs[i].ia64_be = ia64_be;
+ }
+ }
+
+ if ((caps = libxlBuildCapabilities(hostmachine,
+ host_pae,
+ guest_archs,
+ nr_guest_archs)) == NULL)
+ goto no_memory;
+
+ return caps;
+
+ no_memory:
+ virReportOOMError();
+ virCapabilitiesFree(caps);
+ return NULL;
+}
+
+static int
+libxlMakeDomCreateInfo(virDomainDefPtr def, libxl_domain_create_info *c_info)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ libxl_init_create_info(c_info);
+
+ c_info->hvm = STREQ(def->os.type, "hvm");
+ if ((c_info->name = strdup(def->name)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ virUUIDFormat(def->uuid, uuidstr);
+ if (libxl_uuid_from_string(&c_info->uuid, uuidstr) ) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight failed to parse UUID '%s'"), uuidstr);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ libxl_domain_create_info_destroy(c_info);
+ return -1;
+}
+
+static int
+libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ libxl_domain_build_info *b_info = &d_config->b_info;
+ int hvm = STREQ(def->os.type, "hvm");
+
+ libxl_init_build_info(b_info, &d_config->c_info);
+
+ b_info->hvm = hvm;
+ b_info->max_vcpus = def->maxvcpus;
+ b_info->cur_vcpus = def->vcpus;
+ if (def->clock.ntimers > 0 &&
+ def->clock.timers[0]->name == VIR_DOMAIN_TIMER_NAME_TSC) {
+ switch (def->clock.timers[0]->mode) {
+ case VIR_DOMAIN_TIMER_MODE_NATIVE:
+ b_info->tsc_mode = 2;
+ break;
+ case VIR_DOMAIN_TIMER_MODE_PARAVIRT:
+ b_info->tsc_mode = 3;
+ break;
+ default:
+ b_info->tsc_mode = 1;
+ }
+ }
+ b_info->max_memkb = def->mem.max_balloon;
+ b_info->target_memkb = def->mem.cur_balloon;
+ if (hvm) {
+ b_info->u.hvm.pae = def->features & (1 <<
VIR_DOMAIN_FEATURE_PAE);
+ b_info->u.hvm.apic = def->features & (1 <<
VIR_DOMAIN_FEATURE_APIC);
+ b_info->u.hvm.acpi = def->features & (1 <<
VIR_DOMAIN_FEATURE_ACPI);
+ /*
+ * The following comment and calculation were taken directly from
+ * libxenlight's internal function libxl_get_required_shadow_memory():
+ *
+ * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M map,
+ * plus 1 page per MiB of RAM to shadow the resident processes.
+ */
+ b_info->shadow_memkb = 4 * (256 * b_info->cur_vcpus +
+ 2 * (b_info->max_memkb / 1024));
+ } else {
+ if (def->os.bootloader) {
+ if ((b_info->u.pv.bootloader = strdup(def->os.bootloader)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->os.bootloaderArgs) {
+ if ((b_info->u.pv.bootloader_args = strdup(def->os.bootloaderArgs)) ==
NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->os.cmdline) {
+ if ((b_info->u.pv.cmdline = strdup(def->os.cmdline)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->os.kernel) {
+ /* libxl_init_build_info() sets kernel.path = strdup("hvmloader")
*/
+ free(b_info->kernel.path);
+ if ((b_info->kernel.path = strdup(def->os.kernel)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->os.initrd) {
+ if ((b_info->u.pv.ramdisk.path = strdup(def->os.initrd)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ }
+
+ return 0;
+
+error:
+ libxl_domain_build_info_destroy(b_info);
+ return -1;
+}
+
+static int
+libxlMakeDiskList(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ virDomainDiskDefPtr *l_disks = def->disks;
+ int ndisks = def->ndisks;
+ libxl_device_disk *x_disks;
+ int i;
+
+ if (VIR_ALLOC_N(x_disks, ndisks) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ for (i = 0; i < ndisks; i++) {
+ if (l_disks[i]->src &&
+ (x_disks[i].pdev_path = strdup(l_disks[i]->src)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (l_disks[i]->dst &&
+ (x_disks[i].vdev = strdup(l_disks[i]->dst)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (l_disks[i]->driverName) {
+ if (STREQ(l_disks[i]->driverName, "tap") ||
+ STREQ(l_disks[i]->driverName, "tap2")) {
+ if (l_disks[i]->driverType) {
+ if (STREQ(l_disks[i]->driverType, "qcow")) {
+ x_disks[i].format = DISK_FORMAT_QCOW;
+ x_disks[i].backend = DISK_BACKEND_QDISK;
+ } else if (STREQ(l_disks[i]->driverType, "qcow2")) {
+ x_disks[i].format = DISK_FORMAT_QCOW2;
+ x_disks[i].backend = DISK_BACKEND_QDISK;
+ } else if (STREQ(l_disks[i]->driverType, "vhd")) {
+ x_disks[i].format = DISK_FORMAT_VHD;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ } else if (STREQ(l_disks[i]->driverType, "aio") ||
+ STREQ(l_disks[i]->driverType, "raw")) {
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ }
+ } else {
+ /* No subtype specified, default to raw/tap */
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ }
+ } else if (STREQ(l_disks[i]->driverName, "file")) {
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ } else if (STREQ(l_disks[i]->driverName, "phy")) {
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_PHY;
+ } else {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight does not support disk driver %s"),
+ l_disks[i]->driverName);
+ goto error;
+ }
+ } else {
+ /* No driverName - default to raw/tap?? */
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ }
+
+ /* How to set unpluggable? */
+ x_disks[i].unpluggable = 1;
+ x_disks[i].readwrite = !l_disks[i]->readonly;
+ x_disks[i].is_cdrom =
+ l_disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM ? 1 : 0;
+ }
+
+ d_config->disks = x_disks;
+ d_config->num_disks = ndisks;
+
+ return 0;
+
+error:
+ for (i = 0; i < ndisks; i++)
+ libxl_device_disk_destroy(&x_disks[i]);
+ VIR_FREE(x_disks);
+ return -1;
+}
+
+static int
+libxlMakeNicList(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ virDomainNetDefPtr *l_nics = def->nets;
+ int nnics = def->nnets;
+ libxl_device_nic *x_nics;
+ int i;
+
+ if (VIR_ALLOC_N(x_nics, nnics) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ for (i = 0; i < nnics; i++) {
+ x_nics[i].devid = i;
+
+ // TODO: Where is mtu stored?
+ //x_nics[i].mtu = 1492;
+
+ memcpy(x_nics[i].mac, l_nics[i]->mac, sizeof(libxl_mac));
+
+ if (l_nics[i]->model && !STREQ(l_nics[i]->model,
"netfront")) {
+ if ((x_nics[i].model = strdup(l_nics[i]->model)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ x_nics[i].nictype = NICTYPE_IOEMU;
+ } else {
+ x_nics[i].nictype = NICTYPE_VIF;
+ }
+
+ if (l_nics[i]->ifname &&
+ (x_nics[i].ifname = strdup(l_nics[i]->ifname)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (l_nics[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+ if (l_nics[i]->data.bridge.brname &&
+ (x_nics[i].bridge =
+ strdup(l_nics[i]->data.bridge.brname)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ if (l_nics[i]->data.bridge.script &&
+ (x_nics[i].script =
+ strdup(l_nics[i]->data.bridge.script)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ }
+
+ d_config->vifs = x_nics;
+ d_config->num_vifs = nnics;
+
+ return 0;
+
+error:
+ for (i = 0; i < nnics; i++)
+ libxl_device_nic_destroy(&x_nics[i]);
+ VIR_FREE(x_nics);
+ return -1;
+}
+
+static int
+libxlMakeVfbList(libxlDriverPrivatePtr driver,
+ virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ virDomainGraphicsDefPtr *l_vfbs = def->graphics;
+ int nvfbs = def->ngraphics;
+ libxl_device_vfb *x_vfbs;
+ libxl_device_vkb *x_vkbs;
+ int i;
+ int port;
+
+ if (nvfbs == 0)
+ return 0;
+
+ if (VIR_ALLOC_N(x_vfbs, nvfbs) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ if (VIR_ALLOC_N(x_vkbs, nvfbs) < 0) {
+ virReportOOMError();
+ VIR_FREE(x_vfbs);
+ return -1;
+ }
+
+ for (i = 0; i < nvfbs; i++) {
+ libxl_device_vfb_init(&x_vfbs[i], i);
+ libxl_device_vkb_init(&x_vkbs[i], i);
+
+ switch (l_vfbs[i]->type) {
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ x_vfbs[i].sdl = 1;
+ if (l_vfbs[i]->data.sdl.display &&
+ (x_vfbs[i].display =
+ strdup(l_vfbs[i]->data.sdl.display)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ if (l_vfbs[i]->data.sdl.xauth &&
+ (x_vfbs[i].xauthority =
+ strdup(l_vfbs[i]->data.sdl.xauth)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ break;
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ x_vfbs[i].vnc = 1;
+ /* driver handles selection of free port */
+ x_vfbs[i].vncunused = 0;
+ if (l_vfbs[i]->data.vnc.autoport) {
+ port = libxlNextFreeVncPort(driver, LIBXL_VNC_PORT_MIN);
+ if (port < 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unable to find an unused VNC
port"));
+ goto error;
+ }
+ l_vfbs[i]->data.vnc.port = port;
+ }
+ x_vfbs[i].vncdisplay = l_vfbs[i]->data.vnc.port -
+ LIBXL_VNC_PORT_MIN;
+
+ if (l_vfbs[i]->data.vnc.listenAddr) {
+ /* libxl_device_vfb_init() does strdup("127.0.0.1") */
+ free(x_vfbs[i].vnclisten);
+ if ((x_vfbs[i].vnclisten =
+ strdup(l_vfbs[i]->data.vnc.listenAddr)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (l_vfbs[i]->data.vnc.keymap &&
+ (x_vfbs[i].keymap =
+ strdup(l_vfbs[i]->data.vnc.keymap)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ break;
+ }
+ }
+
+ d_config->vfbs = x_vfbs;
+ d_config->vkbs = x_vkbs;
+ d_config->num_vfbs = d_config->num_vkbs = nvfbs;
+
+ return 0;
+
+error:
+ for (i = 0; i < nvfbs; i++) {
+ libxl_device_vfb_destroy(&x_vfbs[i]);
+ libxl_device_vkb_destroy(&x_vkbs[i]);
+ }
+ VIR_FREE(x_vfbs);
+ VIR_FREE(x_vkbs);
+ return -1;
+}
+
+static int
+libxlMakeChrdevStr(virDomainChrDefPtr def, char **buf)
+{
+ const char *type = virDomainChrTypeToString(def->source.type);
+
+ if (!type) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unexpected chr device type"));
+ return -1;
+ }
+
+ switch (def->source.type) {
+ case VIR_DOMAIN_CHR_TYPE_NULL:
+ case VIR_DOMAIN_CHR_TYPE_STDIO:
+ case VIR_DOMAIN_CHR_TYPE_VC:
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ if (virAsprintf(buf, "%s", type) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ if (virAsprintf(buf, "%s:%s", type,
+ def->source.data.file.path) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ if (virAsprintf(buf, "%s", def->source.data.file.path) < 0)
{
+ virReportOOMError();
+ return -1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int
+libxlMakeDeviceModelInfo(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ libxl_device_model_info *dm_info = &d_config->dm_info;
+ int i;
+ char b_order[VIR_DOMAIN_BOOT_LAST+1];
+
+ libxl_init_dm_info(dm_info, &d_config->c_info, &d_config->b_info);
+
+ if (d_config->b_info.hvm) {
+ /* HVM-specific device model info */
+ dm_info->type = XENFV;
+ if (def->os.nBootDevs > 0) {
+ free(dm_info->boot);
+ for (i = 0; i < def->os.nBootDevs; i++) {
+ switch (def->os.bootDevs[i]) {
+ case VIR_DOMAIN_BOOT_FLOPPY:
+ b_order[i] = 'a';
+ break;
+ default:
+ case VIR_DOMAIN_BOOT_DISK:
+ b_order[i] = 'c';
+ break;
+ case VIR_DOMAIN_BOOT_CDROM:
+ b_order[i] = 'd';
+ break;
+ case VIR_DOMAIN_BOOT_NET:
+ b_order[i] = 'n';
+ break;
+ }
+ }
+ b_order[def->os.nBootDevs] = '\0';
+ if ((dm_info->boot = strdup(b_order)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->serials &&
+ (libxlMakeChrdevStr(def->serials[0], &dm_info->serial) < 0))
+ goto error;
+ } else {
+ /* PV-specific device model info */
+ dm_info->type = XENPV;
+ }
+
+ /* Build qemu graphics options from previously parsed vfb */
+ if (d_config->num_vfbs > 0) {
+ if (d_config->vfbs[0].vnc) {
+ dm_info->vnc = 1;
+ /* driver handles selection of free port */
+ dm_info->vncunused = 0;
+ if (d_config->vfbs[0].vnclisten) {
+ free(dm_info->vnclisten);
+ if ((dm_info->vnclisten =
+ strdup(d_config->vfbs[0].vnclisten)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (d_config->vfbs[0].keymap &&
+ (dm_info->keymap = strdup(d_config->vfbs[0].keymap)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ dm_info->vncdisplay = d_config->vfbs[0].vncdisplay;
+ if (d_config->vfbs[0].vncpasswd &&
+ (dm_info->vncpasswd =
+ strdup(d_config->vfbs[0].vncpasswd)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ } else if (d_config->vfbs[0].sdl) {
+ dm_info->sdl = 1;
+ dm_info->vnc = 0;
+ }
+ } else if (d_config->num_vfbs == 0) {
+ dm_info->nographic = 1;
+ dm_info->vnc = 0;
+ }
+
+ // TODO
+ //dm_info->usb = ;
+ //dm_info->usbdevice = ;
+ //dm_info->soundhw = ;
+
+ return 0;
+
+error:
+ libxl_device_model_info_destroy(dm_info);
+ return -1;
+}
+
+virCapsPtr
+libxlMakeCapabilities(libxl_ctx *ctx)
+{
+ libxl_physinfo phy_info;
+ const libxl_version_info *ver_info;
+ struct utsname utsname;
+
+ regcomp (&xen_cap_rec, xen_cap_re, REG_EXTENDED);
+
+ if (libxl_get_physinfo(ctx, &phy_info) != 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to get node physical info from libxenlight"));
+ return NULL;
+ }
+
+ if ((ver_info = libxl_get_version_info(ctx)) == NULL) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to get version info from libxenlight"));
+ return NULL;
+ }
+
+ uname(&utsname);
+
+ return libxlMakeCapabilitiesInternal(utsname.machine,
+ &phy_info,
+ ver_info->capabilities);
+}
+
+int
+libxlBuildDomainConfig(libxlDriverPrivatePtr driver,
+ virDomainDefPtr def, libxl_domain_config *d_config)
+{
+
+ if (libxlMakeDomCreateInfo(def, &d_config->c_info) < 0)
+ return -1;
+
+ if (libxlMakeDomBuildInfo(def, d_config) < 0) {
+ goto error;
+ }
+
+ if (libxlMakeDiskList(def, d_config) < 0) {
+ goto error;
+ }
+
+ if (libxlMakeNicList(def, d_config) < 0) {
+ goto error;
+ }
+
+ if (libxlMakeVfbList(driver, def, d_config) < 0) {
+ goto error;
+ }
+
+ if (libxlMakeDeviceModelInfo(def, d_config) < 0) {
+ goto error;
+ }
+
+ d_config->on_reboot = def->onReboot;
+ d_config->on_poweroff = def->onPoweroff;
+ d_config->on_crash = def->onCrash;
+
+ return 0;
+
+error:
+ libxl_domain_config_destroy(d_config);
+ return -1;
+}
diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h
new file mode 100644
index 0000000..bb49d35
--- /dev/null
+++ b/src/libxl/libxl_conf.h
@@ -0,0 +1,91 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#ifndef LIBXL_CONF_H
+# define LIBXL_CONF_H
+
+# include <config.h>
+
+# include <libxl.h>
+
+# include "internal.h"
+# include "domain_conf.h"
+# include "capabilities.h"
+# include "configmake.h"
+# include "bitmap.h"
+
+
+# define LIBXL_VNC_PORT_MIN 5900
+# define LIBXL_VNC_PORT_MAX 65535
+
+# define LIBXL_CONFIG_DIR SYSCONFDIR "/libvirt/libxl"
+# define LIBXL_AUTOSTART_DIR LIBXL_CONFIG_DIR "/autostart"
+# define LIBXL_STATE_DIR LOCALSTATEDIR "/run/libvirt/libxl"
+# define LIBXL_LOG_DIR LOCALSTATEDIR "/log/libvirt/libxl"
+# define LIBXL_LIB_DIR LOCALSTATEDIR "/lib/libvirt/libxl"
+# define LIBXL_SAVE_DIR LIBXL_LIB_DIR "/save"
+
+
+typedef struct _libxlDriverPrivate libxlDriverPrivate;
+typedef libxlDriverPrivate *libxlDriverPrivatePtr;
+struct _libxlDriverPrivate {
+ virMutex lock;
+ virCapsPtr caps;
+ unsigned int version;
+
+ FILE *logger_file;
+ xentoollog_logger *logger;
+ /* libxl ctx for driver wide ops; getVersion, getNodeInfo, ... */
+ libxl_ctx ctx;
+
+ virBitmapPtr reservedVNCPorts;
+ virDomainObjList domains;
+
+ char *configDir;
+ char *autostartDir;
+ char *logDir;
+ char *stateDir;
+ char *libDir;
+ char *saveDir;
+};
+
+typedef struct _libxlDomainObjPrivate libxlDomainObjPrivate;
+typedef libxlDomainObjPrivate *libxlDomainObjPrivatePtr;
+struct _libxlDomainObjPrivate {
+ /* per domain libxl ctx */
+ libxl_ctx ctx;
+ libxl_waiter *dWaiter;
+ int waiterFD;
+ int eventHdl;
+};
+
+
+# define libxlError(code, ...) \
+ virReportErrorHelper(NULL, VIR_FROM_LIBXL, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+virCapsPtr
+libxlMakeCapabilities(libxl_ctx *ctx);
+
+int
+libxlBuildDomainConfig(libxlDriverPrivatePtr driver,
+ virDomainDefPtr def, libxl_domain_config *d_config);
+
+
+#endif /* LIBXL_CONF_H */
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
new file mode 100644
index 0000000..38bfca8
--- /dev/null
+++ b/src/libxl/libxl_driver.c
@@ -0,0 +1,1457 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ * Copyright (C) 2011 Univention GmbH.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#include <config.h>
+
+#include <sys/utsname.h>
+#include <libxl.h>
+
+#include "internal.h"
+#include "logging.h"
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "files.h"
+#include "memory.h"
+#include "event.h"
+#include "uuid.h"
+#include "command.h"
+#include "libxl_driver.h"
+#include "libxl_conf.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_LIBXL
+
+#define LIBXL_DOM_REQ_POWEROFF 0
+#define LIBXL_DOM_REQ_REBOOT 1
+#define LIBXL_DOM_REQ_SUSPEND 2
+#define LIBXL_DOM_REQ_CRASH 3
+#define LIBXL_DOM_REQ_HALT 4
+
+static libxlDriverPrivatePtr libxl_driver = NULL;
+
+
+/* Function declarations */
+static int
+libxlVmStart(libxlDriverPrivatePtr driver,
+ virDomainObjPtr vm, bool start_paused);
+
+
+/* Function definitions */
+static void
+libxlDriverLock(libxlDriverPrivatePtr driver)
+{
+ virMutexLock(&driver->lock);
+}
+
+static void
+libxlDriverUnlock(libxlDriverPrivatePtr driver)
+{
+ virMutexUnlock(&driver->lock);
+}
+
+static void *
+libxlDomainObjPrivateAlloc(void)
+{
+ libxlDomainObjPrivatePtr priv;
+
+ if (VIR_ALLOC(priv) < 0)
+ return NULL;
+
+ libxl_ctx_init(&priv->ctx, LIBXL_VERSION, libxl_driver->logger);
+ priv->waiterFD = -1;
+ priv->eventHdl = -1;
+
+ return priv;
+}
+
+static void
+libxlDomainObjPrivateFree(void *data)
+{
+ libxlDomainObjPrivatePtr priv = data;
+
+ if (priv->eventHdl >= 0)
+ virEventRemoveHandle(priv->eventHdl);
+
+ if (priv->dWaiter) {
+ libxl_stop_waiting(&priv->ctx, priv->dWaiter);
+ libxl_free_waiter(priv->dWaiter);
+ VIR_FREE(priv->dWaiter);
+ }
+
+ libxl_ctx_free(&priv->ctx);
+ VIR_FREE(priv);
+}
+
+/*
+ * Remove reference to domain object.
+ */
+static void
+libxlDomainObjUnref(void *data)
+{
+ virDomainObjPtr vm = data;
+
+ virDomainObjUnref(vm);
+}
+
+/*
+ * Cleanup function for domain that has reached shutoff state.
+ *
+ * virDomainObjPtr should be locked on invocation
+ */
+static void
+libxlVmCleanup(libxlDriverPrivatePtr driver, virDomainObjPtr vm)
+{
+ libxlDomainObjPrivatePtr priv = vm->privateData;
+ int vnc_port;
+ char *file;
+
+ if (priv->eventHdl >= 0) {
+ virEventRemoveHandle(priv->eventHdl);
+ priv->eventHdl = -1;
+ }
+
+ if (priv->dWaiter) {
+ libxl_stop_waiting(&priv->ctx, priv->dWaiter);
+ libxl_free_waiter(priv->dWaiter);
+ VIR_FREE(priv->dWaiter);
+ }
+
+ if (vm->persistent) {
+ vm->def->id = -1;
+ vm->state = VIR_DOMAIN_SHUTOFF;
+ }
+
+ if ((vm->def->ngraphics == 1) &&
+ vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
+ vm->def->graphics[0]->data.vnc.autoport) {
+ vnc_port = vm->def->graphics[0]->data.vnc.port;
+ if (vnc_port >= LIBXL_VNC_PORT_MIN) {
+ if (virBitmapClearBit(driver->reservedVNCPorts,
+ vnc_port - LIBXL_VNC_PORT_MIN) < 0)
+ VIR_DEBUG("Could not mark port %d as unused", vnc_port);
+ }
+ }
+
+ if (virAsprintf(&file, "%s/%s.xml", driver->stateDir,
vm->def->name) > 0) {
+ if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR)
+ VIR_DEBUG("Failed to remove domain XML for %s",
vm->def->name);
+ VIR_FREE(file);
+ }
+}
+
+/*
+ * Reap a domain from libxenlight.
+ *
+ * virDomainObjPtr should be locked on invocation
+ */
+static int
+libxlVmReap(libxlDriverPrivatePtr driver, virDomainObjPtr vm, int force)
+{
+ libxlDomainObjPrivatePtr priv = vm->privateData;
+
+ if (libxl_domain_destroy(&priv->ctx, vm->def->id, force) < 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to cleanup domain %d"), vm->def->id);
+ return -1;
+ }
+
+ libxlVmCleanup(driver, vm);
+ return 0;
+}
+
+/*
+ * Handle previously registered event notification from libxenlight
+ */
+static void libxlEventHandler(int watch,
+ int fd,
+ int events,
+ void *data)
+{
+ libxlDriverPrivatePtr driver = libxl_driver;
+ virDomainObjPtr vm = data;
+ libxlDomainObjPrivatePtr priv;
+ libxl_event event;
+ libxl_dominfo info;
+
+ libxlDriverLock(driver);
+ virDomainObjLock(vm);
+ libxlDriverUnlock(driver);
+
+ priv = vm->privateData;
+
+ memset(&event, 0, sizeof(event));
+ memset(&info, 0, sizeof(info));
+
+ if (priv->waiterFD != fd || priv->eventHdl != watch) {
+ virEventRemoveHandle(watch);
+ priv->eventHdl = -1;
+ goto cleanup;
+ }
+
+ if (!(events & VIR_EVENT_HANDLE_READABLE))
+ goto cleanup;
+
+ if (libxl_get_event(&priv->ctx, &event))
+ goto cleanup;
+
+ if (event.type == LIBXL_EVENT_DOMAIN_DEATH) {
+ /* libxl_event_get_domain_death_info returns 1 if death
+ * event was for this domid */
+ if (libxl_event_get_domain_death_info(&priv->ctx,
+ vm->def->id,
+ &event,
+ &info) != 1)
+ goto cleanup;
+
+ virEventRemoveHandle(watch);
+ priv->eventHdl = -1;
+ switch (info.shutdown_reason) {
+ case SHUTDOWN_poweroff:
+ case SHUTDOWN_crash:
+ libxlVmReap(driver, vm, 0);
+ if (!vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+ break;
+ case SHUTDOWN_reboot:
+ libxlVmReap(driver, vm, 0);
+ libxlVmStart(driver, vm, 0);
+ break;
+ default:
+ VIR_INFO("Unhandled shutdown_reason %d",
info.shutdown_reason);
+ break;
+ }
+ }
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxl_free_event(&event);
+}
+
+/*
+ * Register domain events with libxenlight and insert event handles
+ * in libvirt's event loop.
+ */
+static int
+libxlCreateDomEvents(virDomainObjPtr vm)
+{
+ libxlDomainObjPrivatePtr priv = vm->privateData;
+ int fd;
+
+ if (VIR_ALLOC(priv->dWaiter) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (libxl_wait_for_domain_death(&priv->ctx, vm->def->id,
priv->dWaiter))
+ goto error;
+
+ libxl_get_wait_fd(&priv->ctx, &fd);
+ if (fd < 0)
+ goto error;
+
+ priv->waiterFD = fd;
+ /* Add a reference to the domain object while it is injected in
+ * the event loop.
+ */
+ virDomainObjRef(vm);
+ if ((priv->eventHdl = virEventAddHandle(
+ fd,
+ VIR_EVENT_HANDLE_READABLE | VIR_EVENT_HANDLE_ERROR,
+ libxlEventHandler,
+ vm, libxlDomainObjUnref)) < 0) {
+ virDomainObjUnref(vm);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ libxl_free_waiter(priv->dWaiter);
+ VIR_FREE(priv->dWaiter);
+ priv->eventHdl = -1;
+ return -1;
+}
+
+/*
+ * Start a domain through libxenlight.
+ *
+ * virDomainObjPtr should be locked on invocation
+ */
+static int
+libxlVmStart(libxlDriverPrivatePtr driver,
+ virDomainObjPtr vm, bool start_paused)
+{
+ libxl_domain_config d_config;
+ virDomainDefPtr def = vm->def;
+ int ret;
+ uint32_t domid = 0;
+ char *dom_xml = NULL;
+ pid_t child_console_pid = -1;
+ libxlDomainObjPrivatePtr priv = vm->privateData;
+
+ memset(&d_config, 0, sizeof(d_config));
+
+ if (libxlBuildDomainConfig(driver, def, &d_config) < 0 )
+ return -1;
+
+ //TODO: Balloon dom0 ??
+ //ret = freemem(&d_config->b_info, &d_config->dm_info);
+
+ ret = libxl_domain_create_new(&priv->ctx, &d_config,
+ NULL, &child_console_pid, &domid);
+ if (ret) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight failed to create new domain '%s'"),
+ d_config.c_info.name);
+ goto error;
+ }
+
+ def->id = domid;
+ if ((dom_xml = virDomainDefFormat(def, 0)) == NULL)
+ goto error;
+
+ if (libxl_userdata_store(&priv->ctx, domid, "libvirt-xml",
+ (uint8_t *)dom_xml, strlen(dom_xml) + 1)) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight failed to store userdata"));
+ goto error;
+ }
+
+ if (libxlCreateDomEvents(vm) < 0)
+ goto error;
+
+ if (!start_paused) {
+ libxl_domain_unpause(&priv->ctx, domid);
+ vm->state = VIR_DOMAIN_RUNNING;
+ } else {
+ vm->state = VIR_DOMAIN_PAUSED;
+ }
+
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
+ goto error;
+
+ libxl_domain_config_destroy(&d_config);
+ VIR_FREE(dom_xml);
+ return 0;
+
+error:
+ if (domid > 0) {
+ libxl_domain_destroy(&priv->ctx, domid, 0);
+ def->id = -1;
+ vm->state = VIR_DOMAIN_SHUTOFF;
+ }
+ libxl_domain_config_destroy(&d_config);
+ VIR_FREE(dom_xml);
+ return -1;
+}
+
+
+/*
+ * Reconnect to running domains that were previously started/created
+ * with libxenlight driver.
+ */
+static void
+libxlReconnectDomain(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ virDomainObjPtr vm = payload;
+ libxlDriverPrivatePtr driver = opaque;
+ int rc;
+ libxl_dominfo d_info;
+ int len;
+ uint8_t *data = NULL;
+
+ virDomainObjLock(vm);
+
+ /* Does domain still exist? */
+ rc = libxl_domain_info(&driver->ctx, &d_info, vm->def->id);
+ if (rc == ERROR_INVAL) {
+ goto out;
+ } else if (rc != 0) {
+ VIR_DEBUG("libxl_domain_info failed (code %d), ignoring domain %d",
+ rc, vm->def->id);
+ goto out;
+ }
+
+ /* Is this a domain that was under libvirt control? */
+ if (libxl_userdata_retrieve(&driver->ctx, vm->def->id,
+ "libvirt-xml", &data, &len)) {
+ VIR_DEBUG("libxl_userdata_retrieve failed, ignoring domain %d",
vm->def->id);
+ goto out;
+ }
+
+ /* Update domid in case it changed (e.g. reboot) while we were gone? */
+ vm->def->id = d_info.domid;
+ vm->state = VIR_DOMAIN_RUNNING;
+
+ /* Recreate domain death et. al. events */
+ libxlCreateDomEvents(vm);
+ virDomainObjUnlock(vm);
+ return;
+
+out:
+ libxlVmCleanup(driver, vm);
+ if (!vm->persistent)
+ virDomainRemoveInactive(&driver->domains, vm);
+ else
+ virDomainObjUnlock(vm);
+}
+
+static void
+libxlReconnectDomains(libxlDriverPrivatePtr driver)
+{
+ virHashForEach(driver->domains.objs, libxlReconnectDomain, driver);
+}
+
+static int
+libxlShutdown(void)
+{
+ if (!libxl_driver)
+ return -1;
+
+ libxlDriverLock(libxl_driver);
+ virCapabilitiesFree(libxl_driver->caps);
+ virDomainObjListDeinit(&libxl_driver->domains);
+ libxl_ctx_free(&libxl_driver->ctx);
+ xtl_logger_destroy(libxl_driver->logger);
+ if (libxl_driver->logger_file)
+ VIR_FORCE_FCLOSE(libxl_driver->logger_file);
+
+ virBitmapFree(libxl_driver->reservedVNCPorts);
+
+ VIR_FREE(libxl_driver->configDir);
+ VIR_FREE(libxl_driver->autostartDir);
+ VIR_FREE(libxl_driver->logDir);
+ VIR_FREE(libxl_driver->stateDir);
+ VIR_FREE(libxl_driver->libDir);
+ VIR_FREE(libxl_driver->saveDir);
+
+ libxlDriverUnlock(libxl_driver);
+ virMutexDestroy(&libxl_driver->lock);
+ VIR_FREE(libxl_driver);
+
+ return 0;
+}
+
+static int
+libxlStartup(int privileged) {
+ const libxl_version_info *ver_info;
+ char *log_file = NULL;
+ virCommandPtr cmd = NULL;
+ int status;
+
+ /* Disable libxl driver if non-root */
+ if (!privileged) {
+ VIR_INFO0("Not running privileged, disabling libxenlight driver");
+ return 0;
+ }
+
+ /* Disable driver if legacy xen toolstack (xend) is in use */
+ if ((cmd = virCommandNew("/usr/sbin/xend")) != NULL) {
+ virCommandAddArg(cmd, "status");
+ if (virCommandRun(cmd, &status) == 0) {
+ if (status == 0) {
+ VIR_INFO0("Legacy xen tool stack seems to be in use, disabling
"
+ "libxenlight driver.");
+ virCommandFree(cmd);
+ return 0;
+ }
+ }
+ virCommandFree(cmd);
+ }
+
+ if (VIR_ALLOC(libxl_driver) < 0)
+ return -1;
+
+ if (virMutexInit(&libxl_driver->lock) < 0) {
+ VIR_ERROR0(_("cannot initialize mutex"));
+ VIR_FREE(libxl_driver);
+ return -1;
+ }
+ libxlDriverLock(libxl_driver);
+
+ /* Allocate bitmap for vnc port reservation */
+ if ((libxl_driver->reservedVNCPorts =
+ virBitmapAlloc(LIBXL_VNC_PORT_MAX - LIBXL_VNC_PORT_MIN)) == NULL)
+ goto out_of_memory;
+
+ if (virDomainObjListInit(&libxl_driver->domains) < 0)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->configDir,
+ "%s", LIBXL_CONFIG_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->autostartDir,
+ "%s", LIBXL_AUTOSTART_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->logDir,
+ "%s", LIBXL_LOG_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->stateDir,
+ "%s", LIBXL_STATE_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->libDir,
+ "%s", LIBXL_LIB_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->saveDir,
+ "%s", LIBXL_SAVE_DIR) == -1)
+ goto out_of_memory;
+
+ if (virFileMakePath(libxl_driver->logDir) != 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("Failed to create log dir '%s': %s"),
+ libxl_driver->logDir, virStrerror(errno, ebuf, sizeof ebuf));
+ goto error;
+ }
+ if (virFileMakePath(libxl_driver->stateDir) != 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("Failed to create state dir '%s': %s"),
+ libxl_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
+ goto error;
+ }
+ if (virFileMakePath(libxl_driver->libDir) != 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("Failed to create lib dir '%s': %s"),
+ libxl_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
+ goto error;
+ }
+ if (virFileMakePath(libxl_driver->saveDir) != 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("Failed to create save dir '%s': %s"),
+ libxl_driver->saveDir, virStrerror(errno, ebuf, sizeof ebuf));
+ goto error;
+ }
+
+ if (virAsprintf(&log_file, "%s/libxl.log", libxl_driver->logDir)
< 0) {
+ goto out_of_memory;
+ }
+
+ if ((libxl_driver->logger_file = fopen(log_file, "a")) == NULL) {
+ virReportSystemError(errno,
+ _("failed to create logfile %s"),
+ log_file);
+ goto error;
+ }
+ VIR_FREE(log_file);
+
+ libxl_driver->logger =
+ (xentoollog_logger
*)xtl_createlogger_stdiostream(libxl_driver->logger_file, XTL_DEBUG, 0);
+ if (!libxl_driver->logger) {
+ VIR_ERROR0(_("cannot create logger for libxenlight"));
+ goto error;
+ }
+
+ if (libxl_ctx_init(&libxl_driver->ctx,
+ LIBXL_VERSION,
+ libxl_driver->logger)) {
+ VIR_ERROR0(_("cannot initialize libxenlight context"));
+ goto error;
+ }
+
+ if ((ver_info = libxl_get_version_info(&libxl_driver->ctx)) == NULL) {
+ VIR_ERROR0(_("cannot version information from libxenlight"));
+ goto error;
+ }
+ libxl_driver->version = (ver_info->xen_version_major * 1000000) +
+ (ver_info->xen_version_minor * 1000);
+
+ if ((libxl_driver->caps =
+ libxlMakeCapabilities(&libxl_driver->ctx)) == NULL) {
+ VIR_ERROR0(_("cannot create capabilities for libxenlight"));
+ goto error;
+ }
+
+ libxl_driver->caps->privateDataAllocFunc = libxlDomainObjPrivateAlloc;
+ libxl_driver->caps->privateDataFreeFunc = libxlDomainObjPrivateFree;
+
+ /* Load running domains first. */
+ if (virDomainLoadAllConfigs(libxl_driver->caps,
+ &libxl_driver->domains,
+ libxl_driver->stateDir,
+ libxl_driver->autostartDir,
+ 1, NULL, NULL) < 0)
+ goto error;
+
+ libxlReconnectDomains(libxl_driver);
+
+ /* Then inactive persistent configs */
+ if (virDomainLoadAllConfigs(libxl_driver->caps,
+ &libxl_driver->domains,
+ libxl_driver->configDir,
+ libxl_driver->autostartDir,
+ 0, NULL, NULL) < 0)
+ goto error;
+
+ libxlDriverUnlock(libxl_driver);
+
+ /* TODO: autostart domains */
+
+ return 0;
+
+out_of_memory:
+ virReportOOMError();
+error:
+ VIR_FREE(log_file);
+ if (libxl_driver)
+ libxlDriverUnlock(libxl_driver);
+ libxlShutdown();
+ return -1;
+}
+
+static int
+libxlReload(void)
+{
+ if (!libxl_driver)
+ return 0;
+
+ libxlDriverLock(libxl_driver);
+ virDomainLoadAllConfigs(libxl_driver->caps,
+ &libxl_driver->domains,
+ libxl_driver->configDir,
+ libxl_driver->autostartDir,
+ 0, NULL, libxl_driver);
+ libxlDriverUnlock(libxl_driver);
+
+ /* TODO: autostart domains */
+
+ return 0;
+}
+
+static int
+libxlActive(void)
+{
+ if (!libxl_driver)
+ return 0;
+
+ return 1;
+}
+
+static virDrvOpenStatus
+libxlOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ if (conn->uri == NULL) {
+ if (libxl_driver == NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ conn->uri = xmlParseURI("xen:///");
+ if (!conn->uri) {
+ virReportOOMError();
+ return VIR_DRV_OPEN_ERROR;
+ }
+ } else {
+ /* Only xen scheme */
+ if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme,
"xen"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* If server name is given, its for remote driver */
+ if (conn->uri->server != NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* Error if xen or libxl scheme specified but driver not started. */
+ if (libxl_driver == NULL) {
+ libxlError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("libxenlight state driver is not active"));
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ /* /session isn't supported in libxenlight */
+ if (conn->uri->path &&
+ STRNEQ(conn->uri->path, "") &&
+ STRNEQ(conn->uri->path, "/") &&
+ STRNEQ(conn->uri->path, "/system")) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected Xen URI path '%s', try xen:///"),
+ NULLSTR(conn->uri->path));
+ return VIR_DRV_OPEN_ERROR;
+ }
+ }
+
+ conn->privateData = libxl_driver;
+
+ return VIR_DRV_OPEN_SUCCESS;
+};
+
+static int
+libxlClose(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ conn->privateData = NULL;
+ return 0;
+}
+
+static const char *
+libxlGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return "xenlight";
+}
+
+static int
+libxlGetVersion(virConnectPtr conn, unsigned long *version)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+
+ libxlDriverLock(driver);
+ *version = driver->version;
+ libxlDriverUnlock(driver);
+ return 0;
+}
+
+static int
+libxlGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
+{
+ int ret;
+ libxlDriverPrivatePtr driver = conn->privateData;
+
+ ret = libxl_get_max_cpus(&driver->ctx);
+ /* libxl_get_max_cpus() will return 0 if there were any failures,
+ e.g. xc_physinfo() failing */
+ if (ret == 0)
+ return -1;
+
+ return ret;
+}
+
+static int
+libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
+{
+ libxl_physinfo phy_info;
+ const libxl_version_info* ver_info;
+ libxlDriverPrivatePtr driver = conn->privateData;
+ struct utsname utsname;
+
+ if (libxl_get_physinfo(&driver->ctx, &phy_info)) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxl_get_physinfo_info failed"));
+ return -1;
+ }
+
+ if ((ver_info = libxl_get_version_info(&driver->ctx)) == NULL) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxl_get_version_info failed"));
+ return -1;
+ }
+
+ uname(&utsname);
+ if (virStrncpy(info->model,
+ utsname.machine,
+ strlen(utsname.machine),
+ sizeof(info->model)) == NULL) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("machine type %s too big for destination"),
+ utsname.machine);
+ return -1;
+ }
+
+ info->memory = phy_info.total_pages * (ver_info->pagesize / 1024);
+ info->cpus = phy_info.nr_cpus;
+ info->nodes = phy_info.nr_nodes;
+ info->cores = phy_info.cores_per_socket;
+ info->threads = phy_info.threads_per_core;
+ info->sockets = 1;
+ info->mhz = phy_info.cpu_khz / 1000;
+ return 0;
+}
+
+static char *
+libxlGetCapabilities(virConnectPtr conn)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ char *xml;
+
+ libxlDriverLock(driver);
+ if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
+ virReportOOMError();
+ libxlDriverUnlock(driver);
+
+ return xml;
+}
+
+static int
+libxlListDomains(virConnectPtr conn, int *ids, int nids)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int n;
+
+ libxlDriverLock(driver);
+ n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
+ libxlDriverUnlock(driver);
+
+ return n;
+}
+
+static int
+libxlNumDomains(virConnectPtr conn)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int n;
+
+ libxlDriverLock(driver);
+ n = virDomainObjListNumOfDomains(&driver->domains, 1);
+ libxlDriverUnlock(driver);
+
+ return n;
+}
+
+static virDomainPtr
+libxlDomainCreateXML(virConnectPtr conn, const char *xml,
+ unsigned int flags)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainDefPtr def;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+
+ virCheckFlags(VIR_DOMAIN_START_PAUSED, NULL);
+
+ libxlDriverLock(driver);
+ if (!(def = virDomainDefParseString(driver->caps, xml,
+ VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
+ goto cleanup;
+
+ if (!(vm = virDomainAssignDef(driver->caps,
+ &driver->domains, def, false)))
+ goto cleanup;
+ def = NULL;
+
+ if (libxlVmStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0) < 0) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+cleanup:
+ virDomainDefFree(def);
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return dom;
+}
+
+static virDomainPtr
+libxlDomainLookupByID(virConnectPtr conn, int id)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByID(&driver->domains, id);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static virDomainPtr
+libxlDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, uuid);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static virDomainPtr
+libxlDomainLookupByName(virConnectPtr conn, const char *name)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByName(&driver->domains, name);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static int
+libxlDomainShutdown(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ libxlDomainObjPrivatePtr priv;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is not running"));
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+ if (libxl_domain_shutdown(&priv->ctx, dom->id, LIBXL_DOM_REQ_POWEROFF) !=
0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to shutdown domain '%d' with
libxenlight"),
+ dom->id);
+ goto cleanup;
+ }
+
+ /* vm is marked shutoff (or removed from domains list if not persistent)
+ * in shutdown event handler.
+ */
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ libxlDomainObjPrivatePtr priv;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is not running"));
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+ if (libxl_domain_shutdown(&priv->ctx, dom->id, LIBXL_DOM_REQ_REBOOT) != 0)
{
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to reboot domain '%d' with libxenlight"),
+ dom->id);
+ goto cleanup;
+ }
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainDestroy(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ libxlDomainObjPrivatePtr priv;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is not running"));
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+ if (libxlVmReap(driver, vm, 1) != 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to destroy domain '%d'"), dom->id);
+ goto cleanup;
+ }
+
+ if (!vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ info->state = vm->state;
+ info->cpuTime = 0;
+ info->maxMem = vm->def->mem.max_balloon;
+ info->memory = vm->def->mem.cur_balloon;
+ info->nrVirtCpu = vm->def->vcpus;
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static char *
+libxlDomainDumpXML(virDomainPtr dom, int flags)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ char *ret = NULL;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ ret = virDomainDefFormat(vm->def, flags);
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
+libxlListDefinedDomains(virConnectPtr conn,
+ char **const names, int nnames)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int n;
+
+ libxlDriverLock(driver);
+ n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
+ libxlDriverUnlock(driver);
+ return n;
+}
+
+static int
+libxlNumDefinedDomains(virConnectPtr conn)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int n;
+
+ libxlDriverLock(driver);
+ n = virDomainObjListNumOfDomains(&driver->domains, 0);
+ libxlDriverUnlock(driver);
+
+ return n;
+}
+
+static int
+libxlDomainCreateWithFlags(virDomainPtr dom,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is already running"));
+ goto cleanup;
+ }
+
+ ret = libxlVmStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0);
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainCreate(virDomainPtr dom)
+{
+ return libxlDomainCreateWithFlags(dom, 0);
+}
+
+static virDomainPtr
+libxlDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainDefPtr def = NULL;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+ int dupVM;
+
+ libxlDriverLock(driver);
+ if (!(def = virDomainDefParseString(driver->caps, xml,
+ VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
+ goto cleanup;
+
+ if (!(vm = virDomainAssignDef(driver->caps,
+ &driver->domains, def, false)))
+ goto cleanup;
+ def = NULL;
+ vm->persistent = 1;
+
+ if (virDomainSaveConfig(driver->configDir,
+ vm->newDef ? vm->newDef : vm->def) < 0) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+cleanup:
+ virDomainDefFree(def);
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return dom;
+}
+
+static int
+libxlDomainUndefine(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot undefine active domain"));
+ goto cleanup;
+ }
+
+ if (!vm->persistent) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot undefine transient domain"));
+ goto cleanup;
+ }
+
+ if (virDomainDeleteConfig(driver->configDir,
+ driver->autostartDir,
+ vm) < 0)
+ goto cleanup;
+
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainIsActive(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr obj;
+ int ret = -1;
+
+ libxlDriverLock(driver);
+ obj = virDomainFindByUUID(&driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+ if (!obj) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+ ret = virDomainObjIsActive(obj);
+
+ cleanup:
+ if (obj)
+ virDomainObjUnlock(obj);
+ return ret;
+}
+
+static int
+libxlDomainIsPersistent(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr obj;
+ int ret = -1;
+
+ libxlDriverLock(driver);
+ obj = virDomainFindByUUID(&driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+ if (!obj) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+ ret = obj->persistent;
+
+ cleanup:
+ if (obj)
+ virDomainObjUnlock(obj);
+ return ret;
+}
+
+
+static virDriver libxlDriver = {
+ VIR_DRV_LIBXL,
+ "xenlight",
+ libxlOpen, /* open */
+ libxlClose, /* close */
+ NULL, /* supports_feature */
+ libxlGetType, /* type */
+ libxlGetVersion, /* version */
+ NULL, /* libvirtVersion (impl. in libvirt.c) */
+ virGetHostname, /* getHostname */
+ NULL, /* getSysinfo */
+ libxlGetMaxVcpus, /* getMaxVcpus */
+ libxlNodeGetInfo, /* nodeGetInfo */
+ libxlGetCapabilities, /* getCapabilities */
+ libxlListDomains, /* listDomains */
+ libxlNumDomains, /* numOfDomains */
+ libxlDomainCreateXML, /* domainCreateXML */
+ libxlDomainLookupByID, /* domainLookupByID */
+ libxlDomainLookupByUUID, /* domainLookupByUUID */
+ libxlDomainLookupByName, /* domainLookupByName */
+ NULL, /* domainSuspend */
+ NULL, /* domainResume */
+ libxlDomainShutdown, /* domainShutdown */
+ libxlDomainReboot, /* domainReboot */
+ libxlDomainDestroy, /* domainDestroy */
+ NULL, /* domainGetOSType */
+ NULL, /* domainGetMaxMemory */
+ NULL, /* domainSetMaxMemory */
+ NULL, /* domainSetMemory */
+ NULL, /* domainSetMemoryFlags */
+ NULL, /* domainSetMemoryParameters */
+ NULL, /* domainGetMemoryParameters */
+ NULL, /* domainSetBlkioParameters */
+ NULL, /* domainGetBlkioParameters */
+ libxlDomainGetInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainSetVcpusFlags */
+ NULL, /* domainGetVcpusFlags */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+ NULL, /* domainGetMaxVcpus */
+ NULL, /* domainGetSecurityLabel */
+ NULL, /* nodeGetSecurityModel */
+ libxlDomainDumpXML, /* domainDumpXML */
+ NULL, /* domainXmlFromNative */
+ NULL, /* domainXmlToNative */
+ libxlListDefinedDomains, /* listDefinedDomains */
+ libxlNumDefinedDomains, /* numOfDefinedDomains */
+ libxlDomainCreate, /* domainCreate */
+ libxlDomainCreateWithFlags, /* domainCreateWithFlags */
+ libxlDomainDefineXML, /* domainDefineXML */
+ libxlDomainUndefine, /* domainUndefine */
+ NULL, /* domainAttachDevice */
+ NULL, /* domainAttachDeviceFlags */
+ NULL, /* domainDetachDevice */
+ NULL, /* domainDetachDeviceFlags */
+ NULL, /* domainUpdateDeviceFlags */
+ NULL, /* domainGetAutostart */
+ NULL, /* domainSetAutostart */
+ NULL, /* domainGetSchedulerType */
+ NULL, /* domainGetSchedulerParameters */
+ NULL, /* domainSetSchedulerParameters */
+ NULL, /* domainMigratePrepare */
+ NULL, /* domainMigratePerform */
+ NULL, /* domainMigrateFinish */
+ NULL, /* domainBlockStats */
+ NULL, /* domainInterfaceStats */
+ NULL, /* domainMemoryStats */
+ NULL, /* domainBlockPeek */
+ NULL, /* domainMemoryPeek */
+ NULL, /* domainGetBlockInfo */
+ NULL, /* nodeGetCellsFreeMemory */
+ NULL, /* getFreeMemory */
+ NULL, /* domainEventRegister */
+ NULL, /* domainEventDeregister */
+ NULL, /* domainMigratePrepare2 */
+ NULL, /* domainMigrateFinish2 */
+ NULL, /* nodeDeviceDettach */
+ NULL, /* nodeDeviceReAttach */
+ NULL, /* nodeDeviceReset */
+ NULL, /* domainMigratePrepareTunnel */
+ NULL, /* IsEncrypted */
+ NULL, /* IsSecure */
+ libxlDomainIsActive, /* DomainIsActive */
+ libxlDomainIsPersistent, /* DomainIsPersistent */
+ NULL, /* domainIsUpdated */
+ NULL, /* cpuCompare */
+ NULL, /* cpuBaseline */
+ NULL, /* domainGetJobInfo */
+ NULL, /* domainAbortJob */
+ NULL, /* domainMigrateSetMaxDowntime */
+ NULL, /* domainEventRegisterAny */
+ NULL, /* domainEventDeregisterAny */
+ NULL, /* domainManagedSave */
+ NULL, /* domainHasManagedSaveImage */
+ NULL, /* domainManagedSaveRemove */
+ NULL, /* domainSnapshotCreateXML */
+ NULL, /* domainSnapshotDumpXML */
+ NULL, /* domainSnapshotNum */
+ NULL, /* domainSnapshotListNames */
+ NULL, /* domainSnapshotLookupByName */
+ NULL, /* domainHasCurrentSnapshot */
+ NULL, /* domainSnapshotCurrent */
+ NULL, /* domainRevertToSnapshot */
+ NULL, /* domainSnapshotDelete */
+ NULL, /* qemuDomainMonitorCommand */
+ NULL, /* domainOpenConsole */
+};
+
+static virStateDriver libxlStateDriver = {
+ .name = "LIBXL",
+ .initialize = libxlStartup,
+ .cleanup = libxlShutdown,
+ .reload = libxlReload,
+ .active = libxlActive,
+};
+
+
+int
+libxlRegister(void)
+{
+ if (virRegisterDriver(&libxlDriver) < 0)
+ return -1;
+ if (virRegisterStateDriver(&libxlStateDriver) < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/src/libxl/libxl_driver.h b/src/libxl/libxl_driver.h
new file mode 100644
index 0000000..e047552
--- /dev/null
+++ b/src/libxl/libxl_driver.h
@@ -0,0 +1,27 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#ifndef LIBXL_DRIVER_H
+# define LIBXL_DRIVER_H
+
+# include <config.h>
+
+int libxlRegister(void);
+
+#endif /* LIBXL_DRIVER_H */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 8553913..160c953 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -89,6 +89,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
case VIR_FROM_XENAPI:
dom = "XenAPI ";
break;
+ case VIR_FROM_LIBXL:
+ dom = "xenlight ";
+ break;
case VIR_FROM_XML:
dom = "XML ";
break;
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index 7d08df3..bec9577 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -50,6 +50,7 @@
#include "uuid.h"
#include "fdstream.h"
#include "files.h"
+#include "command.h"
#define VIR_FROM_THIS VIR_FROM_XEN
@@ -229,6 +230,26 @@ xenUnifiedProbe (void)
return 0;
}
+#ifdef WITH_LIBXL
+static int
+xenUnifiedXendProbe (void)
+{
+ virCommandPtr cmd;
+ int status;
+ int ret = 0;
+
+ if ((cmd = virCommandNew("/usr/sbin/xend")) != NULL) {
+ virCommandAddArg(cmd, "status");
+ if (virCommandRun(cmd, &status) == 0) {
+ if (status == 0)
+ ret = 1;
+ }
+ virCommandFree(cmd);
+ }
+ return ret;
+}
+#endif
+
static virDrvOpenStatus
xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, int flags)
{
@@ -292,6 +313,13 @@ xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, int
flags)
}
}
+#ifdef WITH_LIBXL
+ /* Decline xen:// URI if xend is not running and libxenlight
+ * driver is potentially available. */
+ if (!xenUnifiedXendProbe())
+ return VIR_DRV_OPEN_DECLINED;
+#endif
+
/* We now know the URI is definitely for this driver, so beyond
* here, don't return DECLINED, always use ERROR */
--
1.7.3.1