Add a selftest that logs the device information a driver reports through the devlink info interface: the driver name, serial numbers and every reported version, in the format NIPA CI consumes for device regression tracking. This helps maintainers identify pass/fail status changes caused by FW updates.
Implementing devlink info is optional. devlink reports the driver name for every registered instance, even when the driver does not implement info_get, so a device that reports no versions and no serial number is skipped rather than failed. Devices with no devlink instance are skipped as well. The devlink 'driver' attribute names the driver bound to the parent device, which may legitimately differ from the netdev's ethtool driver - mlx4 reports mlx4_core and mlx4_en, and DSA user ports report dsa - so a difference is logged but not treated as a failure. ethtool is only used for an optional fallback handle lookup and that comparison, so it is not required to run the test. NETIF is read from the environment or from drivers/net/net.config as described in drivers/net/README.rst. net.config is sourced before net/lib.sh so that it cannot clobber the framework's globals. The test needs only a single local interface, so it sources net/lib.sh rather than the forwarding library, which requires NUM_NETIFS and a configured remote host. Example usage: NETIF=eth0 ./tools/testing/selftests/drivers/net/hw/devlink_info.sh INFO: driver: idpf INFO: serial_number: 00-a0-c9-ff-ff-23-45-67 INFO: fw.mgmt.api (running): 2.0 TEST: devlink info [ OK ] Link: https://github.com/linux-netdev/nipa/wiki/Netdev-CI-system#device-information Signed-off-by: Paul Greenwalt <[email protected]> --- .../testing/selftests/drivers/net/hw/Makefile | 1 + .../selftests/drivers/net/hw/devlink_info.sh | 160 ++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100755 tools/testing/selftests/drivers/net/hw/devlink_info.sh diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile index 78bb0169350b..edd353f27a39 100644 --- a/tools/testing/selftests/drivers/net/hw/Makefile +++ b/tools/testing/selftests/drivers/net/hw/Makefile @@ -19,6 +19,7 @@ TEST_GEN_FILES := \ TEST_PROGS = \ csum.py \ + devlink_info.sh \ devlink_rate_cross_esw.py \ devlink_rate_tc_bw.py \ devmem.py \ diff --git a/tools/testing/selftests/drivers/net/hw/devlink_info.sh b/tools/testing/selftests/drivers/net/hw/devlink_info.sh new file mode 100755 index 000000000000..1a23e7d3c5af --- /dev/null +++ b/tools/testing/selftests/drivers/net/hw/devlink_info.sh @@ -0,0 +1,160 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Test devlink info support +# +# This test logs the device information a driver reports through the devlink +# info interface, in the format NIPA CI consumes for regression tracking (see +# the Device information section at +# https://github.com/linux-netdev/nipa/wiki/Netdev-CI-system). +# +# Implementing devlink info is optional, so a device whose driver reports no +# versions and no serial number is skipped rather than failed. +# +# Usage: +# NETIF=eth0 ./devlink_info.sh + +ALL_TESTS="devlink_info_test" + +lib_dir=$(dirname "$0") + +# NETIF may also be provided through drivers/net/net.config, as documented in +# drivers/net/README.rst. Source it before lib.sh so that a stray assignment +# cannot clobber the framework's globals. +if [[ -z "$NETIF" && -f "$lib_dir/../net.config" ]]; then + source "$lib_dir/../net.config" +fi + +source "$lib_dir"/../../../net/lib.sh + +require_command devlink +require_command jq + +DL_HANDLE= +DL_INFO= + +setup_prepare() +{ + local err + + if [[ -z "$NETIF" ]]; then + echo "SKIP: NETIF is not configured" + exit "$ksft_skip" + fi + + # Try to get the devlink handle from the devlink port first. + DL_HANDLE=$(devlink -j port show 2>/dev/null | + jq -r --arg netif "$NETIF" \ + '.port | to_entries[] | + select(.value.netdev == $netif) | .key' 2>/dev/null | + head -n 1 | + cut -d/ -f1-2) + + # Fall back to the PCI address reported by ethtool. Devices on other + # buses are only found through the devlink port lookup above. + if [[ -z "$DL_HANDLE" ]] && command -v ethtool >/dev/null; then + local bus_info + + bus_info=$(ethtool -i "$NETIF" 2>/dev/null | + awk '/^bus-info:/ {print $2}') + if [[ -n "$bus_info" ]] && + devlink dev show "pci/$bus_info" &>/dev/null; then + DL_HANDLE="pci/$bus_info" + fi + fi + + if [[ -z "$DL_HANDLE" ]]; then + echo "SKIP: could not find devlink handle for $NETIF" + exit "$ksft_skip" + fi + + # Query once so that a single snapshot is validated throughout. + DL_INFO=$(devlink -j dev info "$DL_HANDLE" 2>/dev/null) + err=$? + if ((err)); then + echo "SKIP: devlink dev info failed for $DL_HANDLE" + exit "$ksft_skip" + fi +} + +# jq's "// empty" maps a missing or null field to no output, so callers get an +# empty string rather than the literal text "null". +info_get() +{ + local name=$1 + + jq -r --arg name "$name" '.[][][$name] // empty' <<<"$DL_INFO" +} + +log_versions() +{ + local versions line + + versions=$(jq -r '.[][].versions // {} | to_entries[] | .key as $type | + .value | to_entries[] | + "\(.key) (\($type)): \(.value)"' <<<"$DL_INFO" \ + 2>/dev/null) + + while IFS= read -r line; do + [[ -n "$line" ]] && log_info "$line" + done <<<"$versions" +} + +has_any_version() +{ + jq -e '.[][].versions // {} | [.[] | to_entries[]] | length > 0' \ + <<<"$DL_INFO" &>/dev/null +} + +devlink_info_test() +{ + RET=0 + + local driver serial board_serial + + driver=$(info_get "driver") + serial=$(info_get "serial_number") + board_serial=$(info_get "board.serial_number") + + # devlink reports the driver name for every registered instance, even + # when the driver does not implement info_get. Everything else is + # optional, so a device with nothing further to report is not a + # failure. + if ! has_any_version && [[ -z "$serial" && -z "$board_serial" ]]; then + log_test_skip "devlink info" "no info reported for $DL_HANDLE" + return + fi + + if [[ -z "$driver" ]]; then + check_err 1 "no driver name reported" + else + log_info "driver: $driver" + fi + + # devlink names the driver bound to the parent device, which can + # legitimately differ from the netdev's ethtool driver, so report a + # difference without failing. + if command -v ethtool >/dev/null; then + local ethtool_driver + + ethtool_driver=$(ethtool -i "$NETIF" 2>/dev/null | + awk '/^driver:/ {print $2}') + if [[ -n "$driver" && -n "$ethtool_driver" && + "$driver" != "$ethtool_driver" ]]; then + log_info "driver mismatch: devlink='$driver' ethtool='$ethtool_driver'" + fi + fi + + [[ -n "$serial" ]] && log_info "serial_number: $serial" + [[ -n "$board_serial" ]] && log_info "board.serial_number: $board_serial" + + log_versions + + log_test "devlink info" +} + +setup_prepare + +tests_run + +exit "$EXIT_STATUS" -- 2.52.0
