--- 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