Netdev Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH ethtool-next 0/5] pause frame stats
@ 2020-09-15 23:52 Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 1/5] update UAPI header copies Jakub Kicinski
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Jakub Kicinski @ 2020-09-15 23:52 UTC (permalink / raw)
To: mkubecek; +Cc: netdev, Jakub Kicinski
Hi!
This set adds support for pause frame statistics.
This is the first of this kind of statistics so first
support for a new flag (--include-statistics) is added.
Next pause frame info is extended to support --json.
Last but not least - it's taught to display statistics.
Jakub Kicinski (5):
update UAPI header copies
pause: add --json support
separate FLAGS out in -h
add support for stats in subcommands
pause: add support for dumping statistics
ethtool.8.in | 7 +++
ethtool.c | 17 +++++-
internal.h | 1 +
netlink/netlink.h | 12 +++-
netlink/pause.c | 111 +++++++++++++++++++++++++++++++----
uapi/linux/ethtool_netlink.h | 18 +++++-
6 files changed, 149 insertions(+), 17 deletions(-)
--
2.26.2
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH ethtool-next 1/5] update UAPI header copies
2020-09-15 23:52 [PATCH ethtool-next 0/5] pause frame stats Jakub Kicinski
@ 2020-09-15 23:52 ` Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 2/5] pause: add --json support Jakub Kicinski
` (3 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Jakub Kicinski @ 2020-09-15 23:52 UTC (permalink / raw)
To: mkubecek; +Cc: netdev, Jakub Kicinski
Update to kernel commit 945c5704887e.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
uapi/linux/ethtool_netlink.h | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/uapi/linux/ethtool_netlink.h b/uapi/linux/ethtool_netlink.h
index cebdb52e6a05..8d3926c56769 100644
--- a/uapi/linux/ethtool_netlink.h
+++ b/uapi/linux/ethtool_netlink.h
@@ -91,9 +91,12 @@ enum {
#define ETHTOOL_FLAG_COMPACT_BITSETS (1 << 0)
/* provide optional reply for SET or ACT requests */
#define ETHTOOL_FLAG_OMIT_REPLY (1 << 1)
+/* request statistics, if supported by the driver */
+#define ETHTOOL_FLAG_STATS (1 << 2)
#define ETHTOOL_FLAG_ALL (ETHTOOL_FLAG_COMPACT_BITSETS | \
- ETHTOOL_FLAG_OMIT_REPLY)
+ ETHTOOL_FLAG_OMIT_REPLY | \
+ ETHTOOL_FLAG_STATS)
enum {
ETHTOOL_A_HEADER_UNSPEC,
@@ -376,12 +379,25 @@ enum {
ETHTOOL_A_PAUSE_AUTONEG, /* u8 */
ETHTOOL_A_PAUSE_RX, /* u8 */
ETHTOOL_A_PAUSE_TX, /* u8 */
+ ETHTOOL_A_PAUSE_STATS, /* nest - _PAUSE_STAT_* */
/* add new constants above here */
__ETHTOOL_A_PAUSE_CNT,
ETHTOOL_A_PAUSE_MAX = (__ETHTOOL_A_PAUSE_CNT - 1)
};
+enum {
+ ETHTOOL_A_PAUSE_STAT_UNSPEC,
+ ETHTOOL_A_PAUSE_STAT_PAD,
+
+ ETHTOOL_A_PAUSE_STAT_TX_FRAMES,
+ ETHTOOL_A_PAUSE_STAT_RX_FRAMES,
+
+ /* add new constants above here */
+ __ETHTOOL_A_PAUSE_STAT_CNT,
+ ETHTOOL_A_PAUSE_STAT_MAX = (__ETHTOOL_A_PAUSE_STAT_CNT - 1)
+};
+
/* EEE */
enum {
--
2.26.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH ethtool-next 2/5] pause: add --json support
2020-09-15 23:52 [PATCH ethtool-next 0/5] pause frame stats Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 1/5] update UAPI header copies Jakub Kicinski
@ 2020-09-15 23:52 ` Jakub Kicinski
2020-09-24 0:10 ` Jacob Keller
2020-09-15 23:52 ` [PATCH ethtool-next 3/5] separate FLAGS out in -h Jakub Kicinski
` (2 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Jakub Kicinski @ 2020-09-15 23:52 UTC (permalink / raw)
To: mkubecek; +Cc: netdev, Jakub Kicinski
No change in normal text output:
# ./ethtool -a eth0
Pause parameters for eth0:
Autonegotiate: on
RX: on
TX: on
RX negotiated: on
TX negotiated: on
JSON:
# ./ethtool --json -a eth0
[ {
"ifname": "eth0",
"autonegotiate": true,
"rx": true,
"tx": true,
"negotiated": {
"rx": true,
"tx": true
}
} ]
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
netlink/netlink.h | 12 ++++++++++--
netlink/pause.c | 45 +++++++++++++++++++++++++++++++++++----------
2 files changed, 45 insertions(+), 12 deletions(-)
diff --git a/netlink/netlink.h b/netlink/netlink.h
index dd4a02bcc916..4916d25ed5c0 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -106,9 +106,17 @@ static inline const char *u8_to_bool(const struct nlattr *attr)
return "n/a";
}
-static inline void show_bool(const struct nlattr *attr, const char *label)
+static inline void show_bool(const char *key, const char *fmt,
+ const struct nlattr *attr)
{
- printf("%s%s\n", label, u8_to_bool(attr));
+ if (is_json_context()) {
+ if (attr) {
+ print_bool(PRINT_JSON, key, NULL,
+ mnl_attr_get_u8(attr));
+ }
+ } else {
+ print_string(PRINT_FP, NULL, fmt, u8_to_bool(attr));
+ }
}
/* misc */
diff --git a/netlink/pause.c b/netlink/pause.c
index 7b6b3a1d2c10..30ecdccb15eb 100644
--- a/netlink/pause.c
+++ b/netlink/pause.c
@@ -72,8 +72,16 @@ static int pause_autoneg_cb(const struct nlmsghdr *nlhdr, void *data)
else if (peer.pause)
tx_status = true;
}
- printf("RX negotiated: %s\nTX negotiated: %s\n",
- rx_status ? "on" : "off", tx_status ? "on" : "off");
+
+ if (is_json_context()) {
+ open_json_object("negotiated");
+ print_bool(PRINT_JSON, "rx", NULL, rx_status);
+ print_bool(PRINT_JSON, "tx", NULL, tx_status);
+ close_json_object();
+ } else {
+ printf("RX negotiated: %s\nTX negotiated: %s\n",
+ rx_status ? "on" : "off", tx_status ? "on" : "off");
+ }
return MNL_CB_OK;
}
@@ -121,21 +129,34 @@ int pause_reply_cb(const struct nlmsghdr *nlhdr, void *data)
return err_ret;
if (silent)
- putchar('\n');
- printf("Pause parameters for %s:\n", nlctx->devname);
- show_bool(tb[ETHTOOL_A_PAUSE_AUTONEG], "Autonegotiate:\t");
- show_bool(tb[ETHTOOL_A_PAUSE_RX], "RX:\t\t");
- show_bool(tb[ETHTOOL_A_PAUSE_TX], "TX:\t\t");
+ print_nl();
+
+ open_json_object(NULL);
+
+ print_string(PRINT_ANY, "ifname", "Pause parameters for %s:\n",
+ nlctx->devname);
+
+ show_bool("autonegotiate", "Autonegotiate:\t%s\n",
+ tb[ETHTOOL_A_PAUSE_AUTONEG]);
+ show_bool("rx", "RX:\t\t%s\n", tb[ETHTOOL_A_PAUSE_RX]);
+ show_bool("tx", "TX:\t\t%s\n", tb[ETHTOOL_A_PAUSE_TX]);
+
if (!nlctx->is_monitor && tb[ETHTOOL_A_PAUSE_AUTONEG] &&
mnl_attr_get_u8(tb[ETHTOOL_A_PAUSE_AUTONEG])) {
ret = show_pause_autoneg_status(nlctx);
if (ret < 0)
- return err_ret;
+ goto err_close_dev;
}
if (!silent)
- putchar('\n');
+ print_nl();
+
+ close_json_object();
return MNL_CB_OK;
+
+err_close_dev:
+ close_json_object();
+ return err_ret;
}
int nl_gpause(struct cmd_context *ctx)
@@ -156,7 +177,11 @@ int nl_gpause(struct cmd_context *ctx)
ETHTOOL_A_PAUSE_HEADER, 0);
if (ret < 0)
return ret;
- return nlsock_send_get_request(nlsk, pause_reply_cb);
+
+ new_json_obj(ctx->json);
+ ret = nlsock_send_get_request(nlsk, pause_reply_cb);
+ delete_json_obj();
+ return ret;
}
/* PAUSE_SET */
--
2.26.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH ethtool-next 3/5] separate FLAGS out in -h
2020-09-15 23:52 [PATCH ethtool-next 0/5] pause frame stats Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 1/5] update UAPI header copies Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 2/5] pause: add --json support Jakub Kicinski
@ 2020-09-15 23:52 ` Jakub Kicinski
2020-09-24 0:12 ` Jacob Keller
2020-09-15 23:52 ` [PATCH ethtool-next 4/5] add support for stats in subcommands Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 5/5] pause: add support for dumping statistics Jakub Kicinski
4 siblings, 1 reply; 12+ messages in thread
From: Jakub Kicinski @ 2020-09-15 23:52 UTC (permalink / raw)
To: mkubecek; +Cc: netdev, Jakub Kicinski
Help output is quite crowded already with every command
being prefixed by --debug and --json options, and we're
about to add a third one.
Add an indirection.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
ethtool.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/ethtool.c b/ethtool.c
index 23ecfcfd069c..ae5310e9e306 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5947,10 +5947,10 @@ static int show_usage(struct cmd_context *ctx __maybe_unused)
fprintf(stdout, PACKAGE " version " VERSION "\n");
fprintf(stdout,
"Usage:\n"
- " ethtool [ --debug MASK ][ --json ] DEVNAME\t"
+ " ethtool [ FLAGS ] DEVNAME\t"
"Display standard information about device\n");
for (i = 0; args[i].opts; i++) {
- fputs(" ethtool [ --debug MASK ][ --json ] ", stdout);
+ fputs(" ethtool [ FLAGS ] ", stdout);
fprintf(stdout, "%s %s\t%s\n",
args[i].opts,
args[i].no_dev ? "\t" : "DEVNAME",
@@ -5959,7 +5959,10 @@ static int show_usage(struct cmd_context *ctx __maybe_unused)
fputs(args[i].xhelp, stdout);
}
nl_monitor_usage();
- fprintf(stdout, "Not all options support JSON output\n");
+ fprintf(stdout, "\n");
+ fprintf(stdout, "FLAGS:\n");
+ fprintf(stdout, " --debug MASK turn on debugging messages\n");
+ fprintf(stdout, " --json enable JSON output format (not supported by all commands)\n");
return 0;
}
--
2.26.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH ethtool-next 4/5] add support for stats in subcommands
2020-09-15 23:52 [PATCH ethtool-next 0/5] pause frame stats Jakub Kicinski
` (2 preceding siblings ...)
2020-09-15 23:52 ` [PATCH ethtool-next 3/5] separate FLAGS out in -h Jakub Kicinski
@ 2020-09-15 23:52 ` Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 5/5] pause: add support for dumping statistics Jakub Kicinski
4 siblings, 0 replies; 12+ messages in thread
From: Jakub Kicinski @ 2020-09-15 23:52 UTC (permalink / raw)
To: mkubecek; +Cc: netdev, Jakub Kicinski
Add new parameters (-I | --include-statistics) which will
control requesting statistic dumps from the kernel.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
ethtool.8.in | 7 +++++++
ethtool.c | 8 ++++++++
internal.h | 1 +
3 files changed, 16 insertions(+)
diff --git a/ethtool.8.in b/ethtool.8.in
index 42c4767db33e..00cf7870376c 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -140,6 +140,9 @@ ethtool \- query or control network driver and hardware settings
.B ethtool [--json]
.I args
.HP
+.B ethtool [-I | --include-statistics]
+.I args
+.HP
.B ethtool \-\-monitor
[
.I command
@@ -499,6 +502,10 @@ Output results in JavaScript Object Notation (JSON). Only a subset of
options support this. Those which do not will continue to output
plain text in the presence of this option.
.TP
+.B \-I \-\-include\-statistics
+Include command-related statistics in the output. This option allows
+displaying relevant device statistics for selected get commands.
+.TP
.B \-a \-\-show\-pause
Queries the specified Ethernet device for pause parameter information.
.TP
diff --git a/ethtool.c b/ethtool.c
index ae5310e9e306..309539579cc9 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5963,6 +5963,7 @@ static int show_usage(struct cmd_context *ctx __maybe_unused)
fprintf(stdout, "FLAGS:\n");
fprintf(stdout, " --debug MASK turn on debugging messages\n");
fprintf(stdout, " --json enable JSON output format (not supported by all commands)\n");
+ fprintf(stdout, " -I|--include-statistics request device statistics related to the command (not supported by all commands)\n");
return 0;
}
@@ -6223,6 +6224,13 @@ int main(int argc, char **argp)
argc -= 1;
continue;
}
+ if (*argp && (!strcmp(*argp, "--include-statistics") ||
+ !strcmp(*argp, "-I"))) {
+ ctx.show_stats = true;
+ argp += 1;
+ argc -= 1;
+ continue;
+ }
break;
}
if (*argp && !strcmp(*argp, "--monitor")) {
diff --git a/internal.h b/internal.h
index d096a28abfa2..1c0652d28793 100644
--- a/internal.h
+++ b/internal.h
@@ -225,6 +225,7 @@ struct cmd_context {
char **argp; /* arguments to the sub-command */
unsigned long debug; /* debugging mask */
bool json; /* Output JSON, if supported */
+ bool show_stats; /* include command-specific stats */
#ifdef ETHTOOL_ENABLE_NETLINK
struct nl_context *nlctx; /* netlink context (opaque) */
#endif
--
2.26.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH ethtool-next 5/5] pause: add support for dumping statistics
2020-09-15 23:52 [PATCH ethtool-next 0/5] pause frame stats Jakub Kicinski
` (3 preceding siblings ...)
2020-09-15 23:52 ` [PATCH ethtool-next 4/5] add support for stats in subcommands Jakub Kicinski
@ 2020-09-15 23:52 ` Jakub Kicinski
2020-09-23 22:45 ` Michal Kubecek
4 siblings, 1 reply; 12+ messages in thread
From: Jakub Kicinski @ 2020-09-15 23:52 UTC (permalink / raw)
To: mkubecek; +Cc: netdev, Jakub Kicinski
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@kernel.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
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH ethtool-next 5/5] pause: add support for dumping statistics
2020-09-15 23:52 ` [PATCH ethtool-next 5/5] pause: add support for dumping statistics Jakub Kicinski
@ 2020-09-23 22:45 ` Michal Kubecek
2020-09-23 23:36 ` Jakub Kicinski
0 siblings, 1 reply; 12+ messages in thread
From: Michal Kubecek @ 2020-09-23 22:45 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev
On Tue, Sep 15, 2020 at 04:52:59PM -0700, Jakub Kicinski wrote:
> 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@kernel.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);
The stats are unsigned so the format should be PRIu64 here.
> + 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;
>
When the stats are supported by kernel but not provided by a device,
the request will succeed and usual output without stats will be shown.
However, when stats are requested on a pre-5.10 kernel not recognizing
ETHTOOL_FLAG_STATS, the request will fail:
mike@lion:~/work/git/ethtool> ./ethtool --debug 0x10 -I -a eth0
netlink error: unrecognized request flags
netlink error: Operation not supported
offending message and attribute:
ETHTOOL_MSG_PAUSE_GET
ETHTOOL_A_PAUSE_HEADER
ETHTOOL_A_HEADER_DEV_NAME = "eth0"
===> ETHTOOL_A_HEADER_FLAGS = 0x00000004
We should probably repeat the request with flags=0 in this case but that
would require keeping the offset of ETHTOOL_A_HEADER_FLAGS attribute and
checking for -EOPNOTSUPP with this offset in nlsock_process_ack().
Michal
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH ethtool-next 5/5] pause: add support for dumping statistics
2020-09-23 22:45 ` Michal Kubecek
@ 2020-09-23 23:36 ` Jakub Kicinski
0 siblings, 0 replies; 12+ messages in thread
From: Jakub Kicinski @ 2020-09-23 23:36 UTC (permalink / raw)
To: Michal Kubecek; +Cc: netdev
On Thu, 24 Sep 2020 00:45:10 +0200 Michal Kubecek wrote:
> > + 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);
>
> The stats are unsigned so the format should be PRIu64 here.
Good catch.
> > @@ -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;
> >
>
> When the stats are supported by kernel but not provided by a device,
> the request will succeed and usual output without stats will be shown.
> However, when stats are requested on a pre-5.10 kernel not recognizing
> ETHTOOL_FLAG_STATS, the request will fail:
>
> mike@lion:~/work/git/ethtool> ./ethtool --debug 0x10 -I -a eth0
> netlink error: unrecognized request flags
> netlink error: Operation not supported
> offending message and attribute:
> ETHTOOL_MSG_PAUSE_GET
> ETHTOOL_A_PAUSE_HEADER
> ETHTOOL_A_HEADER_DEV_NAME = "eth0"
> ===> ETHTOOL_A_HEADER_FLAGS = 0x00000004
>
> We should probably repeat the request with flags=0 in this case but that
> would require keeping the offset of ETHTOOL_A_HEADER_FLAGS attribute and
> checking for -EOPNOTSUPP with this offset in nlsock_process_ack().
Makes sense, will do.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH ethtool-next 2/5] pause: add --json support
2020-09-15 23:52 ` [PATCH ethtool-next 2/5] pause: add --json support Jakub Kicinski
@ 2020-09-24 0:10 ` Jacob Keller
2020-09-24 15:36 ` Jakub Kicinski
0 siblings, 1 reply; 12+ messages in thread
From: Jacob Keller @ 2020-09-24 0:10 UTC (permalink / raw)
To: Jakub Kicinski, mkubecek; +Cc: netdev
On 9/15/2020 4:52 PM, Jakub Kicinski wrote:
> No change in normal text output:
>
> # ./ethtool -a eth0
> Pause parameters for eth0:
> Autonegotiate: on
> RX: on
> TX: on
> RX negotiated: on
> TX negotiated: on
>
> JSON:
>
> # ./ethtool --json -a eth0
> [ {
> "ifname": "eth0",
> "autonegotiate": true,
> "rx": true,
> "tx": true,
> "negotiated": {
> "rx": true,
> "tx": true
> }
> } ]
Makes sense, we report all of these as a single dictionary with
key-values. Putting negotiated as a subsection seems reasonable as well.
I guess we could split this so that tx and rx have their own section.
but I think this is good.
This looks good to me.
Reviewed-by: Jacob Keller <jacob.e.keller@gmail.com>
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> netlink/netlink.h | 12 ++++++++++--
> netlink/pause.c | 45 +++++++++++++++++++++++++++++++++++----------
> 2 files changed, 45 insertions(+), 12 deletions(-)
>
> diff --git a/netlink/netlink.h b/netlink/netlink.h
> index dd4a02bcc916..4916d25ed5c0 100644
> --- a/netlink/netlink.h
> +++ b/netlink/netlink.h
> @@ -106,9 +106,17 @@ static inline const char *u8_to_bool(const struct nlattr *attr)
> return "n/a";
> }
>
> -static inline void show_bool(const struct nlattr *attr, const char *label)
> +static inline void show_bool(const char *key, const char *fmt,
> + const struct nlattr *attr)
> {
> - printf("%s%s\n", label, u8_to_bool(attr));
> + if (is_json_context()) {
> + if (attr) {
> + print_bool(PRINT_JSON, key, NULL,
> + mnl_attr_get_u8(attr));
> + }
> + } else {
> + print_string(PRINT_FP, NULL, fmt, u8_to_bool(attr));
Ok. The change from label to fmt makes sense because we now pass a
format string instead of a label, and we use print_string instead of printf.
> + }
> }
>
> /* misc */
> diff --git a/netlink/pause.c b/netlink/pause.c
> index 7b6b3a1d2c10..30ecdccb15eb 100644
> --- a/netlink/pause.c
> +++ b/netlink/pause.c
> @@ -72,8 +72,16 @@ static int pause_autoneg_cb(const struct nlmsghdr *nlhdr, void *data)
> else if (peer.pause)
> tx_status = true;
> }
> - printf("RX negotiated: %s\nTX negotiated: %s\n",
> - rx_status ? "on" : "off", tx_status ? "on" : "off");
> +
> + if (is_json_context()) {
> + open_json_object("negotiated");
> + print_bool(PRINT_JSON, "rx", NULL, rx_status);
> + print_bool(PRINT_JSON, "tx", NULL, tx_status);
> + close_json_object();
> + } else {
> + printf("RX negotiated: %s\nTX negotiated: %s\n",
> + rx_status ? "on" : "off", tx_status ? "on" : "off");
> + }
>
Why not use print_string here like show_bool did?
> return MNL_CB_OK;
> }
> @@ -121,21 +129,34 @@ int pause_reply_cb(const struct nlmsghdr *nlhdr, void *data)
> return err_ret;
>
> if (silent)
> - putchar('\n');
> - printf("Pause parameters for %s:\n", nlctx->devname);
> - show_bool(tb[ETHTOOL_A_PAUSE_AUTONEG], "Autonegotiate:\t");
> - show_bool(tb[ETHTOOL_A_PAUSE_RX], "RX:\t\t");
> - show_bool(tb[ETHTOOL_A_PAUSE_TX], "TX:\t\t");
> + print_nl();
> +
> + open_json_object(NULL);
> +
> + print_string(PRINT_ANY, "ifname", "Pause parameters for %s:\n",
> + nlctx->devname);
> +
Ah, nice, so this prints based on the current format and will just print
the ifname instead of showing the format string. Neat.
> + show_bool("autonegotiate", "Autonegotiate:\t%s\n",
> + tb[ETHTOOL_A_PAUSE_AUTONEG]);
> + show_bool("rx", "RX:\t\t%s\n", tb[ETHTOOL_A_PAUSE_RX]);
> + show_bool("tx", "TX:\t\t%s\n", tb[ETHTOOL_A_PAUSE_TX]);
> +
> if (!nlctx->is_monitor && tb[ETHTOOL_A_PAUSE_AUTONEG] &&
> mnl_attr_get_u8(tb[ETHTOOL_A_PAUSE_AUTONEG])) {
> ret = show_pause_autoneg_status(nlctx);
> if (ret < 0)
> - return err_ret;
> + goto err_close_dev;
> }
> if (!silent)
> - putchar('\n');
> + print_nl();
> +
> + close_json_object();
>
> return MNL_CB_OK;
> +
> +err_close_dev:
> + close_json_object();
> + return err_ret;
> }
>
> int nl_gpause(struct cmd_context *ctx)
> @@ -156,7 +177,11 @@ int nl_gpause(struct cmd_context *ctx)
> ETHTOOL_A_PAUSE_HEADER, 0);
> if (ret < 0)
> return ret;
> - return nlsock_send_get_request(nlsk, pause_reply_cb);
> +
> + new_json_obj(ctx->json);
> + ret = nlsock_send_get_request(nlsk, pause_reply_cb);
> + delete_json_obj();
> + return ret;
> }
>
> /* PAUSE_SET */
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH ethtool-next 3/5] separate FLAGS out in -h
2020-09-15 23:52 ` [PATCH ethtool-next 3/5] separate FLAGS out in -h Jakub Kicinski
@ 2020-09-24 0:12 ` Jacob Keller
0 siblings, 0 replies; 12+ messages in thread
From: Jacob Keller @ 2020-09-24 0:12 UTC (permalink / raw)
To: Jakub Kicinski, mkubecek; +Cc: netdev
On 9/15/2020 4:52 PM, Jakub Kicinski wrote:
> Help output is quite crowded already with every command
> being prefixed by --debug and --json options, and we're
> about to add a third one.
>
> Add an indirection.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Seems reasonable to me.
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
> ---
> ethtool.c | 9 ++++++---
> 1 file changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/ethtool.c b/ethtool.c
> index 23ecfcfd069c..ae5310e9e306 100644
> --- a/ethtool.c
> +++ b/ethtool.c
> @@ -5947,10 +5947,10 @@ static int show_usage(struct cmd_context *ctx __maybe_unused)
> fprintf(stdout, PACKAGE " version " VERSION "\n");
> fprintf(stdout,
> "Usage:\n"
> - " ethtool [ --debug MASK ][ --json ] DEVNAME\t"
> + " ethtool [ FLAGS ] DEVNAME\t"
> "Display standard information about device\n");
> for (i = 0; args[i].opts; i++) {
> - fputs(" ethtool [ --debug MASK ][ --json ] ", stdout);
> + fputs(" ethtool [ FLAGS ] ", stdout);
> fprintf(stdout, "%s %s\t%s\n",
> args[i].opts,
> args[i].no_dev ? "\t" : "DEVNAME",
> @@ -5959,7 +5959,10 @@ static int show_usage(struct cmd_context *ctx __maybe_unused)
> fputs(args[i].xhelp, stdout);
> }
> nl_monitor_usage();
> - fprintf(stdout, "Not all options support JSON output\n");
> + fprintf(stdout, "\n");
> + fprintf(stdout, "FLAGS:\n");
> + fprintf(stdout, " --debug MASK turn on debugging messages\n");
> + fprintf(stdout, " --json enable JSON output format (not supported by all commands)\n");
>
Not really related to this patch, but what is the behavior of a command
when --json is used but it doesn't support it?
Thanks,
Jake
> return 0;
> }
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH ethtool-next 2/5] pause: add --json support
2020-09-24 0:10 ` Jacob Keller
@ 2020-09-24 15:36 ` Jakub Kicinski
2020-09-24 20:41 ` Jacob Keller
0 siblings, 1 reply; 12+ messages in thread
From: Jakub Kicinski @ 2020-09-24 15:36 UTC (permalink / raw)
To: Jacob Keller; +Cc: mkubecek, netdev
On Wed, 23 Sep 2020 17:10:30 -0700 Jacob Keller wrote:
> > - printf("RX negotiated: %s\nTX negotiated: %s\n",
> > - rx_status ? "on" : "off", tx_status ? "on" : "off");
> > +
> > + if (is_json_context()) {
> > + open_json_object("negotiated");
> > + print_bool(PRINT_JSON, "rx", NULL, rx_status);
> > + print_bool(PRINT_JSON, "tx", NULL, tx_status);
> > + close_json_object();
> > + } else {
> > + printf("RX negotiated: %s\nTX negotiated: %s\n",
> > + rx_status ? "on" : "off", tx_status ? "on" : "off");
> > + }
>
> Why not use print_string here like show_bool did?
Yeah.. I did not come up with a good way of reusing the show_bool code
so I gave up. Taking another swing at it - how does this look?
diff --git a/netlink/coalesce.c b/netlink/coalesce.c
index 65f75cf9a8dd..07a92d04b7a1 100644
--- a/netlink/coalesce.c
+++ b/netlink/coalesce.c
@@ -36,9 +36,9 @@ int coalesce_reply_cb(const struct nlmsghdr *nlhdr, void *data)
if (silent)
putchar('\n');
printf("Coalesce parameters for %s:\n", nlctx->devname);
- printf("Adaptive RX: %s TX: %s\n",
- u8_to_bool(tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX]),
- u8_to_bool(tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX]));
+ show_bool("rx", "Adaptive RX: %s ",
+ tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX]);
+ show_bool("tx", "TX: %s\n", tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX]);
show_u32(tb[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS],
"stats-block-usecs: ");
show_u32(tb[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL],
diff --git a/netlink/netlink.h b/netlink/netlink.h
index 4916d25ed5c0..1012e8e32cd8 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -98,27 +98,30 @@ static inline void show_u32(const struct nlattr *attr, const char *label)
printf("%sn/a\n", label);
}
-static inline const char *u8_to_bool(const struct nlattr *attr)
+static inline const char *u8_to_bool(const uint8_t *val)
{
- if (attr)
- return mnl_attr_get_u8(attr) ? "on" : "off";
+ if (val)
+ return *val ? "on" : "off";
else
return "n/a";
}
-static inline void show_bool(const char *key, const char *fmt,
- const struct nlattr *attr)
+static inline void show_bool_val(const char *key, const char *fmt, uint8_t *val)
{
if (is_json_context()) {
- if (attr) {
- print_bool(PRINT_JSON, key, NULL,
- mnl_attr_get_u8(attr));
- }
+ if (val)
+ print_bool(PRINT_JSON, key, NULL, val);
} else {
- print_string(PRINT_FP, NULL, fmt, u8_to_bool(attr));
+ print_string(PRINT_FP, NULL, fmt, u8_to_bool(val));
}
}
+static inline void show_bool(const char *key, const char *fmt,
+ const struct nlattr *attr)
+{
+ show_bool_val(key, fmt, attr ? mnl_attr_get_payload(attr) : NULL);
+}
+
/* misc */
static inline void copy_devname(char *dst, const char *src)
diff --git a/netlink/pause.c b/netlink/pause.c
index f9dec9fe887a..5395398ba948 100644
--- a/netlink/pause.c
+++ b/netlink/pause.c
@@ -41,8 +41,8 @@ static int pause_autoneg_cb(const struct nlmsghdr *nlhdr, void *data)
struct pause_autoneg_status ours = {};
struct pause_autoneg_status peer = {};
struct nl_context *nlctx = data;
- bool rx_status = false;
- bool tx_status = false;
+ uint8_t rx_status = false;
+ uint8_t tx_status = false;
bool silent;
int err_ret;
int ret;
@@ -74,15 +74,10 @@ static int pause_autoneg_cb(const struct nlmsghdr *nlhdr, void *data)
tx_status = true;
}
- if (is_json_context()) {
- open_json_object("negotiated");
- print_bool(PRINT_JSON, "rx", NULL, rx_status);
- print_bool(PRINT_JSON, "tx", NULL, tx_status);
- close_json_object();
- } else {
- printf("RX negotiated: %s\nTX negotiated: %s\n",
- rx_status ? "on" : "off", tx_status ? "on" : "off");
- }
+ open_json_object("negotiated");
+ show_bool_val("rx", "RX negotiated: %s\n", &rx_status);
+ show_bool_val("tx", "TX negotiated: %s\n", &tx_status);
+ close_json_object();
return MNL_CB_OK;
}
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH ethtool-next 2/5] pause: add --json support
2020-09-24 15:36 ` Jakub Kicinski
@ 2020-09-24 20:41 ` Jacob Keller
0 siblings, 0 replies; 12+ messages in thread
From: Jacob Keller @ 2020-09-24 20:41 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: mkubecek, netdev
On 9/24/2020 8:36 AM, Jakub Kicinski wrote:
> On Wed, 23 Sep 2020 17:10:30 -0700 Jacob Keller wrote:
>>> - printf("RX negotiated: %s\nTX negotiated: %s\n",
>>> - rx_status ? "on" : "off", tx_status ? "on" : "off");
>>> +
>>> + if (is_json_context()) {
>>> + open_json_object("negotiated");
>>> + print_bool(PRINT_JSON, "rx", NULL, rx_status);
>>> + print_bool(PRINT_JSON, "tx", NULL, tx_status);
>>> + close_json_object();
>>> + } else {
>>> + printf("RX negotiated: %s\nTX negotiated: %s\n",
>>> + rx_status ? "on" : "off", tx_status ? "on" : "off");
>>> + }
>>
>> Why not use print_string here like show_bool did?
>
> Yeah.. I did not come up with a good way of reusing the show_bool code
> so I gave up. Taking another swing at it - how does this look?
>
> diff --git a/netlink/coalesce.c b/netlink/coalesce.c
> index 65f75cf9a8dd..07a92d04b7a1 100644
> --- a/netlink/coalesce.c
> +++ b/netlink/coalesce.c
> @@ -36,9 +36,9 @@ int coalesce_reply_cb(const struct nlmsghdr *nlhdr, void *data)
> if (silent)
> putchar('\n');
> printf("Coalesce parameters for %s:\n", nlctx->devname);
> - printf("Adaptive RX: %s TX: %s\n",
> - u8_to_bool(tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX]),
> - u8_to_bool(tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX]));
> + show_bool("rx", "Adaptive RX: %s ",
> + tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX]);
> + show_bool("tx", "TX: %s\n", tb[ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX]);
> show_u32(tb[ETHTOOL_A_COALESCE_STATS_BLOCK_USECS],
> "stats-block-usecs: ");
> show_u32(tb[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL],
> diff --git a/netlink/netlink.h b/netlink/netlink.h
> index 4916d25ed5c0..1012e8e32cd8 100644
> --- a/netlink/netlink.h
> +++ b/netlink/netlink.h
> @@ -98,27 +98,30 @@ static inline void show_u32(const struct nlattr *attr, const char *label)
> printf("%sn/a\n", label);
> }
>
> -static inline const char *u8_to_bool(const struct nlattr *attr)
> +static inline const char *u8_to_bool(const uint8_t *val)
> {
> - if (attr)
> - return mnl_attr_get_u8(attr) ? "on" : "off";
> + if (val)
> + return *val ? "on" : "off";
> else
> return "n/a";
> }
>
> -static inline void show_bool(const char *key, const char *fmt,
> - const struct nlattr *attr)
> +static inline void show_bool_val(const char *key, const char *fmt, uint8_t *val)
> {
> if (is_json_context()) {
> - if (attr) {
> - print_bool(PRINT_JSON, key, NULL,
> - mnl_attr_get_u8(attr));
> - }
> + if (val)
> + print_bool(PRINT_JSON, key, NULL, val);
> } else {
> - print_string(PRINT_FP, NULL, fmt, u8_to_bool(attr));
> + print_string(PRINT_FP, NULL, fmt, u8_to_bool(val));
> }
> }
>
> +static inline void show_bool(const char *key, const char *fmt,
> + const struct nlattr *attr)
> +{
> + show_bool_val(key, fmt, attr ? mnl_attr_get_payload(attr) : NULL);
> +}
> +
> /* misc */
>
> static inline void copy_devname(char *dst, const char *src)
> diff --git a/netlink/pause.c b/netlink/pause.c
> index f9dec9fe887a..5395398ba948 100644
> --- a/netlink/pause.c
> +++ b/netlink/pause.c
> @@ -41,8 +41,8 @@ static int pause_autoneg_cb(const struct nlmsghdr *nlhdr, void *data)
> struct pause_autoneg_status ours = {};
> struct pause_autoneg_status peer = {};
> struct nl_context *nlctx = data;
> - bool rx_status = false;
> - bool tx_status = false;
> + uint8_t rx_status = false;
> + uint8_t tx_status = false;
> bool silent;
> int err_ret;
> int ret;
> @@ -74,15 +74,10 @@ static int pause_autoneg_cb(const struct nlmsghdr *nlhdr, void *data)
> tx_status = true;
> }
>
> - if (is_json_context()) {
> - open_json_object("negotiated");
> - print_bool(PRINT_JSON, "rx", NULL, rx_status);
> - print_bool(PRINT_JSON, "tx", NULL, tx_status);
> - close_json_object();
> - } else {
> - printf("RX negotiated: %s\nTX negotiated: %s\n",
> - rx_status ? "on" : "off", tx_status ? "on" : "off");
> - }
> + open_json_object("negotiated");
> + show_bool_val("rx", "RX negotiated: %s\n", &rx_status);
> + show_bool_val("tx", "TX negotiated: %s\n", &tx_status);
> + close_json_object();
>
> return MNL_CB_OK;
> }
>
This looks good!
Thanks,
Jake
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2020-09-24 20:41 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-15 23:52 [PATCH ethtool-next 0/5] pause frame stats Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 1/5] update UAPI header copies Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 2/5] pause: add --json support Jakub Kicinski
2020-09-24 0:10 ` Jacob Keller
2020-09-24 15:36 ` Jakub Kicinski
2020-09-24 20:41 ` Jacob Keller
2020-09-15 23:52 ` [PATCH ethtool-next 3/5] separate FLAGS out in -h Jakub Kicinski
2020-09-24 0:12 ` Jacob Keller
2020-09-15 23:52 ` [PATCH ethtool-next 4/5] add support for stats in subcommands Jakub Kicinski
2020-09-15 23:52 ` [PATCH ethtool-next 5/5] pause: add support for dumping statistics Jakub Kicinski
2020-09-23 22:45 ` Michal Kubecek
2020-09-23 23:36 ` Jakub Kicinski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).