From cd0f3755bd04bb58089d756400f20c75550e54f2 Mon Sep 17 00:00:00 2001 From: tujipei Date: Wed, 12 Jun 2024 12:02:00 +0800 Subject: [PATCH] libvirt: add get tmm memory info API and libvirtd RPC Add the get tmm memory info API into libvirt-host. Also should add the RPC calls into libvirtd for API calling. Signed-off-by: tujipei --- include/libvirt/libvirt-host.h | 2 + scripts/apibuild.py | 1 + scripts/check-aclrules.py | 1 + src/driver-hypervisor.h | 5 + src/libvirt-host.c | 35 +++++++ src/libvirt_public.syms | 1 + src/qemu/qemu_driver.c | 139 ++++++++++++++++++++++++++++ src/remote/remote_daemon_dispatch.c | 23 +++++ src/remote/remote_driver.c | 29 ++++++ src/remote/remote_protocol.x | 16 +++- 10 files changed, 251 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h index 6972834175..e7272ccb20 100644 --- a/include/libvirt/libvirt-host.h +++ b/include/libvirt/libvirt-host.h @@ -820,5 +820,7 @@ int virNodeAllocPages(virConnectPtr conn, unsigned int cellCount, unsigned int flags); +char *virConnectGetTmmMemoryInfo(virConnectPtr conn, + unsigned int detail); #endif /* LIBVIRT_HOST_H */ diff --git a/scripts/apibuild.py b/scripts/apibuild.py index c98bcf6091..9b78754e5d 100755 --- a/scripts/apibuild.py +++ b/scripts/apibuild.py @@ -107,6 +107,7 @@ ignored_functions = { "virDomainMigrateConfirm3Params": "private function for migration", "virDomainMigratePrepareTunnel3Params": "private function for tunnelled migration", "virErrorCopyNew": "private", + "virConnectGetTmmMemoryInfo": "private function for tmm", } ignored_macros = { diff --git a/scripts/check-aclrules.py b/scripts/check-aclrules.py index e196f81de9..aa5a589c85 100755 --- a/scripts/check-aclrules.py +++ b/scripts/check-aclrules.py @@ -54,6 +54,7 @@ whitelist = { "localOnly": True, "domainQemuAttach": True, "domainHotpatchManage": True, + "connectGetTmmMemoryInfo": True, } # XXX this vzDomainMigrateConfirm3Params looks diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 82f808905d..e48b701365 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1402,6 +1402,10 @@ typedef int typedef struct _virHypervisorDriver virHypervisorDriver; typedef virHypervisorDriver *virHypervisorDriverPtr; +typedef char * +(*virDrvConnectGetTmmMemoryInfo)(virConnectPtr conn, + bool detail); + /** * _virHypervisorDriver: * @@ -1664,4 +1668,5 @@ struct _virHypervisorDriver { virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc; virDrvDomainHotpatchManage domainHotpatchManage; virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc; + virDrvConnectGetTmmMemoryInfo connectGetTmmMemoryInfo; }; diff --git a/src/libvirt-host.c b/src/libvirt-host.c index bc3d1d2803..d0750d28cc 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1754,3 +1754,38 @@ virNodeGetSEVInfo(virConnectPtr conn, virDispatchError(conn); return -1; } + +/* + * virConnectGetTmmMemoryInfo: + * @conn: pointer to the hypervisor connection + * @detail: whether libvirtd return detailed tmm memory information; + * the default value is 0 which means don't return detailed tmm memory information. + * + * If Tmm enable, then will fill the cotents of string buffer with tmm memory information. + * + * Returns string ptr in case of success, and NULL in case of failure. + */ +char * +virConnectGetTmmMemoryInfo(virConnectPtr conn, + unsigned int detail) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + + virCheckConnectReturn(conn, NULL); + + if (conn->driver->connectGetTmmMemoryInfo) { + char *ret; + ret = conn->driver->connectGetTmmMemoryInfo(conn, detail); + if (!ret) + goto error; + return ret; + } + + virReportUnsupportedError(); + error: + virDispatchError(conn); + return NULL; +} + diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index f006516208..284b7f7873 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -877,5 +877,6 @@ LIBVIRT_6.2.0 { global: virDomainHotpatchManage; virDomainStartDirtyRateCalc; + virConnectGetTmmMemoryInfo; } LIBVIRT_6.0.0; # .... define new API here using predicted next version number .... diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 77a139c66b..1e3f63a39a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -23385,6 +23385,144 @@ qemuDomainStartDirtyRateCalc(virDomainPtr dom, return ret; } +static int +qemuConnectTmmInfoListAppend(char ***targetInfoStrList, + char **infoStrList, + int targetNumaNum, + int *startIndex, + int maxListSize) +{ + char *numStart; + int numaNode, index, ret = 0; + + for (index = *startIndex; index < maxListSize; index++) { + if (strlen(infoStrList[index]) == 0) + break; + + numStart = strstr(infoStrList[index], "node "); + if (!numStart) + return -1; + + virSkipToDigit((const char **)(&numStart)); + ret = virStrToLong_i(numStart, &numStart, 10, &numaNode); + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to get current numa node")); + return ret; + } + + if (numaNode == targetNumaNum) { + ret = virStringListAdd(targetInfoStrList, infoStrList[index]); + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s [%d]", + _("Failed to get add info list member"), index); + return ret; + } + } else { + break; + } + } + + *startIndex = index; + + return ret; +} + +static char * +qemuConnectTmmDetailInfoFormat(char *baseMeminfo, + char *slabInfo) +{ + int ret, i = 0, j = 0; + char *numStart, *numListStart, *format = NULL; + char **baseMeminfoSplits = virStringSplit(baseMeminfo, "\n", 0); + char **slabInfoSplits = virStringSplit(slabInfo, "\n", 0); + char **resultStrList = NULL; + int numaSize, numaIndex, headNumaNode; + ssize_t meminfoListSize = virStringListLength((const char * const *)baseMeminfoSplits); + ssize_t slabInfoSize = virStringListLength((const char * const *)slabInfoSplits); + + numStart = strchr(baseMeminfoSplits[i], ':'); + numListStart = strchr(baseMeminfoSplits[i], '('); + if (!numStart || !numListStart) + goto cleanup; + + virSkipToDigit((const char **)(&numStart)); + ret = virStrToLong_i(numStart, &numStart, 10, &numaSize); + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to get available numa size")); + goto cleanup; + } + + ret = virStringListAdd(&resultStrList, baseMeminfoSplits[i++]); + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s [%d]", + _("Failed to get add base memory info list member"), (i - 1)); + goto cleanup; + } + + virSkipToDigit((const char **)(&numListStart)); + for (numaIndex = 0; *numListStart && numaIndex < numaSize; numaIndex++, numListStart++) { + ret = virStrToLong_i(numListStart, &numListStart, 10, &headNumaNode); + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to get current numa node")); + goto cleanup; + } + + ret = qemuConnectTmmInfoListAppend(&resultStrList, baseMeminfoSplits, headNumaNode, &i, meminfoListSize); + if (ret < 0) + goto cleanup; + ret = qemuConnectTmmInfoListAppend(&resultStrList, slabInfoSplits, headNumaNode, &j, slabInfoSize); + if (ret < 0) + goto cleanup; + } + + format = virStringListJoin((const char **)resultStrList, "\n"); + + cleanup: + virStringListFree(baseMeminfoSplits); + virStringListFree(slabInfoSplits); + virStringListFree(resultStrList); + return format; +} + +static char * +qemuConnectGetTmmMemoryInfo(virConnectPtr conn G_GNUC_UNUSED, + bool detail) +{ + int maxLen = 10 * 1024; + char *meminfo = NULL; + g_autofree char *formatInfo = NULL; + g_autofree char *baseMeminfo = NULL; + g_autofree char *slabInfo = NULL; + g_autofree char *buddyInfo = NULL; + + if (virFileReadAll("/sys/kernel/tmm/memory_info", maxLen, &baseMeminfo) < 0) + goto end; + if (detail && virFileReadAll("/sys/kernel/tmm/slab_info", maxLen, &slabInfo) < 0) + goto end; + if (detail && virFileReadAll("/sys/kernel/tmm/buddy_info", maxLen, &buddyInfo) < 0) + goto end; + + if (detail) { + if (!virStringIsEmpty(baseMeminfo) && !virStringIsEmpty(slabInfo)) { + formatInfo = qemuConnectTmmDetailInfoFormat(baseMeminfo, slabInfo); + if (formatInfo == NULL) + goto end; + } else { + formatInfo = g_strdup_printf(_("%s%s"), baseMeminfo, slabInfo); + } + + meminfo = g_strdup_printf(_("%s\n%s"), formatInfo, buddyInfo); + } else { + meminfo = g_steal_pointer(&baseMeminfo); + } + +end: + return meminfo; +} + static virHypervisorDriver qemuHypervisorDriver = { .name = QEMU_DRIVER_NAME, @@ -23627,6 +23765,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */ .domainHotpatchManage = qemuDomainHotpatchManage, /* 6.2.0 */ .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 6.2.0 */ + .connectGetTmmMemoryInfo = qemuConnectGetTmmMemoryInfo, /* 6.2.0 */ }; diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index 0bbcc05235..a9763cee7b 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -7268,6 +7268,29 @@ remoteDispatchNetworkPortGetParameters(virNetServerPtr server G_GNUC_UNUSED, return rv; } +static int +remoteDispatchConnectGetTmmMemoryInfo(virNetServerPtr server G_GNUC_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg G_GNUC_UNUSED, + virNetMessageErrorPtr rerr, + remote_connect_get_tmm_memory_info_args *args, + remote_connect_get_tmm_memory_info_ret *ret) +{ + int rv = -1; + char *meminfo = NULL; + virConnectPtr conn = remoteGetHypervisorConn(client); + + if (conn && (meminfo = virConnectGetTmmMemoryInfo(conn, args->detail))) { + rv = 0; + ret->meminfo = meminfo; + } + + if (rv < 0) + virNetMessageSaveError(rerr); + + return rv; +} + /*----- Helpers. -----*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 9c272b4ff8..b597ae614c 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8253,6 +8253,34 @@ remoteDomainGetGuestInfo(virDomainPtr dom, return rv; } +static char * +remoteConnectGetTmmMemoryInfo(virConnectPtr conn, + bool detail) +{ + char *rv = NULL; + struct private_data *priv = conn->privateData; + remote_connect_get_tmm_memory_info_args args; + remote_connect_get_tmm_memory_info_ret ret; + + remoteDriverLock(priv); + + args.detail = detail; + + memset(&ret, 0, sizeof(ret)); + + if (call(conn, priv, 0, REMOTE_PROC_CONNECT_GET_TMM_MEMORY_INFO, + (xdrproc_t)xdr_remote_connect_get_tmm_memory_info_args, (char *)&args, + (xdrproc_t)xdr_remote_connect_get_tmm_memory_info_ret, (char *)&ret) < 0) { + goto done; + } + + rv = ret.meminfo; + + done: + remoteDriverUnlock(priv); + 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, @@ -8686,6 +8714,7 @@ static virHypervisorDriver hypervisor_driver = { .domainBackupGetXMLDesc = remoteDomainBackupGetXMLDesc, /* 6.0.0 */ .domainHotpatchManage = remoteDomainHotpatchManage, /* 6.2.0 */ .domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 6.2.0 */ + .connectGetTmmMemoryInfo = remoteConnectGetTmmMemoryInfo /* 6.2.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index d89cc1a087..f37bd332a1 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3789,6 +3789,14 @@ struct remote_domain_start_dirty_rate_calc_args { unsigned int flags; }; +struct remote_connect_get_tmm_memory_info_args { + unsigned int detail; +}; + +struct remote_connect_get_tmm_memory_info_ret { + remote_nonnull_string meminfo; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6698,5 +6706,11 @@ enum remote_procedure { * @generate: both * @acl: domain:read */ - REMOTE_PROC_DOMAIN_HOTPATCH_MANAGE = 800 + REMOTE_PROC_DOMAIN_HOTPATCH_MANAGE = 800, + + /** + * @generate: none + * @acl: connect:read + */ + REMOTE_PROC_CONNECT_GET_TMM_MEMORY_INFO = 900 }; -- 2.27.0