From 498e53c0294b9fb97c1d9ce4df4d08cca77b04cc Mon Sep 17 00:00:00 2001
From: Jim Fehlig <jfehlig@suse.com>
Date: Mon, 27 Jun 2022 15:47:03 -0600
Subject: Extract stats functions from the qemu driver

From: <cbosdonnat@suse.com>

Some of the qemu functions getting statistics can easily be reused in
other drivers. Create a conf/domain_stats.[ch] pair to host some of
them.
---
 src/conf/domain_stats.c  | 117 +++++++++++++++++++++++++++++++++++++++
 src/conf/domain_stats.h  |  55 ++++++++++++++++++
 src/conf/meson.build     |   1 +
 src/libvirt_private.syms |   6 ++
 src/qemu/qemu_driver.c   |  88 ++---------------------------
 src/util/vircgroup.c     |  33 +++++++++++
 src/util/vircgroup.h     |   4 ++
 7 files changed, 220 insertions(+), 84 deletions(-)
 create mode 100644 src/conf/domain_stats.c
 create mode 100644 src/conf/domain_stats.h

Index: libvirt-8.0.0/src/conf/domain_stats.c
===================================================================
--- /dev/null
+++ libvirt-8.0.0/src/conf/domain_stats.c
@@ -0,0 +1,117 @@
+/*
+ * domain_stats.c: domain stats extraction helpers
+ *
+ * Copyright (C) 2006-2016 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ * Copyright (c) 2018 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "virlog.h"
+#include "domain_stats.h"
+#include "virtypedparam.h"
+#include "virnetdevtap.h"
+#include "virnetdevopenvswitch.h"
+
+#define VIR_FROM_THIS VIR_FROM_DOMAIN
+
+VIR_LOG_INIT("conf.domain_stats");
+
+int
+virDomainStatsGetState(virDomainObj *dom,
+                       virTypedParamList *params)
+{
+    if (virTypedParamListAddInt(params, dom->state.state, "state.state") < 0)
+        return -1;
+
+    if (virTypedParamListAddInt(params, dom->state.reason, "state.reason") < 0)
+        return -1;
+
+    return 0;
+}
+
+#define STATS_ADD_NET_PARAM(params, num, name, value) \
+    if (value >= 0 && \
+        virTypedParamListAddULLong((params), (value), "net.%zu.%s", (num), (name)) < 0) \
+        return -1;
+
+int
+virDomainStatsGetInterface(virDomainObj *dom,
+                           virTypedParamList *params)
+{
+    size_t i;
+    struct _virDomainInterfaceStats tmp;
+
+    if (!virDomainObjIsActive(dom))
+        return 0;
+
+    if (virTypedParamListAddUInt(params, dom->def->nnets, "net.count") < 0)
+        return -1;
+
+    /* Check the path is one of the domain's network interfaces. */
+    for (i = 0; i < dom->def->nnets; i++) {
+        virDomainNetDef *net = dom->def->nets[i];
+        virDomainNetType actualType;
+
+        if (!net->ifname)
+            continue;
+
+        memset(&tmp, 0, sizeof(tmp));
+
+        actualType = virDomainNetGetActualType(net);
+
+        if (virTypedParamListAddString(params, net->ifname, "net.%zu.name", i) < 0)
+            return -1;
+
+        if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
+            if (virNetDevOpenvswitchInterfaceStats(net->ifname, &tmp) < 0) {
+                virResetLastError();
+                continue;
+            }
+        } else {
+            if (virNetDevTapInterfaceStats(net->ifname, &tmp,
+                                           !virDomainNetTypeSharesHostView(net)) < 0) {
+                virResetLastError();
+                continue;
+            }
+        }
+
+        STATS_ADD_NET_PARAM(params, i,
+                            "rx.bytes", tmp.rx_bytes);
+        STATS_ADD_NET_PARAM(params, i,
+                            "rx.pkts", tmp.rx_packets);
+        STATS_ADD_NET_PARAM(params, i,
+                            "rx.errs", tmp.rx_errs);
+        STATS_ADD_NET_PARAM(params, i,
+                            "rx.drop", tmp.rx_drop);
+        STATS_ADD_NET_PARAM(params, i,
+                            "tx.bytes", tmp.tx_bytes);
+        STATS_ADD_NET_PARAM(params, i,
+                            "tx.pkts", tmp.tx_packets);
+        STATS_ADD_NET_PARAM(params, i,
+                            "tx.errs", tmp.tx_errs);
+        STATS_ADD_NET_PARAM(params, i,
+                            "tx.drop", tmp.tx_drop);
+    }
+
+    return 0;
+}
+
+#undef STATS_ADD_NET_PARAM
Index: libvirt-8.0.0/src/conf/domain_stats.h
===================================================================
--- /dev/null
+++ libvirt-8.0.0/src/conf/domain_stats.h
@@ -0,0 +1,55 @@
+/*
+ * domain_stats.h: domain stats extraction helpers
+ *
+ * Copyright (C) 2006-2016 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ * Copyright (c) 2018 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "internal.h"
+#include "domain_conf.h"
+
+
+#define VIR_DOMAIN_STATS_ADD_COUNT_PARAM(record, maxparams, type, count) \
+do { \
+    g_autofree char *param_name = g_strdup_printf("%s.count", type); \
+    if (virTypedParamsAddUInt(&(record)->params, \
+                              &(record)->nparams, \
+                              maxparams, \
+                              param_name, \
+                              count) < 0) \
+        goto cleanup; \
+} while (0)
+
+#define VIR_DOMAIN_STATS_ADD_NAME_PARAM(record, maxparams, type, subtype, num, name) \
+do { \
+    g_autofree char *param_name = g_strdup_printf("%s.%zu.%s", type, num, subtype); \
+    if (virTypedParamsAddString(&(record)->params, \
+                                &(record)->nparams, \
+                                maxparams, \
+                                param_name, \
+                                name) < 0) \
+        goto cleanup; \
+} while (0)
+
+int virDomainStatsGetState(virDomainObj *dom,
+                           virTypedParamList *params);
+
+int virDomainStatsGetInterface(virDomainObj *dom,
+                           virTypedParamList *params);
Index: libvirt-8.0.0/src/conf/meson.build
===================================================================
--- libvirt-8.0.0.orig/src/conf/meson.build
+++ libvirt-8.0.0/src/conf/meson.build
@@ -15,6 +15,7 @@ domain_conf_sources = [
   'domain_conf.c',
   'domain_nwfilter.c',
   'domain_validate.c',
+  'domain_stats.c',
   'moment_conf.c',
   'numa_conf.c',
   'snapshot_conf.c',
Index: libvirt-8.0.0/src/libvirt_private.syms
===================================================================
--- libvirt-8.0.0.orig/src/libvirt_private.syms
+++ libvirt-8.0.0/src/libvirt_private.syms
@@ -774,6 +774,11 @@ virDomainConfNWFilterTeardown;
 virDomainConfVMNWFilterTeardown;
 
 
+# conf/domain_stats.h
+virDomainStatsGetInterface;
+virDomainStatsGetState;
+
+
 # conf/domain_validate.h
 virDomainActualNetDefValidate;
 virDomainDefValidate;
@@ -1944,6 +1949,7 @@ virCgroupGetMemoryUsage;
 virCgroupGetMemSwapHardLimit;
 virCgroupGetMemSwapUsage;
 virCgroupGetPercpuStats;
+virCgroupGetStatsCpu;
 virCgroupHasController;
 virCgroupHasEmptyTasks;
 virCgroupKillPainfully;
Index: libvirt-8.0.0/src/qemu/qemu_driver.c
===================================================================
--- libvirt-8.0.0.orig/src/qemu/qemu_driver.c
+++ libvirt-8.0.0/src/qemu/qemu_driver.c
@@ -68,6 +68,7 @@
 #include "virarptable.h"
 #include "viruuid.h"
 #include "domain_conf.h"
+#include "domain_stats.h"
 #include "domain_audit.h"
 #include "domain_cgroup.h"
 #include "domain_driver.h"
@@ -17411,13 +17412,7 @@ qemuDomainGetStatsState(virQEMUDriver *d
                         virTypedParamList *params,
                         unsigned int privflags G_GNUC_UNUSED)
 {
-    if (virTypedParamListAddInt(params, dom->state.state, "state.state") < 0)
-        return -1;
-
-    if (virTypedParamListAddInt(params, dom->state.reason, "state.reason") < 0)
-        return -1;
-
-    return 0;
+    return virDomainStatsGetState(dom, params);
 }
 
 
@@ -17709,25 +17704,11 @@ qemuDomainGetStatsCpuCgroup(virDomainObj
                             virTypedParamList *params)
 {
     qemuDomainObjPrivate *priv = dom->privateData;
-    unsigned long long cpu_time = 0;
-    unsigned long long user_time = 0;
-    unsigned long long sys_time = 0;
-    int err = 0;
 
     if (!priv->cgroup)
         return 0;
 
-    err = virCgroupGetCpuacctUsage(priv->cgroup, &cpu_time);
-    if (!err && virTypedParamListAddULLong(params, cpu_time, "cpu.time") < 0)
-        return -1;
-
-    err = virCgroupGetCpuacctStat(priv->cgroup, &user_time, &sys_time);
-    if (!err && virTypedParamListAddULLong(params, user_time, "cpu.user") < 0)
-        return -1;
-    if (!err && virTypedParamListAddULLong(params, sys_time, "cpu.system") < 0)
-        return -1;
-
-    return 0;
+    return virCgroupGetStatsCpu(priv->cgroup, params);
 }
 
 static int
@@ -17920,76 +17901,15 @@ qemuDomainGetStatsVcpu(virQEMUDriver *dr
     return ret;
 }
 
-#define QEMU_ADD_NET_PARAM(params, num, name, value) \
-    if (value >= 0 && \
-        virTypedParamListAddULLong((params), (value), "net.%zu.%s", (num), (name)) < 0) \
-        return -1;
-
 static int
 qemuDomainGetStatsInterface(virQEMUDriver *driver G_GNUC_UNUSED,
                             virDomainObj *dom,
                             virTypedParamList *params,
                             unsigned int privflags G_GNUC_UNUSED)
 {
-    size_t i;
-    struct _virDomainInterfaceStats tmp;
-
-    if (!virDomainObjIsActive(dom))
-        return 0;
-
-    if (virTypedParamListAddUInt(params, dom->def->nnets, "net.count") < 0)
-        return -1;
-
-    /* Check the path is one of the domain's network interfaces. */
-    for (i = 0; i < dom->def->nnets; i++) {
-        virDomainNetDef *net = dom->def->nets[i];
-        virDomainNetType actualType;
-
-        if (!net->ifname)
-            continue;
-
-        memset(&tmp, 0, sizeof(tmp));
-
-        actualType = virDomainNetGetActualType(net);
-
-        if (virTypedParamListAddString(params, net->ifname, "net.%zu.name", i) < 0)
-            return -1;
-
-        if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
-            if (virNetDevOpenvswitchInterfaceStats(net->ifname, &tmp) < 0) {
-                virResetLastError();
-                continue;
-            }
-        } else {
-            if (virNetDevTapInterfaceStats(net->ifname, &tmp,
-                                           !virDomainNetTypeSharesHostView(net)) < 0) {
-                virResetLastError();
-                continue;
-            }
-        }
-
-        QEMU_ADD_NET_PARAM(params, i,
-                           "rx.bytes", tmp.rx_bytes);
-        QEMU_ADD_NET_PARAM(params, i,
-                           "rx.pkts", tmp.rx_packets);
-        QEMU_ADD_NET_PARAM(params, i,
-                           "rx.errs", tmp.rx_errs);
-        QEMU_ADD_NET_PARAM(params, i,
-                           "rx.drop", tmp.rx_drop);
-        QEMU_ADD_NET_PARAM(params, i,
-                           "tx.bytes", tmp.tx_bytes);
-        QEMU_ADD_NET_PARAM(params, i,
-                           "tx.pkts", tmp.tx_packets);
-        QEMU_ADD_NET_PARAM(params, i,
-                           "tx.errs", tmp.tx_errs);
-        QEMU_ADD_NET_PARAM(params, i,
-                           "tx.drop", tmp.tx_drop);
-    }
-
-    return 0;
+    return virDomainStatsGetInterface(dom, params);
 }
 
