lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 11 Dec 2017 14:54:31 +0100 (CET)
From:   Michal Kubecek <mkubecek@...e.cz>
To:     netdev@...r.kernel.org
Cc:     linux-kernel@...r.kernel.org
Subject: [RFC PATCH 8/9] ethtool: implement GET_PARAMS message

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@...e.cz>
---
 Documentation/networking/ethtool-netlink.txt |  98 ++++++-
 include/uapi/linux/ethtool_netlink.h         | 118 ++++++++
 net/core/ethtool_netlink.c                   | 411 +++++++++++++++++++++++++++
 3 files changed, 621 insertions(+), 6 deletions(-)

diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 187fab33f721..45ed1801ab50 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -111,6 +111,8 @@ List of message types
     ETHTOOL_CMD_SET_DRVINFO		response only
     ETHTOOL_CMD_GET_SETTINGS
     ETHTOOL_CMD_SET_SETTINGS
+    ETHTOOL_CMD_GET_PARAMS
+    ETHTOOL_CMD_SET_PARAMS		response only (for now)
 
 All constants use ETHTOOL_CMD_ prefix followed by "GET", "SET" or "ACT" to
 indicate the type.
@@ -231,6 +233,90 @@ is supposed to allow requesting changes without knowing what exactly kernel
 supports.
 
 
+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.
+
+Header flags:
+    ETH_PARAMS_RF_COMPACT_BITSETS	bitset form in response (1 is compact)
+
+Header 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
+
+On top level, there is one attribute for each of the information categories,
+the information is nested in it.
+
+    ETHA_PARAMS_COALESCE	(nest)		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		(nest)		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		(nest)		pause parameters
+        ETHA_PAUSE_AUTONEG			(bool)
+        ETHA_PAUSE_RX				(bool)
+        ETHA_PAUSE_TX				(bool)
+    ETHA_PARAMS_CHANNELS	(nest)		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		(nest)		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		(nest)		FEC parameters
+        ETHA_FEC_MODES				(bitfield32)
+		- active (value) and configured (selector) FEC encodings
+
+
+
 Request translation
 -------------------
 
@@ -252,11 +338,11 @@ ETHTOOL_NWAY_RST		n/a
 ETHTOOL_GLINK			ETHTOOL_CMD_GET_SETTINGS
 ETHTOOL_GEEPROM			n/a
 ETHTOOL_SEEPROM			n/a
-ETHTOOL_GCOALESCE		n/a
+ETHTOOL_GCOALESCE		ETHTOOL_CMD_GET_PARAMS
 ETHTOOL_SCOALESCE		n/a
-ETHTOOL_GRINGPARAM		n/a
+ETHTOOL_GRINGPARAM		ETHTOOL_CMD_GET_PARAMS
 ETHTOOL_SRINGPARAM		n/a
-ETHTOOL_GPAUSEPARAM		n/a
+ETHTOOL_GPAUSEPARAM		ETHTOOL_CMD_GET_PARAMS
 ETHTOOL_SPAUSEPARAM		n/a
 ETHTOOL_GRXCSUM			n/a
 ETHTOOL_SRXCSUM			n/a
@@ -298,7 +384,7 @@ ETHTOOL_GRXFHINDIR		n/a
 ETHTOOL_SRXFHINDIR		n/a
 ETHTOOL_GFEATURES		n/a
 ETHTOOL_SFEATURES		n/a
-ETHTOOL_GCHANNELS		n/a
+ETHTOOL_GCHANNELS		ETHTOOL_CMD_GET_PARAMS
 ETHTOOL_SCHANNELS		n/a
 ETHTOOL_SET_DUMP		n/a
 ETHTOOL_GET_DUMP_FLAG		n/a
@@ -306,7 +392,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			ETHTOOL_CMD_GET_PARAMS
 ETHTOOL_SEEE			n/a
 ETHTOOL_GRSSH			n/a
 ETHTOOL_SRSSH			n/a
