[libvirt] [PATCH] doc: Add schema definition for imagelabel
by Osier Yang
---
docs/schemas/domain.rng | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 21c4380..30f673f 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -64,6 +64,9 @@
<element name="label">
<text/>
</element>
+ <element name="imagelabel">
+ <text/>
+ </element>
</element>
</define>
<define name="hvs">
--
1.7.4
13 years, 8 months
[libvirt] [PATCH V6] Add libxenlight driver
by Jim Fehlig
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
13 years, 8 months
[libvirt] [PATCH] update virGetVersion description
by Tiziano Mueller
The current description suggests that you always have to provide
a valid typeVer pointer. But if you want only the libvirt version
it's also possible to set type and typeVer to NULL to skip the
hypervisor part.
---
src/libvirt.c | 11 ++++++-----
1 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c
index e4b451e..a8b48ea 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -863,11 +863,12 @@ int virStateActive(void) {
* @type: the type of connection/driver looked at
* @typeVer: return value for the version of the hypervisor (OUT)
*
- * Provides two information back, @libVer is the version of the library
- * while @typeVer will be the version of the hypervisor type @type against
- * which the library was compiled. If @type is NULL, "Xen" is assumed, if
- * @type is unknown or not available, an error code will be returned and
- * @typeVer will be 0.
+ * Provides two information back: @libVer is the version of the library
+ * and will always be set unless an error occurs, in which case an error
+ * code will be returned. If @typeVer is not NULL it will be set to the
+ * version of the hypervisor @type against which the library was compiled.
+ * If @type is NULL, "Xen" is assumed, if @type is unknown or not
+ * available, an error code will be returned and @typeVer will be 0.
*
* Returns -1 in case of failure, 0 otherwise, and values for @libVer and
* @typeVer have the format major * 1,000,000 + minor * 1,000 + release.
--
1.7.4.1
13 years, 8 months
[libvirt] [PATCH 1/2] Gives a warning when unable to create cgroup for qemu.
by Hu Tao
Signed-off-by: Hu Tao <hutao(a)cn.fujitsu.com>
---
src/qemu/qemu_driver.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c9095bb..a54bfc5 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -520,7 +520,7 @@ qemudStartup(int privileged) {
rc = virCgroupForDriver("qemu", &qemu_driver->cgroup, privileged, 1);
if (rc < 0) {
char buf[1024];
- VIR_INFO("Unable to create cgroup for driver: %s",
+ VIR_WARN("Unable to create cgroup for driver: %s",
virStrerror(-rc, buf, sizeof(buf)));
}
--
1.7.3.1
13 years, 8 months
[libvirt] [PATCH] Don't build libxenlight driver for Xen 4.0
by Jim Fehlig
The libxenlight driver does not build against the tech preview
version of libxenlight in Xen 4.0. Only enable building the
driver against more complete libxenlight found in Xen 4.1.
---
configure.ac | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/configure.ac b/configure.ac
index 9d8862c..12bf0f6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -512,7 +512,7 @@ if test "$with_libxl" != "no" ; then
fi
CFLAGS="$CFLAGS $LIBXL_CFLAGS"
LIBS="$LIBS $LIBXL_LIBS"
- AC_CHECK_LIB([xenlight], [libxl_ctx_init], [
+ AC_CHECK_LIB([xenlight], [libxl_domain_create_new], [
with_libxl=yes
LIBXL_LIBS="$LIBXL_LIBS -lxenlight -lxenstore -lxenctrl -lxenguest -luuid -lutil -lblktapctl"
],[
--
1.7.3.1
13 years, 8 months
[libvirt] [PATCH] qemu: respect locking rules
by Eric Blake
THREADS.txt states that the contents of vm should not be read or
modified while the vm lock is not held, but that the lock must not
be held while performing a monitor command. This fixes all the
offenders that I could find.
* src/qemu/qemu_process.c (qemuProcessStartCPUs)
(qemuProcessInitPasswords, qemuProcessStart): Don't modify or
refer to vm state outside lock.
* src/qemu/qemu_driver.c (qemudDomainHotplugVcpus): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainChangeGraphicsPasswords):
Likewise.
---
Most of these just move the vm manipulation outside the monitor lock.
qemu_hotplug is a case of checking if the vm is active in between two
monitor commands while the monitor lock was not dropped. Technically,
this was wasted - the qemu process might have stopped (independently,
such as from a guest shutdown), but as long as we hold the monitor
lock, the monitor object will react correctly even if the underlying
qemu process goes away in between the two monitor commands. The
alternative would have been to drop monitor lock, regain vm lock, keep
the check that vm is still active but now under the correct lock, then
regain monitor lock and drop vm lock.
My only question is whether qemuProcessStartCPUs needs to be careful
to check if the VM is still active when it regains the vm lock, since
it is possible that the guest shutdown in the window between the
monitor command resuming the CPUs and when the vm lock is regained -
that is, blindly setting vm->state to VIR_DOMAIN_RUNNING seems fishy
if the vm went away during the window. However, when I tested this
under gdb, by setting a breakpoint in that window and causing the
guest to shutdown, it looked like everything recovered gracefully.
And if we do start checking after a monitor exit that the vm is still
active before changing state of the vm object, then we should probably
adopt that convention everywhere.
src/qemu/qemu_driver.c | 12 +++++++-----
src/qemu/qemu_hotplug.c | 7 -------
src/qemu/qemu_process.c | 18 +++++++++++-------
3 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index dac2bf2..c8870b1 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2553,14 +2553,15 @@ static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
int i, rc = 1;
int ret = -1;
int oldvcpus = vm->def->vcpus;
+ int vcpus = oldvcpus;
qemuDomainObjEnterMonitor(vm);
/* We need different branches here, because we want to offline
* in reverse order to onlining, so any partial fail leaves us in a
* reasonably sensible state */
- if (nvcpus > vm->def->vcpus) {
- for (i = vm->def->vcpus ; i < nvcpus ; i++) {
+ if (nvcpus > vcpus) {
+ for (i = vcpus ; i < nvcpus ; i++) {
/* Online new CPU */
rc = qemuMonitorSetCPU(priv->mon, i, 1);
if (rc == 0)
@@ -2568,10 +2569,10 @@ static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
if (rc < 0)
goto cleanup;
- vm->def->vcpus++;
+ vcpus++;
}
} else {
- for (i = vm->def->vcpus - 1 ; i >= nvcpus ; i--) {
+ for (i = vcpus - 1 ; i >= nvcpus ; i--) {
/* Offline old CPU */
rc = qemuMonitorSetCPU(priv->mon, i, 0);
if (rc == 0)
@@ -2579,7 +2580,7 @@ static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
if (rc < 0)
goto cleanup;
- vm->def->vcpus--;
+ vcpus--;
}
}
@@ -2587,6 +2588,7 @@ static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
cleanup:
qemuDomainObjExitMonitor(vm);
+ vm->def->vcpus = vcpus;
qemuAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
return ret;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index e4ba526..e1d9d29 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1836,13 +1836,6 @@ qemuDomainChangeGraphicsPasswords(struct qemud_driver *driver,
if (ret != 0)
goto cleanup;
- if (!virDomainObjIsActive(vm)) {
- ret = -1;
- qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("guest unexpectedly quit"));
- goto cleanup;
- }
-
if (auth->expires) {
time_t lifetime = auth->validTo - now;
if (lifetime <= 0)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 740684a..793a43c 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1008,8 +1008,8 @@ qemuProcessWaitForMonitor(struct qemud_driver* driver,
if (paths == NULL)
goto cleanup;
- qemuDomainObjEnterMonitorWithDriver(driver, vm);
qemuDomainObjPrivatePtr priv = vm->privateData;
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorGetPtyPaths(priv->mon, paths);
qemuDomainObjExitMonitorWithDriver(driver, vm);
@@ -1175,6 +1175,7 @@ qemuProcessInitPasswords(virConnectPtr conn,
for (i = 0 ; i < vm->def->ndisks ; i++) {
char *secret;
size_t secretLen;
+ const char *alias;
if (!vm->def->disks[i]->encryption ||
!vm->def->disks[i]->src)
@@ -1185,10 +1186,9 @@ qemuProcessInitPasswords(virConnectPtr conn,
&secret, &secretLen) < 0)
goto cleanup;
+ alias = vm->def->disks[i]->info.alias;
qemuDomainObjEnterMonitorWithDriver(driver, vm);
- ret = qemuMonitorSetDrivePassphrase(priv->mon,
- vm->def->disks[i]->info.alias,
- secret);
+ ret = qemuMonitorSetDrivePassphrase(priv->mon, alias, secret);
VIR_FREE(secret);
qemuDomainObjExitMonitorWithDriver(driver, vm);
if (ret < 0)
@@ -1727,17 +1727,19 @@ qemuProcessPrepareMonitorChr(struct qemud_driver *driver,
}
-int qemuProcessStartCPUs(struct qemud_driver *driver, virDomainObjPtr vm, virConnectPtr conn)
+int
+qemuProcessStartCPUs(struct qemud_driver *driver, virDomainObjPtr vm,
+ virConnectPtr conn)
{
int ret;
qemuDomainObjPrivatePtr priv = vm->privateData;
qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorStartCPUs(priv->mon, conn);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
if (ret == 0) {
vm->state = VIR_DOMAIN_RUNNING;
}
- qemuDomainObjExitMonitorWithDriver(driver, vm);
return ret;
}
@@ -1901,6 +1903,7 @@ int qemuProcessStart(virConnectPtr conn,
qemuDomainObjPrivatePtr priv = vm->privateData;
virCommandPtr cmd = NULL;
struct qemuProcessHookData hookData;
+ unsigned long cur_balloon;
hookData.conn = conn;
hookData.vm = vm;
@@ -2210,8 +2213,9 @@ int qemuProcessStart(virConnectPtr conn,
}
VIR_DEBUG0("Setting initial memory amount");
+ cur_balloon = vm->def->mem.cur_balloon;
qemuDomainObjEnterMonitorWithDriver(driver, vm);
- if (qemuMonitorSetBalloon(priv->mon, vm->def->mem.cur_balloon) < 0) {
+ if (qemuMonitorSetBalloon(priv->mon, cur_balloon) < 0) {
qemuDomainObjExitMonitorWithDriver(driver, vm);
goto cleanup;
}
--
1.7.4
13 years, 8 months
[libvirt] [PATCH] Disable libxl build in RPM on Fedora < 16
by Daniel P. Berrange
The xen RPM in Fedora isn't new enough to support libxl builds
yet. Disable it until Fedora 16
Q: What actually is the min required Xen ? Is xen 4.0.1
in fact sufficient ? If so I'll change this to s/16/15/
* libvirt.spec.in: Disable libxl on Fedora < 16
---
libvirt.spec.in | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 988ea4e..4a62c80 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -133,6 +133,11 @@
%endif
%endif
+# Fedora doesn't have new enough Xen for libxl until F16
+%if 0%{?fedora} < 16
+%define with_libxl 0
+%endif
+
# PolicyKit was introduced in Fedora 8 / RHEL-6 or newer
%if 0%{?fedora} >= 8 || 0%{?rhel} >= 6
%define with_polkit 0%{!?_without_polkit:1}
--
1.7.4
13 years, 8 months
[libvirt] [PATCH 0/5] Improve detach-device intelligence for net interfaces
by Michal Privoznik
Until now it was possible to device-detach network device by mac address only.
This patch improves libvirt user-friendliness so it is possible to detach
also via PCI address, and in case when there is exactly one network interface
even without specifying redundant addresses (MAC/PCI).
Michal Privoznik (5):
conf: Change statically allocated MAC to dynamic
DomainXMLFlags: Introduce flag allowing suppress of generation of
additional items
virDomainNetDefParseXML: suppress generation of MAC when
VIR_DOMAIN_PARSE_NO_GENERATE is set
qemu: Allow network device-detach by PCI address and/or MAC
xen: Allow network device-detach by PCI address and/or MAC
include/libvirt/libvirt.h.in | 7 ++--
src/conf/domain_conf.c | 9 +++++-
src/conf/domain_conf.h | 2 +-
src/openvz/openvz_conf.c | 3 +-
src/qemu/qemu_command.c | 3 +-
src/qemu/qemu_driver.c | 3 +-
src/qemu/qemu_hotplug.c | 46 +++++++++++++++++++++-------
src/vbox/vbox_tmpl.c | 4 ++-
src/vmx/vmx.c | 3 +-
src/xen/xm_internal.c | 66 +++++++++++++++++++++++++++++++++--------
src/xenxs/xen_sxpr.c | 3 +-
src/xenxs/xen_xm.c | 3 +-
12 files changed, 115 insertions(+), 37 deletions(-)
--
1.7.4
13 years, 8 months