Skip to content

Commit

Permalink
Merge branch 'ethtool-stats'
Browse files Browse the repository at this point in the history
Jakub Kicinski says:

====================
ethtool: add uAPI for reading standard stats

Continuing the effort of providing a unified access method
to standard stats, and explicitly tying the definitions to
the standards this series adds an API for general stats
which do no fit into more targeted control APIs.

There is nothing clever here, just a netlink API for dumping
statistics defined by standards and RFCs which today end up
in ethtool -S under infinite variations of names.

This series adds basic IEEE stats (for PHY, MAC, Ctrl frames)
and RMON stats. AFAICT other RFCs only duplicate the IEEE
stats.

This series does _not_ add a netlink API to read driver-defined
stats. There seems to be little to gain from moving that part
to netlink.

The netlink message format is very simple, and aims to allow
adding stats and groups with no changes to user tooling (which
IIUC is expected for ethtool).

On user space side we can re-use -S, and make it dump
standard stats if --groups are defined.

$ ethtool -S eth0 --groups eth-phy eth-mac eth-ctrl rmon
Stats for eth0:
eth-phy-SymbolErrorDuringCarrier: 0
eth-mac-FramesTransmittedOK: 0
eth-mac-FrameTooLongErrors: 0
eth-ctrl-MACControlFramesTransmitted: 0
eth-ctrl-MACControlFramesReceived: 1
eth-ctrl-UnsupportedOpcodesReceived: 0
rmon-etherStatsUndersizePkts: 0
rmon-etherStatsJabbers: 0
rmon-rx-etherStatsPkts64Octets: 1
rmon-rx-etherStatsPkts128to255Octets: 0
rmon-rx-etherStatsPkts1024toMaxOctets: 1
rmon-tx-etherStatsPkts64Octets: 1
rmon-tx-etherStatsPkts128to255Octets: 0
rmon-tx-etherStatsPkts1024toMaxOctets: 1

v1:

Driver support for mlxsw, mlx5 and bnxt included.

Compared to the RFC I went ahead with wrapping the stats into
a 1:1 nest. Now IDs of stats can start from 0, at a cost of
slightly "careful" u64 alignment handling.

v2:

Add missing kdoc in patch 5.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Apr 17, 2021
2 parents e5272ad + b572ec9 commit 1c86514
Show file tree
Hide file tree
Showing 15 changed files with 1,257 additions and 10 deletions.
82 changes: 82 additions & 0 deletions Documentation/networking/ethtool-netlink.rst
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ Userspace to kernel:
``ETHTOOL_MSG_TUNNEL_INFO_GET`` get tunnel offload info
``ETHTOOL_MSG_FEC_GET`` get FEC settings
``ETHTOOL_MSG_FEC_SET`` set FEC settings
``ETHTOOL_MSG_STATS_GET`` get standard statistics
===================================== ================================

Kernel to userspace:
Expand Down Expand Up @@ -246,6 +247,7 @@ Kernel to userspace:
``ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY`` tunnel offload info
``ETHTOOL_MSG_FEC_GET_REPLY`` FEC settings
``ETHTOOL_MSG_FEC_NTF`` FEC settings
``ETHTOOL_MSG_STATS_GET_REPLY`` standard statistics
===================================== =================================

``GET`` requests are sent by userspace applications to retrieve device
Expand Down Expand Up @@ -1391,6 +1393,86 @@ Kernel response contents:
``ETHTOOL_A_MODULE_EEPROM_DATA`` has an attribute length equal to the amount of
bytes driver actually read.

STATS_GET
=========

Get standard statistics for the interface. Note that this is not
a re-implementation of ``ETHTOOL_GSTATS`` which exposed driver-defined
stats.

Request contents:

======================================= ====== ==========================
``ETHTOOL_A_STATS_HEADER`` nested request header
``ETHTOOL_A_STATS_GROUPS`` bitset requested groups of stats
======================================= ====== ==========================

Kernel response contents:

