Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Jakub Kicinski and committed by
Paolo Abeni
6167c0b6 b7a2c1fe

+61 -1
+1
Documentation/networking/ethtool-netlink.rst
··· 1616 1616 ETHTOOL_STATS_ETH_PHY eth-phy Basic IEEE 802.3 PHY statistics (30.3.2.1.*) 1617 1617 ETHTOOL_STATS_ETH_CTRL eth-ctrl Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*) 1618 1618 ETHTOOL_STATS_RMON rmon RMON (RFC 2819) statistics 1619 + ETHTOOL_STATS_PHY phy Additional PHY statistics, not defined by IEEE 1619 1620 ====================== ======== =============================================== 1620 1621 1621 1622 Each group should have a corresponding ``ETHTOOL_A_STATS_GRP`` in the reply.
+2
include/uapi/linux/ethtool.h
··· 681 681 * @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics 682 682 * @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics 683 683 * @ETH_SS_STATS_RMON: names of RMON statistics 684 + * @ETH_SS_STATS_PHY: names of PHY(dev) statistics 684 685 * 685 686 * @ETH_SS_COUNT: number of defined string sets 686 687 */ ··· 707 706 ETH_SS_STATS_ETH_MAC, 708 707 ETH_SS_STATS_ETH_CTRL, 709 708 ETH_SS_STATS_RMON, 709 + ETH_SS_STATS_PHY, 710 710 711 711 /* add new constants above here */ 712 712 ETH_SS_COUNT
+14
include/uapi/linux/ethtool_netlink.h
··· 99 99 ETHTOOL_STATS_ETH_MAC, 100 100 ETHTOOL_STATS_ETH_CTRL, 101 101 ETHTOOL_STATS_RMON, 102 + ETHTOOL_STATS_PHY, 102 103 103 104 /* add new constants above here */ 104 105 __ETHTOOL_STATS_CNT ··· 194 193 ETHTOOL_A_STATS_RMON_MAX = (__ETHTOOL_A_STATS_RMON_CNT - 1) 195 194 }; 196 195 196 + enum { 197 + /* Basic packet counters if PHY has separate counters from the MAC */ 198 + ETHTOOL_A_STATS_PHY_RX_PKTS, 199 + ETHTOOL_A_STATS_PHY_RX_BYTES, 200 + ETHTOOL_A_STATS_PHY_RX_ERRORS, 201 + ETHTOOL_A_STATS_PHY_TX_PKTS, 202 + ETHTOOL_A_STATS_PHY_TX_BYTES, 203 + ETHTOOL_A_STATS_PHY_TX_ERRORS, 204 + 205 + /* add new constants above here */ 206 + __ETHTOOL_A_STATS_PHY_CNT, 207 + ETHTOOL_A_STATS_PHY_MAX = (__ETHTOOL_A_STATS_PHY_CNT - 1) 208 + }; 197 209 198 210 /* generic netlink info */ 199 211 #define ETHTOOL_GENL_NAME "ethtool"
+1
net/ethtool/netlink.h
··· 511 511 extern const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN]; 512 512 extern const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN]; 513 513 extern const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN]; 514 + extern const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN]; 514 515 515 516 #endif /* _NET_ETHTOOL_NETLINK_H */
+38 -1
net/ethtool/stats.c
··· 36 36 [ETHTOOL_STATS_ETH_MAC] = "eth-mac", 37 37 [ETHTOOL_STATS_ETH_CTRL] = "eth-ctrl", 38 38 [ETHTOOL_STATS_RMON] = "rmon", 39 + [ETHTOOL_STATS_PHY] = "phydev", 39 40 }; 40 41 41 42 const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = { ··· 79 78 [ETHTOOL_A_STATS_RMON_OVERSIZE] = "etherStatsOversizePkts", 80 79 [ETHTOOL_A_STATS_RMON_FRAG] = "etherStatsFragments", 81 80 [ETHTOOL_A_STATS_RMON_JABBER] = "etherStatsJabbers", 81 + }; 82 + 83 + const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN] = { 84 + [ETHTOOL_A_STATS_PHY_RX_PKTS] = "RxFrames", 85 + [ETHTOOL_A_STATS_PHY_RX_BYTES] = "RxOctets", 86 + [ETHTOOL_A_STATS_PHY_RX_ERRORS] = "RxErrors", 87 + [ETHTOOL_A_STATS_PHY_TX_PKTS] = "TxFrames", 88 + [ETHTOOL_A_STATS_PHY_TX_BYTES] = "TxOctets", 89 + [ETHTOOL_A_STATS_PHY_TX_ERRORS] = "TxErrors", 82 90 }; 83 91 84 92 const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_SRC + 1] = { ··· 166 156 data->ctrl_stats.src = src; 167 157 data->rmon_stats.src = src; 168 158 169 - if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) && 159 + if ((test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask) || 160 + test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask)) && 170 161 src == ETHTOOL_MAC_STATS_SRC_AGGREGATE) { 171 162 if (phydev) 172 163 phy_ethtool_get_phy_stats(phydev, &data->phy_stats, ··· 223 212 nla_total_size(4)) * /* _A_STATS_GRP_HIST_BKT_HI */ 224 213 ETHTOOL_RMON_HIST_MAX * 2; 225 214 } 215 + if (test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask)) { 216 + n_stats += sizeof(struct ethtool_phy_stats) / sizeof(u64); 217 + n_grps++; 218 + } 226 219 227 220 len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */ 228 221 nla_total_size(4) + /* _A_STATS_GRP_ID */ ··· 276 261 { 277 262 if (stat_put(skb, ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR, 278 263 data->phy_stats.SymbolErrorDuringCarrier)) 264 + return -EMSGSIZE; 265 + return 0; 266 + } 267 + 268 + static int stats_put_phydev_stats(struct sk_buff *skb, 269 + const struct stats_reply_data *data) 270 + { 271 + if (stat_put(skb, ETHTOOL_A_STATS_PHY_RX_PKTS, 272 + data->phydev_stats.rx_packets) || 273 + stat_put(skb, ETHTOOL_A_STATS_PHY_RX_BYTES, 274 + data->phydev_stats.rx_bytes) || 275 + stat_put(skb, ETHTOOL_A_STATS_PHY_RX_ERRORS, 276 + data->phydev_stats.rx_errors) || 277 + stat_put(skb, ETHTOOL_A_STATS_PHY_TX_PKTS, 278 + data->phydev_stats.tx_packets) || 279 + stat_put(skb, ETHTOOL_A_STATS_PHY_TX_BYTES, 280 + data->phydev_stats.tx_bytes) || 281 + stat_put(skb, ETHTOOL_A_STATS_PHY_TX_ERRORS, 282 + data->phydev_stats.tx_errors)) 279 283 return -EMSGSIZE; 280 284 return 0; 281 285 } ··· 475 441 if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask)) 476 442 ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON, 477 443 ETH_SS_STATS_RMON, stats_put_rmon_stats); 444 + if (!ret && test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask)) 445 + ret = stats_put_stats(skb, data, ETHTOOL_STATS_PHY, 446 + ETH_SS_STATS_PHY, stats_put_phydev_stats); 478 447 479 448 return ret; 480 449 }
+5
net/ethtool/strset.c
··· 105 105 .count = __ETHTOOL_A_STATS_RMON_CNT, 106 106 .strings = stats_rmon_names, 107 107 }, 108 + [ETH_SS_STATS_PHY] = { 109 + .per_dev = false, 110 + .count = __ETHTOOL_A_STATS_PHY_CNT, 111 + .strings = stats_phy_names, 112 + }, 108 113 }; 109 114 110 115 struct strset_req_info {