[libvirt] [PATCH 05/11] lib: Add API to map virtual cpus of a guest

Peter Krempa pkrempa at redhat.com
Mon May 27 17:59:56 UTC 2013


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 0e253bf..bb0640a 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 1804c93..46d499c 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -4858,6 +4858,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 6ed2624..016b192 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 e998adf..0caa2d6 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -1047,6 +1047,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;

@@ -1248,6 +1253,7 @@ struct _virDriver {
     virDrvDomainFSTrim domainFSTrim;
     virDrvDomainSendProcessSignal domainSendProcessSignal;
     virDrvDomainLxcOpenNamespace domainLxcOpenNamespace;
+    virDrvDomainGetVCPUMap domainGetVCPUMap;
 };


diff --git a/src/libvirt.c b/src/libvirt.c
index b129611..3f51e83 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -9499,6 +9499,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 1ebbce7..7db6be3 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




More information about the libvir-list mailing list