+-----------------------------------+--------+--------------------------------+
| ``ETHTOOL_A_STATS_HEADER`` | nested | reply header |
+-----------------------------------+--------+--------------------------------+
| ``ETHTOOL_A_STATS_GRP`` | nested | one or more group of stats |
+-+---------------------------------+--------+--------------------------------+
| | ``ETHTOOL_A_STATS_GRP_ID`` | u32 | group ID - ``ETHTOOL_STATS_*`` |
+-+---------------------------------+--------+--------------------------------+
| | ``ETHTOOL_A_STATS_GRP_SS_ID`` | u32 | string set ID for names |
+-+---------------------------------+--------+--------------------------------+
| | ``ETHTOOL_A_STATS_GRP_STAT`` | nested | nest containing a statistic |
+-+---------------------------------+--------+--------------------------------+
| | ``ETHTOOL_A_STATS_GRP_HIST_RX`` | nested | histogram statistic (Rx) |
+-+---------------------------------+--------+--------------------------------+
| | ``ETHTOOL_A_STATS_GRP_HIST_TX`` | nested | histogram statistic (Tx) |
+-+---------------------------------+--------+--------------------------------+

Users specify which groups of statistics they are requesting via
the ``ETHTOOL_A_STATS_GROUPS`` bitset. Currently defined values are:

====================== ======== ===============================================
ETHTOOL_STATS_ETH_MAC eth-mac Basic IEEE 802.3 MAC statistics (30.3.1.1.*)
ETHTOOL_STATS_ETH_PHY eth-phy Basic IEEE 802.3 PHY statistics (30.3.2.1.*)
ETHTOOL_STATS_ETH_CTRL eth-ctrl Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*)
ETHTOOL_STATS_RMON rmon RMON (RFC 2819) statistics
====================== ======== ===============================================

Each group should have a corresponding ``ETHTOOL_A_STATS_GRP`` in the reply.
``ETHTOOL_A_STATS_GRP_ID`` identifies which group's statistics nest contains.
``ETHTOOL_A_STATS_GRP_SS_ID`` identifies the string set ID for the names of
the statistics in the group, if available.

Statistics are added to the ``ETHTOOL_A_STATS_GRP`` nest under
``ETHTOOL_A_STATS_GRP_STAT``. ``ETHTOOL_A_STATS_GRP_STAT`` should contain
single 8 byte (u64) attribute inside - the type of that attribute is
the statistic ID and the value is the value of the statistic.
Each group has its own interpretation of statistic IDs.
Attribute IDs correspond to strings from the string set identified
by ``ETHTOOL_A_STATS_GRP_SS_ID``. Complex statistics (such as RMON histogram
entries) are also listed inside ``ETHTOOL_A_STATS_GRP`` and do not have
a string defined in the string set.

RMON "histogram" counters count number of packets within given size range.
Because RFC does not specify the ranges beyond the standard 1518 MTU devices
differ in definition of buckets. For this reason the definition of packet ranges
is left to each driver.

``ETHTOOL_A_STATS_GRP_HIST_RX`` and ``ETHTOOL_A_STATS_GRP_HIST_TX`` nests
contain the following attributes:

================================= ====== ===================================
ETHTOOL_A_STATS_RMON_HIST_BKT_LOW u32 low bound of the packet size bucket
ETHTOOL_A_STATS_RMON_HIST_BKT_HI u32 high bound of the bucket
ETHTOOL_A_STATS_RMON_HIST_VAL u64 packet counter
================================= ====== ===================================

Low and high bounds are inclusive, for example:

============================= ==== ====
RFC statistic low high
============================= ==== ====
etherStatsPkts64Octets 0 64
etherStatsPkts512to1023Octets 512 1023
============================= ==== ====

Request translation
===================

Expand Down
44 changes: 42 additions & 2 deletions Documentation/networking/statistics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,27 @@ If `-s` is specified once the detailed errors won't be shown.
Protocol-specific statistics
----------------------------

