---
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@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