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
346346 } corrected_blocks, uncorrectable_blocks, corrected_bits;
347347 };
348348
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+ */
354+struct 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+ */
377+struct 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+
349387 #define ETH_MODULE_EEPROM_PAGE_LEN 128
350388 #define ETH_MODULE_MAX_I2C_ADDRESS 0x7f
351389
@@ -534,6 +572,8 @@ struct ethtool_module_eeprom { · 182 unmodified lines
534572 * @get_eth_phy_stats: Query some of the IEEE 802.3 PHY statistics.
535573 * @get_eth_mac_stats: Query some of the IEEE 802.3 MAC statistics.
536574 * @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.
537577 *
538578 * All operations are optional (i.e. the function pointer may be set
539579 * to %NULL) and callers must take this into account. Callers must
@@ -650,6 +690,9 @@ struct ethtool_ops { · 110 unmodified lines
650690 struct ethtool_eth_mac_stats *mac_stats);
651691 void (*get_eth_ctrl_stats)(struct net_device *dev,
652692 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);
653696 };
654697
655698 int 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
673673 * @ETH_SS_STATS_ETH_PHY: names of IEEE 802.3 PHY statistics
674674 * @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics
675675 * @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics
676+ * @ETH_SS_STATS_RMON: names of RMON statistics
676677 *
677678 * @ETH_SS_COUNT: number of defined string sets
678679 */
@@ -697,6 +698,7 @@ enum ethtool_stringset { · 18 unmodified lines
697698 ETH_SS_STATS_ETH_PHY,
698699 ETH_SS_STATS_ETH_MAC,
699700 ETH_SS_STATS_ETH_CTRL,
701+ ETH_SS_STATS_RMON,
700702
701703 /* add new constants above here */
702704 ETH_SS_COUNT
include/uapi/linux/ethtool_netlink.h+23−0
@@ -700,6 +700,7 @@ enum { · 699 unmodified lines
700700 ETHTOOL_STATS_ETH_PHY,
701701 ETHTOOL_STATS_ETH_MAC,
702702 ETHTOOL_STATS_ETH_CTRL,
703+ ETHTOOL_STATS_RMON,
703704
704705 /* add new constants above here */
705706 __ETHTOOL_STATS_CNT
@@ -714,6 +715,13 @@ enum { · 8 unmodified lines
714715
715716 ETHTOOL_A_STATS_GRP_STAT, /* nest */
716717
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+
717725 /* add new constants above here */
718726 __ETHTOOL_A_STATS_GRP_CNT,
719727 ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_CNT - 1)
@@ -793,6 +801,21 @@ enum { · 73 unmodified lines
793801 ETHTOOL_A_STATS_ETH_CTRL_MAX = (__ETHTOOL_A_STATS_ETH_CTRL_CNT - 1)
794802 };
795803
804+enum {
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+
796819 /* generic netlink info */
797820 #define ETHTOOL_GENL_NAME "ethtool"
798821 #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
405405 extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
406406 extern const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN];
407407 extern const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN];
408+extern const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN];
408409
409410 #endif /* _NET_ETHTOOL_NETLINK_H */
net/ethtool/stats.c+87−0
@@ -17,6 +17,8 @@ struct stats_reply_data { · 16 unmodified lines
1717 struct ethtool_eth_phy_stats phy_stats;
1818 struct ethtool_eth_mac_stats mac_stats;
1919 struct ethtool_eth_ctrl_stats ctrl_stats;
20+ struct ethtool_rmon_stats rmon_stats;
21+ const struct ethtool_rmon_hist_range *rmon_ranges;
2022 };
2123
2224 #define STATS_REPDATA(__reply_base) \
@@ -26,6 +28,7 @@ const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = { · 3 unmodified lines
2628 [ETHTOOL_STATS_ETH_PHY] = "eth-phy",
2729 [ETHTOOL_STATS_ETH_MAC] = "eth-mac",
2830 [ETHTOOL_STATS_ETH_CTRL] = "eth-ctrl",
31+ [ETHTOOL_STATS_RMON] = "rmon",
2932 };
3033
3134 const 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
6366 [ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP] = "UnsupportedOpcodesReceived",
6467 };
6568
69+const 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+
6676 const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1] = {
6777 [ETHTOOL_A_STATS_HEADER] =
6878 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
107117 memset(&data->phy_stats, 0xff, sizeof(data->phy_stats));
108118 memset(&data->mac_stats, 0xff, sizeof(data->mac_stats));
109119 memset(&data->ctrl_stats, 0xff, sizeof(data->mac_stats));
120+ memset(&data->rmon_stats, 0xff, sizeof(data->rmon_stats));
110121
111122 if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
112123 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
117128 if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask) &&
118129 dev->ethtool_ops->get_eth_ctrl_stats)
119130 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);
120135
121136 ethnl_ops_complete(dev);
122137 return 0;
@@ -141,6 +156,16 @@ static int stats_reply_size(const struct ethnl_req_info *req_base, · 18 unmodified lines
141156 n_stats += sizeof(struct ethtool_eth_ctrl_stats) / sizeof(u64);
142157 n_grps++;
143158 }
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+ }
144169
145170 len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
146171 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
258283 return 0;
259284 }
260285
286+static 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+
318+err_cancel_hist:
319+ nla_nest_cancel(skb, nest);
320+ return -EMSGSIZE;
321+}
322+
323+static 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+
261345 static int stats_put_stats(struct sk_buff *skb,
262346 const struct stats_reply_data *data,
263347 u32 id, u32 ss_id,
@@ -305,6 +389,9 @@ static int stats_fill_reply(struct sk_buff *skb, · 41 unmodified lines
305389 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_CTRL,
306390 ETH_SS_STATS_ETH_CTRL,
307391 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);
308395
309396 return ret;
310397 }
net/ethtool/strset.c+5−0
@@ -100,6 +100,11 @@ static const struct strset_info info_template[] = { · 99 unmodified lines
100100 .count = __ETHTOOL_A_STATS_ETH_CTRL_CNT,
101101 .strings = stats_eth_ctrl_names,
102102 },
103+ [ETH_SS_STATS_RMON] = {
104+ .per_dev = false,
105+ .count = __ETHTOOL_A_STATS_RMON_CNT,
106+ .strings = stats_rmon_names,
107+ },
103108 };
104109
105110 struct 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