libvirt/src/xen/xen_driver.c
Daniel P. Berrange eed1de14b5 Simplify the Xen domain stats/peek / node memory driver methods
Make the Xen domain stats / peek and node memory driver
methods unconditionally call the sub-drivers which are
guaranteed to be open.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-05-09 13:16:20 +01:00

2259 lines
64 KiB
C

/*
* 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
* <http://www.gnu.org/licenses/>.
*
* Richard W.M. Jones <rjones@redhat.com>
*/
#include <config.h>
/* 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 <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <xen/dom0_ops.h>
#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"
#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
xenUnifiedDomainGetMaxVcpus(virDomainPtr dom);
static int
xenUnifiedDomainGetVcpus(virDomainPtr dom,
virVcpuInfoPtr info, int maxinfo,
unsigned char *cpumaps, int maplen);
static bool is_privileged = false;
/**
* 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
*
* 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)
{
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 = xenUnifiedDomainGetMaxVcpus(dom);
if (nb_vcpu <= 0)
return NULL;
if (xenUnifiedNodeGetInfo(dom->conn, &nodeinfo) < 0)
return NULL;
if (!(cpulist = virBitmapNew(priv->nbNodeCpus))) {
virReportOOMError();
goto done;
}
if (VIR_ALLOC_N(cpuinfo, nb_vcpu) < 0) {
virReportOOMError();
goto done;
}
cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
if (xalloc_oversized(nb_vcpu, cpumaplen) ||
VIR_ALLOC_N(cpumap, nb_vcpu * cpumaplen) < 0) {
virReportOOMError();
goto done;
}
if ((ncpus = xenUnifiedDomainGetVcpus(dom, 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;
return 0;
}
static virStateDriver state_driver = {
.name = "Xen",
.stateInitialize = xenUnifiedStateInitialize,
};
/*----- 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,
virDomainDefPtr 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;
}
virDomainDefParserConfig xenDomainDefParserConfig = {
.macPrefix = { 0x00, 0x16, 0x3e },
.devicesPostParseCallback = xenDomainDeviceDefPostParse,
};
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;
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;
/* 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;
}
}
#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
/* We now know the URI is definitely for this driver, so beyond
* here, don't return DECLINED, always use ERROR */
/* Allocate per-connection private data. */
if (VIR_ALLOC(priv) < 0) {
virReportOOMError();
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 = virDomainEventStateNew())) {
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 (!(priv->saveDir = strdup(XEN_SAVE_DIR))) {
virReportOOMError();
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);
virDomainEventStateFree(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 ATTRIBUTE_UNUSED)
{
return "Xen";
}
/* Which features are supported by this driver? */
static int
xenUnifiedConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
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)
{
return xenHypervisorGetVersion(conn, hvVer);
}
static char *xenUnifiedConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
{
return virGetHostname();
}
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 (type && STRCASENEQ(type, "Xen")) {
virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
return -1;
}
return xenHypervisorGetMaxVcpus(conn, type);
}
static int
xenUnifiedNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
{
return xenDaemonNodeGetInfo(conn, info);
}
static char *
xenUnifiedConnectGetCapabilities(virConnectPtr conn)
{
xenUnifiedPrivatePtr priv = conn->privateData;
char *xml;
if (!(xml = virCapabilitiesFormatXML(priv->caps))) {
virReportOOMError();
return NULL;
}
return xml;
}
static int
xenUnifiedConnectListDomains(virConnectPtr conn, int *ids, int maxids)
{
return xenStoreListDomains(conn, ids, maxids);
}
static int
xenUnifiedConnectNumOfDomains(virConnectPtr conn)
{
return xenStoreNumOfDomains(conn);
}
static virDomainPtr
xenUnifiedDomainCreateXML(virConnectPtr conn,
const char *xmlDesc, unsigned int flags)
{
virCheckFlags(0, NULL);
return xenDaemonCreateXML(conn, xmlDesc);
}
static virDomainPtr
xenUnifiedDomainLookupByID(virConnectPtr conn, int id)
{
virDomainPtr ret = NULL;
ret = xenHypervisorLookupDomainByID(conn, id);
if (!ret && virGetLastError() == NULL)
virReportError(VIR_ERR_NO_DOMAIN, __FUNCTION__);
return ret;
}
static virDomainPtr
xenUnifiedDomainLookupByUUID(virConnectPtr conn,
const unsigned char *uuid)
{
xenUnifiedPrivatePtr priv = conn->privateData;
virDomainPtr 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 virDomainPtr
xenUnifiedDomainLookupByName(virConnectPtr conn,
const char *name)
{
xenUnifiedPrivatePtr priv = conn->privateData;
virDomainPtr ret;
ret = xenDaemonLookupByName(conn, name);
/* Try XM for inactive domains. */
if (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 int
xenUnifiedDomainIsActive(virDomainPtr dom)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
virDomainPtr currdom;
int ret = -1;
/* ID field in dom may be outdated, so re-lookup */
currdom = xenHypervisorLookupDomainByUUID(dom->conn, dom->uuid);
/* Try XM for inactive domains. */
if (!currdom) {
if (priv->xendConfigVersion <= XEND_CONFIG_VERSION_3_0_3)
currdom = xenXMDomainLookupByUUID(dom->conn, dom->uuid);
else
currdom = xenDaemonLookupByUUID(dom->conn, dom->uuid);
}
if (currdom) {
ret = currdom->id == -1 ? 0 : 1;
virDomainFree(currdom);
} else if (virGetLastError() == NULL) {
virReportError(VIR_ERR_NO_DOMAIN, __FUNCTION__);
}
return ret;
}
static int
xenUnifiedDomainIsPersistent(virDomainPtr dom)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
virDomainPtr currdom = 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 */
currdom = xenXMDomainLookupByUUID(dom->conn, dom->uuid);
if (currdom)
ret = 1;
else
ret = 0;
} else {
/* New Xen with inactive domain management */
currdom = xenDaemonLookupByUUID(dom->conn, dom->uuid);
if (currdom) {
if (currdom->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) {
virReportOOMError();
goto done;
}
if (access(path, R_OK) == 0)
ret = 1;
else if (errno == ENOENT)
ret = 0;
}
}
}
done:
if (currdom)
virDomainFree(currdom);
return ret;
}
static int
xenUnifiedDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
{
return 0;
}
static int
xenUnifiedDomainSuspend(virDomainPtr dom)
{
return xenDaemonDomainSuspend(dom);
}
static int
xenUnifiedDomainResume(virDomainPtr dom)
{
return xenDaemonDomainResume(dom);
}
static int
xenUnifiedDomainShutdownFlags(virDomainPtr dom,
unsigned int flags)
{
virCheckFlags(0, -1);
return xenDaemonDomainShutdown(dom);
}
static int
xenUnifiedDomainShutdown(virDomainPtr dom)
{
return xenUnifiedDomainShutdownFlags(dom, 0);
}
static int
xenUnifiedDomainReboot(virDomainPtr dom, unsigned int flags)
{
virCheckFlags(0, -1);
return xenDaemonDomainReboot(dom);
}
static int
xenUnifiedDomainDestroyFlags(virDomainPtr dom,
unsigned int flags)
{
virCheckFlags(0, -1);
return xenDaemonDomainDestroy(dom);
}
static int
xenUnifiedDomainDestroy(virDomainPtr dom)
{
return xenUnifiedDomainDestroyFlags(dom, 0);
}
static char *
xenUnifiedDomainGetOSType(virDomainPtr dom)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (dom->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 {
return xenDaemonDomainGetOSType(dom);
}
} else {
return xenHypervisorDomainGetOSType(dom);
}
}
static unsigned long long
xenUnifiedDomainGetMaxMemory(virDomainPtr dom)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainGetMaxMemory(dom);
else
return xenDaemonDomainGetMaxMemory(dom);
} else {
return xenHypervisorGetMaxMemory(dom);
}
}
static int
xenUnifiedDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainSetMaxMemory(dom, memory);
else
return xenDaemonDomainSetMaxMemory(dom, memory);
} else {
return xenHypervisorSetMaxMemory(dom, memory);
}
}
static int
xenUnifiedDomainSetMemory(virDomainPtr dom, unsigned long memory)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainSetMemory(dom, memory);
else
return xenDaemonDomainSetMemory(dom, memory);
}
static int
xenUnifiedDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainGetInfo(dom, info);
else
return xenDaemonDomainGetInfo(dom, info);
} else {
return xenHypervisorGetDomainInfo(dom, info);
}
}
static int
xenUnifiedDomainGetState(virDomainPtr dom,
int *state,
int *reason,
unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
virCheckFlags(0, -1);
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainGetState(dom, state, reason);
else
return xenDaemonDomainGetState(dom, state, reason);
} else {
return xenHypervisorGetDomainState(dom, state, reason);
}
}
static int
xenUnifiedDomainSaveFlags(virDomainPtr dom, const char *to, const char *dxml,
unsigned int flags)
{
virCheckFlags(0, -1);
if (dxml) {
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
_("xml modification unsupported"));
return -1;
}
return xenDaemonDomainSave(dom, to);
}
static int
xenUnifiedDomainSave(virDomainPtr dom, const char *to)
{
return xenUnifiedDomainSaveFlags(dom, to, NULL, 0);
}
static char *
xenUnifiedDomainManagedSavePath(xenUnifiedPrivatePtr priv, virDomainPtr dom)
{
char *ret;
if (virAsprintf(&ret, "%s/%s.save", priv->saveDir, dom->name) < 0) {
virReportOOMError();
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;
int ret = -1;
virCheckFlags(0, -1);
name = xenUnifiedDomainManagedSavePath(priv, dom);
if (!name)
goto cleanup;
ret = xenDaemonDomainSave(dom, name);
cleanup:
VIR_FREE(name);
return ret;
}
static int
xenUnifiedDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
char *name;
int ret = -1;
virCheckFlags(0, -1);
name = xenUnifiedDomainManagedSavePath(priv, dom);
if (!name)
return ret;
ret = virFileExists(name);
VIR_FREE(name);
return ret;
}
static int
xenUnifiedDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
char *name;
int ret = -1;
virCheckFlags(0, -1);
name = xenUnifiedDomainManagedSavePath(priv, dom);
if (!name)
return ret;
ret = unlink(name);
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)
{
return xenDaemonDomainCoreDump(dom, to, flags);
}
static int
xenUnifiedDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
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;
}
/* 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)
return xenXMDomainSetVcpusFlags(dom, nvcpus, flags);
else
return xenDaemonDomainSetVcpusFlags(dom, nvcpus, flags);
}
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;
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainPinVcpu(dom, vcpu, cpumap, maplen);
else
return xenDaemonDomainPinVcpu(dom, vcpu, cpumap, maplen);
} else {
return xenHypervisorPinVcpu(dom, vcpu, cpumap, maplen);
}
}
static int
xenUnifiedDomainGetVcpus(virDomainPtr dom,
virVcpuInfoPtr info, int maxinfo,
unsigned char *cpumaps, int maplen)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
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"));
return -1;
} else {
return xenDaemonDomainGetVcpus(dom, info, maxinfo, cpumaps, maplen);
}
} else {
return xenHypervisorGetVcpus(dom, info, maxinfo, cpumaps, maplen);
}
}
static int
xenUnifiedDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
VIR_DOMAIN_VCPU_CONFIG |
VIR_DOMAIN_VCPU_MAXIMUM, -1);
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainGetVcpusFlags(dom, flags);
else
return xenDaemonDomainGetVcpusFlags(dom, flags);
} else {
if (flags == (VIR_DOMAIN_VCPU_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM))
return xenHypervisorGetVcpuMax(dom);
else
return xenDaemonDomainGetVcpusFlags(dom, flags);
}
}
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;
if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
return xenXMDomainGetXMLDesc(dom, flags);
} else {
char *cpus, *res;
xenUnifiedLock(priv);
cpus = xenDomainUsedCpus(dom);
xenUnifiedUnlock(priv);
res = xenDaemonDomainGetXMLDesc(dom, flags, cpus);
VIR_FREE(cpus);
return res;
}
}
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 (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)) {
id = xenGetDomIdFromSxprString(config, priv->xendConfigVersion);
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 (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) {
virReportOOMError();
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)
{
virCheckFlags(XEN_MIGRATION_FLAGS, -1);
return xenDaemonDomainMigratePerform(dom, cookie, cookielen, uri,
flags, dname, resource);
}
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)
{
virDomainPtr dom = NULL;
char *domain_xml = NULL;
virDomainPtr dom_new = NULL;
virCheckFlags(XEN_MIGRATION_FLAGS, NULL);
if (!(dom = xenUnifiedDomainLookupByName(dconn, dname)))
return NULL;
if (flags & VIR_MIGRATE_PERSIST_DEST) {
domain_xml = xenDaemonDomainGetXMLDesc(dom, 0, NULL);
if (! domain_xml) {
virReportError(VIR_ERR_MIGRATE_PERSIST_FAILED,
"%s", _("failed to get XML representation of migrated domain"));
goto error;
}
dom_new = xenDaemonDomainDefineXML(dconn, domain_xml);
if (! dom_new) {
virReportError(VIR_ERR_MIGRATE_PERSIST_FAILED,
"%s", _("failed to define domain on destination host"));
goto error;
}
/* Free additional reference added by Define */
virDomainFree(dom_new);
}
VIR_FREE(domain_xml);
return dom;
error:
virDomainFree(dom);
VIR_FREE(domain_xml);
return NULL;
}
static int
xenUnifiedConnectListDefinedDomains(virConnectPtr conn, char **const names,
int maxnames)
{
xenUnifiedPrivatePtr priv = conn->privateData;
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 (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;
char *name = NULL;
virCheckFlags(0, -1);
name = xenUnifiedDomainManagedSavePath(priv, dom);
if (!name)
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);
else
ret = xenDaemonDomainCreate(dom);
cleanup:
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;
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainDefineXML(conn, xml);
else
return xenDaemonDomainDefineXML(conn, xml);
}
static int
xenUnifiedDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
virCheckFlags(0, -1);
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainUndefine(dom);
else
return xenDaemonDomainUndefine(dom);
}
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;
/*
* 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 (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainAttachDeviceFlags(dom, xml, flags);
else
return xenDaemonAttachDeviceFlags(dom, xml, flags);
return -1;
}
static int
xenUnifiedDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainAttachDeviceFlags(dom, xml, flags);
else
return xenDaemonAttachDeviceFlags(dom, xml, flags);
}
static int
xenUnifiedDomainDetachDevice(virDomainPtr dom, const char *xml)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
unsigned int flags = VIR_DOMAIN_DEVICE_MODIFY_LIVE;
/*
* 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 (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainDetachDeviceFlags(dom, xml, flags);
else
return xenDaemonDetachDeviceFlags(dom, xml, flags);
}
static int
xenUnifiedDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainDetachDeviceFlags(dom, xml, flags);
else
return xenDaemonDetachDeviceFlags(dom, xml, flags);
}
static int
xenUnifiedDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
unsigned int flags)
{
return xenDaemonUpdateDeviceFlags(dom, xml, flags);
}
static int
xenUnifiedDomainGetAutostart(virDomainPtr dom, int *autostart)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainGetAutostart(dom, autostart);
else
return xenDaemonDomainGetAutostart(dom, autostart);
}
static int
xenUnifiedDomainSetAutostart(virDomainPtr dom, int autostart)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainSetAutostart(dom, autostart);
else
return xenDaemonDomainSetAutostart(dom, autostart);
}
static char *
xenUnifiedDomainGetSchedulerType(virDomainPtr dom, int *nparams)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot change scheduler parameters"));
return NULL;
}
return xenDaemonGetSchedulerType(dom, nparams);
} else {
return xenHypervisorGetSchedulerType(dom, nparams);
}
}
static int
xenUnifiedDomainGetSchedulerParametersFlags(virDomainPtr dom,
virTypedParameterPtr params,
int *nparams,
unsigned int flags)
{
xenUnifiedPrivatePtr priv = dom->conn->privateData;
virCheckFlags(0, -1);
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot change scheduler parameters"));
return -1;
}
return xenDaemonGetSchedulerParameters(dom, params, nparams);
} else {
return xenHypervisorGetSchedulerParameters(dom, params, nparams);
}
}
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;
virCheckFlags(0, -1);
if (dom->id < 0) {
if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot change scheduler parameters"));
return -1;
}
return xenDaemonSetSchedulerParameters(dom, params, nparams);
} else {
return xenHypervisorSetSchedulerParameters(dom, params, nparams);
}
}
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)
{
return xenHypervisorDomainBlockStats(dom, path, stats);
}
static int
xenUnifiedDomainInterfaceStats(virDomainPtr dom, const char *path,
struct _virDomainInterfaceStats *stats)
{
return xenHypervisorDomainInterfaceStats(dom, path, stats);
}
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;
virCheckFlags(0, -1);
if (dom->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
return xenXMDomainBlockPeek(dom, path, offset, size, buffer);
else
return xenDaemonDomainBlockPeek(dom, path, offset, size, buffer);
}
static int
xenUnifiedNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems,
int startCell, int maxCells)
{
return xenHypervisorNodeGetCellsFreeMemory(conn, freeMems,
startCell, maxCells);
}
static unsigned long long
xenUnifiedNodeGetFreeMemory(virConnectPtr conn)
{
unsigned long long freeMem = 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;
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;
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;
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;
xenUnifiedLock(priv);
if (priv->xsWatch == -1) {
virReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
xenUnifiedUnlock(priv);
return -1;
}
ret = virDomainEventStateDeregisterID(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) {
virPCIDeviceSetStubDriver(pci, "pciback");
} else {
virReportError(VIR_ERR_INVALID_ARG,
_("unknown driver name '%s'"), driverName);
goto out;
}
if (virPCIDeviceDetach(pci, NULL, 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, 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) {
virReportOOMError();
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) {
virReportOOMError();
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 ATTRIBUTE_UNUSED,
virTypedParameterPtr params,
int *nparams,
unsigned int flags)
{
return nodeGetMemoryParameters(params, nparams, flags);
}
static int
xenUnifiedNodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED,
virTypedParameterPtr params,
int nparams,
unsigned int flags)
{
return nodeSetMemoryParameters(params, nparams, flags);
}
static int
xenUnifiedNodeSuspendForDuration(virConnectPtr conn ATTRIBUTE_UNUSED,
unsigned int target,
unsigned long long duration,
unsigned int flags)
{
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 */
.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)
{
int i;
if (list == NULL)
return;
for (i=0; i<list->count; 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 memory_error;
if (!(info->name = strdup(name)))
goto memory_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 memory_error;
}
list->doms[n] = info;
list->count++;
return 0;
memory_error:
virReportOOMError();
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)
{
int 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,
virDomainEventPtr event)
{
if (!priv)
return;
virDomainEventStateQueue(priv->domainEvents, event);
}
void xenUnifiedLock(xenUnifiedPrivatePtr priv)
{
virMutexLock(&priv->lock);
}
void xenUnifiedUnlock(xenUnifiedPrivatePtr priv)
{
virMutexUnlock(&priv->lock);
}