]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
net: ethtool: add support for structured PHY statistics
authorJakub Kicinski <kuba@kernel.org>
Fri, 10 Jan 2025 06:05:13 +0000 (07:05 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 14 Jan 2025 10:44:19 +0000 (11:44 +0100)
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>
Documentation/networking/ethtool-netlink.rst
include/uapi/linux/ethtool.h
include/uapi/linux/ethtool_netlink.h
net/ethtool/netlink.h
net/ethtool/stats.c
net/ethtool/strset.c

index a7ba6368a4d522b9fa64fba4da26628426dd725f..da846f1d998ecbe227f5bf6029dffbae4e6e4844 100644 (file)
@@ -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.
index 7e1b3820f91fc3cd9e3aa2adc4b2c39b13b7eec3..d1089b88efc7d92f9c2a0003be27bc876793ade5 100644 (file)
@@ -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
index 9c909ce733a500191d8b31d1305d4463b9472d9c..9ff72cfb2e98d9983a82c3eebeccf64c1c6dd33a 100644 (file)
@@ -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"
index 0a09298fff92b3ad891acada5f7098bb1012bab4..1ce0a3de14304956dd9fc7e176c0bc30247ba158 100644 (file)
@@ -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 */
index f4d822c225db6a5a2d44baf89f4ab725c83d8e45..038a2558f0520458702bf73d9818f6e3e0e07539 100644 (file)
@@ -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;
 }
index b3382b3cf325c518b3a61fdff86885f595e7f7d5..818cf01f091109ad75cdb92761a29ee8f3f8140b 100644 (file)
@@ -105,6 +105,11 @@ static const struct strset_info info_template[] = {
                .count          = __ETHTOOL_A_STATS_RMON_CNT,
                .strings        = stats_rmon_names,
        },
+       [ETH_SS_STATS_PHY] = {
+               .per_dev        = false,
+               .count          = __ETHTOOL_A_STATS_PHY_CNT,
+               .strings        = stats_phy_names,
+       },
 };
 
 struct strset_req_info {