netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH ethtool v3 0/7] pause frame stats
@ 2020-10-18 21:31 Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 1/7] update UAPI header copies Jakub Kicinski
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Jakub Kicinski @ 2020-10-18 21:31 UTC (permalink / raw)
  To: mkubecek; +Cc: netdev, kernel-team, idosch, Jakub Kicinski

Hi!

Sorry about the delay from v2.


This set adds support for pause frame statistics.

First pause frame info is extended to support --json.

Pause stats are first of this kind of statistics so add
support for a new flag (--include-statistics).

Next add support for dumping policy to check if the statistics
flag is supported for a given subcommand.

Last but not least - display statistics.

v3:
 - rename the ctx variable to policy_ctx
 - instead of returning the flags policy save it to a member
   of struct nl_context, for potential reuse. Also we don't
   have to worry about returning flags and negative errors
   from the read helper this way :)

Jakub Kicinski (7):
  update UAPI header copies
  pause: add --json support
  separate FLAGS out in -h
  add support for stats in subcommands
  netlink: prepare for more per-op info
  netlink: use policy dumping to check if stats flag is supported
  pause: add support for dumping statistics

 ethtool.8.in           |   7 ++
 ethtool.c              |  17 +++-
 internal.h             |   1 +
 netlink/coalesce.c     |   6 +-
 netlink/msgbuff.h      |   6 ++
 netlink/netlink.c      | 179 ++++++++++++++++++++++++++++++++++++++---
 netlink/netlink.h      |  31 +++++--
 netlink/pause.c        | 111 ++++++++++++++++++++++---
 uapi/linux/genetlink.h |  11 +++
 uapi/linux/netlink.h   |   4 +
 10 files changed, 336 insertions(+), 37 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH ethtool v3 1/7] update UAPI header copies
  2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
@ 2020-10-18 21:31 ` Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 2/7] pause: add --json support Jakub Kicinski
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Jakub Kicinski @ 2020-10-18 21:31 UTC (permalink / raw)
  To: mkubecek; +Cc: netdev, kernel-team, idosch, Jakub Kicinski

Update to kernel commit 9453b2d4694c.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 uapi/linux/genetlink.h | 11 +++++++++++
 uapi/linux/netlink.h   |  4 ++++
 2 files changed, 15 insertions(+)

diff --git a/uapi/linux/genetlink.h b/uapi/linux/genetlink.h
index 7c6c390c48ee..9fa720ee87ae 100644
--- a/uapi/linux/genetlink.h
+++ b/uapi/linux/genetlink.h
@@ -64,6 +64,8 @@ enum {
 	CTRL_ATTR_OPS,
 	CTRL_ATTR_MCAST_GROUPS,
 	CTRL_ATTR_POLICY,
+	CTRL_ATTR_OP_POLICY,
+	CTRL_ATTR_OP,
 	__CTRL_ATTR_MAX,
 };
 
@@ -85,6 +87,15 @@ enum {
 	__CTRL_ATTR_MCAST_GRP_MAX,
 };
 
+enum {
+	CTRL_ATTR_POLICY_UNSPEC,
+	CTRL_ATTR_POLICY_DO,
+	CTRL_ATTR_POLICY_DUMP,
+
+	__CTRL_ATTR_POLICY_DUMP_MAX,
+	CTRL_ATTR_POLICY_DUMP_MAX = __CTRL_ATTR_POLICY_DUMP_MAX - 1
+};
+
 #define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
 
 
diff --git a/uapi/linux/netlink.h b/uapi/linux/netlink.h
index 695c88e3c29d..dfef006be9f9 100644
--- a/uapi/linux/netlink.h
+++ b/uapi/linux/netlink.h
@@ -129,6 +129,7 @@ struct nlmsgerr {
  * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
  *	be used - in the success case - to identify a created
  *	object or operation or similar (binary)
+ * @NLMSGERR_ATTR_POLICY: policy for a rejected attribute
  * @__NLMSGERR_ATTR_MAX: number of attributes
  * @NLMSGERR_ATTR_MAX: highest attribute number
  */
@@ -137,6 +138,7 @@ enum nlmsgerr_attrs {
 	NLMSGERR_ATTR_MSG,
 	NLMSGERR_ATTR_OFFS,
 	NLMSGERR_ATTR_COOKIE,
+	NLMSGERR_ATTR_POLICY,
 
 	__NLMSGERR_ATTR_MAX,
 	NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
@@ -327,6 +329,7 @@ enum netlink_attribute_type {
  *	the index, if limited inside the nesting (U32)
  * @NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: valid mask for the
  *	bitfield32 type (U32)
+ * @NL_POLICY_TYPE_ATTR_MASK: mask of valid bits for unsigned integers (U64)
  * @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment
  */
 enum netlink_policy_type_attr {
@@ -342,6 +345,7 @@ enum netlink_policy_type_attr {
 	NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
 	NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
 	NL_POLICY_TYPE_ATTR_PAD,
+	NL_POLICY_TYPE_ATTR_MASK,
 
 	/* keep last */
 	__NL_POLICY_TYPE_ATTR_MAX,
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH ethtool v3 2/7] pause: add --json support
  2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 1/7] update UAPI header copies Jakub Kicinski
@ 2020-10-18 21:31 ` Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 3/7] separate FLAGS out in -h Jakub Kicinski
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Jakub Kicinski @ 2020-10-18 21:31 UTC (permalink / raw)
  To: mkubecek; +Cc: netdev, kernel-team, idosch, 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
        }
    } ]

