From: Chun Feng Wu <danielw...@163.com>

Implement new throttle cmds

* Add new virsh cmds: domthrottlegroupset, domthrottlegrouplist,
  domthrottlegroupinfo, domthrottlegroupdel
* Add doc for new cmds at docs/manpages/virsh.rst
* Add cmd helper "virshDomainThrottleGroupCompleter", which is used by
  domthrottlegroupset, domthrottlegroupinfo, domthrottlegroupdel

Signed-off-by: Chun Feng Wu <danielw...@163.com>

* Update of code documentation comments.
* Reimplement Get throttle group from XML.

Signed-off-by: Harikumar Rajkumar <harirajkumar...@gmail.com>a

* Fixed memleaks
* Rewrote getter to avoid extra copies
* Simplified name extractor

Reviewed-by: Peter Krempa <pkre...@redhat.com>
Signed-off-by: Peter Krempa <pkre...@redhat.com>
---
 docs/manpages/virsh.rst        | 134 ++++++++++++
 tools/virsh-completer-domain.c |  45 ++++
 tools/virsh-completer-domain.h |   9 +
 tools/virsh-domain.c           | 368 ++++++++++++++++++++++++++++++++-
 4 files changed, 555 insertions(+), 1 deletion(-)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index baced15dec..621c02fdbd 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -1139,6 +1139,140 @@ given, but *--current* is exclusive. For querying only 
one of *--live*,
 is different depending on hypervisor.


+domthrottlegroupset
+-------------------
+
+**Syntax:**
+
+::
+
+   domthrottlegroupset domain group-name [[--config] [--live] | [--current]]
+      [[total-bytes-sec] | [read-bytes-sec] [write-bytes-sec]]
+      [[total-iops-sec] | [read-iops-sec] [write-iops-sec]]
+      [[total-bytes-sec-max] | [read-bytes-sec-max] [write-bytes-sec-max]]
+      [[total-iops-sec-max] | [read-iops-sec-max] [write-iops-sec-max]]
+      [[total-bytes-sec-max-length] |
+       [read-bytes-sec-max-length] [write-bytes-sec-max-length]]
+      [[total-iops-sec-max-length] |
+       [read-iops-sec-max-length] [write-iops-sec-max-length]]
+      [size-iops-sec]
+
+Add or update a throttle group against specific *domain*.
+*group-name* specifies a unique throttle group name, which defines limit, and
+will be referenced by drives.
+
+If no limit is specified, default them as all zeros, which will fail,
+Otherwise, set limits with these flags:
+*--total-bytes-sec* specifies total throughput limit as a scaled integer, the
+default being bytes per second if no suffix is specified.
+*--read-bytes-sec* specifies read throughput limit as a scaled integer, the
+default being bytes per second if no suffix is specified.
+*--write-bytes-sec* specifies write throughput limit as a scaled integer, the
+default being bytes per second if no suffix is specified.
+*--total-iops-sec* specifies total I/O operations limit per second.
+*--read-iops-sec* specifies read I/O operations limit per second.
+*--write-iops-sec* specifies write I/O operations limit per second.
+*--total-bytes-sec-max* specifies maximum total throughput limit as a scaled
+integer, the default being bytes per second if no suffix is specified
+*--read-bytes-sec-max* specifies maximum read throughput limit as a scaled
+integer, the default being bytes per second if no suffix is specified.
+*--write-bytes-sec-max* specifies maximum write throughput limit as a scaled
+integer, the default being bytes per second if no suffix is specified.
+*--total-iops-sec-max* specifies maximum total I/O operations limit per second.
+*--read-iops-sec-max* specifies maximum read I/O operations limit per second.
+*--write-iops-sec-max* specifies maximum write I/O operations limit per second.
+*--total-bytes-sec-max-length* specifies duration in seconds to allow maximum
+total throughput limit.
+*--read-bytes-sec-max-length* specifies duration in seconds to allow maximum
+read throughput limit.
+*--write-bytes-sec-max-length* specifies duration in seconds to allow maximum
+write throughput limit.
+*--total-iops-sec-max-length* specifies duration in seconds to allow maximum
+total I/O operations limit.
+*--read-iops-sec-max-length* specifies duration in seconds to allow maximum
+read I/O operations limit.
+*--write-iops-sec-max-length* specifies duration in seconds to allow maximum
+write I/O operations limit.
+*--size-iops-sec* specifies size I/O operations limit per second.
+
+Bytes and iops values are independent, but setting only one value (such
+as --read-bytes-sec) resets the other two in that category to unlimited.
+An explicit 0 also clears any limit.  A non-zero value for a given total
+cannot be mixed with non-zero values for read or write.
+
+It is up to the hypervisor to determine how to handle the length values.
+For the QEMU hypervisor, if an I/O limit value or maximum value is set,
+then the default value of 1 second will be displayed. Supplying a 0 will
+reset the value back to the default.
+
+If *--live* is specified, affect a running guest.
+If *--config* is specified, affect the next start of a persistent guest.
+If *--current* is specified, it is equivalent to either *--live* or
+*--config*, depending on the current state of the guest.
+When setting the disk io parameters both *--live* and *--config*
+are specified, both live configuration and config are updated while setting
+the description, but *--current* is exclusive. If no flag is specified, 
behavior
+is different depending on hypervisor.
+
+
+domthrottlegroupdel
+-------------------
+
+**Syntax:**
+
+::
+
+   domthrottlegroupdel domain group-name [[--config] [--live] | [--current]]
+
+Delete a Throttlegroup from the domain using the specified *group-name*.
+If an Throttlegroup is currently referenced by a disk resource, then the 
attempt
+to remove the Throttlegroup will fail.
+If the *group-name* does not exist an error will occur.
+
+If *--live* is specified, affect a running guest. If the guest is not
+running an error is returned.
+If *--config* is specified, affect the next start of a persistent guest.
+If *--current* is specified, it is equivalent to either *--live* or
+*--config*, depending on the current state of the guest.
+
+
+domthrottlegroupinfo
+--------------------
+
+**Syntax:**
+
+::
+
+   domthrottlegroupinfo domain group-name [[--config] [--live] | [--current]]
+
+Display domain Throttlegroup information including I/O limits setting.
+
+If *--live* is specified, get the Throttlegroup data from the running guest. If
+the guest is not running, an error is returned.
+If *--config* is specified, get the Throttlegroup data from the next start of
+a persistent guest.
+If *--current* is specified or *--live* and *--config* are not specified,
+then get the Throttlegroup data based on the current guest state, which can
+either be live or offline.
+If both *--live* and *--config* are specified, the *--config* option takes
+precedence on getting the current description.
+
+
+domthrottlegrouplist
+--------------------
+
+**Syntax:**
+
+::
+
+   domthrottlegrouplist domain [--inactive]
+
+Print a table showing names of all throttle groups
+associated with *domain*. If *--inactive* is specified, query the
+Throttlegroup data that will be used on the next boot, rather than those
+currently in use by a running domain.
+
+
 blkiotune
 ---------

