600 lines
22 KiB
Diff
600 lines
22 KiB
Diff
From baec17f8f0b7359c3a9bbd6d2dfaf35f413f5e0b Mon Sep 17 00:00:00 2001
|
|
From: Jakub Kicinski <kuba@kernel.org>
|
|
Date: Thu, 15 Apr 2021 15:53:15 -0700
|
|
Subject: [PATCH 229/283] ethtool: add FEC statistics
|
|
|
|
mainline inclusion
|
|
from mainline-v5.13-rc1
|
|
commit be85dbfeb37c8c4d4344da2ee594d78034b82489
|
|
category: feature
|
|
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8EN49
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=be85dbfeb37c8c4d4344da2ee594d78034b82489
|
|
|
|
--------------------------------
|
|
|
|
Similarly to pause statistics add stats for FEC.
|
|
|
|
The IEEE standard mandates two sets of counters:
|
|
- 30.5.1.1.17 aFECCorrectedBlocks
|
|
- 30.5.1.1.18 aFECUncorrectableBlocks
|
|
where block is a block of bits FEC operates on.
|
|
Each of these counters is defined per lane (PCS instance).
|
|
|
|
Multiple vendors provide number of corrected _bits_ rather
|
|
than/as well as blocks.
|
|
|
|
This set adds the 2 standard-based block counters and a extra
|
|
one for corrected bits.
|
|
|
|
Counters are exposed to user space via netlink in new attributes.
|
|
Each attribute carries an array of u64s, first element is
|
|
the total count, and the following ones are a per-lane break down.
|
|
|
|
Much like with pause stats the operation will not fail when driver
|
|
does not implement the get_fec_stats callback (nor can the driver
|
|
fail the operation by returning an error). If stats can't be
|
|
reported the relevant attributes will be empty.
|
|
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
Signed-off-by: Xiaodong Li <lixiaodong67@huawei.com>
|
|
|
|
Conflicts:
|
|
Documentation/networking/statistics.rst
|
|
include/linux/ethtool.h
|
|
include/uapi/linux/ethtool_netlink.h
|
|
---
|
|
Documentation/networking/ethtool-netlink.rst | 21 +++
|
|
Documentation/networking/statistics.rst | 180 +++++++++++++++++++
|
|
include/linux/ethtool.h | 72 ++++++--
|
|
include/net/netlink.h | 9 +-
|
|
include/uapi/linux/ethtool_netlink.h | 15 ++
|
|
net/ethtool/fec.c | 73 +++++++-
|
|
net/ethtool/netlink.c | 12 ++
|
|
7 files changed, 367 insertions(+), 15 deletions(-)
|
|
create mode 100644 Documentation/networking/statistics.rst
|
|
|
|
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
|
|
index 39d038e327e9..01da978de86d 100644
|
|
--- a/Documentation/networking/ethtool-netlink.rst
|
|
+++ b/Documentation/networking/ethtool-netlink.rst
|
|
@@ -315,6 +315,7 @@ Kernel response contents:
|
|
``ETHTOOL_A_FEC_MODES`` bitset configured modes
|
|
``ETHTOOL_A_FEC_AUTO`` bool FEC mode auto selection
|
|
``ETHTOOL_A_FEC_ACTIVE`` u32 index of active FEC mode
|
|
+ ``ETHTOOL_A_FEC_STATS`` nested FEC statistics
|
|
===================================== ====== ==========================
|
|
|
|
``ETHTOOL_A_FEC_ACTIVE`` is the bit index of the FEC link mode currently
|
|
@@ -328,6 +329,26 @@ This is equivalent to the ``ETHTOOL_FEC_AUTO`` bit of the ioctl interface.
|
|
``ETHTOOL_A_FEC_MODES`` carry the current FEC configuration using link mode
|
|
bits (rather than old ``ETHTOOL_FEC_*`` bits).
|
|
|
|
+``ETHTOOL_A_FEC_STATS`` are reported if ``ETHTOOL_FLAG_STATS`` was set in
|
|
+``ETHTOOL_A_HEADER_FLAGS``.
|
|
+Each attribute carries an array of 64bit statistics. First entry in the array
|
|
+contains the total number of events on the port, while the following entries
|
|
+are counters corresponding to lanes/PCS instances. The number of entries in
|
|
+the array will be:
|
|
+
|
|
++--------------+---------------------------------------------+
|
|
+| `0` | device does not support FEC statistics |
|
|
++--------------+---------------------------------------------+
|
|
+| `1` | device does not support per-lane break down |
|
|
++--------------+---------------------------------------------+
|
|
+| `1 + #lanes` | device has full support for FEC stats |
|
|
++--------------+---------------------------------------------+
|
|
+
|
|
+Drivers fill in the statistics in the following structure:
|
|
+
|
|
+.. kernel-doc:: include/linux/ethtool.h
|
|
+ :identifiers: ethtool_fec_stats
|
|
+
|
|
FEC_SET
|
|
=======
|
|
|
|
diff --git a/Documentation/networking/statistics.rst b/Documentation/networking/statistics.rst
|
|
new file mode 100644
|
|
index 000000000000..b748fe44ee02
|
|
--- /dev/null
|
|
+++ b/Documentation/networking/statistics.rst
|
|
@@ -0,0 +1,180 @@
|
|
+.. SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+====================
|
|
+Interface statistics
|
|
+====================
|
|
+
|
|
+Overview
|
|
+========
|
|
+
|
|
+This document is a guide to Linux network interface statistics.
|
|
+
|
|
+There are three main sources of interface statistics in Linux:
|
|
+
|
|
+ - standard interface statistics based on
|
|
+ :c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`;
|
|
+ - protocol-specific statistics; and
|
|
+ - driver-defined statistics available via ethtool.
|
|
+
|
|
+Standard interface statistics
|
|
+-----------------------------
|
|
+
|
|
+There are multiple interfaces to reach the standard statistics.
|
|
+Most commonly used is the `ip` command from `iproute2`::
|
|
+
|
|
+ $ ip -s -s link show dev ens4u1u1
|
|
+ 6: ens4u1u1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
|
|
+ link/ether 48:2a:e3:4c:b1:d1 brd ff:ff:ff:ff:ff:ff
|
|
+ RX: bytes packets errors dropped overrun mcast
|
|
+ 74327665117 69016965 0 0 0 0
|
|
+ RX errors: length crc frame fifo missed
|
|
+ 0 0 0 0 0
|
|
+ TX: bytes packets errors dropped carrier collsns
|
|
+ 21405556176 44608960 0 0 0 0
|
|
+ TX errors: aborted fifo window heartbeat transns
|
|
+ 0 0 0 0 128
|
|
+ altname enp58s0u1u1
|
|
+
|
|
+Note that `-s` has been specified twice to see all members of
|
|
+:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`.
|
|
+If `-s` is specified once the detailed errors won't be shown.
|
|
+
|
|
+`ip` supports JSON formatting via the `-j` option.
|
|
+
|
|
+Protocol-specific statistics
|
|
+----------------------------
|
|
+
|
|
+Some of the interfaces used for configuring devices are also able
|
|
+to report related statistics. For example ethtool interface used
|
|
+to configure pause frames can report corresponding hardware counters::
|
|
+
|
|
+ $ ethtool --include-statistics -a eth0
|
|
+ Pause parameters for eth0:
|
|
+ Autonegotiate: on
|
|
+ RX: on
|
|
+ TX: on
|
|
+ Statistics:
|
|
+ tx_pause_frames: 1
|
|
+ rx_pause_frames: 1
|
|
+
|
|
+Driver-defined statistics
|
|
+-------------------------
|
|
+
|
|
+Driver-defined ethtool statistics can be dumped using `ethtool -S $ifc`, e.g.::
|
|
+
|
|
+ $ ethtool -S ens4u1u1
|
|
+ NIC statistics:
|
|
+ tx_single_collisions: 0
|
|
+ tx_multi_collisions: 0
|
|
+
|
|
+uAPIs
|
|
+=====
|
|
+
|
|
+procfs
|
|
+------
|
|
+
|
|
+The historical `/proc/net/dev` text interface gives access to the list
|
|
+of interfaces as well as their statistics.
|
|
+
|
|
+Note that even though this interface is using
|
|
+:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`
|
|
+internally it combines some of the fields.
|
|
+
|
|
+sysfs
|
|
+-----
|
|
+
|
|
+Each device directory in sysfs contains a `statistics` directory (e.g.
|
|
+`/sys/class/net/lo/statistics/`) with files corresponding to
|
|
+members of :c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`.
|
|
+
|
|
+This simple interface is convenient especially in constrained/embedded
|
|
+environments without access to tools. However, it's inefficient when
|
|
+reading multiple stats as it internally performs a full dump of
|
|
+:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`
|
|
+and reports only the stat corresponding to the accessed file.
|
|
+
|
|
+Sysfs files are documented in
|
|
+`Documentation/ABI/testing/sysfs-class-net-statistics`.
|
|
+
|
|
+
|
|
+netlink
|
|
+-------
|
|
+
|
|
+`rtnetlink` (`NETLINK_ROUTE`) is the preferred method of accessing
|
|
+:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>` stats.
|
|
+
|
|
+Statistics are reported both in the responses to link information
|
|
+requests (`RTM_GETLINK`) and statistic requests (`RTM_GETSTATS`,
|
|
+when `IFLA_STATS_LINK_64` bit is set in the `.filter_mask` of the request).
|
|
+
|
|
+ethtool
|
|
+-------
|
|
+
|
|
+Ethtool IOCTL interface allows drivers to report implementation
|
|
+specific statistics. Historically it has also been used to report
|
|
+statistics for which other APIs did not exist, like per-device-queue
|
|
+statistics, or standard-based statistics (e.g. RFC 2863).
|
|
+
|
|
+Statistics and their string identifiers are retrieved separately.
|
|
+Identifiers via `ETHTOOL_GSTRINGS` with `string_set` set to `ETH_SS_STATS`,
|
|
+and values via `ETHTOOL_GSTATS`. User space should use `ETHTOOL_GDRVINFO`
|
|
+to retrieve the number of statistics (`.n_stats`).
|
|
+
|
|
+ethtool-netlink
|
|
+---------------
|
|
+
|
|
+Ethtool netlink is a replacement for the older IOCTL interface.
|
|
+
|
|
+Protocol-related statistics can be requested in get commands by setting
|
|
+the `ETHTOOL_FLAG_STATS` flag in `ETHTOOL_A_HEADER_FLAGS`. Currently
|
|
+statistics are supported in the following commands:
|
|
+
|
|
+ - `ETHTOOL_MSG_PAUSE_GET`
|
|
+ - `ETHTOOL_MSG_FEC_GET`
|
|
+
|
|
+debugfs
|
|
+-------
|
|
+
|
|
+Some drivers expose extra statistics via `debugfs`.
|
|
+
|
|
+struct rtnl_link_stats64
|
|
+========================
|
|
+
|
|
+.. kernel-doc:: include/uapi/linux/if_link.h
|
|
+ :identifiers: rtnl_link_stats64
|
|
+
|
|
+Notes for driver authors
|
|
+========================
|
|
+
|
|
+Drivers should report all statistics which have a matching member in
|
|
+:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>` exclusively
|
|
+via `.ndo_get_stats64`. Reporting such standard stats via ethtool
|
|
+or debugfs will not be accepted.
|
|
+
|
|
+Drivers must ensure best possible compliance with
|
|
+:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`.
|
|
+Please note for example that detailed error statistics must be
|
|
+added into the general `rx_error` / `tx_error` counters.
|
|
+
|
|
+The `.ndo_get_stats64` callback can not sleep because of accesses
|
|
+via `/proc/net/dev`. If driver may sleep when retrieving the statistics
|
|
+from the device it should do so periodically asynchronously and only return
|
|
+a recent copy from `.ndo_get_stats64`. Ethtool interrupt coalescing interface
|
|
+allows setting the frequency of refreshing statistics, if needed.
|
|
+
|
|
+Retrieving ethtool statistics is a multi-syscall process, drivers are advised
|
|
+to keep the number of statistics constant to avoid race conditions with
|
|
+user space trying to read them.
|
|
+
|
|
+Statistics must persist across routine operations like bringing the interface
|
|
+down and up.
|
|
+
|
|
+Kernel-internal data structures
|
|
+-------------------------------
|
|
+
|
|
+The following structures are internal to the kernel, their members are
|
|
+translated to netlink attributes when dumped. Drivers must not overwrite
|
|
+the statistics they don't report with 0.
|
|
+
|
|
+- ethtool_pause_stats()
|
|
+- ethtool_fec_stats()
|
|
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
|
|
index 1b0afcdaf34e..e9b7695a4c0e 100644
|
|
--- a/include/linux/ethtool.h
|
|
+++ b/include/linux/ethtool.h
|
|
@@ -249,6 +249,48 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
|
|
ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ)
|
|
#define ETHTOOL_COALESCE_USE_ADAPTIVE \
|
|
(ETHTOOL_COALESCE_USE_ADAPTIVE_RX | ETHTOOL_COALESCE_USE_ADAPTIVE_TX)
|
|
+
|
|
+#define ETHTOOL_STAT_NOT_SET (~0ULL)
|
|
+
|
|
+static inline void ethtool_stats_init(u64 *stats, unsigned int n)
|
|
+{
|
|
+ while (n--)
|
|
+ stats[n] = ETHTOOL_STAT_NOT_SET;
|
|
+}
|
|
+
|
|
+#define ETHTOOL_MAX_LANES 8
|
|
+
|
|
+/**
|
|
+ * struct ethtool_fec_stats - statistics for IEEE 802.3 FEC
|
|
+ * @corrected_blocks: number of received blocks corrected by FEC
|
|
+ * Reported to user space as %ETHTOOL_A_FEC_STAT_CORRECTED.
|
|
+ *
|
|
+ * Equivalent to `30.5.1.1.17 aFECCorrectedBlocks` from the standard.
|
|
+ *
|
|
+ * @uncorrectable_blocks: number of received blocks FEC was not able to correct
|
|
+ * Reported to user space as %ETHTOOL_A_FEC_STAT_UNCORR.
|
|
+ *
|
|
+ * Equivalent to `30.5.1.1.18 aFECUncorrectableBlocks` from the standard.
|
|
+ *
|
|
+ * @corrected_bits: number of bits corrected by FEC
|
|
+ * Similar to @corrected_blocks but counts individual bit changes,
|
|
+ * not entire FEC data blocks. This is a non-standard statistic.
|
|
+ * Reported to user space as %ETHTOOL_A_FEC_STAT_CORR_BITS.
|
|
+ *
|
|
+ * @lane: per-lane/PCS-instance counts as defined by the standard
|
|
+ * @total: error counts for the entire port, for drivers incapable of reporting
|
|
+ * per-lane stats
|
|
+ *
|
|
+ * Drivers should fill in either only total or per-lane statistics, core
|
|
+ * will take care of adding lane values up to produce the total.
|
|
+ */
|
|
+struct ethtool_fec_stats {
|
|
+ struct ethtool_fec_stat {
|
|
+ u64 total;
|
|
+ u64 lanes[ETHTOOL_MAX_LANES];
|
|
+ } corrected_blocks, uncorrectable_blocks, corrected_bits;
|
|
+};
|
|
+
|
|
/**
|
|
* struct ethtool_ops - optional netdev operations
|
|
* @cap_link_lanes_supported: indicates if the driver supports lanes
|
|
@@ -363,19 +405,21 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
|
|
* a TX queue has this number, return -EINVAL. If only a RX queue or a TX
|
|
* queue has this number, ignore the inapplicable fields.
|
|
* Returns a negative error code or zero.
|
|
- * @get_link_ksettings: When defined, takes precedence over the
|
|
- * %get_settings method. Get various device settings
|
|
- * including Ethernet link settings. The %cmd and
|
|
- * %link_mode_masks_nwords fields should be ignored (use
|
|
- * %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter), any
|
|
- * change to them will be overwritten by kernel. Returns a
|
|
- * negative error code or zero.
|
|
- * @set_link_ksettings: When defined, takes precedence over the
|
|
- * %set_settings method. Set various device settings including
|
|
- * Ethernet link settings. The %cmd and %link_mode_masks_nwords
|
|
- * fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS
|
|
- * instead of the latter), any change to them will be overwritten
|
|
- * by kernel. Returns a negative error code or zero.
|
|
+ * @get_link_ksettings: Get various device settings including Ethernet link
|
|
+ * settings. The %cmd and %link_mode_masks_nwords fields should be
|
|
+ * ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter),
|
|
+ * any change to them will be overwritten by kernel. Returns a negative
|
|
+ * error code or zero.
|
|
+ * @set_link_ksettings: Set various device settings including Ethernet link
|
|
+ * settings. The %cmd and %link_mode_masks_nwords fields should be
|
|
+ * ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter),
|
|
+ * any change to them will be overwritten by kernel. Returns a negative
|
|
+ * error code or zero.
|
|
+ * @get_fec_stats: Report FEC statistics.
|
|
+ * Core will sum up per-lane stats to get the total.
|
|
+ * Drivers must not zero statistics which they don't report. The stats
|
|
+ * structure is initialized to ETHTOOL_STAT_NOT_SET indicating driver does
|
|
+ * not report statistics.
|
|
* @get_fecparam: Get the network device Forward Error Correction parameters.
|
|
* @set_fecparam: Set the network device Forward Error Correction parameters.
|
|
* @get_ethtool_phy_stats: Return extended statistics about the PHY device.
|
|
@@ -481,6 +525,8 @@ struct ethtool_ops {
|
|
struct ethtool_link_ksettings *);
|
|
int (*set_link_ksettings)(struct net_device *,
|
|
const struct ethtool_link_ksettings *);
|
|
+ void (*get_fec_stats)(struct net_device *dev,
|
|
+ struct ethtool_fec_stats *fec_stats);
|
|
int (*get_fecparam)(struct net_device *,
|
|
struct ethtool_fecparam *);
|
|
int (*set_fecparam)(struct net_device *,
|
|
diff --git a/include/net/netlink.h b/include/net/netlink.h
|
|
index 7b7c14128558..e91076f81d3e 100644
|
|
--- a/include/net/netlink.h
|
|
+++ b/include/net/netlink.h
|
|
@@ -270,7 +270,8 @@ struct nla_policy {
|
|
(tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64)
|
|
|
|
#define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition))
|
|
-
|
|
+#define NLA_ENSURE_UINT_TYPE(tp) \
|
|
+ (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp)) + tp)
|
|
#define NLA_ENSURE_INT_OR_BINARY_TYPE(tp) \
|
|
(__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp) || \
|
|
__NLA_IS_SINT_TYPE(tp) || \
|
|
@@ -296,6 +297,12 @@ struct nla_policy {
|
|
.max = _max, \
|
|
}
|
|
|
|
+#define NLA_POLICY_MASK(tp, _mask) { \
|
|
+ .type = NLA_ENSURE_UINT_TYPE(tp), \
|
|
+ .validation_type = NLA_VALIDATE_MASK, \
|
|
+ .mask = _mask, \
|
|
+}
|
|
+
|
|
/**
|
|
* struct nl_info - netlink source information
|
|
* @nlh: Netlink message header of original request
|
|
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
|
|
index 8dffdf192102..3b7ed0fe545a 100644
|
|
--- a/include/uapi/linux/ethtool_netlink.h
|
|
+++ b/include/uapi/linux/ethtool_netlink.h
|
|
@@ -72,6 +72,7 @@ enum {
|
|
#define ETHTOOL_FLAG_COMPACT_BITSETS (1 << 0)
|
|
/* provide optional reply for SET or ACT requests */
|
|
#define ETHTOOL_FLAG_OMIT_REPLY (1 << 1)
|
|
+#define ETHTOOL_FLAG_STATS (1 << 2)
|
|
|
|
#define ETHTOOL_FLAG_ALL (ETHTOOL_FLAG_COMPACT_BITSETS | \
|
|
ETHTOOL_FLAG_OMIT_REPLY)
|
|
@@ -303,11 +304,25 @@ enum {
|
|
ETHTOOL_A_FEC_MODES, /* bitset */
|
|
ETHTOOL_A_FEC_AUTO, /* u8 */
|
|
ETHTOOL_A_FEC_ACTIVE, /* u32 */
|
|
+ ETHTOOL_A_FEC_STATS, /* nest - _A_FEC_STAT */
|
|
|
|
__ETHTOOL_A_FEC_CNT,
|
|
ETHTOOL_A_FEC_MAX = (__ETHTOOL_A_FEC_CNT - 1)
|
|
};
|
|
|
|
+enum {
|
|
+ ETHTOOL_A_FEC_STAT_UNSPEC,
|
|
+ ETHTOOL_A_FEC_STAT_PAD,
|
|
+
|
|
+ ETHTOOL_A_FEC_STAT_CORRECTED, /* array, u64 */
|
|
+ ETHTOOL_A_FEC_STAT_UNCORR, /* array, u64 */
|
|
+ ETHTOOL_A_FEC_STAT_CORR_BITS, /* array, u64 */
|
|
+
|
|
+ /* add new constants above here */
|
|
+ __ETHTOOL_A_FEC_STAT_CNT,
|
|
+ ETHTOOL_A_FEC_STAT_MAX = (__ETHTOOL_A_FEC_STAT_CNT - 1)
|
|
+};
|
|
+
|
|
/* generic netlink info */
|
|
#define ETHTOOL_GENL_NAME "ethtool"
|
|
#define ETHTOOL_GENL_VERSION 1
|
|
diff --git a/net/ethtool/fec.c b/net/ethtool/fec.c
|
|
index 3e7d091ee7aa..8738dafd5417 100644
|
|
--- a/net/ethtool/fec.c
|
|
+++ b/net/ethtool/fec.c
|
|
@@ -13,6 +13,10 @@ struct fec_reply_data {
|
|
__ETHTOOL_DECLARE_LINK_MODE_MASK(fec_link_modes);
|
|
u32 active_fec;
|
|
u8 fec_auto;
|
|
+ struct fec_stat_grp {
|
|
+ u64 stats[1 + ETHTOOL_MAX_LANES];
|
|
+ u8 cnt;
|
|
+ } corr, uncorr, corr_bits;
|
|
};
|
|
|
|
#define FEC_REPDATA(__reply_base) \
|
|
@@ -21,7 +25,7 @@ struct fec_reply_data {
|
|
#define ETHTOOL_FEC_MASK ((ETHTOOL_FEC_LLRS << 1) - 1)
|
|
|
|
const struct nla_policy ethnl_fec_get_policy[ETHTOOL_A_FEC_HEADER + 1] = {
|
|
- [ETHTOOL_A_FEC_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
|
|
+ [ETHTOOL_A_FEC_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy_stats),
|
|
};
|
|
|
|
static void
|
|
@@ -64,6 +68,28 @@ ethtool_link_modes_to_fecparam(struct ethtool_fecparam *fec,
|
|
return 0;
|
|
}
|
|
|
|
+static void
|
|
+fec_stats_recalc(struct fec_stat_grp *grp, struct ethtool_fec_stat *stats)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (stats->lanes[0] == ETHTOOL_STAT_NOT_SET) {
|
|
+ grp->stats[0] = stats->total;
|
|
+ grp->cnt = stats->total != ETHTOOL_STAT_NOT_SET;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ grp->cnt = 1;
|
|
+ grp->stats[0] = 0;
|
|
+ for (i = 0; i < ETHTOOL_MAX_LANES; i++) {
|
|
+ if (stats->lanes[i] == ETHTOOL_STAT_NOT_SET)
|
|
+ break;
|
|
+
|
|
+ grp->stats[0] += stats->lanes[i];
|
|
+ grp->stats[grp->cnt++] = stats->lanes[i];
|
|
+ }
|
|
+}
|
|
+
|
|
static int fec_prepare_data(const struct ethnl_req_info *req_base,
|
|
struct ethnl_reply_data *reply_base,
|
|
struct genl_info *info)
|
|
@@ -82,6 +108,17 @@ static int fec_prepare_data(const struct ethnl_req_info *req_base,
|
|
ret = dev->ethtool_ops->get_fecparam(dev, &fec);
|
|
if (ret)
|
|
goto out_complete;
|
|
+ if (req_base->flags & ETHTOOL_FLAG_STATS &&
|
|
+ dev->ethtool_ops->get_fec_stats) {
|
|
+ struct ethtool_fec_stats stats;
|
|
+
|
|
+ ethtool_stats_init((u64 *)&stats, sizeof(stats) / 8);
|
|
+ dev->ethtool_ops->get_fec_stats(dev, &stats);
|
|
+
|
|
+ fec_stats_recalc(&data->corr, &stats.corrected_blocks);
|
|
+ fec_stats_recalc(&data->uncorr, &stats.uncorrectable_blocks);
|
|
+ fec_stats_recalc(&data->corr_bits, &stats.corrected_bits);
|
|
+ }
|
|
|
|
WARN_ON_ONCE(fec.reserved);
|
|
|
|
@@ -120,9 +157,40 @@ static int fec_reply_size(const struct ethnl_req_info *req_base,
|
|
len += nla_total_size(sizeof(u8)) + /* _FEC_AUTO */
|
|
nla_total_size(sizeof(u32)); /* _FEC_ACTIVE */
|
|
|
|
+ if (req_base->flags & ETHTOOL_FLAG_STATS)
|
|
+ len += 3 * nla_total_size_64bit(sizeof(u64) *
|
|
+ (1 + ETHTOOL_MAX_LANES));
|
|
+
|
|
return len;
|
|
}
|
|
|
|
+static int fec_put_stats(struct sk_buff *skb, const struct fec_reply_data *data)
|
|
+{
|
|
+ struct nlattr *nest;
|
|
+
|
|
+ nest = nla_nest_start(skb, ETHTOOL_A_FEC_STATS);
|
|
+ if (!nest)
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ if (nla_put_64bit(skb, ETHTOOL_A_FEC_STAT_CORRECTED,
|
|
+ sizeof(u64) * data->corr.cnt,
|
|
+ data->corr.stats, ETHTOOL_A_FEC_STAT_PAD) ||
|
|
+ nla_put_64bit(skb, ETHTOOL_A_FEC_STAT_UNCORR,
|
|
+ sizeof(u64) * data->uncorr.cnt,
|
|
+ data->uncorr.stats, ETHTOOL_A_FEC_STAT_PAD) ||
|
|
+ nla_put_64bit(skb, ETHTOOL_A_FEC_STAT_CORR_BITS,
|
|
+ sizeof(u64) * data->corr_bits.cnt,
|
|
+ data->corr_bits.stats, ETHTOOL_A_FEC_STAT_PAD))
|
|
+ goto err_cancel;
|
|
+
|
|
+ nla_nest_end(skb, nest);
|
|
+ return 0;
|
|
+
|
|
+err_cancel:
|
|
+ nla_nest_cancel(skb, nest);
|
|
+ return -EMSGSIZE;
|
|
+}
|
|
+
|
|
static int fec_fill_reply(struct sk_buff *skb,
|
|
const struct ethnl_req_info *req_base,
|
|
const struct ethnl_reply_data *reply_base)
|
|
@@ -143,6 +211,9 @@ static int fec_fill_reply(struct sk_buff *skb,
|
|
nla_put_u32(skb, ETHTOOL_A_FEC_ACTIVE, data->active_fec)))
|
|
return -EMSGSIZE;
|
|
|
|
+ if (req_base->flags & ETHTOOL_FLAG_STATS && fec_put_stats(skb, data))
|
|
+ return -EMSGSIZE;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
|
|
index 0b740fe1cd35..1fdf23c0a6ec 100644
|
|
--- a/net/ethtool/netlink.c
|
|
+++ b/net/ethtool/netlink.c
|
|
@@ -9,6 +9,10 @@ static struct genl_family ethtool_genl_family;
|
|
static bool ethnl_ok __read_mostly;
|
|
static u32 ethnl_bcast_seq;
|
|
|
|
+#define ETHTOOL_FLAGS_BASIC (ETHTOOL_FLAG_COMPACT_BITSETS | \
|
|
+ ETHTOOL_FLAG_OMIT_REPLY)
|
|
+#define ETHTOOL_FLAGS_STATS (ETHTOOL_FLAGS_BASIC | ETHTOOL_FLAG_STATS)
|
|
+
|
|
const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_MAX + 1] = {
|
|
[ETHTOOL_A_HEADER_UNSPEC] = { .type = NLA_REJECT },
|
|
[ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 },
|
|
@@ -17,6 +21,14 @@ const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_MAX + 1] = {
|
|
[ETHTOOL_A_HEADER_FLAGS] = { .type = NLA_U32 },
|
|
};
|
|
|
|
+const struct nla_policy ethnl_header_policy_stats[] = {
|
|
+ [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 },
|
|
+ [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING,
|
|
+ .len = ALTIFNAMSIZ - 1 },
|
|
+ [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32,
|
|
+ ETHTOOL_FLAGS_STATS),
|
|
+};
|
|
+
|
|
/**
|
|
* ethnl_parse_header_dev_get() - parse request header
|
|
* @req_info: structure to put results into
|
|
--
|
|
2.34.1
|
|
|