v2:
 - restructure show_bool() so we can use its logic for show_bool_val()

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 netlink/coalesce.c |  6 +++---
 netlink/netlink.h  | 21 ++++++++++++++++-----
 netlink/pause.c    | 44 ++++++++++++++++++++++++++++++++------------
 3 files changed, 51 insertions(+), 20 deletions(-)

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 dd4a02bcc916..1012e8e32cd8 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -98,17 +98,28 @@ 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 struct nlattr *attr, const char *label)
+static inline void show_bool_val(const char *key, const char *fmt, uint8_t *val)
+{
+	if (is_json_context()) {
+		if (val)
+			print_bool(PRINT_JSON, key, NULL, val);
+	} else {
+		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)
 {
-	printf("%s%s\n", label, u8_to_bool(attr));
+	show_bool_val(key, fmt, attr ? mnl_attr_get_payload(attr) : NULL);
 }
 
 /* misc */
diff --git a/netlink/pause.c b/netlink/pause.c
index 7b6b3a1d2c10..c960c82cba5f 100644
--- a/netlink/pause.c
+++ b/netlink/pause.c
@@ -40,8 +40,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;
@@ -72,8 +72,11 @@ 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");
+
+	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;
 }
@@ -121,21 +124,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 +172,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] 9+ messages in thread

* [PATCH ethtool v3 3/7] separate FLAGS out in -h
  2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 1/7] update UAPI header copies Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 2/7] pause: add --json support Jakub Kicinski
@ 2020-10-18 21:31 ` Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 4/7] add support for stats in subcommands Jakub Kicinski
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Jakub Kicinski @ 2020-10-18 21:31 UTC (permalink / raw)
  To: mkubecek; +Cc: netdev, kernel-team, idosch, 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 2a7de97c51bb..403616bb7fa0 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -6015,10 +6015,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",
@@ -6027,7 +6027,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] 9+ messages in thread

* [PATCH ethtool v3 4/7] add support for stats in subcommands
  2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
                   ` (2 preceding siblings ...)
  2020-10-18 21:31 ` [PATCH ethtool v3 3/7] separate FLAGS out in -h Jakub Kicinski
@ 2020-10-18 21:31 ` Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 5/7] netlink: prepare for more per-op info Jakub Kicinski
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Jakub Kicinski @ 2020-10-18 21:31 UTC (permalink / raw)
  To: mkubecek; +Cc: netdev, kernel-team, idosch, 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 9beb1e5791eb..429c75f3f682 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 403616bb7fa0..1d9067e774af 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -6031,6 +6031,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;
 }
