[RFC PATCH ethtool-next 0/2] ethtool: Add ability to write to transceiver module EEPROMs

STALE1872d

Revision rfc of 2 in this series.

3 messages, 1 author, 2021-06-23 · open the first message on its own page

[RFC PATCH ethtool-next 0/2] ethtool: Add ability to write to transceiver module EEPROMs

From: Ido Schimmel <hidden>
Date: 2021-06-23 08:08:59

From: Ido Schimmel <idosch@nvidia.com>

Patch #1 updates the UAPI headers.

Patch #2 adds the actual implementation. See the commit message for
example output.

Patches are on top of [1] which are currently under review.

Refer to [2] for more background information.

[1] https://patchwork.kernel.org/project/netdevbpf/cover/1623949504-51291-1-git-send-email-moshe@nvidia.com/
[2] https://patchwork.kernel.org/project/netdevbpf/cover/20210623075925.2610908-1-idosch@idosch.org/

Ido Schimmel (2):
  Update UAPI header copies
  ethtool: Add ability to write to transceiver module EEPROM

 ethtool.8.in                 |  29 ++++++++
 ethtool.c                    |  10 +++
 netlink/desc-ethtool.c       |   2 +
 netlink/extapi.h             |   2 +
 netlink/module-eeprom.c      | 125 ++++++++++++++++++++++++++++++++++-
 netlink/monitor.c            |   4 ++
 netlink/netlink.h            |   1 +
 uapi/linux/ethtool.h         |   4 +-
 uapi/linux/ethtool_netlink.h |   4 +-
 uapi/linux/if_link.h         |   9 +++
 uapi/linux/netlink.h         |   5 +-
 11 files changed, 188 insertions(+), 7 deletions(-)

-- 
2.31.1

[RFC PATCH ethtool-next 1/2] Update UAPI header copies

From: Ido Schimmel <hidden>
Date: 2021-06-23 08:09:02

From: Ido Schimmel <idosch@nvidia.com>

Update to kernel commit XXX.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 uapi/linux/ethtool.h         | 4 ++--
 uapi/linux/ethtool_netlink.h | 4 +++-
 uapi/linux/if_link.h         | 9 +++++++++
 uapi/linux/netlink.h         | 5 +++--
 4 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/uapi/linux/ethtool.h b/uapi/linux/ethtool.h
index c6ec1111ffa3..f40b00d94276 100644
--- a/uapi/linux/ethtool.h
+++ b/uapi/linux/ethtool.h
@@ -231,7 +231,7 @@ enum tunable_id {
 	ETHTOOL_PFC_PREVENTION_TOUT, /* timeout in msecs */
 	/*
 	 * Add your fresh new tunable attribute above and remember to update
-	 * tunable_strings[] in net/core/ethtool.c
+	 * tunable_strings[] in net/ethtool/common.c
 	 */
 	__ETHTOOL_TUNABLE_COUNT,
 };
@@ -295,7 +295,7 @@ enum phy_tunable_id {
 	ETHTOOL_PHY_EDPD,
 	/*
 	 * Add your fresh new phy tunable attribute above and remember to update
-	 * phy_tunable_strings[] in net/core/ethtool.c
+	 * phy_tunable_strings[] in net/ethtool/common.c
 	 */
 	__ETHTOOL_PHY_TUNABLE_COUNT,
 };
