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