xref: /linux/tools/testing/selftests/net/nl_netdev.py (revision 3f41368fbfe1b3d5922d317fe1a0a0cab6846802)
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 page_pool_check(nf) -> None:
22    with NetdevSimDev() as nsimdev:
23        nsim = nsimdev.nsims[0]
24
25        def up():
26            ip(f"link set dev {nsim.ifname} up")
27
28        def down():
29            ip(f"link set dev {nsim.ifname} down")
30
31        def get_pp():
32            pp_list = nf.page_pool_get({}, dump=True)
33            return [pp for pp in pp_list if pp.get("ifindex") == nsim.ifindex]
34
35        # No page pools when down
36        down()
37        ksft_eq(len(get_pp()), 0)
38
39        # Up, empty page pool appears
40        up()
41        pp_list = get_pp()
42        ksft_ge(len(pp_list), 0)
43        refs = sum([pp["inflight"] for pp in pp_list])
44        ksft_eq(refs, 0)
45
46        # Down, it disappears, again
47        down()
48        pp_list = get_pp()
49        ksft_eq(len(pp_list), 0)
50
51        # Up, allocate a page
52        up()
53        nsim.dfs_write("pp_hold", "y")
54        pp_list = nf.page_pool_get({}, dump=True)
55        refs = sum([pp["inflight"] for pp in pp_list if pp.get("ifindex") == nsim.ifindex])
56        ksft_ge(refs, 1)
57
58        # Now let's leak a page
59        down()
60        pp_list = get_pp()
61        ksft_eq(len(pp_list), 1)
62        refs = sum([pp["inflight"] for pp in pp_list])
63        ksft_eq(refs, 1)
64        attached = [pp for pp in pp_list if "detach-time" not in pp]
65        ksft_eq(len(attached), 0)
66
67        # New pp can get created, and we'll have two
68        up()
69        pp_list = get_pp()
70        attached = [pp for pp in pp_list if "detach-time" not in pp]
71        detached = [pp for pp in pp_list if "detach-time" in pp]
72        ksft_eq(len(attached), 1)
73        ksft_eq(len(detached), 1)
74
75        # Free the old page and the old pp is gone
76        nsim.dfs_write("pp_hold", "n")
77        # Freeing check is once a second so we may need to retry
78        ksft_busy_wait(lambda: len(get_pp()) == 1, deadline=2)
79
80        # And down...
81        down()
82        ksft_eq(len(get_pp()), 0)
83
84        # Last, leave the page hanging for destroy, nothing to check
85        # we're trying to exercise the orphaning path in the kernel
86        up()
87        nsim.dfs_write("pp_hold", "y")
88
89
90def main() -> None:
91    nf = NetdevFamily()
92    ksft_run([empty_check, lo_check, page_pool_check],
93             args=(nf, ))
94    ksft_exit()
95
96
97if __name__ == "__main__":
98    main()
99