diff --git a/uapi/linux/ethtool_netlink.h b/uapi/linux/ethtool_netlink.h
index 4653c4c79972..35737343b8ca 100644
--- a/uapi/linux/ethtool_netlink.h
+++ b/uapi/linux/ethtool_netlink.h
@@ -46,6 +46,7 @@ enum {
 	ETHTOOL_MSG_FEC_SET,
 	ETHTOOL_MSG_MODULE_EEPROM_GET,
 	ETHTOOL_MSG_STATS_GET,
+	ETHTOOL_MSG_MODULE_EEPROM_SET,
 
 	/* add new constants above here */
 	__ETHTOOL_MSG_USER_CNT,
@@ -88,6 +89,7 @@ enum {
 	ETHTOOL_MSG_FEC_NTF,
 	ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY,
 	ETHTOOL_MSG_STATS_GET_REPLY,
+	ETHTOOL_MSG_MODULE_EEPROM_NTF,
 
 	/* add new constants above here */
 	__ETHTOOL_MSG_KERNEL_CNT,
@@ -675,7 +677,7 @@ enum {
 	ETHTOOL_A_MODULE_EEPROM_PAGE,			/* u8 */
 	ETHTOOL_A_MODULE_EEPROM_BANK,			/* u8 */
 	ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS,		/* u8 */
-	ETHTOOL_A_MODULE_EEPROM_DATA,			/* nested */
+	ETHTOOL_A_MODULE_EEPROM_DATA,			/* binary */
 
 	__ETHTOOL_A_MODULE_EEPROM_CNT,
 	ETHTOOL_A_MODULE_EEPROM_MAX = (__ETHTOOL_A_MODULE_EEPROM_CNT - 1)
diff --git a/uapi/linux/if_link.h b/uapi/linux/if_link.h
index 0e81707a9637..5195ed93eff4 100644
--- a/uapi/linux/if_link.h
+++ b/uapi/linux/if_link.h
@@ -341,6 +341,13 @@ enum {
 	IFLA_ALT_IFNAME, /* Alternative ifname */
 	IFLA_PERM_ADDRESS,
 	IFLA_PROTO_DOWN_REASON,
+
+	/* device (sysfs) name as parent, used instead
+	 * of IFLA_LINK where there's no parent netdev
+	 */
+	IFLA_PARENT_DEV_NAME,
+	IFLA_PARENT_DEV_BUS_NAME,
+
 	__IFLA_MAX
 };
 
@@ -1234,6 +1241,8 @@ enum {
 #define RMNET_FLAGS_INGRESS_MAP_COMMANDS          (1U << 1)
 #define RMNET_FLAGS_INGRESS_MAP_CKSUMV4           (1U << 2)
 #define RMNET_FLAGS_EGRESS_MAP_CKSUMV4            (1U << 3)
+#define RMNET_FLAGS_INGRESS_MAP_CKSUMV5           (1U << 4)
+#define RMNET_FLAGS_EGRESS_MAP_CKSUMV5            (1U << 5)
 
 enum {
 	IFLA_RMNET_UNSPEC,
diff --git a/uapi/linux/netlink.h b/uapi/linux/netlink.h
index 5024c5435749..e83e2e300130 100644
--- a/uapi/linux/netlink.h
+++ b/uapi/linux/netlink.h
@@ -91,9 +91,10 @@ struct nlmsghdr {
 #define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
 #define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
 #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
-#define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_DATA(nlh)  ((void *)(((char *)nlh) + NLMSG_HDRLEN))
 #define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
-				  (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+				  (struct nlmsghdr *)(((char *)(nlh)) + \
+				  NLMSG_ALIGN((nlh)->nlmsg_len)))
 #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
 			   (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
 			   (nlh)->nlmsg_len <= (len))
-- 
2.31.1

[RFC PATCH ethtool-next 2/2] ethtool: Add ability to write to transceiver module EEPROM

From: Ido Schimmel <hidden>
Date: 2021-06-23 08:09:05

From: Ido Schimmel <idosch@nvidia.com>

Implement support for writing to a transceiver module EEPROM using the
'ETHTOOL_MSG_MODULE_EEPROM_SET' message. While the netlink API allows
for multi-byte writes, the command line interface is limited to
single-byte writes. Example:

 # ethtool -M swp11 offset 0x80 page 3 bank 0 i2c 0x50 value 0x44

This is in accordance with the '-E' option which allows changing a byte
in the EEPROM of a network device.

Upon a successful write, a 'ETHTOOL_MSG_MODULE_EEPROM_NTF' notification
is sent to user space. Example:

 # ethtool --monitor
 listening...

 Module EEPROM write for swp11:
 offset: 128
 length: 1
 page: 3
 bank: 0
 i2c address: 0x50

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 ethtool.8.in            |  29 ++++++++++
 ethtool.c               |  10 ++++
 netlink/desc-ethtool.c  |   2 +
 netlink/extapi.h        |   2 +
 netlink/module-eeprom.c | 125 +++++++++++++++++++++++++++++++++++++++-
 netlink/monitor.c       |   4 ++
 netlink/netlink.h       |   1 +
 7 files changed, 171 insertions(+), 2 deletions(-)
diff --git a/ethtool.8.in b/ethtool.8.in
index 115322a21932..4c77c4bcaefa 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -369,6 +369,14 @@ ethtool \- query or control network driver and hardware settings
 .BN bank
 .BN i2c
 .HP
+.B ethtool \-M|\-\-change\-module\-eeprom
+.I devname
+.BN offset \ N
+.BN page \ N
+.BN bank \ N
+.BN i2c \ N
+.BN value \ N
+.HP
 .B ethtool \-\-show\-priv\-flags
 .I devname
 .HP
@@ -1188,6 +1196,27 @@ and
 .I length
 parameters are treated relatively to EEPROM page boundaries.
 .TP
+.B \-M \-\-change\-module\-eeprom
+Changes a single byte in the module EEPROM at the specified address to a
+specific value.
+.RS 4
+.TP
+.BI offset \ N
+Specifies the offset within a page to write to.
+.TP
+.BI page \ N
+Specifies the page number to write to.
+.TP
+.BI bank \ N
+Specifies the bank number to write to. If not specified, kernel assumes bank 0.
+.TP
+.BI i2c \ N
+Specifies the I2C address of the page to write to.
+.TP
+.BI value \ N
+Specifies the value to write.
+.RE
+.TP
 .B \-\-show\-priv\-flags
 Queries the specified network device for its private flags.  The
 names and meanings of private flags (if any) are defined by each
diff --git a/ethtool.c b/ethtool.c
index 33a0a492cb15..601bb409d0ae 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5907,6 +5907,16 @@ static const struct option args[] = {
 			  "		[ bank N ]\n"
 			  "		[ i2c N ]\n"
 	},
+	{
+		.opts	= "-M|--change-module-eeprom",
+		.nlfunc = nl_setmodule,
+		.help	= "Change byte in device module EEPROM",
+		.xhelp	= "		[ offset N ]\n"
+			  "		[ page N ]\n"
+			  "		[ bank N ]\n"
+			  "		[ i2c N ]\n"
+			  "		[ value N ]\n"
+	},
 	{
 		.opts	= "--show-eee",
 		.func	= do_geee,
diff --git a/netlink/desc-ethtool.c b/netlink/desc-ethtool.c
index d6fc4e2d03df..4b86cd849f7d 100644
--- a/netlink/desc-ethtool.c
+++ b/netlink/desc-ethtool.c
@@ -408,6 +408,7 @@ const struct pretty_nlmsg_desc ethnl_umsg_desc[] = {
 	NLMSG_DESC(ETHTOOL_MSG_FEC_SET, fec),
 	NLMSG_DESC(ETHTOOL_MSG_STATS_GET, stats),
 	NLMSG_DESC(ETHTOOL_MSG_MODULE_EEPROM_GET, module_eeprom),
+	NLMSG_DESC(ETHTOOL_MSG_MODULE_EEPROM_SET, module_eeprom),
 };
 
 const unsigned int ethnl_umsg_n_desc = ARRAY_SIZE(ethnl_umsg_desc);
@@ -447,6 +448,7 @@ const struct pretty_nlmsg_desc ethnl_kmsg_desc[] = {
 	NLMSG_DESC(ETHTOOL_MSG_FEC_NTF, fec),
 	NLMSG_DESC(ETHTOOL_MSG_STATS_GET_REPLY, stats),
 	NLMSG_DESC(ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY, module_eeprom),
+	NLMSG_DESC(ETHTOOL_MSG_MODULE_EEPROM_NTF, module_eeprom),
 };
 
 const unsigned int ethnl_kmsg_n_desc = ARRAY_SIZE(ethnl_kmsg_desc);
diff --git a/netlink/extapi.h b/netlink/extapi.h
index 91bf02b5e3be..0579c2abdb5d 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -45,6 +45,7 @@ bool nl_gstats_chk(struct cmd_context *ctx);
 int nl_gstats(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
 int nl_getmodule(struct cmd_context *ctx);
+int nl_setmodule(struct cmd_context *ctx);
 
 void nl_monitor_usage(void);
 
@@ -99,6 +100,7 @@ static inline void nl_monitor_usage(void)
 #define nl_gstats_chk		NULL
 #define nl_gstats		NULL
 #define nl_getmodule		NULL
+#define nl_setmodule		NULL
 
 #endif /* ETHTOOL_ENABLE_NETLINK */
 
diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c
index 355d1de047a8..5ce74e6b7731 100644
--- a/netlink/module-eeprom.c
+++ b/netlink/module-eeprom.c
@@ -1,7 +1,7 @@
 /*
- * module-eeprom.c - netlink implementation of module eeprom get command
+ * module-eeprom.c - netlink implementation of module eeprom commands
  *
- * ethtool -m <dev>
+ * Implementation of "ethtool -m <dev>" and "ethtool -M <dev> ..."
  */
 
 #include <errno.h>
@@ -18,6 +18,8 @@
 #include "netlink.h"
 #include "parser.h"
 
+/* MODULE_EEPROM_GET */
+
 #define ETH_I2C_ADDRESS_LOW	0x50
 #define ETH_I2C_ADDRESS_HIGH	0x51
 #define ETH_I2C_MAX_ADDRESS	0x7F
@@ -340,6 +342,43 @@ static void decoder_print(void)
 	}
 }
 
+int module_eeprom_ntf_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+	const struct nlattr *tb[ETHTOOL_A_MODULE_EEPROM_MAX + 1] = {};
+	DECLARE_ATTR_TB_INFO(tb);
+	struct nl_context *nlctx = data;
+	bool silent;
+	int err_ret;
+	int ret;
+
+	silent = nlctx->is_dump || nlctx->is_monitor;
+	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;
+	if (!tb[ETHTOOL_A_MODULE_EEPROM_OFFSET] ||
+	    !tb[ETHTOOL_A_MODULE_EEPROM_LENGTH] ||
+	    !tb[ETHTOOL_A_MODULE_EEPROM_PAGE] ||
+	    !tb[ETHTOOL_A_MODULE_EEPROM_BANK] ||
+	    !tb[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS])
+		return err_ret;
+	nlctx->devname = get_dev_name(tb[ETHTOOL_A_FEC_HEADER]);
+	if (!dev_ok(nlctx))
+		return err_ret;
+
+	if (silent)
+		putchar('\n');
+	printf("Module EEPROM write for %s:\n", nlctx->devname);
+	show_u32(tb[ETHTOOL_A_MODULE_EEPROM_OFFSET], "offset: ");
+	show_u32(tb[ETHTOOL_A_MODULE_EEPROM_LENGTH], "length: ");
+	printf("page: %u\n", mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_PAGE]));
+	printf("bank: %u\n", mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_BANK]));
+	printf("i2c address: 0x%x\n",
+	       mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS]));
+
+	return MNL_CB_OK;
+}
+
 int nl_getmodule(struct cmd_context *ctx)
 {
 	struct ethtool_module_eeprom request = {0};
@@ -414,3 +453,85 @@ cleanup:
 	cache_free();
 	return ret;
 }
