[libvirt] [PATCH 2/3] tools: virsh: add command for controling/monitoring resctrl

Wang Huaqiang huaqiang.wang at intel.com
Fri Jun 8 09:02:18 UTC 2018


---
 include/libvirt/libvirt-domain.h    |   9 +++
 src/conf/domain_conf.c              |  28 +++++++
 src/conf/domain_conf.h              |   3 +
 src/driver-hypervisor.h             |   8 ++
 src/libvirt-domain.c                |  81 +++++++++++++++++++++
 src/libvirt_public.syms             |   6 ++
 src/qemu/qemu_driver.c              | 141 ++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_process.c             |  65 ++++++++++++++++-
 src/remote/remote_daemon_dispatch.c |  45 ++++++++++++
 src/remote/remote_driver.c          |   2 +
 src/remote/remote_protocol.x        |  28 ++++++-
 src/remote_protocol-structs         |  12 +++
 tools/virsh-domain.c                |  74 +++++++++++++++++++
 13 files changed, 499 insertions(+), 3 deletions(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index da773b7..598db28 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -4767,4 +4767,13 @@ int virDomainSetLifecycleAction(virDomainPtr domain,
                                 unsigned int action,
                                 unsigned int flags);
 
+/*
+ * resctrl API
+ */
+int virDomainSetResctrlMon(virDomainPtr domain,
+        int enable, int disable);
+
+int virDomainGetResctrlMonSts(virDomainPtr domain,
+		char **sts);
+
 #endif /* __VIR_LIBVIRT_DOMAIN_H__ */
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5be773c..0ada3dc 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -18885,6 +18885,7 @@ virDomainCachetuneDefParse(virDomainDefPtr def,
     xmlNodePtr *nodes = NULL;
     virBitmapPtr vcpus = NULL;
     virResctrlAllocPtr alloc = virResctrlAllocNew();
+    virResctrlMonPtr mon= virResctrlMonNew();
     virDomainCachetuneDefPtr tmp_cachetune = NULL;
     char *tmp = NULL;
     char *vcpus_str = NULL;
@@ -18898,6 +18899,9 @@ virDomainCachetuneDefParse(virDomainDefPtr def,
     if (!alloc)
         goto cleanup;
 
+    if (!mon)
+        goto cleanup;
+
     if (VIR_ALLOC(tmp_cachetune) < 0)
         goto cleanup;
 
@@ -18970,8 +18974,12 @@ virDomainCachetuneDefParse(virDomainDefPtr def,
     if (virResctrlAllocSetID(alloc, alloc_id) < 0)
         goto cleanup;
 
+    if (virResctrlMonSetID(mon, alloc_id) < 0)
+        goto cleanup;
+
     VIR_STEAL_PTR(tmp_cachetune->vcpus, vcpus);
     VIR_STEAL_PTR(tmp_cachetune->alloc, alloc);
+    VIR_STEAL_PTR(tmp_cachetune->mon, mon);
 
     if (VIR_APPEND_ELEMENT(def->cachetunes, def->ncachetunes, tmp_cachetune) < 0)
         goto cleanup;
@@ -18990,6 +18998,20 @@ virDomainCachetuneDefParse(virDomainDefPtr def,
 }
 
 
+static int
+virDomainResctrlDefParse(virDomainDefPtr def,
+        xmlXPathContextPtr ctxr ATTRIBUTE_UNUSED)
+{
+    virResctrlMonPtr mon= virResctrlMonNew();
+    if (virResctrlMonSetID(mon, "vcpu-rest") < 0)
+        return -1;
+
+    def->resctrlmon_noalloc = mon;
+
+    return 0;
+}
+
+
 static virDomainDefPtr
 virDomainDefParseXML(xmlDocPtr xml,
                      xmlNodePtr root,
@@ -19585,6 +19607,12 @@ virDomainDefParseXML(xmlDocPtr xml,
     }
     VIR_FREE(nodes);
 
+    if (virDomainResctrlDefParse(def, ctxt) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                _("cannot extract resctrl"));
+        goto error;
+    }
+
     if (virCPUDefParseXML(ctxt, "./cpu[1]", VIR_CPU_TYPE_GUEST, &def->cpu) < 0)
         goto error;
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 8a8121b..2febe62 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2234,6 +2234,7 @@ typedef virDomainCachetuneDef *virDomainCachetuneDefPtr;
 struct _virDomainCachetuneDef {
     virBitmapPtr vcpus;
     virResctrlAllocPtr alloc;
+    virResctrlMonPtr mon;
 };
 
 
@@ -2389,6 +2390,8 @@ struct _virDomainDef {
 
     virDomainCputune cputune;
 
+    virResctrlMonPtr resctrlmon_noalloc;
+
     virDomainCachetuneDefPtr *cachetunes;
     size_t ncachetunes;
 
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index aa99cbb..c2e5d2a 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1309,6 +1309,12 @@ typedef int
                                   unsigned int action,
                                   unsigned int flags);
 
+typedef int
+(*virDrvDomainSetResctrlMon)(virDomainPtr domain,
+                             int enable, int disable);
+
+typedef char *
+(*virDrvDomainGetResctrlMonSts)(virDomainPtr domain);
 
 typedef struct _virHypervisorDriver virHypervisorDriver;
 typedef virHypervisorDriver *virHypervisorDriverPtr;
@@ -1558,6 +1564,8 @@ struct _virHypervisorDriver {
     virDrvDomainSetLifecycleAction domainSetLifecycleAction;
     virDrvConnectCompareHypervisorCPU connectCompareHypervisorCPU;
     virDrvConnectBaselineHypervisorCPU connectBaselineHypervisorCPU;
+    virDrvDomainSetResctrlMon  domainSetResctrlMon;
+    virDrvDomainGetResctrlMonSts  domainGetResctrlMonSts;
 };
 
 
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index d44b553..07a19a6 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -12154,3 +12154,84 @@ int virDomainSetLifecycleAction(virDomainPtr domain,
     virDispatchError(domain->conn);
     return -1;
 }
+
+
+/**
+ * virDomainSetResctrlMon:
+ * @domain: a domain object
+ * @enable: true(non-zero) for enbling resctrl mon group.
+ * @disable: true(non-zero) for disbling resctrl mon group.
+ * valid if @enable is false
+ *
+ * Enable or disable resctrl monitoring.
+ *
+ * Returns -1 in case of failure, 0 in case of success.
+ */
+int
+virDomainSetResctrlMon(virDomainPtr domain,
+        int enable, int disable)
+{
+    int ret;
+    virConnectPtr conn;
+
+    virResetLastError();
+
+    if(!disable && !enable)
+        return 0;
+
+    virCheckDomainReturn(domain, -1);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainSetResctrlMon) {
+        ret = conn->driver->domainSetResctrlMon(domain,
+                enable, disable);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetResctrlMonSts:
+ * @domain: a domain object
+ * @status: pointer of a string buffer for holding resctrl mon
+ * group status string, caller is responsible for free it.
+ *
+ * Get domain resctrl status.
+ *
+ * Returns -1 in case of failure, 0 in case of success.
+ */
+int
+virDomainGetResctrlMonSts(virDomainPtr domain,
+        char **status)
+{
+	int ret = -1;
+    virConnectPtr conn;
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+
+    conn = domain->conn;
+
+	if (conn->driver->domainGetResctrlMonSts) {
+		*status = conn->driver->domainGetResctrlMonSts(domain);
+		if (*status)
+			ret = 0;
+
+		goto done;
+	}
+
+    virReportUnsupportedError();
+ done:
+    virDispatchError(domain->conn);
+	return ret;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 4f54b84..fb3eef5 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -798,4 +798,10 @@ LIBVIRT_4.5.0 {
         virGetLastErrorDomain;
 } LIBVIRT_4.4.0;
 
+LIBVIRT_4.6.0 {
+    global:
+        virDomainSetResctrlMon;
+        virDomainGetResctrlMonSts;
+} LIBVIRT_4.5.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 38ea865..4075daa 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -108,6 +108,7 @@
 #include "virnuma.h"
 #include "dirname.h"
 #include "netdev_bandwidth_conf.h"
+#include "virresctrl.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -21437,6 +21438,144 @@ qemuDomainSetLifecycleAction(virDomainPtr dom,
 }
 
 
+static int
+qemuDomainSetResctrlMon(virDomainPtr dom,
+        int enable ,int disable)
+{
+    int ret = -1;
+    virDomainObjPtr vm;
+    virResctrlMonAct act = VIR_RESCTRL_MONACT_NONE;;
+    int i = 0;
+    unsigned int maxvcpus = 0;
+
+    /* The 'enable' action will override the 'disable' one */
+    if(disable)
+        act = VIR_RESCTRL_MONACT_DISABLE;
+    if(enable)
+        act = VIR_RESCTRL_MONACT_ENABLE;
+
+    if (act == VIR_RESCTRL_MONACT_NONE)
+        return 0;
+
+    if (!(vm = qemuDomObjFromDomain(dom)))
+        return ret;
+
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("domain is not running"));
+        goto cleanup;
+    }
+
+    /* If 'resctrl' is enabled in xml configuation file through 'cachetune'
+     * section, this interface doesn't work. return 1 for this case */
+    if (vm->def->ncachetunes != 0){
+        VIR_DEBUG("resctrl monitoring interface is governed by domain "
+               "configration 'cachetune' sections. Interface disabled.\n");
+        ret = 1;
+        goto cleanup;
+    }
+
+    if (act == VIR_RESCTRL_MONACT_ENABLE) {
+
+        if (!vm->def->resctrlmon_noalloc){
+            virReportError(VIR_ERR_NO_DOMAIN,
+                    _("resctrlmon_noalloc should be allocated."));
+            goto cleanup;
+        }
+
+        if(!virResctrlMonIsRunning(vm->def->resctrlmon_noalloc)) {
+
+            if (virResctrlMonCreate(NULL,
+                        vm->def->resctrlmon_noalloc, priv->machineName) < 0)
+                goto cleanup;
+
+            /* Set vcpus */
+            maxvcpus = virDomainDefGetVcpusMax(vm->def);
+            for (i = 0; i < maxvcpus; i++) {
+                virDomainVcpuDefPtr vcpu
+                    = virDomainDefGetVcpu(vm->def, i);
+
+                if (!vcpu->online)
+                    continue;
+
+                pid_t vcpupid = qemuDomainGetVcpuPid(vm, i);
+                if (virResctrlMonAddPID(vm->def->resctrlmon_noalloc,
+                            vcpupid) < 0)
+                    goto cleanup;
+            }
+        }
+
+        VIR_DEBUG("resctrl monitoring is enabled");
+    } else if (act == VIR_RESCTRL_MONACT_DISABLE){
+        if (!vm->def->resctrlmon_noalloc){
+            virReportError(VIR_ERR_NO_DOMAIN,
+                    _("resctrlmon_noalloc should be allocated."));
+            goto cleanup;
+        }
+
+        if(virResctrlMonIsRunning(vm->def->resctrlmon_noalloc)) {
+            if (virResctrlMonRemove(vm->def->resctrlmon_noalloc) < 0){
+                virReportError(VIR_ERR_NO_DOMAIN,
+                        _("Error in remove resctrl mon group."));
+                goto cleanup;
+            }
+        }
+
+        VIR_DEBUG("resctrl monitoring is disabled\n");
+    }
+
+    ret = 0;
+cleanup:
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
+
+
+static char *
+qemuDomainGetResctrlMonSts(virDomainPtr dom)
+{
+    virDomainObjPtr vm;
+	char *sts = NULL;
+
+    if (!(vm = qemuDomObjFromDomain(dom)))
+        return sts;
+
+    if (vm->def->ncachetunes != 0){
+	    VIR_DEBUG("resctrl monitoring interface is governed by domain "
+			    "'cachetune' sections. resctrl monitoring is compulsively enabled.\n");
+
+        /* only check cachetune[0] for domain resctrl mon group status */
+        if (!virResctrlMonIsRunning(vm->def->cachetunes[0]->mon)) {
+            if (virAsprintf(&sts, "Disabled") < 0)
+                goto cleanup;
+        } else {
+            if (virAsprintf(&sts, "Enabled (forced by cachetune)") < 0)
+                goto cleanup;
+        }
+
+    } else {
+
+        if (vm->def->resctrlmon_noalloc &&
+                virResctrlMonIsRunning(vm->def->resctrlmon_noalloc)){
+            if (virAsprintf(&sts, "Enabled") < 0)
+                goto cleanup;
+
+        } else {
+            if (virAsprintf(&sts, "Disabled") < 0)
+                goto cleanup;
+        }
+    }
+
+    VIR_DEBUG("resctrl monitoring status: %s\n", sts);
+
+cleanup:
+    virDomainObjEndAPI(&vm);
+    return sts;
+}
+
+
 static virHypervisorDriver qemuHypervisorDriver = {
     .name = QEMU_DRIVER_NAME,
     .connectURIProbe = qemuConnectURIProbe,
@@ -21660,6 +21799,8 @@ static virHypervisorDriver qemuHypervisorDriver = {
     .domainSetLifecycleAction = qemuDomainSetLifecycleAction, /* 3.9.0 */
     .connectCompareHypervisorCPU = qemuConnectCompareHypervisorCPU, /* 4.4.0 */
     .connectBaselineHypervisorCPU = qemuConnectBaselineHypervisorCPU, /* 4.4.0 */
+    .domainSetResctrlMon = qemuDomainSetResctrlMon, /*FIXME: assign proper ver string */
+    .domainGetResctrlMonSts = qemuDomainGetResctrlMonSts, /*FIXME: assign proper ver string */
 };
 
 
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 1606f4c..4fab0e1 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -2461,6 +2461,11 @@ qemuProcessResctrlCreate(virQEMUDriverPtr driver,
                                   vm->def->cachetunes[i]->alloc,
                                   priv->machineName) < 0)
             goto cleanup;
+
+        if (virResctrlMonCreate(vm->def->cachetunes[i]->alloc,
+                    vm->def->cachetunes[i]->mon,
+                    priv->machineName) < 0)
+            goto cleanup;
     }
 
     ret = 0;
@@ -5259,6 +5264,7 @@ qemuProcessSetupVcpu(virDomainObjPtr vm,
                             &vcpu->sched) < 0)
         return -1;
 
+    
     for (i = 0; i < vm->def->ncachetunes; i++) {
         virDomainCachetuneDefPtr ct = vm->def->cachetunes[i];
 
@@ -5279,6 +5285,10 @@ qemuProcessSetupVcpus(virDomainObjPtr vm)
     virDomainVcpuDefPtr vcpu;
     unsigned int maxvcpus = virDomainDefGetVcpusMax(vm->def);
     size_t i;
+    virBitmapPtr vcpuleft = NULL;
+    int ret = -1;
+
+    qemuDomainObjPrivatePtr priv = vm->privateData;
 
     if ((vm->def->cputune.period || vm->def->cputune.quota) &&
         !virCgroupHasController(((qemuDomainObjPrivatePtr) vm->privateData)->cgroup,
@@ -5308,17 +5318,52 @@ qemuProcessSetupVcpus(virDomainObjPtr vm)
         return 0;
     }
 
+    /* To monitor whole domain's cache occupancy information
+     * create mon group for un-covered VCPUs */
+    if (!(vcpuleft = virBitmapNew(maxvcpus + 1)))
+        goto cleanup;
+
+    virBitmapClearAll(vcpuleft);
+
     for (i = 0; i < maxvcpus; i++) {
         vcpu = virDomainDefGetVcpu(vm->def, i);
 
         if (!vcpu->online)
             continue;
 
+	if ( virBitmapSetBit(vcpuleft, i) < 0)
+		goto cleanup;
+
         if (qemuProcessSetupVcpu(vm, i) < 0)
             return -1;
     }
 
-    return 0;
+    for (i = 0; i < vm->def->ncachetunes; i++) {
+        virDomainCachetuneDefPtr ct = vm->def->cachetunes[i];
+        virBitmapSubtract(vcpuleft, ct->vcpus);
+    }
+
+
+    if (vm->def->ncachetunes &&
+		    !virBitmapIsAllClear(vcpuleft)){
+
+	    if (virResctrlMonCreate(NULL, vm->def->resctrlmon_noalloc, priv->machineName) < 0)
+		    goto cleanup;
+
+	    for (i = 0; i < maxvcpus; i++) {
+		    if (virBitmapIsBitSet(vcpuleft, i)){
+			    pid_t vcpupid = qemuDomainGetVcpuPid(vm, i);
+
+			    if (virResctrlMonAddPID(vm->def->resctrlmon_noalloc, vcpupid) < 0)
+				    goto cleanup;
+		    }
+	    }
+    }
+
+    ret = 0;
+cleanup:
+    virBitmapFree(vcpuleft);
+    return ret;
 }
 
 
@@ -6895,8 +6940,14 @@ void qemuProcessStop(virQEMUDriverPtr driver,
     /* Remove resctrl allocation after cgroups are cleaned up which makes it
      * kind of safer (although removing the allocation should work even with
      * pids in tasks file */
-    for (i = 0; i < vm->def->ncachetunes; i++)
+    for (i = 0; i < vm->def->ncachetunes; i++){
         virResctrlAllocRemove(vm->def->cachetunes[i]->alloc);
+        virResctrlMonRemove(vm->def->cachetunes[i]->mon);
+    }
+
+    if(vm->def->resctrlmon_noalloc)
+        virResctrlMonRemove(vm->def->resctrlmon_noalloc);
+
 
     qemuProcessRemoveDomainStatus(driver, vm);
 
@@ -7620,8 +7671,18 @@ qemuProcessReconnect(void *opaque)
         if (virResctrlAllocDeterminePath(obj->def->cachetunes[i]->alloc,
                                          priv->machineName) < 0)
             goto error;
+
+        if (virResctrlMonDeterminePath(obj->def->cachetunes[i]->mon,
+                    priv->machineName) < 0)
+            goto error;
+
     }
 
+    if(obj->def->resctrlmon_noalloc &&
+            virResctrlMonDeterminePath(obj->def->resctrlmon_noalloc,
+                priv->machineName) < 0)
+        goto error;
+
     /* update domain state XML with possibly updated state in virDomainObj */
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj, driver->caps) < 0)
         goto error;
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index 81d0445..2ef0e5e 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -7107,3 +7107,48 @@ remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
     }
     return -1;
 }
