[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH V4 2/5] remote handler for virDomainGetCPUStats()



remote protocol driver for virDomainGetCPUStats()

Note:
Unlike other users of virTypedParameter with RPC, this interface
can return zero-filled entries because the interface assumes
2 dimentional array. Then, the function has its own serialize/deserialize
routine.

 daemon/remote.c              |  146 +++++++++++++++++++++++++++++++++++++++++++
 src/remote/remote_driver.c   |  117 ++++++++++++++++++++++++++++++++++
 src/remote/remote_protocol.x |   22 ++++++
 src/remote_protocol-structs  |   15 ++++
---
 daemon/remote.c              |  147 ++++++++++++++++++++++++++++++++++++++++++
 src/remote/remote_driver.c   |  117 +++++++++++++++++++++++++++++++++
 src/remote/remote_protocol.x |   22 ++++++-
 src/remote_protocol-structs  |   15 ++++
 4 files changed, 300 insertions(+), 1 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 1ada146..0bf3262 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -3505,6 +3505,153 @@ cleanup:
     return rv;
 }
 
+static int
+remoteDispatchDomainGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+                                virNetMessageErrorPtr rerr,
+                                remote_domain_get_cpu_stats_args *args,
+                                remote_domain_get_cpu_stats_ret *ret)
+{
+    virDomainPtr dom = NULL;
+    struct daemonClientPrivate *priv;
+    virTypedParameterPtr params = NULL;
+    remote_typed_param *info = NULL;
+    int cpu, idx, src, dest;
+    int rv = -1;
+    unsigned int return_size = 0;
+    int percpu_len = 0;
+
+    priv = virNetServerClientGetPrivateData(client);
+    if (!priv->conn) {
+        virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+        goto cleanup;
+    }
+
+    /*
+     * nparams * ncpus should be smaller than
+     * REMOTE_DOMAIN_GET_CPU_STATS_MAX but nparams
+     * and ncpus are limited by API. check it.
+     */
+    if (args->nparams > 16) {
+        virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+        goto cleanup;
+    }
+    if (args->ncpus > 128) {
+        virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpus too large"));
+        goto cleanup;
+    }
+
+    if (args->nparams > 0) {
+        if (VIR_ALLOC_N(params, args->ncpus * args->nparams) < 0)
+            goto no_memory;
+    }
+
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+        goto cleanup;
+
+    percpu_len = virDomainGetCPUStats(dom, params, args->nparams,
+                                args->start_cpu, args->ncpus, args->flags);
+    if (percpu_len < 0)
+        goto cleanup;
+    /* If nparams == 0, the function returns a sigle value */
+    if (args->nparams == 0)
+        goto success;
+
+    /*
+     * Here, we return values based on the real param size returned by
+     * a driver rather than the passed one. RPC Client stub should decode
+     * it to fit callar's expectation.
+     *
+     * If cpu ID is sparse, The whole array for some cpu IDs will be
+     * zero-cleared. This doesn't meet to remoteSerializeTypedParameters()
+     * and we do serialization by ourselves.
+     */
+    return_size = percpu_len * args->ncpus;
+    if (VIR_ALLOC_N(info, return_size) < 0)
+        goto no_memory;
+
+    for (cpu = 0; cpu < args->ncpus; ++cpu) {
+        for (idx = 0; idx < percpu_len; ++idx) {
+            src = cpu * args->nparams + idx;
+            dest = cpu * percpu_len + idx;
+
+            /* If CPU ID is discontiguous, this can happen */
+            if (params[src].type == 0)
+                continue;
+
+            info[dest].field = strdup(params[src].field);
+            if (info[dest].field == NULL)
+                goto no_memory;
+
+            info[dest].value.type = params[src].type;
+
+            switch (params[src].type) {
+            case VIR_TYPED_PARAM_INT:
+                info[dest].value.remote_typed_param_value_u.i =
+                    params[src].value.i;
+                break;
+            case VIR_TYPED_PARAM_UINT:
+                info[dest].value.remote_typed_param_value_u.ui =
+                    params[src].value.ui;
+                break;
+            case VIR_TYPED_PARAM_LLONG:
+                info[dest].value.remote_typed_param_value_u.l =
+                    params[src].value.l;
+                break;
+            case VIR_TYPED_PARAM_ULLONG:
+                info[dest].value.remote_typed_param_value_u.ul =
+                    params[src].value.ul;
+                break;
+            case VIR_TYPED_PARAM_DOUBLE:
+                info[dest].value.remote_typed_param_value_u.d =
+                    params[src].value.d;
+                break;
+            case VIR_TYPED_PARAM_BOOLEAN:
+                info[dest].value.remote_typed_param_value_u.b =
+                    params[src].value.b;
+                break;
+            case VIR_TYPED_PARAM_STRING:
+                info[dest].value.remote_typed_param_value_u.s =
+                    strdup(params[src].value.s);
+                if (info[dest].value.remote_typed_param_value_u.s == NULL)
+                    goto no_memory;
+                break;
+            default:
+                virNetError(VIR_ERR_RPC, _("unknown parameter type: %d"),
+                            params[src].type);
+                goto cleanup;
+            }
+        }
+    }
+success:
+    rv = 0;
+    ret->params.params_len = return_size;
+    ret->params.params_val = info;
+    ret->nparams = percpu_len;
+cleanup:
+    if (rv < 0) {
+         virNetMessageSaveError(rerr);
+         if (info) {
+             int i;
+             for (i = 0; i < return_size; i++) {
+                 VIR_FREE(info[i].field);
+                 if (info[i].value.type == VIR_TYPED_PARAM_STRING)
+                     VIR_FREE(info[i].value.remote_typed_param_value_u.s);
+             }
+             VIR_FREE(info);
+         }
+    }
+    virTypedParameterArrayClear(params, args->ncpus * args->nparams);
+    VIR_FREE(params);
+    if (dom)
+        virDomainFree(dom);
+    return rv;
+no_memory:
+    virReportOOMError();
+    goto cleanup;
+}
+
 /*----- Helpers. -----*/
 
 /* get_nonnull_domain and get_nonnull_network turn an on-wire
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index f79f53e..9f548ed 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -2305,6 +2305,122 @@ done:
     return rv;
 }
 
+static int remoteDomainGetCPUStats(virDomainPtr domain,
+                                   virTypedParameterPtr params,
+                                   unsigned int nparams,
+                                   int start_cpu,
+                                   unsigned int ncpus,
+                                   unsigned int flags)
+{
+    struct private_data *priv = domain->conn->privateData;
+    remote_domain_get_cpu_stats_args args;
+    remote_domain_get_cpu_stats_ret ret;
+    remote_typed_param *info;
+    int rv = -1;
+    int cpu, idx, src, dest;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain(&args.dom, domain);
+    args.nparams = nparams;
+    args.start_cpu = start_cpu;
+    args.ncpus = ncpus;
+    args.flags = flags;
+
+    memset(&ret, 0, sizeof(ret));
+
+    if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_CPU_STATS,
+             (xdrproc_t) xdr_remote_domain_get_cpu_stats_args,
+             (char *) &args,
+             (xdrproc_t) xdr_remote_domain_get_cpu_stats_ret,
+             (char *) &ret) == -1)
+        goto done;
+
+    if (nparams == 0) {
+        rv = ret.nparams;
+        goto cleanup;
+    }
+    /*
+     * the returned arrray's size is not same to nparams * ncpus. And
+     * if cpu ID is not contiguous, all-zero entries can be found.
+     */
+    memset(params, 0, sizeof(virTypedParameter) * nparams * ncpus);
+
+    /* Here, ret.nparams is always smaller than nparams */
+    info = ret.params.params_val;
+
+    for (cpu = 0; cpu < ncpus; ++cpu) {
+        for (idx = 0; idx < ret.nparams; ++idx) {
+            src = cpu * ret.nparams + idx;
+            dest = cpu * nparams + idx;
+
+            if (info[src].value.type == 0) /* skip zeroed ones */
+                continue;
+
+            params[dest].type = info[src].value.type;
+            strcpy(params[dest].field, info[src].field);
+
+            switch (params[dest].type) {
+            case VIR_TYPED_PARAM_INT:
+                params[dest].value.i =
+                    info[src].value.remote_typed_param_value_u.i;
+                break;
+            case VIR_TYPED_PARAM_UINT:
+                params[dest].value.ui =
+                    info[src].value.remote_typed_param_value_u.ui;
+                break;
+            case VIR_TYPED_PARAM_LLONG:
+                params[dest].value.l =
+                    info[src].value.remote_typed_param_value_u.l;
+                break;
+            case VIR_TYPED_PARAM_ULLONG:
+                params[dest].value.ul =
+                    info[src].value.remote_typed_param_value_u.ul;
+                break;
+            case VIR_TYPED_PARAM_DOUBLE:
+                params[dest].value.d =
+                    info[src].value.remote_typed_param_value_u.d;
+                break;
+            case VIR_TYPED_PARAM_BOOLEAN:
+                params[dest].value.b =
+                    info[src].value.remote_typed_param_value_u.b;
+                break;
+            case VIR_TYPED_PARAM_STRING:
+                params[dest].value.s =
+                    strdup(info[src].value.remote_typed_param_value_u.s);
+                if (params[dest].value.s == NULL)
+                    goto out_of_memory;
+                break;
+            default:
+                remoteError(VIR_ERR_RPC, _("unknown parameter type: %d"),
+                            params[dest].type);
+                goto cleanup;
+            }
+        }
+    }
+
+    rv = ret.nparams;
+cleanup:
+    if (rv < 0) {
+        int max = nparams * ncpus;
+        int i;
+
+        for (i = 0; i < max; i++) {
+            if (params[i].type == VIR_TYPED_PARAM_STRING)
+                VIR_FREE(params[i].value.s);
+        }
+    }
+    xdr_free ((xdrproc_t) xdr_remote_domain_get_cpu_stats_ret,
+              (char *) &ret);
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+out_of_memory:
+    virReportOOMError();
+    goto cleanup;
+}
+
+
 /*----------------------------------------------------------------------*/
 
 static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
