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