[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH V2] Add libxenlight driver



Add a new xen driver based on libxenlight [1], which is the primary
toolstack starting with Xen 4.1.0.  The driver is stateful, runs
privileged only, and is accessed with libxl:/// URI.

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 +
 docs/drivers.html.in        |    3 +-
 docs/drvxen.html.in         |    6 +-
 docs/drvxenlight.html.in    |   53 ++
 docs/sitemap.html.in        |    6 +-
 include/libvirt/virterror.h |    1 +
 po/POTFILES.in              |    2 +
 src/Makefile.am             |   32 ++
 src/driver.h                |    3 +-
 src/libvirt.c               |    4 +
 src/libxl/libxl_conf.c      |  894 ++++++++++++++++++++++++++++++
 src/libxl/libxl_conf.h      |   88 +++
 src/libxl/libxl_driver.c    | 1281 +++++++++++++++++++++++++++++++++++++++++++
 src/libxl/libxl_driver.h    |   27 +
 src/util/virterror.c        |    3 +
 18 files changed, 2458 insertions(+), 4 deletions(-)

diff --git a/cfg.mk b/cfg.mk
index 1bb9cbb..f155ce3 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -401,6 +401,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 bd509f3..9658a68 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([libxenlight: $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 86f024f..1a215f3 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -112,6 +112,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 b2e5e20..6e552f2 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -80,6 +80,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
@@ -928,6 +931,9 @@ static struct qemud_server *qemudInitialize(void) {
 # ifdef WITH_LXC
     lxcRegister();
 # endif
+# ifdef WITH_LIBXL
+    libxlRegister();
+# endif
 # ifdef WITH_UML
     umlRegister();
 # endif
diff --git a/docs/drivers.html.in b/docs/drivers.html.in
index ecad03a..368664e 100644
--- a/docs/drivers.html.in
+++ b/docs/drivers.html.in
@@ -28,7 +28,8 @@
       <li><strong><a href="drvvbox.html">VirtualBox</a></strong></li>
       <li><strong><a href="drvesx.html">VMware ESX</a></strong></li>
       <li><strong><a href="drvvmware.html">VMware 
Workstation/Player</a></strong></li>
-      <li><strong><a href="drvxen.html">Xen</a></strong></li>
+      <li><strong><a href="drvxen.html">Xen 3.0.1 - 4.0.x</a></strong></li>
+      <li><strong><a href="drvxenlight.html">Xen 4.1.0 
onwards</a></strong></li>
     </ul>
 
     <h2><a name="stroage">Storage drivers</a></h2>
diff --git a/docs/drvxen.html.in b/docs/drvxen.html.in
index 4e35afa..4b88a7d 100644
--- a/docs/drvxen.html.in
+++ b/docs/drvxen.html.in
@@ -6,7 +6,11 @@
 
     <p>
       The libvirt Xen driver provides the ability to manage virtual machines
-      on any Xen release from 3.0.1 onwards.
+      on any Xen release from 3.0.1 to 4.0.x.  Starting with Xen 4.1.0,
+      the traditional xm/xend toolstack is replaced with a new toolstack
+      based on libxenlight.  Consult the
+      <a href="drvxenlight.html">libxenlight driver</a> if your Xen host is 
+      configured to use the new toolstack.
     </p>
 
     <h2><a name="prereq">Deployment pre-requisites</a></h2>
diff --git a/docs/drvxenlight.html.in b/docs/drvxenlight.html.in
new file mode 100644
index 0000000..fe60786
--- /dev/null
+++ b/docs/drvxenlight.html.in
@@ -0,0 +1,53 @@
+<html>
+  <body>
+    <h1>libxenlight hypervisor driver</h1>
+
+    <ul id="toc"></ul>
+
+    <p>
+      The libvirt libxenlight driver provides the ability to manage virtual
+      machines on any Xen release from 4.1.0 onwards.
+    </p>
+
+    <h2><a name="prereq">Deployment pre-requisites</a></h2>
+
+    <p>
+      This driver uses Xen's libxenlight toolstack, which is the default
+      toolstack configuration starting with Xen 4.1.0.  The traditional
+      xm/xend toolstack is still provided, but it is no longer maintained
+      and may be removed in a future Xen release.
+    </p>
+
+    <p>
+      The libxenlight toolstack uses xenstored and blktap2.  Ensure
+      xenstored is running, or use the xencommons init script provided.
+      Ensure your kernel supports the blktap2 module and it is loaded.
+    </p>
+
+    <h2><a name="uri">Connections to libxenlight driver</a></h2>
+
+    <p>
+    The libvirt libxenlight driver is a stateful, privileged driver,
+    with a driver name of 'libxl'. Some example conection URIs for
+    the libxenlight driver are:
+    </p>
+
+<pre>
+libxl:///                      (local access, direct)
+libxl://example.com/           (remote access, TLS/x509)
+libxl+tcp://example.com/       (remote access, SASl/Kerberos)
+libxl+ssh://root@xxxxxxxxxxx/  (remote access, SSH tunnelled)
+</pre>
+
+    <h2><a name="xmlconfig">Example domain XML config</a></h2>
+
+    <p>
+      The libxenlight toolstack attempts to be compatible with the
+      legacy xm/xend toolstack, supporting the traditional python
+      configuration files (xen-xm).  Fortunately, the libvirt XML
+      syntax is unchanged with the libxenlight driver.  Consult 
+      the <a href="drvxen.html#xmlconfig">Xen driver examples</a>.
+    </p>
+
+  </body>
+</html>
diff --git a/docs/sitemap.html.in b/docs/sitemap.html.in
index ac0af71..538f227 100644
--- a/docs/sitemap.html.in
+++ b/docs/sitemap.html.in
@@ -156,7 +156,11 @@
             <ul>
               <li>
                 <a href="drvxen.html">Xen</a>
-                <span>Driver the Xen hypervisor</span>
+                <span>Driver the Xen hypervisor, versions 3.0.1 - 4.0.x</span>
+              </li>
+              <li>
+                <a href="drvxenlight.html">libxenlight</a>
+                <span>Driver the Xen hypervisor, version 4.1.0 onwards</span>
               </li>
               <li>
                 <a href="drvqemu.html">QEMU / KVM</a>
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 5962dbf..9f263d2 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -79,6 +79,7 @@ typedef enum {
     VIR_FROM_SYSINFO = 37,     /* Error from sysinfo/SMBIOS */
     VIR_FROM_STREAMS = 38,     /* Error from I/O streams */
     VIR_FROM_VMWARE = 39,      /* Error from VMware driver */
+    VIR_FROM_LIBXL = 40,       /* Error from libxenlight driver */
 } virErrorDomain;
 
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9852f97..64be591 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 bd25b38..2b1f9fc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -297,6 +297,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
@@ -691,6 +695,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
@@ -990,6 +1013,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)                       \
@@ -1244,6 +1268,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"
@@ -1281,6 +1309,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 7451004..b2d9814 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -28,7 +28,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 e4b451e..5e2876b 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, "libxl"))
+            *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..dacb82b
--- /dev/null
+++ b/src/libxl/libxl_conf.c
@@ -0,0 +1,894 @@
+/*---------------------------------------------------------------------------*/
+/*  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/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
+
+
+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 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));
+
+    // TODO: extract pae from phy_info->phys_cap
+    // for now, better default is 1
+    (void)phy_info;
+    host_pae = 1;
+
+    /* 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);
+        /* 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.
+           This is higher than the minimum that Xen would allocate if no value
+           were given (but the Xen minimum is for safety, not performance).
+        */
+        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;
+            }
+        }
+
+        //TODO
+        //x_nics[i].ip = ;
+    }
+
+    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(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;
+
+    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;
+                if (l_vfbs[i]->data.vnc.autoport)
+                    x_vfbs[i].vncunused = 1;
+                else
+                    x_vfbs[i].vncdisplay = l_vfbs[i]->data.vnc.port;
+
+                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;
+    }
+
+    if (def->ngraphics > 0) {
+        if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+            dm_info->vnc = 1;
+            if (def->graphics[0]->data.vnc.listenAddr) {
+                free(dm_info->vnclisten);
+                if ((dm_info->vnclisten =
+                     strdup(def->graphics[0]->data.vnc.listenAddr)) == NULL) {
+                    virReportOOMError();
+                    goto error;
+                }
+            }
+            if (def->graphics[0]->data.vnc.keymap &&
+                (dm_info->keymap =
+                 strdup(def->graphics[0]->data.vnc.keymap)) == NULL) {
+                virReportOOMError();
+                goto error;
+            }
+            if (def->graphics[0]->data.vnc.autoport)
+                dm_info->vncunused = 1;
+            else
+                dm_info->vncdisplay = def->graphics[0]->data.vnc.port;
+            if (def->graphics[0]->data.vnc.auth.passwd &&
+                (dm_info->vncpasswd =
+                 strdup(def->graphics[0]->data.vnc.auth.passwd)) == NULL) {
+                virReportOOMError();
+                goto error;
+            }
+        } else if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+            dm_info->sdl = 1;
+            dm_info->vnc = 0;
+        }
+    } else if (def->ngraphics == 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
+libxlLoadRunningDomains(libxlDriverPrivatePtr driver)
+{
+    libxl_dominfo *domains;
+    int n_domains;
+    int i;
+    int ret = -1;
+    int len;
+    uint8_t *data = NULL;
+    virDomainDefPtr def = NULL;
+    virDomainObjPtr vm = NULL;
+
+    if (!(domains = libxl_list_domain(&driver->ctx, &n_domains))) {
+        libxlError(VIR_ERR_INTERNAL_ERROR,
+                   _("Failed to retrieve domain list from libxenlight"));
+        return -1;
+    }
+
+    for (i = 0; i < n_domains; i++) {
+        /* ignore dom0?? */
+        if (domains[i].domid == 0)
+            continue;
+
+        /* Ignore domains that don't contain libvirtXML */
+        if (libxl_userdata_retrieve(&driver->ctx, domains[i].domid,
+                                    "libvirt-xml", &data, &len)) {
+            libxlError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to retrieve domain userdata from 
libxenlight"));
+            continue;
+        }
+        /* Ensure userdata_retrieve gave us some data */
+        if (len == 0)
+            continue;
+
+        if (!(def = virDomainDefParseString(driver->caps, (char *)data, 0))) {
+            libxlError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to parse userdata from libxenlight"));
+            goto cleanup;
+        }
+
+        if (!(vm = virDomainAssignDef(driver->caps,
+                                      &driver->domains, def, false)))
+            goto cleanup;
+
+        def = NULL;
+        free(data);
+        data = NULL;
+        vm->persistent = 1;
+
+        if (virDomainSaveConfig(driver->configDir,
+                                vm->newDef ? vm->newDef : vm->def) < 0) {
+            virDomainRemoveInactive(&driver->domains, vm);
+            vm = NULL;
+            goto cleanup;
+        }
+        virDomainObjUnlock(vm);
+        vm = NULL;
+    }
+    ret = 0;
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    virDomainDefFree(def);
+    free(data);
+    free(domains);
+    return ret;
+}
+
+int
+libxlBuildDomainConfig(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(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..1c4eff3
--- /dev/null
+++ b/src/libxl/libxl_conf.h
@@ -0,0 +1,88 @@
+/*---------------------------------------------------------------------------*/
+/*  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"
+
+
+# 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;
+
+    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
+libxlLoadRunningDomains(libxlDriverPrivatePtr driver);
+
+int
+libxlBuildDomainConfig(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..d38f5a0
--- /dev/null
+++ b/src/libxl/libxl_driver.c
@@ -0,0 +1,1281 @@
+/*---------------------------------------------------------------------------*/
+/*  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 "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(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->dWaiter) {
+        libxl_free_waiter(priv->dWaiter);
+        VIR_FREE(priv->dWaiter);
+    }
+    libxl_ctx_free(&priv->ctx);
+    VIR_FREE(priv);
+}
+
+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);
+        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);
+        switch (info.shutdown_reason) {
+            case SHUTDOWN_poweroff:
+            case SHUTDOWN_crash:
+                libxl_domain_destroy(&priv->ctx, vm->def->id, 0);
+                if (vm->persistent) {
+                    vm->def->id = -1;
+                    vm->state = VIR_DOMAIN_SHUTOFF;
+                } else {
+                    libxl_free_waiter(priv->dWaiter);
+                    VIR_FREE(priv->dWaiter);
+                    virDomainRemoveInactive(&driver->domains, vm);
+                    vm = NULL;
+                }
+                break;
+            case SHUTDOWN_reboot:
+                libxl_domain_destroy(&priv->ctx, vm->def->id, 0);
+                vm->def->id = -1;
+                vm->state = VIR_DOMAIN_SHUTOFF;
+                libxlVmStart(vm, 0);
+                break;
+            default:
+                VIR_INFO("Unhandled shutdown_reason %d", info.shutdown_reason);
+                break;
+        }
+    }
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    libxl_free_event(&event);
+}
+
+static int
+libxlCreateDomEvents(virDomainObjPtr vm)
+{
+    libxlDomainObjPrivatePtr priv = vm->privateData;
+    int fd;
+
+    /* Do we already have a waiter for this domain? */
+    if (priv->dWaiter == NULL) {
+        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;
+    if ((priv->eventHdl = virEventAddHandle(
+             fd,
+             VIR_EVENT_HANDLE_READABLE | VIR_EVENT_HANDLE_ERROR,
+             libxlEventHandler,
+             vm, NULL)) < 0)
+        goto error;
+
+    return 0;
+
+error:
+    libxl_free_waiter(priv->dWaiter);
+    VIR_FREE(priv->dWaiter);
+    return -1;
+}
+
+static int
+libxlVmStart(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(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;
+    }
+
+    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;
+    }
+    libxl_domain_config_destroy(&d_config);
+    VIR_FREE(dom_xml);
+    return -1;
+}
+
+static int
+libxlShutdown(void)
+{
+    if (!libxl_driver)
+        return -1;
+
+    libxlDriverLock(libxl_driver);
+    virCapabilitiesFree(libxl_driver->caps);
+    libxl_ctx_free(&libxl_driver->ctx);
+    xtl_logger_destroy(libxl_driver->logger);
+    if (libxl_driver->logger_file)
+        VIR_FORCE_FCLOSE(libxl_driver->logger_file);
+
+    virDomainObjListDeinit(&libxl_driver->domains);
+
+    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;
+
+    /* Check that the user is root, silently disable if not */
+    if (!privileged) {
+        VIR_INFO0("Not running privileged, disabling libxenlight driver");
+        return 0;
+    }
+
+    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);
+
+    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;
+
+    /* Get running domains from libxenlight */
+    if (libxlLoadRunningDomains(libxl_driver) < 0)
+        goto error;
+
+    /* 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
+    //libxlAutostartConfigs(libxl_driver);
+
+    return 0;
+
+out_of_memory:
+    virReportOOMError();
+error:
+    VIR_FREE(log_file);
+    if (libxl_driver)
+        libxlDriverUnlock(libxl_driver);
+    libxlShutdown();
+    return -1;
+}
+
+/**
+ * libxlReload:
+ *
+ * Function to restart the libxenligt driver.  Configuration files
+ * will be reloaded and driver state updated.
+ */
+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
+    //libxlAutostartConfigs(libxl_driver);
+
+    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("libxl:///");
+        if (!conn->uri) {
+            virReportOOMError();
+            return VIR_DRV_OPEN_ERROR;
+        }
+    } else {
+        if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme, "libxl"))
+            return VIR_DRV_OPEN_DECLINED;
+
+        /* If server name is given, its for remote driver */
+        if (conn->uri->server != NULL)
+            return VIR_DRV_OPEN_DECLINED;
+
+        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 libxl:///"),
+                       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 "libxl";
+}
+
+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(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 (libxl_domain_destroy(&priv->ctx, dom->id, 1) != 0) {
+        libxlError(VIR_ERR_INTERNAL_ERROR,
+                   _("Failed to destroy domain '%d' with libxenlight"),
+                   dom->id);
+        goto cleanup;
+    }
+
+    /* Direct kill of domain wont be handled in event callback.
+     * Cleanup here. */
+    if (vm->persistent) {
+        vm->def->id = -1;
+        vm->state = VIR_DOMAIN_SHUTOFF;
+    } else {
+        libxl_free_waiter(priv->dWaiter);
+        VIR_FREE(priv->dWaiter);
+        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(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,
+    "libxenlight",
+    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 */
+    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,                       /* domainSetMemoryParameters */
+    NULL,                       /* domainGetMemoryParameters */
+    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 e45b582..c763d92 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 = "libxenlight ";
+            break;
         case VIR_FROM_XML:
             dom = "XML ";
             break;
-- 
1.7.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.