xref: /linux/tools/testing/selftests/drivers/net/hw/pp_alloc_fail.py (revision 9410645520e9b820069761f3450ef6661418e279)
19da271f8SJakub Kicinski#!/usr/bin/env python3
29da271f8SJakub Kicinski# SPDX-License-Identifier: GPL-2.0
39da271f8SJakub Kicinski
4*a48395f2SStanislav Fomichevimport errno
59da271f8SJakub Kicinskiimport time
69da271f8SJakub Kicinskiimport os
79da271f8SJakub Kicinskifrom lib.py import ksft_run, ksft_exit, ksft_pr
89da271f8SJakub Kicinskifrom lib.py import KsftSkipEx, KsftFailEx
99da271f8SJakub Kicinskifrom lib.py import NetdevFamily, NlError
109da271f8SJakub Kicinskifrom lib.py import NetDrvEpEnv
119da271f8SJakub Kicinskifrom lib.py import cmd, tool, GenerateTraffic
129da271f8SJakub Kicinski
139da271f8SJakub Kicinski
149da271f8SJakub Kicinskidef _write_fail_config(config):
159da271f8SJakub Kicinski    for key, value in config.items():
169da271f8SJakub Kicinski        with open("/sys/kernel/debug/fail_function/" + key, "w") as fp:
179da271f8SJakub Kicinski            fp.write(str(value) + "\n")
189da271f8SJakub Kicinski
199da271f8SJakub Kicinski
209da271f8SJakub Kicinskidef _enable_pp_allocation_fail():
219da271f8SJakub Kicinski    if not os.path.exists("/sys/kernel/debug/fail_function"):
229da271f8SJakub Kicinski        raise KsftSkipEx("Kernel built without function error injection (or DebugFS)")
239da271f8SJakub Kicinski
249da271f8SJakub Kicinski    if not os.path.exists("/sys/kernel/debug/fail_function/page_pool_alloc_pages"):
259da271f8SJakub Kicinski        with open("/sys/kernel/debug/fail_function/inject", "w") as fp:
269da271f8SJakub Kicinski            fp.write("page_pool_alloc_pages\n")
279da271f8SJakub Kicinski
289da271f8SJakub Kicinski    _write_fail_config({
299da271f8SJakub Kicinski        "verbose": 0,
309da271f8SJakub Kicinski        "interval": 511,
319da271f8SJakub Kicinski        "probability": 100,
329da271f8SJakub Kicinski        "times": -1,
339da271f8SJakub Kicinski    })
349da271f8SJakub Kicinski
359da271f8SJakub Kicinski
369da271f8SJakub Kicinskidef _disable_pp_allocation_fail():
379da271f8SJakub Kicinski    if not os.path.exists("/sys/kernel/debug/fail_function"):
389da271f8SJakub Kicinski        return
399da271f8SJakub Kicinski
409da271f8SJakub Kicinski    if os.path.exists("/sys/kernel/debug/fail_function/page_pool_alloc_pages"):
419da271f8SJakub Kicinski        with open("/sys/kernel/debug/fail_function/inject", "w") as fp:
429da271f8SJakub Kicinski            fp.write("\n")
439da271f8SJakub Kicinski
449da271f8SJakub Kicinski    _write_fail_config({
459da271f8SJakub Kicinski        "probability": 0,
469da271f8SJakub Kicinski        "times": 0,
479da271f8SJakub Kicinski    })
489da271f8SJakub Kicinski
499da271f8SJakub Kicinski
509da271f8SJakub Kicinskidef test_pp_alloc(cfg, netdevnl):
519da271f8SJakub Kicinski    def get_stats():
529da271f8SJakub Kicinski        return netdevnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
539da271f8SJakub Kicinski
549da271f8SJakub Kicinski    def check_traffic_flowing():
559da271f8SJakub Kicinski        stat1 = get_stats()
569da271f8SJakub Kicinski        time.sleep(1)
579da271f8SJakub Kicinski        stat2 = get_stats()
589da271f8SJakub Kicinski        if stat2['rx-packets'] - stat1['rx-packets'] < 15000:
599da271f8SJakub Kicinski            raise KsftFailEx("Traffic seems low:", stat2['rx-packets'] - stat1['rx-packets'])
609da271f8SJakub Kicinski
619da271f8SJakub Kicinski
629da271f8SJakub Kicinski    try:
639da271f8SJakub Kicinski        stats = get_stats()
649da271f8SJakub Kicinski    except NlError as e:
65*a48395f2SStanislav Fomichev        if e.nl_msg.error == -errno.EOPNOTSUPP:
669da271f8SJakub Kicinski            stats = {}
679da271f8SJakub Kicinski        else:
689da271f8SJakub Kicinski            raise
699da271f8SJakub Kicinski    if 'rx-alloc-fail' not in stats:
709da271f8SJakub Kicinski        raise KsftSkipEx("Driver does not report 'rx-alloc-fail' via qstats")
719da271f8SJakub Kicinski
729da271f8SJakub Kicinski    set_g = False
739da271f8SJakub Kicinski    traffic = None
749da271f8SJakub Kicinski    try:
759da271f8SJakub Kicinski        traffic = GenerateTraffic(cfg)
769da271f8SJakub Kicinski
779da271f8SJakub Kicinski        check_traffic_flowing()
789da271f8SJakub Kicinski
799da271f8SJakub Kicinski        _enable_pp_allocation_fail()
809da271f8SJakub Kicinski
819da271f8SJakub Kicinski        s1 = get_stats()
829da271f8SJakub Kicinski        time.sleep(3)
839da271f8SJakub Kicinski        s2 = get_stats()
849da271f8SJakub Kicinski
859da271f8SJakub Kicinski        if s2['rx-alloc-fail'] - s1['rx-alloc-fail'] < 1:
869da271f8SJakub Kicinski            raise KsftSkipEx("Allocation failures not increasing")
879da271f8SJakub Kicinski        if s2['rx-alloc-fail'] - s1['rx-alloc-fail'] < 100:
889da271f8SJakub Kicinski            raise KsftSkipEx("Allocation increasing too slowly", s2['rx-alloc-fail'] - s1['rx-alloc-fail'],
899da271f8SJakub Kicinski                             "packets:", s2['rx-packets'] - s1['rx-packets'])
909da271f8SJakub Kicinski
919da271f8SJakub Kicinski        # Basic failures are fine, try to wobble some settings to catch extra failures
929da271f8SJakub Kicinski        check_traffic_flowing()
939da271f8SJakub Kicinski        g = tool("ethtool", "-g " + cfg.ifname, json=True)[0]
949da271f8SJakub Kicinski        if 'rx' in g and g["rx"] * 2 <= g["rx-max"]:
959da271f8SJakub Kicinski            new_g = g['rx'] * 2
969da271f8SJakub Kicinski        elif 'rx' in g:
979da271f8SJakub Kicinski            new_g = g['rx'] // 2
989da271f8SJakub Kicinski        else:
999da271f8SJakub Kicinski            new_g = None
1009da271f8SJakub Kicinski
1019da271f8SJakub Kicinski        if new_g:
1029da271f8SJakub Kicinski            set_g = cmd(f"ethtool -G {cfg.ifname} rx {new_g}", fail=False).ret == 0
1039da271f8SJakub Kicinski            if set_g:
1049da271f8SJakub Kicinski                ksft_pr("ethtool -G change retval: success")
1059da271f8SJakub Kicinski            else:
1069da271f8SJakub Kicinski                ksft_pr("ethtool -G change retval: did not succeed", new_g)
1079da271f8SJakub Kicinski        else:
1089da271f8SJakub Kicinski                ksft_pr("ethtool -G change retval: did not try")
1099da271f8SJakub Kicinski
1109da271f8SJakub Kicinski        time.sleep(0.1)
1119da271f8SJakub Kicinski        check_traffic_flowing()
1129da271f8SJakub Kicinski    finally:
1139da271f8SJakub Kicinski        _disable_pp_allocation_fail()
1149da271f8SJakub Kicinski        if traffic:
1159da271f8SJakub Kicinski            traffic.stop()
1169da271f8SJakub Kicinski        time.sleep(0.1)
1179da271f8SJakub Kicinski        if set_g:
1189da271f8SJakub Kicinski            cmd(f"ethtool -G {cfg.ifname} rx {g['rx']}")
1199da271f8SJakub Kicinski
1209da271f8SJakub Kicinski
1219da271f8SJakub Kicinskidef main() -> None:
1229da271f8SJakub Kicinski    netdevnl = NetdevFamily()
1239da271f8SJakub Kicinski    with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
1249da271f8SJakub Kicinski
1259da271f8SJakub Kicinski        ksft_run([test_pp_alloc], args=(cfg, netdevnl, ))
1269da271f8SJakub Kicinski    ksft_exit()
1279da271f8SJakub Kicinski
1289da271f8SJakub Kicinski
1299da271f8SJakub Kicinskiif __name__ == "__main__":
1309da271f8SJakub Kicinski    main()
131