Commit 6167c0b6 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by Paolo Abeni
Browse files

net: ethtool: add support for structured PHY statistics



Introduce a new way to report PHY statistics in a structured and
standardized format using the netlink API. This new method does not
replace the old driver-specific stats, which can still be accessed with
`ethtool -S <eth name>`. The structured stats are available with
`ethtool -S <eth name> --all-groups`.

This new method makes it easier to diagnose problems by organizing stats
in a consistent and documented way.

Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent b7a2c1fe
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1616,6 +1616,7 @@ the ``ETHTOOL_A_STATS_GROUPS`` bitset. Currently defined values are:
 ETHTOOL_STATS_ETH_PHY  eth-phy  Basic IEEE 802.3 PHY statistics (30.3.2.1.*)
 ETHTOOL_STATS_ETH_CTRL eth-ctrl Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*)
 ETHTOOL_STATS_RMON     rmon     RMON (RFC 2819) statistics
 ETHTOOL_STATS_PHY      phy      Additional PHY statistics, not defined by IEEE
 ====================== ======== ===============================================

Each group should have a corresponding ``ETHTOOL_A_STATS_GRP`` in the reply.
+2 −0
Original line number Diff line number Diff line
@@ -681,6 +681,7 @@ enum ethtool_link_ext_substate_module {
 * @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics
 * @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics
 * @ETH_SS_STATS_RMON: names of RMON statistics
 * @ETH_SS_STATS_PHY: names of PHY(dev) statistics
 *
 * @ETH_SS_COUNT: number of defined string sets
 */
@@ -706,6 +707,7 @@ enum ethtool_stringset {
	ETH_SS_STATS_ETH_MAC,
	ETH_SS_STATS_ETH_CTRL,
	ETH_SS_STATS_RMON,
	ETH_SS_STATS_PHY,

	/* add new constants above here */
	ETH_SS_COUNT
+14 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ enum {
	ETHTOOL_STATS_ETH_MAC,
	ETHTOOL_STATS_ETH_CTRL,
	ETHTOOL_STATS_RMON,
	ETHTOOL_STATS_PHY,

	/* add new constants above here */
	__ETHTOOL_STATS_CNT
@@ -193,6 +194,19 @@ enum {
	ETHTOOL_A_STATS_RMON_MAX = (__ETHTOOL_A_STATS_RMON_CNT - 1)
};

enum {
	/* Basic packet counters if PHY has separate counters from the MAC */
	ETHTOOL_A_STATS_PHY_RX_PKTS,
	ETHTOOL_A_STATS_PHY_RX_BYTES,
	ETHTOOL_A_STATS_PHY_RX_ERRORS,
	ETHTOOL_A_STATS_PHY_TX_PKTS,
	ETHTOOL_A_STATS_PHY_TX_BYTES,
	ETHTOOL_A_STATS_PHY_TX_ERRORS,

	/* add new constants above here */
	__ETHTOOL_A_STATS_PHY_CNT,
	ETHTOOL_A_STATS_PHY_MAX = (__ETHTOOL_A_STATS_PHY_CNT - 1)
};

/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
+1 −0
Original line number Diff line number Diff line
@@ -511,5 +511,6 @@ extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING
extern const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN];
extern const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN];
extern const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN];
extern const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN];

#endif /* _NET_ETHTOOL_NETLINK_H */
+38 −1
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = {
	[ETHTOOL_STATS_ETH_MAC]			= "eth-mac",
	[ETHTOOL_STATS_ETH_CTRL]		= "eth-ctrl",
	[ETHTOOL_STATS_RMON]			= "rmon",
	[ETHTOOL_STATS_PHY]			= "phydev",
};

const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {
@@ -80,6 +81,15 @@ const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN] = {
	[ETHTOOL_A_STATS_RMON_JABBER]		= "etherStatsJabbers",
};

const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN] = {
	[ETHTOOL_A_STATS_PHY_RX_PKTS]		= "RxFrames",
	[ETHTOOL_A_STATS_PHY_RX_BYTES]		= "RxOctets",
	[ETHTOOL_A_STATS_PHY_RX_ERRORS]		= "RxErrors",
	[ETHTOOL_A_STATS_PHY_TX_PKTS]		= "TxFrames",
	[ETHTOOL_A_STATS_PHY_TX_BYTES]		= "TxOctets",
	[ETHTOOL_A_STATS_PHY_TX_ERRORS]		= "TxErrors",
};

const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_SRC + 1] = {
	[ETHTOOL_A_STATS_HEADER]	=
		NLA_POLICY_NESTED(ethnl_header_policy),
@@ -156,7 +166,8 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
	data->ctrl_stats.src = src;
	data->rmon_stats.src = src;

	if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
	if ((test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask) ||
	     test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask)) &&
	    src == ETHTOOL_MAC_STATS_SRC_AGGREGATE) {
		if (phydev)
			phy_ethtool_get_phy_stats(phydev, &data->phy_stats,
@@ -212,6 +223,10 @@ static int stats_reply_size(const struct ethnl_req_info *req_base,
			nla_total_size(4)) *	/* _A_STATS_GRP_HIST_BKT_HI */
			ETHTOOL_RMON_HIST_MAX * 2;
	}
	if (test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask)) {
		n_stats += sizeof(struct ethtool_phy_stats) / sizeof(u64);
		n_grps++;
	}

	len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
			 nla_total_size(4) + /* _A_STATS_GRP_ID */
@@ -265,6 +280,25 @@ static int stats_put_phy_stats(struct sk_buff *skb,
	return 0;
}

static int stats_put_phydev_stats(struct sk_buff *skb,
				  const struct stats_reply_data *data)
{
	if (stat_put(skb, ETHTOOL_A_STATS_PHY_RX_PKTS,
		     data->phydev_stats.rx_packets) ||
	    stat_put(skb, ETHTOOL_A_STATS_PHY_RX_BYTES,
		     data->phydev_stats.rx_bytes) ||
	    stat_put(skb, ETHTOOL_A_STATS_PHY_RX_ERRORS,
		     data->phydev_stats.rx_errors) ||
	    stat_put(skb, ETHTOOL_A_STATS_PHY_TX_PKTS,
		     data->phydev_stats.tx_packets) ||
	    stat_put(skb, ETHTOOL_A_STATS_PHY_TX_BYTES,
		     data->phydev_stats.tx_bytes) ||
	    stat_put(skb, ETHTOOL_A_STATS_PHY_TX_ERRORS,
		     data->phydev_stats.tx_errors))
		return -EMSGSIZE;
	return 0;
}

static int stats_put_mac_stats(struct sk_buff *skb,
			       const struct stats_reply_data *data)
{
@@ -441,6 +475,9 @@ static int stats_fill_reply(struct sk_buff *skb,
	if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask))
		ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON,
				      ETH_SS_STATS_RMON, stats_put_rmon_stats);
	if (!ret && test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask))
		ret = stats_put_stats(skb, data, ETHTOOL_STATS_PHY,
				      ETH_SS_STATS_PHY, stats_put_phydev_stats);

	return ret;
}
Loading