@@ -318,6 +404,6 @@ ETHTOOL_GLINKSETTINGS		ETHTOOL_CMD_GET_SETTINGS
 ETHTOOL_SLINKSETTINGS		ETHTOOL_CMD_SET_SETTINGS
 ETHTOOL_PHY_GTUNABLE		n/a
 ETHTOOL_PHY_STUNABLE		n/a
-ETHTOOL_GFECPARAM		n/a
+ETHTOOL_GFECPARAM		ETHTOOL_CMD_GET_PARAMS
 ETHTOOL_SFECPARAM		n/a
 
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 9520d13fc9ab..8621e0a9d481 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -25,6 +25,8 @@ enum {
 	ETHTOOL_CMD_SET_DRVINFO,	/* only for reply */
 	ETHTOOL_CMD_GET_SETTINGS,
 	ETHTOOL_CMD_SET_SETTINGS,
+	ETHTOOL_CMD_GET_PARAMS,
+	ETHTOOL_CMD_SET_PARAMS,
 
 	__ETHTOOL_CMD_MAX,
 	ETHTOOL_CMD_MAX = (__ETHTOOL_CMD_MAX - 1),
@@ -114,6 +116,122 @@ enum {
 
 #define ETH_SETTINGS_IM_DEFAULT			0x1f
 
+/* GET_PARAMS / SET_PARAMS */
+
+enum {
+	ETHA_PARAMS_UNSPEC,
+	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_RF_COMPACT_BITSETS		0x1
+
+#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/core/ethtool_netlink.c b/net/core/ethtool_netlink.c
index 4b14a02be12a..3fb49427f211 100644
--- a/net/core/ethtool_netlink.c
+++ b/net/core/ethtool_netlink.c
@@ -1438,6 +1438,413 @@ static int ethnl_set_settings(struct sk_buff *skb, struct genl_info *info)
 	return ret;
 }
 
+/* GET_PARAMS */
+
+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 ethnl_params_size(struct ethtool_eee *eee, u16 flags, u16 mask)
+{
+	int len = 0;
+
+	if (mask & ETH_PARAMS_IM_COALESCE)
+		len += nla_total_size(20 * nla_total_size(sizeof(u32)) +
+				      2 * nla_total_size(sizeof(u8)));
+	if (mask & ETH_PARAMS_IM_RING)
+		len += nla_total_size(8 * nla_total_size(sizeof(u32)));
+	if (mask & ETH_PARAMS_IM_PAUSE)
+		len += nla_total_size(3 * nla_total_size(sizeof(u8)));
+	if (mask & ETH_PARAMS_IM_CHANNELS)
+		len += nla_total_size(8 * nla_total_size(sizeof(u32)));
+	if (mask & ETH_PARAMS_IM_EEE) {
+		int nlen = 0;
+		int ret;
+
+		/* link_modes */
+		ret = ethnl_bitset_size(flags & ETH_PARAMS_RF_COMPACT_BITSETS,
+					sizeof(u32) * 8, &eee->advertised,
+					&eee->supported, link_mode_names);
+		if (ret < 0)
+			return ret;
+		nlen += ret;
+		/* peer_modes */
+		ret = ethnl_bitset_size(flags & ETH_PARAMS_RF_COMPACT_BITSETS,
+					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 (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, u16 flags)
+{
+	struct nlattr *nest = ethnl_nest_start(skb, ETHA_PARAMS_EEE);
+	int ret;
+
+	if (!nest)
+		return -EMSGSIZE;
+	ret = ethnl_put_bitset(skb, ETHA_EEE_LINK_MODES,
+			       flags & ETH_PARAMS_RF_COMPACT_BITSETS,
+			       sizeof(data->advertised) * 8, &data->advertised,
+			       &data->supported, link_mode_names);
+	if (ret < 0)
+		goto err;
+	ret = ethnl_put_bitset(skb, ETHA_EEE_PEER_MODES,
+			       flags & ETH_PARAMS_RF_COMPACT_BITSETS,
+			       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 ethnl_get_params(struct sk_buff *skb, struct genl_info *info)
+{
+	struct ethtool_coalesce coalesce = {};
+	struct ethtool_channels channels = {};
+	struct ethtool_pauseparam pause = {};
+	struct ethtool_ringparam ring = {};
+	struct ethtool_fecparam fec = {};
+	struct ethtool_eee eee = {};
+	unsigned int reply_len = 0;
+	struct ethnlmsghdr *ehdr;
+	struct net_device *dev;
+	struct sk_buff *rskb;
+	u16 req_flags;
+	u16 req_mask;
+	int ret = 0;
+
+	ehdr = info->userhdr;
+	if (!ehdr->info_mask)
+		ehdr->info_mask = ETH_PARAMS_IM_DEFAULT;
+	req_mask = ehdr->info_mask;
+	req_flags = ehdr->flags;
+
+	dev = ethnl_dev_get(info);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+
+	if (req_mask & ETH_PARAMS_IM_COALESCE) {
+		ret = ethnl_get_coalesce(dev, &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, &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, &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, &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, &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, &fec);
+		if (ret < 0) {
+			warn_partial_info(info);
+			req_mask &= ~ETH_PARAMS_IM_FEC;
+		}
+	}
+
+	ret = ethnl_params_size(&eee, req_flags, req_mask);
+	if (ret < 0)
+		goto err_putdev;
+	else
+		reply_len = ret;
+	rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_CMD_SET_PARAMS, info,
+				&ehdr);
+	ret = -ENOMEM;
+	if (!rskb)
+		goto err_putdev;
+	if (req_mask != ETH_SETTINGS_IM_DEFAULT)
+		ehdr->info_mask = req_mask;
+
+	if (req_mask & ETH_PARAMS_IM_COALESCE) {
+		ret = fill_coalesce(rskb, &coalesce);
+		if (ret < 0)
+			goto err;
+	}
+	if (req_mask & ETH_PARAMS_IM_RING) {
+		ret = fill_ring(rskb, &ring);
+		if (ret < 0)
+			goto err;
+	}
+	if (req_mask & ETH_PARAMS_IM_PAUSE) {
+		ret = fill_pause(rskb, &pause);
+		if (ret < 0)
+			goto err;
+	}
+	if (req_mask & ETH_PARAMS_IM_CHANNELS) {
+		ret = fill_channels(rskb, &channels);
+		if (ret < 0)
+			goto err;
+	}
+	if (req_mask & ETH_PARAMS_IM_EEE) {
+		ret = fill_eee(rskb, &eee, req_flags);
+		if (ret < 0)
+			goto err;
+	}
+	if (req_mask & ETH_PARAMS_IM_FEC) {
+		ret = fill_fec(rskb, &fec);
+		if (ret < 0)
+			goto err;
+	}
+
+	dev_put(dev);
+	genlmsg_end(rskb, ehdr);
+	return genlmsg_reply(rskb, info);
+
+err:
+	nlmsg_free(rskb);
+err_putdev:
+	dev_put(dev);
+	if (ret == -EMSGSIZE)
+		GENL_SET_ERR_MSG(info,
+				 "kernel error, see kernel log for details");
+	WARN_ONCE(ret == -EMSGSIZE,
+		  "calculated message payload length (%d) not sufficient\n",
+		  reply_len);
+	return ret;
+}
+
 /* genetlink paperwork */
 
 static const struct genl_ops ethtool_genl_ops[] = {
@@ -1455,6 +1862,10 @@ static const struct genl_ops ethtool_genl_ops[] = {
 		.policy	= settings_policy,
 		.doit	= ethnl_set_settings,
 	},
+	{
+		.cmd	= ETHTOOL_CMD_GET_PARAMS,
+		.doit	= ethnl_get_params,
+	},
 };
 
 static struct genl_family ethtool_genl_family = {
-- 
2.15.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