Some of the interfaces used for configuring devices are also able
to report related statistics. For example ethtool interface used
Protocol-specific statistics are exposed via relevant interfaces,
the same interfaces as are used to configure them.

ethtool
~~~~~~~

Ethtool exposes common low-level statistics.
All the standard statistics are expected to be maintained
by the device, not the driver (as opposed to driver-defined stats
described in the next section which mix software and hardware stats).
For devices which contain unmanaged
switches (e.g. legacy SR-IOV or multi-host NICs) the events counted
may not pertain exclusively to the packets destined to
the local host interface. In other words the events may
be counted at the network port (MAC/PHY blocks) without separation
for different host side (PCIe) devices. Such ambiguity must not
be present when internal switch is managed by Linux (so called
switchdev mode for NICs).

Standard ethtool statistics can be accessed via the interfaces used
for configuration. For example ethtool interface used
to configure pause frames can report corresponding hardware counters::

$ ethtool --include-statistics -a eth0
Expand All @@ -57,6 +76,27 @@ to configure pause frames can report corresponding hardware counters::
tx_pause_frames: 1
rx_pause_frames: 1

General Ethernet statistics not associated with any particular
functionality are exposed via ``ethtool -S $ifc`` by specifying
the ``--groups`` parameter::

$ ethtool -S eth0 --groups eth-phy eth-mac eth-ctrl rmon
Stats for eth0:
eth-phy-SymbolErrorDuringCarrier: 0
eth-mac-FramesTransmittedOK: 1
eth-mac-FrameTooLongErrors: 1
eth-ctrl-MACControlFramesTransmitted: 1
eth-ctrl-MACControlFramesReceived: 0
eth-ctrl-UnsupportedOpcodesReceived: 1
rmon-etherStatsUndersizePkts: 1
rmon-etherStatsJabbers: 0
rmon-rx-etherStatsPkts64Octets: 1
rmon-rx-etherStatsPkts65to127Octets: 0
rmon-rx-etherStatsPkts128to255Octets: 0
rmon-tx-etherStatsPkts64Octets: 2
rmon-tx-etherStatsPkts65to127Octets: 3
rmon-tx-etherStatsPkts128to255Octets: 0

Driver-defined statistics
-------------------------

Expand Down
125 changes: 125 additions & 0 deletions drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -3990,6 +3990,127 @@ void bnxt_ethtool_init(struct bnxt *bp)
mutex_unlock(&bp->hwrm_cmd_lock);
}

static void bnxt_get_eth_phy_stats(struct net_device *dev,
struct ethtool_eth_phy_stats *phy_stats)
{
struct bnxt *bp = netdev_priv(dev);
u64 *rx;

if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT))
return;

rx = bp->rx_port_stats_ext.sw_stats;
phy_stats->SymbolErrorDuringCarrier =
*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err));
}

static void bnxt_get_eth_mac_stats(struct net_device *dev,
struct ethtool_eth_mac_stats *mac_stats)
{
struct bnxt *bp = netdev_priv(dev);
u64 *rx, *tx;

if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
return;

rx = bp->port_stats.sw_stats;
tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8;

mac_stats->FramesReceivedOK =
BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames);
mac_stats->FramesTransmittedOK =
BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames);
}

static void bnxt_get_eth_ctrl_stats(struct net_device *dev,
struct ethtool_eth_ctrl_stats *ctrl_stats)
{
struct bnxt *bp = netdev_priv(dev);
u64 *rx;

if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
return;

rx = bp->port_stats.sw_stats;
ctrl_stats->MACControlFramesReceived =
BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames);
}

static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = {
{ 0, 64 },
{ 65, 127 },
{ 128, 255 },
{ 256, 511 },
{ 512, 1023 },
{ 1024, 1518 },
{ 1519, 2047 },
{ 2048, 4095 },
{ 4096, 9216 },
{ 9217, 16383 },
{}
};

