1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3 4import time 5from os import system 6from lib.py import ksft_run, ksft_exit, ksft_pr 7from lib.py import ksft_eq, ksft_ge, ksft_ne, ksft_busy_wait 8from lib.py import NetdevFamily, NetdevSimDev, ip 9 10 11def empty_check(nf) -> None: 12 devs = nf.dev_get({}, dump=True) 13 ksft_ge(len(devs), 1) 14 15 16def lo_check(nf) -> None: 17 lo_info = nf.dev_get({"ifindex": 1}) 18 ksft_eq(len(lo_info['xdp-features']), 0) 19 ksft_eq(len(lo_info['xdp-rx-metadata-features']), 0) 20 21 22def napi_list_check(nf) -> None: 23 with NetdevSimDev(queue_count=100) as nsimdev: 24 nsim = nsimdev.nsims[0] 25 26 ip(f"link set dev {nsim.ifname} up") 27 28 napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True) 29 ksft_eq(len(napis), 100) 30 31 for q in [50, 0, 99]: 32 for i in range(4): 33 nsim.dfs_write("queue_reset", f"{q} {i}") 34 napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True) 35 ksft_eq(len(napis), 100, 36 comment=f"queue count after reset queue {q} mode {i}") 37 38def dev_set_threaded(nf) -> None: 39 """ 40 Test that verifies various cases of napi threaded 41 set and unset at device level using sysfs. 42 """ 43 with NetdevSimDev(queue_count=2) as nsimdev: 44 nsim = nsimdev.nsims[0] 45 46 ip(f"link set dev {nsim.ifname} up") 47 48 napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True) 49 ksft_eq(len(napis), 2) 50 51 napi0_id = napis[0]['id'] 52 napi1_id = napis[1]['id'] 53 54 # set threaded 55 system(f"echo 1 > /sys/class/net/{nsim.ifname}/threaded") 56 57 # check napi threaded is set for both napis 58 napi0 = nf.napi_get({'id': napi0_id}) 59 ksft_ne(napi0.get('pid'), None) 60 napi1 = nf.napi_get({'id': napi1_id}) 61 ksft_ne(napi1.get('pid'), None) 62 63 # unset threaded 64 system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded") 65 66 # check napi threaded is unset for both napis 67 napi0 = nf.napi_get({'id': napi0_id}) 68 ksft_eq(napi0.get('pid'), None) 69 napi1 = nf.napi_get({'id': napi1_id}) 70 ksft_eq(napi1.get('pid'), None) 71 72def nsim_rxq_reset_down(nf) -> None: 73 """ 74 Test that the queue API supports resetting a queue 75 while the interface is down. We should convert this 76 test to testing real HW once more devices support 77 queue API. 78 """ 79 with NetdevSimDev(queue_count=4) as nsimdev: 80 nsim = nsimdev.nsims[0] 81 82 ip(f"link set dev {nsim.ifname} down") 83 for i in [0, 2, 3]: 84 nsim.dfs_write("queue_reset", f"1 {i}") 85 86 87def page_pool_check(nf) -> None: 88 with NetdevSimDev() as nsimdev: 89 nsim = nsimdev.nsims[0] 90 91 def up(): 92 ip(f"link set dev {nsim.ifname} up") 93 94 def down(): 95 ip(f"link set dev {nsim.ifname} down") 96 97 def get_pp(): 98 pp_list = nf.page_pool_get({}, dump=True) 99 return [pp for pp in pp_list if pp.get("ifindex") == nsim.ifindex] 100 101 # No page pools when down 102 down() 103 ksft_eq(len(get_pp()), 0) 104 105 # Up, empty page pool appears 106 up() 107 pp_list = get_pp() 108 ksft_ge(len(pp_list), 0) 109 refs = sum([pp["inflight"] for pp in pp_list]) 110 ksft_eq(refs, 0) 111 112 # Down, it disappears, again 113 down() 114 pp_list = get_pp() 115 ksft_eq(len(pp_list), 0) 116 117 # Up, allocate a page 118 up() 119 nsim.dfs_write("pp_hold", "y") 120 pp_list = nf.page_pool_get({}, dump=True) 121 refs = sum([pp["inflight"] for pp in pp_list if pp.get("ifindex") == nsim.ifindex]) 122 ksft_ge(refs, 1) 123 124 # Now let's leak a page 125 down() 126 pp_list = get_pp() 127 ksft_eq(len(pp_list), 1) 128 refs = sum([pp["inflight"] for pp in pp_list]) 129 ksft_eq(refs, 1) 130 attached = [pp for pp in pp_list if "detach-time" not in pp] 131 ksft_eq(len(attached), 0) 132 133 # New pp can get created, and we'll have two 134 up() 135 pp_list = get_pp() 136 attached = [pp for pp in pp_list if "detach-time" not in pp] 137 detached = [pp for pp in pp_list if "detach-time" in pp] 138 ksft_eq(len(attached), 1) 139 ksft_eq(len(detached), 1) 140 141 # Free the old page and the old pp is gone 142 nsim.dfs_write("pp_hold", "n") 143 # Freeing check is once a second so we may need to retry 144 ksft_busy_wait(lambda: len(get_pp()) == 1, deadline=2) 145 146 # And down... 147 down() 148 ksft_eq(len(get_pp()), 0) 149 150 # Last, leave the page hanging for destroy, nothing to check 151 # we're trying to exercise the orphaning path in the kernel 152 up() 153 nsim.dfs_write("pp_hold", "y") 154 155 156def main() -> None: 157 nf = NetdevFamily() 158 ksft_run([empty_check, lo_check, page_pool_check, napi_list_check, 159 dev_set_threaded, nsim_rxq_reset_down], 160 args=(nf, )) 161 ksft_exit() 162 163 164if __name__ == "__main__": 165 main() 166