Add selftest file to test basic features of a NIC driver. Tests for link modes, auto-negotiation are placed. Selftest makes use of ksft modules and ethtool. Add selftest file in the Makefile. Signed-off-by: Mohan Prasad J <mohan.prasad@xxxxxxxxxxxxx> --- .../testing/selftests/drivers/net/hw/Makefile | 1 + .../drivers/net/hw/nic_basic_tests.py | 145 ++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 tools/testing/selftests/drivers/net/hw/nic_basic_tests.py diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile index c9f2f48fc..9f105227c 100644 --- a/tools/testing/selftests/drivers/net/hw/Makefile +++ b/tools/testing/selftests/drivers/net/hw/Makefile @@ -10,6 +10,7 @@ TEST_PROGS = \ hw_stats_l3.sh \ hw_stats_l3_gre.sh \ loopback.sh \ + nic_basic_tests.py \ pp_alloc_fail.py \ rss_ctx.py \ # diff --git a/tools/testing/selftests/drivers/net/hw/nic_basic_tests.py b/tools/testing/selftests/drivers/net/hw/nic_basic_tests.py new file mode 100644 index 000000000..27f780032 --- /dev/null +++ b/tools/testing/selftests/drivers/net/hw/nic_basic_tests.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +#Introduction: +#This file has basic tests for generic NIC drivers. +#The test comprises of auto-negotiation, speed and duplex checks. +#Also has tests to check the throughput +# +#Setup: +#Connect the DUT PC with NIC card to partner pc back via ethernet medium of your choice(RJ45, T1) +# +# DUT PC Partner PC +#┌───────────────────────┐ ┌──────────────────────────┐ +#│ │ │ │ +#│ │ │ │ +#│ ┌───────────┐ │ │ +#│ │DUT NIC │ Eth │ │ +#│ │Interface ─┼─────────────────────────┼─ any eth Interface │ +#│ └───────────┘ │ │ +#│ │ │ │ +#│ │ │ │ +#└───────────────────────┘ └──────────────────────────┘ +# +#Configurations: +# Change the below configuration based on your hw needs. +# """Default values""" +sleep_time = 5 #time taken to wait for transitions to happen, in seconds. +test_duration = 5 #performance test duration for the throughput check, in seconds. +throughput_threshold = 0.8 #percentage of throughput required to pass the throughput + +import time +import os +import re +import configparser +import json +from lib.py import ksft_run, ksft_exit, ksft_pr, ksft_eq +from lib.py import KsftFailEx, KsftSkipEx +from lib.py import NetDrvEpEnv +from lib.py import cmd +from lib.py import ethtool + +"""Global variables""" +common_link_modes = [] + +def get_ethtool_content(ifname: str, field: str): + capture = False + content = [] + + """Get the ethtool content for the interface""" + process = ethtool(f"{ifname}") + if process.ret != 0: + raise KsftSkipEx(f"Error while getting the ethtool content for interface {ifname}") + lines = process.stdout.splitlines() + + """Retrieve the content of the field""" + for line in lines: + if field in line: + capture = True + data = line.split(":")[1].strip() + content.extend(data.split()) + continue + + if capture: + if ":" in line: + break; + if line.strip(): + content.extend(line.strip().split()) + if capture == False: + raise KsftSkipEx(f"Field \"{field}\" not found in ethtool output") + return content + +def get_speed_duplex(content): + speed = [] + duplex = [] + """Check the link modes""" + for data in content: + parts = data.split('/') + speed_value = re.match(r'\d+', parts[0]) + if speed_value: + speed.append(speed_value.group()) + else: + raise KsftSkipEx(f"No speed value found for interface {ifname}") + duplex.append(parts[1].lower()) + return speed, duplex + +def verify_link_up(ifname: str) -> None: + """Verify whether the link is up""" + with open(f"/sys/class/net/{ifname}/operstate", "r") as fp: + link_state = fp.read().strip() + + if link_state == "down": + raise KsftSkipEx(f"Link state of interface {ifname} is DOWN") + +def set_autonegotiation_state(ifname: str, state: str) -> None: + content = get_ethtool_content(ifname, "Supported link modes:") + speeds, duplex_modes = get_speed_duplex(content) + speed = speeds[0] + duplex = duplex_modes[0] + if not speed or not duplex: + KsftSkipEx("No speed or duplex modes found") + """Set the autonegotiation state for the interface""" + process = ethtool(f"-s {ifname} speed {speed} duplex {duplex} autoneg {state}") + if process.ret != 0: + raise KsftFailEx(f"Not able to set autoneg parameter for {ifname}") + ksft_pr(f"Autoneg set as {state} for {ifname}") + +def verify_autonegotiation(ifname: str, expected_state: str) -> None: + verify_link_up(ifname) + """Verifying the autonegotiation state""" + output = get_ethtool_content(ifname, "Auto-negotiation:") + actual_state = output[0] + + ksft_eq(actual_state, expected_state) + +def test_link_modes(cfg) -> None: + global common_link_modes + link_modes = get_ethtool_content(cfg.ifname, "Supported link modes:") + partner_link_modes = get_ethtool_content(cfg.ifname, "Link partner advertised link modes:") + + if link_modes and partner_link_modes: + for idx1 in range(len(link_modes)): + for idx2 in range(len(partner_link_modes)): + if link_modes[idx1] == partner_link_modes[idx2]: + common_link_modes.append(link_modes[idx1]) + break + else: + raise KsftFailEx("No link modes available") + +def test_autonegotiation(cfg) -> None: + autoneg = get_ethtool_content(cfg.ifname, "Supports auto-negotiation:") + if autoneg[0] == "Yes": + for state in ["off", "on"]: + set_autonegotiation_state(cfg.ifname, state) + time.sleep(sleep_time) + verify_autonegotiation(cfg.ifname, state) + else: + raise KsftSkipEx(f"Auto-Negotiation is not supported for interface {cfg.ifname}") + +def main() -> None: + with NetDrvEpEnv(__file__) as cfg: + ksft_run(globs=globals(), case_pfx={"test_"}, args=(cfg,)) + ksft_exit() + +if __name__ == "__main__": + main() -- 2.43.0