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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list