xref: /linux/tools/testing/selftests/bpf/prog_tests/tailcalls.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <unistd.h>
3 #include <test_progs.h>
4 #include <network_helpers.h>
5 #include "tailcall_poke.skel.h"
6 #include "tailcall_bpf2bpf_hierarchy2.skel.h"
7 #include "tailcall_bpf2bpf_hierarchy3.skel.h"
8 #include "tailcall_freplace.skel.h"
9 #include "tc_bpf2bpf.skel.h"
10 
11 /* test_tailcall_1 checks basic functionality by patching multiple locations
12  * in a single program for a single tail call slot with nop->jmp, jmp->nop
13  * and jmp->jmp rewrites. Also checks for nop->nop.
14  */
test_tailcall_1(void)15 static void test_tailcall_1(void)
16 {
17 	int err, map_fd, prog_fd, main_fd, i, j;
18 	struct bpf_map *prog_array;
19 	struct bpf_program *prog;
20 	struct bpf_object *obj;
21 	char prog_name[32];
22 	char buff[128] = {};
23 	LIBBPF_OPTS(bpf_test_run_opts, topts,
24 		.data_in = buff,
25 		.data_size_in = sizeof(buff),
26 		.repeat = 1,
27 	);
28 
29 	err = bpf_prog_test_load("tailcall1.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
30 				 &prog_fd);
31 	if (CHECK_FAIL(err))
32 		return;
33 
34 	prog = bpf_object__find_program_by_name(obj, "entry");
35 	if (CHECK_FAIL(!prog))
36 		goto out;
37 
38 	main_fd = bpf_program__fd(prog);
39 	if (CHECK_FAIL(main_fd < 0))
40 		goto out;
41 
42 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
43 	if (CHECK_FAIL(!prog_array))
44 		goto out;
45 
46 	map_fd = bpf_map__fd(prog_array);
47 	if (CHECK_FAIL(map_fd < 0))
48 		goto out;
49 
50 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
51 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
52 
53 		prog = bpf_object__find_program_by_name(obj, prog_name);
54 		if (CHECK_FAIL(!prog))
55 			goto out;
56 
57 		prog_fd = bpf_program__fd(prog);
58 		if (CHECK_FAIL(prog_fd < 0))
59 			goto out;
60 
61 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
62 		if (CHECK_FAIL(err))
63 			goto out;
64 	}
65 
66 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
67 		err = bpf_prog_test_run_opts(main_fd, &topts);
68 		ASSERT_OK(err, "tailcall");
69 		ASSERT_EQ(topts.retval, i, "tailcall retval");
70 
71 		err = bpf_map_delete_elem(map_fd, &i);
72 		if (CHECK_FAIL(err))
73 			goto out;
74 	}
75 
76 	err = bpf_prog_test_run_opts(main_fd, &topts);
77 	ASSERT_OK(err, "tailcall");
78 	ASSERT_EQ(topts.retval, 3, "tailcall retval");
79 
80 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
81 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
82 
83 		prog = bpf_object__find_program_by_name(obj, prog_name);
84 		if (CHECK_FAIL(!prog))
85 			goto out;
86 
87 		prog_fd = bpf_program__fd(prog);
88 		if (CHECK_FAIL(prog_fd < 0))
89 			goto out;
90 
91 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
92 		if (CHECK_FAIL(err))
93 			goto out;
94 	}
95 
96 	err = bpf_prog_test_run_opts(main_fd, &topts);
97 	ASSERT_OK(err, "tailcall");
98 	ASSERT_OK(topts.retval, "tailcall retval");
99 
100 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
101 		j = bpf_map__max_entries(prog_array) - 1 - i;
102 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", j);
103 
104 		prog = bpf_object__find_program_by_name(obj, prog_name);
105 		if (CHECK_FAIL(!prog))
106 			goto out;
107 
108 		prog_fd = bpf_program__fd(prog);
109 		if (CHECK_FAIL(prog_fd < 0))
110 			goto out;
111 
112 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
113 		if (CHECK_FAIL(err))
114 			goto out;
115 	}
116 
117 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
118 		j = bpf_map__max_entries(prog_array) - 1 - i;
119 
120 		err = bpf_prog_test_run_opts(main_fd, &topts);
121 		ASSERT_OK(err, "tailcall");
122 		ASSERT_EQ(topts.retval, j, "tailcall retval");
123 
124 		err = bpf_map_delete_elem(map_fd, &i);
125 		if (CHECK_FAIL(err))
126 			goto out;
127 	}
128 
129 	err = bpf_prog_test_run_opts(main_fd, &topts);
130 	ASSERT_OK(err, "tailcall");
131 	ASSERT_EQ(topts.retval, 3, "tailcall retval");
132 
133 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
134 		err = bpf_map_delete_elem(map_fd, &i);
135 		if (CHECK_FAIL(err >= 0 || errno != ENOENT))
136 			goto out;
137 
138 		err = bpf_prog_test_run_opts(main_fd, &topts);
139 		ASSERT_OK(err, "tailcall");
140 		ASSERT_EQ(topts.retval, 3, "tailcall retval");
141 	}
142 
143 out:
144 	bpf_object__close(obj);
145 }
146 
147 /* test_tailcall_2 checks that patching multiple programs for a single
148  * tail call slot works. It also jumps through several programs and tests
149  * the tail call limit counter.
150  */
test_tailcall_2(void)151 static void test_tailcall_2(void)
152 {
153 	int err, map_fd, prog_fd, main_fd, i;
154 	struct bpf_map *prog_array;
155 	struct bpf_program *prog;
156 	struct bpf_object *obj;
157 	char prog_name[32];
158 	char buff[128] = {};
159 	LIBBPF_OPTS(bpf_test_run_opts, topts,
160 		.data_in = buff,
161 		.data_size_in = sizeof(buff),
162 		.repeat = 1,
163 	);
164 
165 	err = bpf_prog_test_load("tailcall2.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
166 				 &prog_fd);
167 	if (CHECK_FAIL(err))
168 		return;
169 
170 	prog = bpf_object__find_program_by_name(obj, "entry");
171 	if (CHECK_FAIL(!prog))
172 		goto out;
173 
174 	main_fd = bpf_program__fd(prog);
175 	if (CHECK_FAIL(main_fd < 0))
176 		goto out;
177 
178 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
179 	if (CHECK_FAIL(!prog_array))
180 		goto out;
181 
182 	map_fd = bpf_map__fd(prog_array);
183 	if (CHECK_FAIL(map_fd < 0))
184 		goto out;
185 
186 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
187 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
188 
189 		prog = bpf_object__find_program_by_name(obj, prog_name);
190 		if (CHECK_FAIL(!prog))
191 			goto out;
192 
193 		prog_fd = bpf_program__fd(prog);
194 		if (CHECK_FAIL(prog_fd < 0))
195 			goto out;
196 
197 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
198 		if (CHECK_FAIL(err))
199 			goto out;
200 	}
201 
202 	err = bpf_prog_test_run_opts(main_fd, &topts);
203 	ASSERT_OK(err, "tailcall");
204 	ASSERT_EQ(topts.retval, 2, "tailcall retval");
205 
206 	i = 2;
207 	err = bpf_map_delete_elem(map_fd, &i);
208 	if (CHECK_FAIL(err))
209 		goto out;
210 
211 	err = bpf_prog_test_run_opts(main_fd, &topts);
212 	ASSERT_OK(err, "tailcall");
213 	ASSERT_EQ(topts.retval, 1, "tailcall retval");
214 
215 	i = 0;
216 	err = bpf_map_delete_elem(map_fd, &i);
217 	if (CHECK_FAIL(err))
218 		goto out;
219 
220 	err = bpf_prog_test_run_opts(main_fd, &topts);
221 	ASSERT_OK(err, "tailcall");
222 	ASSERT_EQ(topts.retval, 3, "tailcall retval");
223 out:
224 	bpf_object__close(obj);
225 }
226 
test_tailcall_count(const char * which,bool test_fentry,bool test_fexit)227 static void test_tailcall_count(const char *which, bool test_fentry,
228 				bool test_fexit)
229 {
230 	struct bpf_object *obj = NULL, *fentry_obj = NULL, *fexit_obj = NULL;
231 	struct bpf_link *fentry_link = NULL, *fexit_link = NULL;
232 	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
233 	struct bpf_map *prog_array, *data_map;
234 	struct bpf_program *prog;
235 	char buff[128] = {};
236 	LIBBPF_OPTS(bpf_test_run_opts, topts,
237 		.data_in = buff,
238 		.data_size_in = sizeof(buff),
239 		.repeat = 1,
240 	);
241 
242 	err = bpf_prog_test_load(which, BPF_PROG_TYPE_SCHED_CLS, &obj,
243 			    &prog_fd);
244 	if (CHECK_FAIL(err))
245 		return;
246 
247 	prog = bpf_object__find_program_by_name(obj, "entry");
248 	if (CHECK_FAIL(!prog))
249 		goto out;
250 
251 	main_fd = bpf_program__fd(prog);
252 	if (CHECK_FAIL(main_fd < 0))
253 		goto out;
254 
255 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
256 	if (CHECK_FAIL(!prog_array))
257 		goto out;
258 
259 	map_fd = bpf_map__fd(prog_array);
260 	if (CHECK_FAIL(map_fd < 0))
261 		goto out;
262 
263 	prog = bpf_object__find_program_by_name(obj, "classifier_0");
264 	if (CHECK_FAIL(!prog))
265 		goto out;
266 
267 	prog_fd = bpf_program__fd(prog);
268 	if (CHECK_FAIL(prog_fd < 0))
269 		goto out;
270 
271 	i = 0;
272 	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
273 	if (CHECK_FAIL(err))
274 		goto out;
275 
276 	if (test_fentry) {
277 		fentry_obj = bpf_object__open_file("tailcall_bpf2bpf_fentry.bpf.o",
278 						   NULL);
279 		if (!ASSERT_OK_PTR(fentry_obj, "open fentry_obj file"))
280 			goto out;
281 
282 		prog = bpf_object__find_program_by_name(fentry_obj, "fentry");
283 		if (!ASSERT_OK_PTR(prog, "find fentry prog"))
284 			goto out;
285 
286 		err = bpf_program__set_attach_target(prog, prog_fd,
287 						     "subprog_tail");
288 		if (!ASSERT_OK(err, "set_attach_target subprog_tail"))
289 			goto out;
290 
291 		err = bpf_object__load(fentry_obj);
292 		if (!ASSERT_OK(err, "load fentry_obj"))
293 			goto out;
294 
295 		fentry_link = bpf_program__attach_trace(prog);
296 		if (!ASSERT_OK_PTR(fentry_link, "attach_trace"))
297 			goto out;
298 	}
299 
300 	if (test_fexit) {
301 		fexit_obj = bpf_object__open_file("tailcall_bpf2bpf_fexit.bpf.o",
302 						  NULL);
303 		if (!ASSERT_OK_PTR(fexit_obj, "open fexit_obj file"))
304 			goto out;
305 
306 		prog = bpf_object__find_program_by_name(fexit_obj, "fexit");
307 		if (!ASSERT_OK_PTR(prog, "find fexit prog"))
308 			goto out;
309 
310 		err = bpf_program__set_attach_target(prog, prog_fd,
311 						     "subprog_tail");
312 		if (!ASSERT_OK(err, "set_attach_target subprog_tail"))
313 			goto out;
314 
315 		err = bpf_object__load(fexit_obj);
316 		if (!ASSERT_OK(err, "load fexit_obj"))
317 			goto out;
318 
319 		fexit_link = bpf_program__attach_trace(prog);
320 		if (!ASSERT_OK_PTR(fexit_link, "attach_trace"))
321 			goto out;
322 	}
323 
324 	err = bpf_prog_test_run_opts(main_fd, &topts);
325 	ASSERT_OK(err, "tailcall");
326 	ASSERT_EQ(topts.retval, 1, "tailcall retval");
327 
328 	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
329 	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
330 		goto out;
331 
332 	data_fd = bpf_map__fd(data_map);
333 	if (CHECK_FAIL(data_fd < 0))
334 		goto out;
335 
336 	i = 0;
337 	err = bpf_map_lookup_elem(data_fd, &i, &val);
338 	ASSERT_OK(err, "tailcall count");
339 	ASSERT_EQ(val, 33, "tailcall count");
340 
341 	if (test_fentry) {
342 		data_map = bpf_object__find_map_by_name(fentry_obj, ".bss");
343 		if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
344 				  "find tailcall_bpf2bpf_fentry.bss map"))
345 			goto out;
346 
347 		data_fd = bpf_map__fd(data_map);
348 		if (!ASSERT_FALSE(data_fd < 0,
349 				  "find tailcall_bpf2bpf_fentry.bss map fd"))
350 			goto out;
351 
352 		i = 0;
353 		err = bpf_map_lookup_elem(data_fd, &i, &val);
354 		ASSERT_OK(err, "fentry count");
355 		ASSERT_EQ(val, 33, "fentry count");
356 	}
357 
358 	if (test_fexit) {
359 		data_map = bpf_object__find_map_by_name(fexit_obj, ".bss");
360 		if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
361 				  "find tailcall_bpf2bpf_fexit.bss map"))
362 			goto out;
363 
364 		data_fd = bpf_map__fd(data_map);
365 		if (!ASSERT_FALSE(data_fd < 0,
366 				  "find tailcall_bpf2bpf_fexit.bss map fd"))
367 			goto out;
368 
369 		i = 0;
370 		err = bpf_map_lookup_elem(data_fd, &i, &val);
371 		ASSERT_OK(err, "fexit count");
372 		ASSERT_EQ(val, 33, "fexit count");
373 	}
374 
375 	i = 0;
376 	err = bpf_map_delete_elem(map_fd, &i);
377 	if (CHECK_FAIL(err))
378 		goto out;
379 
380 	err = bpf_prog_test_run_opts(main_fd, &topts);
381 	ASSERT_OK(err, "tailcall");
382 	ASSERT_OK(topts.retval, "tailcall retval");
383 out:
384 	bpf_link__destroy(fentry_link);
385 	bpf_link__destroy(fexit_link);
386 	bpf_object__close(fentry_obj);
387 	bpf_object__close(fexit_obj);
388 	bpf_object__close(obj);
389 }
390 
391 /* test_tailcall_3 checks that the count value of the tail call limit
392  * enforcement matches with expectations. JIT uses direct jump.
393  */
test_tailcall_3(void)394 static void test_tailcall_3(void)
395 {
396 	test_tailcall_count("tailcall3.bpf.o", false, false);
397 }
398 
399 /* test_tailcall_6 checks that the count value of the tail call limit
400  * enforcement matches with expectations. JIT uses indirect jump.
401  */
test_tailcall_6(void)402 static void test_tailcall_6(void)
403 {
404 	test_tailcall_count("tailcall6.bpf.o", false, false);
405 }
406 
407 /* test_tailcall_4 checks that the kernel properly selects indirect jump
408  * for the case where the key is not known. Latter is passed via global
409  * data to select different targets we can compare return value of.
410  */
test_tailcall_4(void)411 static void test_tailcall_4(void)
412 {
413 	int err, map_fd, prog_fd, main_fd, data_fd, i;
414 	struct bpf_map *prog_array, *data_map;
415 	struct bpf_program *prog;
416 	struct bpf_object *obj;
417 	static const int zero = 0;
418 	char buff[128] = {};
419 	char prog_name[32];
420 	LIBBPF_OPTS(bpf_test_run_opts, topts,
421 		.data_in = buff,
422 		.data_size_in = sizeof(buff),
423 		.repeat = 1,
424 	);
425 
426 	err = bpf_prog_test_load("tailcall4.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
427 				 &prog_fd);
428 	if (CHECK_FAIL(err))
429 		return;
430 
431 	prog = bpf_object__find_program_by_name(obj, "entry");
432 	if (CHECK_FAIL(!prog))
433 		goto out;
434 
435 	main_fd = bpf_program__fd(prog);
436 	if (CHECK_FAIL(main_fd < 0))
437 		goto out;
438 
439 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
440 	if (CHECK_FAIL(!prog_array))
441 		goto out;
442 
443 	map_fd = bpf_map__fd(prog_array);
444 	if (CHECK_FAIL(map_fd < 0))
445 		goto out;
446 
447 	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
448 	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
449 		goto out;
450 
451 	data_fd = bpf_map__fd(data_map);
452 	if (CHECK_FAIL(data_fd < 0))
453 		goto out;
454 
455 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
456 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
457 
458 		prog = bpf_object__find_program_by_name(obj, prog_name);
459 		if (CHECK_FAIL(!prog))
460 			goto out;
461 
462 		prog_fd = bpf_program__fd(prog);
463 		if (CHECK_FAIL(prog_fd < 0))
464 			goto out;
465 
466 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
467 		if (CHECK_FAIL(err))
468 			goto out;
469 	}
470 
471 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
472 		err = bpf_map_update_elem(data_fd, &zero, &i, BPF_ANY);
473 		if (CHECK_FAIL(err))
474 			goto out;
475 
476 		err = bpf_prog_test_run_opts(main_fd, &topts);
477 		ASSERT_OK(err, "tailcall");
478 		ASSERT_EQ(topts.retval, i, "tailcall retval");
479 	}
480 
481 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
482 		err = bpf_map_update_elem(data_fd, &zero, &i, BPF_ANY);
483 		if (CHECK_FAIL(err))
484 			goto out;
485 
486 		err = bpf_map_delete_elem(map_fd, &i);
487 		if (CHECK_FAIL(err))
488 			goto out;
489 
490 		err = bpf_prog_test_run_opts(main_fd, &topts);
491 		ASSERT_OK(err, "tailcall");
492 		ASSERT_EQ(topts.retval, 3, "tailcall retval");
493 	}
494 out:
495 	bpf_object__close(obj);
496 }
497 
498 /* test_tailcall_5 probes similarly to test_tailcall_4 that the kernel generates
499  * an indirect jump when the keys are const but different from different branches.
500  */
test_tailcall_5(void)501 static void test_tailcall_5(void)
502 {
503 	int err, map_fd, prog_fd, main_fd, data_fd, i, key[] = { 1111, 1234, 5678 };
504 	struct bpf_map *prog_array, *data_map;
505 	struct bpf_program *prog;
506 	struct bpf_object *obj;
507 	static const int zero = 0;
508 	char buff[128] = {};
509 	char prog_name[32];
510 	LIBBPF_OPTS(bpf_test_run_opts, topts,
511 		.data_in = buff,
512 		.data_size_in = sizeof(buff),
513 		.repeat = 1,
514 	);
515 
516 	err = bpf_prog_test_load("tailcall5.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
517 				 &prog_fd);
518 	if (CHECK_FAIL(err))
519 		return;
520 
521 	prog = bpf_object__find_program_by_name(obj, "entry");
522 	if (CHECK_FAIL(!prog))
523 		goto out;
524 
525 	main_fd = bpf_program__fd(prog);
526 	if (CHECK_FAIL(main_fd < 0))
527 		goto out;
528 
529 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
530 	if (CHECK_FAIL(!prog_array))
531 		goto out;
532 
533 	map_fd = bpf_map__fd(prog_array);
534 	if (CHECK_FAIL(map_fd < 0))
535 		goto out;
536 
537 	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
538 	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
539 		goto out;
540 
541 	data_fd = bpf_map__fd(data_map);
542 	if (CHECK_FAIL(data_fd < 0))
543 		goto out;
544 
545 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
546 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
547 
548 		prog = bpf_object__find_program_by_name(obj, prog_name);
549 		if (CHECK_FAIL(!prog))
550 			goto out;
551 
552 		prog_fd = bpf_program__fd(prog);
553 		if (CHECK_FAIL(prog_fd < 0))
554 			goto out;
555 
556 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
557 		if (CHECK_FAIL(err))
558 			goto out;
559 	}
560 
561 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
562 		err = bpf_map_update_elem(data_fd, &zero, &key[i], BPF_ANY);
563 		if (CHECK_FAIL(err))
564 			goto out;
565 
566 		err = bpf_prog_test_run_opts(main_fd, &topts);
567 		ASSERT_OK(err, "tailcall");
568 		ASSERT_EQ(topts.retval, i, "tailcall retval");
569 	}
570 
571 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
572 		err = bpf_map_update_elem(data_fd, &zero, &key[i], BPF_ANY);
573 		if (CHECK_FAIL(err))
574 			goto out;
575 
576 		err = bpf_map_delete_elem(map_fd, &i);
577 		if (CHECK_FAIL(err))
578 			goto out;
579 
580 		err = bpf_prog_test_run_opts(main_fd, &topts);
581 		ASSERT_OK(err, "tailcall");
582 		ASSERT_EQ(topts.retval, 3, "tailcall retval");
583 	}
584 out:
585 	bpf_object__close(obj);
586 }
587 
588 /* test_tailcall_bpf2bpf_1 purpose is to make sure that tailcalls are working
589  * correctly in correlation with BPF subprograms
590  */
test_tailcall_bpf2bpf_1(void)591 static void test_tailcall_bpf2bpf_1(void)
592 {
593 	int err, map_fd, prog_fd, main_fd, i;
594 	struct bpf_map *prog_array;
595 	struct bpf_program *prog;
596 	struct bpf_object *obj;
597 	char prog_name[32];
598 	LIBBPF_OPTS(bpf_test_run_opts, topts,
599 		.data_in = &pkt_v4,
600 		.data_size_in = sizeof(pkt_v4),
601 		.repeat = 1,
602 	);
603 
604 	err = bpf_prog_test_load("tailcall_bpf2bpf1.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
605 				 &obj, &prog_fd);
606 	if (CHECK_FAIL(err))
607 		return;
608 
609 	prog = bpf_object__find_program_by_name(obj, "entry");
610 	if (CHECK_FAIL(!prog))
611 		goto out;
612 
613 	main_fd = bpf_program__fd(prog);
614 	if (CHECK_FAIL(main_fd < 0))
615 		goto out;
616 
617 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
618 	if (CHECK_FAIL(!prog_array))
619 		goto out;
620 
621 	map_fd = bpf_map__fd(prog_array);
622 	if (CHECK_FAIL(map_fd < 0))
623 		goto out;
624 
625 	/* nop -> jmp */
626 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
627 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
628 
629 		prog = bpf_object__find_program_by_name(obj, prog_name);
630 		if (CHECK_FAIL(!prog))
631 			goto out;
632 
633 		prog_fd = bpf_program__fd(prog);
634 		if (CHECK_FAIL(prog_fd < 0))
635 			goto out;
636 
637 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
638 		if (CHECK_FAIL(err))
639 			goto out;
640 	}
641 
642 	err = bpf_prog_test_run_opts(main_fd, &topts);
643 	ASSERT_OK(err, "tailcall");
644 	ASSERT_EQ(topts.retval, 1, "tailcall retval");
645 
646 	/* jmp -> nop, call subprog that will do tailcall */
647 	i = 1;
648 	err = bpf_map_delete_elem(map_fd, &i);
649 	if (CHECK_FAIL(err))
650 		goto out;
651 
652 	err = bpf_prog_test_run_opts(main_fd, &topts);
653 	ASSERT_OK(err, "tailcall");
654 	ASSERT_OK(topts.retval, "tailcall retval");
655 
656 	/* make sure that subprog can access ctx and entry prog that
657 	 * called this subprog can properly return
658 	 */
659 	i = 0;
660 	err = bpf_map_delete_elem(map_fd, &i);
661 	if (CHECK_FAIL(err))
662 		goto out;
663 
664 	err = bpf_prog_test_run_opts(main_fd, &topts);
665 	ASSERT_OK(err, "tailcall");
666 	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 2, "tailcall retval");
667 out:
668 	bpf_object__close(obj);
669 }
670 
671 /* test_tailcall_bpf2bpf_2 checks that the count value of the tail call limit
672  * enforcement matches with expectations when tailcall is preceded with
673  * bpf2bpf call.
674  */
test_tailcall_bpf2bpf_2(void)675 static void test_tailcall_bpf2bpf_2(void)
676 {
677 	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
678 	struct bpf_map *prog_array, *data_map;
679 	struct bpf_program *prog;
680 	struct bpf_object *obj;
681 	char buff[128] = {};
682 	LIBBPF_OPTS(bpf_test_run_opts, topts,
683 		.data_in = buff,
684 		.data_size_in = sizeof(buff),
685 		.repeat = 1,
686 	);
687 
688 	err = bpf_prog_test_load("tailcall_bpf2bpf2.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
689 				 &obj, &prog_fd);
690 	if (CHECK_FAIL(err))
691 		return;
692 
693 	prog = bpf_object__find_program_by_name(obj, "entry");
694 	if (CHECK_FAIL(!prog))
695 		goto out;
696 
697 	main_fd = bpf_program__fd(prog);
698 	if (CHECK_FAIL(main_fd < 0))
699 		goto out;
700 
701 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
702 	if (CHECK_FAIL(!prog_array))
703 		goto out;
704 
705 	map_fd = bpf_map__fd(prog_array);
706 	if (CHECK_FAIL(map_fd < 0))
707 		goto out;
708 
709 	prog = bpf_object__find_program_by_name(obj, "classifier_0");
710 	if (CHECK_FAIL(!prog))
711 		goto out;
712 
713 	prog_fd = bpf_program__fd(prog);
714 	if (CHECK_FAIL(prog_fd < 0))
715 		goto out;
716 
717 	i = 0;
718 	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
719 	if (CHECK_FAIL(err))
720 		goto out;
721 
722 	err = bpf_prog_test_run_opts(main_fd, &topts);
723 	ASSERT_OK(err, "tailcall");
724 	ASSERT_EQ(topts.retval, 1, "tailcall retval");
725 
726 	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
727 	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
728 		goto out;
729 
730 	data_fd = bpf_map__fd(data_map);
731 	if (CHECK_FAIL(data_fd < 0))
732 		goto out;
733 
734 	i = 0;
735 	err = bpf_map_lookup_elem(data_fd, &i, &val);
736 	ASSERT_OK(err, "tailcall count");
737 	ASSERT_EQ(val, 33, "tailcall count");
738 
739 	i = 0;
740 	err = bpf_map_delete_elem(map_fd, &i);
741 	if (CHECK_FAIL(err))
742 		goto out;
743 
744 	err = bpf_prog_test_run_opts(main_fd, &topts);
745 	ASSERT_OK(err, "tailcall");
746 	ASSERT_OK(topts.retval, "tailcall retval");
747 out:
748 	bpf_object__close(obj);
749 }
750 
751 /* test_tailcall_bpf2bpf_3 checks that non-trivial amount of stack (up to
752  * 256 bytes) can be used within bpf subprograms that have the tailcalls
753  * in them
754  */
test_tailcall_bpf2bpf_3(void)755 static void test_tailcall_bpf2bpf_3(void)
756 {
757 	int err, map_fd, prog_fd, main_fd, i;
758 	struct bpf_map *prog_array;
759 	struct bpf_program *prog;
760 	struct bpf_object *obj;
761 	char prog_name[32];
762 	LIBBPF_OPTS(bpf_test_run_opts, topts,
763 		.data_in = &pkt_v4,
764 		.data_size_in = sizeof(pkt_v4),
765 		.repeat = 1,
766 	);
767 
768 	err = bpf_prog_test_load("tailcall_bpf2bpf3.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
769 				 &obj, &prog_fd);
770 	if (CHECK_FAIL(err))
771 		return;
772 
773 	prog = bpf_object__find_program_by_name(obj, "entry");
774 	if (CHECK_FAIL(!prog))
775 		goto out;
776 
777 	main_fd = bpf_program__fd(prog);
778 	if (CHECK_FAIL(main_fd < 0))
779 		goto out;
780 
781 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
782 	if (CHECK_FAIL(!prog_array))
783 		goto out;
784 
785 	map_fd = bpf_map__fd(prog_array);
786 	if (CHECK_FAIL(map_fd < 0))
787 		goto out;
788 
789 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
790 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
791 
792 		prog = bpf_object__find_program_by_name(obj, prog_name);
793 		if (CHECK_FAIL(!prog))
794 			goto out;
795 
796 		prog_fd = bpf_program__fd(prog);
797 		if (CHECK_FAIL(prog_fd < 0))
798 			goto out;
799 
800 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
801 		if (CHECK_FAIL(err))
802 			goto out;
803 	}
804 
805 	err = bpf_prog_test_run_opts(main_fd, &topts);
806 	ASSERT_OK(err, "tailcall");
807 	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 3, "tailcall retval");
808 
809 	i = 1;
810 	err = bpf_map_delete_elem(map_fd, &i);
811 	if (CHECK_FAIL(err))
812 		goto out;
813 
814 	err = bpf_prog_test_run_opts(main_fd, &topts);
815 	ASSERT_OK(err, "tailcall");
816 	ASSERT_EQ(topts.retval, sizeof(pkt_v4), "tailcall retval");
817 
818 	i = 0;
819 	err = bpf_map_delete_elem(map_fd, &i);
820 	if (CHECK_FAIL(err))
821 		goto out;
822 
823 	err = bpf_prog_test_run_opts(main_fd, &topts);
824 	ASSERT_OK(err, "tailcall");
825 	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 2, "tailcall retval");
826 out:
827 	bpf_object__close(obj);
828 }
829 
830 #include "tailcall_bpf2bpf4.skel.h"
831 
832 /* test_tailcall_bpf2bpf_4 checks that tailcall counter is correctly preserved
833  * across tailcalls combined with bpf2bpf calls. for making sure that tailcall
834  * counter behaves correctly, bpf program will go through following flow:
835  *
836  * entry -> entry_subprog -> tailcall0 -> bpf_func0 -> subprog0 ->
837  * -> tailcall1 -> bpf_func1 -> subprog1 -> tailcall2 -> bpf_func2 ->
838  * subprog2 [here bump global counter] --------^
839  *
840  * We go through first two tailcalls and start counting from the subprog2 where
841  * the loop begins. At the end of the test make sure that the global counter is
842  * equal to 31, because tailcall counter includes the first two tailcalls
843  * whereas global counter is incremented only on loop presented on flow above.
844  *
845  * The noise parameter is used to insert bpf_map_update calls into the logic
846  * to force verifier to patch instructions. This allows us to ensure jump
847  * logic remains correct with instruction movement.
848  */
test_tailcall_bpf2bpf_4(bool noise)849 static void test_tailcall_bpf2bpf_4(bool noise)
850 {
851 	int err, map_fd, prog_fd, main_fd, data_fd, i;
852 	struct tailcall_bpf2bpf4__bss val;
853 	struct bpf_map *prog_array, *data_map;
854 	struct bpf_program *prog;
855 	struct bpf_object *obj;
856 	char prog_name[32];
857 	LIBBPF_OPTS(bpf_test_run_opts, topts,
858 		.data_in = &pkt_v4,
859 		.data_size_in = sizeof(pkt_v4),
860 		.repeat = 1,
861 	);
862 
863 	err = bpf_prog_test_load("tailcall_bpf2bpf4.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
864 				 &obj, &prog_fd);
865 	if (CHECK_FAIL(err))
866 		return;
867 
868 	prog = bpf_object__find_program_by_name(obj, "entry");
869 	if (CHECK_FAIL(!prog))
870 		goto out;
871 
872 	main_fd = bpf_program__fd(prog);
873 	if (CHECK_FAIL(main_fd < 0))
874 		goto out;
875 
876 	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
877 	if (CHECK_FAIL(!prog_array))
878 		goto out;
879 
880 	map_fd = bpf_map__fd(prog_array);
881 	if (CHECK_FAIL(map_fd < 0))
882 		goto out;
883 
884 	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
885 		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
886 
887 		prog = bpf_object__find_program_by_name(obj, prog_name);
888 		if (CHECK_FAIL(!prog))
889 			goto out;
890 
891 		prog_fd = bpf_program__fd(prog);
892 		if (CHECK_FAIL(prog_fd < 0))
893 			goto out;
894 
895 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
896 		if (CHECK_FAIL(err))
897 			goto out;
898 	}
899 
900 	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
901 	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
902 		goto out;
903 
904 	data_fd = bpf_map__fd(data_map);
905 	if (CHECK_FAIL(data_fd < 0))
906 		goto out;
907 
908 	i = 0;
909 	val.noise = noise;
910 	val.count = 0;
911 	err = bpf_map_update_elem(data_fd, &i, &val, BPF_ANY);
912 	if (CHECK_FAIL(err))
913 		goto out;
914 
915 	err = bpf_prog_test_run_opts(main_fd, &topts);
916 	ASSERT_OK(err, "tailcall");
917 	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 3, "tailcall retval");
918 
919 	i = 0;
920 	err = bpf_map_lookup_elem(data_fd, &i, &val);
921 	ASSERT_OK(err, "tailcall count");
922 	ASSERT_EQ(val.count, 31, "tailcall count");
923 
924 out:
925 	bpf_object__close(obj);
926 }
927 
928 #include "tailcall_bpf2bpf6.skel.h"
929 
930 /* Tail call counting works even when there is data on stack which is
931  * not aligned to 8 bytes.
932  */
test_tailcall_bpf2bpf_6(void)933 static void test_tailcall_bpf2bpf_6(void)
934 {
935 	struct tailcall_bpf2bpf6 *obj;
936 	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
937 	LIBBPF_OPTS(bpf_test_run_opts, topts,
938 		.data_in = &pkt_v4,
939 		.data_size_in = sizeof(pkt_v4),
940 		.repeat = 1,
941 	);
942 
943 	obj = tailcall_bpf2bpf6__open_and_load();
944 	if (!ASSERT_OK_PTR(obj, "open and load"))
945 		return;
946 
947 	main_fd = bpf_program__fd(obj->progs.entry);
948 	if (!ASSERT_GE(main_fd, 0, "entry prog fd"))
949 		goto out;
950 
951 	map_fd = bpf_map__fd(obj->maps.jmp_table);
952 	if (!ASSERT_GE(map_fd, 0, "jmp_table map fd"))
953 		goto out;
954 
955 	prog_fd = bpf_program__fd(obj->progs.classifier_0);
956 	if (!ASSERT_GE(prog_fd, 0, "classifier_0 prog fd"))
957 		goto out;
958 
959 	i = 0;
960 	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
961 	if (!ASSERT_OK(err, "jmp_table map update"))
962 		goto out;
963 
964 	err = bpf_prog_test_run_opts(main_fd, &topts);
965 	ASSERT_OK(err, "entry prog test run");
966 	ASSERT_EQ(topts.retval, 0, "tailcall retval");
967 
968 	data_fd = bpf_map__fd(obj->maps.bss);
969 	if (!ASSERT_GE(data_fd, 0, "bss map fd"))
970 		goto out;
971 
972 	i = 0;
973 	err = bpf_map_lookup_elem(data_fd, &i, &val);
974 	ASSERT_OK(err, "bss map lookup");
975 	ASSERT_EQ(val, 1, "done flag is set");
976 
977 out:
978 	tailcall_bpf2bpf6__destroy(obj);
979 }
980 
981 /* test_tailcall_bpf2bpf_fentry checks that the count value of the tail call
982  * limit enforcement matches with expectations when tailcall is preceded with
983  * bpf2bpf call, and the bpf2bpf call is traced by fentry.
984  */
test_tailcall_bpf2bpf_fentry(void)985 static void test_tailcall_bpf2bpf_fentry(void)
986 {
987 	test_tailcall_count("tailcall_bpf2bpf2.bpf.o", true, false);
988 }
989 
990 /* test_tailcall_bpf2bpf_fexit checks that the count value of the tail call
991  * limit enforcement matches with expectations when tailcall is preceded with
992  * bpf2bpf call, and the bpf2bpf call is traced by fexit.
993  */
test_tailcall_bpf2bpf_fexit(void)994 static void test_tailcall_bpf2bpf_fexit(void)
995 {
996 	test_tailcall_count("tailcall_bpf2bpf2.bpf.o", false, true);
997 }
998 
999 /* test_tailcall_bpf2bpf_fentry_fexit checks that the count value of the tail
1000  * call limit enforcement matches with expectations when tailcall is preceded
1001  * with bpf2bpf call, and the bpf2bpf call is traced by both fentry and fexit.
1002  */
test_tailcall_bpf2bpf_fentry_fexit(void)1003 static void test_tailcall_bpf2bpf_fentry_fexit(void)
1004 {
1005 	test_tailcall_count("tailcall_bpf2bpf2.bpf.o", true, true);
1006 }
1007 
1008 /* test_tailcall_bpf2bpf_fentry_entry checks that the count value of the tail
1009  * call limit enforcement matches with expectations when tailcall is preceded
1010  * with bpf2bpf call, and the bpf2bpf caller is traced by fentry.
1011  */
test_tailcall_bpf2bpf_fentry_entry(void)1012 static void test_tailcall_bpf2bpf_fentry_entry(void)
1013 {
1014 	struct bpf_object *tgt_obj = NULL, *fentry_obj = NULL;
1015 	int err, map_fd, prog_fd, data_fd, i, val;
1016 	struct bpf_map *prog_array, *data_map;
1017 	struct bpf_link *fentry_link = NULL;
1018 	struct bpf_program *prog;
1019 	char buff[128] = {};
1020 
1021 	LIBBPF_OPTS(bpf_test_run_opts, topts,
1022 		.data_in = buff,
1023 		.data_size_in = sizeof(buff),
1024 		.repeat = 1,
1025 	);
1026 
1027 	err = bpf_prog_test_load("tailcall_bpf2bpf2.bpf.o",
1028 				 BPF_PROG_TYPE_SCHED_CLS,
1029 				 &tgt_obj, &prog_fd);
1030 	if (!ASSERT_OK(err, "load tgt_obj"))
1031 		return;
1032 
1033 	prog_array = bpf_object__find_map_by_name(tgt_obj, "jmp_table");
1034 	if (!ASSERT_OK_PTR(prog_array, "find jmp_table map"))
1035 		goto out;
1036 
1037 	map_fd = bpf_map__fd(prog_array);
1038 	if (!ASSERT_FALSE(map_fd < 0, "find jmp_table map fd"))
1039 		goto out;
1040 
1041 	prog = bpf_object__find_program_by_name(tgt_obj, "classifier_0");
1042 	if (!ASSERT_OK_PTR(prog, "find classifier_0 prog"))
1043 		goto out;
1044 
1045 	prog_fd = bpf_program__fd(prog);
1046 	if (!ASSERT_FALSE(prog_fd < 0, "find classifier_0 prog fd"))
1047 		goto out;
1048 
1049 	i = 0;
1050 	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
1051 	if (!ASSERT_OK(err, "update jmp_table"))
1052 		goto out;
1053 
1054 	fentry_obj = bpf_object__open_file("tailcall_bpf2bpf_fentry.bpf.o",
1055 					   NULL);
1056 	if (!ASSERT_OK_PTR(fentry_obj, "open fentry_obj file"))
1057 		goto out;
1058 
1059 	prog = bpf_object__find_program_by_name(fentry_obj, "fentry");
1060 	if (!ASSERT_OK_PTR(prog, "find fentry prog"))
1061 		goto out;
1062 
1063 	err = bpf_program__set_attach_target(prog, prog_fd, "classifier_0");
1064 	if (!ASSERT_OK(err, "set_attach_target classifier_0"))
1065 		goto out;
1066 
1067 	err = bpf_object__load(fentry_obj);
1068 	if (!ASSERT_OK(err, "load fentry_obj"))
1069 		goto out;
1070 
1071 	fentry_link = bpf_program__attach_trace(prog);
1072 	if (!ASSERT_OK_PTR(fentry_link, "attach_trace"))
1073 		goto out;
1074 
1075 	err = bpf_prog_test_run_opts(prog_fd, &topts);
1076 	ASSERT_OK(err, "tailcall");
1077 	ASSERT_EQ(topts.retval, 1, "tailcall retval");
1078 
1079 	data_map = bpf_object__find_map_by_name(tgt_obj, "tailcall.bss");
1080 	if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
1081 			  "find tailcall.bss map"))
1082 		goto out;
1083 
1084 	data_fd = bpf_map__fd(data_map);
1085 	if (!ASSERT_FALSE(data_fd < 0, "find tailcall.bss map fd"))
1086 		goto out;
1087 
1088 	i = 0;
1089 	err = bpf_map_lookup_elem(data_fd, &i, &val);
1090 	ASSERT_OK(err, "tailcall count");
1091 	ASSERT_EQ(val, 34, "tailcall count");
1092 
1093 	data_map = bpf_object__find_map_by_name(fentry_obj, ".bss");
1094 	if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
1095 			  "find tailcall_bpf2bpf_fentry.bss map"))
1096 		goto out;
1097 
1098 	data_fd = bpf_map__fd(data_map);
1099 	if (!ASSERT_FALSE(data_fd < 0,
1100 			  "find tailcall_bpf2bpf_fentry.bss map fd"))
1101 		goto out;
1102 
1103 	i = 0;
1104 	err = bpf_map_lookup_elem(data_fd, &i, &val);
1105 	ASSERT_OK(err, "fentry count");
1106 	ASSERT_EQ(val, 1, "fentry count");
1107 
1108 out:
1109 	bpf_link__destroy(fentry_link);
1110 	bpf_object__close(fentry_obj);
1111 	bpf_object__close(tgt_obj);
1112 }
1113 
1114 #define JMP_TABLE "/sys/fs/bpf/jmp_table"
1115 
1116 static int poke_thread_exit;
1117 
poke_update(void * arg)1118 static void *poke_update(void *arg)
1119 {
1120 	__u32 zero = 0, prog1_fd, prog2_fd, map_fd;
1121 	struct tailcall_poke *call = arg;
1122 
1123 	map_fd = bpf_map__fd(call->maps.jmp_table);
1124 	prog1_fd = bpf_program__fd(call->progs.call1);
1125 	prog2_fd = bpf_program__fd(call->progs.call2);
1126 
1127 	while (!poke_thread_exit) {
1128 		bpf_map_update_elem(map_fd, &zero, &prog1_fd, BPF_ANY);
1129 		bpf_map_update_elem(map_fd, &zero, &prog2_fd, BPF_ANY);
1130 	}
1131 
1132 	return NULL;
1133 }
1134 
1135 /*
1136  * We are trying to hit prog array update during another program load
1137  * that shares the same prog array map.
1138  *
1139  * For that we share the jmp_table map between two skeleton instances
1140  * by pinning the jmp_table to same path. Then first skeleton instance
1141  * periodically updates jmp_table in 'poke update' thread while we load
1142  * the second skeleton instance in the main thread.
1143  */
test_tailcall_poke(void)1144 static void test_tailcall_poke(void)
1145 {
1146 	struct tailcall_poke *call, *test;
1147 	int err, cnt = 10;
1148 	pthread_t thread;
1149 
1150 	unlink(JMP_TABLE);
1151 
1152 	call = tailcall_poke__open_and_load();
1153 	if (!ASSERT_OK_PTR(call, "tailcall_poke__open"))
1154 		return;
1155 
1156 	err = bpf_map__pin(call->maps.jmp_table, JMP_TABLE);
1157 	if (!ASSERT_OK(err, "bpf_map__pin"))
1158 		goto out;
1159 
1160 	err = pthread_create(&thread, NULL, poke_update, call);
1161 	if (!ASSERT_OK(err, "new toggler"))
1162 		goto out;
1163 
1164 	while (cnt--) {
1165 		test = tailcall_poke__open();
1166 		if (!ASSERT_OK_PTR(test, "tailcall_poke__open"))
1167 			break;
1168 
1169 		err = bpf_map__set_pin_path(test->maps.jmp_table, JMP_TABLE);
1170 		if (!ASSERT_OK(err, "bpf_map__pin")) {
1171 			tailcall_poke__destroy(test);
1172 			break;
1173 		}
1174 
1175 		bpf_program__set_autoload(test->progs.test, true);
1176 		bpf_program__set_autoload(test->progs.call1, false);
1177 		bpf_program__set_autoload(test->progs.call2, false);
1178 
1179 		err = tailcall_poke__load(test);
1180 		tailcall_poke__destroy(test);
1181 		if (!ASSERT_OK(err, "tailcall_poke__load"))
1182 			break;
1183 	}
1184 
1185 	poke_thread_exit = 1;
1186 	ASSERT_OK(pthread_join(thread, NULL), "pthread_join");
1187 
1188 out:
1189 	bpf_map__unpin(call->maps.jmp_table, JMP_TABLE);
1190 	tailcall_poke__destroy(call);
1191 }
1192 
test_tailcall_hierarchy_count(const char * which,bool test_fentry,bool test_fexit,bool test_fentry_entry)1193 static void test_tailcall_hierarchy_count(const char *which, bool test_fentry,
1194 					  bool test_fexit,
1195 					  bool test_fentry_entry)
1196 {
1197 	int err, map_fd, prog_fd, main_data_fd, fentry_data_fd, fexit_data_fd, i, val;
1198 	struct bpf_object *obj = NULL, *fentry_obj = NULL, *fexit_obj = NULL;
1199 	struct bpf_link *fentry_link = NULL, *fexit_link = NULL;
1200 	struct bpf_program *prog, *fentry_prog;
1201 	struct bpf_map *prog_array, *data_map;
1202 	int fentry_prog_fd;
1203 	char buff[128] = {};
1204 
1205 	LIBBPF_OPTS(bpf_test_run_opts, topts,
1206 		.data_in = buff,
1207 		.data_size_in = sizeof(buff),
1208 		.repeat = 1,
1209 	);
1210 
1211 	err = bpf_prog_test_load(which, BPF_PROG_TYPE_SCHED_CLS, &obj,
1212 				 &prog_fd);
1213 	if (!ASSERT_OK(err, "load obj"))
1214 		return;
1215 
1216 	prog = bpf_object__find_program_by_name(obj, "entry");
1217 	if (!ASSERT_OK_PTR(prog, "find entry prog"))
1218 		goto out;
1219 
1220 	prog_fd = bpf_program__fd(prog);
1221 	if (!ASSERT_GE(prog_fd, 0, "prog_fd"))
1222 		goto out;
1223 
1224 	if (test_fentry_entry) {
1225 		fentry_obj = bpf_object__open_file("tailcall_bpf2bpf_hierarchy_fentry.bpf.o",
1226 						   NULL);
1227 		if (!ASSERT_OK_PTR(fentry_obj, "open fentry_obj file"))
1228 			goto out;
1229 
1230 		fentry_prog = bpf_object__find_program_by_name(fentry_obj,
1231 							       "fentry");
1232 		if (!ASSERT_OK_PTR(prog, "find fentry prog"))
1233 			goto out;
1234 
1235 		err = bpf_program__set_attach_target(fentry_prog, prog_fd,
1236 						     "entry");
1237 		if (!ASSERT_OK(err, "set_attach_target entry"))
1238 			goto out;
1239 
1240 		err = bpf_object__load(fentry_obj);
1241 		if (!ASSERT_OK(err, "load fentry_obj"))
1242 			goto out;
1243 
1244 		fentry_link = bpf_program__attach_trace(fentry_prog);
1245 		if (!ASSERT_OK_PTR(fentry_link, "attach_trace"))
1246 			goto out;
1247 
1248 		fentry_prog_fd = bpf_program__fd(fentry_prog);
1249 		if (!ASSERT_GE(fentry_prog_fd, 0, "fentry_prog_fd"))
1250 			goto out;
1251 
1252 		prog_array = bpf_object__find_map_by_name(fentry_obj, "jmp_table");
1253 		if (!ASSERT_OK_PTR(prog_array, "find jmp_table"))
1254 			goto out;
1255 
1256 		map_fd = bpf_map__fd(prog_array);
1257 		if (!ASSERT_GE(map_fd, 0, "map_fd"))
1258 			goto out;
1259 
1260 		i = 0;
1261 		err = bpf_map_update_elem(map_fd, &i, &fentry_prog_fd, BPF_ANY);
1262 		if (!ASSERT_OK(err, "update jmp_table"))
1263 			goto out;
1264 
1265 		data_map = bpf_object__find_map_by_name(fentry_obj, ".bss");
1266 		if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
1267 				  "find data_map"))
1268 			goto out;
1269 
1270 	} else {
1271 		prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
1272 		if (!ASSERT_OK_PTR(prog_array, "find jmp_table"))
1273 			goto out;
1274 
1275 		map_fd = bpf_map__fd(prog_array);
1276 		if (!ASSERT_GE(map_fd, 0, "map_fd"))
1277 			goto out;
1278 
1279 		i = 0;
1280 		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
1281 		if (!ASSERT_OK(err, "update jmp_table"))
1282 			goto out;
1283 
1284 		data_map = bpf_object__find_map_by_name(obj, ".bss");
1285 		if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
1286 				  "find data_map"))
1287 			goto out;
1288 	}
1289 
1290 	if (test_fentry) {
1291 		fentry_obj = bpf_object__open_file("tailcall_bpf2bpf_fentry.bpf.o",
1292 						   NULL);
1293 		if (!ASSERT_OK_PTR(fentry_obj, "open fentry_obj file"))
1294 			goto out;
1295 
1296 		prog = bpf_object__find_program_by_name(fentry_obj, "fentry");
1297 		if (!ASSERT_OK_PTR(prog, "find fentry prog"))
1298 			goto out;
1299 
1300 		err = bpf_program__set_attach_target(prog, prog_fd,
1301 						     "subprog_tail");
1302 		if (!ASSERT_OK(err, "set_attach_target subprog_tail"))
1303 			goto out;
1304 
1305 		err = bpf_object__load(fentry_obj);
1306 		if (!ASSERT_OK(err, "load fentry_obj"))
1307 			goto out;
1308 
1309 		fentry_link = bpf_program__attach_trace(prog);
1310 		if (!ASSERT_OK_PTR(fentry_link, "attach_trace"))
1311 			goto out;
1312 	}
1313 
1314 	if (test_fexit) {
1315 		fexit_obj = bpf_object__open_file("tailcall_bpf2bpf_fexit.bpf.o",
1316 						  NULL);
1317 		if (!ASSERT_OK_PTR(fexit_obj, "open fexit_obj file"))
1318 			goto out;
1319 
1320 		prog = bpf_object__find_program_by_name(fexit_obj, "fexit");
1321 		if (!ASSERT_OK_PTR(prog, "find fexit prog"))
1322 			goto out;
1323 
1324 		err = bpf_program__set_attach_target(prog, prog_fd,
1325 						     "subprog_tail");
1326 		if (!ASSERT_OK(err, "set_attach_target subprog_tail"))
1327 			goto out;
1328 
1329 		err = bpf_object__load(fexit_obj);
1330 		if (!ASSERT_OK(err, "load fexit_obj"))
1331 			goto out;
1332 
1333 		fexit_link = bpf_program__attach_trace(prog);
1334 		if (!ASSERT_OK_PTR(fexit_link, "attach_trace"))
1335 			goto out;
1336 	}
1337 
1338 	err = bpf_prog_test_run_opts(prog_fd, &topts);
1339 	ASSERT_OK(err, "tailcall");
1340 	ASSERT_EQ(topts.retval, 1, "tailcall retval");
1341 
1342 	main_data_fd = bpf_map__fd(data_map);
1343 	if (!ASSERT_GE(main_data_fd, 0, "main_data_fd"))
1344 		goto out;
1345 
1346 	i = 0;
1347 	err = bpf_map_lookup_elem(main_data_fd, &i, &val);
1348 	ASSERT_OK(err, "tailcall count");
1349 	ASSERT_EQ(val, 34, "tailcall count");
1350 
1351 	if (test_fentry) {
1352 		data_map = bpf_object__find_map_by_name(fentry_obj, ".bss");
1353 		if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
1354 				  "find tailcall_bpf2bpf_fentry.bss map"))
1355 			goto out;
1356 
1357 		fentry_data_fd = bpf_map__fd(data_map);
1358 		if (!ASSERT_GE(fentry_data_fd, 0,
1359 				  "find tailcall_bpf2bpf_fentry.bss map fd"))
1360 			goto out;
1361 
1362 		i = 0;
1363 		err = bpf_map_lookup_elem(fentry_data_fd, &i, &val);
1364 		ASSERT_OK(err, "fentry count");
1365 		ASSERT_EQ(val, 68, "fentry count");
1366 	}
1367 
1368 	if (test_fexit) {
1369 		data_map = bpf_object__find_map_by_name(fexit_obj, ".bss");
1370 		if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
1371 				  "find tailcall_bpf2bpf_fexit.bss map"))
1372 			goto out;
1373 
1374 		fexit_data_fd = bpf_map__fd(data_map);
1375 		if (!ASSERT_GE(fexit_data_fd, 0,
1376 				  "find tailcall_bpf2bpf_fexit.bss map fd"))
1377 			goto out;
1378 
1379 		i = 0;
1380 		err = bpf_map_lookup_elem(fexit_data_fd, &i, &val);
1381 		ASSERT_OK(err, "fexit count");
1382 		ASSERT_EQ(val, 68, "fexit count");
1383 	}
1384 
1385 	i = 0;
1386 	err = bpf_map_delete_elem(map_fd, &i);
1387 	if (!ASSERT_OK(err, "delete_elem from jmp_table"))
1388 		goto out;
1389 
1390 	err = bpf_prog_test_run_opts(prog_fd, &topts);
1391 	ASSERT_OK(err, "tailcall");
1392 	ASSERT_EQ(topts.retval, 1, "tailcall retval");
1393 
1394 	i = 0;
1395 	err = bpf_map_lookup_elem(main_data_fd, &i, &val);
1396 	ASSERT_OK(err, "tailcall count");
1397 	ASSERT_EQ(val, 35, "tailcall count");
1398 
1399 	if (test_fentry) {
1400 		i = 0;
1401 		err = bpf_map_lookup_elem(fentry_data_fd, &i, &val);
1402 		ASSERT_OK(err, "fentry count");
1403 		ASSERT_EQ(val, 70, "fentry count");
1404 	}
1405 
1406 	if (test_fexit) {
1407 		i = 0;
1408 		err = bpf_map_lookup_elem(fexit_data_fd, &i, &val);
1409 		ASSERT_OK(err, "fexit count");
1410 		ASSERT_EQ(val, 70, "fexit count");
1411 	}
1412 
1413 out:
1414 	bpf_link__destroy(fentry_link);
1415 	bpf_link__destroy(fexit_link);
1416 	bpf_object__close(fentry_obj);
1417 	bpf_object__close(fexit_obj);
1418 	bpf_object__close(obj);
1419 }
1420 
1421 /* test_tailcall_bpf2bpf_hierarchy_1 checks that the count value of the tail
1422  * call limit enforcement matches with expectations when tailcalls are preceded
1423  * with two bpf2bpf calls.
1424  *
1425  *         subprog --tailcall-> entry
1426  * entry <
1427  *         subprog --tailcall-> entry
1428  */
test_tailcall_bpf2bpf_hierarchy_1(void)1429 static void test_tailcall_bpf2bpf_hierarchy_1(void)
1430 {
1431 	test_tailcall_hierarchy_count("tailcall_bpf2bpf_hierarchy1.bpf.o",
1432 				      false, false, false);
1433 }
1434 
1435 /* test_tailcall_bpf2bpf_hierarchy_fentry checks that the count value of the
1436  * tail call limit enforcement matches with expectations when tailcalls are
1437  * preceded with two bpf2bpf calls, and the two subprogs are traced by fentry.
1438  */
test_tailcall_bpf2bpf_hierarchy_fentry(void)1439 static void test_tailcall_bpf2bpf_hierarchy_fentry(void)
1440 {
1441 	test_tailcall_hierarchy_count("tailcall_bpf2bpf_hierarchy1.bpf.o",
1442 				      true, false, false);
1443 }
1444 
1445 /* test_tailcall_bpf2bpf_hierarchy_fexit checks that the count value of the tail
1446  * call limit enforcement matches with expectations when tailcalls are preceded
1447  * with two bpf2bpf calls, and the two subprogs are traced by fexit.
1448  */
test_tailcall_bpf2bpf_hierarchy_fexit(void)1449 static void test_tailcall_bpf2bpf_hierarchy_fexit(void)
1450 {
1451 	test_tailcall_hierarchy_count("tailcall_bpf2bpf_hierarchy1.bpf.o",
1452 				      false, true, false);
1453 }
1454 
1455 /* test_tailcall_bpf2bpf_hierarchy_fentry_fexit checks that the count value of
1456  * the tail call limit enforcement matches with expectations when tailcalls are
1457  * preceded with two bpf2bpf calls, and the two subprogs are traced by both
1458  * fentry and fexit.
1459  */
test_tailcall_bpf2bpf_hierarchy_fentry_fexit(void)1460 static void test_tailcall_bpf2bpf_hierarchy_fentry_fexit(void)
1461 {
1462 	test_tailcall_hierarchy_count("tailcall_bpf2bpf_hierarchy1.bpf.o",
1463 				      true, true, false);
1464 }
1465 
1466 /* test_tailcall_bpf2bpf_hierarchy_fentry_entry checks that the count value of
1467  * the tail call limit enforcement matches with expectations when tailcalls are
1468  * preceded with two bpf2bpf calls in fentry.
1469  */
test_tailcall_bpf2bpf_hierarchy_fentry_entry(void)1470 static void test_tailcall_bpf2bpf_hierarchy_fentry_entry(void)
1471 {
1472 	test_tailcall_hierarchy_count("tc_dummy.bpf.o", false, false, true);
1473 }
1474 
1475 /* test_tailcall_bpf2bpf_hierarchy_2 checks that the count value of the tail
1476  * call limit enforcement matches with expectations:
1477  *
1478  *         subprog_tail0 --tailcall-> classifier_0 -> subprog_tail0
1479  * entry <
1480  *         subprog_tail1 --tailcall-> classifier_1 -> subprog_tail1
1481  */
test_tailcall_bpf2bpf_hierarchy_2(void)1482 static void test_tailcall_bpf2bpf_hierarchy_2(void)
1483 {
1484 	RUN_TESTS(tailcall_bpf2bpf_hierarchy2);
1485 }
1486 
1487 /* test_tailcall_bpf2bpf_hierarchy_3 checks that the count value of the tail
1488  * call limit enforcement matches with expectations:
1489  *
1490  *                                   subprog with jmp_table0 to classifier_0
1491  * entry --tailcall-> classifier_0 <
1492  *                                   subprog with jmp_table1 to classifier_0
1493  */
test_tailcall_bpf2bpf_hierarchy_3(void)1494 static void test_tailcall_bpf2bpf_hierarchy_3(void)
1495 {
1496 	RUN_TESTS(tailcall_bpf2bpf_hierarchy3);
1497 }
1498 
1499 /* test_tailcall_freplace checks that the attached freplace prog is OK to
1500  * update the prog_array map.
1501  */
test_tailcall_freplace(void)1502 static void test_tailcall_freplace(void)
1503 {
1504 	struct tailcall_freplace *freplace_skel = NULL;
1505 	struct bpf_link *freplace_link = NULL;
1506 	struct bpf_program *freplace_prog;
1507 	struct tc_bpf2bpf *tc_skel = NULL;
1508 	int prog_fd, map_fd;
1509 	char buff[128] = {};
1510 	int err, key;
1511 
1512 	LIBBPF_OPTS(bpf_test_run_opts, topts,
1513 		    .data_in = buff,
1514 		    .data_size_in = sizeof(buff),
1515 		    .repeat = 1,
1516 	);
1517 
1518 	freplace_skel = tailcall_freplace__open();
1519 	if (!ASSERT_OK_PTR(freplace_skel, "tailcall_freplace__open"))
1520 		return;
1521 
1522 	tc_skel = tc_bpf2bpf__open_and_load();
1523 	if (!ASSERT_OK_PTR(tc_skel, "tc_bpf2bpf__open_and_load"))
1524 		goto out;
1525 
1526 	prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
1527 	freplace_prog = freplace_skel->progs.entry_freplace;
1528 	err = bpf_program__set_attach_target(freplace_prog, prog_fd, "subprog");
1529 	if (!ASSERT_OK(err, "set_attach_target"))
1530 		goto out;
1531 
1532 	err = tailcall_freplace__load(freplace_skel);
1533 	if (!ASSERT_OK(err, "tailcall_freplace__load"))
1534 		goto out;
1535 
1536 	freplace_link = bpf_program__attach_freplace(freplace_prog, prog_fd,
1537 						     "subprog");
1538 	if (!ASSERT_OK_PTR(freplace_link, "attach_freplace"))
1539 		goto out;
1540 
1541 	map_fd = bpf_map__fd(freplace_skel->maps.jmp_table);
1542 	prog_fd = bpf_program__fd(freplace_prog);
1543 	key = 0;
1544 	err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
1545 	if (!ASSERT_OK(err, "update jmp_table"))
1546 		goto out;
1547 
1548 	prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
1549 	err = bpf_prog_test_run_opts(prog_fd, &topts);
1550 	ASSERT_OK(err, "test_run");
1551 	ASSERT_EQ(topts.retval, 34, "test_run retval");
1552 
1553 out:
1554 	bpf_link__destroy(freplace_link);
1555 	tc_bpf2bpf__destroy(tc_skel);
1556 	tailcall_freplace__destroy(freplace_skel);
1557 }
1558 
test_tailcalls(void)1559 void test_tailcalls(void)
1560 {
1561 	if (test__start_subtest("tailcall_1"))
1562 		test_tailcall_1();
1563 	if (test__start_subtest("tailcall_2"))
1564 		test_tailcall_2();
1565 	if (test__start_subtest("tailcall_3"))
1566 		test_tailcall_3();
1567 	if (test__start_subtest("tailcall_4"))
1568 		test_tailcall_4();
1569 	if (test__start_subtest("tailcall_5"))
1570 		test_tailcall_5();
1571 	if (test__start_subtest("tailcall_6"))
1572 		test_tailcall_6();
1573 	if (test__start_subtest("tailcall_bpf2bpf_1"))
1574 		test_tailcall_bpf2bpf_1();
1575 	if (test__start_subtest("tailcall_bpf2bpf_2"))
1576 		test_tailcall_bpf2bpf_2();
1577 	if (test__start_subtest("tailcall_bpf2bpf_3"))
1578 		test_tailcall_bpf2bpf_3();
1579 	if (test__start_subtest("tailcall_bpf2bpf_4"))
1580 		test_tailcall_bpf2bpf_4(false);
1581 	if (test__start_subtest("tailcall_bpf2bpf_5"))
1582 		test_tailcall_bpf2bpf_4(true);
1583 	if (test__start_subtest("tailcall_bpf2bpf_6"))
1584 		test_tailcall_bpf2bpf_6();
1585 	if (test__start_subtest("tailcall_bpf2bpf_fentry"))
1586 		test_tailcall_bpf2bpf_fentry();
1587 	if (test__start_subtest("tailcall_bpf2bpf_fexit"))
1588 		test_tailcall_bpf2bpf_fexit();
1589 	if (test__start_subtest("tailcall_bpf2bpf_fentry_fexit"))
1590 		test_tailcall_bpf2bpf_fentry_fexit();
1591 	if (test__start_subtest("tailcall_bpf2bpf_fentry_entry"))
1592 		test_tailcall_bpf2bpf_fentry_entry();
1593 	if (test__start_subtest("tailcall_poke"))
1594 		test_tailcall_poke();
1595 	if (test__start_subtest("tailcall_bpf2bpf_hierarchy_1"))
1596 		test_tailcall_bpf2bpf_hierarchy_1();
1597 	if (test__start_subtest("tailcall_bpf2bpf_hierarchy_fentry"))
1598 		test_tailcall_bpf2bpf_hierarchy_fentry();
1599 	if (test__start_subtest("tailcall_bpf2bpf_hierarchy_fexit"))
1600 		test_tailcall_bpf2bpf_hierarchy_fexit();
1601 	if (test__start_subtest("tailcall_bpf2bpf_hierarchy_fentry_fexit"))
1602 		test_tailcall_bpf2bpf_hierarchy_fentry_fexit();
1603 	if (test__start_subtest("tailcall_bpf2bpf_hierarchy_fentry_entry"))
1604 		test_tailcall_bpf2bpf_hierarchy_fentry_entry();
1605 	test_tailcall_bpf2bpf_hierarchy_2();
1606 	test_tailcall_bpf2bpf_hierarchy_3();
1607 	if (test__start_subtest("tailcall_freplace"))
1608 		test_tailcall_freplace();
1609 }
1610