xref: /linux/tools/testing/selftests/net/nl_netdev.py (revision 2ee738e90e80850582cbe10f34c6447965c1d87b)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3
4import time
5from lib.py import ksft_run, ksft_exit, ksft_pr
6from lib.py import ksft_eq, ksft_ge, ksft_busy_wait
7from lib.py import NetdevFamily, NetdevSimDev, ip
8
9
10def empty_check(nf) -> None:
11    devs = nf.dev_get({}, dump=True)
12    ksft_ge(len(devs), 1)
13
14
15def lo_check(nf) -> None:
16    lo_info = nf.dev_get({"ifindex": 1})
17    ksft_eq(len(lo_info['xdp-features']), 0)
18    ksft_eq(len(lo_info['xdp-rx-metadata-features']), 0)
19
20
21def napi_list_check(nf) -> None:
22    with NetdevSimDev(queue_count=100) as nsimdev:
23        nsim = nsimdev.nsims[0]
24
25        ip(f"link set dev {nsim.ifname} up")
26
27        napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
28        ksft_eq(len(napis), 100)
29
30        for q in [50, 0, 99]:
31            for i in range(4):
32                nsim.dfs_write("queue_reset", f"{q} {i}")
33                napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
34                ksft_eq(len(napis), 100,
35                        comment=f"queue count after reset queue {q} mode {i}")
36
37
38def page_pool_check(nf) -> None:
39    with NetdevSimDev() as nsimdev:
40        nsim = nsimdev.nsims[0]
41
42        def up():
43            ip(f"link set dev {nsim.ifname} up")
44
45        def down():
46            ip(f"link set dev {nsim.ifname} down")
47
48        def get_pp():
49            pp_list = nf.page_pool_get({}, dump=True)
50            return [pp for pp in pp_list if pp.get("ifindex") == nsim.ifindex]
51
52        # No page pools when down
53        down()
54        ksft_eq(len(get_pp()), 0)
55
56        # Up, empty page pool appears
57        up()
58        pp_list = get_pp()
59        ksft_ge(len(pp_list), 0)
60        refs = sum([pp["inflight"] for pp in pp_list])
61        ksft_eq(refs, 0)
62
63        # Down, it disappears, again
64        down()
65        pp_list = get_pp()
66        ksft_eq(len(pp_list), 0)
67
68        # Up, allocate a page
69        up()
70        nsim.dfs_write("pp_hold", "y")
71        pp_list = nf.page_pool_get({}, dump=True)
72        refs = sum([pp["inflight"] for pp in pp_list if pp.get("ifindex") == nsim.ifindex])
73        ksft_ge(refs, 1)
74
75        # Now let's leak a page
76        down()
77        pp_list = get_pp()
78        ksft_eq(len(pp_list), 1)
79        refs = sum([pp["inflight"] for pp in pp_list])
80        ksft_eq(refs, 1)
81        attached = [pp for pp in pp_list if "detach-time" not in pp]
82        ksft_eq(len(attached), 0)
83
84        # New pp can get created, and we'll have two
85        up()
86        pp_list = get_pp()
87        attached = [pp for pp in pp_list if "detach-time" not in pp]
88        detached = [pp for pp in pp_list if "detach-time" in pp]
89        ksft_eq(len(attached), 1)
90        ksft_eq(len(detached), 1)
91
92        # Free the old page and the old pp is gone
93        nsim.dfs_write("pp_hold", "n")
94        # Freeing check is once a second so we may need to retry
95        ksft_busy_wait(lambda: len(get_pp()) == 1, deadline=2)
96
97        # And down...
98        down()
99        ksft_eq(len(get_pp()), 0)
100
101        # Last, leave the page hanging for destroy, nothing to check
102        # we're trying to exercise the orphaning path in the kernel
103        up()
104        nsim.dfs_write("pp_hold", "y")
105
106
107def main() -> None:
108    nf = NetdevFamily()
109    ksft_run([empty_check, lo_check, page_pool_check, napi_list_check],
110             args=(nf, ))
111    ksft_exit()
112
113
114if __name__ == "__main__":
115    main()
116