Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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()