[RFC PATCH net-next 3/7] net: ethtool: stats: make stats_put_stats() take input from multiple sources

Vladimir Oltean
2022-08-16T22:29:46Z

IEEE 802.3 defines a MAC merge layer, for supporting the 802.1Q Frame
Preemption capability. Beyond the MAC merge layer there are 2 distinct
MACs, one is for express traffic (eMAC, aka the good old MAC that the
Linux network stack knows about) and the other is for preemptable
traffic (pMAC).

The pMAC is a MAC in its own right, and has a full set of statistics
that can be exposed through the standardized ethtool counters (RMON,
802.3 etc).

In preparation for extending struct stats_reply_data to store both the
eMAC and the pMAC stats structures, modify stats_put_stats() to not
assume that we only care about the eMAC stats. Instead, we will
introduce separate ops for pMAC stats, and put those stats into separate
netlink attributes, and take them from different instances of the same
structure types as in the case of the eMAC.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
net/ethtool/stats.c | 148 +++++++++++++++++++++++++-------------------
1 file changed, 86 insertions(+), 62 deletions(-)

diff --git a/net/ethtool/stats.c b/net/ethtool/stats.c
index a20e0a24ff61..8d4d3c70c0a4 100644
--- a/net/ethtool/stats.c
+++ b/net/ethtool/stats.c
@@ -9,6 +9,11 @@ struct stats_req_info {
DECLARE_BITMAP(stat_mask, __ETHTOOL_STATS_CNT);
};

+struct rmon_stats_put_ctx {
+ const struct ethtool_rmon_stats *rmon_stats;
+ const struct ethtool_rmon_hist_range *rmon_ranges;
+};
+
#define STATS_REQINFO(__req_base) \
container_of(__req_base, struct stats_req_info, base)

@@ -110,8 +115,11 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
const struct stats_req_info *req_info = STATS_REQINFO(req_base);
struct stats_reply_data *data = STATS_REPDATA(reply_base);
struct net_device *dev = reply_base->dev;
+ const struct ethtool_ops *ops;
int ret;

+ ops = dev->ethtool_ops;
+
ret = ethnl_ops_begin(dev);
if (ret < 0)
return ret;
@@ -122,18 +130,18 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
memset(&data->stats, 0xff, sizeof(data->stats));

if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
- dev->ethtool_ops->get_eth_phy_stats)
- dev->ethtool_ops->get_eth_phy_stats(dev, &data->phy_stats);
+ ops->get_eth_phy_stats)
+ ops->get_eth_phy_stats(dev, &data->phy_stats);
if (test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask) &&
- dev->ethtool_ops->get_eth_mac_stats)
- dev->ethtool_ops->get_eth_mac_stats(dev, &data->mac_stats);
+ ops->get_eth_mac_stats)
+ ops->get_eth_mac_stats(dev, &data->mac_stats);
if (test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask) &&
- dev->ethtool_ops->get_eth_ctrl_stats)
- dev->ethtool_ops->get_eth_ctrl_stats(dev, &data->ctrl_stats);
+ ops->get_eth_ctrl_stats)
+ ops->get_eth_ctrl_stats(dev, &data->ctrl_stats);
if (test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask) &&
- dev->ethtool_ops->get_rmon_stats)
- dev->ethtool_ops->get_rmon_stats(dev, &data->rmon_stats,
- &data->rmon_ranges);
+ ops->get_rmon_stats)
+ ops->get_rmon_stats(dev, &data->rmon_stats,
+ &data->rmon_ranges);

ethnl_ops_complete(dev);
return 0;
@@ -212,76 +220,82 @@ static int stat_put(struct sk_buff *skb, u16 attrtype, u64 val)
return 0;
}

-static int stats_put_phy_stats(struct sk_buff *skb,
- const struct stats_reply_data *data)
+static int stats_put_phy_stats(struct sk_buff *skb, const void *src)
{
+ const struct ethtool_eth_phy_stats *phy_stats = src;
+
if (stat_put(skb, ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR,
- data->phy_stats.SymbolErrorDuringCarrier))
+ phy_stats->SymbolErrorDuringCarrier))
return -EMSGSIZE;
+
return 0;
}

