selftests: drivers: hw: add test for the ethtool standard counters

Add a new selftest - ethtool_std_stats.sh - which validates the
eth-ctrl, eth-mac and pause standard statistics exported by an
interface. Collision related eth-mac counters as well as the error ones
will be checked against zero since that is the most likely correct
scenario.

The central part of this patch is the traffic_test() function which
gathers the 'before' counter values, sends a batch of traffic and then
interrogates again the same counters in order to determine if the delta
is on target. The function receives an array through which the caller
can request what counters to be interrogated and, for each of them, what
is their target delta value.

The output from this selftest looks as follows on a LX2160ARDB board:

 $ ./run_kselftest.sh -t drivers/net/hw:ethtool_std_stats.sh
 TAP version 13
 1..1
 # timeout set to 0
 # selftests: drivers/net/hw: ethtool_std_stats.sh
 # TAP version 13
 # 1..26
 # ok 1 ethtool_std_stats.eth-ctrl-MACControlFramesTransmitted
 # ok 2 ethtool_std_stats.eth-ctrl-MACControlFramesReceived
 # ok 3 ethtool_std_stats.eth-mac-FrameCheckSequenceErrors
 # ok 4 ethtool_std_stats.eth-mac-AlignmentErrors
 # ok 5 ethtool_std_stats.eth-mac-FramesLostDueToIntMACXmitError
 # ok 6 ethtool_std_stats.eth-mac-CarrierSenseErrors # SKIP
 # ok 7 ethtool_std_stats.eth-mac-FramesLostDueToIntMACRcvError
 # ok 8 ethtool_std_stats.eth-mac-InRangeLengthErrors # SKIP
 # ok 9 ethtool_std_stats.eth-mac-OutOfRangeLengthField # SKIP
 # ok 10 ethtool_std_stats.eth-mac-FrameTooLongErrors # SKIP
 # ok 11 ethtool_std_stats.eth-mac-FramesAbortedDueToXSColls # SKIP
 # ok 12 ethtool_std_stats.eth-mac-SingleCollisionFrames # SKIP
 # ok 13 ethtool_std_stats.eth-mac-MultipleCollisionFrames # SKIP
 # ok 14 ethtool_std_stats.eth-mac-FramesWithDeferredXmissions # SKIP
 # ok 15 ethtool_std_stats.eth-mac-LateCollisions # SKIP
 # ok 16 ethtool_std_stats.eth-mac-FramesWithExcessiveDeferral # SKIP
 # ok 17 ethtool_std_stats.eth-mac-BroadcastFramesXmittedOK
 # ok 18 ethtool_std_stats.eth-mac-OctetsTransmittedOK
 # ok 19 ethtool_std_stats.eth-mac-BroadcastFramesReceivedOK
 # ok 20 ethtool_std_stats.eth-mac-OctetsReceivedOK
 # ok 21 ethtool_std_stats.eth-mac-FramesTransmittedOK
 # ok 22 ethtool_std_stats.eth-mac-MulticastFramesXmittedOK
 # ok 23 ethtool_std_stats.eth-mac-FramesReceivedOK
 # ok 24 ethtool_std_stats.eth-mac-MulticastFramesReceivedOK
 # ok 25 ethtool_std_stats.pause-tx_pause_frames
 # ok 26 ethtool_std_stats.pause-rx_pause_frames
 # # 10 skipped test(s) detected.  Consider enabling relevant config options to improve coverage.
 # # Totals: pass:16 fail:0 xfail:0 xpass:0 skip:10 error:0
 ok 1 selftests: drivers/net/hw: ethtool_std_stats.sh

Please note that not all MACs are counting the software injected pause
frames as real Tx pause. For example, on a LS1028ARDB the selftest
output will reflect the fact that neither the ENETC MAC, nor the Felix
switch MAC are able to detect Tx pause frames injected by software.

 $ ./run_kselftest.sh -t drivers/net/hw:ethtool_std_stats.sh
 (...)
 # # software sent pause frames not detected
 # ok 25 ethtool_std_stats.pause-tx_pause_frames # XFAIL
 # ok 26 ethtool_std_stats.pause-rx_pause_frames

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Acked-by: Petr Machata <petrm@nvidia.com>
Link: https://patch.msgid.link/20260330152933.2195885-10-ioana.ciornei@nxp.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Ioana Ciornei
2026-03-30 18:29:33 +03:00
committed by Paolo Abeni
parent abe4929bc7
commit 3016574ea2
2 changed files with 207 additions and 0 deletions

