/*
* 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);
}