-static int stats_put_mac_stats(struct sk_buff *skb,
- const struct stats_reply_data *data)
+static int stats_put_mac_stats(struct sk_buff *skb, const void *src)
{
+ const struct ethtool_eth_mac_stats *mac_stats = src;
+
if (stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT,
- data->mac_stats.FramesTransmittedOK) ||
+ mac_stats->FramesTransmittedOK) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL,
- data->mac_stats.SingleCollisionFrames) ||
+ mac_stats->SingleCollisionFrames) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL,
- data->mac_stats.MultipleCollisionFrames) ||
+ mac_stats->MultipleCollisionFrames) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT,
- data->mac_stats.FramesReceivedOK) ||
+ mac_stats->FramesReceivedOK) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR,
- data->mac_stats.FrameCheckSequenceErrors) ||
+ mac_stats->FrameCheckSequenceErrors) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR,
- data->mac_stats.AlignmentErrors) ||
+ mac_stats->AlignmentErrors) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES,
- data->mac_stats.OctetsTransmittedOK) ||
+ mac_stats->OctetsTransmittedOK) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER,
- data->mac_stats.FramesWithDeferredXmissions) ||
+ mac_stats->FramesWithDeferredXmissions) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL,
- data->mac_stats.LateCollisions) ||
+ mac_stats->LateCollisions) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_11_XS_COL,
- data->mac_stats.FramesAbortedDueToXSColls) ||
+ mac_stats->FramesAbortedDueToXSColls) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR,
- data->mac_stats.FramesLostDueToIntMACXmitError) ||
+ mac_stats->FramesLostDueToIntMACXmitError) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR,
- data->mac_stats.CarrierSenseErrors) ||
+ mac_stats->CarrierSenseErrors) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES,
- data->mac_stats.OctetsReceivedOK) ||
+ mac_stats->OctetsReceivedOK) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR,
- data->mac_stats.FramesLostDueToIntMACRcvError) ||
+ mac_stats->FramesLostDueToIntMACRcvError) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST,
- data->mac_stats.MulticastFramesXmittedOK) ||
+ mac_stats->MulticastFramesXmittedOK) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST,
- data->mac_stats.BroadcastFramesXmittedOK) ||
+ mac_stats->BroadcastFramesXmittedOK) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER,
- data->mac_stats.FramesWithExcessiveDeferral) ||
+ mac_stats->FramesWithExcessiveDeferral) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST,
- data->mac_stats.MulticastFramesReceivedOK) ||
+ mac_stats->MulticastFramesReceivedOK) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST,
- data->mac_stats.BroadcastFramesReceivedOK) ||
+ mac_stats->BroadcastFramesReceivedOK) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR,
- data->mac_stats.InRangeLengthErrors) ||
+ mac_stats->InRangeLengthErrors) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN,
- data->mac_stats.OutOfRangeLengthField) ||
+ mac_stats->OutOfRangeLengthField) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR,
- data->mac_stats.FrameTooLongErrors))
+ mac_stats->FrameTooLongErrors))
return -EMSGSIZE;
+
return 0;
}

-static int stats_put_ctrl_stats(struct sk_buff *skb,
- const struct stats_reply_data *data)
+static int stats_put_ctrl_stats(struct sk_buff *skb, const void *src)
{
+ const struct ethtool_eth_ctrl_stats *ctrl_stats = src;
+
if (stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_3_TX,
- data->ctrl_stats.MACControlFramesTransmitted) ||
+ ctrl_stats->MACControlFramesTransmitted) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_4_RX,
- data->ctrl_stats.MACControlFramesReceived) ||
+ ctrl_stats->MACControlFramesReceived) ||
stat_put(skb, ETHTOOL_A_STATS_ETH_CTRL_5_RX_UNSUP,
- data->ctrl_stats.UnsupportedOpcodesReceived))
+ ctrl_stats->UnsupportedOpcodesReceived))
return -EMSGSIZE;
+
return 0;
}

@@ -322,33 +336,34 @@ static int stats_put_rmon_hist(struct sk_buff *skb, u32 attr, const u64 *hist,
return -EMSGSIZE;
}

