Merge tag 'nfsd-5.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
[linux-2.6-microblaze.git] / net / ethtool / stats.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include "netlink.h"
4 #include "common.h"
5 #include "bitset.h"
6
7 struct stats_req_info {
8         struct ethnl_req_info           base;
9         DECLARE_BITMAP(stat_mask, __ETHTOOL_STATS_CNT);
10 };
11
12 #define STATS_REQINFO(__req_base) \
13         container_of(__req_base, struct stats_req_info, base)
14
15 struct stats_reply_data {
16         struct ethnl_reply_data         base;
17         struct_group(stats,
18                 struct ethtool_eth_phy_stats    phy_stats;
19                 struct ethtool_eth_mac_stats    mac_stats;
20                 struct ethtool_eth_ctrl_stats   ctrl_stats;
21                 struct ethtool_rmon_stats       rmon_stats;
22         );
23         const struct ethtool_rmon_hist_range    *rmon_ranges;
24 };
25
26 #define STATS_REPDATA(__reply_base) \
27         container_of(__reply_base, struct stats_reply_data, base)
28
29 const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = {
30         [ETHTOOL_STATS_ETH_PHY]                 = "eth-phy",
31         [ETHTOOL_STATS_ETH_MAC]                 = "eth-mac",
32         [ETHTOOL_STATS_ETH_CTRL]                = "eth-ctrl",
33         [ETHTOOL_STATS_RMON]                    = "rmon",
34 };
35
36 const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {
37         [ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR]     = "SymbolErrorDuringCarrier",
38 };
39
40 const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN] = {
41         [ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT]      = "FramesTransmittedOK",
42         [ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL]  = "SingleCollisionFrames",
43         [ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL]   = "MultipleCollisionFrames",
44         [ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT]      = "FramesReceivedOK",
45         [ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR]     = "FrameCheckSequenceErrors",
46         [ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR]   = "AlignmentErrors",
47         [ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES]    = "OctetsTransmittedOK",
48         [ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER]    = "FramesWithDeferredXmissions",
49         [ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL]   = "LateCollisions",
50         [ETHTOOL_A_STATS_ETH_MAC_11_XS_COL]     = "FramesAbortedDueToXSColls",
51         [ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR] = "FramesLostDueToIntMACXmitError",
52         [ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR]     = "CarrierSenseErrors",
53         [ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES]   = "OctetsReceivedOK",
54         [ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR] = "FramesLostDueToIntMACRcvError",
55         [ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST]   = "MulticastFramesXmittedOK",
56         [ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST]   = "BroadcastFramesXmittedOK",
57         [ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER]   = "FramesWithExcessiveDeferral",
58         [ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST]   = "MulticastFramesReceivedOK",
59         [ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST]   = "BroadcastFramesReceivedOK",
60         [ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR] = "InRangeLengthErrors",
61         [ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN]    = "OutOfRangeLengthField",
62         [ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR]       = "FrameTooLongErrors",
63 };
64
65 const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN] = {
66         [ETHTOOL_A_STATS_ETH_CTRL_3_TX]         = "MACControlFramesTransmitted",
67         [ETHTOOL_A_STATS_ETH_CTRL_4_RX]         = "MACControlFramesReceived",
68         [ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP]   = "UnsupportedOpcodesReceived",
69 };
70
71 const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN] = {
72         [ETHTOOL_A_STATS_RMON_UNDERSIZE]        = "etherStatsUndersizePkts",
73         [ETHTOOL_A_STATS_RMON_OVERSIZE]         = "etherStatsOversizePkts",
74         [ETHTOOL_A_STATS_RMON_FRAG]             = "etherStatsFragments",
75         [ETHTOOL_A_STATS_RMON_JABBER]           = "etherStatsJabbers",
76 };
77
78 const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1] = {
79         [ETHTOOL_A_STATS_HEADER]        =
80                 NLA_POLICY_NESTED(ethnl_header_policy),
81         [ETHTOOL_A_STATS_GROUPS]        = { .type = NLA_NESTED },
82 };
83
84 static int stats_parse_request(struct ethnl_req_info *req_base,
85                                struct nlattr **tb,
86                                struct netlink_ext_ack *extack)
87 {
88         struct stats_req_info *req_info = STATS_REQINFO(req_base);
89         bool mod = false;
90         int err;
91
92         err = ethnl_update_bitset(req_info->stat_mask, __ETHTOOL_STATS_CNT,
93                                   tb[ETHTOOL_A_STATS_GROUPS], stats_std_names,
94                                   extack, &mod);
95         if (err)
96                 return err;
97
98         if (!mod) {
99                 NL_SET_ERR_MSG(extack, "no stats requested");
100                 return -EINVAL;
101         }
102
103         return 0;
104 }
105
106 static int stats_prepare_data(const struct ethnl_req_info *req_base,
107                               struct ethnl_reply_data *reply_base,
108                               struct genl_info *info)
109 {
110         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
111         struct stats_reply_data *data = STATS_REPDATA(reply_base);
112         struct net_device *dev = reply_base->dev;
113         int ret;
114
115         ret = ethnl_ops_begin(dev);
116         if (ret < 0)
117                 return ret;
118
119         /* Mark all stats as unset (see ETHTOOL_STAT_NOT_SET) to prevent them
120          * from being reported to user space in case driver did not set them.
121          */
122         memset(&data->stats, 0xff, sizeof(data->stats));
123
124         if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
125             dev->ethtool_ops->get_eth_phy_stats)
126                 dev->ethtool_ops->get_eth_phy_stats(dev, &data->phy_stats);
127         if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask) &&
128             dev->ethtool_ops->get_eth_mac_stats)
129                 dev->ethtool_ops->get_eth_mac_stats(dev, &data->mac_stats);
130         if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask) &&
131             dev->ethtool_ops->get_eth_ctrl_stats)
132                 dev->ethtool_ops->get_eth_ctrl_stats(dev, &data->ctrl_stats);
133         if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask) &&
134             dev->ethtool_ops->get_rmon_stats)
135                 dev->ethtool_ops->get_rmon_stats(dev, &data->rmon_stats,
136                                                  &data->rmon_ranges);
137
138         ethnl_ops_complete(dev);
139         return 0;
140 }
141
142 static int stats_reply_size(const struct ethnl_req_info *req_base,
143                             const struct ethnl_reply_data *reply_base)
144 {
145         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
146         unsigned int n_grps = 0, n_stats = 0;
147         int len = 0;
148
149         if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask)) {
150                 n_stats += sizeof(struct ethtool_eth_phy_stats) / sizeof(u64);
151                 n_grps++;
152         }
153         if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask)) {
154                 n_stats += sizeof(struct ethtool_eth_mac_stats) / sizeof(u64);
155                 n_grps++;
156         }
157         if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask)) {
158                 n_stats += sizeof(struct ethtool_eth_ctrl_stats) / sizeof(u64);
159                 n_grps++;
160         }
161         if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask)) {
162                 n_stats += sizeof(struct ethtool_rmon_stats) / sizeof(u64);
163                 n_grps++;
164                 /* Above includes the space for _A_STATS_GRP_HIST_VALs */
165
166                 len += (nla_total_size(0) +     /* _A_STATS_GRP_HIST */
167                         nla_total_size(4) +     /* _A_STATS_GRP_HIST_BKT_LOW */
168                         nla_total_size(4)) *    /* _A_STATS_GRP_HIST_BKT_HI */
169                         ETHTOOL_RMON_HIST_MAX * 2;
170         }
171
172         len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
173                          nla_total_size(4) + /* _A_STATS_GRP_ID */
174                          nla_total_size(4)); /* _A_STATS_GRP_SS_ID */
175         len += n_stats * (nla_total_size(0) + /* _A_STATS_GRP_STAT */
176                           nla_total_size_64bit(sizeof(u64)));
177
178         return len;
179 }
180
181 static int stat_put(struct sk_buff *skb, u16 attrtype, u64 val)
182 {
183         struct nlattr *nest;
184         int ret;
185
186         if (val == ETHTOOL_STAT_NOT_SET)
187                 return 0;
188
189         /* We want to start stats attr types from 0, so we don't have a type
190          * for pad inside ETHTOOL_A_STATS_GRP_STAT. Pad things on the outside
191          * of ETHTOOL_A_STATS_GRP_STAT. Since we're one nest away from the
192          * actual attr we're 4B off - nla_need_padding_for_64bit() & co.
193          * can't be used.
194          */
195 #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
196         if (!IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8))
197                 if (!nla_reserve(skb, ETHTOOL_A_STATS_GRP_PAD, 0))
198                         return -EMSGSIZE;
199 #endif
200
201         nest = nla_nest_start(skb, ETHTOOL_A_STATS_GRP_STAT);
202         if (!nest)
203                 return -EMSGSIZE;
204
205         ret = nla_put_u64_64bit(skb, attrtype, val, -1 /* not used */);
206         if (ret) {
207                 nla_nest_cancel(skb, nest);
208                 return ret;
209         }
210
211         nla_nest_end(skb, nest);
212         return 0;
213 }
214
215 static int stats_put_phy_stats(struct sk_buff *skb,
216                                const struct stats_reply_data *data)
217 {
218         if (stat_put(skb, ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR,
219                      data->phy_stats.SymbolErrorDuringCarrier))
220                 return -EMSGSIZE;
221         return 0;
222 }
223
224 static int stats_put_mac_stats(struct sk_buff *skb,
225                                const struct stats_reply_data *data)
226 {
227         if (stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT,
228                      data->mac_stats.FramesTransmittedOK) ||
229             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL,
230                      data->mac_stats.SingleCollisionFrames) ||
231             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL,
232                      data->mac_stats.MultipleCollisionFrames) ||
233             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT,
234                      data->mac_stats.FramesReceivedOK) ||
235             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR,
236                      data->mac_stats.FrameCheckSequenceErrors) ||
237             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR,
238                      data->mac_stats.AlignmentErrors) ||
239             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES,
240                      data->mac_stats.OctetsTransmittedOK) ||
241             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER,
242                      data->mac_stats.FramesWithDeferredXmissions) ||
243             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL,
244                      data->mac_stats.LateCollisions) ||
245             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_11_XS_COL,
246                      data->mac_stats.FramesAbortedDueToXSColls) ||
247             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR,
248                      data->mac_stats.FramesLostDueToIntMACXmitError) ||
249             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR,
250                      data->mac_stats.CarrierSenseErrors) ||
251             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES,
252                      data->mac_stats.OctetsReceivedOK) ||
253             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR,
254                      data->mac_stats.FramesLostDueToIntMACRcvError) ||
255             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST,
256                      data->mac_stats.MulticastFramesXmittedOK) ||
257             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST,
258                      data->mac_stats.BroadcastFramesXmittedOK) ||
259             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER,
260                      data->mac_stats.FramesWithExcessiveDeferral) ||
261             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST,
262                      data->mac_stats.MulticastFramesReceivedOK) ||
263             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST,
264                      data->mac_stats.BroadcastFramesReceivedOK) ||
265             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR,
266                      data->mac_stats.InRangeLengthErrors) ||
267             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN,
268                      data->mac_stats.OutOfRangeLengthField) ||
269             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR,
270                      data->mac_stats.FrameTooLongErrors))
271                 return -EMSGSIZE;
272         return 0;
273 }
274
275 static int stats_put_ctrl_stats(struct sk_buff *skb,
276                                 const struct stats_reply_data *data)
277 {
278         if (stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_3_TX,
279                      data->ctrl_stats.MACControlFramesTransmitted) ||
280             stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_4_RX,
281                      data->ctrl_stats.MACControlFramesReceived) ||
282             stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP,
283                      data->ctrl_stats.UnsupportedOpcodesReceived))
284                 return -EMSGSIZE;
285         return 0;
286 }
287
288 static int stats_put_rmon_hist(struct sk_buff *skb, u32 attr, const u64 *hist,
289                                const struct ethtool_rmon_hist_range *ranges)
290 {
291         struct nlattr *nest;
292         int i;
293
294         if (!ranges)
295                 return 0;
296
297         for (i = 0; i < ETHTOOL_RMON_HIST_MAX; i++) {
298                 if (!ranges[i].low && !ranges[i].high)
299                         break;
300                 if (hist[i] == ETHTOOL_STAT_NOT_SET)
301                         continue;
302
303                 nest = nla_nest_start(skb, attr);
304                 if (!nest)
305                         return -EMSGSIZE;
306
307                 if (nla_put_u32(skb, ETHTOOL_A_STATS_GRP_HIST_BKT_LOW,
308                                 ranges[i].low) ||
309                     nla_put_u32(skb, ETHTOOL_A_STATS_GRP_HIST_BKT_HI,
310                                 ranges[i].high) ||
311                     nla_put_u64_64bit(skb, ETHTOOL_A_STATS_GRP_HIST_VAL,
312                                       hist[i], ETHTOOL_A_STATS_GRP_PAD))
313                         goto err_cancel_hist;
314
315                 nla_nest_end(skb, nest);
316         }
317
318         return 0;
319
320 err_cancel_hist:
321         nla_nest_cancel(skb, nest);
322         return -EMSGSIZE;
323 }
324
325 static int stats_put_rmon_stats(struct sk_buff *skb,
326                                 const struct stats_reply_data *data)
327 {
328         if (stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_RX,
329                                 data->rmon_stats.hist, data->rmon_ranges) ||
330             stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_TX,
331                                 data->rmon_stats.hist_tx, data->rmon_ranges))
332                 return -EMSGSIZE;
333
334         if (stat_put(skb, ETHTOOL_A_STATS_RMON_UNDERSIZE,
335                      data->rmon_stats.undersize_pkts) ||
336             stat_put(skb, ETHTOOL_A_STATS_RMON_OVERSIZE,
337                      data->rmon_stats.oversize_pkts) ||
338             stat_put(skb, ETHTOOL_A_STATS_RMON_FRAG,
339                      data->rmon_stats.fragments) ||
340             stat_put(skb, ETHTOOL_A_STATS_RMON_JABBER,
341                      data->rmon_stats.jabbers))
342                 return -EMSGSIZE;
343
344         return 0;
345 }
346
347 static int stats_put_stats(struct sk_buff *skb,
348                            const struct stats_reply_data *data,
349                            u32 id, u32 ss_id,
350                            int (*cb)(struct sk_buff *skb,
351                                      const struct stats_reply_data *data))
352 {
353         struct nlattr *nest;
354
355         nest = nla_nest_start(skb, ETHTOOL_A_STATS_GRP);
356         if (!nest)
357                 return -EMSGSIZE;
358
359         if (nla_put_u32(skb, ETHTOOL_A_STATS_GRP_ID, id) ||
360             nla_put_u32(skb, ETHTOOL_A_STATS_GRP_SS_ID, ss_id))
361                 goto err_cancel;
362
363         if (cb(skb, data))
364                 goto err_cancel;
365
366         nla_nest_end(skb, nest);
367         return 0;
368
369 err_cancel:
370         nla_nest_cancel(skb, nest);
371         return -EMSGSIZE;
372 }
373
374 static int stats_fill_reply(struct sk_buff *skb,
375                             const struct ethnl_req_info *req_base,
376                             const struct ethnl_reply_data *reply_base)
377 {
378         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
379         const struct stats_reply_data *data = STATS_REPDATA(reply_base);
380         int ret = 0;
381
382         if (!ret && test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask))
383                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_PHY,
384                                       ETH_SS_STATS_ETH_PHY,
385                                       stats_put_phy_stats);
386         if (!ret && test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask))
387                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_MAC,
388                                       ETH_SS_STATS_ETH_MAC,
389                                       stats_put_mac_stats);
390         if (!ret && test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask))
391                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_CTRL,
392                                       ETH_SS_STATS_ETH_CTRL,
393                                       stats_put_ctrl_stats);
394         if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask))
395                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON,
396                                       ETH_SS_STATS_RMON, stats_put_rmon_stats);
397
398         return ret;
399 }
400
401 const struct ethnl_request_ops ethnl_stats_request_ops = {
402         .request_cmd            = ETHTOOL_MSG_STATS_GET,
403         .reply_cmd              = ETHTOOL_MSG_STATS_GET_REPLY,
404         .hdr_attr               = ETHTOOL_A_STATS_HEADER,
405         .req_info_size          = sizeof(struct stats_req_info),
406         .reply_data_size        = sizeof(struct stats_reply_data),
407
408         .parse_request          = stats_parse_request,
409         .prepare_data           = stats_prepare_data,
410         .reply_size             = stats_reply_size,
411         .fill_reply             = stats_fill_reply,
412 };