-#undef QEMU_ADD_NET_PARAM
 
 /* refresh information by opening images on the disk */
 static int
Index: libvirt-8.0.0/src/util/vircgroup.c
===================================================================
--- libvirt-8.0.0.orig/src/util/vircgroup.c
+++ libvirt-8.0.0/src/util/vircgroup.c
@@ -3022,6 +3022,31 @@ virCgroupGetInode(virCgroup *cgroup)
     return st.st_ino;
 }
 
+int
+virCgroupGetStatsCpu(virCgroup *cgroup,
+                     virTypedParamList *params)
+{
+    unsigned long long cpu_time = 0;
+    unsigned long long user_time = 0;
+    unsigned long long sys_time = 0;
+    int err = 0;
+
+    if (!cgroup)
+        return 0;
+
+    err = virCgroupGetCpuacctUsage(cgroup, &cpu_time);
+    if (!err && virTypedParamListAddULLong(params, cpu_time, "cpu.time") < 0)
+        return -1;
+
+    err = virCgroupGetCpuacctStat(cgroup, &user_time, &sys_time);
+    if (!err && virTypedParamListAddULLong(params, user_time, "cpu.user") < 0)
+        return -1;
+    if (!err && virTypedParamListAddULLong(params, sys_time, "cpu.system") < 0)
+        return -1;
+
+    return 0;
+}
+
 #else /* !__linux__ */
 
 bool
@@ -3031,6 +3056,14 @@ virCgroupAvailable(void)
 }
 
 
+int
+virCgroupGetStatsCpu(virCgroup *cgroup,
+                     virTypedParamList *params)
+{
+    return 0;
+}
+
+
 int
 virCgroupNewPartition(const char *path G_GNUC_UNUSED,
                       bool create G_GNUC_UNUSED,
Index: libvirt-8.0.0/src/util/vircgroup.h
===================================================================
--- libvirt-8.0.0.orig/src/util/vircgroup.h
+++ libvirt-8.0.0/src/util/vircgroup.h
@@ -23,6 +23,7 @@
 
 #include "virbitmap.h"
 #include "virenum.h"
+#include "virtypedparam.h"
 
 struct _virCgroup;
 typedef struct _virCgroup virCgroup;
@@ -284,4 +285,7 @@ int virCgroupHasEmptyTasks(virCgroup *cg
 
 bool virCgroupControllerAvailable(int controller);
 
+int virCgroupGetStatsCpu(virCgroup *cgroup,
+                         virTypedParamList *params);
+
 int virCgroupGetInode(virCgroup *cgroup);