-static int stats_put_rmon_stats(struct sk_buff *skb,
- const struct stats_reply_data *data)
+static int stats_put_rmon_stats(struct sk_buff *skb, const void *src)
{
+ const struct ethtool_rmon_hist_range *rmon_ranges;
+ const struct ethtool_rmon_stats *rmon_stats;
+ const struct rmon_stats_put_ctx *ctx = src;
+
+ rmon_stats = ctx->rmon_stats;
+ rmon_ranges = ctx->rmon_ranges;
+
if (stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_RX,
- data->rmon_stats.hist, data->rmon_ranges) ||
+ rmon_stats->hist, rmon_ranges) ||
stats_put_rmon_hist(skb, ETHTOOL_A_STATS_GRP_HIST_TX,
- data->rmon_stats.hist_tx, data->rmon_ranges))
+ rmon_stats->hist_tx, rmon_ranges))
return -EMSGSIZE;

if (stat_put(skb, ETHTOOL_A_STATS_RMON_UNDERSIZE,
- data->rmon_stats.undersize_pkts) ||
+ rmon_stats->undersize_pkts) ||
stat_put(skb, ETHTOOL_A_STATS_RMON_OVERSIZE,
- data->rmon_stats.oversize_pkts) ||
- stat_put(skb, ETHTOOL_A_STATS_RMON_FRAG,
- data->rmon_stats.fragments) ||
- stat_put(skb, ETHTOOL_A_STATS_RMON_JABBER,
- data->rmon_stats.jabbers))
+ rmon_stats->oversize_pkts) ||
+ stat_put(skb, ETHTOOL_A_STATS_RMON_FRAG, rmon_stats->fragments) ||
+ stat_put(skb, ETHTOOL_A_STATS_RMON_JABBER, rmon_stats->jabbers))
return -EMSGSIZE;

return 0;
}

-static int stats_put_stats(struct sk_buff *skb,
- const struct stats_reply_data *data,
- u32 id, u32 ss_id,
- int (*cb)(struct sk_buff *skb,
- const struct stats_reply_data *data))
+static int stats_put_stats(struct sk_buff *skb, const void *src, u32 id, u32 ss_id,
+ int (*cb)(struct sk_buff *skb, const void *src))
{
struct nlattr *nest;

@@ -360,7 +375,7 @@ static int stats_put_stats(struct sk_buff *skb,
nla_put_u32(skb, ETHTOOL_A_STATS_GRP_SS_ID, ss_id))
goto err_cancel;

- if (cb(skb, data))
+ if (cb(skb, src))
goto err_cancel;

nla_nest_end(skb, nest);
@@ -380,20 +395,29 @@ static int stats_fill_reply(struct sk_buff *skb,
int ret = 0;

if (!ret && test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask))
- ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_PHY,
+ ret = stats_put_stats(skb, &data->phy_stats,
+ ETHTOOL_STATS_ETH_PHY,
ETH_SS_STATS_ETH_PHY,
stats_put_phy_stats);
if (!ret && test_bit(ETHTOOL_STATS_ETH_MAC, req_info->stat_mask))
- ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_MAC,
+ ret = stats_put_stats(skb, &data->mac_stats,
+ ETHTOOL_STATS_ETH_MAC,
ETH_SS_STATS_ETH_MAC,
stats_put_mac_stats);
if (!ret && test_bit(ETHTOOL_STATS_ETH_CTRL, req_info->stat_mask))
- ret = stats_put_stats(skb, data, ETHTOOL_STATS_ETH_CTRL,
+ ret = stats_put_stats(skb, &data->ctrl_stats,
+ ETHTOOL_STATS_ETH_CTRL,
ETH_SS_STATS_ETH_CTRL,
stats_put_ctrl_stats);
- if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask))
- ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON,
+ if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask)) {
+ struct rmon_stats_put_ctx ctx = {
+ .rmon_stats = &data->rmon_stats,
+ .rmon_ranges = data->rmon_ranges,
+ };
+
+ ret = stats_put_stats(skb, &ctx, ETHTOOL_STATS_RMON,
ETH_SS_STATS_RMON, stats_put_rmon_stats);
+ }

return ret;
}
--
2.34.1