All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Kubecek <mkubecek@suse.cz>
To: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Jiri Pirko <jiri@resnulli.us>,
	David Miller <davem@davemloft.net>,
	Florian Fainelli <f.fainelli@gmail.com>,
	Roopa Prabhu <roopa@cumulusnetworks.com>,
	Jakub Kicinski <kubakici@wp.pl>,
	"John W. Linville" <linville@tuxdriver.com>
Subject: [RFC PATCH net-next v2 15/17] ethtool: implement GET_PARAMS message
Date: Mon, 30 Jul 2018 14:53:57 +0200 (CEST)	[thread overview]
Message-ID: <3a9f1d3161fe7a435b01f165de762b3a362c3572.1532953989.git.mkubecek@suse.cz> (raw)
In-Reply-To: <cover.1532953989.git.mkubecek@suse.cz>

Requests the information provide by ETHTOOL_GCOALESCE, ETHTOOL_GRINGPARAM,
ETHTOOL_GPAUSEPARAM, ETHTOOL_GCHANNELS, ETHTOOL_GEEE and ETHTOOL_GFECPARAM.
Flags in info_mask allow selecting only some (or on) of these categories.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 Documentation/networking/ethtool-netlink.txt | 107 +++-
 include/uapi/linux/ethtool_netlink.h         | 119 ++++
 net/ethtool/Makefile                         |   2 +-
 net/ethtool/netlink.c                        |  10 +
 net/ethtool/params.c                         | 539 +++++++++++++++++++
 5 files changed, 770 insertions(+), 7 deletions(-)
 create mode 100644 net/ethtool/params.c

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 307d8c6c6c85..630eebd7e741 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -125,6 +125,8 @@ List of message types
     ETHNL_CMD_SET_DRVINFO		response only
     ETHNL_CMD_GET_SETTINGS
     ETHNL_CMD_SET_SETTINGS
+    ETHNL_CMD_GET_PARAMS
+    ETHNL_CMD_SET_PARAMS		response only (for now)
 
 All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
 to indicate the type.
@@ -314,6 +316,99 @@ the operation); mask shows bits which have been changed and value their new
 values.
 
 
+GET_PARAMS
+----------
+
+GET_PARAMS request retrieves information provided by legacy comands
+ETHTOOL_GCOALESCE (coalescing setting), ETHTOOL_GRINGPARAM (ring parameters),
+ETHTOOL_GPAUSEPARAM (pause parameters), ETHTOOL_GCHANNELS (channel settings),
+ETHTOOL_GEEE (EEE settings) and ETHTOOL_GFECPARAM (FEC parameters). For each
+of these, there is a bit in header info_mask so that only one type of
+information can be requested.
+
+Request contents:
+
+    ETHA_PARAMS_DEV		(nested)	device identification
+    ETHA_PARAMS_INFOMASK	(u32)		info mask
+    ETHA_PARAMS_COMPACT		(flag)		request compact bitsets
+
+Info mask bits:
+
+    ETH_PARAMS_IM_COALESCE		coalescing settings
+    ETH_PARAMS_IM_RING			ring parameters
+    ETH_PARAMS_IM_PAUSE			pause parameters
+    ETH_PARAMS_IM_CHANNELS		channel settings
+    ETH_PARAMS_IM_EEE			EEE settings
+    ETH_PARAMS_IM_FEC			FEC parameters
+
+Response contents: On top level, there is one attribute for each of the
+information categories, the information is nested in it.
+
+    ETHA_PARAMS_DEV		(nested)	device identification
+    ETHA_PARAMS_COALESCE	(nested)	coalescing
+        ETHA_COALESCE_RX_USECS			(u32)
+        ETHA_COALESCE_RX_MAXFRM			(u32)
+        ETHA_COALESCE_RX_USECS_IRQ		(u32)
+        ETHA_COALESCE_RX_MAXFRM_IRQ		(u32)
+        ETHA_COALESCE_RX_USECS_LOW		(u32)
+        ETHA_COALESCE_RX_MAXFRM_LOW		(u32)
+        ETHA_COALESCE_RX_USECS_HIGH		(u32)
+        ETHA_COALESCE_RX_MAXFRM_HIGH		(u32)
+        ETHA_COALESCE_TX_USECS			(u32)
+        ETHA_COALESCE_TX_MAXFRM			(u32)
+        ETHA_COALESCE_TX_USECS_IRQ		(u32)
+        ETHA_COALESCE_TX_MAXFRM_IRQ		(u32)
+        ETHA_COALESCE_TX_USECS_LOW		(u32)
+        ETHA_COALESCE_TX_MAXFRM_LOW		(u32)
+        ETHA_COALESCE_TX_USECS_HIGH		(u32)
+        ETHA_COALESCE_TX_MAXFRM_HIGH		(u32)
+        ETHA_COALESCE_PKT_RATE_LOW		(u32)
+        ETHA_COALESCE_PKT_RATE_HIGH		(u32)
+        ETHA_COALESCE_RX_USE_ADAPTIVE		(bool)
+        ETHA_COALESCE_TX_USE_ADAPTIVE		(bool)
+        ETHA_COALESCE_RATE_SAMPLE_INTERVAL	(u32)
+        ETHA_COALESCE_STATS_BLOCK_USECS		(u32)
+    ETHA_PARAMS_RING		(nested)	ring parameters
+        ETHA_RING_RX_MAX_PENDING		(u32)
+        ETHA_RING_RX_MINI_MAX_PENDING		(u32)
+        ETHA_RING_RX_JUMBO_MAX_PENDING		(u32)
+        ETHA_RING_TX_MAX_PENDING		(u32)
+        ETHA_RING_RX_PENDING			(u32)
+        ETHA_RING_RX_MINI_PENDING		(u32)
+        ETHA_RING_RX_JUMBO_PENDING		(u32)
+        ETHA_RING_TX_PENDING			(u32)
+    ETHA_PARAMS_PAUSE		(nested)	pause parameters
+        ETHA_PAUSE_AUTONEG			(bool)
+        ETHA_PAUSE_RX				(bool)
+        ETHA_PAUSE_TX				(bool)
+    ETHA_PARAMS_CHANNELS	(nested)	channel settings
+        ETHA_CHANNELS_MAX_RX			(u32)
+        ETHA_CHANNELS_MAX_TX			(u32)
+        ETHA_CHANNELS_MAX_OTHER			(u32)
+        ETHA_CHANNELS_MAX_COMBINED		(u32)
+        ETHA_CHANNELS_RX_COUNT			(u32)
+        ETHA_CHANNELS_TX_COUNT			(u32)
+        ETHA_CHANNELS_OTHER_COUNT		(u32)
+        ETHA_CHANNELS_COMBINED_COUNT		(u32)
+    ETHA_PARAMS_EEE		(nested)	EEE settings
+        ETHA_EEE_LINK_MODES			(bitset)
+		- modes for which EEE is advertised (value) or supported (mask)
+        ETHA_EEE_PEER_MODES			(bitset)
+		- modes for which link partner advertises EEE
+        ETHA_EEE_ACTIVE				(bool)
+        ETHA_EEE_ENABLED			(bool)
+        ETHA_EEE_TX_LPI_ENABLED			(bool)
+        ETHA_EEE_TX_LPI_TIMER			(u32)
+    ETHA_PARAMS_FEC		(nested)	FEC parameters
+        ETHA_FEC_MODES				(bitfield32)
+		- active (value) and configured (selector) FEC encodings
+
+GET_PARAMS requests allow dumps and messages in the same format as response
+to them are broadcasted as notifications on change of these settings using
+netlink or ioctl ethtool interface.
+
+
+
 Request translation
 -------------------
 
