]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
rdma: Add optional-counters set/unset support
authorNeta Ostrovsky <netao@nvidia.com>
Thu, 14 Oct 2021 07:53:58 +0000 (10:53 +0300)
committerDavid Ahern <dsahern@kernel.org>
Fri, 15 Oct 2021 23:52:57 +0000 (17:52 -0600)
This patch provides an extension to the rdma statistics tool
that allows to set/unset optional counters set dynamically,
using new netlink commands.
Note that the optional counter statistic implementation is
driver-specific and may impact the performance.

Examples:
To enable a set of optional counters on link rocep8s0f0/1:
    $ sudo rdma statistic set link rocep8s0f0/1 optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts
To disable all optional counters on link rocep8s0f0/1:
    $ sudo rdma statistic unset link rocep8s0f0/1 optional-counters

Signed-off-by: Neta Ostrovsky <netao@nvidia.com>
Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Mark Zhang <markzhang@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
man/man8/rdma-statistic.8
rdma/stat.c

index 885769bc9eb66f6fb1112d38279cbc0cad70486c..7dd2b02c3e92815a0d46fb308119c8061e6e4734 100644 (file)
@@ -65,6 +65,21 @@ rdma-statistic \- RDMA statistic counter configuration
 .B link
 .RI "[ " DEV/PORT_INDEX " ]"
 
+.ti -8
+.B rdma statistic
+.B set
+.B link
+.RI "[ " DEV/PORT_INDEX " ]"
+.B optional-counters
+.RI "[ " OPTIONAL-COUNTERS " ]"
+
+.ti -8
+.B rdma statistic
+.B unset
+.B link
+.RI "[ " DEV/PORT_INDEX " ]"
+.B optional-counters
+
 .ti -8
 .IR COUNTER_SCOPE " := "
 .RB "{ " link " | " dev " }"
@@ -111,6 +126,13 @@ If this argument is omitted then a new counter will be allocated.
 
 .SS rdma statistic mode supported - Display the supported optional counters for each link.
 
+.SS rdma statistic set - Enable a set of optional counters for a specific device/port.
+
+.I "OPTIONAL-COUNTERS"
+- specifies the name of the optional counters to enable. Optional counters that are not specified will be disabled. Note that optional counters are driver-specific.
+
+.SS rdma statistic unset - Disable all optional counters for a specific device/port.
+
 .SH "EXAMPLES"
 .PP
 rdma statistic show
@@ -207,6 +229,16 @@ rdma statistic mode supported link mlx5_2/1
 .RS 4
 Display the optional counters that mlx5_2/1 supports.
 .RE
+.PP
+rdma statistic set link mlx5_2/1 optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts
+.RS 4
+Enable the cc_rx_ce_pkts,cc_rx_cnp_pkts counters on device mlx5_2 port 1.
+.RE
+.PP
+rdma statistic unset link mlx5_2/1 optional-counters
+.RS 4
+Disable all the optional counters on device mlx5_2 port 1.
+.RE
 
 .SH SEE ALSO
 .BR rdma (8),
index 7d645d8f6a2a85769882ef7f8152f2defd3b66f0..adfcd34afa856ca4deb73aa53d5a7fd3061fd9e4 100644 (file)
@@ -22,6 +22,8 @@ static int stat_help(struct rd *rd)
        pr_out("       %s statistic show link [ DEV/PORT_INDEX ]\n", rd->filename);
        pr_out("       %s statistic mode [ supported ]\n", rd->filename);
        pr_out("       %s statistic mode [ supported ] link [ DEV/PORT_INDEX ]\n", rd->filename);
+       pr_out("       %s statistic set link [ DEV/PORT_INDEX ] optional-counters [ OPTIONAL-COUNTERS ]\n", rd->filename);
+       pr_out("       %s statistic unset link [ DEV/PORT_INDEX ] optional-counters\n", rd->filename);
        pr_out("where  OBJECT: = { qp }\n");
        pr_out("       CRITERIA : = { type }\n");
        pr_out("       COUNTER_SCOPE: = { link | dev }\n");
@@ -43,6 +45,8 @@ static int stat_help(struct rd *rd)
        pr_out("       %s statistic mode link mlx5_2/1\n", rd->filename);
        pr_out("       %s statistic mode supported\n", rd->filename);
        pr_out("       %s statistic mode supported link mlx5_2/1\n", rd->filename);
+       pr_out("       %s statistic set link mlx5_2/1 optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts\n", rd->filename);
+       pr_out("       %s statistic unset link mlx5_2/1 optional-counters\n", rd->filename);
 
        return 0;
 }
@@ -499,6 +503,30 @@ static int stat_qp_set(struct rd *rd)
        return rd_exec_cmd(rd, cmds, "parameter");
 }
 