@@ -4751,6 +4867,7 @@ static virDriver remote_driver = {
     .domainGetBlockIoTune = remoteDomainGetBlockIoTune, /* 0.9.8 */
     .domainSetNumaParameters = remoteDomainSetNumaParameters, /* 0.9.9 */
     .domainGetNumaParameters = remoteDomainGetNumaParameters, /* 0.9.9 */
+    .domainGetCPUStats = remoteDomainGetCPUStats, /* 0.9.10 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 0f354bb..205aeeb 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -208,6 +208,12 @@ const REMOTE_DOMAIN_SEND_KEY_MAX = 16;
  */
 const REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX = 16;
 
+/*
+ * Upper limit on list of (real) cpu parameters
+ * nparams(<=16) * ncpus(<=128) <= 2048.
+ */
+const REMOTE_DOMAIN_GET_CPU_STATS_MAX = 2048;
+
 /* UUID.  VIR_UUID_BUFLEN definition comes from libvirt.h */
 typedef opaque remote_uuid[VIR_UUID_BUFLEN];
 
@@ -1149,6 +1155,19 @@ struct remote_domain_get_block_io_tune_ret {
     int nparams;
 };
 
+struct remote_domain_get_cpu_stats_args {
+    remote_nonnull_domain dom;
+    unsigned int nparams;
+    int          start_cpu;
+    unsigned int ncpus;
+    unsigned int flags;
+};
+
+struct remote_domain_get_cpu_stats_ret {
+    remote_typed_param params<REMOTE_DOMAIN_GET_CPU_STATS_MAX>;
+    int nparams;
+};
+
 /* Network calls: */
 
 struct remote_num_of_networks_ret {
@@ -2667,7 +2686,8 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_SET_INTERFACE_PARAMETERS = 256, /* autogen autogen */
     REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS = 258, /* autogen autogen */
-    REMOTE_PROC_STORAGE_VOL_WIPE_PATTERN = 259 /* autogen autogen */
+    REMOTE_PROC_STORAGE_VOL_WIPE_PATTERN = 259, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_GET_CPU_STATS = 260 /* skipgen skipgen */
 
     /*
      * Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index de85862..8dd5801 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1841,6 +1841,20 @@ struct remote_domain_shutdown_flags_args {
         remote_nonnull_domain      dom;
         u_int                      flags;
 };
+struct remote_domain_get_cpu_stats_args {
+        remote_nonnull_domain      dom;
+        u_int                      nparams;
+        int                        start_cpu;
+        u_int                      ncpus;
+        u_int                      flags;
+};
+struct remote_domain_get_cpu_stats_ret {
+        struct {
+                u_int              params_len;
+                remote_typed_param * params_val;
+        } params;
+        int                        nparams;
+};
 enum remote_procedure {
         REMOTE_PROC_OPEN = 1,
         REMOTE_PROC_CLOSE = 2,
@@ -2101,4 +2115,5 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257,
         REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS = 258,
         REMOTE_PROC_STORAGE_VOL_WIPE_PATTERN = 259,
+        REMOTE_PROC_DOMAIN_GET_CPU_STATS = 260,
 };
-- 
1.7.4.1



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]