@@ -335,11 +430,11 @@ ETHTOOL_NWAY_RST		n/a
 ETHTOOL_GLINK			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_GEEPROM			n/a
 ETHTOOL_SEEPROM			n/a
-ETHTOOL_GCOALESCE		n/a
+ETHTOOL_GCOALESCE		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SCOALESCE		n/a
-ETHTOOL_GRINGPARAM		n/a
+ETHTOOL_GRINGPARAM		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SRINGPARAM		n/a
-ETHTOOL_GPAUSEPARAM		n/a
+ETHTOOL_GPAUSEPARAM		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SPAUSEPARAM		n/a
 ETHTOOL_GRXCSUM			ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SRXCSUM			ETHNL_CMD_SET_SETTINGS
@@ -381,7 +476,7 @@ ETHTOOL_GRXFHINDIR		n/a
 ETHTOOL_SRXFHINDIR		n/a
 ETHTOOL_GFEATURES		ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SFEATURES		n/a
-ETHTOOL_GCHANNELS		n/a
+ETHTOOL_GCHANNELS		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SCHANNELS		n/a
 ETHTOOL_SET_DUMP		n/a
 ETHTOOL_GET_DUMP_FLAG		n/a
@@ -389,7 +484,7 @@ ETHTOOL_GET_DUMP_DATA		n/a
 ETHTOOL_GET_TS_INFO		n/a
 ETHTOOL_GMODULEINFO		n/a
 ETHTOOL_GMODULEEEPROM		n/a
-ETHTOOL_GEEE			n/a
+ETHTOOL_GEEE			ETHNL_CMD_GET_PARAMS
 ETHTOOL_SEEE			n/a
 ETHTOOL_GRSSH			n/a
 ETHTOOL_SRSSH			n/a
@@ -401,6 +496,6 @@ ETHTOOL_GLINKSETTINGS		ETHNL_CMD_GET_SETTINGS
 ETHTOOL_SLINKSETTINGS		ETHNL_CMD_SET_SETTINGS
 ETHTOOL_PHY_GTUNABLE		n/a
 ETHTOOL_PHY_STUNABLE		n/a
