10SN/A#!/usr/bin/env python3 20SN/A# SPDX-License-Identifier: GPL-2.0 30SN/A 40SN/Aimport time 50SN/Aimport os 60SN/Afrom lib.py import ksft_run, ksft_exit, ksft_pr 70SN/Afrom lib.py import KsftSkipEx, KsftFailEx 80SN/Afrom lib.py import NetdevFamily, NlError 90SN/Afrom lib.py import NetDrvEpEnv 100SN/Afrom lib.py import cmd, tool, GenerateTraffic 110SN/A 120SN/A 130SN/Adef _write_fail_config(config): 140SN/A for key, value in config.items(): 150SN/A with open("/sys/kernel/debug/fail_function/" + key, "w") as fp: 160SN/A fp.write(str(value) + "\n") 170SN/A 180SN/A 190SN/Adef _enable_pp_allocation_fail(): 200SN/A if not os.path.exists("/sys/kernel/debug/fail_function"): 210SN/A raise KsftSkipEx("Kernel built without function error injection (or DebugFS)") 220SN/A 230SN/A if not os.path.exists("/sys/kernel/debug/fail_function/page_pool_alloc_pages"): 240SN/A with open("/sys/kernel/debug/fail_function/inject", "w") as fp: 250SN/A fp.write("page_pool_alloc_pages\n") 260SN/A 270SN/A _write_fail_config({ 280SN/A "verbose": 0, 290SN/A "interval": 511, 300SN/A "probability": 100, 310SN/A "times": -1, 320SN/A }) 330SN/A 340SN/A 350SN/Adef _disable_pp_allocation_fail(): 360SN/A if not os.path.exists("/sys/kernel/debug/fail_function"): 370SN/A return 380SN/A 390SN/A if os.path.exists("/sys/kernel/debug/fail_function/page_pool_alloc_pages"): 400SN/A with open("/sys/kernel/debug/fail_function/inject", "w") as fp: 410SN/A fp.write("\n") 420SN/A 430SN/A _write_fail_config({ 440SN/A "probability": 0, 450SN/A "times": 0, 460SN/A }) 470SN/A 480SN/A 490SN/Adef test_pp_alloc(cfg, netdevnl): 500SN/A def get_stats(): 510SN/A return netdevnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0] 520SN/A 530SN/A def check_traffic_flowing(): 540SN/A stat1 = get_stats() 550SN/A time.sleep(1) 560SN/A stat2 = get_stats() 570SN/A if stat2['rx-packets'] - stat1['rx-packets'] < 15000: 580SN/A raise KsftFailEx("Traffic seems low:", stat2['rx-packets'] - stat1['rx-packets']) 590SN/A 600SN/A 610SN/A try: 620SN/A stats = get_stats() 630SN/A except NlError as e: 640SN/A if e.nl_msg.error == -95: 650SN/A stats = {} 660SN/A else: 670SN/A raise 680SN/A if 'rx-alloc-fail' not in stats: 690SN/A raise KsftSkipEx("Driver does not report 'rx-alloc-fail' via qstats") 700SN/A 710SN/A set_g = False 720SN/A traffic = None 730SN/A try: 740SN/A traffic = GenerateTraffic(cfg) 750SN/A 760SN/A check_traffic_flowing() 770SN/A 780SN/A _enable_pp_allocation_fail() 790SN/A 800SN/A s1 = get_stats() 810SN/A time.sleep(3) 820SN/A s2 = get_stats() 830SN/A 840SN/A if s2['rx-alloc-fail'] - s1['rx-alloc-fail'] < 1: 850SN/A raise KsftSkipEx("Allocation failures not increasing") 860SN/A if s2['rx-alloc-fail'] - s1['rx-alloc-fail'] < 100: 870SN/A raise KsftSkipEx("Allocation increasing too slowly", s2['rx-alloc-fail'] - s1['rx-alloc-fail'], 880SN/A "packets:", s2['rx-packets'] - s1['rx-packets']) 890SN/A 900SN/A # Basic failures are fine, try to wobble some settings to catch extra failures 910SN/A check_traffic_flowing() 920SN/A g = tool("ethtool", "-g " + cfg.ifname, json=True)[0] 930SN/A if 'rx' in g and g["rx"] * 2 <= g["rx-max"]: 940SN/A new_g = g['rx'] * 2 950SN/A elif 'rx' in g: 960SN/A new_g = g['rx'] // 2 970SN/A else: 980SN/A new_g = None 990SN/A 1000SN/A if new_g: 1010SN/A set_g = cmd(f"ethtool -G {cfg.ifname} rx {new_g}", fail=False).ret == 0 1020SN/A if set_g: 1030SN/A ksft_pr("ethtool -G change retval: success") 1040SN/A else: 1050SN/A ksft_pr("ethtool -G change retval: did not succeed", new_g) 1060SN/A else: 1070SN/A ksft_pr("ethtool -G change retval: did not try") 1080SN/A 1090SN/A time.sleep(0.1) 1100SN/A check_traffic_flowing() 1110SN/A finally: 1120SN/A _disable_pp_allocation_fail() 1130SN/A if traffic: 1140SN/A traffic.stop() 1150SN/A time.sleep(0.1) 1160SN/A if set_g: 1170SN/A cmd(f"ethtool -G {cfg.ifname} rx {g['rx']}") 1180SN/A 1190SN/A 1200SN/Adef main() -> None: 1210SN/A netdevnl = NetdevFamily() 1220SN/A with NetDrvEpEnv(__file__, nsim_test=False) as cfg: 1230SN/A 1240SN/A ksft_run([test_pp_alloc], args=(cfg, netdevnl, )) 1250SN/A ksft_exit() 1260SN/A 1270SN/A 1280SN/Aif __name__ == "__main__": 1290SN/A main() 1300SN/A