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