[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200915235259.457050-6-kuba@kernel.org>
Date: Tue, 15 Sep 2020 16:52:59 -0700
From: Jakub Kicinski <kuba@...nel.org>
To: mkubecek@...e.cz
Cc: netdev@...r.kernel.org, Jakub Kicinski <kuba@...nel.org>
Subject: [PATCH ethtool-next 5/5] pause: add support for dumping statistics
Add support for requesting pause frame stats from the kernel.
# ./ethtool -I -a eth0
Pause parameters for eth0:
Autonegotiate: on
RX: on
TX: on
Statistics:
tx_pause_frames: 1
rx_pause_frames: 1
# ./ethtool -I --json -a eth0
[ {
"ifname": "eth0",
"autonegotiate": true,
"rx": true,
"tx": true,
"statistics": {
"tx_pause_frames": 1,
"rx_pause_frames": 1
}
} ]
Signed-off-by: Jakub Kicinski <kuba@...nel.org>
---
netlink/pause.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/netlink/pause.c b/netlink/pause.c
index 30ecdccb15eb..f9dec9fe887a 100644
--- a/netlink/pause.c
+++ b/netlink/pause.c
@@ -5,6 +5,7 @@
*/
#include <errno.h>
+#include <inttypes.h>
#include <string.h>
#include <stdio.h>
@@ -110,6 +111,62 @@ static int show_pause_autoneg_status(struct nl_context *nlctx)
return ret;
}
+static int show_pause_stats(const struct nlattr *nest)
+{
+ const struct nlattr *tb[ETHTOOL_A_PAUSE_STAT_MAX + 1] = {};
+ DECLARE_ATTR_TB_INFO(tb);
+ static const struct {
+ unsigned int attr;
+ char *name;
+ } stats[] = {
+ { ETHTOOL_A_PAUSE_STAT_TX_FRAMES, "tx_pause_frames" },
+ { ETHTOOL_A_PAUSE_STAT_RX_FRAMES, "rx_pause_frames" },
+ };
+ bool header = false;
+ unsigned int i;
+ size_t n;
+ int ret;
+
+ ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info);
+ if (ret < 0)
+ return ret;
+
+ open_json_object("statistics");
+ for (i = 0; i < ARRAY_SIZE(stats); i++) {
+ char fmt[32];
+
+ if (!tb[stats[i].attr])
+ continue;
+
+ if (!header && !is_json_context()) {
+ printf("Statistics:\n");
+ header = true;
+ }
+
+ if (mnl_attr_validate(tb[stats[i].attr], MNL_TYPE_U64)) {
+ fprintf(stderr, "malformed netlink message (statistic)\n");
+ goto err_close_stats;
+ }
+
+ n = snprintf(fmt, sizeof(fmt), " %s: %%" PRId64 "\n",
+ stats[i].name);
+ if (n >= sizeof(fmt)) {
+ fprintf(stderr, "internal error - malformed label\n");
+ goto err_close_stats;
+ }
+
+ print_u64(PRINT_ANY, stats[i].name, fmt,
+ mnl_attr_get_u64(tb[stats[i].attr]));
+ }
+ close_json_object();
+
+ return 0;
+
+err_close_stats:
+ close_json_object();
+ return -1;
+}
+
int pause_reply_cb(const struct nlmsghdr *nlhdr, void *data)
{
const struct nlattr *tb[ETHTOOL_A_PAUSE_MAX + 1] = {};
@@ -147,6 +204,11 @@ int pause_reply_cb(const struct nlmsghdr *nlhdr, void *data)
if (ret < 0)
goto err_close_dev;
}
+ if (tb[ETHTOOL_A_PAUSE_STATS]) {
+ ret = show_pause_stats(tb[ETHTOOL_A_PAUSE_STATS]);
+ if (ret < 0)
+ goto err_close_dev;
+ }
if (!silent)
print_nl();
@@ -163,6 +225,7 @@ int nl_gpause(struct cmd_context *ctx)
{
struct nl_context *nlctx = ctx->nlctx;
struct nl_socket *nlsk = nlctx->ethnl_socket;
+ u32 flags;
int ret;
if (netlink_cmd_check(ctx, ETHTOOL_MSG_PAUSE_GET, true))
@@ -173,8 +236,9 @@ int nl_gpause(struct cmd_context *ctx)
return 1;
}
+ flags = nlctx->ctx->show_stats ? ETHTOOL_FLAG_STATS : 0;
ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_PAUSE_GET,
- ETHTOOL_A_PAUSE_HEADER, 0);
+ ETHTOOL_A_PAUSE_HEADER, flags);
if (ret < 0)
return ret;
--
2.26.2
Powered by blists - more mailing lists