@@ -6291,6 +6292,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 935ebac3ca2e..27da8eac57bb 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] 9+ messages in thread

* [PATCH ethtool v3 5/7] netlink: prepare for more per-op info
  2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
                   ` (3 preceding siblings ...)
  2020-10-18 21:31 ` [PATCH ethtool v3 4/7] add support for stats in subcommands Jakub Kicinski
@ 2020-10-18 21:31 ` Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 6/7] netlink: use policy dumping to check if stats flag is supported Jakub Kicinski
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Jakub Kicinski @ 2020-10-18 21:31 UTC (permalink / raw)
  To: mkubecek; +Cc: netdev, kernel-team, idosch, Jakub Kicinski

We stored an array of op flags, to check if operations are
supported. Make that array a structure rather than plain
uint32_t in preparation for storing more state.

v3: new patch

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 netlink/netlink.c | 25 +++++++++++++------------
 netlink/netlink.h |  6 +++++-
 2 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/netlink/netlink.c b/netlink/netlink.c
index e42d57076a4b..86dc1efdf5ce 100644
--- a/netlink/netlink.c
+++ b/netlink/netlink.c
@@ -120,19 +120,19 @@ bool netlink_cmd_check(struct cmd_context *ctx, unsigned int cmd,
 		nlctx->wildcard_unsupported = true;
 		return true;
 	}
-	if (!nlctx->ops_flags) {
+	if (!nlctx->ops_info) {
 		nlctx->ioctl_fallback = true;
 		return false;
 	}
-	if (cmd > ETHTOOL_MSG_USER_MAX || !nlctx->ops_flags[cmd]) {
+	if (cmd > ETHTOOL_MSG_USER_MAX || !nlctx->ops_info[cmd].op_flags) {
 		nlctx->ioctl_fallback = true;
 		return true;
 	}
 
-	if (is_dump && !(nlctx->ops_flags[cmd] & GENL_CMD_CAP_DUMP))
+	if (is_dump && !(nlctx->ops_info[cmd].op_flags & GENL_CMD_CAP_DUMP))
 		nlctx->wildcard_unsupported = true;
 
-	return !(nlctx->ops_flags[cmd] & cap);
+	return !(nlctx->ops_info[cmd].op_flags & cap);
 }
 
 /* initialization */
@@ -140,12 +140,12 @@ bool netlink_cmd_check(struct cmd_context *ctx, unsigned int cmd,
 static int genl_read_ops(struct nl_context *nlctx,
 			 const struct nlattr *ops_attr)
 {
+	struct nl_op_info *ops_info;
 	struct nlattr *op_attr;
-	uint32_t *ops_flags;
 	int ret;
 
-	ops_flags = calloc(__ETHTOOL_MSG_USER_CNT, sizeof(ops_flags[0]));
-	if (!ops_flags)
+	ops_info = calloc(__ETHTOOL_MSG_USER_CNT, sizeof(ops_info[0]));
+	if (!ops_info)
 		return -ENOMEM;
 
 	mnl_attr_for_each_nested(op_attr, ops_attr) {
@@ -163,13 +163,14 @@ static int genl_read_ops(struct nl_context *nlctx,
 		if (op_id >= __ETHTOOL_MSG_USER_CNT)
 			continue;
 
-		ops_flags[op_id] = mnl_attr_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
+		ops_info[op_id].op_flags =
+			mnl_attr_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
 	}
 
-	nlctx->ops_flags = ops_flags;
+	nlctx->ops_info = ops_info;
 	return 0;
 err:
-	free(ops_flags);
+	free(ops_info);
 	return ret;
 }
 
@@ -273,7 +274,7 @@ int netlink_init(struct cmd_context *ctx)
 out_nlsk:
 	nlsock_done(nlctx->ethnl_socket);
 out_free:
-	free(nlctx->ops_flags);
+	free(nlctx->ops_info);
 	free(nlctx);
 	return ret;
 }
@@ -283,7 +284,7 @@ static void netlink_done(struct cmd_context *ctx)
 	if (!ctx->nlctx)
 		return;
 
-	free(ctx->nlctx->ops_flags);
+	free(ctx->nlctx->ops_info);
 	free(ctx->nlctx);
 	ctx->nlctx = NULL;
 	cleanup_all_strings();
diff --git a/netlink/netlink.h b/netlink/netlink.h
index 1012e8e32cd8..e79143016bd5 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -25,6 +25,10 @@ enum link_mode_class {
 	LM_CLASS_FEC,
 };
 
+struct nl_op_info {
+	uint32_t		op_flags;
+};
+
 struct nl_context {
 	struct cmd_context	*ctx;
 	void			*cmd_private;
@@ -34,7 +38,7 @@ struct nl_context {
 	unsigned int		suppress_nlerr;
 	uint16_t		ethnl_fam;
 	uint32_t		ethnl_mongrp;
-	uint32_t		*ops_flags;
+	struct nl_op_info	*ops_info;
 	struct nl_socket	*ethnl_socket;
 	struct nl_socket	*ethnl2_socket;
 	struct nl_socket	*rtnl_socket;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH ethtool v3 6/7] netlink: use policy dumping to check if stats flag is supported
  2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
                   ` (4 preceding siblings ...)
  2020-10-18 21:31 ` [PATCH ethtool v3 5/7] netlink: prepare for more per-op info Jakub Kicinski
@ 2020-10-18 21:31 ` Jakub Kicinski
  2020-10-18 21:31 ` [PATCH ethtool v3 7/7] pause: add support for dumping statistics Jakub Kicinski
  2020-10-19 11:11 ` [PATCH ethtool v3 0/7] pause frame stats Michal Kubecek
  7 siblings, 0 replies; 9+ messages in thread
