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