From: tujipei <tujipei(a)huawei.com>
Signed-off-by: tujipei <tujipei(a)huawei.com>
---
docs/schemas/domaincommon.rng | 68 ++++++++------
include/libvirt/libvirt-host.h | 2 +
scripts/apibuild.py | 1 +
scripts/check-aclrules.py | 1 +
src/conf/domain_conf.c | 25 ++++-
src/conf/domain_conf.h | 3 +
src/driver-hypervisor.h | 5 +
src/libvirt-host.c | 34 +++++++
src/libvirt_public.syms | 1 +
src/qemu/qemu_command.c | 3 +
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 +++-
tools/virsh-host.c | 99 ++++++++++++++++++++
15 files changed, 414 insertions(+), 35 deletions(-)
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 764f826df4..a0a6412805 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -460,38 +460,48 @@
<define name="launchSecurity">
<element name="launchSecurity">
- <attribute name="type">
- <value>sev</value>
- </attribute>
- <interleave>
- <element name="cbitpos">
- <data type='unsignedInt'/>
- </element>
- <element name="reducedPhysBits">
- <data type='unsignedInt'/>
- </element>
- <element name="policy">
- <ref name='hexuint'/>
- </element>
- <optional>
- <element name="handle">
- <ref name='unsignedInt'/>
- </element>
- </optional>
- <optional>
- <element name="dhCert">
- <data type="string"/>
- </element>
- </optional>
- <optional>
- <element name="session">
- <data type="string"/>
- </element>
- </optional>
- </interleave>
+ <choice>
+ <group>
+ <attribute name="type">
+ <value>sev</value>
+ </attribute>
+ <interleave>
+ <element name="cbitpos">
+ <data type='unsignedInt'/>
+ </element>
+ <element name="reducedPhysBits">
+ <data type='unsignedInt'/>
+ </element>
+ <element name="policy">
+ <ref name='hexuint'/>
+ </element>
+ <optional>
+ <element name="handle">
+ <ref name='unsignedInt'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="dhCert">
+ <data type="string"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="session">
+ <data type="string"/>
+ </element>
+ </optional>
+ </interleave>
+ </group>
+ <group>
+ <attribute name="type">
+ <value>cvm</value>
+ </attribute>
+ </group>
+ </choice>
</element>
</define>
+
<!--
Enable or disable perf events for the domain. For each
of the events the following rules apply:
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/conf/domain_conf.c b/src/conf/domain_conf.c
index 5a04d1b5d1..45689b209f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1272,6 +1272,7 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity,
VIR_DOMAIN_LAUNCH_SECURITY_LAST,
"",
"sev",
+ "cvm",
);
static virClassPtr virDomainObjClass;
@@ -16821,6 +16822,7 @@ virDomainSEVDefParseXML(xmlNodePtr sevNode,
def->sectype = virDomainLaunchSecurityTypeFromString(type);
switch ((virDomainLaunchSecurity) def->sectype) {
case VIR_DOMAIN_LAUNCH_SECURITY_SEV:
+ case VIR_DOMAIN_LAUNCH_SECURITY_CVM:
break;
case VIR_DOMAIN_LAUNCH_SECURITY_NONE:
case VIR_DOMAIN_LAUNCH_SECURITY_LAST:
@@ -22159,11 +22161,19 @@ virDomainDefParseXML(xmlDocPtr xml,
ctxt->node = node;
VIR_FREE(nodes);
- /* Check for SEV feature */
+ /* Check for CVM/SEV feature */
if ((node = virXPathNode("./launchSecurity", ctxt)) != NULL) {
- def->sev = virDomainSEVDefParseXML(node, ctxt);
- if (!def->sev)
- goto error;
+ tmp = virXMLPropString(node, "type");
+ if((virDomainLaunchSecurity)virDomainLaunchSecurityTypeFromString(tmp) == VIR_DOMAIN_LAUNCH_SECURITY_CVM) {
+ def->cvm = true;
+ } else {
+ def->sev = virDomainSEVDefParseXML(node, ctxt);
+ if(!def->sev) {
+ VIR_FREE(tmp);
+ goto error;
+ }
+ }
+ VIR_FREE(tmp);
}
/* analysis of memory devices */
@@ -29826,7 +29836,12 @@ virDomainDefFormatInternalSetRootName(virDomainDefPtr def,
if (def->keywrap)
virDomainKeyWrapDefFormat(buf, def->keywrap);
- virDomainSEVDefFormat(buf, def->sev);
+ if (def->cvm) {
+ virBufferAddLit(buf, "<launchSecurity type='cvm'>\n");
+ virBufferAddLit(buf, "</launchSecurity>\n");
+ } else {
+ virDomainSEVDefFormat(buf, def->sev);
+ }
virBufferAdjustIndent(buf, -2);
virBufferAsprintf(buf, "</%s>\n", rootname);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6d56ef0282..c7abd61109 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2365,6 +2365,7 @@ struct _virDomainKeyWrapDef {
typedef enum {
VIR_DOMAIN_LAUNCH_SECURITY_NONE,
VIR_DOMAIN_LAUNCH_SECURITY_SEV,
+ VIR_DOMAIN_LAUNCH_SECURITY_CVM,
VIR_DOMAIN_LAUNCH_SECURITY_LAST,
} virDomainLaunchSecurity;
@@ -2578,6 +2579,8 @@ struct _virDomainDef {
/* SEV-specific domain */
virDomainSEVDefPtr sev;
+ // support for cvm
+ bool cvm;
/* Application-specific custom metadata */
xmlNodePtr metadata;
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..35f2afc6dd 100644
--- a/src/libvirt-host.c
+++ b/src/libvirt-host.c
@@ -1754,3 +1754,37 @@ 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;
+ }
+
+ 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_command.c b/src/qemu/qemu_command.c
index d7db30d19b..4d2833195a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -7263,6 +7263,9 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
if (def->sev)
virBufferAddLit(&buf, ",memory-encryption=sev0");
+ //support for cvm
+ if (def->cvm)
+ virBufferAddLit(&buf, ",kvm-type=cvm");
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) {
if (priv->pflash0)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9cb14b01ad..923f056caa 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -23369,6 +23369,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)
+ 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], ':');
+ if (numStart)
+ virSkipToDigit((const char **)(&numStart));
+
+ numListStart = strchr(baseMeminfoSplits[i], '(');
+ if (numListStart)
+ virSkipToDigit((const char **)(&numListStart));
+
+ 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;
+ }
+
+ for (numaIndex = 0; 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_strdup(baseMeminfo);
+ }
+
+end:
+ return meminfo;
+}
+
static virHypervisorDriver qemuHypervisorDriver = {
.name = QEMU_DRIVER_NAME,
@@ -23611,6 +23749,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 d2652e3231..e3359d4b03 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -7203,6 +7203,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
};
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
index 67d5466be2..4f54cafec7 100644
--- a/tools/virsh-host.c
+++ b/tools/virsh-host.c
@@ -1799,6 +1799,99 @@ cmdHypervisorCPUBaseline(vshControl *ctl,
return ret;
}
+/*
+ * "securememinfo" command
+ */
+
+static const vshCmdInfo info_tmm[] = {
+ {.name = "help",
+ .data = N_("Interaction with the tmm")
+ },
+ {.name = "desc",
+ .data = N_("Call the host kernel dev which is provided for virsh to use receiving tmm informations.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_tmm[] = {
+ {.name = "dev",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("Device name of host kernel dev")
+ },
+ {.name = "detail",
+ .type = VSH_OT_BOOL,
+ .help = N_("print detailed info if this option contained in cmd")
+ },
+ {.name = NULL}
+};
+
+static bool
+virshGetTmmMemoryInfo(vshControl *ctl,
+ const vshCmd *cmd)
+{
+ char *tmmMemoryInfo = NULL;
+ bool detail;
+ virshControlPtr priv = ctl->privData;
+
+ detail = vshCommandOptBool(cmd, "detail");
+ if (!(tmmMemoryInfo = virConnectGetTmmMemoryInfo(priv->conn, (unsigned int)detail))) {
+ vshError(ctl, _("Get tmm_memory_info failed"));
+ return false;
+ }
+
+ vshPrintExtra(ctl, _("%s"), tmmMemoryInfo);
+
+ VIR_FREE(tmmMemoryInfo);
+ return true;
+}
+
+typedef bool
+(*virshTmmFunc)(vshControl *ctl,
+ const vshCmd *cmd);
+
+struct _virshTmmFuncInfo {
+ const char *devName;
+ virshTmmFunc funcPtr;
+};
+
+typedef struct _virshTmmFuncInfo virshTmmFuncInfo;
+
+static virshTmmFuncInfo virshTmmFuncMap[] = {
+ {"tmm_memory_info", virshGetTmmMemoryInfo},
+};
+
+static bool
+virshTmmRunFunc(vshControl *ctl,
+ const char *devName,
+ const vshCmd *cmd)
+{
+ int funcIndex;
+
+ for (funcIndex = 0; funcIndex < sizeof(virshTmmFuncMap) / sizeof(virshTmmFuncInfo); funcIndex++) {
+ if (strcmp(devName, virshTmmFuncMap[funcIndex].devName) == 0) {
+ virshTmmFuncMap[funcIndex].funcPtr(ctl, cmd);
+ return true;
+ }
+ }
+
+ vshError(ctl, _("Invalid dev name"));
+ return false;
+}
+
+static bool
+cmdTmm(vshControl *ctl, const vshCmd *cmd)
+{
+ const char *devName = NULL;
+
+ if (vshCommandOptStringReq(ctl, cmd, "dev", &devName) < 0)
+ return false;
+
+ if (!virshTmmRunFunc(ctl, devName, cmd))
+ return false;
+
+ return true;
+}
const vshCmdDef hostAndHypervisorCmds[] = {
{.name = "allocpages",
@@ -1927,5 +2020,11 @@ const vshCmdDef hostAndHypervisorCmds[] = {
.info = info_version,
.flags = 0
},
+ {.name = "tmm",
+ .handler = cmdTmm,
+ .opts = opts_tmm,
+ .info = info_tmm,
+ .flags = 0
+ },
{.name = NULL}
};
--
2.33.0