From: Jakub Kicinski @ 2020-10-18 21:31 UTC (permalink / raw)
  To: mkubecek; +Cc: netdev, kernel-team, idosch, Jakub Kicinski

Older kernels don't support statistics, to avoid retries
make use of netlink policy dumps to figure out which
flags kernel actually supports.

v3:
 - s/ctx/policy_ctx/
 - save the flags in nl_context to be able to reuse them,
   and not have to return errors and values from the policy
   get function

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 netlink/msgbuff.h |   6 ++
 netlink/netlink.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++
 netlink/netlink.h |   4 ++
 3 files changed, 164 insertions(+)

diff --git a/netlink/msgbuff.h b/netlink/msgbuff.h
index 24b99c5a28d7..7d6731fc24a3 100644
--- a/netlink/msgbuff.h
+++ b/netlink/msgbuff.h
@@ -81,6 +81,12 @@ static inline bool ethnla_put_u32(struct nl_msg_buff *msgbuff, uint16_t type,
 	return ethnla_put(msgbuff, type, sizeof(uint32_t), &data);
 }
 
+static inline bool ethnla_put_u16(struct nl_msg_buff *msgbuff, uint16_t type,
+				  uint16_t data)
+{
+	return ethnla_put(msgbuff, type, sizeof(uint16_t), &data);
+}
+
 static inline bool ethnla_put_u8(struct nl_msg_buff *msgbuff, uint16_t type,
 				 uint8_t data)
 {
diff --git a/netlink/netlink.c b/netlink/netlink.c
index 86dc1efdf5ce..f655f6ea25b7 100644
--- a/netlink/netlink.c
+++ b/netlink/netlink.c
@@ -135,6 +135,160 @@ bool netlink_cmd_check(struct cmd_context *ctx, unsigned int cmd,
 	return !(nlctx->ops_info[cmd].op_flags & cap);
 }
 
+struct ethtool_op_policy_query_ctx {
+	struct nl_context *nlctx;
+	unsigned int op;
+	unsigned int op_hdr_attr;
+
+	bool op_policy_found;
+	bool hdr_policy_found;
+	unsigned int op_policy_idx;
+	unsigned int hdr_policy_idx;
+	uint64_t flag_mask;
+};
+
+static int family_policy_find_op(struct ethtool_op_policy_query_ctx *policy_ctx,
+				 const struct nlattr *op_policy)
+{
+	const struct nlattr *attr;
+	unsigned int type;
+	int ret;
+
+	type = policy_ctx->nlctx->is_dump ?
+		CTRL_ATTR_POLICY_DUMP : CTRL_ATTR_POLICY_DO;
+
+	mnl_attr_for_each_nested(attr, op_policy) {
+		const struct nlattr *tb[CTRL_ATTR_POLICY_DUMP_MAX + 1] = {};
+		DECLARE_ATTR_TB_INFO(tb);
+
+		if (mnl_attr_get_type(attr) != policy_ctx->op)
+			continue;
+
+		ret = mnl_attr_parse_nested(attr, attr_cb, &tb_info);
+		if (ret < 0)
+			return ret;
+
+		if (!tb[type])
+			continue;
+
+		policy_ctx->op_policy_found = true;
+		policy_ctx->op_policy_idx = mnl_attr_get_u32(tb[type]);
+		break;
+	}
+
+	return 0;
+}
+
+static int family_policy_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct nlattr *tba[NL_POLICY_TYPE_ATTR_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tba);
+	const struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	struct ethtool_op_policy_query_ctx *policy_ctx = data;
+	const struct nlattr *policy_attr, *attr_attr, *attr;
+	unsigned int attr_idx, policy_idx;
+	int ret;
+
+	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
+	if (ret < 0)
+		return MNL_CB_ERROR;
+
+	if (!policy_ctx->op_policy_found) {
+		if (!tb[CTRL_ATTR_OP_POLICY]) {
+			fprintf(stderr, "Error: op policy map not present\n");
+			return MNL_CB_ERROR;
+		}
+		ret = family_policy_find_op(policy_ctx, tb[CTRL_ATTR_OP_POLICY]);
+		return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK;
+	}
+
+	if (!tb[CTRL_ATTR_POLICY])
+		return MNL_CB_OK;
+
+	policy_attr = mnl_attr_get_payload(tb[CTRL_ATTR_POLICY]);
+	policy_idx = mnl_attr_get_type(policy_attr);
+	attr_attr = mnl_attr_get_payload(policy_attr);
+	attr_idx = mnl_attr_get_type(attr_attr);
+
+	ret = mnl_attr_parse_nested(attr_attr, attr_cb, &tba_info);
+	if (ret < 0)
+		return MNL_CB_ERROR;
+
+	if (policy_idx == policy_ctx->op_policy_idx &&
+	    attr_idx == policy_ctx->op_hdr_attr) {
+		attr = tba[NL_POLICY_TYPE_ATTR_POLICY_IDX];
+		if (!attr) {
+			fprintf(stderr,	"Error: no policy index in what was expected to be ethtool header attribute\n");
+			return MNL_CB_ERROR;
+		}
+		policy_ctx->hdr_policy_found = true;
+		policy_ctx->hdr_policy_idx = mnl_attr_get_u32(attr);
+	}
+
+	if (policy_ctx->hdr_policy_found &&
+	    policy_ctx->hdr_policy_idx == policy_idx &&
+	    attr_idx == ETHTOOL_A_HEADER_FLAGS) {
+		attr = tba[NL_POLICY_TYPE_ATTR_MASK];
+		if (!attr) {
+			fprintf(stderr,	"Error: validation mask not reported for ethtool header flags\n");
+			return MNL_CB_ERROR;
+		}
+
+		policy_ctx->flag_mask = mnl_attr_get_u64(attr);
+	}
+
+	return MNL_CB_OK;
+}
+
+static int read_flags_policy(struct nl_context *nlctx, struct nl_socket *nlsk,
+			     unsigned int nlcmd, unsigned int hdrattr)
+{
+	struct ethtool_op_policy_query_ctx policy_ctx;
+	struct nl_msg_buff *msgbuff = &nlsk->msgbuff;
+	int ret;
+
+	if (nlctx->ops_info[nlcmd].hdr_policy_loaded)
+		return 0;
+
+	memset(&policy_ctx, 0, sizeof(policy_ctx));
+	policy_ctx.nlctx = nlctx;
+	policy_ctx.op = nlcmd;
+	policy_ctx.op_hdr_attr = hdrattr;
+
+	ret = __msg_init(msgbuff, GENL_ID_CTRL, CTRL_CMD_GETPOLICY,
+			 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, 1);
+	if (ret < 0)
+		return ret;
+	ret = -EMSGSIZE;
+	if (ethnla_put_u16(msgbuff, CTRL_ATTR_FAMILY_ID, nlctx->ethnl_fam))
+		return ret;
+	if (ethnla_put_u32(msgbuff, CTRL_ATTR_OP, nlcmd))
+		return ret;
+
+	nlsock_sendmsg(nlsk, NULL);
+	nlsock_process_reply(nlsk, family_policy_cb, &policy_ctx);
+
+	nlctx->ops_info[nlcmd].hdr_policy_loaded = 1;
+	nlctx->ops_info[nlcmd].hdr_flags = policy_ctx.flag_mask;
+	return 0;
+}
+
+u32 get_stats_flag(struct nl_context *nlctx, unsigned int nlcmd,
+		   unsigned int hdrattr)
+{
+	if (!nlctx->ctx->show_stats)
+		return 0;
+	if (nlcmd > ETHTOOL_MSG_USER_MAX ||
+	    !(nlctx->ops_info[nlcmd].op_flags & GENL_CMD_CAP_HASPOL))
+		return 0;
+
+	if (read_flags_policy(nlctx, nlctx->ethnl_socket, nlcmd, hdrattr) < 0)
+		return 0;
+
+	return nlctx->ops_info[nlcmd].hdr_flags & ETHTOOL_FLAG_STATS;
+}
+
 /* initialization */
 
 static int genl_read_ops(struct nl_context *nlctx,
diff --git a/netlink/netlink.h b/netlink/netlink.h
index e79143016bd5..c02558540218 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -27,6 +27,8 @@ enum link_mode_class {
 
 struct nl_op_info {
 	uint32_t		op_flags;
+	uint32_t		hdr_flags;
+	uint8_t			hdr_policy_loaded:1;
 };
 
 struct nl_context {
@@ -70,6 +72,8 @@ bool netlink_cmd_check(struct cmd_context *ctx, unsigned int cmd,
 		       bool allow_wildcard);
 const char *get_dev_name(const struct nlattr *nest);
 int get_dev_info(const struct nlattr *nest, int *ifindex, char *ifname);
+u32 get_stats_flag(struct nl_context *nlctx, unsigned int nlcmd,
+		   unsigned int hdrattr);
 
 int linkmodes_reply_cb(const struct nlmsghdr *nlhdr, void *data);
 int linkinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH ethtool v3 7/7] pause: add support for dumping statistics
  2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
                   ` (5 preceding siblings ...)
  2020-10-18 21:31 ` [PATCH ethtool v3 6/7] netlink: use policy dumping to check if stats flag is supported Jakub Kicinski
@ 2020-10-18 21:31 ` Jakub Kicinski
  2020-10-19 11:11 ` [PATCH ethtool v3 0/7] pause frame stats Michal Kubecek
  7 siblings, 0 replies; 9+ messages in thread
From: Jakub Kicinski @ 2020-10-18 21:31 UTC (permalink / raw)
  To: mkubecek; +Cc: netdev, kernel-team, idosch, 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
        }
    } ]