+static int stat_get_arg_str(struct rd *rd, const char *arg, char **value, bool allow_empty)
+{
+       int len = 0;
+
+       if (strcmpx(rd_argv(rd), arg) != 0) {
+               pr_err("Unknown parameter '%s'.\n", rd_argv(rd));
+               return -EINVAL;
+       }
+
+       rd_arg_inc(rd);
+       if (!rd_no_arg(rd)) {
+               *value = strdup(rd_argv(rd));
+               len = strlen(*value);
+               rd_arg_inc(rd);
+       }
+
+       if ((allow_empty && len) || (!allow_empty && !len)) {
+               stat_help(rd);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int stat_get_arg(struct rd *rd, const char *arg)
 {
        int value = 0;
@@ -877,6 +905,154 @@ static int stat_mode(struct rd *rd)
        return rd_exec_cmd(rd, cmds, "parameter");
 }
 
+static int stat_one_set_link_opcounters(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
+       struct nlattr *nla_entry, *tb_set;
+       int ret, flags = NLM_F_REQUEST | NLM_F_ACK;
+       char *opcnt, *opcnts;
+       struct rd *rd = data;
+       uint32_t seq;
+       bool found;
+
+       mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
+       if (!tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS])
+               return MNL_CB_ERROR;
+
+       if (rd_no_arg(rd)) {
+               stat_help(rd);
+               return -EINVAL;
+       }
+
+       ret = stat_get_arg_str(rd, "optional-counters", &opcnts, false);
+       if (ret)
+               return ret;
+
+       rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_SET, &seq, flags);
+       mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX,
+                        rd->dev_idx);
+       mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX,
+                        rd->port_idx);
+
+       tb_set = mnl_attr_nest_start(rd->nlh, RDMA_NLDEV_ATTR_STAT_HWCOUNTERS);
+
+       opcnt = strtok(opcnts, ",");
+       while (opcnt) {
+               found = false;
+               mnl_attr_for_each_nested(nla_entry,
+                                        tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS]) {
+                       struct nlattr *cnt[RDMA_NLDEV_ATTR_MAX] = {}, *nm, *id;
+
+                       if (mnl_attr_parse_nested(nla_entry, rd_attr_cb,
+                                                 cnt) != MNL_CB_OK)
+                               return -EINVAL;
+
+                       nm = cnt[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME];
+                       id = cnt[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_INDEX];
+                       if (!nm || ! id)
+                               return -EINVAL;
+
+                       if (!cnt[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC])
+                               continue;
+
+                       if (strcmp(opcnt, mnl_attr_get_str(nm)) == 0) {
+                               mnl_attr_put_u32(rd->nlh,
+                                                RDMA_NLDEV_ATTR_STAT_HWCOUNTER_INDEX,
+                                                mnl_attr_get_u32(id));
+                               found = true;
+                       }
+               }
+
+               if (!found)
+                       return -EINVAL;
+
+               opcnt = strtok(NULL, ",");
+       }
+       mnl_attr_nest_end(rd->nlh, tb_set);
+
+       return rd_sendrecv_msg(rd, seq);
+}
+
+static int stat_one_set_link(struct rd *rd)
+{
+       uint32_t seq;
+       int err;
+
+       if (!rd->port_idx)
+               return 0;
+
+       err = stat_one_link_get_status_req(rd, &seq);
+       if (err)
+               return err;
+
+       return rd_recv_msg(rd, stat_one_set_link_opcounters, rd, seq);
+}
+
+static int stat_set_link(struct rd *rd)
+{
+       return rd_exec_link(rd, stat_one_set_link, true);
+}
+
+static int stat_set(struct rd *rd)
+{
+       const struct rd_cmd cmds[] = {
+               { NULL,         stat_help },
+               { "link",       stat_set_link },
+               { "help",       stat_help },
+               { 0 },
+       };
+       return rd_exec_cmd(rd, cmds, "parameter");
+}
+
+static int stat_one_unset_link_opcounters(struct rd *rd)
+{
+       int ret, flags = NLM_F_REQUEST | NLM_F_ACK;
+       struct nlattr *tbl;
+       uint32_t seq;
+       char *opcnts;
+
+       if (rd_no_arg(rd)) {
+               stat_help(rd);
+               return -EINVAL;
+       }
+
+       ret = stat_get_arg_str(rd, "optional-counters", &opcnts, true);
+       if (ret)
+               return ret;
+
+       rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_SET, &seq, flags);
+       mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX,
+                        rd->dev_idx);
+       mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX,
+                        rd->port_idx);
+
+       tbl = mnl_attr_nest_start(rd->nlh, RDMA_NLDEV_ATTR_STAT_HWCOUNTERS);
+       mnl_attr_nest_end(rd->nlh, tbl);
+
+       return rd_sendrecv_msg(rd, seq);
+}
+
+static int stat_one_unset_link(struct rd *rd)
+{
+       return stat_one_unset_link_opcounters(rd);
+}
+
+static int stat_unset_link(struct rd *rd)
+{
+       return rd_exec_link(rd, stat_one_unset_link, true);
+}
+
+static int stat_unset(struct rd *rd)
+{
+       const struct rd_cmd cmds[] = {
+               { NULL,         stat_help },
+               { "link",       stat_unset_link },
+               { "help",       stat_help },
+               { 0 },
+       };
+       return rd_exec_cmd(rd, cmds, "parameter");
+}
+
 static int stat_show_parse_cb(const struct nlmsghdr *nlh, void *data)
 {
        struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
@@ -949,6 +1125,8 @@ int cmd_stat(struct rd *rd)
                { "qp",         stat_qp },
                { "mr",         stat_mr },
                { "mode",       stat_mode },
+               { "set",        stat_set },
+               { "unset",      stat_unset },
                { 0 }
        };