lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20210415083837.6dfc0af9@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com>
Date:   Thu, 15 Apr 2021 08:38:37 -0700
From:   Jakub Kicinski <kuba@...nel.org>
To:     Saeed Mahameed <saeed@...nel.org>
Cc:     netdev@...r.kernel.org, davem@...emloft.net, andrew@...n.ch,
        mkubecek@...e.cz, idosch@...dia.com
Subject: Re: [RFC net-next 4/6] ethtool: add interface to read standard MAC
 stats

On Wed, 14 Apr 2021 23:12:52 -0700 Saeed Mahameed wrote:
> On Wed, 2021-04-14 at 13:23 -0700, Jakub Kicinski wrote:
> > Most of the MAC statistics are included in
> > struct rtnl_link_stats64, but some fields
> > are aggregated. Besides it's good to expose
> > these clearly hardware stats separately.
> > 
> > Signed-off-by: Jakub Kicinski <kuba@...nel.org>

> > +/* Basic IEEE 802.3 MAC statistics (30.3.1.1.*), not otherwise exposed
> > + * via a more targeted API.
> > + */
> > +struct ethtool_eth_mac_stats {
> > +       u64 FramesTransmittedOK;
> > +       u64 SingleCollisionFrames;
> > +       u64 MultipleCollisionFrames;
> > +       u64 FramesReceivedOK;
> > +       u64 FrameCheckSequenceErrors;
> > +       u64 AlignmentErrors;
> > +       u64 OctetsTransmittedOK;
> > +       u64 FramesWithDeferredXmissions;
> > +       u64 LateCollisions;
> > +       u64 FramesAbortedDueToXSColls;
> > +       u64 FramesLostDueToIntMACXmitError;
> > +       u64 CarrierSenseErrors;
> > +       u64 OctetsReceivedOK;
> > +       u64 FramesLostDueToIntMACRcvError;
> > +       u64 MulticastFramesXmittedOK;
> > +       u64 BroadcastFramesXmittedOK;
> > +       u64 FramesWithExcessiveDeferral;
> > +       u64 MulticastFramesReceivedOK;
> > +       u64 BroadcastFramesReceivedOK;
> > +       u64 InRangeLengthErrors;
> > +       u64 OutOfRangeLengthField;
> > +       u64 FrameTooLongErrors;
> > +};
> > +
> >  /* Basic IEEE 802.3 PHY statistics (30.3.2.1.*), not otherwise exposed
> >   * via a more targeted API.
> >   */
> > @@ -495,6 +523,7 @@ struct ethtool_module_eeprom {
> >   *     specified page. Returns a negative error code or the amount of
> > bytes
> >   *     read.
> >   * @get_eth_phy_stats: Query some of the IEEE 802.3 PHY statistics.
> > + * @get_eth_mac_stats: Query some of the IEEE 802.3 MAC statistics.
> >   *
> >   * All operations are optional (i.e. the function pointer may be set
> >   * to %NULL) and callers must take this into account.  Callers must
> > @@ -607,6 +636,8 @@ struct ethtool_ops {
> >                                              struct netlink_ext_ack
> > *extack);
> >         void    (*get_eth_phy_stats)(struct net_device *dev,
> >                                      struct ethtool_eth_phy_stats
> > *phy_stats);
> > +       void    (*get_eth_mac_stats)(struct net_device *dev,
> > +                                    struct ethtool_eth_mac_stats
> > *mac_stats);  
> 
> too many callbacks.. I understand the point of having explicit structs
> per stats group, but it can be achievable with one generic ethtool
> calback function with the help of a flexible struct:
> 
> void (*get_std_stats)(struct net_device *dev, struct *std_stats)
> 
> 
> union stats_groups {
>     struct ethtool_eth_phy_stats eth_phy;
>     struct ethtool_eth_mac_stats eth_mac;
>     ...
> }
> 
> struct std_stats {
>      u16 type;
>      union stats_groups stats[0];
> }
> 
> where std_stats.stats is allocated dynamically according to
> std_stats.type
> 
> and driver can just access the corresponding stats according to type
> 
> e.g: 
> std_stats.stats.eth_phy

Kinda expected you'd say this :) The mux make life simpler for drivers
with a lot of layers of abstraction. Separate ops make life simpler for
simpler drivers.

Basic Ethernet driver goes from this:

get_mac_stats()
{
	priv = netdev_priv()

	stat->x = readl(priv->regs + REG_X);
	stat->z = readl(priv->regs + REG_Y);
	stat->y = readl(priv->regs + REG_Z);
}

to:

get_std_stats()
{
	priv = netdev_priv();

	switch (stats->type) {
	case MAC:
		stat->x = readl(priv->regs + REG_X);
		stat->z = readl(priv->regs + REG_Y);
		stat->y = readl(priv->regs + REG_Z);
		break;
	}
}

or likely:

get_std_stats()
{
	priv = netdev_priv();

	switch (stats->type) {
	case MAC:
		return get_mac_stats(priv..);
	}
}

I prefer to keep the callbacks separate, there isn't that many of them.

> > +static int stats_put_mac_stats(struct sk_buff *skb,
> > +                              const struct stats_reply_data *data)
> > +{
> > +       if (stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_2_TX_PKT,
> > +                    data->mac_stats.FramesTransmittedOK) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_3_SINGLE_COL,
> > +                    data->mac_stats.SingleCollisionFrames) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_4_MULTI_COL,
> > +                    data->mac_stats.MultipleCollisionFrames) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_5_RX_PKT,
> > +                    data->mac_stats.FramesReceivedOK) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_6_FCS_ERR,
> > +                    data->mac_stats.FrameCheckSequenceErrors) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_7_ALIGN_ERR,
> > +                    data->mac_stats.AlignmentErrors) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_8_TX_BYTES,
> > +                    data->mac_stats.OctetsTransmittedOK) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_9_TX_DEFER,
> > +                    data->mac_stats.FramesWithDeferredXmissions) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_10_LATE_COL,
> > +                    data->mac_stats.LateCollisions) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_11_XS_COL,
> > +                    data->mac_stats.FramesAbortedDueToXSColls) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_12_TX_INT_ERR,
> > +                    data->mac_stats.FramesLostDueToIntMACXmitError) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_13_CS_ERR,
> > +                    data->mac_stats.CarrierSenseErrors) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_14_RX_BYTES,
> > +                    data->mac_stats.OctetsReceivedOK) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_15_RX_INT_ERR,
> > +                    data->mac_stats.FramesLostDueToIntMACRcvError) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_18_TX_MCAST,
> > +                    data->mac_stats.MulticastFramesXmittedOK) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_19_TX_BCAST,
> > +                    data->mac_stats.BroadcastFramesXmittedOK) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_20_XS_DEFER,
> > +                    data->mac_stats.FramesWithExcessiveDeferral) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_21_RX_MCAST,
> > +                    data->mac_stats.MulticastFramesReceivedOK) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_22_RX_BCAST,
> > +                    data->mac_stats.BroadcastFramesReceivedOK) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_23_IR_LEN_ERR,
> > +                    data->mac_stats.InRangeLengthErrors) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_24_OOR_LEN,
> > +                    data->mac_stats.OutOfRangeLengthField) ||
> > +           stat_put(skb, ETHTOOL_A_STATS_ETH_MAC_25_TOO_LONG_ERR,
> > +                    data->mac_stats.FrameTooLongErrors))
> > +               return -EMSGSIZE;  
> 
> lots of repetition, someone might forget to add the new stat in one of
> these places .. 

If someone forgets to add a stat to the place they are dumped?
They will immediately realize it's not getting dumped...

> best practice here is to centralize all the data structures and
> information definitions in one place, you define the stat id, string,
> and value offset, then a generic loop can generate the strset and fill
> up values in the correct offset.
> 
> similar implementation is already in mlx5:
> 
> see pport_802_3_stats_desc:
> https://elixir.bootlin.com/linux/latest/source/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c#L682
> 
> the "pport_802_3_stats_desc" has a description of the strings and
> offsets of all stats in this stats group
> and the fill/put functions are very simple and they just iterate over
> the array/group and fill up according to the descriptor.

We can maybe save 60 lines if we generate stats_eth_mac_names 
in a initcall, is it really worth it? I prefer the readability 
/ grepability.

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