QEMU recently added support for cpu hotplug upstream that will support
plugging arbitrary cpus. Additionally guest-agent-based cpu state
modification from the guest point of view was added recently.
This API will help monitoring the state of vCPUs using the two
apporoaches as a support infrastructure for the modification APIs.
---
daemon/remote.c | 54 ++++++++++++++++++++++++++++++
include/libvirt/libvirt.h.in | 21 ++++++++++++
python/generator.py | 1 +
python/libvirt-override-api.xml | 7 ++++
python/libvirt-override.c | 66 ++++++++++++++++++++++++++++++++++++
src/driver.h | 6 ++++
src/libvirt.c | 74 +++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 6 ++++
src/remote/remote_driver.c | 47 ++++++++++++++++++++++++++
src/remote/remote_protocol.x | 18 +++++++++-
src/remote_protocol-structs | 13 ++++++++
11 files changed, 312 insertions(+), 1 deletion(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 47267c2..e02ac7e 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -4583,6 +4583,60 @@ cleanup:
return rv;
}
+
+static int
+remoteDispatchDomainGetVcpuMap(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_vcpu_map_args *args,
+ remote_domain_get_vcpu_map_ret *ret)
+{
+ unsigned char *cpumap = NULL;
+ unsigned int flags;
+ int cpunum;
+ int rv = -1;
+ virDomainPtr dom = NULL;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ flags = args->flags;
+
+ cpunum = virDomainGetVCPUMap(dom,
+ args->need_map ? &cpumap : NULL,
+ flags);
+ if (cpunum < 0)
+ goto cleanup;
+
+ /* 'serialize' return cpumap */
+ if (args->need_map) {
+ ret->cpumap.cpumap_len = VIR_CPU_MAPLEN(cpunum);
+ ret->cpumap.cpumap_val = (char *) cpumap;
+ cpumap = NULL;
+ }
+
+ ret->ret = cpunum;
+
+ rv = 0;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ if (dom)
+ virDomainFree(dom);
+ VIR_FREE(cpumap);
+ return rv;
+}
+
+
static int
lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client ATTRIBUTE_UNUSED,
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index e057be1..c8f639a 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -4859,6 +4859,27 @@ int virNWFilterGetUUIDString (virNWFilterPtr
nwfilter,
char *buf);
char * virNWFilterGetXMLDesc (virNWFilterPtr nwfilter,
unsigned int flags);
+
+/**
+ * virDomainGetVCPUMapFlags
+ *
+ * Since 1.0.6
+ */
+typedef enum {
+ VIR_DOMAIN_VCPU_MAP_HYPERVISOR = (1 << 0), /* request data from hypervisor */
+ VIR_DOMAIN_VCPU_MAP_AGENT = (1 << 1), /* request data from guest agent */
+
+ VIR_DOMAIN_VCPU_MAP_POSSIBLE = (1 << 2), /* map all possible vcpus */
+ VIR_DOMAIN_VCPU_MAP_ONLINE = (1 << 3), /* map all online vcpus */
+ VIR_DOMAIN_VCPU_MAP_OFFLINE = (1 << 4), /* map all offline vcpus */
+ VIR_DOMAIN_VCPU_MAP_OFFLINABLE = (1 << 5), /* map all vcpus that can be
offlined */
+ VIR_DOMAIN_VCPU_MAP_ACTIVE = (1 << 6), /* map cpus that are in use by the guest
*/
+} virDomainGetVCPUMapFlags;
+
+int virDomainGetVCPUMap(virDomainPtr dom,
+ unsigned char **cpumap,
+ unsigned int flags);
+
/**
* virDomainConsoleFlags
*
diff --git a/python/generator.py b/python/generator.py
index 8c380bb..4884c29 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -458,6 +458,7 @@ skip_impl = (
'virNodeGetMemoryParameters',
'virNodeSetMemoryParameters',
'virNodeGetCPUMap',
+ 'virDomainGetVCPUMap',
)
lxc_skip_impl = (
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
index 155ab36..7725800 100644
--- a/python/libvirt-override-api.xml
+++ b/python/libvirt-override-api.xml
@@ -584,5 +584,12 @@
<arg name='conn' type='virConnectPtr' info='pointer to the
hypervisor connection'/>
<arg name='flags' type='int' info='unused, pass 0'/>
</function>
+ <function name='virDomainGetVCPUMap' file='python'>
+ <info>Get node CPU information</info>
+ <return type='char *' info='(cpunum, cpumap) on success, None on
error'/>
+ <arg name='dom' type='virDomainPtr' info='pointer to the
domain'/>
+ <arg name='flags' type='unsigned int' info='an
OR'ed set of virDomainGetVCPUMapFlags'/>
+ </function>
+
</symbols>
</api>
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index b6462c2..fb451c9 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -6759,6 +6759,71 @@ error:
}
+static PyObject *
+libvirt_virDomainGetVCPUMap(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ virDomainPtr domain;
+ PyObject *pyobj_domain;
+ PyObject *ret = NULL;
+ PyObject *pycpumap = NULL;
+ PyObject *pyused = NULL;
+ PyObject *pycpunum = NULL;
+ PyObject *pyonline = NULL;
+ int i_retval;
+ unsigned char *cpumap = NULL;
+ unsigned int flags;
+ int i;
+
+ if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetVCPUMap",
+ &pyobj_domain, &flags))
+ return NULL;
+
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ i_retval = virDomainGetVCPUMap(domain, &cpumap, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (i_retval < 0)
+ return VIR_PY_NONE;
+
+ if (!(ret = PyTuple_New(2)))
+ goto error;
+
+ /* 0: number of CPUs */
+ if ((pycpunum = PyLong_FromLong(i_retval)) == NULL ||
+ PyTuple_SetItem(ret, 0, pycpunum) < 0)
+ goto error;
+
+ /* 1: CPU map */
+ if ((pycpumap = PyList_New(i_retval)) == NULL)
+ goto error;
+
+ for (i = 0; i < i_retval; i++) {
+ if ((pyused = PyBool_FromLong(VIR_CPU_USED(cpumap, i))) == NULL)
+ goto error;
+ if (PyList_SetItem(pycpumap, i, pyused) < 0)
+ goto error;
+ }
+
+ if (PyTuple_SetItem(ret, 1, pycpumap) < 0)
+ goto error;
+
+cleanup:
+ VIR_FREE(cpumap);
+ return ret;
+error:
+ Py_XDECREF(ret);
+ Py_XDECREF(pycpumap);
+ Py_XDECREF(pyused);
+ Py_XDECREF(pycpunum);
+ Py_XDECREF(pyonline);
+ ret = NULL;
+ goto cleanup;
+}
+
+
/************************************************************************
* *
* The registration stuff *
@@ -6882,6 +6947,7 @@ static PyMethodDef libvirtMethods[] = {
{(char *) "virNodeGetMemoryParameters", libvirt_virNodeGetMemoryParameters,
METH_VARARGS, NULL},
{(char *) "virNodeSetMemoryParameters", libvirt_virNodeSetMemoryParameters,
METH_VARARGS, NULL},
{(char *) "virNodeGetCPUMap", libvirt_virNodeGetCPUMap, METH_VARARGS,
NULL},
+ {(char *) "virDomainGetVCPUMap", libvirt_virDomainGetVCPUMap, METH_VARARGS,
NULL},
{NULL, NULL, 0, NULL}
};
diff --git a/src/driver.h b/src/driver.h
index ec5fc53..cbafdce 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -1045,6 +1045,11 @@ typedef int
int **fdlist,
unsigned int flags);
+typedef int
+(*virDrvDomainGetVCPUMap)(virDomainPtr dom,
+ unsigned char **cpumap,
+ unsigned int flags);
+
typedef struct _virDriver virDriver;
typedef virDriver *virDriverPtr;
@@ -1246,6 +1251,7 @@ struct _virDriver {
virDrvDomainFSTrim domainFSTrim;
virDrvDomainSendProcessSignal domainSendProcessSignal;
virDrvDomainLxcOpenNamespace domainLxcOpenNamespace;
+ virDrvDomainGetVCPUMap domainGetVCPUMap;
};
diff --git a/src/libvirt.c b/src/libvirt.c
index 820519a..59e02a1 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -9526,6 +9526,80 @@ error:
return -1;
}
+
+/**
+ * virDomainGetVCPUMap:
+ * @domain: pointer to domain object
+ * @cpumap: pointer to a pointer where the returned cpumap will be stored
+ * @flags: bitwise-OR of virDomainGetVCPUMapFlags
+ *
+ * Request a map of virtual processors of a domain. Use @flags to control
+ * the data contained in the map.
+ *
+ * If @flags is 0 this function behaves as if flags
+ * VIR_DOMAIN_VCPU_MAP_HYPERVISOR and VIR_DOMAIN_VCPU_MAP_POSSIBLE were
+ * specified.
+ *
+ * When @flags contains VIR_DOMAIN_VCPU_MAP_AGENT the guest agent is used
+ * to query the requested data from the point of view of the guest.
+ *
+ * Returns the length of @cpumap or -1 in case of error.
+ */
+int
+virDomainGetVCPUMap(virDomainPtr domain,
+ unsigned char **cpumap,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(domain);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ conn = domain->conn;
+
+ if ((flags & (VIR_DOMAIN_VCPU_MAP_HYPERVISOR |
+ VIR_DOMAIN_VCPU_MAP_AGENT)) == 0)
+ flags |= VIR_DOMAIN_VCPU_MAP_HYPERVISOR;
+
+ if ((flags & (VIR_DOMAIN_VCPU_MAP_POSSIBLE |
+ VIR_DOMAIN_VCPU_MAP_ONLINE |
+ VIR_DOMAIN_VCPU_MAP_OFFLINE |
+ VIR_DOMAIN_VCPU_MAP_OFFLINABLE)) == 0)
+ flags |= VIR_DOMAIN_VCPU_MAP_ONLINE;
+
+ if (flags & VIR_DOMAIN_VCPU_MAP_HYPERVISOR &&
+ flags & VIR_DOMAIN_VCPU_MAP_AGENT) {
+ virReportInvalidArg(flags,
+ _("flags VIR_DOMAIN_VCPU_MAP_HYPERVISOR and "
+ "VIR_DOMAIN_VCPU_MAP_AGENT in %s "
+ "are mutually exclusive"),
+ __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->driver->domainGetVCPUMap) {
+ int ret;
+ ret = conn->driver->domainGetVCPUMap(domain, cpumap, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(domain->conn);
+ return -1;
+
+}
+
/**
* virDomainGetSecurityLabel:
* @domain: a domain object
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 4ee2d27..04465be 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -621,4 +621,10 @@ LIBVIRT_1.0.6 {
virGetLastErrorMessage;
} LIBVIRT_1.0.5;
+LIBVIRT_1.0.7 {
+ global:
+ virDomainGetVCPUMap;
+} LIBVIRT_1.0.6;
+
+
# .... define new API here using predicted next version number ....
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 2cda559..99fa3c1 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -5951,6 +5951,52 @@ done:
static int
+remoteDomainGetVCPUMap(virDomainPtr dom,
+ unsigned char **cpumap,
+ unsigned int flags)
+{
+ int rv = -1;
+ remote_domain_get_vcpu_map_args args;
+ remote_domain_get_vcpu_map_ret ret;
+ struct private_data *priv = dom->conn->privateData;
+
+ remoteDriverLock(priv);
+
+ args.need_map = !!cpumap;
+ args.flags = flags;
+ make_nonnull_domain(&args.dom, dom);
+
+ memset(&ret, 0, sizeof(ret));
+ if (call(dom->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_VCPU_MAP,
+ (xdrproc_t) xdr_remote_domain_get_vcpu_map_args,
+ (char *) &args,
+ (xdrproc_t) xdr_remote_domain_get_vcpu_map_ret,
+ (char *) &ret) == -1)
+ goto done;
+
+ if (ret.ret < 0)
+ goto cleanup;
+
+ if (cpumap) {
+ if (VIR_ALLOC_N(*cpumap, ret.cpumap.cpumap_len) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ memcpy(*cpumap, ret.cpumap.cpumap_val, ret.cpumap.cpumap_len);
+ }
+
+ rv = ret.ret;
+
+cleanup:
+ xdr_free((xdrproc_t) xdr_remote_domain_get_vcpu_map_ret, (char *) &ret);
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
+
+static int
remoteDomainLxcOpenNamespace(virDomainPtr domain,
int **fdlist,
unsigned int flags)
@@ -6348,6 +6394,7 @@ static virDriver remote_driver = {
.nodeGetCPUMap = remoteNodeGetCPUMap, /* 1.0.0 */
.domainFSTrim = remoteDomainFSTrim, /* 1.0.1 */
.domainLxcOpenNamespace = remoteDomainLxcOpenNamespace, /* 1.0.2 */
+ .domainGetVCPUMap = remoteDomainGetVCPUMap, /* 1.0.7 */
};
static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 9723377..cec3541 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2737,6 +2737,17 @@ struct remote_node_get_cpu_map_ret {
int ret;
};
+struct remote_domain_get_vcpu_map_args {
+ remote_nonnull_domain dom;
+ int need_map;
+ unsigned int flags;
+};
+
+struct remote_domain_get_vcpu_map_ret {
+ opaque cpumap<REMOTE_CPUMAP_MAX>;
+ int ret;
+};
+
struct remote_domain_fstrim_args {
remote_nonnull_domain dom;
remote_string mountPoint;
@@ -4434,6 +4445,11 @@ enum remote_procedure {
/**
* @generate: server
*/
- REMOTE_PROC_NODE_DEVICE_DETACH_FLAGS = 301
+ REMOTE_PROC_NODE_DEVICE_DETACH_FLAGS = 301,
+
+ /**
+ * @generate: none
+ */
+ REMOTE_PROC_DOMAIN_GET_VCPU_MAP = 302
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index ea38ea2..e1ceabd 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2186,6 +2186,18 @@ struct remote_node_get_cpu_map_ret {
u_int online;
int ret;
};
+struct remote_domain_get_vcpu_map_args {
+ remote_nonnull_domain dom;
+ int need_map;
+ u_int flags;
+};
+struct remote_domain_get_vcpu_map_ret {
+ struct {
+ u_int cpumap_len;
+ char * cpumap_val;
+ } cpumap;
+ int ret;
+};
struct remote_domain_fstrim_args {
remote_nonnull_domain dom;
remote_string mountPoint;
@@ -2494,4 +2506,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_MIGRATE_GET_COMPRESSION_CACHE = 299,
REMOTE_PROC_DOMAIN_MIGRATE_SET_COMPRESSION_CACHE = 300,
REMOTE_PROC_NODE_DEVICE_DETACH_FLAGS = 301,
+ REMOTE_PROC_DOMAIN_GET_VCPU_MAP = 302,
};
--
1.8.2.1