History

ethtool: add interface to read RMON stats

Most devices maintain RMON (RFC 2819) stats - particularly the "histogram" of packets received by size. Unlike other RFCs which duplicate IEEE stats, the short/oversized frame counters in RMON don't seem to match IEEE stats 1-to-1 either, so expose those, too. Do not expose basic packet, CRC errors etc - those are already otherwise covered. Because standard defines packet ranges only up to 1518, and everything above that should theoretically be "oversized" - devices often create their own ranges. Going beyond what the RFC defines - expose the "histogram" in the Tx direction (assume for now that the ranges will be the same).

Jakub Kicinski committed 5 years ago

Commit a8b06e91 parent bfad2b96 files · +161 −0Browse files

Unified · Split

6 files
  1. include/linux/ethtool.h +43 −0
  2. include/uapi/linux/ethtool.h +2 −0
  3. include/uapi/linux/ethtool_netlink.h +23 −0
  4. net/ethtool/netlink.h +1 −0
  5. net/ethtool/stats.c +87 −0
  6. net/ethtool/strset.c +5 −0
include/linux/ethtool.h+43−0
@@ -346,6 +346,44 @@ struct ethtool_fec_stats { · 345 unmodified lines
346 } corrected_blocks, uncorrectable_blocks, corrected_bits;346 } corrected_blocks, uncorrectable_blocks, corrected_bits;
347};347};
348 348
349/**
350 * struct ethtool_rmon_hist_range - byte range for histogram statistics
351 * @low: low bound of the bucket (inclusive)
352 * @high: high bound of the bucket (inclusive)
353 */
354struct ethtool_rmon_hist_range {
355 u16 low;
356 u16 high;
357};
358
359#define ETHTOOL_RMON_HIST_MAX 10
360
361/**
362 * struct ethtool_rmon_stats - selected RMON (RFC 2819) statistics
363 * @undersize_pkts: Equivalent to `etherStatsUndersizePkts` from the RFC.
364 * @oversize_pkts: Equivalent to `etherStatsOversizePkts` from the RFC.
365 * @fragments: Equivalent to `etherStatsFragments` from the RFC.
366 * @jabbers: Equivalent to `etherStatsJabbers` from the RFC.
367 * @hist: Packet counter for packet length buckets (e.g.
368 * `etherStatsPkts128to255Octets` from the RFC).
369 * @hist_tx: Tx counters in similar form to @hist, not defined in the RFC.
370 *
371 * Selection of RMON (RFC 2819) statistics which are not exposed via different
372 * APIs, primarily the packet-length-based counters.
373 * Unfortunately different designs choose different buckets beyond
374 * the 1024B mark (jumbo frame teritory), so the definition of the bucket
375 * ranges is left to the driver.
376 */
377struct ethtool_rmon_stats {
378 u64 undersize_pkts;
379 u64 oversize_pkts;
380 u64 fragments;
381 u64 jabbers;
382
383 u64 hist[ETHTOOL_RMON_HIST_MAX];
384 u64 hist_tx[ETHTOOL_RMON_HIST_MAX];
385};
386
349#define ETH_MODULE_EEPROM_PAGE_LEN 128387#define ETH_MODULE_EEPROM_PAGE_LEN 128
350#define ETH_MODULE_MAX_I2C_ADDRESS 0x7f388#define ETH_MODULE_MAX_I2C_ADDRESS 0x7f
351 389
@@ -534,6 +572,8 @@ struct ethtool_module_eeprom { · 182 unmodified lines
534 * @get_eth_phy_stats: Query some of the IEEE 802.3 PHY statistics.572 * @get_eth_phy_stats: Query some of the IEEE 802.3 PHY statistics.
535 * @get_eth_mac_stats: Query some of the IEEE 802.3 MAC statistics.573 * @get_eth_mac_stats: Query some of the IEEE 802.3 MAC statistics.
536 * @get_eth_ctrl_stats: Query some of the IEEE 802.3 MAC Ctrl statistics.574 * @get_eth_ctrl_stats: Query some of the IEEE 802.3 MAC Ctrl statistics.
575 * @get_rmon_stats: Query some of the RMON (RFC 2819) statistics.
576 * Set %ranges to a pointer to zero-terminated array of byte ranges.
537 *577 *
538 * All operations are optional (i.e. the function pointer may be set578 * All operations are optional (i.e. the function pointer may be set
539 * to %NULL) and callers must take this into account. Callers must579 * to %NULL) and callers must take this into account. Callers must
@@ -650,6 +690,9 @@ struct ethtool_ops { · 110 unmodified lines
650 struct ethtool_eth_mac_stats *mac_stats);690 struct ethtool_eth_mac_stats *mac_stats);
651 void (*get_eth_ctrl_stats)(struct net_device *dev,691 void (*get_eth_ctrl_stats)(struct net_device *dev,
652 struct ethtool_eth_ctrl_stats *ctrl_stats);692 struct ethtool_eth_ctrl_stats *ctrl_stats);
693 void (*get_rmon_stats)(struct net_device *dev,
694 struct ethtool_rmon_stats *rmon_stats,
695 const struct ethtool_rmon_hist_range **ranges);
653};696};
654 697
655int ethtool_check_ops(const struct ethtool_ops *ops);698int ethtool_check_ops(const struct ethtool_ops *ops);
include/uapi/linux/ethtool.h+2−0
@@ -673,6 +673,7 @@ enum ethtool_link_ext_substate_cable_issue { · 672 unmodified lines
673 * @ETH_SS_STATS_ETH_PHY: names of IEEE 802.3 PHY statistics673 * @ETH_SS_STATS_ETH_PHY: names of IEEE 802.3 PHY statistics
674 * @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics674 * @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics
675 * @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics675 * @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics
676 * @ETH_SS_STATS_RMON: names of RMON statistics
676 *677 *
677 * @ETH_SS_COUNT: number of defined string sets678 * @ETH_SS_COUNT: number of defined string sets
678 */679 */
@@ -697,6 +698,7 @@ enum ethtool_stringset { · 18 unmodified lines
697 ETH_SS_STATS_ETH_PHY,698 ETH_SS_STATS_ETH_PHY,
698 ETH_SS_STATS_ETH_MAC,699 ETH_SS_STATS_ETH_MAC,
699 ETH_SS_STATS_ETH_CTRL,700 ETH_SS_STATS_ETH_CTRL,
701 ETH_SS_STATS_RMON,
700 702
701 /* add new constants above here */703 /* add new constants above here */
702 ETH_SS_COUNT704 ETH_SS_COUNT
include/uapi/linux/ethtool_netlink.h+23−0
@@ -700,6 +700,7 @@ enum { · 699 unmodified lines
700 ETHTOOL_STATS_ETH_PHY,700 ETHTOOL_STATS_ETH_PHY,
701 ETHTOOL_STATS_ETH_MAC,701 ETHTOOL_STATS_ETH_MAC,
702 ETHTOOL_STATS_ETH_CTRL,702 ETHTOOL_STATS_ETH_CTRL,
703 ETHTOOL_STATS_RMON,
703 704
704 /* add new constants above here */705 /* add new constants above here */
705 __ETHTOOL_STATS_CNT706 __ETHTOOL_STATS_CNT
@@ -714,6 +715,13 @@ enum { · 8 unmodified lines
714 715
715 ETHTOOL_A_STATS_GRP_STAT, /* nest */716 ETHTOOL_A_STATS_GRP_STAT, /* nest */
716 717
718 ETHTOOL_A_STATS_GRP_HIST_RX, /* nest */
719 ETHTOOL_A_STATS_GRP_HIST_TX, /* nest */
720
721 ETHTOOL_A_STATS_GRP_HIST_BKT_LOW, /* u32 */
722 ETHTOOL_A_STATS_GRP_HIST_BKT_HI, /* u32 */
723 ETHTOOL_A_STATS_GRP_HIST_VAL, /* u64 */
724
717 /* add new constants above here */725 /* add new constants above here */
718 __ETHTOOL_A_STATS_GRP_CNT,726 __ETHTOOL_A_STATS_GRP_CNT,
719 ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_CNT - 1)727 ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_CNT - 1)
@@ -793,6 +801,21 @@ enum { · 73 unmodified lines
793 ETHTOOL_A_STATS_ETH_CTRL_MAX = (__ETHTOOL_A_STATS_ETH_CTRL_CNT - 1)801 ETHTOOL_A_STATS_ETH_CTRL_MAX = (__ETHTOOL_A_STATS_ETH_CTRL_CNT - 1)
794};802};
795 803
804enum {
805 /* etherStatsUndersizePkts */
806 ETHTOOL_A_STATS_RMON_UNDERSIZE,
807 /* etherStatsOversizePkts */
808 ETHTOOL_A_STATS_RMON_OVERSIZE,
809 /* etherStatsFragments */
810 ETHTOOL_A_STATS_RMON_FRAG,
811 /* etherStatsJabbers */
812 ETHTOOL_A_STATS_RMON_JABBER,
813
814 /* add new constants above here */
815 __ETHTOOL_A_STATS_RMON_CNT,
816 ETHTOOL_A_STATS_RMON_MAX = (__ETHTOOL_A_STATS_RMON_CNT - 1)
817};
818
796/* generic netlink info */819/* generic netlink info */
797#define ETHTOOL_GENL_NAME "ethtool"820#define ETHTOOL_GENL_NAME "ethtool"
798#define ETHTOOL_GENL_VERSION 1821#define ETHTOOL_GENL_VERSION 1
net/ethtool/netlink.h+1−0
@@ -405,5 +405,6 @@ extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; · 404 unmodified lines
405extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];405extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
406extern const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN];406extern const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN];
407extern const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN];407extern const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN];
408extern const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN];
408 409
409#endif /* _NET_ETHTOOL_NETLINK_H */410#endif /* _NET_ETHTOOL_NETLINK_H */
net/ethtool/stats.c+87−0
@@ -17,6 +17,8 @@ struct stats_reply_data { · 16 unmodified lines
17 struct ethtool_eth_phy_stats phy_stats;17 struct ethtool_eth_phy_stats phy_stats;
18 struct ethtool_eth_mac_stats mac_stats;18 struct ethtool_eth_mac_stats mac_stats;
19 struct ethtool_eth_ctrl_stats ctrl_stats;19 struct ethtool_eth_ctrl_stats ctrl_stats;
20 struct ethtool_rmon_stats rmon_stats;
21 const struct ethtool_rmon_hist_range *rmon_ranges;
20};22};
21 23
22#define STATS_REPDATA(__reply_base) \24#define STATS_REPDATA(__reply_base) \
@@ -26,6 +28,7 @@ const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = { · 3 unmodified lines
26 [ETHTOOL_STATS_ETH_PHY] = "eth-phy",28 [ETHTOOL_STATS_ETH_PHY] = "eth-phy",
27 [ETHTOOL_STATS_ETH_MAC] = "eth-mac",29 [ETHTOOL_STATS_ETH_MAC] = "eth-mac",
28 [ETHTOOL_STATS_ETH_CTRL] = "eth-ctrl",30 [ETHTOOL_STATS_ETH_CTRL] = "eth-ctrl",
31 [ETHTOOL_STATS_RMON] = "rmon",
29};32};
30 33
31const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {34const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {
@@ -63,6 +66,13 @@ const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN] · 31 unmodified lines
63 [ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP] = "UnsupportedOpcodesReceived",66 [ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP] = "UnsupportedOpcodesReceived",
64};67};
65 68
69const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN] = {
70 [ETHTOOL_A_STATS_RMON_UNDERSIZE] = "etherStatsUndersizePkts",
71 [ETHTOOL_A_STATS_RMON_OVERSIZE] = "etherStatsOversizePkts",
72 [ETHTOOL_A_STATS_RMON_FRAG] = "etherStatsFragments",
73 [ETHTOOL_A_STATS_RMON_JABBER] = "etherStatsJabbers",
74};
75
66const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1] = {76const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1] = {
67 [ETHTOOL_A_STATS_HEADER] =77 [ETHTOOL_A_STATS_HEADER] =
68 NLA_POLICY_NESTED(ethnl_header_policy),78 NLA_POLICY_NESTED(ethnl_header_policy),
@@ -107,6 +117,7 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base, · 38 unmodified lines
107 memset(&data->phy_stats, 0xff, sizeof(data->phy_stats));117 memset(&data->phy_stats, 0xff, sizeof(data->phy_stats));
108 memset(&data->mac_stats, 0xff, sizeof(data->mac_stats));118 memset(&data->mac_stats, 0xff, sizeof(data->mac_stats));
109 memset(&data->ctrl_stats, 0xff, sizeof(data->mac_stats));119 memset(&data->ctrl_stats, 0xff, sizeof(data->mac_stats));
120 memset(&data->rmon_stats, 0xff, sizeof(data->rmon_stats));
110 121
111 if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&122 if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
112 dev->ethtool_ops->get_eth_phy_stats)123 dev->ethtool_ops->get_eth_phy_stats)
@@ -117,6 +128,10 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base, · 4 unmodified lines
117 if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask) &&128 if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask) &&
118 dev->ethtool_ops->get_eth_ctrl_stats)129 dev->ethtool_ops->get_eth_ctrl_stats)
119 dev->ethtool_ops->get_eth_ctrl_stats(dev, &data->ctrl_stats);130 dev->ethtool_ops->get_eth_ctrl_stats(dev, &data->ctrl_stats);
131 if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask) &&
132 dev->ethtool_ops->get_rmon_stats)
133 dev->ethtool_ops->get_rmon_stats(dev, &data->rmon_stats,
134 &data->rmon_ranges);
120 135
121 ethnl_ops_complete(dev);136 ethnl_ops_complete(dev);
122 return 0;137 return 0;
@@ -141,6 +156,16 @@ static int stats_reply_size(const struct ethnl_req_info *req_base, · 18 unmodified lines
141 n_stats += sizeof(struct ethtool_eth_ctrl_stats) / sizeof(u64);156 n_stats += sizeof(struct ethtool_eth_ctrl_stats) / sizeof(u64);
142 n_grps++;157 n_grps++;
143 }158 }
159 if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask)) {
160 n_stats += sizeof(struct ethtool_rmon_stats) / sizeof(u64);
161 n_grps++;
162 /* Above includes the space for _A_STATS_GRP_HIST_VALs */
163
164 len += (nla_total_size(0) + /* _A_STATS_GRP_HIST */
165 nla_total_size(4) + /* _A_STATS_GRP_HIST_BKT_LOW */
166 nla_total_size(4)) * /* _A_STATS_GRP_HIST_BKT_HI */
167 ETHTOOL_RMON_HIST_MAX * 2;
168 }
144 169
145 len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */170 len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
146 nla_total_size(4) + /* _A_STATS_GRP_ID */171 nla_total_size(4) + /* _A_STATS_GRP_ID */
@@ -258,6 +283,65 @@ static int stats_put_ctrl_stats(struct sk_buff *skb, · 111 unmodified lines
258 return 0;283 return 0;
259}284}
260 285
286static int stats_put_rmon_hist(struct sk_buff *skb, u32 attr, const u64 *hist,
287 const struct ethtool_rmon_hist_range *ranges)
288{
289 struct nlattr *nest;
290 int i;
291
292 if (!ranges)
293 return 0;
294
295 for (i = 0; i < ETHTOOL_RMON_HIST_MAX; i++) {
296 if (!ranges[i].low && !ranges[i].high)
297 break;
298 if (hist[i] == ETHTOOL_STAT_NOT_SET)
299 continue;
300
301 nest = nla_nest_start(skb, attr);
302 if (!nest)
303 return -EMSGSIZE;
304
305 if (nla_put_u32(skb, ETHTOOL_A_STATS_GRP_HIST_BKT_LOW,
306 ranges[i].low) ||
307 nla_put_u32(skb, ETHTOOL_A_STATS_GRP_HIST_BKT_HI,
308 ranges[i].high) ||
309 nla_put_u64_64bit(skb, ETHTOOL_A_STATS_GRP_HIST_VAL,
310 hist[i], ETHTOOL_A_STATS_GRP_PAD))
311 goto err_cancel_hist;
312
313 nla_nest_end(skb, nest);
314 }
315
316 return 0;
317
318err_cancel_hist:
319 nla_nest_cancel(skb, nest);
320 return -EMSGSIZE;
321}
322
323static int stats_put_rmon_stats(struct sk_buff *skb,
324 const struct stats_reply_data *data)
325{
326 if (stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_RX,
327 data->rmon_stats.hist, data->rmon_ranges) ||
328 stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_TX,
329 data->rmon_stats.hist_tx, data->rmon_ranges))
330 return -EMSGSIZE;
331
332 if (stat_put(skb, ETHTOOL_A_STATS_RMON_UNDERSIZE,
333 data->rmon_stats.undersize_pkts) ||
334 stat_put(skb, ETHTOOL_A_STATS_RMON_OVERSIZE,
335 data->rmon_stats.oversize_pkts) ||
336 stat_put(skb, ETHTOOL_A_STATS_RMON_FRAG,
337 data->rmon_stats.fragments) ||
338 stat_put(skb, ETHTOOL_A_STATS_RMON_JABBER,
339 data->rmon_stats.jabbers))
340 return -EMSGSIZE;
341
342 return 0;
343}
344
261static int stats_put_stats(struct sk_buff *skb,345static int stats_put_stats(struct sk_buff *skb,
262 const struct stats_reply_data *data,346 const struct stats_reply_data *data,
263 u32 id, u32 ss_id,347 u32 id, u32 ss_id,
@@ -305,6 +389,9 @@ static int stats_fill_reply(struct sk_buff *skb, · 41 unmodified lines
305 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_CTRL,389 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_CTRL,
306 ETH_SS_STATS_ETH_CTRL,390 ETH_SS_STATS_ETH_CTRL,
307 stats_put_ctrl_stats);391 stats_put_ctrl_stats);
392 if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask))
393 ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON,
394 ETH_SS_STATS_RMON, stats_put_rmon_stats);
308 395
309 return ret;396 return ret;
310}397}
net/ethtool/strset.c+5−0
@@ -100,6 +100,11 @@ static const struct strset_info info_template[] = { · 99 unmodified lines
100 .count = __ETHTOOL_A_STATS_ETH_CTRL_CNT,100 .count = __ETHTOOL_A_STATS_ETH_CTRL_CNT,
101 .strings = stats_eth_ctrl_names,101 .strings = stats_eth_ctrl_names,
102 },102 },
103 [ETH_SS_STATS_RMON] = {
104 .per_dev = false,
105 .count = __ETHTOOL_A_STATS_RMON_CNT,
106 .strings = stats_rmon_names,
107 },
103};108};
104 109
105struct strset_req_info {110struct strset_req_info {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t