1 // SPDX-License-Identifier: GPL-2.0
2 #include <vmlinux.h>
3 #include <bpf/bpf_tracing.h>
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_core_read.h>
6 #include "bpf_experimental.h"
7 
8 #ifndef ARRAY_SIZE
9 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
10 #endif
11 
12 #include "linked_list.h"
13 
14 static __always_inline
15 int list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
16 {
17 	struct bpf_list_node *n;
18 	struct foo *f;
19 
20 	f = bpf_obj_new(typeof(*f));
21 	if (!f)
22 		return 2;
23 
24 	bpf_spin_lock(lock);
25 	n = bpf_list_pop_front(head);
26 	bpf_spin_unlock(lock);
27 	if (n) {
28 		bpf_obj_drop(container_of(n, struct foo, node));
29 		bpf_obj_drop(f);
30 		return 3;
31 	}
32 
33 	bpf_spin_lock(lock);
34 	n = bpf_list_pop_back(head);
35 	bpf_spin_unlock(lock);
36 	if (n) {
37 		bpf_obj_drop(container_of(n, struct foo, node));
38 		bpf_obj_drop(f);
39 		return 4;
40 	}
41 
42 
43 	bpf_spin_lock(lock);
44 	f->data = 42;
45 	bpf_list_push_front(head, &f->node);
46 	bpf_spin_unlock(lock);
47 	if (leave_in_map)
48 		return 0;
49 	bpf_spin_lock(lock);
50 	n = bpf_list_pop_back(head);
51 	bpf_spin_unlock(lock);
52 	if (!n)
53 		return 5;
54 	f = container_of(n, struct foo, node);
55 	if (f->data != 42) {
56 		bpf_obj_drop(f);
57 		return 6;
58 	}
59 
60 	bpf_spin_lock(lock);
61 	f->data = 13;
62 	bpf_list_push_front(head, &f->node);
63 	bpf_spin_unlock(lock);
64 	bpf_spin_lock(lock);
65 	n = bpf_list_pop_front(head);
66 	bpf_spin_unlock(lock);
67 	if (!n)
68 		return 7;
69 	f = container_of(n, struct foo, node);
70 	if (f->data != 13) {
71 		bpf_obj_drop(f);
72 		return 8;
73 	}
74 	bpf_obj_drop(f);
75 
76 	bpf_spin_lock(lock);
77 	n = bpf_list_pop_front(head);
78 	bpf_spin_unlock(lock);
79 	if (n) {
80 		bpf_obj_drop(container_of(n, struct foo, node));
81 		return 9;
82 	}
83 
84 	bpf_spin_lock(lock);
85 	n = bpf_list_pop_back(head);
86 	bpf_spin_unlock(lock);
87 	if (n) {
88 		bpf_obj_drop(container_of(n, struct foo, node));
89 		return 10;
90 	}
91 	return 0;
92 }
93 
94 
95 static __always_inline
96 int list_push_pop_multiple(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
97 {
98 	struct bpf_list_node *n;
99 	struct foo *f[8], *pf;
100 	int i;
101 
102 	for (i = 0; i < ARRAY_SIZE(f); i++) {
103 		f[i] = bpf_obj_new(typeof(**f));
104 		if (!f[i])
105 			return 2;
106 		f[i]->data = i;
107 		bpf_spin_lock(lock);
108 		bpf_list_push_front(head, &f[i]->node);
109 		bpf_spin_unlock(lock);
110 	}
111 
112 	for (i = 0; i < ARRAY_SIZE(f); i++) {
113 		bpf_spin_lock(lock);
114 		n = bpf_list_pop_front(head);
115 		bpf_spin_unlock(lock);
116 		if (!n)
117 			return 3;
118 		pf = container_of(n, struct foo, node);
119 		if (pf->data != (ARRAY_SIZE(f) - i - 1)) {
120 			bpf_obj_drop(pf);
121 			return 4;
122 		}
123 		bpf_spin_lock(lock);
124 		bpf_list_push_back(head, &pf->node);
125 		bpf_spin_unlock(lock);
126 	}
127 
128 	if (leave_in_map)
129 		return 0;
130 
131 	for (i = 0; i < ARRAY_SIZE(f); i++) {
132 		bpf_spin_lock(lock);
133 		n = bpf_list_pop_back(head);
134 		bpf_spin_unlock(lock);
135 		if (!n)
136 			return 5;
137 		pf = container_of(n, struct foo, node);
138 		if (pf->data != i) {
139 			bpf_obj_drop(pf);
140 			return 6;
141 		}
142 		bpf_obj_drop(pf);
143 	}
144 	bpf_spin_lock(lock);
145 	n = bpf_list_pop_back(head);
146 	bpf_spin_unlock(lock);
147 	if (n) {
148 		bpf_obj_drop(container_of(n, struct foo, node));
149 		return 7;
150 	}
151 
152 	bpf_spin_lock(lock);
153 	n = bpf_list_pop_front(head);
154 	bpf_spin_unlock(lock);
155 	if (n) {
156 		bpf_obj_drop(container_of(n, struct foo, node));
157 		return 8;
158 	}
159 	return 0;
160 }
161 
162 static __always_inline
163 int list_in_list(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
164 {
165 	struct bpf_list_node *n;
166 	struct bar *ba[8], *b;
167 	struct foo *f;
168 	int i;
169 
170 	f = bpf_obj_new(typeof(*f));
171 	if (!f)
172 		return 2;
173 	for (i = 0; i < ARRAY_SIZE(ba); i++) {
174 		b = bpf_obj_new(typeof(*b));
175 		if (!b) {
176 			bpf_obj_drop(f);
177 			return 3;
178 		}
179 		b->data = i;
180 		bpf_spin_lock(&f->lock);
181 		bpf_list_push_back(&f->head, &b->node);
182 		bpf_spin_unlock(&f->lock);
183 	}
184 
185 	bpf_spin_lock(lock);
186 	f->data = 42;
187 	bpf_list_push_front(head, &f->node);
188 	bpf_spin_unlock(lock);
189 
190 	if (leave_in_map)
191 		return 0;
192 
193 	bpf_spin_lock(lock);
194 	n = bpf_list_pop_front(head);
195 	bpf_spin_unlock(lock);
196 	if (!n)
197 		return 4;
198 	f = container_of(n, struct foo, node);
199 	if (f->data != 42) {
200 		bpf_obj_drop(f);
201 		return 5;
202 	}
203 
204 	for (i = 0; i < ARRAY_SIZE(ba); i++) {
205 		bpf_spin_lock(&f->lock);
206 		n = bpf_list_pop_front(&f->head);
207 		bpf_spin_unlock(&f->lock);
208 		if (!n) {
209 			bpf_obj_drop(f);
210 			return 6;
211 		}
212 		b = container_of(n, struct bar, node);
213 		if (b->data != i) {
214 			bpf_obj_drop(f);
215 			bpf_obj_drop(b);
216 			return 7;
217 		}
218 		bpf_obj_drop(b);
219 	}
220 	bpf_spin_lock(&f->lock);
221 	n = bpf_list_pop_front(&f->head);
222 	bpf_spin_unlock(&f->lock);
223 	if (n) {
224 		bpf_obj_drop(f);
225 		bpf_obj_drop(container_of(n, struct bar, node));
226 		return 8;
227 	}
228 	bpf_obj_drop(f);
229 	return 0;
230 }
231 
232 static __always_inline
233 int test_list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head)
234 {
235 	int ret;
236 
237 	ret = list_push_pop(lock, head, false);
238 	if (ret)
239 		return ret;
240 	return list_push_pop(lock, head, true);
241 }
242 
243 static __always_inline
244 int test_list_push_pop_multiple(struct bpf_spin_lock *lock, struct bpf_list_head *head)
245 {
246 	int ret;
247 
248 	ret = list_push_pop_multiple(lock ,head, false);
249 	if (ret)
250 		return ret;
251 	return list_push_pop_multiple(lock, head, true);
252 }
253 
254 static __always_inline
255 int test_list_in_list(struct bpf_spin_lock *lock, struct bpf_list_head *head)
256 {
257 	int ret;
258 
259 	ret = list_in_list(lock, head, false);
260 	if (ret)
261 		return ret;
262 	return list_in_list(lock, head, true);
263 }
264 
265 SEC("tc")
266 int map_list_push_pop(void *ctx)
267 {
268 	struct map_value *v;
269 
270 	v = bpf_map_lookup_elem(&array_map, &(int){0});
271 	if (!v)
272 		return 1;
273 	return test_list_push_pop(&v->lock, &v->head);
274 }
275 
276 SEC("tc")
277 int inner_map_list_push_pop(void *ctx)
278 {
279 	struct map_value *v;
280 	void *map;
281 
282 	map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
283 	if (!map)
284 		return 1;
285 	v = bpf_map_lookup_elem(map, &(int){0});
286 	if (!v)
287 		return 1;
288 	return test_list_push_pop(&v->lock, &v->head);
289 }
290 
291 SEC("tc")
292 int global_list_push_pop(void *ctx)
293 {
294 	return test_list_push_pop(&glock, &ghead);
295 }
296 
297 SEC("tc")
298 int map_list_push_pop_multiple(void *ctx)
299 {
300 	struct map_value *v;
301 	int ret;
302 
303 	v = bpf_map_lookup_elem(&array_map, &(int){0});
304 	if (!v)
305 		return 1;
306 	return test_list_push_pop_multiple(&v->lock, &v->head);
307 }
308 
309 SEC("tc")
310 int inner_map_list_push_pop_multiple(void *ctx)
311 {
312 	struct map_value *v;
313 	void *map;
314 	int ret;
315 
316 	map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
317 	if (!map)
318 		return 1;
319 	v = bpf_map_lookup_elem(map, &(int){0});
320 	if (!v)
321 		return 1;
322 	return test_list_push_pop_multiple(&v->lock, &v->head);
323 }
324 
325 SEC("tc")
326 int global_list_push_pop_multiple(void *ctx)
327 {
328 	int ret;
329 
330 	ret = list_push_pop_multiple(&glock, &ghead, false);
331 	if (ret)
332 		return ret;
333 	return list_push_pop_multiple(&glock, &ghead, true);
334 }
335 
336 SEC("tc")
337 int map_list_in_list(void *ctx)
338 {
339 	struct map_value *v;
340 	int ret;
341 
342 	v = bpf_map_lookup_elem(&array_map, &(int){0});
343 	if (!v)
344 		return 1;
345 	return test_list_in_list(&v->lock, &v->head);
346 }
347 
348 SEC("tc")
349 int inner_map_list_in_list(void *ctx)
350 {
351 	struct map_value *v;
352 	void *map;
353 	int ret;
354 
355 	map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
356 	if (!map)
357 		return 1;
358 	v = bpf_map_lookup_elem(map, &(int){0});
359 	if (!v)
360 		return 1;
361 	return test_list_in_list(&v->lock, &v->head);
362 }
363 
364 SEC("tc")
365 int global_list_in_list(void *ctx)
366 {
367 	return test_list_in_list(&glock, &ghead);
368 }
369 
370 char _license[] SEC("license") = "GPL";
371