/* * xen_driver.c: Unified Xen driver. * * Copyright (C) 2007-2013 Red Hat, Inc. * * 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, see * . * * Richard W.M. Jones */ #include /* Note: * * This driver provides a unified interface to the five * separate underlying Xen drivers (xen_internal, * xend_internal, xs_internal and xm_internal). Historically * the body of libvirt.c handled the five Xen drivers, * and contained Xen-specific code. */ #include #include #include #include #include #include #include #include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "xen_driver.h" #include "xen_sxpr.h" #include "xen_xm.h" #include "xen_hypervisor.h" #include "xend_internal.h" #include "xs_internal.h" #include "xm_internal.h" #if WITH_XEN_INOTIFY # include "xen_inotify.h" #endif #include "virxml.h" #include "viralloc.h" #include "node_device_conf.h" #include "virpci.h" #include "viruuid.h" #include "fdstream.h" #include "virfile.h" #include "viruri.h" #include "vircommand.h" #include "virnodesuspend.h" #include "nodeinfo.h" #include "configmake.h" #include "virstring.h" #include "viraccessapicheck.h" #define VIR_FROM_THIS VIR_FROM_XEN #define XEN_SAVE_DIR LOCALSTATEDIR "/lib/libvirt/xen/save" static int xenUnifiedNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info); static int xenUnifiedDomainGetVcpusFlagsInternal(virDomainPtr dom, virDomainDefPtr def, unsigned int flags); static int xenUnifiedDomainGetVcpusInternal(virDomainPtr dom, virDomainDefPtr def, virVcpuInfoPtr info, int maxinfo, unsigned char *cpumaps, int maplen); static bool is_privileged = false; static virSysinfoDefPtr hostsysinfo = NULL; static virDomainDefPtr xenGetDomainDefForID(virConnectPtr conn, int id) { virDomainDefPtr ret; ret = xenHypervisorLookupDomainByID(conn, id); if (!ret && virGetLastError() == NULL) virReportError(VIR_ERR_NO_DOMAIN, __FUNCTION__); return ret; } static virDomainDefPtr xenGetDomainDefForName(virConnectPtr conn, const char *name) { xenUnifiedPrivatePtr priv = conn->privateData; virDomainDefPtr ret; ret = xenDaemonLookupByName(conn, name); /* Try XM for inactive domains. */ if (!ret && priv->xendConfigVersion <= XEND_CONFIG_VERSION_3_0_3) ret = xenXMDomainLookupByName(conn, name); if (!ret && virGetLastError() == NULL) virReportError(VIR_ERR_NO_DOMAIN, __FUNCTION__); return ret; } static virDomainDefPtr xenGetDomainDefForUUID(virConnectPtr conn, const unsigned char *uuid) { xenUnifiedPrivatePtr priv = conn->privateData; virDomainDefPtr ret; ret = xenHypervisorLookupDomainByUUID(conn, uuid); /* Try XM for inactive domains. */ if (!ret) { if (priv->xendConfigVersion <= XEND_CONFIG_VERSION_3_0_3) ret = xenXMDomainLookupByUUID(conn, uuid); else ret = xenDaemonLookupByUUID(conn, uuid); } if (!ret && virGetLastError() == NULL) virReportError(VIR_ERR_NO_DOMAIN, __FUNCTION__); return ret; } static virDomainDefPtr xenGetDomainDefForDom(virDomainPtr dom) { /* UUID lookup is more efficient than name lookup */ return xenGetDomainDefForUUID(dom->conn, dom->uuid); } /** * xenNumaInit: * @conn: pointer to the hypervisor connection * * Initializer for previous variables. We currently assume that * the number of physical CPU and the number of NUMA cell is fixed * until reboot which might be false in future Xen implementations. */ static void xenNumaInit(virConnectPtr conn) { virNodeInfo nodeInfo; xenUnifiedPrivatePtr priv; int ret; ret = xenUnifiedNodeGetInfo(conn, &nodeInfo); if (ret < 0) return; priv = conn->privateData; priv->nbNodeCells = nodeInfo.nodes; priv->nbNodeCpus = nodeInfo.cpus; } /** * xenDomainUsedCpus: * @dom: the domain * @def: the domain definition * * Analyze which set of CPUs are used by the domain and * return a string providing the ranges. * * Returns the string which needs to be freed by the caller or * NULL if the domain uses all CPU or in case of error. */ char * xenDomainUsedCpus(virDomainPtr dom, virDomainDefPtr def) { char *res = NULL; int ncpus; int nb_vcpu; virBitmapPtr cpulist = NULL; unsigned char *cpumap = NULL; size_t cpumaplen; int nb = 0; int n, m; virVcpuInfoPtr cpuinfo = NULL; virNodeInfo nodeinfo; xenUnifiedPrivatePtr priv; if (!VIR_IS_CONNECTED_DOMAIN(dom)) return NULL; priv = dom->conn->privateData; if (priv->nbNodeCpus <= 0) return NULL; nb_vcpu = xenUnifiedDomainGetVcpusFlagsInternal(dom, def, (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)); if (nb_vcpu <= 0) return NULL; if (xenUnifiedNodeGetInfo(dom->conn, &nodeinfo) < 0) return NULL; if (!(cpulist = virBitmapNew(priv->nbNodeCpus))) goto done; if (VIR_ALLOC_N(cpuinfo, nb_vcpu) < 0) goto done; cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); if (xalloc_oversized(nb_vcpu, cpumaplen) || VIR_ALLOC_N(cpumap, nb_vcpu * cpumaplen) < 0) goto done; if ((ncpus = xenUnifiedDomainGetVcpusInternal(dom, def, cpuinfo, nb_vcpu, cpumap, cpumaplen)) >= 0) { for (n = 0; n < ncpus; n++) { for (m = 0; m < priv->nbNodeCpus; m++) { bool used; ignore_value(virBitmapGetBit(cpulist, m, &used)); if ((!used) && (VIR_CPU_USABLE(cpumap, cpumaplen, n, m))) { ignore_value(virBitmapSetBit(cpulist, m)); nb++; /* if all CPU are used just return NULL */ if (nb == priv->nbNodeCpus) goto done; } } } res = virBitmapFormat(cpulist); } done: virBitmapFree(cpulist); VIR_FREE(cpumap); VIR_FREE(cpuinfo); return res; } static int xenUnifiedStateInitialize(bool privileged, virStateInhibitCallback callback ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED) { /* Don't allow driver to work in non-root libvirtd */ if (privileged) { is_privileged = true; hostsysinfo = virSysinfoRead(); } return 0; } static int xenUnifiedStateCleanup(void) { virSysinfoDefFree(hostsysinfo); return 0; } static virStateDriver state_driver = { .name = "Xen", .stateInitialize = xenUnifiedStateInitialize, .stateCleanup = xenUnifiedStateCleanup, }; /*----- Dispatch functions. -----*/ /* These dispatch functions follow the model used historically * by libvirt.c -- trying each low-level Xen driver in turn * until one succeeds. However since we know what low-level * drivers can perform which functions, it is probably better * in future to optimise these dispatch functions to just call * the single function (or small number of appropriate functions) * in the low level drivers directly. */ static int xenUnifiedProbe(void) { #ifdef __linux__ if (virFileExists("/proc/xen")) return 1; #endif #ifdef __sun int fd; if ((fd = open("/dev/xen/domcaps", O_RDONLY)) >= 0) { VIR_FORCE_CLOSE(fd); return 1; } #endif return 0; } #ifdef WITH_LIBXL static int xenUnifiedXendProbe(void) { virCommandPtr cmd; int status; int ret = 0; cmd = virCommandNewArgList("/usr/sbin/xend", "status", NULL); if (virCommandRun(cmd, &status) == 0 && status == 0) ret = 1; virCommandFree(cmd); return ret; } #endif static int xenDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, const virDomainDef *def, virCapsPtr caps ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED) { if (dev->type == VIR_DOMAIN_DEVICE_CHR && dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE && STRNEQ(def->os.type, "hvm")) dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN; return 0; } static int xenDomainDefPostParse(virDomainDefPtr def, virCapsPtr caps ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED) { if (!def->memballoon) { virDomainMemballoonDefPtr memballoon; if (VIR_ALLOC(memballoon) < 0) return -1; memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_XEN; def->memballoon = memballoon; } return 0; } virDomainDefParserConfig xenDomainDefParserConfig = { .macPrefix = { 0x00, 0x16, 0x3e }, .devicesPostParseCallback = xenDomainDeviceDefPostParse, .domainPostParseCallback = xenDomainDefPostParse, }; virDomainXMLOptionPtr xenDomainXMLConfInit(void) { return virDomainXMLOptionNew(&xenDomainDefParserConfig, NULL, NULL); } static virDrvOpenStatus xenUnifiedConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags) { xenUnifiedPrivatePtr priv; char ebuf[1024]; /* * Only the libvirtd instance can open this driver. * Everything else falls back to the remote driver. */ if (!is_privileged) return VIR_DRV_OPEN_DECLINED; if (conn->uri == NULL) { if (!xenUnifiedProbe()) return VIR_DRV_OPEN_DECLINED; #ifdef WITH_LIBXL /* Decline xen:// URI if xend is not running and libxenlight * driver is potentially available. */ if (!xenUnifiedXendProbe()) return VIR_DRV_OPEN_DECLINED; #endif if (!(conn->uri = virURIParse("xen:///"))) return VIR_DRV_OPEN_ERROR; } else { if (conn->uri->scheme) { /* Decline any scheme which isn't "xen://" or "http://". */ if (STRCASENEQ(conn->uri->scheme, "xen") && STRCASENEQ(conn->uri->scheme, "http")) return VIR_DRV_OPEN_DECLINED; #ifdef WITH_LIBXL /* Decline xen:// URI if xend is not running and libxenlight * driver is potentially available. */ if (!xenUnifiedXendProbe()) return VIR_DRV_OPEN_DECLINED; #endif /* Return an error if the path isn't '' or '/' */ if (conn->uri->path && STRNEQ(conn->uri->path, "") && STRNEQ(conn->uri->path, "/")) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected Xen URI path '%s', try xen:///"), conn->uri->path); return VIR_DRV_OPEN_ERROR; } /* Decline any xen:// URI with a server specified, allowing remote * driver to handle, but keep any http:/// URIs */ if (STRCASEEQ(conn->uri->scheme, "xen") && conn->uri->server) return VIR_DRV_OPEN_DECLINED; } else { return VIR_DRV_OPEN_DECLINED; } } /* We now know the URI is definitely for this driver, so beyond * here, don't return DECLINED, always use ERROR */ if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; /* Allocate per-connection private data. */ if (VIR_ALLOC(priv) < 0) return VIR_DRV_OPEN_ERROR; if (virMutexInit(&priv->lock) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize mutex")); VIR_FREE(priv); return VIR_DRV_OPEN_ERROR; } if (!(priv->domainEvents = virObjectEventStateNew())) { virMutexDestroy(&priv->lock); VIR_FREE(priv); return VIR_DRV_OPEN_ERROR; } conn->privateData = priv; priv->handle = -1; priv->xendConfigVersion = -1; priv->xshandle = NULL; /* Hypervisor required to succeed */ VIR_DEBUG("Trying hypervisor sub-driver"); if (xenHypervisorOpen(conn, auth, flags) < 0) goto error; VIR_DEBUG("Activated hypervisor sub-driver"); priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] = 1; /* XenD is required to succeed */ VIR_DEBUG("Trying XenD sub-driver"); if (xenDaemonOpen(conn, auth, flags) < 0) goto error; VIR_DEBUG("Activated XenD sub-driver"); priv->opened[XEN_UNIFIED_XEND_OFFSET] = 1; /* For old XenD, the XM driver is required to succeed */ if (priv->xendConfigVersion <= XEND_CONFIG_VERSION_3_0_3) { VIR_DEBUG("Trying XM sub-driver"); if (xenXMOpen(conn, auth, flags) < 0) goto error; VIR_DEBUG("Activated XM sub-driver"); priv->opened[XEN_UNIFIED_XM_OFFSET] = 1; } VIR_DEBUG("Trying XS sub-driver"); if (xenStoreOpen(conn, auth, flags) < 0) goto error; VIR_DEBUG("Activated XS sub-driver"); priv->opened[XEN_UNIFIED_XS_OFFSET] = 1; xenNumaInit(conn); if (!(priv->caps = xenHypervisorMakeCapabilities(conn))) { VIR_DEBUG("Failed to make capabilities"); goto error; } if (!(priv->xmlopt = xenDomainXMLConfInit())) goto error; #if WITH_XEN_INOTIFY VIR_DEBUG("Trying Xen inotify sub-driver"); if (xenInotifyOpen(conn, auth, flags) < 0) goto error; VIR_DEBUG("Activated Xen inotify sub-driver"); priv->opened[XEN_UNIFIED_INOTIFY_OFFSET] = 1; #endif if (VIR_STRDUP(priv->saveDir, XEN_SAVE_DIR) < 0) goto error; if (virFileMakePath(priv->saveDir) < 0) { VIR_ERROR(_("Errored to create save dir '%s': %s"), priv->saveDir, virStrerror(errno, ebuf, sizeof(ebuf))); goto error; } return VIR_DRV_OPEN_SUCCESS; error: VIR_DEBUG("Failed to activate a mandatory sub-driver"); #if WITH_XEN_INOTIFY if (priv->opened[XEN_UNIFIED_INOTIFY_OFFSET]) xenInotifyClose(conn); #endif if (priv->opened[XEN_UNIFIED_XM_OFFSET]) xenXMClose(conn); if (priv->opened[XEN_UNIFIED_XS_OFFSET]) xenStoreClose(conn); if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) xenDaemonClose(conn); if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) xenHypervisorClose(conn); virMutexDestroy(&priv->lock); VIR_FREE(priv->saveDir); VIR_FREE(priv); conn->privateData = NULL; return VIR_DRV_OPEN_ERROR; } static int xenUnifiedConnectClose(virConnectPtr conn) { xenUnifiedPrivatePtr priv = conn->privateData; virObjectUnref(priv->caps); virObjectUnref(priv->xmlopt); virObjectEventStateFree(priv->domainEvents); #if WITH_XEN_INOTIFY if (priv->opened[XEN_UNIFIED_INOTIFY_OFFSET]) xenInotifyClose(conn); #endif if (priv->opened[XEN_UNIFIED_XM_OFFSET]) xenXMClose(conn); if (priv->opened[XEN_UNIFIED_XS_OFFSET]) xenStoreClose(conn); if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) xenDaemonClose(conn); if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) xenHypervisorClose(conn); VIR_FREE(priv->saveDir); virMutexDestroy(&priv->lock); VIR_FREE(conn->privateData); return 0; } #define HV_VERSION ((DOM0_INTERFACE_VERSION >> 24) * 1000000 + \ ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 + \ (DOM0_INTERFACE_VERSION & 0xFFFF)) unsigned long xenUnifiedVersion(void) { return HV_VERSION; } static const char * xenUnifiedConnectGetType(virConnectPtr conn) { if (virConnectGetTypeEnsureACL(conn) < 0) return NULL; return "Xen"; } /* Which features are supported by this driver? */ static int xenUnifiedConnectSupportsFeature(virConnectPtr conn, int feature) { if (virConnectSupportsFeatureEnsureACL(conn) < 0) return -1; switch (feature) { case VIR_DRV_FEATURE_MIGRATION_V1: case VIR_DRV_FEATURE_MIGRATION_DIRECT: return 1; default: return 0; } } static int xenUnifiedConnectGetVersion(virConnectPtr conn, unsigned long *hvVer) { if (virConnectGetVersionEnsureACL(conn) < 0) return -1; return xenHypervisorGetVersion(conn, hvVer); } static char *xenUnifiedConnectGetHostname(virConnectPtr conn) { if (virConnectGetHostnameEnsureACL(conn) < 0) return NULL; return virGetHostname(); } static char * xenUnifiedConnectGetSysinfo(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned int flags) { virBuffer buf = VIR_BUFFER_INITIALIZER; virCheckFlags(0, NULL); if (virConnectGetSysinfoEnsureACL(conn) < 0) return NULL; if (!hostsysinfo) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Host SMBIOS information is not available")); return NULL; } if (virSysinfoFormat(&buf, hostsysinfo) < 0) return NULL; if (virBufferError(&buf)) { virReportOOMError(); return NULL; } return virBufferContentAndReset(&buf); } static int xenUnifiedConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) { return 0; } static int xenUnifiedConnectIsSecure(virConnectPtr conn) { xenUnifiedPrivatePtr priv = conn->privateData; int ret = 1; /* All drivers are secure, except for XenD over TCP */ if (priv->opened[XEN_UNIFIED_XEND_OFFSET] && priv->addrfamily != AF_UNIX) ret = 0; return ret; } static int xenUnifiedConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED) { /* XenD reconnects for each request */ return 1; } int xenUnifiedConnectGetMaxVcpus(virConnectPtr conn, const char *type) { if (virConnectGetMaxVcpusEnsureACL(conn) < 0) return -1; if (type && STRCASENEQ(type, "Xen")) { virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__); return -1; } return xenHypervisorGetMaxVcpus(conn, type); } static int xenUnifiedNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) { if (virNodeGetInfoEnsureACL(conn) < 0) return -1; return xenDaemonNodeGetInfo(conn, info); } static char * xenUnifiedConnectGetCapabilities(virConnectPtr conn) { xenUnifiedPrivatePtr priv = conn->privateData; char *xml; if (virConnectGetCapabilitiesEnsureACL(conn) < 0) return NULL; if (!(xml = virCapabilitiesFormatXML(priv->caps))) { virReportOOMError(); return NULL; } return xml; } static int xenUnifiedConnectListDomains(virConnectPtr conn, int *ids, int maxids) { if (virConnectListDomainsEnsureACL(conn) < 0) return -1; return xenStoreListDomains(conn, ids, maxids); } static int xenUnifiedConnectNumOfDomains(virConnectPtr conn) { if (virConnectNumOfDomainsEnsureACL(conn) < 0) return -1; return xenStoreNumOfDomains(conn); } static virDomainPtr xenUnifiedDomainCreateXML(virConnectPtr conn, const char *xml, unsigned int flags) { xenUnifiedPrivatePtr priv = conn->privateData; virDomainDefPtr def = NULL; virDomainPtr ret = NULL; virCheckFlags(0, NULL); if (!(def = virDomainDefParseString(xml, priv->caps, priv->xmlopt, 1 << VIR_DOMAIN_VIRT_XEN, VIR_DOMAIN_XML_INACTIVE))) goto cleanup; if (virDomainCreateXMLEnsureACL(conn, def) < 0) goto cleanup; if (xenDaemonCreateXML(conn, def) < 0) goto cleanup; ret = virGetDomain(conn, def->name, def->uuid); if (ret) ret->id = def->id; cleanup: virDomainDefFree(def); return ret; } static virDomainPtr xenUnifiedDomainLookupByID(virConnectPtr conn, int id) { virDomainPtr ret = NULL; virDomainDefPtr def = NULL; if (!(def = xenGetDomainDefForID(conn, id))) goto cleanup; if (virDomainLookupByIDEnsureACL(conn, def) < 0) goto cleanup; if (!(ret = virGetDomain(conn, def->name, def->uuid))) goto cleanup; ret->id = def->id; cleanup: virDomainDefFree(def); return ret; } static virDomainPtr xenUnifiedDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { virDomainPtr ret = NULL; virDomainDefPtr def = NULL; if (!(def = xenGetDomainDefForUUID(conn, uuid))) goto cleanup; if (virDomainLookupByUUIDEnsureACL(conn, def) < 0) goto cleanup; if (!(ret = virGetDomain(conn, def->name, def->uuid))) goto cleanup; ret->id = def->id; cleanup: virDomainDefFree(def); return ret; } static virDomainPtr xenUnifiedDomainLookupByName(virConnectPtr conn, const char *name) { virDomainPtr ret = NULL; virDomainDefPtr def = NULL; if (!(def = xenGetDomainDefForName(conn, name))) goto cleanup; if (virDomainLookupByNameEnsureACL(conn, def) < 0) goto cleanup; if (!(ret = virGetDomain(conn, def->name, def->uuid))) goto cleanup; ret->id = def->id; cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainIsActive(virDomainPtr dom) { virDomainDefPtr def; int ret = -1; if (!(def = xenGetDomainDefForUUID(dom->conn, dom->uuid))) goto cleanup; ret = def->id == -1 ? 0 : 1; cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainIsPersistent(virDomainPtr dom) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; if (priv->opened[XEN_UNIFIED_XM_OFFSET]) { /* Old Xen, pre-inactive domain management. * If the XM driver can see the guest, it is definitely persistent */ def = xenXMDomainLookupByUUID(dom->conn, dom->uuid); if (def) ret = 1; else ret = 0; } else { /* New Xen with inactive domain management */ def = xenDaemonLookupByUUID(dom->conn, dom->uuid); if (def) { if (def->id == -1) { /* If its inactive, then trivially, it must be persistent */ ret = 1; } else { char *path; char uuidstr[VIR_UUID_STRING_BUFLEN]; /* If its running there's no official way to tell, so we * go behind xend's back & look at the config dir */ virUUIDFormat(dom->uuid, uuidstr); if (virAsprintf(&path, "%s/%s", XEND_DOMAINS_DIR, uuidstr) < 0) goto cleanup; if (access(path, R_OK) == 0) ret = 1; else if (errno == ENOENT) ret = 0; } } } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED) { return 0; } static int xenUnifiedDomainSuspend(virDomainPtr dom) { int ret = -1; virDomainDefPtr def; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainSuspendEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenDaemonDomainSuspend(dom->conn, def); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainResume(virDomainPtr dom) { int ret = -1; virDomainDefPtr def; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainResumeEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenDaemonDomainResume(dom->conn, def); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainShutdownFlags(virDomainPtr dom, unsigned int flags) { int ret = -1; virDomainDefPtr def; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainShutdownFlagsEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenDaemonDomainShutdown(dom->conn, def); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainShutdown(virDomainPtr dom) { return xenUnifiedDomainShutdownFlags(dom, 0); } static int xenUnifiedDomainReboot(virDomainPtr dom, unsigned int flags) { int ret = -1; virDomainDefPtr def; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainRebootEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenDaemonDomainReboot(dom->conn, def); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainDestroyFlags(virDomainPtr dom, unsigned int flags) { int ret = -1; virDomainDefPtr def; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainDestroyFlagsEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenDaemonDomainDestroy(dom->conn, def); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainDestroy(virDomainPtr dom) { return xenUnifiedDomainDestroyFlags(dom, 0); } static char * xenUnifiedDomainGetOSType(virDomainPtr dom) { xenUnifiedPrivatePtr priv = dom->conn->privateData; char *ret = NULL; virDomainDefPtr def; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetOSTypeEnsureACL(dom->conn, def) < 0) goto cleanup; if (def->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to query OS type for inactive domain")); return NULL; } else { ret = xenDaemonDomainGetOSType(dom->conn, def); } } else { ret = xenHypervisorDomainGetOSType(dom->conn, def); } cleanup: virDomainDefFree(def); return ret; } static unsigned long long xenUnifiedDomainGetMaxMemory(virDomainPtr dom) { xenUnifiedPrivatePtr priv = dom->conn->privateData; unsigned long long ret = 0; virDomainDefPtr def; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetMaxMemoryEnsureACL(dom->conn, def) < 0) goto cleanup; if (def->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainGetMaxMemory(dom->conn, def); else ret = xenDaemonDomainGetMaxMemory(dom->conn, def); } else { ret = xenHypervisorGetMaxMemory(dom->conn, def); } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) { xenUnifiedPrivatePtr priv = dom->conn->privateData; int ret = -1; virDomainDefPtr def; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainSetMaxMemoryEnsureACL(dom->conn, def) < 0) goto cleanup; if (def->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainSetMaxMemory(dom->conn, def, memory); else ret = xenDaemonDomainSetMaxMemory(dom->conn, def, memory); } else { ret = xenHypervisorSetMaxMemory(dom->conn, def, memory); } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainSetMemory(virDomainPtr dom, unsigned long memory) { xenUnifiedPrivatePtr priv = dom->conn->privateData; int ret = -1; virDomainDefPtr def; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainSetMemoryEnsureACL(dom->conn, def) < 0) goto cleanup; if (def->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainSetMemory(dom->conn, def, memory); else ret = xenDaemonDomainSetMemory(dom->conn, def, memory); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { xenUnifiedPrivatePtr priv = dom->conn->privateData; int ret = -1; virDomainDefPtr def; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetInfoEnsureACL(dom->conn, def) < 0) goto cleanup; if (def->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainGetInfo(dom->conn, def, info); else ret = xenDaemonDomainGetInfo(dom->conn, def, info); } else { ret = xenHypervisorGetDomainInfo(dom->conn, def, info); } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainGetState(virDomainPtr dom, int *state, int *reason, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; int ret = -1; virDomainDefPtr def; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetStateEnsureACL(dom->conn, def) < 0) goto cleanup; if (def->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainGetState(dom->conn, def, state, reason); else ret = xenDaemonDomainGetState(dom->conn, def, state, reason); } else { ret = xenHypervisorGetDomainState(dom->conn, def, state, reason); } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainSaveFlags(virDomainPtr dom, const char *to, const char *dxml, unsigned int flags) { int ret = -1; virDomainDefPtr def; virCheckFlags(0, -1); if (dxml) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("xml modification unsupported")); return -1; } if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainSaveFlagsEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenDaemonDomainSave(dom->conn, def, to); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainSave(virDomainPtr dom, const char *to) { return xenUnifiedDomainSaveFlags(dom, to, NULL, 0); } static char * xenUnifiedDomainManagedSavePath(xenUnifiedPrivatePtr priv, virDomainDefPtr def) { char *ret; if (virAsprintf(&ret, "%s/%s.save", priv->saveDir, def->name) < 0) return NULL; VIR_DEBUG("managed save image: %s", ret); return ret; } static int xenUnifiedDomainManagedSave(virDomainPtr dom, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; char *name = NULL; virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainManagedSaveEnsureACL(dom->conn, def) < 0) goto cleanup; if (!(name = xenUnifiedDomainManagedSavePath(priv, def))) goto cleanup; ret = xenDaemonDomainSave(dom->conn, def, name); cleanup: VIR_FREE(name); virDomainDefFree(def); return ret; } static int xenUnifiedDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; char *name = NULL; virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainHasManagedSaveImageEnsureACL(dom->conn, def) < 0) goto cleanup; if (!(name = xenUnifiedDomainManagedSavePath(priv, def))) goto cleanup; ret = virFileExists(name); cleanup: VIR_FREE(name); virDomainDefFree(def); return ret; } static int xenUnifiedDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; char *name = NULL; virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainManagedSaveRemoveEnsureACL(dom->conn, def) < 0) goto cleanup; if (!(name = xenUnifiedDomainManagedSavePath(priv, def))) goto cleanup; ret = unlink(name); cleanup: VIR_FREE(name); return ret; } static int xenUnifiedDomainRestoreFlags(virConnectPtr conn, const char *from, const char *dxml, unsigned int flags) { virCheckFlags(0, -1); if (dxml) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("xml modification unsupported")); return -1; } return xenDaemonDomainRestore(conn, from); } static int xenUnifiedDomainRestore(virConnectPtr conn, const char *from) { return xenUnifiedDomainRestoreFlags(conn, from, NULL, 0); } static int xenUnifiedDomainCoreDump(virDomainPtr dom, const char *to, unsigned int flags) { virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainCoreDumpEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenDaemonDomainCoreDump(dom->conn, def, to, flags); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM, -1); /* At least one of LIVE or CONFIG must be set. MAXIMUM cannot be * mixed with LIVE. */ if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 || (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) == (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) { virReportError(VIR_ERR_INVALID_ARG, _("invalid flag combination: (0x%x)"), flags); return -1; } if (!nvcpus || (unsigned short) nvcpus != nvcpus) { virReportError(VIR_ERR_INVALID_ARG, _("argument out of range: %d"), nvcpus); return -1; } if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainSetVcpusFlagsEnsureACL(dom->conn, def, flags) < 0) goto cleanup; /* Try non-hypervisor methods first, then hypervisor direct method * as a last resort. */ if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainSetVcpusFlags(dom->conn, def, nvcpus, flags); else ret = xenDaemonDomainSetVcpusFlags(dom->conn, def, nvcpus, flags); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) { xenUnifiedPrivatePtr priv = dom->conn->privateData; unsigned int flags = VIR_DOMAIN_VCPU_LIVE; /* Per the documented API, it is hypervisor-dependent whether this * affects just _LIVE or _LIVE|_CONFIG; in xen's case, that * depends on xendConfigVersion. */ if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4) flags |= VIR_DOMAIN_VCPU_CONFIG; return xenUnifiedDomainSetVcpusFlags(dom, nvcpus, flags); } static int xenUnifiedDomainPinVcpu(virDomainPtr dom, unsigned int vcpu, unsigned char *cpumap, int maplen) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainPinVcpuEnsureACL(dom->conn, def) < 0) goto cleanup; if (dom->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainPinVcpu(dom->conn, def, vcpu, cpumap, maplen); else ret = xenDaemonDomainPinVcpu(dom->conn, def, vcpu, cpumap, maplen); } else { ret = xenHypervisorPinVcpu(dom->conn, def, vcpu, cpumap, maplen); } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainGetVcpusInternal(virDomainPtr dom, virDomainDefPtr def, virVcpuInfoPtr info, int maxinfo, unsigned char *cpumaps, int maplen) { xenUnifiedPrivatePtr priv = dom->conn->privateData; int ret = -1; if (dom->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot get VCPUs of inactive domain")); } else { ret = xenDaemonDomainGetVcpus(dom->conn, def, info, maxinfo, cpumaps, maplen); } } else { ret = xenHypervisorGetVcpus(dom->conn, def, info, maxinfo, cpumaps, maplen); } return ret; } static int xenUnifiedDomainGetVcpus(virDomainPtr dom, virVcpuInfoPtr info, int maxinfo, unsigned char *cpumaps, int maplen) { virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetVcpusEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenUnifiedDomainGetVcpusInternal(dom, def, info, maxinfo, cpumaps, maplen); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainGetVcpusFlagsInternal(virDomainPtr dom, virDomainDefPtr def, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; int ret = -1; if (dom->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainGetVcpusFlags(dom->conn, def, flags); else ret = xenDaemonDomainGetVcpusFlags(dom->conn, def, flags); } else { if (flags == (VIR_DOMAIN_VCPU_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM)) ret = xenHypervisorGetVcpuMax(dom->conn, def); else ret = xenDaemonDomainGetVcpusFlags(dom->conn, def, flags); } return ret; } static int xenUnifiedDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) { virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetVcpusFlagsEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenUnifiedDomainGetVcpusFlagsInternal(dom, def, flags); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainGetMaxVcpus(virDomainPtr dom) { return xenUnifiedDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)); } static char * xenUnifiedDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr minidef = NULL; virDomainDefPtr def = NULL; char *ret = NULL; if (!(minidef = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetXMLDescEnsureACL(dom->conn, minidef, flags) < 0) goto cleanup; if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { def = xenXMDomainGetXMLDesc(dom->conn, minidef); } else { char *cpus; xenUnifiedLock(priv); cpus = xenDomainUsedCpus(dom, minidef); xenUnifiedUnlock(priv); def = xenDaemonDomainGetXMLDesc(dom->conn, minidef, cpus); VIR_FREE(cpus); } if (def) ret = virDomainDefFormat(def, flags); cleanup: virDomainDefFree(def); virDomainDefFree(minidef); return ret; } static char * xenUnifiedConnectDomainXMLFromNative(virConnectPtr conn, const char *format, const char *config, unsigned int flags) { virDomainDefPtr def = NULL; char *ret = NULL; virConfPtr conf = NULL; int id; char * tty; int vncport; xenUnifiedPrivatePtr priv = conn->privateData; virCheckFlags(0, NULL); if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0) return NULL; if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) && STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) { virReportError(VIR_ERR_INVALID_ARG, _("unsupported config type %s"), format); return NULL; } if (STREQ(format, XEN_CONFIG_FORMAT_XM)) { conf = virConfReadMem(config, strlen(config), 0); if (!conf) goto cleanup; def = xenParseXM(conf, priv->xendConfigVersion, priv->caps); } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) { if (xenGetDomIdFromSxprString(config, priv->xendConfigVersion, &id) < 0) goto cleanup; xenUnifiedLock(priv); tty = xenStoreDomainGetConsolePath(conn, id); vncport = xenStoreDomainGetVNCPort(conn, id); xenUnifiedUnlock(priv); def = xenParseSxprString(config, priv->xendConfigVersion, tty, vncport); } 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 * xenUnifiedConnectDomainXMLToNative(virConnectPtr conn, const char *format, const char *xmlData, unsigned int flags) { virDomainDefPtr def = NULL; char *ret = NULL; virConfPtr conf = NULL; xenUnifiedPrivatePtr priv = conn->privateData; virCheckFlags(0, NULL); if (virConnectDomainXMLToNativeEnsureACL(conn) < 0) return NULL; if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) && STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) { virReportError(VIR_ERR_INVALID_ARG, _("unsupported config type %s"), format); goto cleanup; } if (!(def = virDomainDefParseString(xmlData, priv->caps, priv->xmlopt, 1 << VIR_DOMAIN_VIRT_XEN, 0))) goto cleanup; if (STREQ(format, XEN_CONFIG_FORMAT_XM)) { int len = MAX_CONFIG_SIZE; conf = xenFormatXM(conn, def, priv->xendConfigVersion); if (!conf) goto cleanup; if (VIR_ALLOC_N(ret, len) < 0) goto cleanup; if (virConfWriteMem(ret, &len, conf) < 0) { VIR_FREE(ret); goto cleanup; } } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) { ret = xenFormatSxpr(conn, def, priv->xendConfigVersion); } cleanup: virDomainDefFree(def); if (conf) virConfFree(conf); return ret; } static int xenUnifiedDomainMigratePrepare(virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, char **uri_out, unsigned long flags, const char *dname, unsigned long resource) { virCheckFlags(XEN_MIGRATION_FLAGS, -1); return xenDaemonDomainMigratePrepare(dconn, cookie, cookielen, uri_in, uri_out, flags, dname, resource); } static int xenUnifiedDomainMigratePerform(virDomainPtr dom, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long resource) { virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(XEN_MIGRATION_FLAGS, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainMigratePerformEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenDaemonDomainMigratePerform(dom->conn, def, cookie, cookielen, uri, flags, dname, resource); cleanup: virDomainDefFree(def); return ret; } static virDomainPtr xenUnifiedDomainMigrateFinish(virConnectPtr dconn, const char *dname, const char *cookie ATTRIBUTE_UNUSED, int cookielen ATTRIBUTE_UNUSED, const char *uri ATTRIBUTE_UNUSED, unsigned long flags) { xenUnifiedPrivatePtr priv = dconn->privateData; virDomainPtr ret = NULL; virDomainDefPtr minidef = NULL; virDomainDefPtr def = NULL; virCheckFlags(XEN_MIGRATION_FLAGS, NULL); if (!(minidef = xenGetDomainDefForName(dconn, dname))) goto cleanup; if (virDomainMigrateFinishEnsureACL(dconn, minidef) < 0) goto cleanup; if (flags & VIR_MIGRATE_PERSIST_DEST) { if (!(def = xenDaemonDomainGetXMLDesc(dconn, minidef, NULL))) goto cleanup; if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { if (xenXMDomainDefineXML(dconn, def) < 0) goto cleanup; } else { if (xenDaemonDomainDefineXML(dconn, def) < 0) goto cleanup; } } ret = virGetDomain(dconn, minidef->name, minidef->uuid); if (ret) ret->id = minidef->id; cleanup: virDomainDefFree(def); virDomainDefFree(minidef); return ret; } static int xenUnifiedConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) { xenUnifiedPrivatePtr priv = conn->privateData; if (virConnectListDefinedDomainsEnsureACL(conn) < 0) return -1; if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { return xenXMListDefinedDomains(conn, names, maxnames); } else { return xenDaemonListDefinedDomains(conn, names, maxnames); } } static int xenUnifiedConnectNumOfDefinedDomains(virConnectPtr conn) { xenUnifiedPrivatePtr priv = conn->privateData; if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0) return -1; if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { return xenXMNumOfDefinedDomains(conn); } else { return xenDaemonNumOfDefinedDomains(conn); } } static int xenUnifiedDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; int ret = -1; virDomainDefPtr def = NULL; char *name = NULL; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainCreateWithFlagsEnsureACL(dom->conn, def) < 0) goto cleanup; if (!(name = xenUnifiedDomainManagedSavePath(priv, def))) goto cleanup; if (virFileExists(name)) { ret = xenDaemonDomainRestore(dom->conn, name); if (ret == 0) unlink(name); goto cleanup; } if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainCreate(dom->conn, def); else ret = xenDaemonDomainCreate(dom->conn, def); if (ret >= 0) dom->id = def->id; cleanup: virDomainDefFree(def); VIR_FREE(name); return ret; } static int xenUnifiedDomainCreate(virDomainPtr dom) { return xenUnifiedDomainCreateWithFlags(dom, 0); } static virDomainPtr xenUnifiedDomainDefineXML(virConnectPtr conn, const char *xml) { xenUnifiedPrivatePtr priv = conn->privateData; virDomainDefPtr def = NULL; virDomainPtr ret = NULL; if (!(def = virDomainDefParseString(xml, priv->caps, priv->xmlopt, 1 << VIR_DOMAIN_VIRT_XEN, VIR_DOMAIN_XML_INACTIVE))) goto cleanup; if (virDomainDefineXMLEnsureACL(conn, def) < 0) goto cleanup; if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { if (xenXMDomainDefineXML(conn, def) < 0) goto cleanup; ret = virGetDomain(conn, def->name, def->uuid); def = NULL; /* XM driver owns it now */ } else { if (xenDaemonDomainDefineXML(conn, def) < 0) goto cleanup; ret = virGetDomain(conn, def->name, def->uuid); } if (ret) ret->id = -1; cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainUndefineFlags(virDomainPtr dom, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainUndefineFlagsEnsureACL(dom->conn, def) < 0) goto cleanup; if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainUndefine(dom->conn, def); else ret = xenDaemonDomainUndefine(dom->conn, def); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainUndefine(virDomainPtr dom) { return xenUnifiedDomainUndefineFlags(dom, 0); } static int xenUnifiedDomainAttachDevice(virDomainPtr dom, const char *xml) { xenUnifiedPrivatePtr priv = dom->conn->privateData; unsigned int flags = VIR_DOMAIN_DEVICE_MODIFY_LIVE; virDomainDefPtr def = NULL; int ret = -1; /* * HACK: xend with xendConfigVersion >= 3 does not support changing live * config without touching persistent config, we add the extra flag here * to make this API work */ if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4) flags |= VIR_DOMAIN_DEVICE_MODIFY_CONFIG; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainAttachDeviceEnsureACL(dom->conn, def) < 0) goto cleanup; if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainAttachDeviceFlags(dom->conn, def, xml, flags); else ret = xenDaemonAttachDeviceFlags(dom->conn, def, xml, flags); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainAttachDeviceFlags(virDomainPtr dom, const char *xml, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, def, flags) < 0) goto cleanup; if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainAttachDeviceFlags(dom->conn, def, xml, flags); else ret = xenDaemonAttachDeviceFlags(dom->conn, def, xml, flags); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainDetachDevice(virDomainPtr dom, const char *xml) { xenUnifiedPrivatePtr priv = dom->conn->privateData; unsigned int flags = VIR_DOMAIN_DEVICE_MODIFY_LIVE; virDomainDefPtr def = NULL; int ret = -1; /* * HACK: xend with xendConfigVersion >= 3 does not support changing live * config without touching persistent config, we add the extra flag here * to make this API work */ if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4) flags |= VIR_DOMAIN_DEVICE_MODIFY_CONFIG; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainDetachDeviceEnsureACL(dom->conn, def) < 0) goto cleanup; if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainDetachDeviceFlags(dom->conn, def, xml, flags); else ret = xenDaemonDetachDeviceFlags(dom->conn, def, xml, flags); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainDetachDeviceFlags(virDomainPtr dom, const char *xml, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, def, flags) < 0) goto cleanup; if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainDetachDeviceFlags(dom->conn, def, xml, flags); else ret = xenDaemonDetachDeviceFlags(dom->conn, def, xml, flags); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml, unsigned int flags) { virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, def, flags) < 0) goto cleanup; ret = xenDaemonUpdateDeviceFlags(dom->conn, def, xml, flags); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainGetAutostart(virDomainPtr dom, int *autostart) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetAutostartEnsureACL(dom->conn, def) < 0) goto cleanup; if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainGetAutostart(def, autostart); else ret = xenDaemonDomainGetAutostart(dom->conn, def, autostart); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainSetAutostart(virDomainPtr dom, int autostart) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainSetAutostartEnsureACL(dom->conn, def) < 0) goto cleanup; if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainSetAutostart(def, autostart); else ret = xenDaemonDomainSetAutostart(dom->conn, def, autostart); cleanup: virDomainDefFree(def); return ret; } static char * xenUnifiedDomainGetSchedulerType(virDomainPtr dom, int *nparams) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; char *ret = NULL; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetSchedulerTypeEnsureACL(dom->conn, def) < 0) goto cleanup; if (dom->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot change scheduler parameters")); goto cleanup; } ret = xenDaemonGetSchedulerType(dom->conn, nparams); } else { ret = xenHypervisorGetSchedulerType(dom->conn, nparams); } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainGetSchedulerParametersFlags(virDomainPtr dom, virTypedParameterPtr params, int *nparams, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, def) < 0) goto cleanup; if (dom->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot change scheduler parameters")); goto cleanup; } ret = xenDaemonGetSchedulerParameters(dom->conn, def, params, nparams); } else { ret = xenHypervisorGetSchedulerParameters(dom->conn, def, params, nparams); } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainGetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params, int *nparams) { return xenUnifiedDomainGetSchedulerParametersFlags(dom, params, nparams, 0); } static int xenUnifiedDomainSetSchedulerParametersFlags(virDomainPtr dom, virTypedParameterPtr params, int nparams, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, def, flags) < 0) goto cleanup; if (dom->id < 0) { if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot change scheduler parameters")); goto cleanup; } ret = xenDaemonSetSchedulerParameters(dom->conn, def, params, nparams); } else { ret = xenHypervisorSetSchedulerParameters(dom->conn, def, params, nparams); } cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainSetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params, int nparams) { return xenUnifiedDomainSetSchedulerParametersFlags(dom, params, nparams, 0); } static int xenUnifiedDomainBlockStats(virDomainPtr dom, const char *path, struct _virDomainBlockStats *stats) { virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainBlockStatsEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenHypervisorDomainBlockStats(dom->conn, def, path, stats); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainInterfaceStats(virDomainPtr dom, const char *path, struct _virDomainInterfaceStats *stats) { virDomainDefPtr def = NULL; int ret = -1; if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainInterfaceStatsEnsureACL(dom->conn, def) < 0) goto cleanup; ret = xenHypervisorDomainInterfaceStats(def, path, stats); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedDomainBlockPeek(virDomainPtr dom, const char *path, unsigned long long offset, size_t size, void *buffer, unsigned int flags) { xenUnifiedPrivatePtr priv = dom->conn->privateData; virDomainDefPtr def = NULL; int ret = -1; virCheckFlags(0, -1); if (!(def = xenGetDomainDefForDom(dom))) goto cleanup; if (virDomainBlockPeekEnsureACL(dom->conn, def) < 0) goto cleanup; if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ret = xenXMDomainBlockPeek(dom->conn, def, path, offset, size, buffer); else ret = xenDaemonDomainBlockPeek(dom->conn, def, path, offset, size, buffer); cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems, int startCell, int maxCells) { if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0) return 0; return xenHypervisorNodeGetCellsFreeMemory(conn, freeMems, startCell, maxCells); } static unsigned long long xenUnifiedNodeGetFreeMemory(virConnectPtr conn) { unsigned long long freeMem = 0; if (virNodeGetFreeMemoryEnsureACL(conn) < 0) return 0; if (xenHypervisorNodeGetCellsFreeMemory(conn, &freeMem, -1, 1) < 0) return 0; return freeMem; } static int xenUnifiedConnectDomainEventRegister(virConnectPtr conn, virConnectDomainEventCallback callback, void *opaque, virFreeCallback freefunc) { xenUnifiedPrivatePtr priv = conn->privateData; int ret; if (virConnectDomainEventRegisterEnsureACL(conn) < 0) return -1; xenUnifiedLock(priv); if (priv->xsWatch == -1) { virReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); xenUnifiedUnlock(priv); return -1; } ret = virDomainEventStateRegister(conn, priv->domainEvents, callback, opaque, freefunc); xenUnifiedUnlock(priv); return ret; } static int xenUnifiedConnectDomainEventDeregister(virConnectPtr conn, virConnectDomainEventCallback callback) { int ret; xenUnifiedPrivatePtr priv = conn->privateData; if (virConnectDomainEventDeregisterEnsureACL(conn) < 0) return -1; xenUnifiedLock(priv); if (priv->xsWatch == -1) { virReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); xenUnifiedUnlock(priv); return -1; } ret = virDomainEventStateDeregister(conn, priv->domainEvents, callback); xenUnifiedUnlock(priv); return ret; } static int xenUnifiedConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID, virConnectDomainEventGenericCallback callback, void *opaque, virFreeCallback freefunc) { xenUnifiedPrivatePtr priv = conn->privateData; int ret; if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0) return -1; xenUnifiedLock(priv); if (priv->xsWatch == -1) { virReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); xenUnifiedUnlock(priv); return -1; } if (virDomainEventStateRegisterID(conn, priv->domainEvents, dom, eventID, callback, opaque, freefunc, &ret) < 0) ret = -1; xenUnifiedUnlock(priv); return ret; } static int xenUnifiedConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID) { int ret; xenUnifiedPrivatePtr priv = conn->privateData; if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0) return -1; xenUnifiedLock(priv); if (priv->xsWatch == -1) { virReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); xenUnifiedUnlock(priv); return -1; } ret = virObjectEventStateDeregisterID(conn, priv->domainEvents, callbackID); xenUnifiedUnlock(priv); return ret; } static int xenUnifiedNodeDeviceGetPciInfo(virNodeDevicePtr dev, unsigned *domain, unsigned *bus, unsigned *slot, unsigned *function) { virNodeDeviceDefPtr def = NULL; virNodeDevCapsDefPtr cap; char *xml = NULL; int ret = -1; xml = virNodeDeviceGetXMLDesc(dev, 0); if (!xml) goto out; def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); if (!def) goto out; cap = def->caps; while (cap) { if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) { *domain = cap->data.pci_dev.domain; *bus = cap->data.pci_dev.bus; *slot = cap->data.pci_dev.slot; *function = cap->data.pci_dev.function; break; } cap = cap->next; } if (!cap) { virReportError(VIR_ERR_INVALID_ARG, _("device %s is not a PCI device"), dev->name); goto out; } ret = 0; out: virNodeDeviceDefFree(def); VIR_FREE(xml); return ret; } static int xenUnifiedNodeDeviceDetachFlags(virNodeDevicePtr dev, const char *driverName, unsigned int flags) { virPCIDevicePtr pci; unsigned domain, bus, slot, function; int ret = -1; virCheckFlags(0, -1); if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) return -1; pci = virPCIDeviceNew(domain, bus, slot, function); if (!pci) return -1; if (!driverName) { if (virPCIDeviceSetStubDriver(pci, "pciback") < 0) goto out; } else { virReportError(VIR_ERR_INVALID_ARG, _("unknown driver name '%s'"), driverName); goto out; } if (virPCIDeviceDetach(pci, NULL, NULL) < 0) goto out; ret = 0; out: virPCIDeviceFree(pci); return ret; } static int xenUnifiedNodeDeviceDettach(virNodeDevicePtr dev) { return xenUnifiedNodeDeviceDetachFlags(dev, NULL, 0); } static int xenUnifiedNodeDeviceAssignedDomainId(virNodeDevicePtr dev) { int numdomains; int ret = -1; size_t i; int *ids = NULL; char *bdf = NULL; char *xref = NULL; unsigned int domain, bus, slot, function; virConnectPtr conn = dev->conn; xenUnifiedPrivatePtr priv = conn->privateData; /* Get active domains */ numdomains = xenUnifiedConnectNumOfDomains(conn); if (numdomains < 0) { return ret; } if (numdomains > 0){ if (VIR_ALLOC_N(ids, numdomains) < 0) goto out; if ((numdomains = xenUnifiedConnectListDomains(conn, &ids[0], numdomains)) < 0) { goto out; } } /* Get pci bdf */ if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) goto out; if (virAsprintf(&bdf, "%04x:%02x:%02x.%0x", domain, bus, slot, function) < 0) goto out; xenUnifiedLock(priv); /* Check if bdf is assigned to one of active domains */ for (i = 0; i < numdomains; i++) { xref = xenStoreDomainGetPCIID(conn, ids[i], bdf); if (xref == NULL) { continue; } else { ret = ids[i]; break; } } xenUnifiedUnlock(priv); VIR_FREE(xref); VIR_FREE(bdf); out: VIR_FREE(ids); return ret; } static int xenUnifiedNodeDeviceReAttach(virNodeDevicePtr dev) { virPCIDevicePtr pci; unsigned domain, bus, slot, function; int ret = -1; int domid; if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) return -1; pci = virPCIDeviceNew(domain, bus, slot, function); if (!pci) return -1; /* Check if device is assigned to an active guest */ if ((domid = xenUnifiedNodeDeviceAssignedDomainId(dev)) >= 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Device %s has been assigned to guest %d"), dev->name, domid); goto out; } if (virPCIDeviceReattach(pci, NULL, NULL) < 0) goto out; ret = 0; out: virPCIDeviceFree(pci); return ret; } static int xenUnifiedNodeDeviceReset(virNodeDevicePtr dev) { virPCIDevicePtr pci; unsigned domain, bus, slot, function; int ret = -1; if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0) return -1; pci = virPCIDeviceNew(domain, bus, slot, function); if (!pci) return -1; if (virPCIDeviceReset(pci, NULL, NULL) < 0) goto out; ret = 0; out: virPCIDeviceFree(pci); return ret; } static int xenUnifiedDomainOpenConsole(virDomainPtr dom, const char *dev_name, virStreamPtr st, unsigned int flags) { virDomainDefPtr def = NULL; int ret = -1; virDomainChrDefPtr chr = NULL; virCheckFlags(0, -1); if (dom->id == -1) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("domain is not running")); goto cleanup; } if (dev_name) { /* XXX support device aliases in future */ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Named device aliases are not supported")); goto cleanup; } def = xenDaemonDomainFetch(dom->conn, dom->id, dom->name, NULL); if (!def) goto cleanup; if (def->nconsoles) chr = def->consoles[0]; else if (def->nserials) chr = def->serials[0]; if (!chr) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot find default console device")); goto cleanup; } if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { virReportError(VIR_ERR_INTERNAL_ERROR, _("character device %s is not using a PTY"), dev_name); goto cleanup; } if (virFDStreamOpenFile(st, chr->source.data.file.path, 0, 0, O_RDWR) < 0) goto cleanup; ret = 0; cleanup: virDomainDefFree(def); return ret; } static int xenUnifiedNodeGetMemoryParameters(virConnectPtr conn, virTypedParameterPtr params, int *nparams, unsigned int flags) { if (virNodeGetMemoryParametersEnsureACL(conn) < 0) return -1; return nodeGetMemoryParameters(params, nparams, flags); } static int xenUnifiedNodeSetMemoryParameters(virConnectPtr conn, virTypedParameterPtr params, int nparams, unsigned int flags) { if (virNodeSetMemoryParametersEnsureACL(conn) < 0) return -1; return nodeSetMemoryParameters(params, nparams, flags); } static int xenUnifiedNodeSuspendForDuration(virConnectPtr conn, unsigned int target, unsigned long long duration, unsigned int flags) { if (virNodeSuspendForDurationEnsureACL(conn) < 0) return -1; return nodeSuspendForDuration(target, duration, flags); } /*----- Register with libvirt.c, and initialize Xen drivers. -----*/ /* The interface which we export upwards to libvirt.c. */ static virDriver xenUnifiedDriver = { .no = VIR_DRV_XEN_UNIFIED, .name = "Xen", .connectOpen = xenUnifiedConnectOpen, /* 0.0.3 */ .connectClose = xenUnifiedConnectClose, /* 0.0.3 */ .connectSupportsFeature = xenUnifiedConnectSupportsFeature, /* 0.3.2 */ .connectGetType = xenUnifiedConnectGetType, /* 0.0.3 */ .connectGetVersion = xenUnifiedConnectGetVersion, /* 0.0.3 */ .connectGetHostname = xenUnifiedConnectGetHostname, /* 0.7.3 */ .connectGetSysinfo = xenUnifiedConnectGetSysinfo, /* 1.1.0 */ .connectGetMaxVcpus = xenUnifiedConnectGetMaxVcpus, /* 0.2.1 */ .nodeGetInfo = xenUnifiedNodeGetInfo, /* 0.1.0 */ .connectGetCapabilities = xenUnifiedConnectGetCapabilities, /* 0.2.1 */ .connectListDomains = xenUnifiedConnectListDomains, /* 0.0.3 */ .connectNumOfDomains = xenUnifiedConnectNumOfDomains, /* 0.0.3 */ .domainCreateXML = xenUnifiedDomainCreateXML, /* 0.0.3 */ .domainLookupByID = xenUnifiedDomainLookupByID, /* 0.0.3 */ .domainLookupByUUID = xenUnifiedDomainLookupByUUID, /* 0.0.5 */ .domainLookupByName = xenUnifiedDomainLookupByName, /* 0.0.3 */ .domainSuspend = xenUnifiedDomainSuspend, /* 0.0.3 */ .domainResume = xenUnifiedDomainResume, /* 0.0.3 */ .domainShutdown = xenUnifiedDomainShutdown, /* 0.0.3 */ .domainShutdownFlags = xenUnifiedDomainShutdownFlags, /* 0.9.10 */ .domainReboot = xenUnifiedDomainReboot, /* 0.1.0 */ .domainDestroy = xenUnifiedDomainDestroy, /* 0.0.3 */ .domainDestroyFlags = xenUnifiedDomainDestroyFlags, /* 0.9.4 */ .domainGetOSType = xenUnifiedDomainGetOSType, /* 0.0.3 */ .domainGetMaxMemory = xenUnifiedDomainGetMaxMemory, /* 0.0.3 */ .domainSetMaxMemory = xenUnifiedDomainSetMaxMemory, /* 0.0.3 */ .domainSetMemory = xenUnifiedDomainSetMemory, /* 0.1.1 */ .domainGetInfo = xenUnifiedDomainGetInfo, /* 0.0.3 */ .domainGetState = xenUnifiedDomainGetState, /* 0.9.2 */ .domainSave = xenUnifiedDomainSave, /* 0.0.3 */ .domainSaveFlags = xenUnifiedDomainSaveFlags, /* 0.9.4 */ .domainManagedSave = xenUnifiedDomainManagedSave, /* 1.0.1 */ .domainHasManagedSaveImage = xenUnifiedDomainHasManagedSaveImage, /* 1.0.1 */ .domainManagedSaveRemove = xenUnifiedDomainManagedSaveRemove, /* 1.0.1 */ .domainRestore = xenUnifiedDomainRestore, /* 0.0.3 */ .domainRestoreFlags = xenUnifiedDomainRestoreFlags, /* 0.9.4 */ .domainCoreDump = xenUnifiedDomainCoreDump, /* 0.1.9 */ .domainSetVcpus = xenUnifiedDomainSetVcpus, /* 0.1.4 */ .domainSetVcpusFlags = xenUnifiedDomainSetVcpusFlags, /* 0.8.5 */ .domainGetVcpusFlags = xenUnifiedDomainGetVcpusFlags, /* 0.8.5 */ .domainPinVcpu = xenUnifiedDomainPinVcpu, /* 0.1.4 */ .domainGetVcpus = xenUnifiedDomainGetVcpus, /* 0.1.4 */ .domainGetMaxVcpus = xenUnifiedDomainGetMaxVcpus, /* 0.2.1 */ .domainGetXMLDesc = xenUnifiedDomainGetXMLDesc, /* 0.0.3 */ .connectDomainXMLFromNative = xenUnifiedConnectDomainXMLFromNative, /* 0.6.4 */ .connectDomainXMLToNative = xenUnifiedConnectDomainXMLToNative, /* 0.6.4 */ .connectListDefinedDomains = xenUnifiedConnectListDefinedDomains, /* 0.1.1 */ .connectNumOfDefinedDomains = xenUnifiedConnectNumOfDefinedDomains, /* 0.1.5 */ .domainCreate = xenUnifiedDomainCreate, /* 0.1.1 */ .domainCreateWithFlags = xenUnifiedDomainCreateWithFlags, /* 0.8.2 */ .domainDefineXML = xenUnifiedDomainDefineXML, /* 0.1.1 */ .domainUndefine = xenUnifiedDomainUndefine, /* 0.1.1 */ .domainUndefineFlags = xenUnifiedDomainUndefineFlags, /* 0.9.4 */ .domainAttachDevice = xenUnifiedDomainAttachDevice, /* 0.1.9 */ .domainAttachDeviceFlags = xenUnifiedDomainAttachDeviceFlags, /* 0.7.7 */ .domainDetachDevice = xenUnifiedDomainDetachDevice, /* 0.1.9 */ .domainDetachDeviceFlags = xenUnifiedDomainDetachDeviceFlags, /* 0.7.7 */ .domainUpdateDeviceFlags = xenUnifiedDomainUpdateDeviceFlags, /* 0.8.0 */ .domainGetAutostart = xenUnifiedDomainGetAutostart, /* 0.4.4 */ .domainSetAutostart = xenUnifiedDomainSetAutostart, /* 0.4.4 */ .domainGetSchedulerType = xenUnifiedDomainGetSchedulerType, /* 0.2.3 */ .domainGetSchedulerParameters = xenUnifiedDomainGetSchedulerParameters, /* 0.2.3 */ .domainGetSchedulerParametersFlags = xenUnifiedDomainGetSchedulerParametersFlags, /* 0.9.2 */ .domainSetSchedulerParameters = xenUnifiedDomainSetSchedulerParameters, /* 0.2.3 */ .domainSetSchedulerParametersFlags = xenUnifiedDomainSetSchedulerParametersFlags, /* 0.9.2 */ .domainMigratePrepare = xenUnifiedDomainMigratePrepare, /* 0.3.2 */ .domainMigratePerform = xenUnifiedDomainMigratePerform, /* 0.3.2 */ .domainMigrateFinish = xenUnifiedDomainMigrateFinish, /* 0.3.2 */ .domainBlockStats = xenUnifiedDomainBlockStats, /* 0.3.2 */ .domainInterfaceStats = xenUnifiedDomainInterfaceStats, /* 0.3.2 */ .domainBlockPeek = xenUnifiedDomainBlockPeek, /* 0.4.4 */ .nodeGetCellsFreeMemory = xenUnifiedNodeGetCellsFreeMemory, /* 0.3.3 */ .nodeGetFreeMemory = xenUnifiedNodeGetFreeMemory, /* 0.3.3 */ .connectDomainEventRegister = xenUnifiedConnectDomainEventRegister, /* 0.5.0 */ .connectDomainEventDeregister = xenUnifiedConnectDomainEventDeregister, /* 0.5.0 */ .nodeDeviceDettach = xenUnifiedNodeDeviceDettach, /* 0.6.1 */ .nodeDeviceDetachFlags = xenUnifiedNodeDeviceDetachFlags, /* 1.0.5 */ .nodeDeviceReAttach = xenUnifiedNodeDeviceReAttach, /* 0.6.1 */ .nodeDeviceReset = xenUnifiedNodeDeviceReset, /* 0.6.1 */ .connectIsEncrypted = xenUnifiedConnectIsEncrypted, /* 0.7.3 */ .connectIsSecure = xenUnifiedConnectIsSecure, /* 0.7.3 */ .domainIsActive = xenUnifiedDomainIsActive, /* 0.7.3 */ .domainIsPersistent = xenUnifiedDomainIsPersistent, /* 0.7.3 */ .domainIsUpdated = xenUnifiedDomainIsUpdated, /* 0.8.6 */ .connectDomainEventRegisterAny = xenUnifiedConnectDomainEventRegisterAny, /* 0.8.0 */ .connectDomainEventDeregisterAny = xenUnifiedConnectDomainEventDeregisterAny, /* 0.8.0 */ .domainOpenConsole = xenUnifiedDomainOpenConsole, /* 0.8.6 */ .connectIsAlive = xenUnifiedConnectIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = xenUnifiedNodeSuspendForDuration, /* 0.9.8 */ .nodeGetMemoryParameters = xenUnifiedNodeGetMemoryParameters, /* 0.10.2 */ .nodeSetMemoryParameters = xenUnifiedNodeSetMemoryParameters, /* 0.10.2 */ }; /** * xenRegister: * * Register xen related drivers * * Returns the driver priority or -1 in case of error. */ int xenRegister(void) { if (virRegisterStateDriver(&state_driver) == -1) return -1; return virRegisterDriver(&xenUnifiedDriver); } /** * xenUnifiedDomainInfoListFree: * * Free the Domain Info List */ void xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr list) { size_t i; if (list == NULL) return; for (i=0; icount; i++) { VIR_FREE(list->doms[i]->name); VIR_FREE(list->doms[i]); } VIR_FREE(list->doms); VIR_FREE(list); } /** * xenUnifiedAddDomainInfo: * * Add name and uuid to the domain info list * * Returns: 0 on success, -1 on failure */ int xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr list, int id, char *name, unsigned char *uuid) { xenUnifiedDomainInfoPtr info; int n; /* check if we already have this callback on our list */ for (n=0; n < list->count; n++) { if (STREQ(list->doms[n]->name, name) && !memcmp(list->doms[n]->uuid, uuid, VIR_UUID_BUFLEN)) { VIR_DEBUG("WARNING: dom already tracked"); return -1; } } if (VIR_ALLOC(info) < 0) goto error; if (VIR_STRDUP(info->name, name) < 0) goto error; memcpy(info->uuid, uuid, VIR_UUID_BUFLEN); info->id = id; /* Make space on list */ n = list->count; if (VIR_REALLOC_N(list->doms, n + 1) < 0) { goto error; } list->doms[n] = info; list->count++; return 0; error: if (info) VIR_FREE(info->name); VIR_FREE(info); return -1; } /** * xenUnifiedRemoveDomainInfo: * * Removes name and uuid to the domain info list * * Returns: 0 on success, -1 on failure */ int xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr list, int id, char *name, unsigned char *uuid) { size_t i; for (i = 0; i < list->count; i++) { if (list->doms[i]->id == id && STREQ(list->doms[i]->name, name) && !memcmp(list->doms[i]->uuid, uuid, VIR_UUID_BUFLEN)) { VIR_FREE(list->doms[i]->name); VIR_FREE(list->doms[i]); if (i < (list->count - 1)) memmove(list->doms + i, list->doms + i + 1, sizeof(*(list->doms)) * (list->count - (i + 1))); if (VIR_REALLOC_N(list->doms, list->count - 1) < 0) { ; /* Failure to reduce memory allocation isn't fatal */ } list->count--; return 0; } } return -1; } /** * xenUnifiedDomainEventDispatch: * @priv: the connection to dispatch events on * @event: the event to dispatch * * Dispatch domain events to registered callbacks * * The caller must hold the lock in 'priv' before invoking * */ void xenUnifiedDomainEventDispatch(xenUnifiedPrivatePtr priv, virObjectEventPtr event) { if (!priv) return; virObjectEventStateQueue(priv->domainEvents, event); } void xenUnifiedLock(xenUnifiedPrivatePtr priv) { virMutexLock(&priv->lock); } void xenUnifiedUnlock(xenUnifiedPrivatePtr priv) { virMutexUnlock(&priv->lock); }