diff --git a/tools/virsh-completer-domain.c b/tools/virsh-completer-domain.c
index 61362224a3..8c5fbb1e1b 100644
--- a/tools/virsh-completer-domain.c
+++ b/tools/virsh-completer-domain.c
@@ -248,6 +248,51 @@ virshDomainMigrateDisksCompleter(vshControl *ctl,
 }


+char **
+virshGetThrottleGroupNames(xmlXPathContext *ctxt)
+{
+    g_auto(GStrv) groupNames = NULL;
+    g_autofree xmlNodePtr *groups = NULL;
+    int ngroups;
+    size_t i;
+
+    if ((ngroups = virXPathNodeSet("./throttlegroups/throttlegroup", ctxt, 
&groups)) < 0)
+        return NULL;
+
+    groupNames = g_new0(char *, ngroups + 1);
+
+    for (i = 0; i < ngroups; i++) {
+        ctxt->node = groups[i];
+
+        if (!(groupNames[i] = virXPathString("string(./group_name)", ctxt)))
+            return NULL;
+    }
+
+    return g_steal_pointer(&groupNames);
+}
+
+
+char **
+virshDomainThrottleGroupCompleter(vshControl *ctl,
+                                  const vshCmd *cmd,
+                                  unsigned int flags)
+{
+    virshControl *priv = ctl->privData;
+    g_autoptr(xmlDoc) xmldoc = NULL;
+    g_autoptr(xmlXPathContext) ctxt = NULL;
+
+    virCheckFlags(0, NULL);
+
+    if (!priv->conn || virConnectIsAlive(priv->conn) <= 0)
+        return NULL;
+
+    if (virshDomainGetXML(ctl, cmd, 0, &xmldoc, &ctxt) < 0)
+        return NULL;
+
+    return virshGetThrottleGroupNames(ctxt);
+}
+
+
 char **
 virshDomainUndefineStorageDisksCompleter(vshControl *ctl,
                                  const vshCmd *cmd,
diff --git a/tools/virsh-completer-domain.h b/tools/virsh-completer-domain.h
index 27cf963912..82c907e4fe 100644
--- a/tools/virsh-completer-domain.h
+++ b/tools/virsh-completer-domain.h
@@ -21,6 +21,7 @@
 #pragma once

 #include "vsh.h"
+#include <libxml/xpath.h>

 char **
 virshDomainNameCompleter(vshControl *ctl,
@@ -41,6 +42,14 @@ virshDomainDiskTargetCompleter(vshControl *ctl,
                                const vshCmd *cmd,
                                unsigned int flags);

+char **
+virshGetThrottleGroupNames(xmlXPathContext *ctxt);
+
+char **
+virshDomainThrottleGroupCompleter(vshControl *ctl,
+                                  const vshCmd *cmd,
+                                  unsigned int flags);
+
 char **
 virshDomainInterfaceStateCompleter(vshControl *ctl,
                                    const vshCmd *cmd,
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 755a9b63e4..e5f9cc0ea9 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -1374,7 +1374,7 @@ static const vshCmdOptDef opts_blkdeviotune[] = {
     VIRSH_COMMON_OPT_DOMAIN_CURRENT,
     {.name = NULL}
 };
-#undef VSH_OPTS_IOTUNE
+

 static bool
 cmdBlkdeviotune(vshControl *ctl, const vshCmd *cmd)
@@ -1512,6 +1512,348 @@ cmdBlkdeviotune(vshControl *ctl, const vshCmd *cmd)
     goto cleanup;
 }

+
+/*
+ * "domthrottlegrouplist" command
+ */
+static const vshCmdInfo info_domthrottlegrouplist = {
+    .help = N_("list all domain throttlegroups."),
+    .desc = N_("Get the summary of throttle groups for a domain."),
+};
+
+
+static const vshCmdOptDef opts_domthrottlegrouplist[] = {
+    VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+    {.name = "inactive",
+     .type = VSH_OT_BOOL,
+     .help = N_("get inactive rather than running configuration")
+    },
+    {.name = NULL}
+};
+
+
+static bool
+cmdThrottleGroupList(vshControl *ctl,
+                     const vshCmd *cmd)
+{
+    unsigned int flags = 0;
+    g_autoptr(xmlDoc) xml = NULL;
+    g_autoptr(xmlXPathContext) ctxt = NULL;
+    g_auto(GStrv) groupNames = NULL;
+    char **n;
+    g_autoptr(vshTable) table = NULL;
+
+    if (vshCommandOptBool(cmd, "inactive"))
+        flags |= VIR_DOMAIN_XML_INACTIVE;
+
+    if (virshDomainGetXML(ctl, cmd, flags, &xml, &ctxt) < 0)
+        return false;
+
+    if (!(table = vshTableNew(_("Name"), NULL)))
+        return false;
+
+    if (!(groupNames = virshGetThrottleGroupNames(ctxt)))
+        return false;
+
+    for (n = groupNames; *n; n++) {
+        if (vshTableRowAppend(table, *n, NULL) < 0)
+            return false;
+    }
+
+    vshTablePrintToStdout(table, ctl);
+
+    return true;
+}
+
+
+/*
+ * "domthrottlegroupset" command
+ */
+static const vshCmdInfo info_domthrottlegroupset = {
+    .help = N_("Add or update a throttling group."),
+    .desc = N_("Add or updte a throttling group."),
+};
+
+
+static const vshCmdOptDef opts_domthrottlegroupset[] = {
+    VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+    {.name = "group-name",
+     .type = VSH_OT_STRING,
+     .positional = true,
+     .required = true,
+     .completer = virshDomainThrottleGroupCompleter,
+     .help = N_("throttle group name")
+    },
+    VSH_OPTS_IOTUNE,
+    VIRSH_COMMON_OPT_DOMAIN_CONFIG,
+    VIRSH_COMMON_OPT_DOMAIN_LIVE,
+    VIRSH_COMMON_OPT_DOMAIN_CURRENT,
+    {.name = NULL}
+};
+#undef VSH_OPTS_IOTUNE
+
+
+static bool
+cmdThrottleGroupSet(vshControl *ctl,
+                    const vshCmd *cmd)
+{
+    g_autoptr(virshDomain) dom = NULL;
+    const char *group_name = NULL;
+    unsigned long long value;
+    int nparams = 0;
+    int maxparams = 0;
+    virTypedParameterPtr params = NULL;
+    unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
+    int rv = 0;
+    bool current = vshCommandOptBool(cmd, "current");
+    bool config = vshCommandOptBool(cmd, "config");
+    bool live = vshCommandOptBool(cmd, "live");
+    bool ret = false;
+
+    VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
+    VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
+
+    if (config)
+        flags |= VIR_DOMAIN_AFFECT_CONFIG;
+    if (live)
+        flags |= VIR_DOMAIN_AFFECT_LIVE;
+
+    if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+        goto cleanup;
+
+
+#define VSH_SET_THROTTLE_GROUP_SCALED(PARAM, CONST) \
+    if ((rv = vshCommandOptScaledInt(ctl, cmd, #PARAM, &value, \
+                                     1, ULLONG_MAX)) < 0) { \
+        goto interror; \
+    } else if (rv > 0) { \
+        if (virTypedParamsAddULLong(&params, &nparams, &maxparams, \
+                                    VIR_DOMAIN_BLOCK_IOTUNE_##CONST, \
+                                    value) < 0) \
+            goto save_error; \
+    }
+
+    VSH_SET_THROTTLE_GROUP_SCALED(total-bytes-sec, TOTAL_BYTES_SEC);
+    VSH_SET_THROTTLE_GROUP_SCALED(read-bytes-sec, READ_BYTES_SEC);
+    VSH_SET_THROTTLE_GROUP_SCALED(write-bytes-sec, WRITE_BYTES_SEC);
+    VSH_SET_THROTTLE_GROUP_SCALED(total-bytes-sec-max, TOTAL_BYTES_SEC_MAX);
+    VSH_SET_THROTTLE_GROUP_SCALED(read-bytes-sec-max, READ_BYTES_SEC_MAX);
+    VSH_SET_THROTTLE_GROUP_SCALED(write-bytes-sec-max, WRITE_BYTES_SEC_MAX);
+#undef VSH_SET_THROTTLE_GROUP_SCALED
+
+#define VSH_SET_THROTTLE_GROUP(PARAM, CONST) \
+    if ((rv = vshCommandOptULongLong(ctl, cmd, #PARAM, &value)) < 0) { \
+        goto interror; \
+    } else if (rv > 0) { \
+        if (virTypedParamsAddULLong(&params, &nparams, &maxparams, \
+                                    VIR_DOMAIN_BLOCK_IOTUNE_##CONST, \
+                                    value) < 0) \
+            goto save_error; \
+    }
+
+    VSH_SET_THROTTLE_GROUP(total-iops-sec, TOTAL_IOPS_SEC);
+    VSH_SET_THROTTLE_GROUP(read-iops-sec, READ_IOPS_SEC);
+    VSH_SET_THROTTLE_GROUP(write-iops-sec, WRITE_IOPS_SEC);
+    VSH_SET_THROTTLE_GROUP(total-iops-sec-max, TOTAL_IOPS_SEC_MAX);
+    VSH_SET_THROTTLE_GROUP(read-iops-sec-max, READ_IOPS_SEC_MAX);
+    VSH_SET_THROTTLE_GROUP(write-iops-sec-max, WRITE_IOPS_SEC_MAX);
+    VSH_SET_THROTTLE_GROUP(size-iops-sec, SIZE_IOPS_SEC);
+
+    VSH_SET_THROTTLE_GROUP(total-bytes-sec-max-length, 
TOTAL_BYTES_SEC_MAX_LENGTH);
+    VSH_SET_THROTTLE_GROUP(read-bytes-sec-max-length, 
READ_BYTES_SEC_MAX_LENGTH);
+    VSH_SET_THROTTLE_GROUP(write-bytes-sec-max-length, 
WRITE_BYTES_SEC_MAX_LENGTH);
+    VSH_SET_THROTTLE_GROUP(total-iops-sec-max-length, 
TOTAL_IOPS_SEC_MAX_LENGTH);
+    VSH_SET_THROTTLE_GROUP(read-iops-sec-max-length, READ_IOPS_SEC_MAX_LENGTH);
+    VSH_SET_THROTTLE_GROUP(write-iops-sec-max-length, 
WRITE_IOPS_SEC_MAX_LENGTH);
+#undef VSH_SET_THROTTLE_GROUP
+
+    if (vshCommandOptString(ctl, cmd, "group-name", &group_name) < 0) {
+        goto cleanup;
+    }
+
+    if (group_name) {
+        if (virTypedParamsAddString(&params, &nparams, &maxparams,
+                                    VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME,
+                                    group_name) < 0)
+            goto save_error;
+    }
+
+    if (virDomainSetThrottleGroup(dom, group_name, params, nparams, flags) < 0)
+        goto error;
+    vshPrintExtra(ctl, "%s", _("Throttle group set successfully\n"));
+
+    ret = true;
+
+ cleanup:
+    virTypedParamsFree(params, nparams);
+    return ret;
+
+ save_error:
+    vshSaveLibvirtError();
+ error:
+    vshError(ctl, "%s", _("Unable to set throttle group"));
+    goto cleanup;
+
+ interror:
+    vshError(ctl, "%s", _("Unable to parse integer parameter"));
+    goto cleanup;
+}
+
+
+/*
+ * "domthrottlegroupdel" command
+ */
+static const vshCmdInfo info_domthrottlegroupdel = {
+    .help = N_("Delete a throttling group."),
+    .desc = N_("Delete a throttling group."),
+};
+
+
+static const vshCmdOptDef opts_domthrottlegroupdel[] = {
+    VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+    {.name = "group-name",
+     .type = VSH_OT_STRING,
+     .positional = true,
+     .required = true,
+     .completer = virshDomainThrottleGroupCompleter,
+     .help = N_("throttle group name")
+    },
+    VIRSH_COMMON_OPT_DOMAIN_CONFIG,
+    VIRSH_COMMON_OPT_DOMAIN_LIVE,
+    VIRSH_COMMON_OPT_DOMAIN_CURRENT,
+    {.name = NULL}
+};
+
+
+static bool
+cmdThrottleGroupDel(vshControl *ctl,
+                    const vshCmd *cmd)
+{
+    g_autoptr(virshDomain) dom = NULL;
+    const char *group_name = NULL;
+    bool config = vshCommandOptBool(cmd, "config");
+    bool live = vshCommandOptBool(cmd, "live");
+    bool current = vshCommandOptBool(cmd, "current");
+    unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
+
+    VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
+    VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
+
+    if (config)
+        flags |= VIR_DOMAIN_AFFECT_CONFIG;
+    if (live)
+        flags |= VIR_DOMAIN_AFFECT_LIVE;
+
+    if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+        return false;
+
+    if (vshCommandOptString(ctl, cmd, "group-name", &group_name) < 0) {
+        return false;
+    }
+
+    if (virDomainDelThrottleGroup(dom, group_name, flags) < 0)
+        return false;
+    vshPrintExtra(ctl, "%s", _("Throttle group deleted successfully\n"));
+
+    return true;
+}
+
+
+/*
+ * "domthrottlegroupinfo" command
+ */
+static const vshCmdInfo info_domthrottlegroupinfo = {
+    .help = N_("Get a throttling group."),
+    .desc = N_("Get a throttling group."),
+};
+
+
+static const vshCmdOptDef opts_domthrottlegroupinfo[] = {
+    VIRSH_COMMON_OPT_DOMAIN_FULL(0),
+    {.name = "group-name",
+     .type = VSH_OT_STRING,
+     .positional = true,
+     .required = true,
+     .completer = virshDomainThrottleGroupCompleter,
+     .help = N_("throttle group name")
+    },
+    {.name = "inactive",
+     .type = VSH_OT_BOOL,
+     .help = N_("get inactive rather than running configuration")
+    },
+    {.name = NULL}
+};
+
+
+#define PARSE_THROTTLE_GROUP(val) \
+    do { \
+        g_autofree char *str = virXPathString("string(./" #val ")", ctxt); \
+        if (str) \
+            vshPrint(ctl, "%-15s: %s\n", #val, str); \
+    } while (false)
+
+static bool
+cmdThrottleGroupInfo(vshControl *ctl,
+                     const vshCmd *cmd)
+{
+    const char *group_name = NULL;
+    unsigned int flags = 0;
+    g_autoptr(xmlDoc) xml = NULL;
+    g_autoptr(xmlXPathContext) ctxt = NULL;
+    g_autofree xmlNodePtr *node = NULL;
+    int n = 0;
+    size_t i;
+
+    if (vshCommandOptBool(cmd, "inactive"))
+        flags |= VIR_DOMAIN_XML_INACTIVE;
+
+    if (vshCommandOptString(ctl, cmd, "group-name", &group_name) < 0)
+        return false;
+
+    if (virshDomainGetXML(ctl, cmd, flags, &xml, &ctxt) < 0)
+        return false;
+
+    if ((n = virXPathNodeSet("/domain/throttlegroups/throttlegroup", ctxt, 
&node)) < 0)
+        return false;
+
+    for (i = 0; i < n; i++) {
+        g_autofree char *name = NULL;
+        VIR_XPATH_NODE_AUTORESTORE(ctxt);
+        ctxt->node = node[i];
+
+        name = virXPathString("string(./group_name)", ctxt);
+
+        if (STRNEQ_NULLABLE(group_name, name))
+            continue;
+
+        PARSE_THROTTLE_GROUP(total_bytes_sec);
+        PARSE_THROTTLE_GROUP(read_bytes_sec);
+        PARSE_THROTTLE_GROUP(write_bytes_sec);
+        PARSE_THROTTLE_GROUP(total_iops_sec);
+        PARSE_THROTTLE_GROUP(read_iops_sec);
+        PARSE_THROTTLE_GROUP(write_iops_sec);
+
+        PARSE_THROTTLE_GROUP(total_bytes_sec_max);
+        PARSE_THROTTLE_GROUP(read_bytes_sec_max);
+        PARSE_THROTTLE_GROUP(write_bytes_sec_max);
+        PARSE_THROTTLE_GROUP(total_iops_sec_max);
+        PARSE_THROTTLE_GROUP(read_iops_sec_max);
+        PARSE_THROTTLE_GROUP(write_iops_sec_max);
+
+        PARSE_THROTTLE_GROUP(size_iops_sec);
+
+        PARSE_THROTTLE_GROUP(total_bytes_sec_max_length);
+        PARSE_THROTTLE_GROUP(read_bytes_sec_max_length);
+        PARSE_THROTTLE_GROUP(write_bytes_sec_max_length);
+        PARSE_THROTTLE_GROUP(total_iops_sec_max_length);
+        PARSE_THROTTLE_GROUP(read_iops_sec_max_length);
+        PARSE_THROTTLE_GROUP(write_iops_sec_max_length);
+    }
+
+    return true;
+}
+#undef PARSE_THROTTLE_GROUP
+
 /*
  * "blkiotune" command
  */
@@ -13442,6 +13784,30 @@ const vshCmdDef domManagementCmds[] = {
      .info = &info_blkdeviotune,
      .flags = 0
     },
+    {.name = "domthrottlegroupset",
+     .handler = cmdThrottleGroupSet,
+     .opts = opts_domthrottlegroupset,
+     .info = &info_domthrottlegroupset,
+     .flags = 0
+    },
+    {.name = "domthrottlegroupdel",
+     .handler = cmdThrottleGroupDel,
+     .opts = opts_domthrottlegroupdel,
+     .info = &info_domthrottlegroupdel,
+     .flags = 0
+    },
+    {.name = "domthrottlegroupinfo",
+     .handler = cmdThrottleGroupInfo,
+     .opts = opts_domthrottlegroupinfo,
+     .info = &info_domthrottlegroupinfo,
+     .flags = 0
+    },
+    {.name = "domthrottlegrouplist",
+     .handler = cmdThrottleGroupList,
+     .opts = opts_domthrottlegrouplist,
+     .info = &info_domthrottlegrouplist,
+     .flags = 0
+    },
     {.name = "blkiotune",
      .handler = cmdBlkiotune,
      .opts = opts_blkiotune,
-- 
2.48.1

Reply via email to