v2: - correct print format for u64

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 netlink/pause.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 66 insertions(+), 1 deletion(-)

diff --git a/netlink/pause.c b/netlink/pause.c
index c960c82cba5f..9bc9a301821f 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>
 
@@ -105,6 +106,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: %%" PRIu64 "\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] = {};
@@ -142,6 +199,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();
 
@@ -158,6 +220,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))
@@ -168,8 +231,10 @@ int nl_gpause(struct cmd_context *ctx)
 		return 1;
 	}
 
+	flags = get_stats_flag(nlctx, ETHTOOL_MSG_PAUSE_GET,
+			       ETHTOOL_A_PAUSE_HEADER);
 	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] 9+ messages in thread

* Re: [PATCH ethtool v3 0/7] pause frame stats
  2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
                   ` (6 preceding siblings ...)
  2020-10-18 21:31 ` [PATCH ethtool v3 7/7] pause: add support for dumping statistics Jakub Kicinski
@ 2020-10-19 11:11 ` Michal Kubecek
  7 siblings, 0 replies; 9+ messages in thread
From: Michal Kubecek @ 2020-10-19 11:11 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: netdev, kernel-team, idosch

[-- Attachment #1: Type: text/plain, Size: 1734 bytes --]

On Sun, Oct 18, 2020 at 02:31:44PM -0700, Jakub Kicinski wrote:
> Hi!
> 
> Sorry about the delay from v2.

Actually, I'm rather surprised you were able to get back to this so
early, given the situation.

> This set adds support for pause frame statistics.
> 
> First pause frame info is extended to support --json.
> 
> Pause stats are first of this kind of statistics so add
> support for a new flag (--include-statistics).
> 
> Next add support for dumping policy to check if the statistics
> flag is supported for a given subcommand.
> 
> Last but not least - display statistics.
> 
> v3:
>  - rename the ctx variable to policy_ctx
>  - instead of returning the flags policy save it to a member
>    of struct nl_context, for potential reuse. Also we don't
>    have to worry about returning flags and negative errors
>    from the read helper this way :)
> 
> Jakub Kicinski (7):
>   update UAPI header copies
>   pause: add --json support
>   separate FLAGS out in -h
>   add support for stats in subcommands
>   netlink: prepare for more per-op info
>   netlink: use policy dumping to check if stats flag is supported
>   pause: add support for dumping statistics
> 
>  ethtool.8.in           |   7 ++
>  ethtool.c              |  17 +++-
>  internal.h             |   1 +
>  netlink/coalesce.c     |   6 +-
>  netlink/msgbuff.h      |   6 ++
>  netlink/netlink.c      | 179 ++++++++++++++++++++++++++++++++++++++---
>  netlink/netlink.h      |  31 +++++--
>  netlink/pause.c        | 111 ++++++++++++++++++++++---
>  uapi/linux/genetlink.h |  11 +++
>  uapi/linux/netlink.h   |   4 +
>  10 files changed, 336 insertions(+), 37 deletions(-)

Series applied, thank you.

Michal

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2020-10-19 11:11 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-18 21:31 [PATCH ethtool v3 0/7] pause frame stats Jakub Kicinski
2020-10-18 21:31 ` [PATCH ethtool v3 1/7] update UAPI header copies Jakub Kicinski
2020-10-18 21:31 ` [PATCH ethtool v3 2/7] pause: add --json support Jakub Kicinski
2020-10-18 21:31 ` [PATCH ethtool v3 3/7] separate FLAGS out in -h Jakub Kicinski
2020-10-18 21:31 ` [PATCH ethtool v3 4/7] add support for stats in subcommands Jakub Kicinski
2020-10-18 21:31 ` [PATCH ethtool v3 5/7] netlink: prepare for more per-op info Jakub Kicinski
2020-10-18 21:31 ` [PATCH ethtool v3 6/7] netlink: use policy dumping to check if stats flag is supported Jakub Kicinski
2020-10-18 21:31 ` [PATCH ethtool v3 7/7] pause: add support for dumping statistics Jakub Kicinski
2020-10-19 11:11 ` [PATCH ethtool v3 0/7] pause frame stats Michal Kubecek

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).