-ETHTOOL_GFECPARAM		n/a
+ETHTOOL_GFECPARAM		ETHNL_CMD_GET_PARAMS
 ETHTOOL_SFECPARAM		n/a
 
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 8dfcb9ef4009..fec0f2000dc5 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -14,6 +14,8 @@ enum {
 	ETHNL_CMD_SET_DRVINFO,		/* only for reply */
 	ETHNL_CMD_GET_SETTINGS,
 	ETHNL_CMD_SET_SETTINGS,
+	ETHNL_CMD_GET_PARAMS,
+	ETHNL_CMD_SET_PARAMS,
 
 	__ETHNL_CMD_MAX,
 	ETHNL_CMD_MAX = (__ETHNL_CMD_MAX - 1)
@@ -197,6 +199,123 @@ enum {
 	ETHA_FEATURES_MAX = (__ETHA_FEATURES_MAX - 1)
 };
 
+/* GET_PARAMS / SET_PARAMS */
+
+enum {
+	ETHA_PARAMS_UNSPEC,
+	ETHA_PARAMS_DEV,			/* nest - ETHA_DEV_* */
+	ETHA_PARAMS_INFOMASK,			/* u32 */
+	ETHA_PARAMS_COMPACT,			/* flag */
+	ETHA_PARAMS_COALESCE,			/* nest - ETHA_COALESCE_* */
+	ETHA_PARAMS_RING,			/* nest - ETHA_RING_* */
+	ETHA_PARAMS_PAUSE,			/* nest - ETHA_PAUSE_* */
+	ETHA_PARAMS_CHANNELS,			/* nest - ETHA_CHANNELS_* */
+	ETHA_PARAMS_EEE,			/* nest - ETHA_EEE_* */
+	ETHA_PARAMS_FEC,			/* nest - ETHA_FEC_* */
+
+	__ETHA_PARAMS_MAX,
+	ETHA_PARAMS_MAX = (__ETHA_PARAMS_MAX - 1)
+};
+
+#define ETH_PARAMS_IM_COALESCE			0x01
+#define ETH_PARAMS_IM_RING			0x02
+#define ETH_PARAMS_IM_PAUSE			0x04
+#define ETH_PARAMS_IM_CHANNELS			0x08
+#define ETH_PARAMS_IM_EEE			0x10
+#define ETH_PARAMS_IM_FEC			0x20
+
+#define ETH_PARAMS_IM_DEFAULT			0x3f
+
+enum {
+	ETHA_COALESCE_UNSPEC,
+	ETHA_COALESCE_RX_USECS,			/* u32 */
+	ETHA_COALESCE_RX_MAXFRM,		/* u32 */
+	ETHA_COALESCE_RX_USECS_IRQ,		/* u32 */
+	ETHA_COALESCE_RX_MAXFRM_IRQ,		/* u32 */
+	ETHA_COALESCE_RX_USECS_LOW,		/* u32 */
+	ETHA_COALESCE_RX_MAXFRM_LOW,		/* u32 */
+	ETHA_COALESCE_RX_USECS_HIGH,		/* u32 */
+	ETHA_COALESCE_RX_MAXFRM_HIGH,		/* u32 */
+	ETHA_COALESCE_TX_USECS,			/* u32 */
+	ETHA_COALESCE_TX_MAXFRM,		/* u32 */
+	ETHA_COALESCE_TX_USECS_IRQ,		/* u32 */
+	ETHA_COALESCE_TX_MAXFRM_IRQ,		/* u32 */
+	ETHA_COALESCE_TX_USECS_LOW,		/* u32 */
+	ETHA_COALESCE_TX_MAXFRM_LOW,		/* u32 */
+	ETHA_COALESCE_TX_USECS_HIGH,		/* u32 */
+	ETHA_COALESCE_TX_MAXFRM_HIGH,		/* u32 */
+	ETHA_COALESCE_PKT_RATE_LOW,		/* u32 */
+	ETHA_COALESCE_PKT_RATE_HIGH,		/* u32 */
+	ETHA_COALESCE_RX_USE_ADAPTIVE,		/* u8 */
+	ETHA_COALESCE_TX_USE_ADAPTIVE,		/* u8 */
+	ETHA_COALESCE_RATE_SAMPLE_INTERVAL,	/* u32 */
+	ETHA_COALESCE_STATS_BLOCK_USECS,	/* u32 */
+
+	__ETHA_COALESCE_MAX,
+	ETHA_COALESCE_MAX = (__ETHA_COALESCE_MAX - 1)
+};
+
+enum {
+	ETHA_RING_UNSPEC,
+	ETHA_RING_RX_MAX_PENDING,		/* u32 */
+	ETHA_RING_RX_MINI_MAX_PENDING,		/* u32 */
+	ETHA_RING_RX_JUMBO_MAX_PENDING,		/* u32 */
+	ETHA_RING_TX_MAX_PENDING,		/* u32 */
+	ETHA_RING_RX_PENDING,			/* u32 */
+	ETHA_RING_RX_MINI_PENDING,		/* u32 */
+	ETHA_RING_RX_JUMBO_PENDING,		/* u32 */
+	ETHA_RING_TX_PENDING,			/* u32 */
+
+	__ETHA_RING_MAX,
+	ETHA_RING_MAX = (__ETHA_RING_MAX - 1)
+};
+
+enum {
+	ETHA_PAUSE_UNSPEC,
+	ETHA_PAUSE_AUTONEG,			/* u8 */
+	ETHA_PAUSE_RX,				/* u8 */
+	ETHA_PAUSE_TX,				/* u8 */
+
+	__ETHA_PAUSE_MAX,
+	ETHA_PAUSE_MAX = (__ETHA_PAUSE_MAX - 1)
+};
+
+enum {
+	ETHA_CHANNELS_UNSPEC,
+	ETHA_CHANNELS_MAX_RX,			/* u32 */
+	ETHA_CHANNELS_MAX_TX,			/* u32 */
+	ETHA_CHANNELS_MAX_OTHER,		/* u32 */
+	ETHA_CHANNELS_MAX_COMBINED,		/* u32 */
+	ETHA_CHANNELS_RX_COUNT,			/* u32 */
+	ETHA_CHANNELS_TX_COUNT,			/* u32 */
+	ETHA_CHANNELS_OTHER_COUNT,		/* u32 */
+	ETHA_CHANNELS_COMBINED_COUNT,		/* u32 */
+
+	__ETHA_CHANNELS_MAX,
+	ETHA_CHANNELS_MAX = (__ETHA_CHANNELS_MAX - 1)
+};
+
+enum {
+	ETHA_EEE_UNSPEC,
+	ETHA_EEE_LINK_MODES,			/* bitset */
+	ETHA_EEE_PEER_MODES,			/* bitset */
+	ETHA_EEE_ACTIVE,			/* u8 */
+	ETHA_EEE_ENABLED,			/* u8 */
+	ETHA_EEE_TX_LPI_ENABLED,		/* u8 */
+	ETHA_EEE_TX_LPI_TIMER,			/* u32 */
+
+	__ETHA_EEE_MAX,
+	ETHA_EEE_MAX = (__ETHA_EEE_MAX - 1)
+};
+
+enum {
+	ETHA_FEC_UNSPEC,
+	ETHA_FEC_MODES,				/* bitfield32 */
+
+	__ETHA_FEC_MAX,
+	ETHA_FEC_MAX = (__ETHA_FEC_MAX - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 8dd98310ed6f..10aeedcee336 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -4,4 +4,4 @@ obj-y				+= ioctl.o common.o
 
 obj-$(CONFIG_ETHTOOL_NETLINK)	+= ethtool_nl.o
 
-ethtool_nl-y	:= netlink.o strset.o drvinfo.o settings.o
+ethtool_nl-y	:= netlink.o strset.o drvinfo.o settings.o params.o
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 6e183caca01f..721101ed2ab6 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -731,13 +731,16 @@ int ethnl_get_strset(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_drvinfo(struct sk_buff *skb, struct genl_info *info);
 int ethnl_get_settings(struct sk_buff *skb, struct genl_info *info);
 int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info);
+int ethnl_get_params(struct sk_buff *skb, struct genl_info *info);
 
 int ethnl_strset_start(struct netlink_callback *cb);
 int ethnl_drvinfo_start(struct netlink_callback *cb);
 int ethnl_settings_start(struct netlink_callback *cb);
+int ethnl_params_start(struct netlink_callback *cb);
 
 int ethnl_strset_done(struct netlink_callback *cb);
 int ethnl_settings_done(struct netlink_callback *cb);
+int ethnl_params_done(struct netlink_callback *cb);
 
 static const struct genl_ops ethtool_genl_ops[] = {
 	{
@@ -765,6 +768,13 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= ethnl_set_settings,
 	},
+	{
+		.cmd	= ETHNL_CMD_GET_PARAMS,
+		.doit	= ethnl_get_params,
+		.start	= ethnl_params_start,
+		.dumpit	= ethnl_dumpit,
+		.done	= ethnl_params_done,
+	},
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/params.c b/net/ethtool/params.c
new file mode 100644
index 000000000000..07d4c527abf2
--- /dev/null
+++ b/net/ethtool/params.c
@@ -0,0 +1,539 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#include "netlink.h"
+#include "common.h"
+
+static const struct nla_policy params_policy[ETHA_PARAMS_MAX + 1] = {
+	[ETHA_PARAMS_UNSPEC]		= { .type = NLA_UNSPEC },
+	[ETHA_PARAMS_DEV]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_INFOMASK]		= { .type = NLA_U32 },
+	[ETHA_PARAMS_COMPACT]		= { .type = NLA_FLAG },
+	[ETHA_PARAMS_COALESCE]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_RING]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_PAUSE]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_CHANNELS]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_EEE]		= { .type = NLA_NESTED },
+	[ETHA_PARAMS_FEC]		= { .type = NLA_NESTED },
+};
+
+struct params_data {
+	struct ethtool_coalesce		coalesce;
+	struct ethtool_channels		channels;
+	struct ethtool_pauseparam	pause;
+	struct ethtool_ringparam	ring;
+	struct ethtool_eee		eee;
+	struct ethtool_fecparam		fec;
+	u32				req_mask;
+};
+
+struct params_reqinfo {
+	struct net_device		*dev;
+	u32				req_mask;
+	bool				compact;
+	bool				have_rtnl;
+};
+
+static int ethnl_get_coalesce(struct net_device *dev,
+			      struct ethtool_coalesce *data)
+{
+	if (!dev->ethtool_ops->get_coalesce)
+		return -EOPNOTSUPP;
+	return dev->ethtool_ops->get_coalesce(dev, data);
+}
+
+static int ethnl_get_ring(struct net_device *dev,
+			  struct ethtool_ringparam *data)
+{
+	if (!dev->ethtool_ops->get_ringparam)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_ringparam(dev, data);
+	return 0;
+}
+
+static int ethnl_get_pause(struct net_device *dev,
+			   struct ethtool_pauseparam *data)
+{
+	if (!dev->ethtool_ops->get_pauseparam)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_pauseparam(dev, data);
+	return 0;
+}
+
+static int ethnl_get_channels(struct net_device *dev,
+			      struct ethtool_channels *data)
+{
+	if (!dev->ethtool_ops->get_channels)
+		return -EOPNOTSUPP;
+	dev->ethtool_ops->get_channels(dev, data);
+	return 0;
+}
+
+static int ethnl_get_eee(struct net_device *dev, struct ethtool_eee *data)
+{
+	if (!dev->ethtool_ops->get_eee)
+		return -EOPNOTSUPP;
+	return dev->ethtool_ops->get_eee(dev, data);
+}
+
+static int ethnl_get_fec(struct net_device *dev, struct ethtool_fecparam *data)
+{
+	if (!dev->ethtool_ops->get_fecparam)
+		return -EOPNOTSUPP;
+	return dev->ethtool_ops->get_fecparam(dev, data);
+}
+
+static int params_size(struct params_data *data,
+		       struct params_reqinfo *req_info)
+{
+	struct ethtool_eee *eee = &data->eee;
+	u32 req_mask = req_info->req_mask;
+	bool compact = req_info->compact;
+	int len = 0;
+
+	if (req_mask & ETH_PARAMS_IM_COALESCE)
+		len += nla_total_size(20 * nla_total_size(sizeof(u32)) +
+				      2 * nla_total_size(sizeof(u8)));
+	if (req_mask & ETH_PARAMS_IM_RING)
+		len += nla_total_size(8 * nla_total_size(sizeof(u32)));
+	if (req_mask & ETH_PARAMS_IM_PAUSE)
+		len += nla_total_size(3 * nla_total_size(sizeof(u8)));
+	if (req_mask & ETH_PARAMS_IM_CHANNELS)
+		len += nla_total_size(8 * nla_total_size(sizeof(u32)));
+	if (req_mask & ETH_PARAMS_IM_EEE) {
+		int nlen = 0;
+		int ret;
+
+		/* link_modes */
+		ret = ethnl_bitset32_size(compact, sizeof(u32) * 8,
+					  &eee->advertised, &eee->supported,
+					  link_mode_names);
+		if (ret < 0)
+			return ret;
+		nlen += ret;
+		/* peer_modes */
+		ret = ethnl_bitset32_size(compact, sizeof(u32) * 8,
+					  &eee->lp_advertised,
+					  &eee->lp_advertised, link_mode_names);
+		if (ret < 0)
+			return ret;
+		nlen += ret;
+		/* active, enabled, tx_lpi_enabled */
+		nlen += 3 * nla_total_size(sizeof(u8));
+		/* tx_lpi_timer */
+		nlen += nla_total_size(sizeof(u32));
+		/* nest */
+		len += nla_total_size(nlen);
+	}
+	if (req_mask & ETH_PARAMS_IM_FEC) {
+		int nlen = nla_total_size(sizeof(struct nla_bitfield32));
+
+		len += nla_total_size(nlen);
+	}
+
+	return len;
+}
+
+static int fill_coalesce(struct sk_buff *skb, struct ethtool_coalesce *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_COALESCE);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_u32(skb, ETHA_COALESCE_RX_USECS,
+			data->rx_coalesce_usecs) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_MAXFRM,
+			data->rx_max_coalesced_frames) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_USECS_IRQ,
+			data->rx_coalesce_usecs_irq) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_MAXFRM_IRQ,
+			data->rx_max_coalesced_frames_irq) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_USECS_LOW,
+			data->rx_coalesce_usecs_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_MAXFRM_LOW,
+			data->rx_max_coalesced_frames_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_USECS_HIGH,
+			data->rx_coalesce_usecs_high) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RX_MAXFRM_HIGH,
+			data->rx_max_coalesced_frames_high) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_USECS,
+			data->tx_coalesce_usecs) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_MAXFRM,
+			data->tx_max_coalesced_frames) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_USECS_IRQ,
+			data->tx_coalesce_usecs_irq) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_MAXFRM_IRQ,
+			data->tx_max_coalesced_frames_irq) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_USECS_LOW,
+			data->tx_coalesce_usecs_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_MAXFRM_LOW,
+			data->tx_max_coalesced_frames_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_USECS_HIGH,
+			data->tx_coalesce_usecs_high) ||
+	    nla_put_u32(skb, ETHA_COALESCE_TX_MAXFRM_HIGH,
+			data->tx_max_coalesced_frames_high) ||
+	    nla_put_u32(skb, ETHA_COALESCE_PKT_RATE_LOW,
+			data->pkt_rate_low) ||
+	    nla_put_u32(skb, ETHA_COALESCE_PKT_RATE_HIGH,
+			data->pkt_rate_high) ||
+	    nla_put_u8(skb, ETHA_COALESCE_RX_USE_ADAPTIVE,
+		       !!data->use_adaptive_rx_coalesce) ||
+	    nla_put_u8(skb, ETHA_COALESCE_TX_USE_ADAPTIVE,
+		       !!data->use_adaptive_tx_coalesce) ||
+	    nla_put_u32(skb, ETHA_COALESCE_RATE_SAMPLE_INTERVAL,
+			data->rate_sample_interval) ||
+	    nla_put_u32(skb, ETHA_COALESCE_STATS_BLOCK_USECS,
+			data->stats_block_coalesce_usecs)) {
+		nla_nest_cancel(skb, nest);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int fill_ring(struct sk_buff *skb, struct ethtool_ringparam *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_RING);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_u32(skb, ETHA_RING_RX_MAX_PENDING,
+			data->rx_max_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_MINI_MAX_PENDING,
+			data->rx_mini_max_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_JUMBO_MAX_PENDING,
+			data->rx_jumbo_max_pending) ||
+	    nla_put_u32(skb, ETHA_RING_TX_MAX_PENDING,
+			data->tx_max_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_PENDING,
+			data->rx_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_MINI_PENDING,
+			data->rx_mini_pending) ||
+	    nla_put_u32(skb, ETHA_RING_RX_JUMBO_PENDING,
+			data->rx_jumbo_pending) ||
+	    nla_put_u32(skb, ETHA_RING_TX_PENDING,
+			data->tx_pending)) {
+		nla_nest_cancel(skb, nest);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int fill_pause(struct sk_buff *skb, struct ethtool_pauseparam *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_PAUSE);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_u8(skb, ETHA_PAUSE_AUTONEG, !!data->autoneg) ||
+	    nla_put_u8(skb, ETHA_PAUSE_RX, !!data->rx_pause) ||
+	    nla_put_u8(skb, ETHA_PAUSE_TX, !!data->tx_pause)) {
+		nla_nest_cancel(skb, nest);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int fill_channels(struct sk_buff *skb, struct ethtool_channels *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_CHANNELS);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_u32(skb, ETHA_CHANNELS_MAX_RX, data->max_rx) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_MAX_TX, data->max_tx) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_MAX_OTHER, data->max_other) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_MAX_COMBINED, data->max_combined) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_RX_COUNT, data->rx_count) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_TX_COUNT, data->tx_count) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_OTHER_COUNT, data->other_count) ||
+	    nla_put_u32(skb, ETHA_CHANNELS_COMBINED_COUNT,
+			data->combined_count)) {
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int fill_eee(struct sk_buff *skb, struct ethtool_eee *data, bool compact)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_EEE);
+	int ret;
+
+	if (!nest)
+		return -EMSGSIZE;
+	ret = ethnl_put_bitset32(skb, ETHA_EEE_LINK_MODES, compact,
+				 sizeof(data->advertised) * 8,
+				 &data->advertised, &data->supported,
+				 link_mode_names);
+	if (ret < 0)
+		goto err;
+	ret = ethnl_put_bitset32(skb, ETHA_EEE_PEER_MODES, compact,
+				 sizeof(data->advertised) * 8,
+				 &data->lp_advertised, &data->lp_advertised,
+				 link_mode_names);
+	if (ret < 0)
+		goto err;
+
+	if (nla_put_u8(skb, ETHA_EEE_ACTIVE, !!data->eee_active) ||
+	    nla_put_u8(skb, ETHA_EEE_ENABLED, !!data->eee_enabled) ||
+	    nla_put_u8(skb, ETHA_EEE_TX_LPI_ENABLED, !!data->tx_lpi_enabled) ||
+	    nla_put_u32(skb, ETHA_EEE_TX_LPI_TIMER, data->tx_lpi_timer)) {
+		ret = -EMSGSIZE;
+		goto err;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+err:
+	nla_nest_cancel(skb, nest);
+	return ret;
+}
+
+static int fill_fec(struct sk_buff *skb, struct ethtool_fecparam *data)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_FEC);
+
+	if (!nest)
+		return -EMSGSIZE;
+	if (nla_put_bitfield32(skb, ETHA_FEC_MODES, data->active_fec,
+			       data->fec)) {
+		nla_nest_cancel(skb, nest);
+		return -EMSGSIZE;
+	}
+
+	nla_nest_end(skb, nest);
+	return 0;
+}
+
+static int parse_params_req(struct params_reqinfo *req_info,
+			    struct genl_info *info, struct sk_buff *skb,
+			    const struct nlmsghdr *nlhdr)
+{
+	struct nlattr *tb[ETHA_PARAMS_MAX + 1];
+	int ret;
+
+	memset(req_info, '\0', sizeof(*req_info));
+
+	ret = genlmsg_parse(nlhdr, &ethtool_genl_family, tb,
+			    ETHA_PARAMS_MAX, params_policy,
+			    info ? info->extack : NULL);
+	if (ret < 0)
+		return ret;
+
+	if (tb[ETHA_PARAMS_DEV]) {
+		req_info->dev = ethnl_dev_get(info, tb[ETHA_PARAMS_DEV]);
+		if (IS_ERR(req_info->dev)) {
+			ret = PTR_ERR(req_info->dev);
+			req_info->dev = NULL;
+			return ret;
+		}
+	}
+	if (tb[ETHA_PARAMS_INFOMASK])
+		req_info->req_mask = nla_get_u32(tb[ETHA_PARAMS_INFOMASK]);
+	if (tb[ETHA_PARAMS_COMPACT])
+		req_info->compact = true;
+	if (req_info->req_mask == 0)
+		req_info->req_mask = ETH_PARAMS_IM_DEFAULT;
+
+	return 0;
+}
+
+static int prepare_params(struct params_data *data,
+			  struct params_reqinfo *req_info,
+			  struct genl_info *info, struct net_device *dev)
+{
+	u32 req_mask = req_info->req_mask;
+	int ret;
+
+	memset(data, '\0', sizeof(*data));
+	if (!req_info->have_rtnl)
+		rtnl_lock();
+	if (req_mask & ETH_PARAMS_IM_COALESCE) {
+		ret = ethnl_get_coalesce(dev, &data->coalesce);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_COALESCE;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_RING) {
+		ret = ethnl_get_ring(dev, &data->ring);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_RING;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_PAUSE) {
+		ret = ethnl_get_pause(dev, &data->pause);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_PAUSE;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_CHANNELS) {
+		ret = ethnl_get_channels(dev, &data->channels);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_CHANNELS;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_EEE) {
+		ret = ethnl_get_eee(dev, &data->eee);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_EEE;
+		}
+	}
+	if (req_mask & ETH_PARAMS_IM_FEC) {
+		ret = ethnl_get_fec(dev, &data->fec);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_FEC;
+		}
+	}
+	if (!req_info->have_rtnl)
+		rtnl_unlock();
+
+	data->req_mask = req_mask;
+	return 0;
+}
+
+static int fill_params(struct sk_buff *rskb, struct params_data *data,
+		       struct params_reqinfo *req_info)
+{
+	u32 req_mask = data->req_mask;
+	int ret;
+
+	if (req_mask & ETH_PARAMS_IM_COALESCE) {
+		ret = fill_coalesce(rskb, &data->coalesce);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_RING) {
+		ret = fill_ring(rskb, &data->ring);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_PAUSE) {
+		ret = fill_pause(rskb, &data->pause);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_CHANNELS) {
+		ret = fill_channels(rskb, &data->channels);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_EEE) {
+		ret = fill_eee(rskb, &data->eee, req_info->compact);
+		if (ret < 0)
+			return ret;
+	}
+	if (req_mask & ETH_PARAMS_IM_FEC) {
+		ret = fill_fec(rskb, &data->fec);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+int ethnl_get_params(struct sk_buff *skb, struct genl_info *info)
+{
+	struct params_data data;
+	struct params_reqinfo req_info;
+	struct sk_buff *rskb;
+	int reply_len;
+	void *ehdr;
+	int ret;
+
+	ret = parse_params_req(&req_info, info, skb, info->nlhdr);
+	if (ret < 0)
+		goto err_dev;
+	ret = prepare_params(&data, &req_info, info, req_info.dev);
+	if (ret < 0)
+		goto err_dev;
+	reply_len = params_size(&data, &req_info);
+	if (ret < 0)
+		goto err_dev;
+	ret = -ENOMEM;
+	rskb = ethnl_reply_init(reply_len, req_info.dev, ETHNL_CMD_SET_PARAMS,
+				ETHA_PARAMS_DEV, info, &ehdr);
+	if (!rskb)
+		goto err_dev;
+	ret = fill_params(rskb, &data, &req_info);
+	if (ret < 0)
+		goto err;
+
+	genlmsg_end(rskb, ehdr);
+	dev_put(req_info.dev);
+	return genlmsg_reply(rskb, info);
+
+err:
+	WARN_ONCE(ret == -EMSGSIZE,
+		  "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	nlmsg_free(rskb);
+err_dev:
+	if (req_info.dev)
+		dev_put(req_info.dev);
+	return ret;
+}
+
+static int params_dump(struct sk_buff *skb, struct netlink_callback *cb,
+		       struct net_device *dev)
+{
+	struct params_data data;
+	struct params_reqinfo *req_info;
+	int ret;
+
+	req_info = (struct params_reqinfo *)cb->args[4];
+	ret = prepare_params(&data, req_info, NULL, dev);
+	if (ret < 0)
+		return ret;
+	ret = ethnl_fill_dev(skb, dev, ETHA_PARAMS_DEV);
+	if (ret < 0)
+		return ret;
+	ret = fill_params(skb, &data, req_info);
+	return ret;
+}
+
+int ethnl_params_start(struct netlink_callback *cb)
+{
+	struct params_reqinfo *req_info;
+	int ret;
+
+	req_info = kmalloc(sizeof(*req_info), GFP_KERNEL);
+	if (!req_info)
+		return -ENOMEM;
+	ret = parse_params_req(req_info, NULL, cb->skb, cb->nlh);
+	if (ret < 0) {
+		if (req_info->dev)
+			dev_put(req_info->dev);
+		req_info->dev = NULL;
+		return ret;
+	}
+
+	cb->args[0] = (long)params_dump;
+	cb->args[1] = ETHNL_CMD_SET_PARAMS;
+	cb->args[4] = (long)req_info;
+
+	return 0;
+}
+
+int ethnl_params_done(struct netlink_callback *cb)
+{
+	struct params_reqinfo *req_info;
+
+	req_info = (struct params_reqinfo *)cb->args[4];
+	if (req_info->dev)
+		dev_put(req_info->dev);
+	kfree(req_info);
+
+	return 0;
+}
-- 
2.18.0


  parent reply	other threads:[~2018-07-30 12:54 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-30 12:52 [RFC PATCH net-next v2 00/17] ethtool netlink interface (WiP) Michal Kubecek
2018-07-30 12:52 ` [RFC PATCH net-next v2 01/17] netlink: introduce nla_put_bitfield32() Michal Kubecek
2018-07-30 12:52 ` [RFC PATCH net-next v2 02/17] ethtool: move to its own directory Michal Kubecek
2018-07-30 12:52 ` [RFC PATCH net-next v2 03/17] ethtool: introduce ethtool netlink interface Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 04/17] ethtool: helper functions for " Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 05/17] ethtool: netlink bitset handling Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 06/17] ethtool: support for netlink notifications Michal Kubecek
2018-07-30 13:16   ` Jiri Pirko
2018-07-30 17:01     ` Michal Kubecek
2018-07-31  6:46       ` Jiri Pirko
2018-07-30 12:53 ` [RFC PATCH net-next v2 07/17] ethtool: implement EVENT notifications Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 08/17] ethtool: implement GET_STRSET message Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 09/17] ethtool: implement GET_DRVINFO message Michal Kubecek
2018-07-30 13:21   ` Jiri Pirko
2018-07-30 14:37     ` Michal Kubecek
2018-07-30 14:28   ` Andrew Lunn
2018-07-30 14:46     ` Michal Kubecek
2018-07-30 15:48       ` Andrew Lunn
2018-07-30 16:47         ` Michal Kubecek
2018-07-31  0:56   ` Jakub Kicinski
2018-07-30 12:53 ` [RFC PATCH net-next v2 10/17] ethtool: implement GET_SETTINGS message Michal Kubecek
2018-07-30 18:54   ` Andrew Lunn
2018-08-21  9:32     ` Michal Kubecek
2018-08-21 14:10       ` Andrew Lunn
2018-08-21 14:52         ` Michal Kubecek
2018-07-30 19:06   ` Andrew Lunn
2018-07-30 19:09   ` Andrew Lunn
2018-07-30 19:42     ` Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 11/17] ethtool: implement GET_SETTINGS request for features Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 12/17] ethtool: implement SET_SETTINGS notification Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 13/17] ethtool: implement SET_SETTINGS message Michal Kubecek
2018-07-30 12:53 ` [RFC PATCH net-next v2 14/17] ethtool: implement SET_SETTINGS request for features Michal Kubecek
2018-07-30 12:53 ` Michal Kubecek [this message]
2018-07-30 12:54 ` [RFC PATCH net-next v2 16/17] ethtool: implement SET_PARAMS notification Michal Kubecek
2018-07-30 12:54 ` [RFC PATCH net-next v2 17/17] ethtool: implement SET_PARAMS message Michal Kubecek
2018-07-30 13:07 ` [RFC PATCH net-next v2 00/17] ethtool netlink interface (WiP) Jiri Pirko
2018-07-31  0:38   ` Jakub Kicinski

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=3a9f1d3161fe7a435b01f165de762b3a362c3572.1532953989.git.mkubecek@suse.cz \
    --to=mkubecek@suse.cz \
    --cc=davem@davemloft.net \
    --cc=f.fainelli@gmail.com \
    --cc=jiri@resnulli.us \
    --cc=kubakici@wp.pl \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linville@tuxdriver.com \
    --cc=netdev@vger.kernel.org \
    --cc=roopa@cumulusnetworks.com \
    /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.