]> Git Repo - linux.git/blob - net/ethtool/stats.c
Linux 6.14-rc3
[linux.git] / net / ethtool / stats.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include <linux/phy.h>
4 #include <linux/phylib_stubs.h>
5
6 #include "netlink.h"
7 #include "common.h"
8 #include "bitset.h"
9
10 struct stats_req_info {
11         struct ethnl_req_info           base;
12         DECLARE_BITMAP(stat_mask, __ETHTOOL_STATS_CNT);
13         enum ethtool_mac_stats_src      src;
14 };
15
16 #define STATS_REQINFO(__req_base) \
17         container_of(__req_base, struct stats_req_info, base)
18
19 struct stats_reply_data {
20         struct ethnl_reply_data         base;
21         struct_group(stats,
22                 struct ethtool_eth_phy_stats    phy_stats;
23                 struct ethtool_eth_mac_stats    mac_stats;
24                 struct ethtool_eth_ctrl_stats   ctrl_stats;
25                 struct ethtool_rmon_stats       rmon_stats;
26                 struct ethtool_phy_stats        phydev_stats;
27         );
28         const struct ethtool_rmon_hist_range    *rmon_ranges;
29 };
30
31 #define STATS_REPDATA(__reply_base) \
32         container_of(__reply_base, struct stats_reply_data, base)
33
34 const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = {
35         [ETHTOOL_STATS_ETH_PHY]                 = "eth-phy",
36         [ETHTOOL_STATS_ETH_MAC]                 = "eth-mac",
37         [ETHTOOL_STATS_ETH_CTRL]                = "eth-ctrl",
38         [ETHTOOL_STATS_RMON]                    = "rmon",
39         [ETHTOOL_STATS_PHY]                     = "phydev",
40 };
41
42 const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {
43         [ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR]     = "SymbolErrorDuringCarrier",
44 };
45
46 const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN] = {
47         [ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT]      = "FramesTransmittedOK",
48         [ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL]  = "SingleCollisionFrames",
49         [ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL]   = "MultipleCollisionFrames",
50         [ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT]      = "FramesReceivedOK",
51         [ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR]     = "FrameCheckSequenceErrors",
52         [ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR]   = "AlignmentErrors",
53         [ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES]    = "OctetsTransmittedOK",
54         [ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER]    = "FramesWithDeferredXmissions",
55         [ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL]   = "LateCollisions",
56         [ETHTOOL_A_STATS_ETH_MAC_11_XS_COL]     = "FramesAbortedDueToXSColls",
57         [ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR] = "FramesLostDueToIntMACXmitError",
58         [ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR]     = "CarrierSenseErrors",
59         [ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES]   = "OctetsReceivedOK",
60         [ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR] = "FramesLostDueToIntMACRcvError",
61         [ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST]   = "MulticastFramesXmittedOK",
62         [ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST]   = "BroadcastFramesXmittedOK",
63         [ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER]   = "FramesWithExcessiveDeferral",
64         [ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST]   = "MulticastFramesReceivedOK",
65         [ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST]   = "BroadcastFramesReceivedOK",
66         [ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR] = "InRangeLengthErrors",
67         [ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN]    = "OutOfRangeLengthField",
68         [ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR]       = "FrameTooLongErrors",
69 };
70
71 const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN] = {
72         [ETHTOOL_A_STATS_ETH_CTRL_3_TX]         = "MACControlFramesTransmitted",
73         [ETHTOOL_A_STATS_ETH_CTRL_4_RX]         = "MACControlFramesReceived",
74         [ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP]   = "UnsupportedOpcodesReceived",
75 };
76
77 const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN] = {
78         [ETHTOOL_A_STATS_RMON_UNDERSIZE]        = "etherStatsUndersizePkts",
79         [ETHTOOL_A_STATS_RMON_OVERSIZE]         = "etherStatsOversizePkts",
80         [ETHTOOL_A_STATS_RMON_FRAG]             = "etherStatsFragments",
81         [ETHTOOL_A_STATS_RMON_JABBER]           = "etherStatsJabbers",
82 };
83
84 const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN] = {
85         [ETHTOOL_A_STATS_PHY_RX_PKTS]           = "RxFrames",
86         [ETHTOOL_A_STATS_PHY_RX_BYTES]          = "RxOctets",
87         [ETHTOOL_A_STATS_PHY_RX_ERRORS]         = "RxErrors",
88         [ETHTOOL_A_STATS_PHY_TX_PKTS]           = "TxFrames",
89         [ETHTOOL_A_STATS_PHY_TX_BYTES]          = "TxOctets",
90         [ETHTOOL_A_STATS_PHY_TX_ERRORS]         = "TxErrors",
91 };
92
93 const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_SRC + 1] = {
94         [ETHTOOL_A_STATS_HEADER]        =
95                 NLA_POLICY_NESTED(ethnl_header_policy),
96         [ETHTOOL_A_STATS_GROUPS]        = { .type = NLA_NESTED },
97         [ETHTOOL_A_STATS_SRC]           =
98                 NLA_POLICY_MAX(NLA_U32, ETHTOOL_MAC_STATS_SRC_PMAC),
99 };
100
101 static int stats_parse_request(struct ethnl_req_info *req_base,
102                                struct nlattr **tb,
103                                struct netlink_ext_ack *extack)
104 {
105         enum ethtool_mac_stats_src src = ETHTOOL_MAC_STATS_SRC_AGGREGATE;
106         struct stats_req_info *req_info = STATS_REQINFO(req_base);
107         bool mod = false;
108         int err;
109
110         err = ethnl_update_bitset(req_info->stat_mask, __ETHTOOL_STATS_CNT,
111                                   tb[ETHTOOL_A_STATS_GROUPS], stats_std_names,
112                                   extack, &mod);
113         if (err)
114                 return err;
115
116         if (!mod) {
117                 NL_SET_ERR_MSG(extack, "no stats requested");
118                 return -EINVAL;
119         }
120
121         if (tb[ETHTOOL_A_STATS_SRC])
122                 src = nla_get_u32(tb[ETHTOOL_A_STATS_SRC]);
123
124         req_info->src = src;
125
126         return 0;
127 }
128
129 static int stats_prepare_data(const struct ethnl_req_info *req_base,
130                               struct ethnl_reply_data *reply_base,
131                               const struct genl_info *info)
132 {
133         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
134         struct stats_reply_data *data = STATS_REPDATA(reply_base);
135         enum ethtool_mac_stats_src src = req_info->src;
136         struct net_device *dev = reply_base->dev;
137         struct nlattr **tb = info->attrs;
138         struct phy_device *phydev;
139         int ret;
140
141         phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_STATS_HEADER],
142                                       info->extack);
143         if (IS_ERR(phydev))
144                 return PTR_ERR(phydev);
145
146         ret = ethnl_ops_begin(dev);
147         if (ret < 0)
148                 return ret;
149
150         if ((src == ETHTOOL_MAC_STATS_SRC_EMAC ||
151              src == ETHTOOL_MAC_STATS_SRC_PMAC) &&
152             !__ethtool_dev_mm_supported(dev)) {
153                 NL_SET_ERR_MSG_MOD(info->extack,
154                                    "Device does not support MAC merge layer");
155                 ethnl_ops_complete(dev);
156                 return -EOPNOTSUPP;
157         }
158
159         /* Mark all stats as unset (see ETHTOOL_STAT_NOT_SET) to prevent them
160          * from being reported to user space in case driver did not set them.
161          */
162         memset(&data->stats, 0xff, sizeof(data->stats));
163
164         data->phy_stats.src = src;
165         data->mac_stats.src = src;
166         data->ctrl_stats.src = src;
167         data->rmon_stats.src = src;
168
169         if ((test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask) ||
170              test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask)) &&
171             src == ETHTOOL_MAC_STATS_SRC_AGGREGATE) {
172                 if (phydev)
173                         phy_ethtool_get_phy_stats(phydev, &data->phy_stats,
174                                                   &data->phydev_stats);
175         }
176
177         if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
178             dev->ethtool_ops->get_eth_phy_stats)
179                 dev->ethtool_ops->get_eth_phy_stats(dev, &data->phy_stats);
180         if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask) &&
181             dev->ethtool_ops->get_eth_mac_stats)
182                 dev->ethtool_ops->get_eth_mac_stats(dev, &data->mac_stats);
183         if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask) &&
184             dev->ethtool_ops->get_eth_ctrl_stats)
185                 dev->ethtool_ops->get_eth_ctrl_stats(dev, &data->ctrl_stats);
186         if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask) &&
187             dev->ethtool_ops->get_rmon_stats)
188                 dev->ethtool_ops->get_rmon_stats(dev, &data->rmon_stats,
189                                                  &data->rmon_ranges);
190
191         ethnl_ops_complete(dev);
192         return 0;
193 }
194
195 static int stats_reply_size(const struct ethnl_req_info *req_base,
196                             const struct ethnl_reply_data *reply_base)
197 {
198         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
199         unsigned int n_grps = 0, n_stats = 0;
200         int len = 0;
201
202         len += nla_total_size(sizeof(u32)); /* _STATS_SRC */
203
204         if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask)) {
205                 n_stats += sizeof(struct ethtool_eth_phy_stats) / sizeof(u64);
206                 n_grps++;
207         }
208         if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask)) {
209                 n_stats += sizeof(struct ethtool_eth_mac_stats) / sizeof(u64);
210                 n_grps++;
211         }
212         if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask)) {
213                 n_stats += sizeof(struct ethtool_eth_ctrl_stats) / sizeof(u64);
214                 n_grps++;
215         }
216         if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask)) {
217                 n_stats += sizeof(struct ethtool_rmon_stats) / sizeof(u64);
218                 n_grps++;
219                 /* Above includes the space for _A_STATS_GRP_HIST_VALs */
220
221                 len += (nla_total_size(0) +     /* _A_STATS_GRP_HIST */
222                         nla_total_size(4) +     /* _A_STATS_GRP_HIST_BKT_LOW */
223                         nla_total_size(4)) *    /* _A_STATS_GRP_HIST_BKT_HI */
224                         ETHTOOL_RMON_HIST_MAX * 2;
225         }
226         if (test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask)) {
227                 n_stats += sizeof(struct ethtool_phy_stats) / sizeof(u64);
228                 n_grps++;
229         }
230
231         len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
232                          nla_total_size(4) + /* _A_STATS_GRP_ID */
233                          nla_total_size(4)); /* _A_STATS_GRP_SS_ID */
234         len += n_stats * (nla_total_size(0) + /* _A_STATS_GRP_STAT */
235                           nla_total_size_64bit(sizeof(u64)));
236
237         return len;
238 }
239
240 static int stat_put(struct sk_buff *skb, u16 attrtype, u64 val)
241 {
242         struct nlattr *nest;
243         int ret;
244
245         if (val == ETHTOOL_STAT_NOT_SET)
246                 return 0;
247
248         /* We want to start stats attr types from 0, so we don't have a type
249          * for pad inside ETHTOOL_A_STATS_GRP_STAT. Pad things on the outside
250          * of ETHTOOL_A_STATS_GRP_STAT. Since we're one nest away from the
251          * actual attr we're 4B off - nla_need_padding_for_64bit() & co.
252          * can't be used.
253          */
254 #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
255         if (!IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8))
256                 if (!nla_reserve(skb, ETHTOOL_A_STATS_GRP_PAD, 0))
257                         return -EMSGSIZE;
258 #endif
259
260         nest = nla_nest_start(skb, ETHTOOL_A_STATS_GRP_STAT);
261         if (!nest)
262                 return -EMSGSIZE;
263
264         ret = nla_put_u64_64bit(skb, attrtype, val, -1 /* not used */);
265         if (ret) {
266                 nla_nest_cancel(skb, nest);
267                 return ret;
268         }
269
270         nla_nest_end(skb, nest);
271         return 0;
272 }
273
274 static int stats_put_phy_stats(struct sk_buff *skb,
275                                const struct stats_reply_data *data)
276 {
277         if (stat_put(skb, ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR,
278                      data->phy_stats.SymbolErrorDuringCarrier))
279                 return -EMSGSIZE;
280         return 0;
281 }
282
283 static int stats_put_phydev_stats(struct sk_buff *skb,
284                                   const struct stats_reply_data *data)
285 {
286         if (stat_put(skb, ETHTOOL_A_STATS_PHY_RX_PKTS,
287                      data->phydev_stats.rx_packets) ||
288             stat_put(skb, ETHTOOL_A_STATS_PHY_RX_BYTES,
289                      data->phydev_stats.rx_bytes) ||
290             stat_put(skb, ETHTOOL_A_STATS_PHY_RX_ERRORS,
291                      data->phydev_stats.rx_errors) ||
292             stat_put(skb, ETHTOOL_A_STATS_PHY_TX_PKTS,
293                      data->phydev_stats.tx_packets) ||
294             stat_put(skb, ETHTOOL_A_STATS_PHY_TX_BYTES,
295                      data->phydev_stats.tx_bytes) ||
296             stat_put(skb, ETHTOOL_A_STATS_PHY_TX_ERRORS,
297                      data->phydev_stats.tx_errors))
298                 return -EMSGSIZE;
299         return 0;
300 }
301
302 static int stats_put_mac_stats(struct sk_buff *skb,
303                                const struct stats_reply_data *data)
304 {
305         if (stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT,
306                      data->mac_stats.FramesTransmittedOK) ||
307             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL,
308                      data->mac_stats.SingleCollisionFrames) ||
309             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL,
310                      data->mac_stats.MultipleCollisionFrames) ||
311             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT,
312                      data->mac_stats.FramesReceivedOK) ||
313             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR,
314                      data->mac_stats.FrameCheckSequenceErrors) ||
315             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR,
316                      data->mac_stats.AlignmentErrors) ||
317             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES,
318                      data->mac_stats.OctetsTransmittedOK) ||
319             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER,
320                      data->mac_stats.FramesWithDeferredXmissions) ||
321             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL,
322                      data->mac_stats.LateCollisions) ||
323             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_11_XS_COL,
324                      data->mac_stats.FramesAbortedDueToXSColls) ||
325             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR,
326                      data->mac_stats.FramesLostDueToIntMACXmitError) ||
327             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR,
328                      data->mac_stats.CarrierSenseErrors) ||
329             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES,
330                      data->mac_stats.OctetsReceivedOK) ||
331             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR,
332                      data->mac_stats.FramesLostDueToIntMACRcvError) ||
333             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST,
334                      data->mac_stats.MulticastFramesXmittedOK) ||
335             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST,
336                      data->mac_stats.BroadcastFramesXmittedOK) ||
337             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER,
338                      data->mac_stats.FramesWithExcessiveDeferral) ||
339             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST,
340                      data->mac_stats.MulticastFramesReceivedOK) ||
341             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST,
342                      data->mac_stats.BroadcastFramesReceivedOK) ||
343             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR,
344                      data->mac_stats.InRangeLengthErrors) ||
345             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN,
346                      data->mac_stats.OutOfRangeLengthField) ||
347             stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR,
348                      data->mac_stats.FrameTooLongErrors))
349                 return -EMSGSIZE;
350         return 0;
351 }
352
353 static int stats_put_ctrl_stats(struct sk_buff *skb,
354                                 const struct stats_reply_data *data)
355 {
356         if (stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_3_TX,
357                      data->ctrl_stats.MACControlFramesTransmitted) ||
358             stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_4_RX,
359                      data->ctrl_stats.MACControlFramesReceived) ||
360             stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP,
361                      data->ctrl_stats.UnsupportedOpcodesReceived))
362                 return -EMSGSIZE;
363         return 0;
364 }
365
366 static int stats_put_rmon_hist(struct sk_buff *skb, u32 attr, const u64 *hist,
367                                const struct ethtool_rmon_hist_range *ranges)
368 {
369         struct nlattr *nest;
370         int i;
371
372         if (!ranges)
373                 return 0;
374
375         for (i = 0; i < ETHTOOL_RMON_HIST_MAX; i++) {
376                 if (!ranges[i].low && !ranges[i].high)
377                         break;
378                 if (hist[i] == ETHTOOL_STAT_NOT_SET)
379                         continue;
380
381                 nest = nla_nest_start(skb, attr);
382                 if (!nest)
383                         return -EMSGSIZE;
384
385                 if (nla_put_u32(skb, ETHTOOL_A_STATS_GRP_HIST_BKT_LOW,
386                                 ranges[i].low) ||
387                     nla_put_u32(skb, ETHTOOL_A_STATS_GRP_HIST_BKT_HI,
388                                 ranges[i].high) ||
389                     nla_put_u64_64bit(skb, ETHTOOL_A_STATS_GRP_HIST_VAL,
390                                       hist[i], ETHTOOL_A_STATS_GRP_PAD))
391                         goto err_cancel_hist;
392
393                 nla_nest_end(skb, nest);
394         }
395
396         return 0;
397
398 err_cancel_hist:
399         nla_nest_cancel(skb, nest);
400         return -EMSGSIZE;
401 }
402
403 static int stats_put_rmon_stats(struct sk_buff *skb,
404                                 const struct stats_reply_data *data)
405 {
406         if (stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_RX,
407                                 data->rmon_stats.hist, data->rmon_ranges) ||
408             stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_TX,
409                                 data->rmon_stats.hist_tx, data->rmon_ranges))
410                 return -EMSGSIZE;
411
412         if (stat_put(skb, ETHTOOL_A_STATS_RMON_UNDERSIZE,
413                      data->rmon_stats.undersize_pkts) ||
414             stat_put(skb, ETHTOOL_A_STATS_RMON_OVERSIZE,
415                      data->rmon_stats.oversize_pkts) ||
416             stat_put(skb, ETHTOOL_A_STATS_RMON_FRAG,
417                      data->rmon_stats.fragments) ||
418             stat_put(skb, ETHTOOL_A_STATS_RMON_JABBER,
419                      data->rmon_stats.jabbers))
420                 return -EMSGSIZE;
421
422         return 0;
423 }
424
425 static int stats_put_stats(struct sk_buff *skb,
426                            const struct stats_reply_data *data,
427                            u32 id, u32 ss_id,
428                            int (*cb)(struct sk_buff *skb,
429                                      const struct stats_reply_data *data))
430 {
431         struct nlattr *nest;
432
433         nest = nla_nest_start(skb, ETHTOOL_A_STATS_GRP);
434         if (!nest)
435                 return -EMSGSIZE;
436
437         if (nla_put_u32(skb, ETHTOOL_A_STATS_GRP_ID, id) ||
438             nla_put_u32(skb, ETHTOOL_A_STATS_GRP_SS_ID, ss_id))
439                 goto err_cancel;
440
441         if (cb(skb, data))
442                 goto err_cancel;
443
444         nla_nest_end(skb, nest);
445         return 0;
446
447 err_cancel:
448         nla_nest_cancel(skb, nest);
449         return -EMSGSIZE;
450 }
451
452 static int stats_fill_reply(struct sk_buff *skb,
453                             const struct ethnl_req_info *req_base,
454                             const struct ethnl_reply_data *reply_base)
455 {
456         const struct stats_req_info *req_info = STATS_REQINFO(req_base);
457         const struct stats_reply_data *data = STATS_REPDATA(reply_base);
458         int ret = 0;
459
460         if (nla_put_u32(skb, ETHTOOL_A_STATS_SRC, req_info->src))
461                 return -EMSGSIZE;
462
463         if (!ret && test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask))
464                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_PHY,
465                                       ETH_SS_STATS_ETH_PHY,
466                                       stats_put_phy_stats);
467         if (!ret && test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask))
468                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_MAC,
469                                       ETH_SS_STATS_ETH_MAC,
470                                       stats_put_mac_stats);
471         if (!ret && test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask))
472                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_CTRL,
473                                       ETH_SS_STATS_ETH_CTRL,
474                                       stats_put_ctrl_stats);
475         if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask))
476                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON,
477                                       ETH_SS_STATS_RMON, stats_put_rmon_stats);
478         if (!ret && test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask))
479                 ret = stats_put_stats(skb, data, ETHTOOL_STATS_PHY,
480                                       ETH_SS_STATS_PHY, stats_put_phydev_stats);
481
482         return ret;
483 }
484
485 const struct ethnl_request_ops ethnl_stats_request_ops = {
486         .request_cmd            = ETHTOOL_MSG_STATS_GET,
487         .reply_cmd              = ETHTOOL_MSG_STATS_GET_REPLY,
488         .hdr_attr               = ETHTOOL_A_STATS_HEADER,
489         .req_info_size          = sizeof(struct stats_req_info),
490         .reply_data_size        = sizeof(struct stats_reply_data),
491
492         .parse_request          = stats_parse_request,
493         .prepare_data           = stats_prepare_data,
494         .reply_size             = stats_reply_size,
495         .fill_reply             = stats_fill_reply,
496 };
497
498 static u64 ethtool_stats_sum(u64 a, u64 b)
499 {
500         if (a == ETHTOOL_STAT_NOT_SET)
501                 return b;
502         if (b == ETHTOOL_STAT_NOT_SET)
503                 return a;
504         return a + b;
505 }
506
507 /* Avoid modifying the aggregation procedure every time a new counter is added
508  * by treating the structures as an array of u64 statistics.
509  */
510 static void ethtool_aggregate_stats(void *aggr_stats, const void *emac_stats,
511                                     const void *pmac_stats, size_t stats_size,
512                                     size_t stats_offset)
513 {
514         size_t num_stats = stats_size / sizeof(u64);
515         const u64 *s1 = emac_stats + stats_offset;
516         const u64 *s2 = pmac_stats + stats_offset;
517         u64 *s = aggr_stats + stats_offset;
518         int i;
519
520         for (i = 0; i < num_stats; i++)
521                 s[i] = ethtool_stats_sum(s1[i], s2[i]);
522 }
523
524 void ethtool_aggregate_mac_stats(struct net_device *dev,
525                                  struct ethtool_eth_mac_stats *mac_stats)
526 {
527         const struct ethtool_ops *ops = dev->ethtool_ops;
528         struct ethtool_eth_mac_stats pmac, emac;
529
530         memset(&emac, 0xff, sizeof(emac));
531         memset(&pmac, 0xff, sizeof(pmac));
532         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
533         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
534
535         ops->get_eth_mac_stats(dev, &emac);
536         ops->get_eth_mac_stats(dev, &pmac);
537
538         ethtool_aggregate_stats(mac_stats, &emac, &pmac,
539                                 sizeof(mac_stats->stats),
540                                 offsetof(struct ethtool_eth_mac_stats, stats));
541 }
542 EXPORT_SYMBOL(ethtool_aggregate_mac_stats);
543
544 void ethtool_aggregate_phy_stats(struct net_device *dev,
545                                  struct ethtool_eth_phy_stats *phy_stats)
546 {
547         const struct ethtool_ops *ops = dev->ethtool_ops;
548         struct ethtool_eth_phy_stats pmac, emac;
549
550         memset(&emac, 0xff, sizeof(emac));
551         memset(&pmac, 0xff, sizeof(pmac));
552         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
553         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
554
555         ops->get_eth_phy_stats(dev, &emac);
556         ops->get_eth_phy_stats(dev, &pmac);
557
558         ethtool_aggregate_stats(phy_stats, &emac, &pmac,
559                                 sizeof(phy_stats->stats),
560                                 offsetof(struct ethtool_eth_phy_stats, stats));
561 }
562 EXPORT_SYMBOL(ethtool_aggregate_phy_stats);
563
564 void ethtool_aggregate_ctrl_stats(struct net_device *dev,
565                                   struct ethtool_eth_ctrl_stats *ctrl_stats)
566 {
567         const struct ethtool_ops *ops = dev->ethtool_ops;
568         struct ethtool_eth_ctrl_stats pmac, emac;
569
570         memset(&emac, 0xff, sizeof(emac));
571         memset(&pmac, 0xff, sizeof(pmac));
572         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
573         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
574
575         ops->get_eth_ctrl_stats(dev, &emac);
576         ops->get_eth_ctrl_stats(dev, &pmac);
577
578         ethtool_aggregate_stats(ctrl_stats, &emac, &pmac,
579                                 sizeof(ctrl_stats->stats),
580                                 offsetof(struct ethtool_eth_ctrl_stats, stats));
581 }
582 EXPORT_SYMBOL(ethtool_aggregate_ctrl_stats);
583
584 void ethtool_aggregate_pause_stats(struct net_device *dev,
585                                    struct ethtool_pause_stats *pause_stats)
586 {
587         const struct ethtool_ops *ops = dev->ethtool_ops;
588         struct ethtool_pause_stats pmac, emac;
589
590         memset(&emac, 0xff, sizeof(emac));
591         memset(&pmac, 0xff, sizeof(pmac));
592         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
593         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
594
595         ops->get_pause_stats(dev, &emac);
596         ops->get_pause_stats(dev, &pmac);
597
598         ethtool_aggregate_stats(pause_stats, &emac, &pmac,
599                                 sizeof(pause_stats->stats),
600                                 offsetof(struct ethtool_pause_stats, stats));
601 }
602 EXPORT_SYMBOL(ethtool_aggregate_pause_stats);
603
604 void ethtool_aggregate_rmon_stats(struct net_device *dev,
605                                   struct ethtool_rmon_stats *rmon_stats)
606 {
607         const struct ethtool_ops *ops = dev->ethtool_ops;
608         const struct ethtool_rmon_hist_range *dummy;
609         struct ethtool_rmon_stats pmac, emac;
610
611         memset(&emac, 0xff, sizeof(emac));
612         memset(&pmac, 0xff, sizeof(pmac));
613         emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
614         pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
615
616         ops->get_rmon_stats(dev, &emac, &dummy);
617         ops->get_rmon_stats(dev, &pmac, &dummy);
618
619         ethtool_aggregate_stats(rmon_stats, &emac, &pmac,
620                                 sizeof(rmon_stats->stats),
621                                 offsetof(struct ethtool_rmon_stats, stats));
622 }
623 EXPORT_SYMBOL(ethtool_aggregate_rmon_stats);
This page took 0.07305 seconds and 4 git commands to generate.