diff --git a/daemon/remote.c b/daemon/remote.c index 9251576b4a8cede7400db18acebcf202014b788e..35eb39fd99a8be3c99725bf78245e5cff9ef8342 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -6383,6 +6383,92 @@ remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED, } +static int +remoteDispatchConnectGetAllDomainStats(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_get_all_domain_stats_args *args, + remote_connect_get_all_domain_stats_ret *ret) +{ + int rv = -1; + size_t i; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virDomainStatsRecordPtr *retStats = NULL; + int nrecords = 0; + virDomainPtr *doms = NULL; + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (args->doms.doms_len) { + if (VIR_ALLOC_N(doms, args->doms.doms_len + 1) < 0) + goto cleanup; + + for (i = 0; i < args->doms.doms_len; i++) { + if (!(doms[i] = get_nonnull_domain(priv->conn, args->doms.doms_val[i]))) + goto cleanup; + } + + if ((nrecords = virDomainListGetStats(doms, + args->stats, + &retStats, + args->flags)) < 0) + goto cleanup; + } else { + if ((nrecords = virConnectGetAllDomainStats(priv->conn, + args->stats, + &retStats, + args->flags)) < 0) + goto cleanup; + } + + if (nrecords > REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of domain stats records is %d, " + "which exceeds max limit: %d"), + nrecords, REMOTE_DOMAIN_LIST_MAX); + goto cleanup; + } + + if (nrecords) { + if (VIR_ALLOC_N(ret->retStats.retStats_val, nrecords) < 0) + goto cleanup; + + ret->retStats.retStats_len = nrecords; + + for (i = 0; i < nrecords; i++) { + remote_domain_stats_record *dst = ret->retStats.retStats_val + i; + + make_nonnull_domain(&dst->dom, retStats[i]->dom); + + if (remoteSerializeTypedParameters(retStats[i]->params, + retStats[i]->nparams, + &dst->params.params_val, + &dst->params.params_len, + VIR_TYPED_PARAM_STRING_OKAY) < 0) + goto cleanup; + } + } else { + ret->retStats.retStats_len = 0; + ret->retStats.retStats_val = NULL; + } + + rv = 0; + + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + + virDomainStatsRecordListFree(retStats); + virDomainListFree(doms); + + return rv; +} + + /*----- 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 e949223bc9764811e54a8f6802283bfca7c3a39a..fda27f7f649a0ec9d6d6287def615c98b1ccb336 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7717,6 +7717,89 @@ remoteNetworkGetDHCPLeases(virNetworkPtr net, } +static int +remoteConnectGetAllDomainStats(virConnectPtr conn, + virDomainPtr *doms, + unsigned int ndoms, + unsigned int stats, + virDomainStatsRecordPtr **retStats, + unsigned int flags) +{ + struct private_data *priv = conn->networkPrivateData; + int rv = -1; + size_t i; + remote_connect_get_all_domain_stats_args args; + remote_connect_get_all_domain_stats_ret ret; + + virDomainStatsRecordPtr *tmpret = NULL; + + if (ndoms) { + if (VIR_ALLOC_N(args.doms.doms_val, ndoms) < 0) + goto cleanup; + + for (i = 0; i < ndoms; i++) + make_nonnull_domain(args.doms.doms_val + i, doms[i]); + } + args.doms.doms_len = ndoms; + + args.stats = stats; + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + + remoteDriverLock(priv); + if (call(conn, priv, 0, REMOTE_PROC_CONNECT_GET_ALL_DOMAIN_STATS, + (xdrproc_t)xdr_remote_connect_get_all_domain_stats_args, (char *)&args, + (xdrproc_t)xdr_remote_connect_get_all_domain_stats_ret, (char *)&ret) == -1) { + remoteDriverUnlock(priv); + goto cleanup; + } + remoteDriverUnlock(priv); + + if (ret.retStats.retStats_len > REMOTE_DOMAIN_LIST_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of stats entries is %d, which exceeds max limit: %d"), + ret.retStats.retStats_len, REMOTE_DOMAIN_LIST_MAX); + goto cleanup; + } + + *retStats = NULL; + + if (VIR_ALLOC_N(tmpret, ret.retStats.retStats_len + 1) < 0) + goto cleanup; + + for (i = 0; i < ret.retStats.retStats_len; i++) { + virDomainStatsRecordPtr elem; + remote_domain_stats_record *rec = ret.retStats.retStats_val + i; + + if (VIR_ALLOC(elem) < 0) + goto cleanup; + + if (!(elem->dom = get_nonnull_domain(conn, rec->dom))) + goto cleanup; + + if (remoteDeserializeTypedParameters(rec->params.params_val, + rec->params.params_len, + REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX, + &elem->params, + &elem->nparams)) + goto cleanup; + + tmpret[i] = elem; + } + + *retStats = tmpret; + tmpret = NULL; + rv = ret.retStats.retStats_len; + + cleanup: + virDomainStatsRecordListFree(tmpret); + xdr_free((xdrproc_t)xdr_remote_connect_get_all_domain_stats_ret, + (char *) &ret); + + return rv; +} + /* get_nonnull_domain and get_nonnull_network turn an on-wire * (name, uuid) pair into virDomainPtr or virNetworkPtr object. * These can return NULL if underlying memory allocations fail, @@ -8056,6 +8139,7 @@ static virDriver remote_driver = { .domainSetTime = remoteDomainSetTime, /* 1.2.5 */ .nodeGetFreePages = remoteNodeGetFreePages, /* 1.2.6 */ .connectGetDomainCapabilities = remoteConnectGetDomainCapabilities, /* 1.2.7 */ + .connectGetAllDomainStats = remoteConnectGetAllDomainStats, /* 1.2.8 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 6dc2d292507ca77b3a355564623336f4737c9479..8fc552f3129508d636e637ff71a5461061665186 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -241,6 +241,9 @@ const REMOTE_DOMAIN_FSFREEZE_MOUNTPOINTS_MAX = 256; /* Upper limit on the maximum number of leases in one lease file */ const REMOTE_NETWORK_DHCP_LEASES_MAX = 65536; +/* Upper limit on count of parameters returned via bulk stats API */ +const REMOTE_CONNECT_GET_ALL_DOMAIN_STATS_MAX = 4096; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -3063,6 +3066,20 @@ struct remote_network_get_dhcp_leases_ret { unsigned int ret; }; +struct remote_domain_stats_record { + remote_nonnull_domain dom; + remote_typed_param params; +}; + +struct remote_connect_get_all_domain_stats_args { + remote_nonnull_domain doms; + unsigned int stats; + unsigned int flags; +}; + +struct remote_connect_get_all_domain_stats_ret { + remote_domain_stats_record retStats; +}; /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -5432,6 +5449,12 @@ enum remote_procedure { * @generate: none * @acl: domain:open_graphics */ - REMOTE_PROC_DOMAIN_OPEN_GRAPHICS_FD = 343 + REMOTE_PROC_DOMAIN_OPEN_GRAPHICS_FD = 343, + /** + * @generate: none + * @acl: connect:search_domains + * @aclfilter: domain:read + */ + REMOTE_PROC_CONNECT_GET_ALL_DOMAIN_STATS = 344 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 38bf0b8582a434c4d01dcea36ee7aefacf844986..899f1cc64e10a0914d4da9e4eeffdf466f00f89d 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2524,6 +2524,27 @@ struct remote_network_get_dhcp_leases_ret { } leases; u_int ret; }; +struct remote_domain_stats_record { + remote_nonnull_domain dom; + struct { + u_int params_len; + remote_typed_param * params_val; + } params; +}; +struct remote_connect_get_all_domain_stats_args { + struct { + u_int doms_len; + remote_nonnull_domain * doms_val; + } doms; + u_int stats; + u_int flags; +}; +struct remote_connect_get_all_domain_stats_ret { + struct { + u_int retStats_len; + remote_domain_stats_record * retStats_val; + } retStats; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -2868,4 +2889,5 @@ enum remote_procedure { REMOTE_PROC_NETWORK_GET_DHCP_LEASES = 341, REMOTE_PROC_CONNECT_GET_DOMAIN_CAPABILITIES = 342, REMOTE_PROC_DOMAIN_OPEN_GRAPHICS_FD = 343, + REMOTE_PROC_CONNECT_GET_ALL_DOMAIN_STATS = 344, };