+
+static int remoteDispatchDomainGetResctrlMonSts(
+    virNetServerPtr server ATTRIBUTE_UNUSED,
+    virNetServerClientPtr client,
+    virNetMessagePtr msg ATTRIBUTE_UNUSED,
+    virNetMessageErrorPtr rerr,
+    remote_domain_get_resctrl_mon_sts_args *args,
+    remote_domain_get_resctrl_mon_sts_ret *ret)
+{
+    int rv = -1;
+    virDomainPtr dom = NULL;
+    char *sts = NULL;
+    char **sts_p = NULL;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+
+    if (!priv->conn) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+        goto cleanup;
+    }
+
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+        goto cleanup;
+
+    if ((rv = virDomainGetResctrlMonSts(dom, &sts)) < 0)
+        goto cleanup;
+
+    if (VIR_ALLOC(sts_p) < 0)
+        goto cleanup;
+
+    if (VIR_STRDUP(*sts_p, sts) < 0)
+        goto cleanup;
+
+    ret->sts = sts_p;
+    rv = 0;
+
+cleanup:
+    if (rv < 0) {
+        virNetMessageSaveError(rerr);
+        VIR_FREE(sts_p);
+    }
+    virObjectUnref(dom);
+    VIR_FREE(sts);
+    return rv;
+}
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index c22993c..4a6b101 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -8451,6 +8451,8 @@ static virHypervisorDriver hypervisor_driver = {
     .domainSetLifecycleAction = remoteDomainSetLifecycleAction, /* 3.9.0 */
     .connectCompareHypervisorCPU = remoteConnectCompareHypervisorCPU, /* 4.4.0 */
     .connectBaselineHypervisorCPU = remoteConnectBaselineHypervisorCPU, /* 4.4.0 */
+    .domainSetResctrlMon = remoteDomainSetResctrlMon, /*FIXME: assign proper ver string */
+    .domainGetResctrlMonSts = remoteDomainGetResctrlMonSts, /*FIXME: assign proper ver string */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index a0ab7e9..9242a61 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3480,6 +3480,20 @@ struct remote_connect_baseline_hypervisor_cpu_ret {
     remote_nonnull_string cpu;
 };
 
+struct remote_domain_set_resctrl_mon_args {
+    remote_nonnull_domain dom;
+    int enable;
+    int disable;
+};
+
+struct remote_domain_get_resctrl_mon_sts_args {
+    remote_nonnull_domain dom;
+};
+
+struct remote_domain_get_resctrl_mon_sts_ret { /* insert at 1 */
+	remote_string sts;
+};
+
 /*----- Protocol. -----*/
 
 /* Define the program number, protocol version and procedure numbers here. */
@@ -6187,5 +6201,17 @@ enum remote_procedure {
      * @generate: both
      * @acl: connect:write
      */
-    REMOTE_PROC_CONNECT_BASELINE_HYPERVISOR_CPU = 394
+    REMOTE_PROC_CONNECT_BASELINE_HYPERVISOR_CPU = 394,
+
+    /**
+     * @generate: both
+     * @acl: domain:write
+     */
+    REMOTE_PROC_DOMAIN_SET_RESCTRL_MON = 395,
+
+    /**
+     * @generate: client
+     * @acl: domain:read
+     */
+    REMOTE_PROC_DOMAIN_GET_RESCTRL_MON_STS = 396
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 0c4cfc6..ed6a782 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2907,6 +2907,16 @@ struct remote_connect_baseline_hypervisor_cpu_args {
 struct remote_connect_baseline_hypervisor_cpu_ret {
         remote_nonnull_string      cpu;
 };
+struct remote_domain_set_resctrl_mon_args {
+        remote_nonnull_domain dom;
+        int enable;
+        int disable;
+}
+struct remote_domain_get_resctrl_mon_sts_args {
+        remote_nonnull_domain dom;
+};
+struct remote_domain_get_resctrl_mon_sts_ret {
+        remote_string sts;
 enum remote_procedure {
         REMOTE_PROC_CONNECT_OPEN = 1,
         REMOTE_PROC_CONNECT_CLOSE = 2,
@@ -3302,4 +3312,6 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_DETACH_DEVICE_ALIAS = 392,
         REMOTE_PROC_CONNECT_COMPARE_HYPERVISOR_CPU = 393,
         REMOTE_PROC_CONNECT_BASELINE_HYPERVISOR_CPU = 394,
+		REMOTE_PROC_DOMAIN_SET_RESCTRL_MON = 395,
+		REMOTE_PROC_DOMAIN_GET_RESCTRL_MON_STS = 396,
 };
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 6aa79f1..4ae8ed2 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -7677,6 +7677,74 @@ cmdIOThreadDel(vshControl *ctl, const vshCmd *cmd)
     return ret;
 }
 
+static const vshCmdInfo info_resctrl[] = {
+    {.name = "help",
+     .data = N_("get or set hardware CPU resource monitoring functions")
+    },
+    {.name = "desc",
+     .data = N_("Enable or disable resctrl monitoring for a guest domain.\n"
+                "    To get resctrl status use following"
+                "    command: \n\n"
+                "    virsh # resctrl <domain>")
+    },
+    {.name = NULL}
+};
+
+static const vshCmdOptDef opts_resctrl[] = {
+    VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
+    {.name = "enable",
+     .type = VSH_OT_BOOL,
+     .help = N_("Enable resctrl function such as monitoring cache occupancy "
+             "or memory bandwidth.")
+    },
+    {.name = "disable",
+     .type = VSH_OT_BOOL,
+     .help = N_("Disable hardware function such as monitoring cache occupancy "
+             "or memory bandwidth.")
+    },
+    {.name = NULL}
+};
+
+
+static bool
+cmdResctrl(vshControl *ctl, const vshCmd *cmd)
+{
+    virDomainPtr dom;
+    bool ret = false;
+    char *ressts = NULL;
+
+    bool enable = vshCommandOptBool(cmd, "enable");
+    bool disable= vshCommandOptBool(cmd, "disable");
+
+    if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+        return false;
+
+    if(!enable && !disable){
+        if (virDomainGetResctrlMonSts(dom, &ressts) < 0)
+            goto cleanup;
+
+        if (!ressts)
+            goto cleanup;
+
+    } else {
+        if (virDomainSetResctrlMon(dom, enable, disable) < 0)
+            goto cleanup;
+
+        if (virDomainGetResctrlMonSts(dom, &ressts) < 0)
+            goto cleanup;
+
+        if (!ressts)
+            goto cleanup;
+    }
+
+    vshPrint(ctl,"RDT Monitoring Status: %s\n", ressts);
+    ret = true;
+cleanup:
+    VIR_FREE(ressts);
+    virshDomainFree(dom);
+    return ret;
+}
+
 /*
  * "cpu-stats" command
  */
@@ -13799,6 +13867,12 @@ const vshCmdDef domManagementCmds[] = {
      .flags = 0
     },
 #endif
+    {.name = "resctrl",
+     .handler = cmdResctrl,
+     .opts = opts_resctrl,
+     .info = info_resctrl,
+     .flags = 0
+    },
     {.name = "cpu-stats",
      .handler = cmdCPUStats,
      .opts = opts_cpu_stats,
-- 
2.7.4




More information about the libvir-list mailing list