All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: mkubecek@suse.cz
Cc: netdev@vger.kernel.org, Jakub Kicinski <kuba@kernel.org>
Subject: [PATCH ethtool v2 2/2] tunnels: implement new --show-tunnels command
Date: Thu, 10 Sep 2020 12:09:15 -0700	[thread overview]
Message-ID: <20200910190915.564904-3-kuba@kernel.org> (raw)
In-Reply-To: <20200910190915.564904-1-kuba@kernel.org>

Add support for the new show-tunnels command. Support dump.

 # ethtool --show-tunnels \*
Tunnel information for eth0:
  UDP port table 0:
    Size: 4
    Types: vxlan
    No entries
  UDP port table 1:
    Size: 4
    Types: geneve, vxlan-gpe
    Entries (2):
        port 1230, vxlan-gpe
        port 6081, geneve

v2: htons -> ntohs

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 Makefile.am       |   2 +-
 ethtool.8.in      |   9 ++
 ethtool.c         |   5 +
 netlink/extapi.h  |   2 +
 netlink/tunnels.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 253 insertions(+), 1 deletion(-)
 create mode 100644 netlink/tunnels.c

diff --git a/Makefile.am b/Makefile.am
index aca0ad7bc773..0e237d070d4b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,7 +37,7 @@ ethtool_SOURCES += \
 		  netlink/channels.c netlink/coalesce.c netlink/pause.c \
 		  netlink/eee.c netlink/tsinfo.c \
 		  netlink/desc-ethtool.c netlink/desc-genlctrl.c \
-		  netlink/desc-rtnl.c netlink/cable_test.c \
+		  netlink/desc-rtnl.c netlink/cable_test.c netlink/tunnels.c \
 		  uapi/linux/ethtool_netlink.h \
 		  uapi/linux/netlink.h uapi/linux/genetlink.h \
 		  uapi/linux/rtnetlink.h uapi/linux/if_link.h
diff --git a/ethtool.8.in b/ethtool.8.in
index a50a4769895c..42c4767db33e 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -459,6 +459,9 @@ ethtool \- query or control network driver and hardware settings
 .BN last N
 .BN step N
 .BN pair N
+.HP
+.B ethtool \-\-show\-tunnels
+.I devname
 .
 .\" Adjust lines (i.e. full justification) and hyphenate.
 .ad
@@ -1383,6 +1386,12 @@ shown.
 If a device name is used as argument, only notification for this device are
 shown. Default is to show notifications for all devices.
 .RE
+.TP
+.B \-\-show\-tunnels
+Show tunnel-related device capabilities and state.
+List UDP ports kernel has programmed the device to parse as VxLAN,
+or GENEVE tunnels.
+.RE
 .SH BUGS
 Not supported (in part or whole) on all network drivers.
 .SH AUTHOR
diff --git a/ethtool.c b/ethtool.c
index 606af3e6b48f..23ecfcfd069c 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5919,6 +5919,11 @@ static const struct option args[] = {
 			  "		[ step N ]\n"
 			  "		[ pair N ]\n"
 	},