static void bnxt_get_rmon_stats(struct net_device *dev,
struct ethtool_rmon_stats *rmon_stats,
const struct ethtool_rmon_hist_range **ranges)
{
struct bnxt *bp = netdev_priv(dev);
u64 *rx, *tx;

if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
return;

rx = bp->port_stats.sw_stats;
tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8;

rmon_stats->jabbers =
BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames);
rmon_stats->oversize_pkts =
BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames);
rmon_stats->undersize_pkts =
BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames);

rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames);
rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames);
rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames);
rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames);
rmon_stats->hist[4] =
BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames);
rmon_stats->hist[5] =
BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames);
rmon_stats->hist[6] =
BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames);
rmon_stats->hist[7] =
BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames);
rmon_stats->hist[8] =
BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames);
rmon_stats->hist[9] =
BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames);

rmon_stats->hist_tx[0] =
BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames);
rmon_stats->hist_tx[1] =
BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames);
rmon_stats->hist_tx[2] =
BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames);
rmon_stats->hist_tx[3] =
BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames);
rmon_stats->hist_tx[4] =
BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames);
rmon_stats->hist_tx[5] =
BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames);
rmon_stats->hist_tx[6] =
BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames);
rmon_stats->hist_tx[7] =
BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames);
rmon_stats->hist_tx[8] =
BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames);
rmon_stats->hist_tx[9] =
BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames);

*ranges = bnxt_rmon_ranges;
}

void bnxt_ethtool_free(struct bnxt *bp)
{
kfree(bp->test_info);
Expand Down Expand Up @@ -4049,4 +4170,8 @@ const struct ethtool_ops bnxt_ethtool_ops = {
.set_dump = bnxt_set_dump,
.get_dump_flag = bnxt_get_dump_flag,
.get_dump_data = bnxt_get_dump_data,
.get_eth_phy_stats = bnxt_get_eth_phy_stats,
.get_eth_mac_stats = bnxt_get_eth_mac_stats,
.get_eth_ctrl_stats = bnxt_get_eth_ctrl_stats,
.get_rmon_stats = bnxt_get_rmon_stats,
};
37 changes: 37 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -2295,6 +2295,39 @@ mlx5e_get_link_ext_state(struct net_device *dev,
return -ENODATA;
}

static void mlx5e_get_eth_phy_stats(struct net_device *netdev,
struct ethtool_eth_phy_stats *phy_stats)
{
struct mlx5e_priv *priv = netdev_priv(netdev);

mlx5e_stats_eth_phy_get(priv, phy_stats);
}

static void mlx5e_get_eth_mac_stats(struct net_device *netdev,
struct ethtool_eth_mac_stats *mac_stats)
{
struct mlx5e_priv *priv = netdev_priv(netdev);

mlx5e_stats_eth_mac_get(priv, mac_stats);
}

static void mlx5e_get_eth_ctrl_stats(struct net_device *netdev,
struct ethtool_eth_ctrl_stats *ctrl_stats)
{
struct mlx5e_priv *priv = netdev_priv(netdev);

mlx5e_stats_eth_ctrl_get(priv, ctrl_stats);
}

static void mlx5e_get_rmon_stats(struct net_device *netdev,
struct ethtool_rmon_stats *rmon_stats,
const struct ethtool_rmon_hist_range **ranges)
{
struct mlx5e_priv *priv = netdev_priv(netdev);

mlx5e_stats_rmon_get(priv, rmon_stats, ranges);
}

const struct ethtool_ops mlx5e_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES |
Expand Down Expand Up @@ -2340,4 +2373,8 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
.get_fec_stats = mlx5e_get_fec_stats,
.get_fecparam = mlx5e_get_fecparam,
.set_fecparam = mlx5e_set_fecparam,
.get_eth_phy_stats = mlx5e_get_eth_phy_stats,
.get_eth_mac_stats = mlx5e_get_eth_mac_stats,
.get_eth_ctrl_stats = mlx5e_get_eth_ctrl_stats,
.get_rmon_stats = mlx5e_get_rmon_stats,
};
Loading

0 comments on commit 1c86514

Please sign in to comment.