Commit bfad2b97 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

ethtool: add interface to read standard MAC Ctrl stats

Number of devices maintains the standard-based MAC control
counters for control frames. Add a API for those.
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ca224454
...@@ -285,6 +285,15 @@ struct ethtool_eth_phy_stats { ...@@ -285,6 +285,15 @@ struct ethtool_eth_phy_stats {
u64 SymbolErrorDuringCarrier; u64 SymbolErrorDuringCarrier;
}; };
/* Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*), not otherwise exposed
* via a more targeted API.
*/
struct ethtool_eth_ctrl_stats {
u64 MACControlFramesTransmitted;
u64 MACControlFramesReceived;
u64 UnsupportedOpcodesReceived;
};
/** /**
* struct ethtool_pause_stats - statistics for IEEE 802.3x pause frames * struct ethtool_pause_stats - statistics for IEEE 802.3x pause frames
* @tx_pause_frames: transmitted pause frame count. Reported to user space * @tx_pause_frames: transmitted pause frame count. Reported to user space
...@@ -524,6 +533,7 @@ struct ethtool_module_eeprom { ...@@ -524,6 +533,7 @@ struct ethtool_module_eeprom {
* read. * read.
* @get_eth_phy_stats: Query some of the IEEE 802.3 PHY statistics. * @get_eth_phy_stats: Query some of the IEEE 802.3 PHY statistics.
* @get_eth_mac_stats: Query some of the IEEE 802.3 MAC statistics. * @get_eth_mac_stats: Query some of the IEEE 802.3 MAC statistics.
* @get_eth_ctrl_stats: Query some of the IEEE 802.3 MAC Ctrl statistics.
* *
* All operations are optional (i.e. the function pointer may be set * All operations are optional (i.e. the function pointer may be set
* to %NULL) and callers must take this into account. Callers must * to %NULL) and callers must take this into account. Callers must
...@@ -638,6 +648,8 @@ struct ethtool_ops { ...@@ -638,6 +648,8 @@ struct ethtool_ops {
struct ethtool_eth_phy_stats *phy_stats); struct ethtool_eth_phy_stats *phy_stats);
void (*get_eth_mac_stats)(struct net_device *dev, void (*get_eth_mac_stats)(struct net_device *dev,
struct ethtool_eth_mac_stats *mac_stats); struct ethtool_eth_mac_stats *mac_stats);
void (*get_eth_ctrl_stats)(struct net_device *dev,
struct ethtool_eth_ctrl_stats *ctrl_stats);
}; };
int ethtool_check_ops(const struct ethtool_ops *ops); int ethtool_check_ops(const struct ethtool_ops *ops);
......
...@@ -672,6 +672,7 @@ enum ethtool_link_ext_substate_cable_issue { ...@@ -672,6 +672,7 @@ enum ethtool_link_ext_substate_cable_issue {
* @ETH_SS_STATS_STD: standardized stats * @ETH_SS_STATS_STD: standardized stats
* @ETH_SS_STATS_ETH_PHY: names of IEEE 802.3 PHY statistics * @ETH_SS_STATS_ETH_PHY: names of IEEE 802.3 PHY statistics
* @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics * @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_COUNT: number of defined string sets * @ETH_SS_COUNT: number of defined string sets
*/ */
...@@ -695,6 +696,7 @@ enum ethtool_stringset { ...@@ -695,6 +696,7 @@ enum ethtool_stringset {
ETH_SS_STATS_STD, ETH_SS_STATS_STD,
ETH_SS_STATS_ETH_PHY, ETH_SS_STATS_ETH_PHY,
ETH_SS_STATS_ETH_MAC, ETH_SS_STATS_ETH_MAC,
ETH_SS_STATS_ETH_CTRL,
/* add new constants above here */ /* add new constants above here */
ETH_SS_COUNT ETH_SS_COUNT
......
...@@ -699,6 +699,7 @@ enum { ...@@ -699,6 +699,7 @@ enum {
enum { enum {
ETHTOOL_STATS_ETH_PHY, ETHTOOL_STATS_ETH_PHY,
ETHTOOL_STATS_ETH_MAC, ETHTOOL_STATS_ETH_MAC,
ETHTOOL_STATS_ETH_CTRL,
/* add new constants above here */ /* add new constants above here */
__ETHTOOL_STATS_CNT __ETHTOOL_STATS_CNT
...@@ -779,6 +780,19 @@ enum { ...@@ -779,6 +780,19 @@ enum {
ETHTOOL_A_STATS_ETH_MAC_MAX = (__ETHTOOL_A_STATS_ETH_MAC_CNT - 1) ETHTOOL_A_STATS_ETH_MAC_MAX = (__ETHTOOL_A_STATS_ETH_MAC_CNT - 1)
}; };
enum {
/* 30.3.3.3 aMACControlFramesTransmitted */
ETHTOOL_A_STATS_ETH_CTRL_3_TX,
/* 30.3.3.4 aMACControlFramesReceived */
ETHTOOL_A_STATS_ETH_CTRL_4_RX,
/* 30.3.3.5 aUnsupportedOpcodesReceived */
ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP,
/* add new constants above here */
__ETHTOOL_A_STATS_ETH_CTRL_CNT,
ETHTOOL_A_STATS_ETH_CTRL_MAX = (__ETHTOOL_A_STATS_ETH_CTRL_CNT - 1)
};
/* generic netlink info */ /* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool" #define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1 #define ETHTOOL_GENL_VERSION 1
......
...@@ -404,5 +404,6 @@ int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info); ...@@ -404,5 +404,6 @@ int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info);
extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN];
extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN]; extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
extern const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN]; 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];
#endif /* _NET_ETHTOOL_NETLINK_H */ #endif /* _NET_ETHTOOL_NETLINK_H */
...@@ -16,6 +16,7 @@ struct stats_reply_data { ...@@ -16,6 +16,7 @@ struct stats_reply_data {
struct ethnl_reply_data base; struct ethnl_reply_data base;
struct ethtool_eth_phy_stats phy_stats; struct ethtool_eth_phy_stats phy_stats;
struct ethtool_eth_mac_stats mac_stats; struct ethtool_eth_mac_stats mac_stats;
struct ethtool_eth_ctrl_stats ctrl_stats;
}; };
#define STATS_REPDATA(__reply_base) \ #define STATS_REPDATA(__reply_base) \
...@@ -24,6 +25,7 @@ struct stats_reply_data { ...@@ -24,6 +25,7 @@ struct stats_reply_data {
const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = { const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = {
[ETHTOOL_STATS_ETH_PHY] = "eth-phy", [ETHTOOL_STATS_ETH_PHY] = "eth-phy",
[ETHTOOL_STATS_ETH_MAC] = "eth-mac", [ETHTOOL_STATS_ETH_MAC] = "eth-mac",
[ETHTOOL_STATS_ETH_CTRL] = "eth-ctrl",
}; };
const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = { const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {
...@@ -55,6 +57,12 @@ const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN] = ...@@ -55,6 +57,12 @@ const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN] =
[ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR] = "FrameTooLongErrors", [ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR] = "FrameTooLongErrors",
}; };
const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN] = {
[ETHTOOL_A_STATS_ETH_CTRL_3_TX] = "MACControlFramesTransmitted",
[ETHTOOL_A_STATS_ETH_CTRL_4_RX] = "MACControlFramesReceived",
[ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP] = "UnsupportedOpcodesReceived",
};
const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1] = { const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1] = {
[ETHTOOL_A_STATS_HEADER] = [ETHTOOL_A_STATS_HEADER] =
NLA_POLICY_NESTED(ethnl_header_policy), NLA_POLICY_NESTED(ethnl_header_policy),
...@@ -98,6 +106,7 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base, ...@@ -98,6 +106,7 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
memset(&data->phy_stats, 0xff, sizeof(data->phy_stats)); memset(&data->phy_stats, 0xff, sizeof(data->phy_stats));
memset(&data->mac_stats, 0xff, sizeof(data->mac_stats)); memset(&data->mac_stats, 0xff, sizeof(data->mac_stats));
memset(&data->ctrl_stats, 0xff, sizeof(data->mac_stats));
if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) && if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
dev->ethtool_ops->get_eth_phy_stats) dev->ethtool_ops->get_eth_phy_stats)
...@@ -105,6 +114,9 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base, ...@@ -105,6 +114,9 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask) && if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask) &&
dev->ethtool_ops->get_eth_mac_stats) dev->ethtool_ops->get_eth_mac_stats)
dev->ethtool_ops->get_eth_mac_stats(dev, &data->mac_stats); dev->ethtool_ops->get_eth_mac_stats(dev, &data->mac_stats);
if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask) &&
dev->ethtool_ops->get_eth_ctrl_stats)
dev->ethtool_ops->get_eth_ctrl_stats(dev, &data->ctrl_stats);
ethnl_ops_complete(dev); ethnl_ops_complete(dev);
return 0; return 0;
...@@ -125,6 +137,10 @@ static int stats_reply_size(const struct ethnl_req_info *req_base, ...@@ -125,6 +137,10 @@ static int stats_reply_size(const struct ethnl_req_info *req_base,
n_stats += sizeof(struct ethtool_eth_mac_stats) / sizeof(u64); n_stats += sizeof(struct ethtool_eth_mac_stats) / sizeof(u64);
n_grps++; n_grps++;
} }
if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask)) {
n_stats += sizeof(struct ethtool_eth_ctrl_stats) / sizeof(u64);
n_grps++;
}
len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */ len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
nla_total_size(4) + /* _A_STATS_GRP_ID */ nla_total_size(4) + /* _A_STATS_GRP_ID */
...@@ -229,6 +245,19 @@ static int stats_put_mac_stats(struct sk_buff *skb, ...@@ -229,6 +245,19 @@ static int stats_put_mac_stats(struct sk_buff *skb,
return 0; return 0;
} }
static int stats_put_ctrl_stats(struct sk_buff *skb,
const struct stats_reply_data *data)
{
if (stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_3_TX,
data->ctrl_stats.MACControlFramesTransmitted) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_4_RX,
data->ctrl_stats.MACControlFramesReceived) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP,
data->ctrl_stats.UnsupportedOpcodesReceived))
return -EMSGSIZE;
return 0;
}
static int stats_put_stats(struct sk_buff *skb, static int stats_put_stats(struct sk_buff *skb,
const struct stats_reply_data *data, const struct stats_reply_data *data,
u32 id, u32 ss_id, u32 id, u32 ss_id,
...@@ -272,6 +301,10 @@ static int stats_fill_reply(struct sk_buff *skb, ...@@ -272,6 +301,10 @@ static int stats_fill_reply(struct sk_buff *skb,
ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_MAC, ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_MAC,
ETH_SS_STATS_ETH_MAC, ETH_SS_STATS_ETH_MAC,
stats_put_mac_stats); stats_put_mac_stats);
if (!ret && test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask))
ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_CTRL,
ETH_SS_STATS_ETH_CTRL,
stats_put_ctrl_stats);
return ret; return ret;
} }
......
...@@ -95,6 +95,11 @@ static const struct strset_info info_template[] = { ...@@ -95,6 +95,11 @@ static const struct strset_info info_template[] = {
.count = __ETHTOOL_A_STATS_ETH_MAC_CNT, .count = __ETHTOOL_A_STATS_ETH_MAC_CNT,
.strings = stats_eth_mac_names, .strings = stats_eth_mac_names,
}, },
[ETH_SS_STATS_ETH_CTRL] = {
.per_dev = false,
.count = __ETHTOOL_A_STATS_ETH_CTRL_CNT,
.strings = stats_eth_ctrl_names,
},
}; };
struct strset_req_info { struct strset_req_info {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment