From 3f48d6fdb52a47e88e708f345e689dcc890f1cf5 Mon Sep 17 00:00:00 2001
From: Jim Fehlig <jfehlig@suse.com>
Date: Mon, 27 Jun 2022 15:48:31 -0600
Subject: lxc: implement connectGetAllDomainStats

From: <cbosdonnat@suse.com>

LXC containers can also provide some statistics. Allow users to fetch
them using the existing API.
---
 src/lxc/lxc_driver.c | 125 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

Index: libvirt-8.0.0/src/lxc/lxc_driver.c
===================================================================
--- libvirt-8.0.0.orig/src/lxc/lxc_driver.c
+++ libvirt-8.0.0/src/lxc/lxc_driver.c
@@ -74,6 +74,8 @@
 #include "netdev_bandwidth_conf.h"
 #include "virsocket.h"
 #include "virutil.h"
+#include "viralloc.h"
+#include "domain_stats.h"
 
 #define VIR_FROM_THIS VIR_FROM_LXC
 
@@ -5036,6 +5038,128 @@ lxcDomainHasManagedSaveImage(virDomainPt
     return ret;
 }
 
+static int
+lxcDomainGetStatsCpu(virDomainObj *dom,
+                     virTypedParamList *params)
+{
+    virLXCDomainObjPrivate *priv = dom->privateData;
+    return virCgroupGetStatsCpu(priv->cgroup, params);
+}
+
+typedef int
+(*lxcDomainGetStatsFunc)(virDomainObj *dom,
+                         virTypedParamList *params);
+
+
+struct lxcDomainGetStatsWorker {
+    lxcDomainGetStatsFunc func;
+    unsigned int stats;
+};
+
+static struct lxcDomainGetStatsWorker lxcDomainGetStatsWorkers[] = {
+    { virDomainStatsGetState, VIR_DOMAIN_STATS_STATE },
+    { lxcDomainGetStatsCpu, VIR_DOMAIN_STATS_CPU_TOTAL },
+    { virDomainStatsGetInterface, VIR_DOMAIN_STATS_INTERFACE },
+    { NULL, 0 }
+};
+
+static int
+lxcDomainGetStats(virConnectPtr conn,
+                  virDomainObj *dom,
+                  unsigned int stats,
+                  virDomainStatsRecordPtr *record)
+{
+    g_autofree virDomainStatsRecordPtr tmp = g_new0(virDomainStatsRecord, 1);
+    g_autoptr(virTypedParamList) params = g_new0(virTypedParamList, 1);
+    size_t i;
+
+    for (i = 0; lxcDomainGetStatsWorkers[i].func; i++) {
+        if (stats & lxcDomainGetStatsWorkers[i].stats) {
+            if (lxcDomainGetStatsWorkers[i].func(dom, params) < 0)
+                return -1;
+        }
+    }
+
+    if (!(tmp->dom = virGetDomain(conn, dom->def->name,
+                                  dom->def->uuid, dom->def->id)))
+        return -1;
+
+    tmp->nparams = virTypedParamListStealParams(params, &tmp->params);
+    *record = g_steal_pointer(&tmp);
+    return 0;
+}
+
+static int
+lxcConnectGetAllDomainStats(virConnectPtr conn,
+                            virDomainPtr *doms,
+                            unsigned int ndoms,
+                            unsigned int stats,
+                            virDomainStatsRecordPtr **retStats,
+                            unsigned int flags)
+{
+    virLXCDriver *driver = conn->privateData;
+    virDomainObj **vms = NULL;
+    virDomainObj *vm;
+    size_t nvms;
+    virDomainStatsRecordPtr *tmpstats = NULL;
+    int nstats = 0;
+    size_t i;
+    int ret = -1;
+    unsigned int lflags = flags & (VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
+                                   VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
+                                   VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE);
+
+    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
+                  VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
+                  VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE, -1);
+
+    if (virConnectGetAllDomainStatsEnsureACL(conn) < 0)
+        return -1;
+
+    /* TODO Check stats support */
+
+    if (ndoms) {
+        if (virDomainObjListConvert(driver->domains, conn, doms, ndoms, &vms,
+                                    &nvms, virConnectGetAllDomainStatsCheckACL,
+                                    lflags, true) < 0)
+            return -1;
+    } else {
+        if (virDomainObjListCollect(driver->domains, conn, &vms, &nvms,
+                                    virConnectGetAllDomainStatsCheckACL,
+                                    lflags) < 0)
+            return -1;
+    }
+
+    tmpstats = g_new0(virDomainStatsRecordPtr, nvms + 1);
+
+    for (i = 0; i < nvms; i++) {
+        virDomainStatsRecordPtr tmp = NULL;
+        vm = vms[i];
+
+        virObjectLock(vm);
+
+        if (lxcDomainGetStats(conn, vm, stats, &tmp) < 0) {
+            virObjectUnlock(vm);
+            goto cleanup;
+        }
+
+        if (tmp)
+            tmpstats[nstats++] = tmp;
+
+        virObjectUnlock(vm);
+    }
+
+    *retStats = tmpstats;
+    tmpstats = NULL;
+
+    ret = nstats;
+
+ cleanup:
+    virDomainStatsRecordListFree(tmpstats);
+    virObjectListFreeCount(vms, nvms);
+
+    return ret;
+}
 
 /* Function Tables */
 static virHypervisorDriver lxcHypervisorDriver = {
@@ -5133,6 +5257,7 @@ static virHypervisorDriver lxcHypervisor
     .nodeGetFreePages = lxcNodeGetFreePages, /* 1.2.6 */
     .nodeAllocPages = lxcNodeAllocPages, /* 1.2.9 */
     .domainHasManagedSaveImage = lxcDomainHasManagedSaveImage, /* 1.2.13 */
+    .connectGetAllDomainStats = lxcConnectGetAllDomainStats, /* 3.11.0 */
 };
 
 static virConnectDriver lxcConnectDriver = {