+
+/* MODULE_EEPROM_SET */
+
+static const struct param_parser setmodule_params[] = {
+	{
+		.arg		= "offset",
+		.type		= ETHTOOL_A_MODULE_EEPROM_OFFSET,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "page",
+		.type		= ETHTOOL_A_MODULE_EEPROM_PAGE,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "bank",
+		.type		= ETHTOOL_A_MODULE_EEPROM_BANK,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "i2c",
+		.type		= ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "value",
+		.type		= ETHTOOL_A_MODULE_EEPROM_DATA,
+		.handler	= nl_parse_direct_u8,
+		.min_argc	= 1,
+	},
+	{}
+};
+
+int nl_setmodule(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx = ctx->nlctx;
+	struct nl_msg_buff *msgbuff;
+	struct nl_socket *nlsk;
+	int ret;
+
+	if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_EEPROM_SET, false))
+		return -EOPNOTSUPP;
+	if (!ctx->argc) {
+		fprintf(stderr, "ethtool (-M): parameters missing\n");
+		return 1;
+	}
+
+	nlctx->cmd = "-M";
+	nlctx->argp = ctx->argp;
+	nlctx->argc = ctx->argc;
+	nlctx->devname = ctx->devname;
+	nlsk = nlctx->ethnl_socket;
+	msgbuff = &nlsk->msgbuff;
+
+	ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_MODULE_EEPROM_SET,
+		       NLM_F_REQUEST | NLM_F_ACK);
+	if (ret < 0)
+		return 2;
+	if (ethnla_fill_header(msgbuff, ETHTOOL_A_MODULE_EEPROM_HEADER,
+			       ctx->devname, 0))
+		return -EMSGSIZE;
+
+	ret = nl_parser(nlctx, setmodule_params, NULL, PARSER_GROUP_NONE, NULL);
+	if (ret < 0)
+		return 1;
+
+	if (ethnla_put_u32(msgbuff, ETHTOOL_A_MODULE_EEPROM_LENGTH, 1))
+		return -EMSGSIZE;
+
+	ret = nlsock_sendmsg(nlsk, NULL);
+	if (ret < 0)
+		return 83;
+	ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
+	if (ret == 0)
+		return 0;
+	else
+		return nlctx->exit_code ?: 83;
+}
diff --git a/netlink/monitor.c b/netlink/monitor.c
index 0c4df9e78ee3..ca4ebc7b0b9b 100644
--- a/netlink/monitor.c
+++ b/netlink/monitor.c
@@ -71,6 +71,10 @@ static struct {
 		.cmd	= ETHTOOL_MSG_FEC_NTF,
 		.cb	= fec_reply_cb,
 	},
+	{
+		.cmd	= ETHTOOL_MSG_MODULE_EEPROM_NTF,
+		.cb	= module_eeprom_ntf_cb,
+	},
 };
 
 static void clear_filter(struct nl_context *nlctx)
diff --git a/netlink/netlink.h b/netlink/netlink.h
index 70fa666b20e5..096a907c65c7 100644
--- a/netlink/netlink.h
+++ b/netlink/netlink.h
@@ -91,6 +91,7 @@ int cable_test_ntf_cb(const struct nlmsghdr *nlhdr, void *data);
 int cable_test_tdr_reply_cb(const struct nlmsghdr *nlhdr, void *data);
 int cable_test_tdr_ntf_cb(const struct nlmsghdr *nlhdr, void *data);
 int fec_reply_cb(const struct nlmsghdr *nlhdr, void *data);
+int module_eeprom_ntf_cb(const struct nlmsghdr *nlhdr, void *data);
 
 /* dump helpers */
 
-- 
2.31.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help