[PATCH 1/3] Add basic libxenlight driver

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

 



---
 src/xenlight/xl_driver.c         |  948 ++++++++++++++++++
 src/xenlight/xl_driver.h         |   46 +
 src/xenlight/xl_driver_private.h |   52 +
 src/xenlight/xl_utils.c          | 1969 ++++++++++++++++++++++++++++++++++++++
 src/xenlight/xl_utils.h          |   90 ++
 5 files changed, 3105 insertions(+), 0 deletions(-)
 create mode 100644 src/xenlight/xl_driver.c
 create mode 100644 src/xenlight/xl_driver.h
 create mode 100644 src/xenlight/xl_driver_private.h
 create mode 100644 src/xenlight/xl_utils.c
 create mode 100644 src/xenlight/xl_utils.h

diff --git a/src/xenlight/xl_driver.c b/src/xenlight/xl_driver.c
new file mode 100644
index 0000000..4278a0c
--- /dev/null
+++ b/src/xenlight/xl_driver.c
@@ -0,0 +1,948 @@
+/*
+ * xl_driver.c: Xen libxl driver
+ *
+ * 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
+ *
+ * Author: Markus GroÃ? <gross@xxxxxxxxxxxxx>
+ *
+ * Based on code from:
+ *    xenapi_driver.c.h, xenapi_utils.c.h, xenapi_driver_private.h:
+ *        Sharadha Prabhakar <sharadha.prabhakar@xxxxxxxxxx>
+ *
+ *    xen_driver.c.h:
+ *        Richard W.M. Jones <rjones@xxxxxxxxxx>
+ *
+ *    xm_internal.c.h:
+ *        Daniel P. Berrange <berrange@xxxxxxxxxx>
+ *
+ *    xend_internal.c.h:
+ *        Anthony Liguori <aliguori@xxxxxxxxxx>
+ *        Daniel Veillard <veillard@xxxxxxxxxx>
+ *
+ *    xl_cmdimpl.c (from xl tool):
+ *        Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
+ *        Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include <stdint.h>
+#include <fcntl.h>
+
+#include "internal.h"
+
+#include "domain_conf.h"
+#include "datatypes.h"
+#include "util.h"
+#include "uuid.h"
+#include "files.h"
+#include "memory.h"
+#include "buf.h"
+#include "logging.h"
+#include "libxl.h"
+#include "libxl_utils.h"
+#include "libxl_uuid.h"
+#include "xentoollog.h"
+#include "xl_driver.h"
+#include "xl_driver_private.h"
+#include "xl_utils.h"
+
+static libxl_ctx ctx;
+
+
+/* xlOpen
+ *
+ * Authenticates and creates a session with the server
+ * Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR. */
+static virDrvOpenStatus xlOpen(virConnectPtr conn,
+                               virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                               int flags ATTRIBUTE_UNUSED)
+{
+    if (conn->uri == NULL || conn->uri->scheme == NULL ||
+        STRCASENEQ(conn->uri->scheme, "XenLight")) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    xl_driver *driver = NULL;
+
+    if (VIR_ALLOC(driver) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if ((driver->caps = xlCreateCapabilities()) == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    driver->logger = xtl_createlogger_stdiostream(stderr, XTL_DEBUG,  0);
+
+    if (libxl_ctx_init(&ctx, LIBXL_VERSION,
+                       (xentoollog_logger*) driver->logger)) {
+        xlError(VIR_DRV_OPEN_ERROR, _("cannot init libxl context"));
+        return VIR_DRV_OPEN_ERROR;
+    }
+
+    driver->ctx = &ctx;
+    conn->privateData = driver;
+
+    return VIR_DRV_OPEN_SUCCESS;
+
+cleanup:
+    VIR_FREE(driver);
+    return VIR_DRV_OPEN_ERROR;
+}
+
+/* xlClose:
+ *
+ * Returns 0 on successfull session logout */
+static int xlClose(virConnectPtr conn)
+{
+    if (conn->privateData) {
+        xl_driver *driver = conn->privateData;
+
+        libxl_ctx_free(driver->ctx);
+        xtl_logger_destroy((xentoollog_logger*) driver->logger);
+
+        virCapabilitiesFree(driver->caps);
+        VIR_FREE(driver);
+
+        conn->privateData = NULL;
+    }
+    return 0;
+}
+
+/* xlType:
+ *
+ * Returns name of the driver */
+static const char * xlType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return "XenLight";
+}
+
+/* xlGetVersion:
+ *
+ * Gets the version of XenLight */
+static int xlGetVersion(virConnectPtr conn, unsigned long *hvVer)
+{
+    const libxl_version_info* ver_info;
+    if (!(ver_info = libxl_get_version_info(connGetXL(conn)))) {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("libxl_get_version_info failed"));
+        *hvVer = 0;
+    } else {
+        *hvVer = 1000000 * ver_info->xen_version_major +
+                    1000 * ver_info->xen_version_minor;
+    }
+    return 0;
+}
+
+/* xlGetMaxVcpus:
+ *
+ * Returns a hardcoded value for Maximum VCPUS */
+static int xlGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
+                         const char *type ATTRIBUTE_UNUSED)
+{
+    return libxl_get_max_cpus(connGetXL(conn));
+}
+
+/* xlNodeGetInfo:
+ *
+ * Returns Node details on success or else -1 */
+static int xlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
+{
+    libxl_physinfo *phy;
+    if (VIR_ALLOC(phy) < 0) {
+      virReportOOMError();
+    } else if (!libxl_get_physinfo(connGetXL(conn), phy)) {
+        const libxl_version_info* ver_info;
+        if (!(ver_info = libxl_get_version_info(connGetXL(conn)))) {
+            xlError(VIR_ERR_INTERNAL_ERROR,
+                    _("libxl_get_version_info failed"));
+        } else {
+            info->memory = phy->total_pages * (ver_info->pagesize / 1024);
+        }
+        // TODO: determine correct cpu model
+        char model[32] = "unavailable";
+        if (virStrcpy(info->model, model, 32) == NULL)
+            xlError(VIR_ERR_INTERNAL_ERROR, _("unable to copy cpu model"));
+        info->nodes = 1;
+        info->cores = phy->cores_per_socket;
+        info->threads = phy->threads_per_core;
+        info->sockets = 1;
+        info->cpus = phy->nr_cpus;
+        info->mhz = phy->cpu_khz / 1000;
+        VIR_FREE(phy);
+        return 0;
+    }
+    return -1;
+}
+
+/* xlGetCapabilities:
+ *
+ * Returns capabilities as an XML string */
+static char * xlGetCapabilities(virConnectPtr conn)
+{
+    xl_driver *driver = conn->privateData;
+    char *xml = NULL;
+
+    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
+        virReportOOMError();
+
+    return xml;
+}
+
+/* xlListDomains
+ *
+ * Collects a list of active domains and stores their id in ids.
+ * The size of ids is stored in maxids.
+ * Returns the number of domains found or -1 in case of an error. */
+static int xlListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+    int nb_domain;
+    libxl_dominfo *doms = libxl_list_domain(connGetXL(conn), &nb_domain);
+    if (doms) {
+        unsigned int i;
+        for (i = 0; i < nb_domain && i < maxids; ++i)
+            ids[i] = doms[i].domid;
+    } else {
+        nb_domain = -1;
+        xlError(VIR_ERR_INTERNAL_ERROR, _("libxl_list_domain failed"));
+    }
+    VIR_FREE(doms);
+    return nb_domain;
+}
+
+/* xlNumDomains
+ *
+ * Returns the number of domains found or -1 in case of an error. */
+static int xlNumDomains(virConnectPtr conn)
+{
+    int nb_domain;
+    libxl_dominfo *doms = libxl_list_domain(connGetXL(conn), &nb_domain);
+    if (!doms) {
+        nb_domain = -1;
+        xlError(VIR_ERR_INTERNAL_ERROR, _("libxl_list_domain failed"));
+    }
+    VIR_FREE(doms);
+    return nb_domain;
+}
+
+/* xlDomainLookupByID
+ *
+ * Returns a valid domain pointer of the domain with ID same as the one passed
+ * or NULL in case of error */
+static virDomainPtr xlDomainLookupByID(virConnectPtr conn, int id)
+{
+    libxl_dominfo *xen_dom;
+    virDomainPtr domPtr = NULL;
+    if (VIR_ALLOC(xen_dom) < 0) {
+        virReportOOMError();
+    } else {
+      if (!libxl_domain_info(connGetXL(conn), xen_dom, id)) {
+          char* name = libxl_domid_to_name(connGetXL(conn), id);
+          domPtr = virGetDomain(conn, name, xen_dom->uuid.uuid);
+          if (domPtr)
+              domPtr->id = id;
+      } else {
+          xlError(VIR_ERR_INTERNAL_ERROR,
+                  _("libxl_domain_info failed for domid: %d"), id);
+      }
+      VIR_FREE(xen_dom);
+    }
+    return domPtr;
+}
+
+/* xlDomainLookupByUUID
+ *
+ * Returns the domain pointer of domain with matching UUID
+ * or -1 in case of error. */
+static virDomainPtr xlDomainLookupByUUID(virConnectPtr conn,
+                                         const unsigned char* uuid)
+{
+    int nb_domain;
+    libxl_dominfo *doms = libxl_list_domain(connGetXL(conn), &nb_domain);
+    if (doms) {
+        int domid = -1;
+        unsigned int i;
+        for (i = 0; i < nb_domain; ++i) {
+            if (memcmp(uuid, doms[i].uuid.uuid, VIR_UUID_BUFLEN) == 0) {
+                domid = doms[i].domid;
+                break;
+            }
+        }
+        VIR_FREE(doms);
+        if (domid >= 0)
+            return xlDomainLookupByID(conn, domid);
+    } else {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("libxl_list_domain failed"));
+    }
+    return NULL;
+}
+
+/* xlDomainLookupByName
+ *
+ * Returns the domain pointer of domain with matching name
+ * or -1 in case of error. */
+static virDomainPtr xlDomainLookupByName(virConnectPtr conn,
+                                         const char *name)
+{
+    int nb_domain;
+    libxl_dominfo *doms = libxl_list_domain(connGetXL(conn), &nb_domain);
+    if (doms) {
+        int domid = -1;
+        unsigned int i;
+        for (i = 0; i < nb_domain; ++i) {
+            char *dom_name = libxl_domid_to_name(connGetXL(conn),
+                                                 doms[i].domid);
+            if (STREQ(name, dom_name)) {
+                domid = doms[i].domid;
+                VIR_FREE(dom_name);
+                break;
+            }
+            VIR_FREE(dom_name);
+        }
+        VIR_FREE(doms);
+        if (domid >= 0)
+            return xlDomainLookupByID(conn, domid);
+    }  else {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("libxl_list_domain failed"));
+    }
+    return NULL;
+}
+
+/* xlDomainSuspend
+ *
+ * Pauses the given domain. Returns 0. */
+static int xlDomainSuspend(virDomainPtr dom)
+{
+    int ret = libxl_domain_pause(domGetXL(dom), domGetID(dom));
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_pause failed for domid: %d"), domGetID(dom));
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainResume
+ *
+ * Unpauses the given domain. Returns 0. */
+static int xlDomainResume(virDomainPtr dom)
+{
+    int ret = libxl_domain_unpause(domGetXL(dom), domGetID(dom));
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_unpause failed for domid: %d"), domGetID(dom));
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainShutdown
+ *
+ * shutsdown a VM
+ * Returns 0 on success or -1 in case of error. */
+static int xlDomainShutdown(virDomainPtr dom)
+{
+    int ret = libxl_domain_shutdown(domGetXL(dom), domGetID(dom), REQ_POWEROFF);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_shutdown (poweroff) failed for domid: %d"),
+                domGetID(dom));
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainReboot
+ *
+ * Reboots a VM
+ * Returns 0 on success or -1 in case of error. */
+static int xlDomainReboot(virDomainPtr dom,
+                          unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int ret = libxl_domain_shutdown(domGetXL(dom), domGetID(dom), REQ_REBOOT);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_shutdown (reboot) failed for domid: %d"),
+                domGetID(dom));
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomaindestroy
+ *
+ * Destroy the given domain.
+ * Returns 0 on success or -1 in case of error. */
+static int xlDomainDestroy(virDomainPtr dom)
+{
+    int ret = libxl_domain_shutdown(domGetXL(dom), domGetID(dom), REQ_HALT);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_shutdown (halt) failed for domid: %d"),
+                domGetID(dom));
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainGetMaxMemory
+ *
+ * Returns maximum static memory for VM on success
+ * or 0 in case of error. */
+static unsigned long xlDomainGetMaxMemory(virDomainPtr dom)
+{
+    libxl_dominfo *xen_dom;
+    unsigned long mem = 0;
+    if (VIR_ALLOC(xen_dom) < 0) {
+        virReportOOMError();
+    } else if (!libxl_domain_info(domGetXL(dom), xen_dom, domGetID(dom))) {
+        mem = xen_dom->max_memkb;
+        VIR_FREE(xen_dom);
+    } else {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_info failed for domid: %d"), domGetID(dom));
+    }
+    return mem;
+}
+
+/* xlDomainSetMaxMemory
+ *
+ * Sets maximum static memory for VM on success
+ * Returns 0 on success or -1 in case of error. */
+static int xlDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
+{
+    int ret = libxl_domain_setmaxmem(domGetXL(dom), domGetID(dom), memory);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_setmaxmem failed for domid: %d"),
+                domGetID(dom));
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainSetMemory
+ *
+ * Sets static memory for VM on success
+ * Returns 0 on success or -1 in case of error. */
+static int xlDomainSetMemory(virDomainPtr dom, unsigned long memory)
+{
+    int ret = libxl_set_memory_target(domGetXL(dom), domGetID(dom), memory, 0,
+                                      /* force */ 1);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_set_memory_target failed for domid: %d"),
+                domGetID(dom));
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainGetInfo:
+ *
+ * Fills a structure with domain information
+ * Returns 0 on success or -1 in case of error. */
+static int xlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
+{
+    int ret = -1;
+    libxl_dominfo *xen_dom;
+    if (VIR_ALLOC(xen_dom) < 0) {
+        virReportOOMError();
+    } else if (!libxl_domain_info(domGetXL(dom), xen_dom, domGetID(dom))) {
+        info->maxMem = xen_dom->max_memkb;
+        info->memory = xen_dom->current_memkb;
+        info->nrVirtCpu = xen_dom->vcpu_max_id + 1;
+        info->cpuTime = xen_dom->cpu_time;
+        if (xen_dom->running)
+            info->state = VIR_DOMAIN_RUNNING;
+        else if (xen_dom->blocked)
+            info->state = VIR_DOMAIN_BLOCKED;
+        else if (xen_dom->paused)
+            info->state = VIR_DOMAIN_PAUSED;
+        else if (xen_dom->shutdown)
+            info->state = VIR_DOMAIN_SHUTOFF;
+        else
+            info->state = VIR_DOMAIN_CRASHED;
+        VIR_FREE(xen_dom);
+        ret = 0;
+    } else {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_info failed for domid: %d"), domGetID(dom));
+    }
+    return ret;
+}
+
+/* xlDomainCoreDump
+ *
+ * This method will dump the core of a domain on a given file for analysis.
+ * Returns 0 in case of success and -1 in case of failure. */
+static int xlDomainCoreDump(virDomainPtr dom, const char * to,
+                            int flags ATTRIBUTE_UNUSED)
+{
+    int ret = libxl_domain_core_dump(domGetXL(dom), domGetID(dom), to);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_core_dump failed for domid: %d"),
+                domGetID(dom));
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainSetVcpus
+ *
+ * Sets the VCPUs on the domain
+ * Return 0 on success or -1 in case of error */
+static int xlDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
+{
+    uint32_t bitmask = 0;
+
+    unsigned int i;
+    for (i = 0; i < nvcpus; ++i)
+        bitmask |= 1 << i;
+
+    int ret = libxl_set_vcpuonline(domGetXL(dom), domGetID(dom), bitmask);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                "libxl_set_vcpuonline failed for domid: %d bitmask: %x",
+                domGetID(dom), bitmask);
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainGetVcpusFlags
+ *
+ * Returns Vcpus count on success or -1 in case of error. */
+static int xlDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
+{
+    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
+        xlError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
+        return -1;
+    }
+    libxl_dominfo *xen_dom;
+    int cpus = -1;
+    if (VIR_ALLOC(xen_dom) < 0) {
+        virReportOOMError();
+    } else if (!libxl_domain_info(domGetXL(dom), xen_dom, domGetID(dom))) {
+        // TODO: check flags
+        cpus = xen_dom->vcpu_max_id + 1;
+        VIR_FREE(xen_dom);
+    } else {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_info failed for domid: %d"), domGetID(dom));
+    }
+    return cpus;
+}
+
+/* xlDomainPinVcpu
+ *
+ * Dynamically change the real CPUs which can be allocated to a virtual CPU
+ * Returns 0 on success or -1 in case of error. */
+static int xlDomainPinVcpu(virDomainPtr dom, unsigned int vcpu,
+                           unsigned char *cpumap, int maplen)
+{
+    libxl_cpumap xlMap;
+    xlMap.size = maplen;
+    xlMap.map = cpumap;
+    int ret = libxl_set_vcpuaffinity(domGetXL(dom), domGetID(dom), vcpu,
+                                     &xlMap);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_set_vcpuaffinity failed for domid: %d vcpu: %d"),
+                domGetID(dom), vcpu);
+        ret = -1;
+    }
+    return ret;
+}
+
+/* xlDomainGetVcpus
+ *
+ * Gets Vcpu information
+ * Return number of structures filled on success or -1 in case of error. */
+static int xlDomainGetVcpus(virDomainPtr dom, virVcpuInfoPtr info, int maxinfo,
+                            unsigned char *cpumaps, int maplen)
+{
+    libxl_vcpuinfo *vcpuinfo;
+    int nb_vcpu, nrcpus;
+
+    vcpuinfo = libxl_list_vcpu(domGetXL(dom), domGetID(dom), &nb_vcpu, &nrcpus);
+
+    if (!vcpuinfo) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_list_vcpu failed for domid: %d"), domGetID(dom));
+        return -1;
+    }
+
+    memset(cpumaps, 0, maplen * maxinfo);
+    unsigned int i = 0;
+    for (i = 0; i < nb_vcpu && i < maxinfo; ++i) {
+        info[i].number = vcpuinfo[i].vcpuid;
+        info[i].cpu = vcpuinfo[i].cpu;
+        info[i].cpuTime = vcpuinfo[i].vcpu_time;
+        info[i].state = VIR_VCPU_OFFLINE;
+        if (vcpuinfo[i].running)
+            info[i].state = VIR_VCPU_RUNNING;
+        else if (vcpuinfo[i].blocked)
+            info[i].state = VIR_VCPU_BLOCKED;
+
+        unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, i);
+        memcpy(cpumap, vcpuinfo[i].cpumap.map,
+               MIN(maplen, vcpuinfo[i].cpumap.size));
+
+        libxl_vcpuinfo_destroy(&vcpuinfo[i]);
+    }
+
+    VIR_FREE(vcpuinfo);
+    return i;
+}
+
+/* xlDomainGetMaxVcpus
+ *
+ * Returns maximum number of Vcpus on success or -1 in case of error. */
+static int xlDomainGetMaxVcpus(virDomainPtr dom)
+{
+    return xlDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
+                                       VIR_DOMAIN_VCPU_MAXIMUM));
+}
+
+/* xlSupportsFeature
+ *
+ * Returns 0. */
+static int xlSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
+{
+    switch (feature) {
+        case VIR_DRV_FEATURE_MIGRATION_V2:
+        case VIR_DRV_FEATURE_MIGRATION_P2P:
+        default:
+            return 0;
+    }
+}
+
+/* xlNodeGetFreeMemory
+ *
+ * provides the free memory available on the Node
+ * Returns memory size on success or 0 in case of error. */
+static unsigned long long xlNodeGetFreeMemory(virConnectPtr conn)
+{
+    unsigned long long freeMem = 0;
+    libxl_physinfo *phy;
+    if (VIR_ALLOC(phy) < 0) {
+      virReportOOMError();
+    } else if (!libxl_get_physinfo(connGetXL(conn), phy)) {
+        const libxl_version_info* ver_info;
+        if (!(ver_info = libxl_get_version_info(connGetXL(conn)))) {
+            xlError(VIR_ERR_INTERNAL_ERROR,
+                    _("libxl_get_version_info failed!"));
+        } else {
+            freeMem = phy->free_pages * (ver_info->pagesize / 1024);
+        }
+        VIR_FREE(phy);
+    } else {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("libxl_get_physinfo failed"));
+    }
+    return freeMem;
+}
+
+/* xlNodeGetCellsFreeMemory
+ *
+ * Returns the number of entries filled in freeMems, or -1 in case of error. */
+static int xlNodeGetCellsFreeMemory(virConnectPtr conn,
+                                    unsigned long long *freeMems,
+                                    int startCell, int maxCells)
+{
+    if (maxCells > 1 && startCell > 0) {
+        xlError(VIR_ERR_NO_SUPPORT, _("GetCellsFreeMemory"));
+        return -1;
+    } else {
+        freeMems[0] = xlNodeGetFreeMemory(conn);
+        return 1;
+    }
+}
+
+/* xlDomainUndefine
+ *
+ * destroys a domain
+ * Return 0 on success or -1 in case of error */
+static int xlDomainUndefine(virDomainPtr dom)
+{
+    int ret = libxl_domain_destroy(domGetXL(dom), domGetID(dom), 1);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_destroy failed for domid: %d"), domGetID(dom));
+    }
+    return ret;
+}
+
+static char * xlDomainGetSchedulerType(virDomainPtr dom, int *nparams)
+{
+    char *result = NULL;
+    *nparams = 0;
+    int sched_id = libxl_get_sched_id(domGetXL(dom));
+    if (!(result = strdup(libxl_schedid_to_name(domGetXL(dom), sched_id))))
+        virReportOOMError();
+    return result;
+}
+
+static int xlDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+/* This method will suspend a domain and save its memory contents to a file on
+ * disk. After the call, if successful, the domain is not listed as running
+ * anymore (this may be a problem). Use virDomainRestore() to restore a domain
+ * after saving.
+ *
+ * Returns 0 in case of success and -1 in case of failure.*/
+static int xlDomainSave(virDomainPtr dom, const char* to)
+{
+    int fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
+    if (fd < 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("creating suspend file failed"));
+        return -1;
+    }
+
+    int ret = libxl_domain_suspend(domGetXL(dom), NULL, domGetID(dom), fd);
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("libxl_domain_suspend failed for domid: %d"),
+                domGetID(dom));
+        ret = -1;
+    } else {
+        ret = libxl_domain_destroy(domGetXL(dom), domGetID(dom), 0);
+        if (ret != 0) {
+            xlError(VIR_ERR_INTERNAL_ERROR,
+                    _("libxl_domain_destroy failed for domid: %d"),
+                    domGetID(dom));
+            ret = -1;
+        }
+    }
+    if (VIR_CLOSE(fd) < 0) {
+      virReportSystemError(errno, "%s", _("failed to close file"));
+    }
+    return ret;
+}
+
+static int xlDomainOpenConsole(virDomainPtr dom,
+                               const char * devname ATTRIBUTE_UNUSED,
+                               virStreamPtr st ATTRIBUTE_UNUSED,
+                               unsigned int flags)
+{
+    // TODO: use virStreamPtr
+    virCheckFlags(0, -1);
+    int ret = libxl_primary_console_exec(domGetXL(dom), domGetID(dom));
+    if (ret != 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("libxl_primary_console_exec failed"));
+        ret = -1;
+    }
+    return ret;
+}
+
+static char * xlDomainXMLFromNative(virConnectPtr conn, const char *format,
+                                    const char *config,
+                                    unsigned int flags ATTRIBUTE_UNUSED)
+{
+    virDomainDefPtr def = NULL;
+    char *ret = NULL;
+    virConfPtr conf = NULL;
+
+    if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
+        conf = virConfReadMem(config, strlen(config), 0);
+        if (!conf)
+            goto cleanup;
+
+        def = xlDomainConfigParse(conn, conf);
+    } else {
+        xlError(VIR_ERR_INVALID_ARG, _("unsupported config type %s"), format);
+        return NULL;
+    }
+
+
+    if (!def)
+        goto cleanup;
+
+    ret = virDomainDefFormat(def, 0);
+
+cleanup:
+    virDomainDefFree(def);
+    if (conf)
+        virConfFree(conf);
+    return ret;
+}
+
+#define MAX_CONFIG_SIZE (1024 * 65)
+static char * xlDomainXMLToNative(virConnectPtr conn, const char *format,
+                                  const char *xmlData,
+                                  unsigned int flags ATTRIBUTE_UNUSED)
+{
+    virDomainDefPtr def = NULL;
+    char *ret = NULL;
+    virConfPtr conf = NULL;
+    xl_driver *driver = conn->privateData;
+
+    if (STRNEQ(format, XEN_CONFIG_FORMAT_XM)) {
+        xlError(VIR_ERR_INVALID_ARG, _("unsupported config type %s"), format);
+        goto cleanup;
+    }
+
+    if (!(def = virDomainDefParseString(driver->caps, xmlData, 0)))
+        goto cleanup;
+
+    if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
+        int len = MAX_CONFIG_SIZE;
+        conf = xlDomainConfigFormat(conn, def);
+        if (!conf)
+            goto cleanup;
+
+        if (VIR_ALLOC_N(ret, len) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (virConfWriteMem(ret, &len, conf) < 0) {
+            VIR_FREE(ret);
+            goto cleanup;
+        }
+    }
+
+cleanup:
+    virDomainDefFree(def);
+    if (conf)
+        virConfFree(conf);
+    return ret;
+}
+
+/* The interface which we export upwards to libvirt.c. */
+static virDriver xlDriver = {
+    VIR_DRV_XENLIGHT,
+    "XenLight",
+    xlOpen, /* open */
+    xlClose, /* close */
+    xlSupportsFeature, /* supports_feature */
+    xlType, /* type */
+    xlGetVersion, /* version */
+    NULL, /* libvirtVersion */
+    virGetHostname, /* getHostname */
+    NULL, /* getSysinfo */
+    xlGetMaxVcpus, /* getMaxVcpus */
+    xlNodeGetInfo, /* nodeGetInfo */
+    xlGetCapabilities, /* getCapabilities */
+    xlListDomains, /* listDomains */
+    xlNumDomains, /* numOfDomains */
+    NULL,//xlDomainCreateXML, /* domainCreateXML */
+    xlDomainLookupByID, /* domainLookupByID */
+    xlDomainLookupByUUID, /* domainLookupByUUID */
+    xlDomainLookupByName, /* domainLookupByName */
+    xlDomainSuspend, /* domainSuspend */
+    xlDomainResume, /* domainResume */
+    xlDomainShutdown, /* domainShutdown */
+    xlDomainReboot, /* domainReboot */
+    xlDomainDestroy, /* domainDestroy */
+    NULL, /* domainGetOSType */
+    xlDomainGetMaxMemory, /* domainGetMaxMemory */
+    xlDomainSetMaxMemory, /* domainSetMaxMemory */
+    xlDomainSetMemory, /* domainSetMemory */
+    xlDomainGetInfo, /* domainGetInfo */
+    xlDomainSave, /* domainSave */
+    NULL, /* domainRestore */
+    xlDomainCoreDump, /* domainCoreDump */
+    xlDomainSetVcpus, /* domainSetVcpus */
+    NULL, /* domainSetVcpusFlags */
+    xlDomainGetVcpusFlags, /* domainGetVcpusFlags */
+    xlDomainPinVcpu, /* domainPinVcpu */
+    xlDomainGetVcpus, /* domainGetVcpus */
+    xlDomainGetMaxVcpus, /* domainGetMaxVcpus */
+    NULL, /* domainGetSecurityLabel */
+    NULL, /* nodeGetSecurityModel */
+    NULL, /* domainDumpXML */
+    xlDomainXMLFromNative, /* domainXmlFromNative */
+    xlDomainXMLToNative, /* domainXmlToNative */
+    NULL, /* listDefinedDomains */
+    NULL, /* numOfDefinedDomains */
+    NULL, /* domainCreate */
+    NULL, /* domainCreateWithFlags */
+    NULL, /* domainDefineXML */
+    xlDomainUndefine, /* domainUndefine */
+    NULL, /* domainAttachDevice */
+    NULL, /* domainAttachDeviceFlags */
+    NULL, /* domainDetachDevice */
+    NULL, /* domainDetachDeviceFlags */
+    NULL, /* domainUpdateDeviceFlags */
+    NULL, /* domainGetAutostart */
+    NULL, /* domainSetAutostart */
+    xlDomainGetSchedulerType, /* domainGetSchedulerType */
+    NULL, /* domainGetSchedulerParameters */
+    NULL, /* domainSetSchedulerParameters */
+    NULL, /* domainMigratePrepare */
+    NULL, /* domainMigratePerform */
+    NULL, /* domainMigrateFinish */
+    NULL, /* domainBlockStats */
+    NULL, /* domainInterfaceStats */
+    NULL, /* domainMemoryStats */
+    NULL, /* domainBlockPeek */
+    NULL, /* domainMemoryPeek */
+    NULL, /* domainGetBlockInfo */
+    xlNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
+    xlNodeGetFreeMemory, /* getFreeMemory */
+    NULL, /* domainEventRegister */
+    NULL, /* domainEventDeregister */
+    NULL, /* domainMigratePrepare2 */
+    NULL, /* domainMigrateFinish2 */
+    NULL, /* nodeDeviceDettach */
+    NULL, /* nodeDeviceReAttach */
+    NULL, /* nodeDeviceReset */
+    NULL, /* domainMigratePrepareTunnel */
+    NULL, /* isEncrypted */
+    NULL, /* isSecure */
+    NULL, /* domainIsActive */
+    NULL, /* domainIsPersistent */
+    xlDomainIsUpdated, /* 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 */
+    xlDomainOpenConsole, /* domainOpenConsole */
+};
+
+/* xlRegister:
+ *
+ * Returns the driver priority or -1 in case of error. */
+int xlRegister(void)
+{
+    return virRegisterDriver(&xlDriver);
+}
diff --git a/src/xenlight/xl_driver.h b/src/xenlight/xl_driver.h
new file mode 100644
index 0000000..a97454c
--- /dev/null
+++ b/src/xenlight/xl_driver.h
@@ -0,0 +1,46 @@
+/*
+ * xl_driver.h: Xen libxl driver
+ *
+ * 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
+ *
+ * Author: Markus GroÃ? <gross@xxxxxxxxxxxxx>
+ *
+ * Based on code from:
+ *    xenapi_driver.c.h, xenapi_utils.c.h, xenapi_driver_private.h:
+ *        Sharadha Prabhakar <sharadha.prabhakar@xxxxxxxxxx>
+ *
+ *    xen_driver.c.h:
+ *        Richard W.M. Jones <rjones@xxxxxxxxxx>
+ *
+ *    xm_internal.c.h:
+ *        Daniel P. Berrange <berrange@xxxxxxxxxx>
+ *
+ *    xend_internal.c.h:
+ *        Anthony Liguori <aliguori@xxxxxxxxxx>
+ *        Daniel Veillard <veillard@xxxxxxxxxx>
+ *
+ *    xl_cmdimpl.c (from xl tool):
+ *        Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
+ *        Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
+ */
+
+#ifndef XL_DRIVER_H
+#define XL_DRIVER_H
+
+extern int xlRegister(void);
+
+#endif
diff --git a/src/xenlight/xl_driver_private.h b/src/xenlight/xl_driver_private.h
new file mode 100644
index 0000000..9fc44ba
--- /dev/null
+++ b/src/xenlight/xl_driver_private.h
@@ -0,0 +1,52 @@
+/*
+ * xl_driver_private.h: Xen libxl driver
+ *
+ * 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
+ *
+ * Author: Markus GroÃ? <gross@xxxxxxxxxxxxx>
+ *
+ * Based on code from:
+ *    xenapi_driver.c.h, xenapi_utils.c.h, xenapi_driver_private.h:
+ *        Sharadha Prabhakar <sharadha.prabhakar@xxxxxxxxxx>
+ *
+ *    xen_driver.c.h:
+ *        Richard W.M. Jones <rjones@xxxxxxxxxx>
+ *
+ *    xm_internal.c.h:
+ *        Daniel P. Berrange <berrange@xxxxxxxxxx>
+ *
+ *    xend_internal.c.h:
+ *        Anthony Liguori <aliguori@xxxxxxxxxx>
+ *        Daniel Veillard <veillard@xxxxxxxxxx>
+ *
+ *    xl_cmdimpl.c (from xl tool):
+ *        Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
+ *        Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
+ */
+
+#ifndef VIR_XENLIGHT_PRIVATE_H
+#define VIR_XENLIGHT_PRIVATE_H
+
+#include "virterror_internal.h"
+
+#define VIR_FROM_THIS VIR_FROM_XENLIGHT
+
+#define xlError(code, ...)                                        \
+        virReportErrorHelper(NULL, VIR_FROM_THIS, code, __FILE__, \
+                             __FUNCTION__, __LINE__, __VA_ARGS__)
+
+#endif
\ No newline at end of file
diff --git a/src/xenlight/xl_utils.c b/src/xenlight/xl_utils.c
new file mode 100644
index 0000000..c00b4d8
--- /dev/null
+++ b/src/xenlight/xl_utils.c
@@ -0,0 +1,1969 @@
+/*
+ * xl_utils.c: Xen libxl driver utility functions
+ *
+ * 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
+ *
+ * Author: Markus GroÃ? <gross@xxxxxxxxxxxxx>
+ *
+ * Based on code from:
+ *    xenapi_driver.c.h, xenapi_utils.c.h, xenapi_driver_private.h:
+ *        Sharadha Prabhakar <sharadha.prabhakar@xxxxxxxxxx>
+ *
+ *    xen_driver.c.h:
+ *        Richard W.M. Jones <rjones@xxxxxxxxxx>
+ *
+ *    xm_internal.c.h:
+ *        Daniel P. Berrange <berrange@xxxxxxxxxx>
+ *
+ *    xend_internal.c.h:
+ *        Anthony Liguori <aliguori@xxxxxxxxxx>
+ *        Daniel Veillard <veillard@xxxxxxxxxx>
+ *
+ *    xl_cmdimpl.c (from xl tool):
+ *        Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
+ *        Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include "xl_utils.h"
+
+#include "datatypes.h"
+#include "uuid.h"
+#include "memory.h"
+#include "count-one-bits.h"
+
+libxl_ctx* connGetXL(virConnectPtr conn)
+{
+    return ((xl_driver*) conn->privateData)->ctx;
+}
+
+libxl_ctx* domGetXL(virDomainPtr dom)
+{
+    return ((xl_driver*) dom->conn->privateData)->ctx;
+}
+
+unsigned int domGetID(virDomainPtr dom)
+{
+    return dom == NULL ? 0 : virDomainGetID(dom);
+}
+
+virCapsPtr xlCreateCapabilities()
+{
+    virCapsPtr caps = virCapabilitiesNew("x86_64", 0, 0);
+    if (!caps) {
+        virReportOOMError();
+        return NULL;
+    }
+    virCapsGuestPtr guest1 = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 0,
+                                                     "", "", 0, NULL);
+    if (!guest1)
+        goto error_cleanup;
+    virCapsGuestDomainPtr dom1 = virCapabilitiesAddGuestDomain(guest1, "xen",
+                                                               "", "", 0,
+                                                               NULL);
+    if (!dom1)
+        goto error_cleanup;
+    virCapsGuestPtr guest2 = virCapabilitiesAddGuest(caps, "xen", "x86_64", 0,
+                                                     "", "", 0, NULL);
+    if (!guest2)
+        goto error_cleanup;
+    virCapsGuestDomainPtr dom2 = virCapabilitiesAddGuestDomain(guest2, "xen",
+                                                               "", "", 0,
+                                                               NULL);
+    if (!dom2)
+        goto error_cleanup;
+
+    return caps;
+
+error_cleanup:
+    virCapabilitiesFree(caps);
+    return NULL;
+}
+
+static int xlConfigSetInt(virConfPtr conf, const char *setting, long l)
+{
+    virConfValuePtr value = NULL;
+
+    if (VIR_ALLOC(value) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    value->type = VIR_CONF_LONG;
+    value->next = NULL;
+    value->l = l;
+
+    return virConfSetValue(conf, setting, value);
+}
+
+static int xlConfigSetString(virConfPtr conf, const char *setting, const char *str)
+{
+    virConfValuePtr value = NULL;
+
+    if (VIR_ALLOC(value) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    value->type = VIR_CONF_STRING;
+    value->next = NULL;
+    if (!(value->str = strdup(str))) {
+        VIR_FREE(value);
+        virReportOOMError();
+        return -1;
+    }
+
+    return virConfSetValue(conf, setting, value);
+}
+
+/* Convenience method to grab a int from the config file object */
+static int xlConfigGetBool(virConfPtr conf, const char *name, int *value,
+                           int def)
+{
+    virConfValuePtr val;
+
+    *value = 0;
+    if (!(val = virConfGetValue(conf, name))) {
+        *value = def;
+        return 0;
+    }
+
+    if (val->type == VIR_CONF_LONG) {
+        *value = val->l ? 1 : 0;
+    } else if (val->type == VIR_CONF_STRING) {
+        *value = STREQ(val->str, "1") ? 1 : 0;
+    } else {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                   _("config value %s was malformed"), name);
+        return -1;
+    }
+    return 0;
+}
+
+
+/* Convenience method to grab a int from the config file object */
+static int xlConfigGetULong(virConfPtr conf, const char *name,
+                            unsigned long *value, int def)
+{
+    virConfValuePtr val;
+
+    *value = 0;
+    if (!(val = virConfGetValue(conf, name))) {
+        *value = def;
+        return 0;
+    }
+
+    if (val->type == VIR_CONF_LONG) {
+        *value = val->l;
+    } else if (val->type == VIR_CONF_STRING) {
+        char *ret;
+        *value = strtol(val->str, &ret, 10);
+        if (ret == val->str) {
+            xlError(VIR_ERR_INTERNAL_ERROR,
+                       _("config value %s was malformed"), name);
+            return -1;
+        }
+    } else {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                   _("config value %s was malformed"), name);
+        return -1;
+    }
+    return 0;
+}
+
+
+/* Convenience method to grab a string from the config file object */
+static int xlConfigGetString(virConfPtr conf, const char *name,
+                             const char **value, const char *def)
+{
+    virConfValuePtr val;
+
+    *value = NULL;
+    if (!(val = virConfGetValue(conf, name))) {
+        *value = def;
+        return 0;
+    }
+
+    if (val->type != VIR_CONF_STRING) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                   _("config value %s was malformed"), name);
+        return -1;
+    }
+    if (!val->str)
+        *value = def;
+    else
+        *value = val->str;
+    return 0;
+}
+
+static int xlConfigCopyStringInternal(virConfPtr conf, const char *name,
+                                      char **value, int allowMissing)
+{
+    virConfValuePtr val;
+
+    *value = NULL;
+    if (!(val = virConfGetValue(conf, name))) {
+        if (allowMissing)
+            return 0;
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                   _("config value %s was missing"), name);
+        return -1;
+    }
+
+    if (val->type != VIR_CONF_STRING) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                   _("config value %s was not a string"), name);
+        return -1;
+    }
+    if (!val->str) {
+        if (allowMissing)
+            return 0;
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                   _("config value %s was missing"), name);
+        return -1;
+    }
+
+    if (!(*value = strdup(val->str))) {
+        virReportOOMError();
+        return -1;
+    }
+
+    return 0;
+}
+
+static int xlConfigCopyString(virConfPtr conf, const char *name, char **value)
+{
+    return xlConfigCopyStringInternal(conf, name, value, 0);
+}
+
+static int xlConfigCopyStringOpt(virConfPtr conf, const char *name, char **value)
+{
+    return xlConfigCopyStringInternal(conf, name, value, 1);
+}
+
+
+/* Convenience method to grab a string UUID from the config file object */
+static int xlConfigGetUUID(virConfPtr conf, const char *name,
+                           unsigned char *uuid)
+{
+    virConfValuePtr val;
+    if (!uuid || !name || !conf)
+        return (-1);
+    if (!(val = virConfGetValue(conf, name))) {
+        return (-1);
+    }
+
+    if (val->type != VIR_CONF_STRING)
+        return (-1);
+    if (!val->str)
+        return (-1);
+
+    if (virUUIDParse(val->str, uuid) < 0)
+        return (-1);
+
+    return (0);
+}
+
+static int xlFormatSxprChr(virDomainChrDefPtr def, virBufferPtr buf)
+{
+    const char *type = virDomainChrTypeToString(def->source.type);
+
+    if (!type) {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("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:
+        virBufferVSprintf(buf, "%s", type);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+        virBufferVSprintf(buf, "%s:", type);
+        virBufferEscapeSexpr(buf, "%s", def->source.data.file.path);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+        virBufferEscapeSexpr(buf, "%s", def->source.data.file.path);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_TCP:
+        virBufferVSprintf(buf, "%s:%s:%s%s",
+                          (def->source.data.tcp.protocol
+                           == VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW ?
+                           "tcp" : "telnet"),
+                          (def->source.data.tcp.host ?
+                           def->source.data.tcp.host : ""),
+                          (def->source.data.tcp.service ?
+                           def->source.data.tcp.service : ""),
+                          (def->source.data.tcp.listen ?
+                           ",server,nowait" : ""));
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_UDP:
+        virBufferVSprintf(buf, "%s:%s:%s@%s:%s", type,
+                          (def->source.data.udp.connectHost ?
+                           def->source.data.udp.connectHost : ""),
+                          (def->source.data.udp.connectService ?
+                           def->source.data.udp.connectService : ""),
+                          (def->source.data.udp.bindHost ?
+                           def->source.data.udp.bindHost : ""),
+                          (def->source.data.udp.bindService ?
+                           def->source.data.udp.bindService : ""));
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_UNIX:
+        virBufferVSprintf(buf, "%s:", type);
+        virBufferEscapeSexpr(buf, "%s", def->source.data.nix.path);
+        if (def->source.data.nix.listen)
+            virBufferAddLit(buf, ",server,nowait");
+        break;
+    }
+
+    if (virBufferError(buf)) {
+        virReportOOMError();
+        return -1;
+    }
+
+    return 0;
+}
+
+static int xlFormatSxprSound(virDomainDefPtr def, virBufferPtr buf)
+{
+    const char *str;
+    int i;
+
+    for (i = 0 ; i < def->nsounds ; i++) {
+        if (!(str = virDomainSoundModelTypeToString(def->sounds[i]->model))) {
+            xlError(VIR_ERR_INTERNAL_ERROR, _("unexpected sound model %d"),
+                    def->sounds[i]->model);
+            return -1;
+        }
+        if (i)
+            virBufferAddChar(buf, ',');
+        virBufferEscapeSexpr(buf, "%s", str);
+    }
+
+    if (virBufferError(buf)) {
+        virReportOOMError();
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static virDomainChrDefPtr xlParseSxprChar(const char *value, const char *tty)
+{
+    const char *prefix;
+    char *tmp;
+    virDomainChrDefPtr def;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    prefix = value;
+
+    if (value[0] == '/') {
+        def->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
+    } else {
+        if ((tmp = strchr(value, ':')) != NULL) {
+            *tmp = '\0';
+            value = tmp + 1;
+        }
+
+        if (STRPREFIX(prefix, "telnet")) {
+            def->source.type = VIR_DOMAIN_CHR_TYPE_TCP;
+            def->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
+        } else {
+            if ((def->source.type = virDomainChrTypeFromString(prefix)) < 0) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                        _("unknown chr device type '%s'"), prefix);
+                goto error;
+            }
+        }
+    }
+
+    /* Compat with legacy  <console tty='/dev/pts/5'/> syntax */
+    switch (def->source.type) {
+    case VIR_DOMAIN_CHR_TYPE_PTY:
+        if (tty != NULL &&
+            !(def->source.data.file.path = strdup(tty)))
+            goto no_memory;
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+        if (!(def->source.data.file.path = strdup(value)))
+            goto no_memory;
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_TCP:
+    {
+        const char *offset = strchr(value, ':');
+        const char *offset2;
+
+        if (offset == NULL) {
+            xlError(VIR_ERR_INTERNAL_ERROR, _("malformed char device string"));
+            goto error;
+        }
+
+        if (offset != value &&
+            (def->source.data.tcp.host = strndup(value,
+                                                 offset - value)) == NULL)
+            goto no_memory;
+
+        offset2 = strchr(offset, ',');
+        if (offset2 == NULL)
+            def->source.data.tcp.service = strdup(offset+1);
+        else
+            def->source.data.tcp.service = strndup(offset+1,
+                                                   offset2-(offset+1));
+        if (def->source.data.tcp.service == NULL)
+            goto no_memory;
+
+        if (offset2 && strstr(offset2, ",server"))
+            def->source.data.tcp.listen = true;
+    }
+    break;
+
+    case VIR_DOMAIN_CHR_TYPE_UDP:
+    {
+        const char *offset = strchr(value, ':');
+        const char *offset2, *offset3;
+
+        if (offset == NULL) {
+            xlError(VIR_ERR_INTERNAL_ERROR, _("malformed char device string"));
+            goto error;
+        }
+
+        if (offset != value &&
+            (def->source.data.udp.connectHost
+             = strndup(value, offset - value)) == NULL)
+            goto no_memory;
+
+        offset2 = strchr(offset, '@');
+        if (offset2 != NULL) {
+            if ((def->source.data.udp.connectService
+                 = strndup(offset + 1, offset2-(offset+1))) == NULL)
+                goto no_memory;
+
+            offset3 = strchr(offset2, ':');
+            if (offset3 == NULL) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                        _("malformed char device string"));
+                goto error;
+            }
+
+            if (offset3 > (offset2 + 1) &&
+                (def->source.data.udp.bindHost
+                 = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL)
+                goto no_memory;
+
+            if ((def->source.data.udp.bindService
+                 = strdup(offset3 + 1)) == NULL)
+                goto no_memory;
+        } else {
+            if ((def->source.data.udp.connectService
+                 = strdup(offset + 1)) == NULL)
+                goto no_memory;
+        }
+    }
+    break;
+
+    case VIR_DOMAIN_CHR_TYPE_UNIX:
+    {
+        const char *offset = strchr(value, ',');
+        if (offset)
+            def->source.data.nix.path = strndup(value, (offset - value));
+        else
+            def->source.data.nix.path = strdup(value);
+        if (def->source.data.nix.path == NULL)
+            goto no_memory;
+
+        if (offset != NULL &&
+            strstr(offset, ",server") != NULL)
+            def->source.data.nix.listen = true;
+    }
+    break;
+    }
+
+    return def;
+
+no_memory:
+    virReportOOMError();
+error:
+    virDomainChrDefFree(def);
+    return NULL;
+}
+
+static int xlParseSxprSound(virDomainDefPtr def, const char *str)
+{
+    if (STREQ(str, "all")) {
+        int i;
+
+        /*
+         * Special compatability code for Xen with a bogus
+         * sound=all in config.
+         *
+         * NB delibrately, don't include all possible
+         * sound models anymore, just the 2 that were
+         * historically present in Xen's QEMU.
+         *
+         * ie just es1370 + sb16.
+         *
+         * Hence use of MODEL_ES1370 + 1, instead of MODEL_LAST
+         */
+
+        if (VIR_ALLOC_N(def->sounds,
+                        VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) < 0)
+            goto no_memory;
+
+
+        for (i = 0 ; i < (VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) ; i++) {
+            virDomainSoundDefPtr sound;
+            if (VIR_ALLOC(sound) < 0)
+                goto no_memory;
+            sound->model = i;
+            def->sounds[def->nsounds++] = sound;
+        }
+    } else {
+        char model[10];
+        const char *offset = str, *offset2;
+
+        do {
+            int len;
+            virDomainSoundDefPtr sound;
+            offset2 = strchr(offset, ',');
+            if (offset2)
+                len = (offset2 - offset);
+            else
+                len = strlen(offset);
+            if (virStrncpy(model, offset, len, sizeof(model)) == NULL) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                        _("Sound model %s too big for destination"), offset);
+                goto error;
+            }
+
+            if (VIR_ALLOC(sound) < 0)
+                goto no_memory;
+
+            if ((sound->model = virDomainSoundModelTypeFromString(model)) < 0) {
+                VIR_FREE(sound);
+                goto error;
+            }
+
+            if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) {
+                virDomainSoundDefFree(sound);
+                goto no_memory;
+            }
+
+            def->sounds[def->nsounds++] = sound;
+            offset = offset2 ? offset2 + 1 : NULL;
+        } while (offset);
+    }
+
+    return 0;
+
+no_memory:
+    virReportOOMError();
+error:
+    return -1;
+}
+
+static int xlConfigFormatDisk(virConfValuePtr list, virDomainDiskDefPtr disk)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    virConfValuePtr val, tmp;
+
+    if(disk->src) {
+        if (disk->driverName) {
+            virBufferVSprintf(&buf, "%s:", disk->driverName);
+            if (STREQ(disk->driverName, "tap"))
+                virBufferVSprintf(&buf, "%s:",
+                                  disk->driverType ? disk->driverType : "aio");
+        } else {
+            switch (disk->type) {
+            case VIR_DOMAIN_DISK_TYPE_FILE:
+                virBufferAddLit(&buf, "file:");
+                break;
+            case VIR_DOMAIN_DISK_TYPE_BLOCK:
+                virBufferAddLit(&buf, "phy:");
+                break;
+            default:
+                xlError(VIR_ERR_INTERNAL_ERROR, _("unsupported disk type %s"),
+                        virDomainDiskTypeToString(disk->type));
+                goto cleanup;
+            }
+        }
+        virBufferVSprintf(&buf, "%s", disk->src);
+    }
+    virBufferAddLit(&buf, ",");
+
+    virBufferVSprintf(&buf, "%s", disk->dst);
+    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
+        virBufferAddLit(&buf, ":cdrom");
+
+    if (disk->readonly)
+        virBufferAddLit(&buf, ",r");
+    else if (disk->shared)
+        virBufferAddLit(&buf, ",!");
+    else
+        virBufferAddLit(&buf, ",w");
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(val) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    val->type = VIR_CONF_STRING;
+    val->str = virBufferContentAndReset(&buf);
+    tmp = list->list;
+    while (tmp && tmp->next)
+        tmp = tmp->next;
+    if (tmp)
+        tmp->next = val;
+    else
+        list->list = val;
+
+    return 0;
+
+cleanup:
+    virBufferFreeAndReset(&buf);
+    return -1;
+}
+
+static int xlConfigFormatNet(virConnectPtr conn, virConfValuePtr list,
+                      virDomainNetDefPtr net, int hvm)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    virConfValuePtr val, tmp;
+
+    virBufferVSprintf(&buf, "mac=%02x:%02x:%02x:%02x:%02x:%02x",
+                      net->mac[0], net->mac[1],
+                      net->mac[2], net->mac[3],
+                      net->mac[4], net->mac[5]);
+
+    switch (net->type) {
+    case VIR_DOMAIN_NET_TYPE_BRIDGE:
+        virBufferVSprintf(&buf, ",bridge=%s", net->data.bridge.brname);
+        if (net->data.bridge.ipaddr)
+            virBufferVSprintf(&buf, ",ip=%s", net->data.bridge.ipaddr);
+        virBufferVSprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
+        break;
+
+    case VIR_DOMAIN_NET_TYPE_ETHERNET:
+        if (net->data.ethernet.script)
+            virBufferVSprintf(&buf, ",script=%s", net->data.ethernet.script);
+        if (net->data.ethernet.ipaddr)
+            virBufferVSprintf(&buf, ",ip=%s", net->data.ethernet.ipaddr);
+        break;
+
+    case VIR_DOMAIN_NET_TYPE_NETWORK:
+    {
+        virNetworkPtr network = virNetworkLookupByName(conn, net->data.network.name);
+        char *bridge;
+        if (!network) {
+            xlError(VIR_ERR_NO_NETWORK, "%s", net->data.network.name);
+            return -1;
+        }
+        bridge = virNetworkGetBridgeName(network);
+        virNetworkFree(network);
+        if (!bridge) {
+            xlError(VIR_ERR_INTERNAL_ERROR, _("network %s is not active"),
+                    net->data.network.name);
+            return -1;
+        }
+
+        virBufferVSprintf(&buf, ",bridge=%s", bridge);
+        virBufferVSprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
+    }
+    break;
+
+    default:
+        xlError(VIR_ERR_INTERNAL_ERROR, _("unsupported network type %d"),
+                net->type);
+        goto cleanup;
+    }
+
+    if (!hvm) {
+        if (net->model != NULL)
+            virBufferVSprintf(&buf, ",model=%s", net->model);
+    }
+    else if (net->model == NULL) {
+    }
+    else if (STREQ(net->model, "netfront")) {
+        virBufferAddLit(&buf, ",type=netfront");
+    }
+    else {
+        virBufferVSprintf(&buf, ",model=%s", net->model);
+        virBufferAddLit(&buf, ",type=ioemu");
+    }
+
+    if (net->ifname)
+        virBufferVSprintf(&buf, ",vifname=%s",
+                          net->ifname);
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(val) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    val->type = VIR_CONF_STRING;
+    val->str = virBufferContentAndReset(&buf);
+    tmp = list->list;
+    while (tmp && tmp->next)
+        tmp = tmp->next;
+    if (tmp)
+        tmp->next = val;
+    else
+        list->list = val;
+
+    return 0;
+
+cleanup:
+    virBufferFreeAndReset(&buf);
+    return -1;
+}
+
+static int xlConfigFormatPCI(virConfPtr conf, virDomainDefPtr def)
+{
+
+    virConfValuePtr pciVal = NULL;
+    int hasPCI = 0;
+    int i;
+
+    for (i = 0 ; i < def->nhostdevs ; i++)
+        if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+            hasPCI = 1;
+
+    if (!hasPCI)
+        return 0;
+
+    if (VIR_ALLOC(pciVal) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    pciVal->type = VIR_CONF_LIST;
+    pciVal->list = NULL;
+
+    for (i = 0 ; i < def->nhostdevs ; i++) {
+        if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
+            virConfValuePtr val, tmp;
+            char *buf;
+
+            if (virAsprintf(&buf, "%04x:%02x:%02x.%x",
+                            def->hostdevs[i]->source.subsys.u.pci.domain,
+                            def->hostdevs[i]->source.subsys.u.pci.bus,
+                            def->hostdevs[i]->source.subsys.u.pci.slot,
+                            def->hostdevs[i]->source.subsys.u.pci.function) < 0) {
+                virReportOOMError();
+                goto error;
+            }
+
+            if (VIR_ALLOC(val) < 0) {
+                VIR_FREE(buf);
+                virReportOOMError();
+                goto error;
+            }
+            val->type = VIR_CONF_STRING;
+            val->str = buf;
+            tmp = pciVal->list;
+            while (tmp && tmp->next)
+                tmp = tmp->next;
+            if (tmp)
+                tmp->next = val;
+            else
+                pciVal->list = val;
+        }
+    }
+
+    if (pciVal->list != NULL) {
+        int ret = virConfSetValue(conf, "pci", pciVal);
+        pciVal = NULL;
+        if (ret < 0)
+            return -1;
+    }
+    VIR_FREE(pciVal);
+
+    return 0;
+
+error:
+    virConfFreeValue(pciVal);
+    return -1;
+}
+
+virConfPtr xlDomainConfigFormat(virConnectPtr conn, virDomainDefPtr def)
+{
+    virConfPtr conf = NULL;
+    int hvm = 0, i;
+    char *cpus = NULL;
+    const char *lifecycle;
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    virConfValuePtr diskVal = NULL;
+    virConfValuePtr netVal = NULL;
+
+    if (!(conf = virConfNew()))
+        goto cleanup;
+
+
+    if (xlConfigSetString(conf, "name", def->name) < 0)
+        goto no_memory;
+
+    virUUIDFormat(def->uuid, uuid);
+    if (xlConfigSetString(conf, "uuid", uuid) < 0)
+        goto no_memory;
+
+    if (xlConfigSetInt(conf, "maxmem", VIR_DIV_UP(def->mem.max_balloon, 1024)) < 0)
+        goto no_memory;
+
+    if (xlConfigSetInt(conf, "memory", VIR_DIV_UP(def->mem.cur_balloon, 1024)) < 0)
+        goto no_memory;
+
+    if (xlConfigSetInt(conf, "vcpus", def->maxvcpus) < 0)
+        goto no_memory;
+    /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
+       either 32, or 64 on a platform where long is big enough.  */
+    if (def->vcpus < def->maxvcpus &&
+        xlConfigSetInt(conf, "vcpu_avail", (1UL << def->vcpus) - 1) < 0)
+        goto no_memory;
+
+    if ((def->cpumask != NULL) &&
+        ((cpus = virDomainCpuSetFormat(def->cpumask,
+                                       def->cpumasklen)) == NULL))
+        goto cleanup;
+
+    if (cpus &&
+        xlConfigSetString(conf, "cpus", cpus) < 0)
+        goto no_memory;
+    VIR_FREE(cpus);
+
+    hvm = STREQ(def->os.type, "hvm") ? 1 : 0;
+
+    if (hvm) {
+        char boot[VIR_DOMAIN_BOOT_LAST+1];
+        if (xlConfigSetString(conf, "builder", "hvm") < 0)
+            goto no_memory;
+
+        if (def->os.loader &&
+            xlConfigSetString(conf, "kernel", def->os.loader) < 0)
+            goto no_memory;
+
+        for (i = 0 ; i < def->os.nBootDevs ; i++) {
+            switch (def->os.bootDevs[i]) {
+            case VIR_DOMAIN_BOOT_FLOPPY:
+                boot[i] = 'a';
+                break;
+            case VIR_DOMAIN_BOOT_CDROM:
+                boot[i] = 'd';
+                break;
+            case VIR_DOMAIN_BOOT_NET:
+                boot[i] = 'n';
+                break;
+            case VIR_DOMAIN_BOOT_DISK:
+            default:
+                boot[i] = 'c';
+                break;
+            }
+        }
+        if (!def->os.nBootDevs) {
+            boot[0] = 'c';
+            boot[1] = '\0';
+        } else {
+            boot[def->os.nBootDevs] = '\0';
+        }
+
+        if (xlConfigSetString(conf, "boot", boot) < 0)
+            goto no_memory;
+
+        if (xlConfigSetInt(conf, "pae",
+                              (def->features &
+                               (1 << VIR_DOMAIN_FEATURE_PAE)) ? 1 : 0) < 0)
+            goto no_memory;
+
+        if (xlConfigSetInt(conf, "acpi",
+                              (def->features &
+                               (1 << VIR_DOMAIN_FEATURE_ACPI)) ? 1 : 0) < 0)
+            goto no_memory;
+
+        if (xlConfigSetInt(conf, "apic",
+                              (def->features &
+                               (1 << VIR_DOMAIN_FEATURE_APIC)) ? 1 : 0) < 0)
+            goto no_memory;
+
+        if (xlConfigSetInt(conf, "hap",
+                              (def->features &
+                               (1 << VIR_DOMAIN_FEATURE_HAP)) ? 1 : 0) < 0)
+            goto no_memory;
+
+        if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
+            if (def->clock.data.timezone) {
+                xlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                        "%s", _("configurable timezones are not supported"));
+                goto cleanup;
+            }
+
+            if (xlConfigSetInt(conf, "localtime", 1) < 0)
+                goto no_memory;
+        } else if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_UTC) {
+            if (xlConfigSetInt(conf, "localtime", 0) < 0)
+                goto no_memory;
+        } else {
+            /* XXX We could support Xen's rtc clock offset */
+            xlError(VIR_ERR_CONFIG_UNSUPPORTED,
+                    _("unsupported clock offset '%s'"),
+                    virDomainClockOffsetTypeToString(def->clock.offset));
+            goto cleanup;
+        }
+
+        /* XXX floppy disks */
+    } else {
+        if (def->os.bootloader &&
+            xlConfigSetString(conf, "bootloader", def->os.bootloader) < 0)
+            goto no_memory;
+        if (def->os.bootloaderArgs &&
+            xlConfigSetString(conf, "bootargs", def->os.bootloaderArgs) < 0)
+            goto no_memory;
+        if (def->os.kernel &&
+            xlConfigSetString(conf, "kernel", def->os.kernel) < 0)
+            goto no_memory;
+        if (def->os.initrd &&
+            xlConfigSetString(conf, "ramdisk", def->os.initrd) < 0)
+            goto no_memory;
+        if (def->os.cmdline &&
+            xlConfigSetString(conf, "extra", def->os.cmdline) < 0)
+            goto no_memory;
+
+    }
+
+    if (!(lifecycle = virDomainLifecycleTypeToString(def->onPoweroff))) {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("unexpected lifecycle action %d"),
+                def->onPoweroff);
+        goto cleanup;
+    }
+    if (xlConfigSetString(conf, "on_poweroff", lifecycle) < 0)
+        goto no_memory;
+
+
+    if (!(lifecycle = virDomainLifecycleTypeToString(def->onReboot))) {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("unexpected lifecycle action %d"),
+                def->onReboot);
+        goto cleanup;
+    }
+    if (xlConfigSetString(conf, "on_reboot", lifecycle) < 0)
+        goto no_memory;
+
+
+    if (!(lifecycle = virDomainLifecycleCrashTypeToString(def->onCrash))) {
+        xlError(VIR_ERR_INTERNAL_ERROR, _("unexpected lifecycle action %d"),
+                def->onCrash);
+        goto cleanup;
+    }
+    if (xlConfigSetString(conf, "on_crash", lifecycle) < 0)
+        goto no_memory;
+
+
+
+    if (hvm) {
+        if (def->emulator &&
+            xlConfigSetString(conf, "device_model", def->emulator) < 0)
+            goto no_memory;
+
+        for (i = 0 ; i < def->ninputs ; i++) {
+            if (def->inputs[i]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
+                if (xlConfigSetInt(conf, "usb", 1) < 0)
+                    goto no_memory;
+                if (xlConfigSetString(conf, "usbdevice",
+                                         def->inputs[i]->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
+                                         "mouse" : "tablet") < 0)
+                    goto no_memory;
+                break;
+            }
+        }
+    }
+
+    if (def->ngraphics == 1) {
+        virConfValuePtr vfb, disp;
+        char *vfbstr = NULL;
+        virBuffer buf = VIR_BUFFER_INITIALIZER;
+        if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+            virBufferAddLit(&buf, "type=sdl");
+            if (def->graphics[0]->data.sdl.display)
+                virBufferVSprintf(&buf, ",display=%s",
+                                    def->graphics[0]->data.sdl.display);
+            if (def->graphics[0]->data.sdl.xauth)
+                virBufferVSprintf(&buf, ",xauthority=%s",
+                                    def->graphics[0]->data.sdl.xauth);
+        } else {
+            virBufferAddLit(&buf, "type=vnc");
+            virBufferVSprintf(&buf, ",vncunused=%d",
+                                def->graphics[0]->data.vnc.autoport ? 1 : 0);
+            if (!def->graphics[0]->data.vnc.autoport)
+                virBufferVSprintf(&buf, ",vncdisplay=%d",
+                                    def->graphics[0]->data.vnc.port - 5900);
+            if (def->graphics[0]->data.vnc.listenAddr)
+                virBufferVSprintf(&buf, ",vnclisten=%s",
+                                    def->graphics[0]->data.vnc.listenAddr);
+            if (def->graphics[0]->data.vnc.auth.passwd)
+                virBufferVSprintf(&buf, ",vncpasswd=%s",
+                                    def->graphics[0]->data.vnc.auth.passwd);
+            if (def->graphics[0]->data.vnc.keymap)
+                virBufferVSprintf(&buf, ",keymap=%s",
+                                    def->graphics[0]->data.vnc.keymap);
+        }
+        if (virBufferError(&buf)) {
+            virBufferFreeAndReset(&buf);
+            goto no_memory;
+        }
+
+        vfbstr = virBufferContentAndReset(&buf);
+
+        if (VIR_ALLOC(vfb) < 0) {
+            VIR_FREE(vfbstr);
+            goto no_memory;
+        }
+
+        if (VIR_ALLOC(disp) < 0) {
+            VIR_FREE(vfb);
+            VIR_FREE(vfbstr);
+            goto no_memory;
+        }
+
+        vfb->type = VIR_CONF_LIST;
+        vfb->list = disp;
+        disp->type = VIR_CONF_STRING;
+        disp->str = vfbstr;
+
+        if (virConfSetValue(conf, "vfb", vfb) < 0)
+            goto no_memory;
+    }
+
+    /* analyze of the devices */
+    if (VIR_ALLOC(diskVal) < 0)
+        goto no_memory;
+    diskVal->type = VIR_CONF_LIST;
+    diskVal->list = NULL;
+
+    for (i = 0 ; i < def->ndisks ; i++) {
+        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
+            continue;
+
+        if (xlConfigFormatDisk(diskVal, def->disks[i]))
+            goto cleanup;
+    }
+    if (diskVal->list != NULL) {
+        int ret = virConfSetValue(conf, "disk", diskVal);
+        diskVal = NULL;
+        if (ret < 0)
+            goto no_memory;
+    }
+    VIR_FREE(diskVal);
+
+    if (VIR_ALLOC(netVal) < 0)
+        goto no_memory;
+    netVal->type = VIR_CONF_LIST;
+    netVal->list = NULL;
+
+    for (i = 0 ; i < def->nnets ; i++) {
+        if (xlConfigFormatNet(conn, netVal,
+                                       def->nets[i],
+                                       hvm) < 0)
+            goto cleanup;
+    }
+    if (netVal->list != NULL) {
+        int ret = virConfSetValue(conf, "vif", netVal);
+        netVal = NULL;
+        if (ret < 0)
+            goto no_memory;
+    }
+    VIR_FREE(netVal);
+
+    if (xlConfigFormatPCI(conf, def) < 0)
+        goto cleanup;
+
+    if (hvm) {
+        if (def->nparallels) {
+            virBuffer buf = VIR_BUFFER_INITIALIZER;
+            char *str;
+            int ret;
+
+            ret = xlFormatSxprChr(def->parallels[0], &buf);
+            str = virBufferContentAndReset(&buf);
+            if (ret == 0)
+                ret = xlConfigSetString(conf, "parallel", str);
+            VIR_FREE(str);
+            if (ret < 0)
+                goto no_memory;
+        } else {
+            if (xlConfigSetString(conf, "parallel", "none") < 0)
+                goto no_memory;
+        }
+
+        if (def->nserials) {
+            virBuffer buf = VIR_BUFFER_INITIALIZER;
+            char *str;
+            int ret;
+
+            ret = xlFormatSxprChr(def->serials[0], &buf);
+            str = virBufferContentAndReset(&buf);
+            if (ret == 0)
+                ret = xlConfigSetString(conf, "serial", str);
+            VIR_FREE(str);
+            if (ret < 0)
+                goto no_memory;
+        } else {
+            if (xlConfigSetString(conf, "serial", "none") < 0)
+                goto no_memory;
+        }
+
+
+        if (def->sounds) {
+            virBuffer buf = VIR_BUFFER_INITIALIZER;
+            char *str = NULL;
+            int ret = xlFormatSxprSound(def, &buf);
+            str = virBufferContentAndReset(&buf);
+            if (ret == 0)
+                ret = xlConfigSetString(conf, "soundhw", str);
+
+            VIR_FREE(str);
+            if (ret < 0)
+                goto no_memory;
+        }
+    }
+
+    return conf;
+
+no_memory:
+    virReportOOMError();
+
+cleanup:
+    virConfFreeValue(diskVal);
+    virConfFreeValue(netVal);
+    VIR_FREE(cpus);
+    if (conf)
+        virConfFree(conf);
+    return (NULL);
+}
+
+#define MAX_VFB 1024
+/*
+ * Turn a config record into a lump of XML describing the
+ * domain, suitable for later feeding for virDomainCreateXML
+ */
+virDomainDefPtr xlDomainConfigParse(virConnectPtr conn, virConfPtr conf)
+{
+    const char *str;
+    int hvm = 0;
+    int val;
+    virConfValuePtr list;
+    xl_driver *driver = conn->privateData;
+    virDomainDefPtr def = NULL;
+    virDomainDiskDefPtr disk = NULL;
+    virDomainNetDefPtr net = NULL;
+    virDomainGraphicsDefPtr graphics = NULL;
+    virDomainHostdevDefPtr hostdev = NULL;
+    int i;
+    const char *defaultArch, *defaultMachine;
+    int vmlocaltime = 0;
+    unsigned long count;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    def->virtType = VIR_DOMAIN_VIRT_XEN;
+    def->id = -1;
+
+    if (xlConfigCopyString(conf, "name", &def->name) < 0)
+        goto cleanup;
+    if (xlConfigGetUUID(conf, "uuid", def->uuid) < 0)
+        goto cleanup;
+
+
+    if ((xlConfigGetString(conf, "builder", &str, "linux") == 0) &&
+        STREQ(str, "hvm"))
+        hvm = 1;
+
+    if (!(def->os.type = strdup(hvm ? "hvm" : "xen")))
+        goto no_memory;
+
+    defaultArch = virCapabilitiesDefaultGuestArch(driver->caps, def->os.type,
+                                                  virDomainVirtTypeToString(def->virtType));
+    if (defaultArch == NULL) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("no supported architecture for os type '%s'"), def->os.type);
+        goto cleanup;
+    }
+    if (!(def->os.arch = strdup(defaultArch)))
+        goto no_memory;
+
+    defaultMachine = virCapabilitiesDefaultGuestMachine(driver->caps,
+                                                        def->os.type,
+                                                        def->os.arch,
+                                                        virDomainVirtTypeToString(def->virtType));
+    if (defaultMachine != NULL) {
+        if (!(def->os.machine = strdup(defaultMachine)))
+            goto no_memory;
+    }
+
+    if (hvm) {
+        const char *boot;
+        if (xlConfigCopyString(conf, "kernel", &def->os.loader) < 0)
+            goto cleanup;
+
+        if (xlConfigGetString(conf, "boot", &boot, "c") < 0)
+            goto cleanup;
+
+        for (i = 0 ; i < VIR_DOMAIN_BOOT_LAST && boot[i] ; i++) {
+            switch (*boot) {
+            case 'a':
+                def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
+                break;
+            case 'd':
+                def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
+                break;
+            case 'n':
+                def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
+                break;
+            case 'c':
+            default:
+                def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
+                break;
+            }
+            def->os.nBootDevs++;
+        }
+    } else {
+        if (xlConfigCopyStringOpt(conf, "bootloader", &def->os.bootloader) < 0)
+            goto cleanup;
+        if (xlConfigCopyStringOpt(conf, "bootargs", &def->os.bootloaderArgs) < 0)
+            goto cleanup;
+
+        if (xlConfigCopyStringOpt(conf, "kernel", &def->os.kernel) < 0)
+            goto cleanup;
+        if (xlConfigCopyStringOpt(conf, "ramdisk", &def->os.initrd) < 0)
+            goto cleanup;
+        if (xlConfigCopyStringOpt(conf, "extra", &def->os.cmdline) < 0)
+            goto cleanup;
+    }
+
+    if (xlConfigGetULong(conf, "memory", &def->mem.cur_balloon,
+                            MIN_XEN_GUEST_SIZE * 2) < 0)
+        goto cleanup;
+
+    if (xlConfigGetULong(conf, "maxmem", &def->mem.max_balloon,
+                            def->mem.cur_balloon) < 0)
+        goto cleanup;
+
+    def->mem.cur_balloon *= 1024;
+    def->mem.max_balloon *= 1024;
+
+    if (xlConfigGetULong(conf, "vcpus", &count, 1) < 0 ||
+        MAX_VIRT_CPUS < count)
+        goto cleanup;
+    def->maxvcpus = count;
+    if (xlConfigGetULong(conf, "vcpu_avail", &count, -1) < 0)
+        goto cleanup;
+    def->vcpus = MIN(count_one_bits_l(count), def->maxvcpus);
+
+    if (xlConfigGetString(conf, "cpus", &str, NULL) < 0)
+        goto cleanup;
+    if (str) {
+        def->cpumasklen = 4096;
+        if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0)
+            goto no_memory;
+
+        if (virDomainCpuSetParse(&str, 0, def->cpumask, def->cpumasklen) < 0)
+            goto cleanup;
+    }
+
+
+    if (xlConfigGetString(conf, "on_poweroff", &str, "destroy") < 0)
+        goto cleanup;
+    if ((def->onPoweroff = virDomainLifecycleTypeFromString(str)) < 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("unexpected value %s for on_poweroff"), str);
+        goto cleanup;
+    }
+
+    if (xlConfigGetString(conf, "on_reboot", &str, "restart") < 0)
+        goto cleanup;
+    if ((def->onReboot = virDomainLifecycleTypeFromString(str)) < 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("unexpected value %s for on_reboot"), str);
+        goto cleanup;
+    }
+
+    if (xlConfigGetString(conf, "on_crash", &str, "restart") < 0)
+        goto cleanup;
+    if ((def->onCrash = virDomainLifecycleCrashTypeFromString(str)) < 0) {
+        xlError(VIR_ERR_INTERNAL_ERROR,
+                _("unexpected value %s for on_crash"), str);
+        goto cleanup;
+    }
+
+
+
+    if (hvm) {
+        if (xlConfigGetBool(conf, "pae", &val, 0) < 0)
+            goto cleanup;
+        else if (val)
+            def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
+        if (xlConfigGetBool(conf, "acpi", &val, 0) < 0)
+            goto cleanup;
+        else if (val)
+            def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI);
+        if (xlConfigGetBool(conf, "apic", &val, 0) < 0)
+            goto cleanup;
+        else if (val)
+            def->features |= (1 << VIR_DOMAIN_FEATURE_APIC);
+        if (xlConfigGetBool(conf, "hap", &val, 0) < 0)
+            goto cleanup;
+        else if (val)
+            def->features |= (1 << VIR_DOMAIN_FEATURE_HAP);
+    }
+    if (xlConfigGetBool(conf, "localtime", &vmlocaltime, 0) < 0)
+        goto cleanup;
+
+    def->clock.offset = vmlocaltime ?
+        VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME :
+        VIR_DOMAIN_CLOCK_OFFSET_UTC;
+
+    if (xlConfigCopyStringOpt(conf, "device_model", &def->emulator) < 0)
+        goto cleanup;
+
+    list = virConfGetValue(conf, "disk");
+    if (list && list->type == VIR_CONF_LIST) {
+        list = list->list;
+        while (list) {
+            char *head;
+            char *offset;
+            char *tmp;
+
+            if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
+                goto skipdisk;
+            head = list->str;
+
+            if (VIR_ALLOC(disk) < 0)
+                goto no_memory;
+
+            /*
+             * Disks have 3 components, SOURCE,DEST-DEVICE,MODE
+             * eg, phy:/dev/HostVG/XenGuest1,xvda,w
+             * The SOURCE is usually prefixed with a driver type,
+             * and optionally driver sub-type
+             * The DEST-DEVICE is optionally post-fixed with disk type
+             */
+
+            /* Extract the source file path*/
+            if (!(offset = strchr(head, ',')))
+                goto skipdisk;
+            if ((offset - head) >= (PATH_MAX-1))
+                goto skipdisk;
+
+            if (offset == head) {
+                disk->src = NULL; /* No source file given, eg CDROM with no media */
+            } else {
+                if (VIR_ALLOC_N(disk->src, (offset - head) + 1) < 0)
+                    goto no_memory;
+                if (virStrncpy(disk->src, head, offset - head,
+                               (offset - head) + 1) == NULL) {
+                    xlError(VIR_ERR_INTERNAL_ERROR,
+                            _("Source file %s too big for destination"), head);
+                    goto cleanup;
+                }
+            }
+            head = offset + 1;
+
+            /* Remove legacy ioemu: junk */
+            if (STRPREFIX(head, "ioemu:"))
+                head = head + 6;
+
+            /* Extract the dest device name */
+            if (!(offset = strchr(head, ',')))
+                goto skipdisk;
+            if (VIR_ALLOC_N(disk->dst, (offset - head) + 1) < 0)
+                goto no_memory;
+            if (virStrncpy(disk->dst, head, offset - head,
+                           (offset - head) + 1) == NULL) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                        _("Dest file %s too big for destination"), head);
+                goto cleanup;
+            }
+            head = offset + 1;
+
+
+            /* Extract source driver type */
+            if (disk->src) {
+                /* The main type  phy:, file:, tap: ... */
+                if ((tmp = strchr(disk->src, ':')) != NULL) {
+                    if (VIR_ALLOC_N(disk->driverName, (tmp - disk->src) + 1) < 0)
+                        goto no_memory;
+                    if (virStrncpy(disk->driverName, disk->src,
+                                   (tmp - disk->src),
+                                   (tmp - disk->src) + 1) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("Driver name %s too big for destination"),
+                                disk->src);
+                        goto cleanup;
+                    }
+
+                    /* Strip the prefix we found off the source file name */
+                    memmove(disk->src, disk->src+(tmp-disk->src)+1,
+                            strlen(disk->src)-(tmp-disk->src));
+                }
+
+                /* And the sub-type for tap:XXX: type */
+                if (disk->driverName &&
+                    STREQ(disk->driverName, "tap")) {
+                    if (!(tmp = strchr(disk->src, ':')))
+                        goto skipdisk;
+                    if (VIR_ALLOC_N(disk->driverType, (tmp - disk->src) + 1) < 0)
+                        goto no_memory;
+                    if (virStrncpy(disk->driverType, disk->src,
+                                   (tmp - disk->src),
+                                   (tmp - disk->src) + 1) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("Driver type %s too big for destination"),
+                                disk->src);
+                        goto cleanup;
+                    }
+
+                    /* Strip the prefix we found off the source file name */
+                    memmove(disk->src, disk->src+(tmp-disk->src)+1,
+                            strlen(disk->src)-(tmp-disk->src));
+                }
+            }
+
+            /* No source, or driver name, so fix to phy: */
+            if (!disk->driverName &&
+                !(disk->driverName = strdup("phy")))
+                goto no_memory;
+
+
+            /* phy: type indicates a block device */
+            disk->type = STREQ(disk->driverName, "phy") ?
+                VIR_DOMAIN_DISK_TYPE_BLOCK : VIR_DOMAIN_DISK_TYPE_FILE;
+
+            /* Check for a :cdrom/:disk postfix */
+            disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+            if ((tmp = strchr(disk->dst, ':')) != NULL) {
+                if (STREQ(tmp, ":cdrom"))
+                    disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
+                tmp[0] = '\0';
+            }
+
+            if (STRPREFIX(disk->dst, "xvd") || !hvm) {
+                disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
+            } else if (STRPREFIX(disk->dst, "sd")) {
+                disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
+            } else {
+                disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
+            }
+
+            if (STREQ(head, "r") ||
+                STREQ(head, "ro"))
+                disk->readonly = 1;
+            else if ((STREQ(head, "w!")) ||
+                     (STREQ(head, "!")))
+                disk->shared = 1;
+
+            /* Maintain list in sorted order according to target device name */
+            if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
+                goto no_memory;
+            def->disks[def->ndisks++] = disk;
+            disk = NULL;
+
+            skipdisk:
+            list = list->next;
+            virDomainDiskDefFree(disk);
+        }
+    }
+
+    list = virConfGetValue(conf, "vif");
+    if (list && list->type == VIR_CONF_LIST) {
+        list = list->list;
+        while (list) {
+            char script[PATH_MAX];
+            char model[10];
+            char type[10];
+            char ip[16];
+            char mac[18];
+            char bridge[50];
+            char vifname[50];
+            char *key;
+
+            bridge[0] = '\0';
+            mac[0] = '\0';
+            script[0] = '\0';
+            ip[0] = '\0';
+            model[0] = '\0';
+            type[0] = '\0';
+            vifname[0] = '\0';
+
+            if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
+                goto skipnic;
+
+            key = list->str;
+            while (key) {
+                char *data;
+                char *nextkey = strchr(key, ',');
+
+                if (!(data = strchr(key, '=')))
+                    goto skipnic;
+                data++;
+
+                if (STRPREFIX(key, "mac=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(mac) - 1;
+                    if (virStrncpy(mac, data, len, sizeof(mac)) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("MAC address %s too big for destination"),
+                                data);
+                        goto skipnic;
+                    }
+                } else if (STRPREFIX(key, "bridge=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(bridge) - 1;
+                    if (virStrncpy(bridge, data, len, sizeof(bridge)) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("Bridge %s too big for destination"), data);
+                        goto skipnic;
+                    }
+                } else if (STRPREFIX(key, "script=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(script) - 1;
+                    if (virStrncpy(script, data, len, sizeof(script)) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("Script %s too big for destination"), data);
+                        goto skipnic;
+                    }
+                } else if (STRPREFIX(key, "model=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(model) - 1;
+                    if (virStrncpy(model, data, len, sizeof(model)) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("Model %s too big for destination"), data);
+                        goto skipnic;
+                    }
+                } else if (STRPREFIX(key, "type=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(type) - 1;
+                    if (virStrncpy(type, data, len, sizeof(type)) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("Type %s too big for destination"), data);
+                        goto skipnic;
+                    }
+                } else if (STRPREFIX(key, "vifname=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(vifname) - 1;
+                    if (virStrncpy(vifname, data, len, sizeof(vifname)) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("Vifname %s too big for destination"), data);
+                        goto skipnic;
+                    }
+                } else if (STRPREFIX(key, "ip=")) {
+                    int len = nextkey ? (nextkey - data) : sizeof(ip) - 1;
+                    if (virStrncpy(ip, data, len, sizeof(ip)) == NULL) {
+                        xlError(VIR_ERR_INTERNAL_ERROR,
+                                _("IP %s too big for destination"), data);
+                        goto skipnic;
+                    }
+                }
+
+                while (nextkey && (nextkey[0] == ',' ||
+                                   nextkey[0] == ' ' ||
+                                   nextkey[0] == '\t'))
+                    nextkey++;
+                key = nextkey;
+            }
+
+            if (VIR_ALLOC(net) < 0)
+                goto no_memory;
+
+            if (mac[0]) {
+                if (virParseMacAddr(mac, net->mac) < 0) {
+                    xlError(VIR_ERR_INTERNAL_ERROR,
+                               _("malformed mac address '%s'"), mac);
+                    goto cleanup;
+                }
+            }
+
+            if (bridge[0] || STREQ(script, "vif-bridge") ||
+                STREQ(script, "vif-vnic")) {
+                net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
+            } else {
+                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+            }
+
+            if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+                if (bridge[0] &&
+                    !(net->data.bridge.brname = strdup(bridge)))
+                    goto no_memory;
+                if (script[0] &&
+                    !(net->data.bridge.script = strdup(script)))
+                    goto no_memory;
+                if (ip[0] &&
+                    !(net->data.bridge.ipaddr = strdup(ip)))
+                    goto no_memory;
+            } else {
+                if (script[0] &&
+                    !(net->data.ethernet.script = strdup(script)))
+                    goto no_memory;
+                if (ip[0] &&
+                    !(net->data.ethernet.ipaddr = strdup(ip)))
+                    goto no_memory;
+            }
+
+            if (model[0] &&
+                !(net->model = strdup(model)))
+                goto no_memory;
+
+            if (!model[0] && type[0] &&
+                STREQ(type, "netfront") &&
+                !(net->model = strdup("netfront")))
+                goto no_memory;
+
+            if (vifname[0] &&
+                !(net->ifname = strdup(vifname)))
+                goto no_memory;
+
+            if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0)
+                goto no_memory;
+            def->nets[def->nnets++] = net;
+            net = NULL;
+
+        skipnic:
+            list = list->next;
+            virDomainNetDefFree(net);
+        }
+    }
+
+    list = virConfGetValue(conf, "pci");
+    if (list && list->type == VIR_CONF_LIST) {
+        list = list->list;
+        while (list) {
+            char domain[5];
+            char bus[3];
+            char slot[3];
+            char func[2];
+            char *key, *nextkey;
+            int domainID;
+            int busID;
+            int slotID;
+            int funcID;
+
+            domain[0] = bus[0] = slot[0] = func[0] = '\0';
+
+            if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
+                goto skippci;
+
+            /* pci=['0000:00:1b.0','0000:00:13.0'] */
+            if (!(key = list->str))
+                goto skippci;
+            if (!(nextkey = strchr(key, ':')))
+                goto skippci;
+
+            if (virStrncpy(domain, key, (nextkey - key), sizeof(domain)) == NULL) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                           _("Domain %s too big for destination"), key);
+                goto skippci;
+            }
+
+            key = nextkey + 1;
+            if (!(nextkey = strchr(key, ':')))
+                goto skippci;
+
+            if (virStrncpy(bus, key, (nextkey - key), sizeof(bus)) == NULL) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                           _("Bus %s too big for destination"), key);
+                goto skippci;
+            }
+
+            key = nextkey + 1;
+            if (!(nextkey = strchr(key, '.')))
+                goto skippci;
+
+            if (virStrncpy(slot, key, (nextkey - key), sizeof(slot)) == NULL) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                           _("Slot %s too big for destination"), key);
+                goto skippci;
+            }
+
+            key = nextkey + 1;
+            if (strlen(key) != 1)
+                goto skippci;
+
+            if (virStrncpy(func, key, 1, sizeof(func)) == NULL) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                           _("Function %s too big for destination"), key);
+                goto skippci;
+            }
+
+            if (virStrToLong_i(domain, NULL, 16, &domainID) < 0)
+                goto skippci;
+            if (virStrToLong_i(bus, NULL, 16, &busID) < 0)
+                goto skippci;
+            if (virStrToLong_i(slot, NULL, 16, &slotID) < 0)
+                goto skippci;
+            if (virStrToLong_i(func, NULL, 16, &funcID) < 0)
+                goto skippci;
+
+            if (VIR_ALLOC(hostdev) < 0)
+                goto no_memory;
+
+            hostdev->managed = 0;
+            hostdev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
+            hostdev->source.subsys.u.pci.domain = domainID;
+            hostdev->source.subsys.u.pci.bus = busID;
+            hostdev->source.subsys.u.pci.slot = slotID;
+            hostdev->source.subsys.u.pci.function = funcID;
+
+            if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0)
+                goto no_memory;
+            def->hostdevs[def->nhostdevs++] = hostdev;
+            hostdev = NULL;
+
+        skippci:
+            list = list->next;
+        }
+    }
+
+    if (hvm) {
+        if (xlConfigGetString(conf, "usbdevice", &str, NULL) < 0)
+            goto cleanup;
+        if (str &&
+            (STREQ(str, "tablet") ||
+             STREQ(str, "mouse"))) {
+            virDomainInputDefPtr input;
+            if (VIR_ALLOC(input) < 0)
+                goto no_memory;
+            input->bus = VIR_DOMAIN_INPUT_BUS_USB;
+            input->type = STREQ(str, "tablet") ?
+                VIR_DOMAIN_INPUT_TYPE_TABLET :
+                VIR_DOMAIN_INPUT_TYPE_MOUSE;
+            if (VIR_ALLOC_N(def->inputs, 1) < 0) {
+                virDomainInputDefFree(input);
+                goto no_memory;
+            }
+            def->inputs[0] = input;
+            def->ninputs = 1;
+        }
+    }
+
+    /* HVM guests, or old PV guests use this config format */
+    if (hvm) {
+        if (xlConfigGetBool(conf, "vnc", &val, 0) < 0)
+            goto cleanup;
+
+        if (val) {
+            if (VIR_ALLOC(graphics) < 0)
+                goto no_memory;
+            graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
+            if (xlConfigGetBool(conf, "vncunused", &val, 1) < 0)
+                goto cleanup;
+            graphics->data.vnc.autoport = val ? 1 : 0;
+
+            if (!graphics->data.vnc.autoport) {
+                unsigned long vncdisplay;
+                if (xlConfigGetULong(conf, "vncdisplay", &vncdisplay, 0) < 0)
+                    goto cleanup;
+                graphics->data.vnc.port = (int)vncdisplay + 5900;
+            }
+            if (xlConfigCopyStringOpt(conf, "vnclisten", &graphics->data.vnc.listenAddr) < 0)
+                goto cleanup;
+            if (xlConfigCopyStringOpt(conf, "vncpasswd", &graphics->data.vnc.auth.passwd) < 0)
+                goto cleanup;
+            if (xlConfigCopyStringOpt(conf, "keymap", &graphics->data.vnc.keymap) < 0)
+                goto cleanup;
+
+            if (VIR_ALLOC_N(def->graphics, 1) < 0)
+                goto no_memory;
+            def->graphics[0] = graphics;
+            def->ngraphics = 1;
+            graphics = NULL;
+        } else {
+            if (xlConfigGetBool(conf, "sdl", &val, 0) < 0)
+                goto cleanup;
+            if (val) {
+                if (VIR_ALLOC(graphics) < 0)
+                    goto no_memory;
+                graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
+                if (xlConfigCopyStringOpt(conf, "display", &graphics->data.sdl.display) < 0)
+                    goto cleanup;
+                if (xlConfigCopyStringOpt(conf, "xauthority", &graphics->data.sdl.xauth) < 0)
+                    goto cleanup;
+                if (VIR_ALLOC_N(def->graphics, 1) < 0)
+                    goto no_memory;
+                def->graphics[0] = graphics;
+                def->ngraphics = 1;
+                graphics = NULL;
+            }
+        }
+    }
+
+    if (!hvm && def->graphics == NULL) { /* New PV guests use this format */
+        list = virConfGetValue(conf, "vfb");
+        if (list && list->type == VIR_CONF_LIST &&
+            list->list && list->list->type == VIR_CONF_STRING &&
+            list->list->str) {
+            char vfb[MAX_VFB];
+            char *key = vfb;
+
+            if (virStrcpyStatic(vfb, list->list->str) == NULL) {
+                xlError(VIR_ERR_INTERNAL_ERROR,
+                           _("VFB %s too big for destination"),
+                           list->list->str);
+                goto cleanup;
+            }
+
+            if (VIR_ALLOC(graphics) < 0)
+                goto no_memory;
+
+            if (strstr(key, "type=sdl"))
+                graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
+            else
+                graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
+
+            while (key) {
+                char *nextkey = strchr(key, ',');
+                char *end = nextkey;
+                if (nextkey) {
+                    *end = '\0';
+                    nextkey++;
+                }
+
+                if (!strchr(key, '='))
+                    break;
+
+                if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+                    if (STRPREFIX(key, "vncunused=")) {
+                        if (STREQ(key + 10, "1"))
+                            graphics->data.vnc.autoport = 1;
+                    } else if (STRPREFIX(key, "vnclisten=")) {
+                        if (!(graphics->data.vnc.listenAddr = strdup(key + 10)))
+                            goto no_memory;
+                    } else if (STRPREFIX(key, "vncpasswd=")) {
+                        if (!(graphics->data.vnc.auth.passwd = strdup(key + 10)))
+                            goto no_memory;
+                    } else if (STRPREFIX(key, "keymap=")) {
+                        if (!(graphics->data.vnc.keymap = strdup(key + 7)))
+                            goto no_memory;
+                    } else if (STRPREFIX(key, "vncdisplay=")) {
+                        graphics->data.vnc.port = strtol(key+11, NULL, 10) + 5900;
+                    }
+                } else {
+                    if (STRPREFIX(key, "display=")) {
+                        if (!(graphics->data.sdl.display = strdup(key + 8)))
+                            goto no_memory;
+                    } else if (STRPREFIX(key, "xauthority=")) {
+                        if (!(graphics->data.sdl.xauth = strdup(key + 11)))
+                            goto no_memory;
+                    }
+                }
+
+                while (nextkey && (nextkey[0] == ',' ||
+                                   nextkey[0] == ' ' ||
+                                   nextkey[0] == '\t'))
+                    nextkey++;
+                key = nextkey;
+            }
+            if (VIR_ALLOC_N(def->graphics, 1) < 0)
+                goto no_memory;
+            def->graphics[0] = graphics;
+            def->ngraphics = 1;
+            graphics = NULL;
+        }
+    }
+
+    if (hvm) {
+        virDomainChrDefPtr chr = NULL;
+
+        if (xlConfigGetString(conf, "parallel", &str, NULL) < 0)
+            goto cleanup;
+        if (str && STRNEQ(str, "none") &&
+            !(chr = xlParseSxprChar(str, NULL)))
+            goto cleanup;
+
+        if (chr) {
+            if (VIR_ALLOC_N(def->parallels, 1) < 0) {
+                virDomainChrDefFree(chr);
+                goto no_memory;
+            }
+            chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
+            def->parallels[0] = chr;
+            def->nparallels++;
+            chr = NULL;
+        }
+
+        if (xlConfigGetString(conf, "serial", &str, NULL) < 0)
+            goto cleanup;
+        if (str && STRNEQ(str, "none") &&
+            !(chr = xlParseSxprChar(str, NULL)))
+            goto cleanup;
+
+        if (chr) {
+            if (VIR_ALLOC_N(def->serials, 1) < 0) {
+                virDomainChrDefFree(chr);
+                goto no_memory;
+            }
+            chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
+            def->serials[0] = chr;
+            def->nserials++;
+        }
+    } else {
+        if (!(def->console = xlParseSxprChar("pty", NULL)))
+            goto cleanup;
+        def->console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
+        def->console->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
+    }
+
+    if (hvm) {
+        if (xlConfigGetString(conf, "soundhw", &str, NULL) < 0)
+            goto cleanup;
+
+        if (str &&
+            xlParseSxprSound(def, str) < 0)
+            goto cleanup;
+    }
+
+    return def;
+
+no_memory:
+    virReportOOMError();
+    /* fallthrough */
+cleanup:
+    virDomainGraphicsDefFree(graphics);
+    virDomainNetDefFree(net);
+    virDomainDiskDefFree(disk);
+    virDomainDefFree(def);
+    return NULL;
+}
diff --git a/src/xenlight/xl_utils.h b/src/xenlight/xl_utils.h
new file mode 100644
index 0000000..d4a858f
--- /dev/null
+++ b/src/xenlight/xl_utils.h
@@ -0,0 +1,90 @@
+/*
+ * xl_utils.h: Xen libxl driver utility functions
+ *
+ * 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
+ *
+ * Author: Markus GroÃ? <gross@xxxxxxxxxxxxx>
+ *
+ * Based on code from:
+ *    xenapi_driver.c.h, xenapi_utils.c.h, xenapi_driver_private.h:
+ *        Sharadha Prabhakar <sharadha.prabhakar@xxxxxxxxxx>
+ *
+ *    xen_driver.c.h:
+ *        Richard W.M. Jones <rjones@xxxxxxxxxx>
+ *
+ *    xm_internal.c.h:
+ *        Daniel P. Berrange <berrange@xxxxxxxxxx>
+ *
+ *    xend_internal.c.h:
+ *        Anthony Liguori <aliguori@xxxxxxxxxx>
+ *        Daniel Veillard <veillard@xxxxxxxxxx>
+ *
+ *    xl_cmdimpl.c (from xl tool):
+ *        Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
+ *        Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
+ */
+
+#ifndef XL_UTILS_H
+#define XL_UTILS_H
+
+#include "conf.h"
+#include "domain_conf.h"
+
+#include "libxl.h"
+#include "libxl_utils.h"
+
+#include "xl_driver_private.h"
+
+typedef struct {
+    libxl_ctx* ctx;
+    xentoollog_logger_stdiostream *logger;
+    virCapsPtr caps;
+} xl_driver;
+
+#define REQ_POWEROFF 0
+#define REQ_REBOOT   1
+#define REQ_HALT     4
+
+/* xen-unstable changeset 19788 removed MAX_VIRT_CPUS from public
+ * headers.  Its semantic was retained with XEN_LEGACY_MAX_VCPUS.
+ * Ensure MAX_VIRT_CPUS is defined accordingly.
+ */
+#if !defined(MAX_VIRT_CPUS) && defined(XEN_LEGACY_MAX_VCPUS)
+    #define MAX_VIRT_CPUS XEN_LEGACY_MAX_VCPUS
+#endif
+
+#define MIN_XEN_GUEST_SIZE 64  /* 64 megabytes */
+
+#define XEN_CONFIG_FORMAT_XM    "xen-xm"
+
+#ifdef __sun
+    #define DEFAULT_VIF_SCRIPT "vif-vnic"
+#else
+    #define DEFAULT_VIF_SCRIPT "vif-bridge"
+#endif
+
+libxl_ctx* connGetXL(virConnectPtr conn);
+libxl_ctx* domGetXL(virDomainPtr dom);
+
+unsigned int domGetID(virDomainPtr dom);
+
+virCapsPtr xlCreateCapabilities(void);
+
+virConfPtr xlDomainConfigFormat(virConnectPtr conn, virDomainDefPtr def);
+virDomainDefPtr xlDomainConfigParse(virConnectPtr conn, virConfPtr conf);
+
+#endif
--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]