1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3 4import errno 5import time 6import os 7from lib.py import ksft_run, ksft_exit, ksft_pr 8from lib.py import KsftSkipEx, KsftFailEx 9from lib.py import NetdevFamily, NlError 10from lib.py import NetDrvEpEnv 11from lib.py import cmd, tool, GenerateTraffic 12 13 14def _write_fail_config(config): 15 for key, value in config.items(): 16 with open("/sys/kernel/debug/fail_function/" + key, "w") as fp: 17 fp.write(str(value) + "\n") 18 19 20def _enable_pp_allocation_fail(): 21 if not os.path.exists("/sys/kernel/debug/fail_function"): 22 raise KsftSkipEx("Kernel built without function error injection (or DebugFS)") 23 24 if not os.path.exists("/sys/kernel/debug/fail_function/page_pool_alloc_pages"): 25 with open("/sys/kernel/debug/fail_function/inject", "w") as fp: 26 fp.write("page_pool_alloc_pages\n") 27 28 _write_fail_config({ 29 "verbose": 0, 30 "interval": 511, 31 "probability": 100, 32 "times": -1, 33 }) 34 35 36def _disable_pp_allocation_fail(): 37 if not os.path.exists("/sys/kernel/debug/fail_function"): 38 return 39 40 if os.path.exists("/sys/kernel/debug/fail_function/page_pool_alloc_pages"): 41 with open("/sys/kernel/debug/fail_function/inject", "w") as fp: 42 fp.write("\n") 43 44 _write_fail_config({ 45 "probability": 0, 46 "times": 0, 47 }) 48 49 50def test_pp_alloc(cfg, netdevnl): 51 def get_stats(): 52 return netdevnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0] 53 54 def check_traffic_flowing(): 55 stat1 = get_stats() 56 time.sleep(1) 57 stat2 = get_stats() 58 if stat2['rx-packets'] - stat1['rx-packets'] < 15000: 59 raise KsftFailEx("Traffic seems low:", stat2['rx-packets'] - stat1['rx-packets']) 60 61 62 try: 63 stats = get_stats() 64 except NlError as e: 65 if e.nl_msg.error == -errno.EOPNOTSUPP: 66 stats = {} 67 else: 68 raise 69 if 'rx-alloc-fail' not in stats: 70 raise KsftSkipEx("Driver does not report 'rx-alloc-fail' via qstats") 71 72 set_g = False 73 traffic = None 74 try: 75 traffic = GenerateTraffic(cfg) 76 77 check_traffic_flowing() 78 79 _enable_pp_allocation_fail() 80 81 s1 = get_stats() 82 time.sleep(3) 83 s2 = get_stats() 84 85 if s2['rx-alloc-fail'] - s1['rx-alloc-fail'] < 1: 86 raise KsftSkipEx("Allocation failures not increasing") 87 if s2['rx-alloc-fail'] - s1['rx-alloc-fail'] < 100: 88 raise KsftSkipEx("Allocation increasing too slowly", s2['rx-alloc-fail'] - s1['rx-alloc-fail'], 89 "packets:", s2['rx-packets'] - s1['rx-packets']) 90 91 # Basic failures are fine, try to wobble some settings to catch extra failures 92 check_traffic_flowing() 93 g = tool("ethtool", "-g " + cfg.ifname, json=True)[0] 94 if 'rx' in g and g["rx"] * 2 <= g["rx-max"]: 95 new_g = g['rx'] * 2 96 elif 'rx' in g: 97 new_g = g['rx'] // 2 98 else: 99 new_g = None 100 101 if new_g: 102 set_g = cmd(f"ethtool -G {cfg.ifname} rx {new_g}", fail=False).ret == 0 103 if set_g: 104 ksft_pr("ethtool -G change retval: success") 105 else: 106 ksft_pr("ethtool -G change retval: did not succeed", new_g) 107 else: 108 ksft_pr("ethtool -G change retval: did not try") 109 110 time.sleep(0.1) 111 check_traffic_flowing() 112 finally: 113 _disable_pp_allocation_fail() 114 if traffic: 115 traffic.stop() 116 time.sleep(0.1) 117 if set_g: 118 cmd(f"ethtool -G {cfg.ifname} rx {g['rx']}") 119 120 121def main() -> None: 122 netdevnl = NetdevFamily() 123 with NetDrvEpEnv(__file__, nsim_test=False) as cfg: 124 125 ksft_run([test_pp_alloc], args=(cfg, netdevnl, )) 126 ksft_exit() 127 128 129if __name__ == "__main__": 130 main() 131