Skip to content

Commit 449c545

Browse files
vladimirolteandavem330
authored andcommitted
net: ethtool: add helpers for aggregate statistics
When a pMAC exists but the driver is unable to atomically query the aggregate eMAC+pMAC statistics, the user should be given back at least the sum of eMAC and pMAC counters queried separately. This is a generic problem, so add helpers in ethtool to do this operation, if the driver doesn't have a better way to report aggregate stats. Do this in a way that does not require changes to these functions when new stats are added (basically treat the structures as an array of u64 values, except for the first element which is the stats source). In include/linux/ethtool.h, there is already a section where helper function prototypes should be placed. The trouble is, this section is too early, before the definitions of struct ethtool_eth_mac_stats et.al. Move that section at the end and append these new helpers to it. Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c319df1 commit 449c545

File tree

2 files changed

+187
-40
lines changed

2 files changed

+187
-40
lines changed

include/linux/ethtool.h

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,6 @@ enum ethtool_supported_ring_param {
106106
struct net_device;
107107
struct netlink_ext_ack;
108108

109-
/* Some generic methods drivers may use in their ethtool_ops */
110-
u32 ethtool_op_get_link(struct net_device *dev);
111-
int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *eti);
112-
113-
114109
/* Link extended state and substate. */
115110
struct ethtool_link_ext_state_info {
116111
enum ethtool_link_ext_state link_ext_state;
@@ -312,46 +307,52 @@ static inline void ethtool_stats_init(u64 *stats, unsigned int n)
312307
*/
313308
struct ethtool_eth_mac_stats {
314309
enum ethtool_mac_stats_src src;
315-
u64 FramesTransmittedOK;
316-
u64 SingleCollisionFrames;
317-
u64 MultipleCollisionFrames;
318-
u64 FramesReceivedOK;
319-
u64 FrameCheckSequenceErrors;
320-
u64 AlignmentErrors;
321-
u64 OctetsTransmittedOK;
322-
u64 FramesWithDeferredXmissions;
323-
u64 LateCollisions;
324-
u64 FramesAbortedDueToXSColls;
325-
u64 FramesLostDueToIntMACXmitError;
326-
u64 CarrierSenseErrors;
327-
u64 OctetsReceivedOK;
328-
u64 FramesLostDueToIntMACRcvError;
329-
u64 MulticastFramesXmittedOK;
330-
u64 BroadcastFramesXmittedOK;
331-
u64 FramesWithExcessiveDeferral;
332-
u64 MulticastFramesReceivedOK;
333-
u64 BroadcastFramesReceivedOK;
334-
u64 InRangeLengthErrors;
335-
u64 OutOfRangeLengthField;
336-
u64 FrameTooLongErrors;
310+
struct_group(stats,
311+
u64 FramesTransmittedOK;
312+
u64 SingleCollisionFrames;
313+
u64 MultipleCollisionFrames;
314+
u64 FramesReceivedOK;
315+
u64 FrameCheckSequenceErrors;
316+
u64 AlignmentErrors;
317+
u64 OctetsTransmittedOK;
318+
u64 FramesWithDeferredXmissions;
319+
u64 LateCollisions;
320+
u64 FramesAbortedDueToXSColls;
321+
u64 FramesLostDueToIntMACXmitError;
322+
u64 CarrierSenseErrors;
323+
u64 OctetsReceivedOK;
324+
u64 FramesLostDueToIntMACRcvError;
325+
u64 MulticastFramesXmittedOK;
326+
u64 BroadcastFramesXmittedOK;
327+
u64 FramesWithExcessiveDeferral;
328+
u64 MulticastFramesReceivedOK;
329+
u64 BroadcastFramesReceivedOK;
330+
u64 InRangeLengthErrors;
331+
u64 OutOfRangeLengthField;
332+
u64 FrameTooLongErrors;
333+
);
337334
};
338335

339336
/* Basic IEEE 802.3 PHY statistics (30.3.2.1.*), not otherwise exposed
340337
* via a more targeted API.
341338
*/
342339
struct ethtool_eth_phy_stats {
343340
enum ethtool_mac_stats_src src;
344-
u64 SymbolErrorDuringCarrier;
341+
struct_group(stats,
342+
u64 SymbolErrorDuringCarrier;
343+
);
345344
};
346345

347346
/* Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*), not otherwise exposed
348347
* via a more targeted API.
349348
*/
350349
struct ethtool_eth_ctrl_stats {
351350
enum ethtool_mac_stats_src src;
352-
u64 MACControlFramesTransmitted;
353-
u64 MACControlFramesReceived;
354-
u64 UnsupportedOpcodesReceived;
351+
struct_group(stats,
352+
u64 MACControlFramesTransmitted;
353+
u64 MACControlFramesReceived;
354+
u64 UnsupportedOpcodesReceived;
355+
);
355356
};
356357

357358
/**
@@ -372,8 +373,10 @@ struct ethtool_eth_ctrl_stats {
372373
*/
373374
struct ethtool_pause_stats {
374375
enum ethtool_mac_stats_src src;
375-
u64 tx_pause_frames;
376-
u64 rx_pause_frames;
376+
struct_group(stats,
377+
u64 tx_pause_frames;
378+
u64 rx_pause_frames;
379+
);
377380
};
378381

379382
#define ETHTOOL_MAX_LANES 8
@@ -441,13 +444,15 @@ struct ethtool_rmon_hist_range {
441444
*/
442445
struct ethtool_rmon_stats {
443446
enum ethtool_mac_stats_src src;
444-
u64 undersize_pkts;
445-
u64 oversize_pkts;
446-
u64 fragments;
447-
u64 jabbers;
448-
449-
u64 hist[ETHTOOL_RMON_HIST_MAX];
450-
u64 hist_tx[ETHTOOL_RMON_HIST_MAX];
447+
struct_group(stats,
448+
u64 undersize_pkts;
449+
u64 oversize_pkts;
450+
u64 fragments;
451+
u64 jabbers;
452+
453+
u64 hist[ETHTOOL_RMON_HIST_MAX];
454+
u64 hist_tx[ETHTOOL_RMON_HIST_MAX];
455+
);
451456
};
452457

453458
#define ETH_MODULE_EEPROM_PAGE_LEN 128
@@ -981,6 +986,21 @@ ethtool_params_from_link_mode(struct ethtool_link_ksettings *link_ksettings,
981986
*/
982987
int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index);
983988

989+
/* Some generic methods drivers may use in their ethtool_ops */
990+
u32 ethtool_op_get_link(struct net_device *dev);
991+
int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *eti);
992+
993+
void ethtool_aggregate_mac_stats(struct net_device *dev,
994+
struct ethtool_eth_mac_stats *mac_stats);
995+
void ethtool_aggregate_phy_stats(struct net_device *dev,
996+
struct ethtool_eth_phy_stats *phy_stats);
997+
void ethtool_aggregate_ctrl_stats(struct net_device *dev,
998+
struct ethtool_eth_ctrl_stats *ctrl_stats);
999+
void ethtool_aggregate_pause_stats(struct net_device *dev,
1000+
struct ethtool_pause_stats *pause_stats);
1001+
void ethtool_aggregate_rmon_stats(struct net_device *dev,
1002+
struct ethtool_rmon_stats *rmon_stats);
1003+
9841004
/**
9851005
* ethtool_sprintf - Write formatted string to ethtool string data
9861006
* @data: Pointer to start of string to update

net/ethtool/stats.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,3 +440,130 @@ const struct ethnl_request_ops ethnl_stats_request_ops = {
440440
.reply_size = stats_reply_size,
441441
.fill_reply = stats_fill_reply,
442442
};
443+
444+
static u64 ethtool_stats_sum(u64 a, u64 b)
445+
{
446+
if (a == ETHTOOL_STAT_NOT_SET)
447+
return b;
448+
if (b == ETHTOOL_STAT_NOT_SET)
449+
return a;
450+
return a + b;
451+
}
452+
453+
/* Avoid modifying the aggregation procedure every time a new counter is added
454+
* by treating the structures as an array of u64 statistics.
455+
*/
456+
static void ethtool_aggregate_stats(void *aggr_stats, const void *emac_stats,
457+
const void *pmac_stats, size_t stats_size,
458+
size_t stats_offset)
459+
{
460+
size_t num_stats = stats_size / sizeof(u64);
461+
const u64 *s1 = emac_stats + stats_offset;
462+
const u64 *s2 = pmac_stats + stats_offset;
463+
u64 *s = aggr_stats + stats_offset;
464+
int i;
465+
466+
for (i = 0; i < num_stats; i++)
467+
s[i] = ethtool_stats_sum(s1[i], s2[i]);
468+
}
469+
470+
void ethtool_aggregate_mac_stats(struct net_device *dev,
471+
struct ethtool_eth_mac_stats *mac_stats)
472+
{
473+
const struct ethtool_ops *ops = dev->ethtool_ops;
474+
struct ethtool_eth_mac_stats pmac, emac;
475+
476+
memset(&emac, 0xff, sizeof(emac));
477+
memset(&pmac, 0xff, sizeof(pmac));
478+
emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
479+
pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
480+
481+
ops->get_eth_mac_stats(dev, &emac);
482+
ops->get_eth_mac_stats(dev, &pmac);
483+
484+
ethtool_aggregate_stats(mac_stats, &emac, &pmac,
485+
sizeof(mac_stats->stats),
486+
offsetof(struct ethtool_eth_mac_stats, stats));
487+
}
488+
EXPORT_SYMBOL(ethtool_aggregate_mac_stats);
489+
490+
void ethtool_aggregate_phy_stats(struct net_device *dev,
491+
struct ethtool_eth_phy_stats *phy_stats)
492+
{
493+
const struct ethtool_ops *ops = dev->ethtool_ops;
494+
struct ethtool_eth_phy_stats pmac, emac;
495+
496+
memset(&emac, 0xff, sizeof(emac));
497+
memset(&pmac, 0xff, sizeof(pmac));
498+
emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
499+
pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
500+
501+
ops->get_eth_phy_stats(dev, &emac);
502+
ops->get_eth_phy_stats(dev, &pmac);
503+
504+
ethtool_aggregate_stats(phy_stats, &emac, &pmac,
505+
sizeof(phy_stats->stats),
506+
offsetof(struct ethtool_eth_phy_stats, stats));
507+
}
508+
EXPORT_SYMBOL(ethtool_aggregate_phy_stats);
509+
510+
void ethtool_aggregate_ctrl_stats(struct net_device *dev,
511+
struct ethtool_eth_ctrl_stats *ctrl_stats)
512+
{
513+
const struct ethtool_ops *ops = dev->ethtool_ops;
514+
struct ethtool_eth_ctrl_stats pmac, emac;
515+
516+
memset(&emac, 0xff, sizeof(emac));
517+
memset(&pmac, 0xff, sizeof(pmac));
518+
emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
519+
pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
520+
521+
ops->get_eth_ctrl_stats(dev, &emac);
522+
ops->get_eth_ctrl_stats(dev, &pmac);
523+
524+
ethtool_aggregate_stats(ctrl_stats, &emac, &pmac,
525+
sizeof(ctrl_stats->stats),
526+
offsetof(struct ethtool_eth_ctrl_stats, stats));
527+
}
528+
EXPORT_SYMBOL(ethtool_aggregate_ctrl_stats);
529+
530+
void ethtool_aggregate_pause_stats(struct net_device *dev,
531+
struct ethtool_pause_stats *pause_stats)
532+
{
533+
const struct ethtool_ops *ops = dev->ethtool_ops;
534+
struct ethtool_pause_stats pmac, emac;
535+
536+
memset(&emac, 0xff, sizeof(emac));
537+
memset(&pmac, 0xff, sizeof(pmac));
538+
emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
539+
pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
540+
541+
ops->get_pause_stats(dev, &emac);
542+
ops->get_pause_stats(dev, &pmac);
543+
544+
ethtool_aggregate_stats(pause_stats, &emac, &pmac,
545+
sizeof(pause_stats->stats),
546+
offsetof(struct ethtool_pause_stats, stats));
547+
}
548+
EXPORT_SYMBOL(ethtool_aggregate_pause_stats);
549+
550+
void ethtool_aggregate_rmon_stats(struct net_device *dev,
551+
struct ethtool_rmon_stats *rmon_stats)
552+
{
553+
const struct ethtool_ops *ops = dev->ethtool_ops;
554+
const struct ethtool_rmon_hist_range *dummy;
555+
struct ethtool_rmon_stats pmac, emac;
556+
557+
memset(&emac, 0xff, sizeof(emac));
558+
memset(&pmac, 0xff, sizeof(pmac));
559+
emac.src = ETHTOOL_MAC_STATS_SRC_EMAC;
560+
pmac.src = ETHTOOL_MAC_STATS_SRC_PMAC;
561+
562+
ops->get_rmon_stats(dev, &emac, &dummy);
563+
ops->get_rmon_stats(dev, &pmac, &dummy);
564+
565+
ethtool_aggregate_stats(rmon_stats, &emac, &pmac,
566+
sizeof(rmon_stats->stats),
567+
offsetof(struct ethtool_rmon_stats, stats));
568+
}
569+
EXPORT_SYMBOL(ethtool_aggregate_rmon_stats);

0 commit comments

Comments
 (0)