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 napi_set_threaded(nf) -> None: 39 """ 40 Test that verifies various cases of napi threaded 41 set and unset at napi and device level. 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 napi threaded and verify 55 nf.napi_set({'id': napi0_id, 'threaded': "enabled"}) 56 napi0 = nf.napi_get({'id': napi0_id}) 57 ksft_eq(napi0['threaded'], "enabled") 58 ksft_ne(napi0.get('pid'), None) 59 60 # check it is not set for napi1 61 napi1 = nf.napi_get({'id': napi1_id}) 62 ksft_eq(napi1['threaded'], "disabled") 63 ksft_eq(napi1.get('pid'), None) 64 65 ip(f"link set dev {nsim.ifname} down") 66 ip(f"link set dev {nsim.ifname} up") 67 68 # verify if napi threaded is still set 69 napi0 = nf.napi_get({'id': napi0_id}) 70 ksft_eq(napi0['threaded'], "enabled") 71 ksft_ne(napi0.get('pid'), None) 72 73 # check it is still not set for napi1 74 napi1 = nf.napi_get({'id': napi1_id}) 75 ksft_eq(napi1['threaded'], "disabled") 76 ksft_eq(napi1.get('pid'), None) 77 78 # unset napi threaded and verify 79 nf.napi_set({'id': napi0_id, 'threaded': "disabled"}) 80 napi0 = nf.napi_get({'id': napi0_id}) 81 ksft_eq(napi0['threaded'], "disabled") 82 ksft_eq(napi0.get('pid'), None) 83 84 # set threaded at device level 85 system(f"echo 1 > /sys/class/net/{nsim.ifname}/threaded") 86 87 # check napi threaded is set for both napis 88 napi0 = nf.napi_get({'id': napi0_id}) 89 ksft_eq(napi0['threaded'], "enabled") 90 ksft_ne(napi0.get('pid'), None) 91 napi1 = nf.napi_get({'id': napi1_id}) 92 ksft_eq(napi1['threaded'], "enabled") 93 ksft_ne(napi1.get('pid'), None) 94 95 # unset threaded at device level 96 system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded") 97 98 # check napi threaded is unset for both napis 99 napi0 = nf.napi_get({'id': napi0_id}) 100 ksft_eq(napi0['threaded'], "disabled") 101 ksft_eq(napi0.get('pid'), None) 102 napi1 = nf.napi_get({'id': napi1_id}) 103 ksft_eq(napi1['threaded'], "disabled") 104 ksft_eq(napi1.get('pid'), None) 105 106 # set napi threaded for napi0 107 nf.napi_set({'id': napi0_id, 'threaded': 1}) 108 napi0 = nf.napi_get({'id': napi0_id}) 109 ksft_eq(napi0['threaded'], "enabled") 110 ksft_ne(napi0.get('pid'), None) 111 112 # unset threaded at device level 113 system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded") 114 115 # check napi threaded is unset for both napis 116 napi0 = nf.napi_get({'id': napi0_id}) 117 ksft_eq(napi0['threaded'], "disabled") 118 ksft_eq(napi0.get('pid'), None) 119 napi1 = nf.napi_get({'id': napi1_id}) 120 ksft_eq(napi1['threaded'], "disabled") 121 ksft_eq(napi1.get('pid'), None) 122 123def dev_set_threaded(nf) -> None: 124 """ 125 Test that verifies various cases of napi threaded 126 set and unset at device level using sysfs. 127 """ 128 with NetdevSimDev(queue_count=2) as nsimdev: 129 nsim = nsimdev.nsims[0] 130 131 ip(f"link set dev {nsim.ifname} up") 132 133 napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True) 134 ksft_eq(len(napis), 2) 135 136 napi0_id = napis[0]['id'] 137 napi1_id = napis[1]['id'] 138 139 # set threaded 140 system(f"echo 1 > /sys/class/net/{nsim.ifname}/threaded") 141 142 # check napi threaded is set for both napis 143 napi0 = nf.napi_get({'id': napi0_id}) 144 ksft_eq(napi0['threaded'], "enabled") 145 ksft_ne(napi0.get('pid'), None) 146 napi1 = nf.napi_get({'id': napi1_id}) 147 ksft_eq(napi1['threaded'], "enabled") 148 ksft_ne(napi1.get('pid'), None) 149 150 # unset threaded 151 system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded") 152 153 # check napi threaded is unset for both napis 154 napi0 = nf.napi_get({'id': napi0_id}) 155 ksft_eq(napi0['threaded'], "disabled") 156 ksft_eq(napi0.get('pid'), None) 157 napi1 = nf.napi_get({'id': napi1_id}) 158 ksft_eq(napi1['threaded'], "disabled") 159 ksft_eq(napi1.get('pid'), None) 160 161def nsim_rxq_reset_down(nf) -> None: 162 """ 163 Test that the queue API supports resetting a queue 164 while the interface is down. We should convert this 165 test to testing real HW once more devices support 166 queue API. 167 """ 168 with NetdevSimDev(queue_count=4) as nsimdev: 169 nsim = nsimdev.nsims[0] 170 171 ip(f"link set dev {nsim.ifname} down") 172 for i in [0, 2, 3]: 173 nsim.dfs_write("queue_reset", f"1 {i}") 174 175 176def page_pool_check(nf) -> None: 177 with NetdevSimDev() as nsimdev: 178 nsim = nsimdev.nsims[0] 179 180 def up(): 181 ip(f"link set dev {nsim.ifname} up") 182 183 def down(): 184 ip(f"link set dev {nsim.ifname} down") 185 186 def get_pp(): 187 pp_list = nf.page_pool_get({}, dump=True) 188 return [pp for pp in pp_list if pp.get("ifindex") == nsim.ifindex] 189 190 # No page pools when down 191 down() 192 ksft_eq(len(get_pp()), 0) 193 194 # Up, empty page pool appears 195 up() 196 pp_list = get_pp() 197 ksft_ge(len(pp_list), 0) 198 refs = sum([pp["inflight"] for pp in pp_list]) 199 ksft_eq(refs, 0) 200 201 # Down, it disappears, again 202 down() 203 pp_list = get_pp() 204 ksft_eq(len(pp_list), 0) 205 206 # Up, allocate a page 207 up() 208 nsim.dfs_write("pp_hold", "y") 209 pp_list = nf.page_pool_get({}, dump=True) 210 refs = sum([pp["inflight"] for pp in pp_list if pp.get("ifindex") == nsim.ifindex]) 211 ksft_ge(refs, 1) 212 213 # Now let's leak a page 214 down() 215 pp_list = get_pp() 216 ksft_eq(len(pp_list), 1) 217 refs = sum([pp["inflight"] for pp in pp_list]) 218 ksft_eq(refs, 1) 219 attached = [pp for pp in pp_list if "detach-time" not in pp] 220 ksft_eq(len(attached), 0) 221 222 # New pp can get created, and we'll have two 223 up() 224 pp_list = get_pp() 225 attached = [pp for pp in pp_list if "detach-time" not in pp] 226 detached = [pp for pp in pp_list if "detach-time" in pp] 227 ksft_eq(len(attached), 1) 228 ksft_eq(len(detached), 1) 229 230 # Free the old page and the old pp is gone 231 nsim.dfs_write("pp_hold", "n") 232 # Freeing check is once a second so we may need to retry 233 ksft_busy_wait(lambda: len(get_pp()) == 1, deadline=2) 234 235 # And down... 236 down() 237 ksft_eq(len(get_pp()), 0) 238 239 # Last, leave the page hanging for destroy, nothing to check 240 # we're trying to exercise the orphaning path in the kernel 241 up() 242 nsim.dfs_write("pp_hold", "y") 243 244 245def main() -> None: 246 nf = NetdevFamily() 247 ksft_run([empty_check, lo_check, page_pool_check, napi_list_check, 248 dev_set_threaded, napi_set_threaded, nsim_rxq_reset_down], 249 args=(nf, )) 250 ksft_exit() 251 252 253if __name__ == "__main__": 254 main() 255