+	{
+		.opts	= "--show-tunnels",
+		.nlfunc	= nl_gtunnels,
+		.help	= "Show NIC tunnel offload information",
+	},
 	{
 		.opts	= "-h|--help",
 		.no_dev	= true,
diff --git a/netlink/extapi.h b/netlink/extapi.h
index a35d5f2c0b26..9285e2325dfd 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -37,6 +37,7 @@ int nl_seee(struct cmd_context *ctx);
 int nl_tsinfo(struct cmd_context *ctx);
 int nl_cable_test(struct cmd_context *ctx);
 int nl_cable_test_tdr(struct cmd_context *ctx);
+int nl_gtunnels(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
 
 void nl_monitor_usage(void);
@@ -84,6 +85,7 @@ static inline void nl_monitor_usage(void)
 #define nl_tsinfo		NULL
 #define nl_cable_test		NULL
 #define nl_cable_test_tdr	NULL
+#define nl_gtunnels		NULL
 
 #endif /* ETHTOOL_ENABLE_NETLINK */
 
diff --git a/netlink/tunnels.c b/netlink/tunnels.c
new file mode 100644
index 000000000000..b464046c021e
--- /dev/null
+++ b/netlink/tunnels.c
@@ -0,0 +1,236 @@
+/*
+ * tunnel.c - device tunnel information
+ *
+ * Implementation of "ethtool --show-tunnels <dev>"
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+
+#include "../common.h"
+#include "../internal.h"
+
+#include "bitset.h"
+#include "netlink.h"
+#include "strset.h"
+
+/* TUNNEL_INFO_GET */
+
+static int
+tunnel_info_strings_load(struct nl_context *nlctx,
+			 const struct stringset **strings)
+{
+	int ret;
+
+	if (*strings)
+		return 0;
+	ret = netlink_init_ethnl2_socket(nlctx);
+	if (ret < 0)
+		return ret;
+	*strings = global_stringset(ETH_SS_UDP_TUNNEL_TYPES,
+				    nlctx->ethnl2_socket);
+	return 0;
+}
+
+static int
+tunnel_info_dump_udp_entry(struct nl_context *nlctx, const struct nlattr *entry,
+			   const struct stringset **strings)
+{
+	const struct nlattr *entry_tb[ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(entry_tb);
+	const struct nlattr *attr;
+	unsigned int port, type;
+	int ret;
+
+	if (tunnel_info_strings_load(nlctx, strings))
+		return 1;
+
+	ret = mnl_attr_parse_nested(entry, attr_cb, &entry_tb_info);
+	if (ret < 0) {
+		fprintf(stderr, "malformed netlink message (udp entry)\n");
+		return 1;
+	}
+
+	attr = entry_tb[ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT];
+	if (!attr || mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
+		fprintf(stderr, "malformed netlink message (port)\n");
+		return 1;
+	}
+	port = ntohs(mnl_attr_get_u16(attr));
+
+	attr = entry_tb[ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE];
+	if (!attr || mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+		fprintf(stderr, "malformed netlink message (tunnel type)\n");
+		return 1;
+	}
+	type = mnl_attr_get_u32(attr);
+
+	printf("        port %d, %s\n", port, get_string(*strings, type));
+
+	return 0;
+}
+
+static void tunnel_info_dump_cb(unsigned int idx, const char *name, bool val,
+				void *data)
+{
+	bool *first = data;
+
+	if (!val)
+		return;
+
+	if (!*first)
+		putchar(',');
+	*first = false;
+
+	if (name)
+		printf(" %s", name);
+	else
+		printf(" bit%u", idx);
+}
+
+static int
+tunnel_info_dump_list(struct nl_context *nlctx, const struct nlattr *attr,
+		      const struct stringset **strings)
+{
+	bool first = true;
+	int ret;
+
+	if (bitset_is_empty(attr, false, &ret) || ret) {
+		if (ret)
+			return 1;
+
+		printf("    Types: none (static entries)\n");
+		return 0;
+	}
+
+	if (bitset_is_compact(attr) &&
+	    tunnel_info_strings_load(nlctx, strings))
+		return 1;
+
+	printf("    Types:");
+	ret = walk_bitset(attr, *strings, tunnel_info_dump_cb, &first);
+	putchar('\n');
+	return ret;
+}
+
+static int
+tunnel_info_dump_udp_table(const struct nlattr *table, struct nl_context *nlctx,
+			   const struct stringset **strings)
+{
+	const struct nlattr *table_tb[ETHTOOL_A_TUNNEL_UDP_TABLE_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(table_tb);
+	const struct nlattr *attr;
+	int i, ret;
+
+	ret = mnl_attr_parse_nested(table, attr_cb, &table_tb_info);
+	if (ret < 0) {
+		fprintf(stderr, "malformed netlink message (udp table)\n");
+		return 1;
+	}
+
+	attr = table_tb[ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE];
+	if (!attr || mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+		fprintf(stderr, "malformed netlink message (table size)\n");
+		return 1;
+	}
+	printf("    Size: %d\n", mnl_attr_get_u32(attr));
+
+	attr = table_tb[ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES];
+	if (!attr || tunnel_info_dump_list(nlctx, attr, strings)) {
+		fprintf(stderr, "malformed netlink message (types)\n");
+		return 1;
+	}
+
+	if (!table_tb[ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY]) {
+		printf("    No entries\n");
+		return 0;
+	}
+
+	i = 0;
+	mnl_attr_for_each_nested(attr, table) {
+		if (mnl_attr_get_type(attr) == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY)
+			i++;
+	}
+
+	printf("    Entries (%d):\n", i++);
+	mnl_attr_for_each_nested(attr, table) {
+		if (mnl_attr_get_type(attr) == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY)
+			if (tunnel_info_dump_udp_entry(nlctx, attr, strings))
+				return 1;
+	}
+
+	return 0;
+}
+
+static int
+tunnel_info_dump_udp(const struct nlattr *udp_ports, struct nl_context *nlctx)
+{
+	const struct stringset *strings = NULL;
+	const struct nlattr *table;
+	int i, err;
+
+	i = 0;
+	mnl_attr_for_each_nested(table, udp_ports) {
+		if (mnl_attr_get_type(table) != ETHTOOL_A_TUNNEL_UDP_TABLE)
+			continue;
+
+		printf("  UDP port table %d: \n", i++);
+		err = tunnel_info_dump_udp_table(table, nlctx, &strings);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tunnel_info_reply_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct nlattr *tb[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	const struct nlattr *udp_ports;
+	struct nl_context *nlctx = data;
+	bool silent;
+	int err_ret;
+	int ret;
+
+	silent = nlctx->is_dump;
+	err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
+	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
+	if (ret < 0)
+		return err_ret;
+	nlctx->devname = get_dev_name(tb[ETHTOOL_A_TUNNEL_INFO_HEADER]);
+	if (!dev_ok(nlctx))
+		return err_ret;
+
+	printf("Tunnel information for %s:\n", nlctx->devname);
+
+	udp_ports = tb[ETHTOOL_A_TUNNEL_INFO_UDP_PORTS];
+	if (udp_ports)
+		if (tunnel_info_dump_udp(udp_ports, nlctx))
+			return err_ret;
+
+	return MNL_CB_OK;
+}
+
+int nl_gtunnels(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx = ctx->nlctx;
+	struct nl_socket *nlsk = nlctx->ethnl_socket;
+	int ret;
+
+	if (netlink_cmd_check(ctx, ETHTOOL_MSG_TUNNEL_INFO_GET, true))
+		return -EOPNOTSUPP;
+	if (ctx->argc > 0) {
+		fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
+			*ctx->argp);
+		return 1;
+	}
+
+	ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_TUNNEL_INFO_GET,
+				      ETHTOOL_A_TUNNEL_INFO_HEADER, 0);
+	if (ret < 0)
+		return ret;
+	return nlsock_send_get_request(nlsk, tunnel_info_reply_cb);
+}
-- 
2.26.2


      parent reply	other threads:[~2020-09-10 19:10 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-10 19:09 [PATCH ethtool v2 0/2] support tunnel info dumping Jakub Kicinski
2020-09-10 19:09 ` [PATCH ethtool v2 1/2] update UAPI header copies Jakub Kicinski
2020-09-10 19:09 ` Jakub Kicinski [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200910190915.564904-3-kuba@kernel.org \
    --to=kuba@kernel.org \
    --cc=mkubecek@suse.cz \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.