View File

@@ -26,6 +26,7 @@ TEST_PROGS = \
ethtool_extended_state.sh \
ethtool_mm.sh \
ethtool_rmon.sh \
ethtool_std_stats.sh \
gro_hw.py \
hw_stats_l3.sh \
hw_stats_l3_gre.sh \

View File

@@ -0,0 +1,206 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#shellcheck disable=SC2034 # SC does not see the global variables
#shellcheck disable=SC2317,SC2329 # unused functions
ALL_TESTS="
test_eth_ctrl_stats
test_eth_mac_stats
test_pause_stats
"
: "${DRIVER_TEST_CONFORMANT:=yes}"
STABLE_MAC_ADDRS=yes
NUM_NETIFS=2
lib_dir=$(dirname "$0")
# shellcheck source=./../../../net/forwarding/lib.sh
source "$lib_dir"/../../../net/forwarding/lib.sh
# shellcheck source=./../../../kselftest/ktap_helpers.sh
source "$lib_dir"/../../../kselftest/ktap_helpers.sh
UINT32_MAX=$((2**32 - 1))
SUBTESTS=0
TEST_NAME=$(basename "$0" .sh)
traffic_test()
{
local iface=$1; shift
local neigh=$1; shift
local num_tx=$1; shift
local pkt_format="$1"; shift
local -a counters=("$@")
local int grp cnt target exact_check
local before after delta
local num_rx=$((num_tx * 2))
local xfail_message
local src="aggregate"
local i
for i in "${!counters[@]}"; do
read -r int grp cnt target exact_check xfail_message \
<<< "${counters[$i]}"
before[i]=$(ethtool_std_stats_get "$int" "$grp" "$cnt" "$src")
done
# shellcheck disable=SC2086 # needs split options
run_on "$iface" "$MZ" "$iface" -q -c "$num_tx" $pkt_format
# shellcheck disable=SC2086 # needs split options
run_on "$neigh" "$MZ" "$neigh" -q -c "$num_rx" $pkt_format
for i in "${!counters[@]}"; do
read -r int grp cnt target exact_check xfail_message \
<<< "${counters[$i]}"
after[i]=$(ethtool_std_stats_get "$int" "$grp" "$cnt" "$src")
if [[ "${after[$i]}" == "null" ]]; then
ktap_test_skip "$TEST_NAME.$grp-$cnt"
continue;
fi
delta=$((after[i] - before[i]))
if [ "$exact_check" -ne 0 ]; then
[ "$delta" -eq "$target" ]
else
[ "$delta" -ge "$target" ] && \
[ "$delta" -le "$UINT32_MAX" ]
fi
err="$?"
if [[ $err != 0 ]] && [[ -n $xfail_message ]]; then
ktap_print_msg "$xfail_message"
ktap_test_xfail "$TEST_NAME.$grp-$cnt"
continue;
fi
if [[ $err != 0 ]]; then
ktap_print_msg "$grp-$cnt is not valid on $int (expected $target, got $delta)"
ktap_test_fail "$TEST_NAME.$grp-$cnt"
else
ktap_test_pass "$TEST_NAME.$grp-$cnt"
fi
done
}
test_eth_ctrl_stats()
{
local pkt_format="-a own -b bcast 88:08 -p 64"
local num_pkts=1000
local -a counters
counters=("$h1 eth-ctrl MACControlFramesTransmitted $num_pkts 0")
traffic_test "$h1" "$h2" "$num_pkts" "$pkt_format" \
"${counters[@]}"
counters=("$h1 eth-ctrl MACControlFramesReceived $num_pkts 0")
traffic_test "$h2" "$h1" "$num_pkts" "$pkt_format" \
"${counters[@]}"
}
SUBTESTS=$((SUBTESTS + 2))
test_eth_mac_stats()
{
local pkt_size=100
local pkt_size_fcs=$((pkt_size + 4))
local bcast_pkt_format="-a own -b bcast -p $pkt_size"
local mcast_pkt_format="-a own -b 01:00:5E:00:00:01 -p $pkt_size"
local num_pkts=2000
local octets=$((pkt_size_fcs * num_pkts))
local -a counters error_cnt collision_cnt
# Error counters should be exactly zero
counters=("$h1 eth-mac FrameCheckSequenceErrors 0 1"
"$h1 eth-mac AlignmentErrors 0 1"
"$h1 eth-mac FramesLostDueToIntMACXmitError 0 1"
"$h1 eth-mac CarrierSenseErrors 0 1"
"$h1 eth-mac FramesLostDueToIntMACRcvError 0 1"
"$h1 eth-mac InRangeLengthErrors 0 1"
"$h1 eth-mac OutOfRangeLengthField 0 1"
"$h1 eth-mac FrameTooLongErrors 0 1"
"$h1 eth-mac FramesAbortedDueToXSColls 0 1")
traffic_test "$h1" "$h2" "$num_pkts" "$bcast_pkt_format" \
"${counters[@]}"
# Collision related counters should also be zero
counters=("$h1 eth-mac SingleCollisionFrames 0 1"
"$h1 eth-mac MultipleCollisionFrames 0 1"
"$h1 eth-mac FramesWithDeferredXmissions 0 1"
"$h1 eth-mac LateCollisions 0 1"
"$h1 eth-mac FramesWithExcessiveDeferral 0 1")
traffic_test "$h1" "$h2" "$num_pkts" "$bcast_pkt_format" \
"${counters[@]}"
counters=("$h1 eth-mac BroadcastFramesXmittedOK $num_pkts 0"
"$h1 eth-mac OctetsTransmittedOK $octets 0")
traffic_test "$h1" "$h2" "$num_pkts" "$bcast_pkt_format" \
"${counters[@]}"
counters=("$h1 eth-mac BroadcastFramesReceivedOK $num_pkts 0"
"$h1 eth-mac OctetsReceivedOK $octets 0")
traffic_test "$h2" "$h1" "$num_pkts" "$bcast_pkt_format" \
"${counters[@]}"
counters=("$h1 eth-mac FramesTransmittedOK $num_pkts 0"
"$h1 eth-mac MulticastFramesXmittedOK $num_pkts 0")
traffic_test "$h1" "$h2" "$num_pkts" "$mcast_pkt_format" \
"${counters[@]}"
counters=("$h1 eth-mac FramesReceivedOK $num_pkts 0"
"$h1 eth-mac MulticastFramesReceivedOK $num_pkts 0")
traffic_test "$h2" "$h1" "$num_pkts" "$mcast_pkt_format" \
"${counters[@]}"
}
SUBTESTS=$((SUBTESTS + 22))
test_pause_stats()
{
local pkt_format="-a own -b 01:80:c2:00:00:01 88:08:00:01:00:01"
local xfail_message="software sent pause frames not detected"
local num_pkts=2000
local -a counters
local int
local i
# Check that there is pause frame support
for ((i = 1; i <= NUM_NETIFS; ++i)); do
int="${NETIFS[p$i]}"
if ! run_on "$int" ethtool -I --json -a "$int" > /dev/null 2>&1; then
ktap_test_skip "$TEST_NAME.tx_pause_frames"
ktap_test_skip "$TEST_NAME.rx_pause_frames"
return
fi
done
counters=("$h1 pause tx_pause_frames $num_pkts 0 $xfail_message")
traffic_test "$h1" "$h2" "$num_pkts" "$pkt_format" \
"${counters[@]}"
counters=("$h1 pause rx_pause_frames $num_pkts 0")
traffic_test "$h2" "$h1" "$num_pkts" "$pkt_format" \
"${counters[@]}"
}
SUBTESTS=$((SUBTESTS + 2))
setup_prepare()
{
local iface
h1=${NETIFS[p1]}
h2=${NETIFS[p2]}
h2_mac=$(mac_get "$h2")
}
ktap_print_header
ktap_set_plan $SUBTESTS
check_ethtool_counter_group_support
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
ktap_finished