xref: /linux/tools/testing/selftests/drivers/net/hw/pp_alloc_fail.py (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
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