Add a switch for querying all statistic groups available
in the kernel.

To reject --groups and --all-groups being specified
for one request add a concept of "parameter equivalency"
in the parser. Alternative of having a special group
type like "--groups all" seems less clean.

Suggested-by: Ido Schimmel <ido...@nvidia.com>
Signed-off-by: Jakub Kicinski <k...@kernel.org>
---
 ethtool.8.in     |  5 ++++-
 ethtool.c        |  2 +-
 netlink/parser.c | 17 ++++++++++++++-
 netlink/parser.h |  4 ++++
 netlink/stats.c  | 55 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/ethtool.8.in b/ethtool.8.in
index b98c42b8a4c3..a3694b052fbd 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -240,7 +240,7 @@ ethtool \- query or control network driver and hardware 
settings
 .HP
 .B ethtool \-S|\-\-statistics
 .I devname
-.RB [\fB\-\-groups
+.RB [\fB\-\-all\-groups\fP|\fB\-\-groups
 .RB [\fBeth\-phy\fP]
 .RB [\fBeth\-mac\fP]
 .RB [\fBeth\-ctrl\fP]
@@ -666,6 +666,9 @@ devices may implement either, both or none. There is little 
commonality between
 naming of NIC- and driver-specific statistics across vendors.
 .RS 4
 .TP
+.B \fB\-\-all\-groups
+.E
+.TP
 .B \fB\-\-groups [\fBeth\-phy\fP] [\fBeth\-mac\fP] [\fBeth\-ctrl\fP] 
[\fBrmon\fP]
 Request groups of standard device statistics.
 .RE
diff --git a/ethtool.c b/ethtool.c
index 1b5690f424c8..573936d642bd 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5763,7 +5763,7 @@ static const struct option args[] = {
                .nlchk  = nl_gstats_chk,
                .nlfunc = nl_gstats,
                .help   = "Show adapter statistics",
-               .xhelp  = "               [ --groups [eth-phy] [eth-mac] 
[eth-ctrl] [rmon] ]\n"
+               .xhelp  = "               [ --all-groups | --groups [eth-phy] 
[eth-mac] [eth-ctrl] [rmon] ]\n"
        },
        {
                .opts   = "--phy-statistics",
diff --git a/netlink/parser.c b/netlink/parser.c
index c2eae93efb69..d15fa332cc55 100644
--- a/netlink/parser.c
+++ b/netlink/parser.c
@@ -919,6 +919,17 @@ static void __parser_set(uint64_t *map, unsigned int idx)
        map[idx / 64] |= (1 << (idx % 64));
 }
 
+static void __parser_set_group(const struct param_parser *params,
+                              uint64_t *map, unsigned int equiv_group)
+{
+       const struct param_parser *parser;
+       unsigned int idx = 0;
+
+       for (parser = params; parser->arg; parser++, idx++)
+               if (parser->equiv_group == equiv_group)
+                       __parser_set(map, idx);
+}
+
 struct tmp_buff {
        struct nl_msg_buff      *msgbuff;
        unsigned int            id;
@@ -1074,7 +1085,11 @@ int nl_parser(struct nl_context *nlctx, const struct 
param_parser *params,
                        parser_err_min_argc(nlctx, parser->min_argc);
                        goto out_free;
                }
-               __parser_set(params_seen, parser - params);
+               if (parser->equiv_group)
+                       __parser_set_group(params, params_seen,
+                                          parser->equiv_group);
+               else
+                       __parser_set(params_seen, parser - params);
 
                buff = NULL;
                if (parser->group)
diff --git a/netlink/parser.h b/netlink/parser.h
index 28f26ccc2a1c..57ad6d0498a8 100644
--- a/netlink/parser.h
+++ b/netlink/parser.h
@@ -43,6 +43,10 @@ struct param_parser {
        unsigned int            min_argc;
        /* if @dest is passed to nl_parser(), offset to store value */
        unsigned int            dest_offset;
+       /* parameter equivalency group - only one parameter from a group
+        * can be specified, 0 means no group
+        */
+       unsigned int            equiv_group;
 };
 
 /* data structures used for handler data */
diff --git a/netlink/stats.c b/netlink/stats.c
index e7e69f002cd5..5c7716afe60e 100644
--- a/netlink/stats.c
+++ b/netlink/stats.c
@@ -220,6 +220,54 @@ static const struct bitset_parser_data stats_parser_data = 
{
        .force_hex      = false,
 };
 
+static int stats_parse_all_groups(struct nl_context *nlctx, uint16_t type,
+                                 const void *data, struct nl_msg_buff *msgbuff,
+                                 void *dest)
+{
+       const struct stringset *std_str;
+       struct nlattr *nest;
+       int i, ret, nbits;
+       uint32_t *bits;
+
+       if (data || dest)
+               return -EFAULT;
+
+       /* ethnl2 and strset code already does caching */
+       ret = netlink_init_ethnl2_socket(nlctx);
+       if (ret < 0)
+               return ret;
+       std_str = global_stringset(ETH_SS_STATS_STD, nlctx->ethnl2_socket);
+
+       nbits = get_count(std_str);
+       bits = calloc(DIV_ROUND_UP(nbits, 32), sizeof(uint32_t));
+       if (!bits)
+               return -ENOMEM;
+
+       for (i = 0; i < nbits; i++)
+               bits[i / 32] |= 1U << (i % 32);
+
+       ret = -EMSGSIZE;
+       nest = ethnla_nest_start(msgbuff, type);
+       if (!nest)
+               goto err_free;
+
+       if (ethnla_put_flag(msgbuff, ETHTOOL_A_BITSET_NOMASK, true) ||
+           ethnla_put_u32(msgbuff, ETHTOOL_A_BITSET_SIZE, nbits) ||
+           ethnla_put(msgbuff, ETHTOOL_A_BITSET_VALUE,
+                      DIV_ROUND_UP(nbits, 32) * sizeof(uint32_t), bits))
+               goto err_cancel;
+
+       ethnla_nest_end(msgbuff, nest);
+       free(bits);
+       return 0;
+
+err_cancel:
+       ethnla_nest_cancel(msgbuff, nest);
+err_free:
+       free(bits);
+       return ret;
+}
+
 static const struct param_parser stats_params[] = {
        {
                .arg            = "--groups",
@@ -227,6 +275,13 @@ static const struct param_parser stats_params[] = {
                .handler        = nl_parse_bitset,
                .handler_data   = &stats_parser_data,
                .min_argc       = 1,
+               .equiv_group    = 1,
+       },
+       {
+               .arg            = "--all-groups",
+               .type           = ETHTOOL_A_STATS_GROUPS,
+               .handler        = stats_parse_all_groups,
+               .equiv_group    = 1,
        },
        {}
 };
-- 
2.30.2

Reply via email to