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
7
8/* test_tailcall_1 checks basic functionality by patching multiple locations
9 * in a single program for a single tail call slot with nop->jmp, jmp->nop
10 * and jmp->jmp rewrites. Also checks for nop->nop.
11 */
12static void test_tailcall_1(void)
13{
14	int err, map_fd, prog_fd, main_fd, i, j;
15	struct bpf_map *prog_array;
16	struct bpf_program *prog;
17	struct bpf_object *obj;
18	char prog_name[32];
19	char buff[128] = {};
20	LIBBPF_OPTS(bpf_test_run_opts, topts,
21		.data_in = buff,
22		.data_size_in = sizeof(buff),
23		.repeat = 1,
24	);
25
26	err = bpf_prog_test_load("tailcall1.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
27				 &prog_fd);
28	if (CHECK_FAIL(err))
29		return;
30
31	prog = bpf_object__find_program_by_name(obj, "entry");
32	if (CHECK_FAIL(!prog))
33		goto out;
34
35	main_fd = bpf_program__fd(prog);
36	if (CHECK_FAIL(main_fd < 0))
37		goto out;
38
39	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
40	if (CHECK_FAIL(!prog_array))
41		goto out;
42
43	map_fd = bpf_map__fd(prog_array);
44	if (CHECK_FAIL(map_fd < 0))
45		goto out;
46
47	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
48		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
49
50		prog = bpf_object__find_program_by_name(obj, prog_name);
51		if (CHECK_FAIL(!prog))
52			goto out;
53
54		prog_fd = bpf_program__fd(prog);
55		if (CHECK_FAIL(prog_fd < 0))
56			goto out;
57
58		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
59		if (CHECK_FAIL(err))
60			goto out;
61	}
62
63	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
64		err = bpf_prog_test_run_opts(main_fd, &topts);
65		ASSERT_OK(err, "tailcall");
66		ASSERT_EQ(topts.retval, i, "tailcall retval");
67
68		err = bpf_map_delete_elem(map_fd, &i);
69		if (CHECK_FAIL(err))
70			goto out;
71	}
72
73	err = bpf_prog_test_run_opts(main_fd, &topts);
74	ASSERT_OK(err, "tailcall");
75	ASSERT_EQ(topts.retval, 3, "tailcall retval");
76
77	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
78		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
79
80		prog = bpf_object__find_program_by_name(obj, prog_name);
81		if (CHECK_FAIL(!prog))
82			goto out;
83
84		prog_fd = bpf_program__fd(prog);
85		if (CHECK_FAIL(prog_fd < 0))
86			goto out;
87
88		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
89		if (CHECK_FAIL(err))
90			goto out;
91	}
92
93	err = bpf_prog_test_run_opts(main_fd, &topts);
94	ASSERT_OK(err, "tailcall");
95	ASSERT_OK(topts.retval, "tailcall retval");
96
97	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
98		j = bpf_map__max_entries(prog_array) - 1 - i;
99		snprintf(prog_name, sizeof(prog_name), "classifier_%d", j);
100
101		prog = bpf_object__find_program_by_name(obj, prog_name);
102		if (CHECK_FAIL(!prog))
103			goto out;
104
105		prog_fd = bpf_program__fd(prog);
106		if (CHECK_FAIL(prog_fd < 0))
107			goto out;
108
109		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
110		if (CHECK_FAIL(err))
111			goto out;
112	}
113
114	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
115		j = bpf_map__max_entries(prog_array) - 1 - i;
116
117		err = bpf_prog_test_run_opts(main_fd, &topts);
118		ASSERT_OK(err, "tailcall");
119		ASSERT_EQ(topts.retval, j, "tailcall retval");
120
121		err = bpf_map_delete_elem(map_fd, &i);
122		if (CHECK_FAIL(err))
123			goto out;
124	}
125
126	err = bpf_prog_test_run_opts(main_fd, &topts);
127	ASSERT_OK(err, "tailcall");
128	ASSERT_EQ(topts.retval, 3, "tailcall retval");
129
130	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
131		err = bpf_map_delete_elem(map_fd, &i);
132		if (CHECK_FAIL(err >= 0 || errno != ENOENT))
133			goto out;
134
135		err = bpf_prog_test_run_opts(main_fd, &topts);
136		ASSERT_OK(err, "tailcall");
137		ASSERT_EQ(topts.retval, 3, "tailcall retval");
138	}
139
140out:
141	bpf_object__close(obj);
142}
143
144/* test_tailcall_2 checks that patching multiple programs for a single
145 * tail call slot works. It also jumps through several programs and tests
146 * the tail call limit counter.
147 */
148static void test_tailcall_2(void)
149{
150	int err, map_fd, prog_fd, main_fd, i;
151	struct bpf_map *prog_array;
152	struct bpf_program *prog;
153	struct bpf_object *obj;
154	char prog_name[32];
155	char buff[128] = {};
156	LIBBPF_OPTS(bpf_test_run_opts, topts,
157		.data_in = buff,
158		.data_size_in = sizeof(buff),
159		.repeat = 1,
160	);
161
162	err = bpf_prog_test_load("tailcall2.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
163				 &prog_fd);
164	if (CHECK_FAIL(err))
165		return;
166
167	prog = bpf_object__find_program_by_name(obj, "entry");
168	if (CHECK_FAIL(!prog))
169		goto out;
170
171	main_fd = bpf_program__fd(prog);
172	if (CHECK_FAIL(main_fd < 0))
173		goto out;
174
175	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
176	if (CHECK_FAIL(!prog_array))
177		goto out;
178
179	map_fd = bpf_map__fd(prog_array);
180	if (CHECK_FAIL(map_fd < 0))
181		goto out;
182
183	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
184		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
185
186		prog = bpf_object__find_program_by_name(obj, prog_name);
187		if (CHECK_FAIL(!prog))
188			goto out;
189
190		prog_fd = bpf_program__fd(prog);
191		if (CHECK_FAIL(prog_fd < 0))
192			goto out;
193
194		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
195		if (CHECK_FAIL(err))
196			goto out;
197	}
198
199	err = bpf_prog_test_run_opts(main_fd, &topts);
200	ASSERT_OK(err, "tailcall");
201	ASSERT_EQ(topts.retval, 2, "tailcall retval");
202
203	i = 2;
204	err = bpf_map_delete_elem(map_fd, &i);
205	if (CHECK_FAIL(err))
206		goto out;
207
208	err = bpf_prog_test_run_opts(main_fd, &topts);
209	ASSERT_OK(err, "tailcall");
210	ASSERT_EQ(topts.retval, 1, "tailcall retval");
211
212	i = 0;
213	err = bpf_map_delete_elem(map_fd, &i);
214	if (CHECK_FAIL(err))
215		goto out;
216
217	err = bpf_prog_test_run_opts(main_fd, &topts);
218	ASSERT_OK(err, "tailcall");
219	ASSERT_EQ(topts.retval, 3, "tailcall retval");
220out:
221	bpf_object__close(obj);
222}
223
224static void test_tailcall_count(const char *which, bool test_fentry,
225				bool test_fexit)
226{
227	struct bpf_object *obj = NULL, *fentry_obj = NULL, *fexit_obj = NULL;
228	struct bpf_link *fentry_link = NULL, *fexit_link = NULL;
229	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
230	struct bpf_map *prog_array, *data_map;
231	struct bpf_program *prog;
232	char buff[128] = {};
233	LIBBPF_OPTS(bpf_test_run_opts, topts,
234		.data_in = buff,
235		.data_size_in = sizeof(buff),
236		.repeat = 1,
237	);
238
239	err = bpf_prog_test_load(which, BPF_PROG_TYPE_SCHED_CLS, &obj,
240			    &prog_fd);
241	if (CHECK_FAIL(err))
242		return;
243
244	prog = bpf_object__find_program_by_name(obj, "entry");
245	if (CHECK_FAIL(!prog))
246		goto out;
247
248	main_fd = bpf_program__fd(prog);
249	if (CHECK_FAIL(main_fd < 0))
250		goto out;
251
252	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
253	if (CHECK_FAIL(!prog_array))
254		goto out;
255
256	map_fd = bpf_map__fd(prog_array);
257	if (CHECK_FAIL(map_fd < 0))
258		goto out;
259
260	prog = bpf_object__find_program_by_name(obj, "classifier_0");
261	if (CHECK_FAIL(!prog))
262		goto out;
263
264	prog_fd = bpf_program__fd(prog);
265	if (CHECK_FAIL(prog_fd < 0))
266		goto out;
267
268	i = 0;
269	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
270	if (CHECK_FAIL(err))
271		goto out;
272
273	if (test_fentry) {
274		fentry_obj = bpf_object__open_file("tailcall_bpf2bpf_fentry.bpf.o",
275						   NULL);
276		if (!ASSERT_OK_PTR(fentry_obj, "open fentry_obj file"))
277			goto out;
278
279		prog = bpf_object__find_program_by_name(fentry_obj, "fentry");
280		if (!ASSERT_OK_PTR(prog, "find fentry prog"))
281			goto out;
282
283		err = bpf_program__set_attach_target(prog, prog_fd,
284						     "subprog_tail");
285		if (!ASSERT_OK(err, "set_attach_target subprog_tail"))
286			goto out;
287
288		err = bpf_object__load(fentry_obj);
289		if (!ASSERT_OK(err, "load fentry_obj"))
290			goto out;
291
292		fentry_link = bpf_program__attach_trace(prog);
293		if (!ASSERT_OK_PTR(fentry_link, "attach_trace"))
294			goto out;
295	}
296
297	if (test_fexit) {
298		fexit_obj = bpf_object__open_file("tailcall_bpf2bpf_fexit.bpf.o",
299						  NULL);
300		if (!ASSERT_OK_PTR(fexit_obj, "open fexit_obj file"))
301			goto out;
302
303		prog = bpf_object__find_program_by_name(fexit_obj, "fexit");
304		if (!ASSERT_OK_PTR(prog, "find fexit prog"))
305			goto out;
306
307		err = bpf_program__set_attach_target(prog, prog_fd,
308						     "subprog_tail");
309		if (!ASSERT_OK(err, "set_attach_target subprog_tail"))
310			goto out;
311
312		err = bpf_object__load(fexit_obj);
313		if (!ASSERT_OK(err, "load fexit_obj"))
314			goto out;
315
316		fexit_link = bpf_program__attach_trace(prog);
317		if (!ASSERT_OK_PTR(fexit_link, "attach_trace"))
318			goto out;
319	}
320
321	err = bpf_prog_test_run_opts(main_fd, &topts);
322	ASSERT_OK(err, "tailcall");
323	ASSERT_EQ(topts.retval, 1, "tailcall retval");
324
325	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
326	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
327		goto out;
328
329	data_fd = bpf_map__fd(data_map);
330	if (CHECK_FAIL(data_fd < 0))
331		goto out;
332
333	i = 0;
334	err = bpf_map_lookup_elem(data_fd, &i, &val);
335	ASSERT_OK(err, "tailcall count");
336	ASSERT_EQ(val, 33, "tailcall count");
337
338	if (test_fentry) {
339		data_map = bpf_object__find_map_by_name(fentry_obj, ".bss");
340		if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
341				  "find tailcall_bpf2bpf_fentry.bss map"))
342			goto out;
343
344		data_fd = bpf_map__fd(data_map);
345		if (!ASSERT_FALSE(data_fd < 0,
346				  "find tailcall_bpf2bpf_fentry.bss map fd"))
347			goto out;
348
349		i = 0;
350		err = bpf_map_lookup_elem(data_fd, &i, &val);
351		ASSERT_OK(err, "fentry count");
352		ASSERT_EQ(val, 33, "fentry count");
353	}
354
355	if (test_fexit) {
356		data_map = bpf_object__find_map_by_name(fexit_obj, ".bss");
357		if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
358				  "find tailcall_bpf2bpf_fexit.bss map"))
359			goto out;
360
361		data_fd = bpf_map__fd(data_map);
362		if (!ASSERT_FALSE(data_fd < 0,
363				  "find tailcall_bpf2bpf_fexit.bss map fd"))
364			goto out;
365
366		i = 0;
367		err = bpf_map_lookup_elem(data_fd, &i, &val);
368		ASSERT_OK(err, "fexit count");
369		ASSERT_EQ(val, 33, "fexit count");
370	}
371
372	i = 0;
373	err = bpf_map_delete_elem(map_fd, &i);
374	if (CHECK_FAIL(err))
375		goto out;
376
377	err = bpf_prog_test_run_opts(main_fd, &topts);
378	ASSERT_OK(err, "tailcall");
379	ASSERT_OK(topts.retval, "tailcall retval");
380out:
381	bpf_link__destroy(fentry_link);
382	bpf_link__destroy(fexit_link);
383	bpf_object__close(fentry_obj);
384	bpf_object__close(fexit_obj);
385	bpf_object__close(obj);
386}
387
388/* test_tailcall_3 checks that the count value of the tail call limit
389 * enforcement matches with expectations. JIT uses direct jump.
390 */
391static void test_tailcall_3(void)
392{
393	test_tailcall_count("tailcall3.bpf.o", false, false);
394}
395
396/* test_tailcall_6 checks that the count value of the tail call limit
397 * enforcement matches with expectations. JIT uses indirect jump.
398 */
399static void test_tailcall_6(void)
400{
401	test_tailcall_count("tailcall6.bpf.o", false, false);
402}
403
404/* test_tailcall_4 checks that the kernel properly selects indirect jump
405 * for the case where the key is not known. Latter is passed via global
406 * data to select different targets we can compare return value of.
407 */
408static void test_tailcall_4(void)
409{
410	int err, map_fd, prog_fd, main_fd, data_fd, i;
411	struct bpf_map *prog_array, *data_map;
412	struct bpf_program *prog;
413	struct bpf_object *obj;
414	static const int zero = 0;
415	char buff[128] = {};
416	char prog_name[32];
417	LIBBPF_OPTS(bpf_test_run_opts, topts,
418		.data_in = buff,
419		.data_size_in = sizeof(buff),
420		.repeat = 1,
421	);
422
423	err = bpf_prog_test_load("tailcall4.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
424				 &prog_fd);
425	if (CHECK_FAIL(err))
426		return;
427
428	prog = bpf_object__find_program_by_name(obj, "entry");
429	if (CHECK_FAIL(!prog))
430		goto out;
431
432	main_fd = bpf_program__fd(prog);
433	if (CHECK_FAIL(main_fd < 0))
434		goto out;
435
436	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
437	if (CHECK_FAIL(!prog_array))
438		goto out;
439
440	map_fd = bpf_map__fd(prog_array);
441	if (CHECK_FAIL(map_fd < 0))
442		goto out;
443
444	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
445	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
446		goto out;
447
448	data_fd = bpf_map__fd(data_map);
449	if (CHECK_FAIL(data_fd < 0))
450		goto out;
451
452	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
453		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
454
455		prog = bpf_object__find_program_by_name(obj, prog_name);
456		if (CHECK_FAIL(!prog))
457			goto out;
458
459		prog_fd = bpf_program__fd(prog);
460		if (CHECK_FAIL(prog_fd < 0))
461			goto out;
462
463		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
464		if (CHECK_FAIL(err))
465			goto out;
466	}
467
468	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
469		err = bpf_map_update_elem(data_fd, &zero, &i, BPF_ANY);
470		if (CHECK_FAIL(err))
471			goto out;
472
473		err = bpf_prog_test_run_opts(main_fd, &topts);
474		ASSERT_OK(err, "tailcall");
475		ASSERT_EQ(topts.retval, i, "tailcall retval");
476	}
477
478	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
479		err = bpf_map_update_elem(data_fd, &zero, &i, BPF_ANY);
480		if (CHECK_FAIL(err))
481			goto out;
482
483		err = bpf_map_delete_elem(map_fd, &i);
484		if (CHECK_FAIL(err))
485			goto out;
486
487		err = bpf_prog_test_run_opts(main_fd, &topts);
488		ASSERT_OK(err, "tailcall");
489		ASSERT_EQ(topts.retval, 3, "tailcall retval");
490	}
491out:
492	bpf_object__close(obj);
493}
494
495/* test_tailcall_5 probes similarly to test_tailcall_4 that the kernel generates
496 * an indirect jump when the keys are const but different from different branches.
497 */
498static void test_tailcall_5(void)
499{
500	int err, map_fd, prog_fd, main_fd, data_fd, i, key[] = { 1111, 1234, 5678 };
501	struct bpf_map *prog_array, *data_map;
502	struct bpf_program *prog;
503	struct bpf_object *obj;
504	static const int zero = 0;
505	char buff[128] = {};
506	char prog_name[32];
507	LIBBPF_OPTS(bpf_test_run_opts, topts,
508		.data_in = buff,
509		.data_size_in = sizeof(buff),
510		.repeat = 1,
511	);
512
513	err = bpf_prog_test_load("tailcall5.bpf.o", BPF_PROG_TYPE_SCHED_CLS, &obj,
514				 &prog_fd);
515	if (CHECK_FAIL(err))
516		return;
517
518	prog = bpf_object__find_program_by_name(obj, "entry");
519	if (CHECK_FAIL(!prog))
520		goto out;
521
522	main_fd = bpf_program__fd(prog);
523	if (CHECK_FAIL(main_fd < 0))
524		goto out;
525
526	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
527	if (CHECK_FAIL(!prog_array))
528		goto out;
529
530	map_fd = bpf_map__fd(prog_array);
531	if (CHECK_FAIL(map_fd < 0))
532		goto out;
533
534	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
535	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
536		goto out;
537
538	data_fd = bpf_map__fd(data_map);
539	if (CHECK_FAIL(data_fd < 0))
540		goto out;
541
542	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
543		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
544
545		prog = bpf_object__find_program_by_name(obj, prog_name);
546		if (CHECK_FAIL(!prog))
547			goto out;
548
549		prog_fd = bpf_program__fd(prog);
550		if (CHECK_FAIL(prog_fd < 0))
551			goto out;
552
553		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
554		if (CHECK_FAIL(err))
555			goto out;
556	}
557
558	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
559		err = bpf_map_update_elem(data_fd, &zero, &key[i], BPF_ANY);
560		if (CHECK_FAIL(err))
561			goto out;
562
563		err = bpf_prog_test_run_opts(main_fd, &topts);
564		ASSERT_OK(err, "tailcall");
565		ASSERT_EQ(topts.retval, i, "tailcall retval");
566	}
567
568	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
569		err = bpf_map_update_elem(data_fd, &zero, &key[i], BPF_ANY);
570		if (CHECK_FAIL(err))
571			goto out;
572
573		err = bpf_map_delete_elem(map_fd, &i);
574		if (CHECK_FAIL(err))
575			goto out;
576
577		err = bpf_prog_test_run_opts(main_fd, &topts);
578		ASSERT_OK(err, "tailcall");
579		ASSERT_EQ(topts.retval, 3, "tailcall retval");
580	}
581out:
582	bpf_object__close(obj);
583}
584
585/* test_tailcall_bpf2bpf_1 purpose is to make sure that tailcalls are working
586 * correctly in correlation with BPF subprograms
587 */
588static void test_tailcall_bpf2bpf_1(void)
589{
590	int err, map_fd, prog_fd, main_fd, i;
591	struct bpf_map *prog_array;
592	struct bpf_program *prog;
593	struct bpf_object *obj;
594	char prog_name[32];
595	LIBBPF_OPTS(bpf_test_run_opts, topts,
596		.data_in = &pkt_v4,
597		.data_size_in = sizeof(pkt_v4),
598		.repeat = 1,
599	);
600
601	err = bpf_prog_test_load("tailcall_bpf2bpf1.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
602				 &obj, &prog_fd);
603	if (CHECK_FAIL(err))
604		return;
605
606	prog = bpf_object__find_program_by_name(obj, "entry");
607	if (CHECK_FAIL(!prog))
608		goto out;
609
610	main_fd = bpf_program__fd(prog);
611	if (CHECK_FAIL(main_fd < 0))
612		goto out;
613
614	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
615	if (CHECK_FAIL(!prog_array))
616		goto out;
617
618	map_fd = bpf_map__fd(prog_array);
619	if (CHECK_FAIL(map_fd < 0))
620		goto out;
621
622	/* nop -> jmp */
623	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
624		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
625
626		prog = bpf_object__find_program_by_name(obj, prog_name);
627		if (CHECK_FAIL(!prog))
628			goto out;
629
630		prog_fd = bpf_program__fd(prog);
631		if (CHECK_FAIL(prog_fd < 0))
632			goto out;
633
634		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
635		if (CHECK_FAIL(err))
636			goto out;
637	}
638
639	err = bpf_prog_test_run_opts(main_fd, &topts);
640	ASSERT_OK(err, "tailcall");
641	ASSERT_EQ(topts.retval, 1, "tailcall retval");
642
643	/* jmp -> nop, call subprog that will do tailcall */
644	i = 1;
645	err = bpf_map_delete_elem(map_fd, &i);
646	if (CHECK_FAIL(err))
647		goto out;
648
649	err = bpf_prog_test_run_opts(main_fd, &topts);
650	ASSERT_OK(err, "tailcall");
651	ASSERT_OK(topts.retval, "tailcall retval");
652
653	/* make sure that subprog can access ctx and entry prog that
654	 * called this subprog can properly return
655	 */
656	i = 0;
657	err = bpf_map_delete_elem(map_fd, &i);
658	if (CHECK_FAIL(err))
659		goto out;
660
661	err = bpf_prog_test_run_opts(main_fd, &topts);
662	ASSERT_OK(err, "tailcall");
663	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 2, "tailcall retval");
664out:
665	bpf_object__close(obj);
666}
667
668/* test_tailcall_bpf2bpf_2 checks that the count value of the tail call limit
669 * enforcement matches with expectations when tailcall is preceded with
670 * bpf2bpf call.
671 */
672static void test_tailcall_bpf2bpf_2(void)
673{
674	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
675	struct bpf_map *prog_array, *data_map;
676	struct bpf_program *prog;
677	struct bpf_object *obj;
678	char buff[128] = {};
679	LIBBPF_OPTS(bpf_test_run_opts, topts,
680		.data_in = buff,
681		.data_size_in = sizeof(buff),
682		.repeat = 1,
683	);
684
685	err = bpf_prog_test_load("tailcall_bpf2bpf2.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
686				 &obj, &prog_fd);
687	if (CHECK_FAIL(err))
688		return;
689
690	prog = bpf_object__find_program_by_name(obj, "entry");
691	if (CHECK_FAIL(!prog))
692		goto out;
693
694	main_fd = bpf_program__fd(prog);
695	if (CHECK_FAIL(main_fd < 0))
696		goto out;
697
698	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
699	if (CHECK_FAIL(!prog_array))
700		goto out;
701
702	map_fd = bpf_map__fd(prog_array);
703	if (CHECK_FAIL(map_fd < 0))
704		goto out;
705
706	prog = bpf_object__find_program_by_name(obj, "classifier_0");
707	if (CHECK_FAIL(!prog))
708		goto out;
709
710	prog_fd = bpf_program__fd(prog);
711	if (CHECK_FAIL(prog_fd < 0))
712		goto out;
713
714	i = 0;
715	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
716	if (CHECK_FAIL(err))
717		goto out;
718
719	err = bpf_prog_test_run_opts(main_fd, &topts);
720	ASSERT_OK(err, "tailcall");
721	ASSERT_EQ(topts.retval, 1, "tailcall retval");
722
723	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
724	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
725		goto out;
726
727	data_fd = bpf_map__fd(data_map);
728	if (CHECK_FAIL(data_fd < 0))
729		goto out;
730
731	i = 0;
732	err = bpf_map_lookup_elem(data_fd, &i, &val);
733	ASSERT_OK(err, "tailcall count");
734	ASSERT_EQ(val, 33, "tailcall count");
735
736	i = 0;
737	err = bpf_map_delete_elem(map_fd, &i);
738	if (CHECK_FAIL(err))
739		goto out;
740
741	err = bpf_prog_test_run_opts(main_fd, &topts);
742	ASSERT_OK(err, "tailcall");
743	ASSERT_OK(topts.retval, "tailcall retval");
744out:
745	bpf_object__close(obj);
746}
747
748/* test_tailcall_bpf2bpf_3 checks that non-trivial amount of stack (up to
749 * 256 bytes) can be used within bpf subprograms that have the tailcalls
750 * in them
751 */
752static void test_tailcall_bpf2bpf_3(void)
753{
754	int err, map_fd, prog_fd, main_fd, i;
755	struct bpf_map *prog_array;
756	struct bpf_program *prog;
757	struct bpf_object *obj;
758	char prog_name[32];
759	LIBBPF_OPTS(bpf_test_run_opts, topts,
760		.data_in = &pkt_v4,
761		.data_size_in = sizeof(pkt_v4),
762		.repeat = 1,
763	);
764
765	err = bpf_prog_test_load("tailcall_bpf2bpf3.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
766				 &obj, &prog_fd);
767	if (CHECK_FAIL(err))
768		return;
769
770	prog = bpf_object__find_program_by_name(obj, "entry");
771	if (CHECK_FAIL(!prog))
772		goto out;
773
774	main_fd = bpf_program__fd(prog);
775	if (CHECK_FAIL(main_fd < 0))
776		goto out;
777
778	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
779	if (CHECK_FAIL(!prog_array))
780		goto out;
781
782	map_fd = bpf_map__fd(prog_array);
783	if (CHECK_FAIL(map_fd < 0))
784		goto out;
785
786	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
787		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
788
789		prog = bpf_object__find_program_by_name(obj, prog_name);
790		if (CHECK_FAIL(!prog))
791			goto out;
792
793		prog_fd = bpf_program__fd(prog);
794		if (CHECK_FAIL(prog_fd < 0))
795			goto out;
796
797		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
798		if (CHECK_FAIL(err))
799			goto out;
800	}
801
802	err = bpf_prog_test_run_opts(main_fd, &topts);
803	ASSERT_OK(err, "tailcall");
804	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 3, "tailcall retval");
805
806	i = 1;
807	err = bpf_map_delete_elem(map_fd, &i);
808	if (CHECK_FAIL(err))
809		goto out;
810
811	err = bpf_prog_test_run_opts(main_fd, &topts);
812	ASSERT_OK(err, "tailcall");
813	ASSERT_EQ(topts.retval, sizeof(pkt_v4), "tailcall retval");
814
815	i = 0;
816	err = bpf_map_delete_elem(map_fd, &i);
817	if (CHECK_FAIL(err))
818		goto out;
819
820	err = bpf_prog_test_run_opts(main_fd, &topts);
821	ASSERT_OK(err, "tailcall");
822	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 2, "tailcall retval");
823out:
824	bpf_object__close(obj);
825}
826
827#include "tailcall_bpf2bpf4.skel.h"
828
829/* test_tailcall_bpf2bpf_4 checks that tailcall counter is correctly preserved
830 * across tailcalls combined with bpf2bpf calls. for making sure that tailcall
831 * counter behaves correctly, bpf program will go through following flow:
832 *
833 * entry -> entry_subprog -> tailcall0 -> bpf_func0 -> subprog0 ->
834 * -> tailcall1 -> bpf_func1 -> subprog1 -> tailcall2 -> bpf_func2 ->
835 * subprog2 [here bump global counter] --------^
836 *
837 * We go through first two tailcalls and start counting from the subprog2 where
838 * the loop begins. At the end of the test make sure that the global counter is
839 * equal to 31, because tailcall counter includes the first two tailcalls
840 * whereas global counter is incremented only on loop presented on flow above.
841 *
842 * The noise parameter is used to insert bpf_map_update calls into the logic
843 * to force verifier to patch instructions. This allows us to ensure jump
844 * logic remains correct with instruction movement.
845 */
846static void test_tailcall_bpf2bpf_4(bool noise)
847{
848	int err, map_fd, prog_fd, main_fd, data_fd, i;
849	struct tailcall_bpf2bpf4__bss val;
850	struct bpf_map *prog_array, *data_map;
851	struct bpf_program *prog;
852	struct bpf_object *obj;
853	char prog_name[32];
854	LIBBPF_OPTS(bpf_test_run_opts, topts,
855		.data_in = &pkt_v4,
856		.data_size_in = sizeof(pkt_v4),
857		.repeat = 1,
858	);
859
860	err = bpf_prog_test_load("tailcall_bpf2bpf4.bpf.o", BPF_PROG_TYPE_SCHED_CLS,
861				 &obj, &prog_fd);
862	if (CHECK_FAIL(err))
863		return;
864
865	prog = bpf_object__find_program_by_name(obj, "entry");
866	if (CHECK_FAIL(!prog))
867		goto out;
868
869	main_fd = bpf_program__fd(prog);
870	if (CHECK_FAIL(main_fd < 0))
871		goto out;
872
873	prog_array = bpf_object__find_map_by_name(obj, "jmp_table");
874	if (CHECK_FAIL(!prog_array))
875		goto out;
876
877	map_fd = bpf_map__fd(prog_array);
878	if (CHECK_FAIL(map_fd < 0))
879		goto out;
880
881	for (i = 0; i < bpf_map__max_entries(prog_array); i++) {
882		snprintf(prog_name, sizeof(prog_name), "classifier_%d", i);
883
884		prog = bpf_object__find_program_by_name(obj, prog_name);
885		if (CHECK_FAIL(!prog))
886			goto out;
887
888		prog_fd = bpf_program__fd(prog);
889		if (CHECK_FAIL(prog_fd < 0))
890			goto out;
891
892		err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
893		if (CHECK_FAIL(err))
894			goto out;
895	}
896
897	data_map = bpf_object__find_map_by_name(obj, "tailcall.bss");
898	if (CHECK_FAIL(!data_map || !bpf_map__is_internal(data_map)))
899		goto out;
900
901	data_fd = bpf_map__fd(data_map);
902	if (CHECK_FAIL(data_fd < 0))
903		goto out;
904
905	i = 0;
906	val.noise = noise;
907	val.count = 0;
908	err = bpf_map_update_elem(data_fd, &i, &val, BPF_ANY);
909	if (CHECK_FAIL(err))
910		goto out;
911
912	err = bpf_prog_test_run_opts(main_fd, &topts);
913	ASSERT_OK(err, "tailcall");
914	ASSERT_EQ(topts.retval, sizeof(pkt_v4) * 3, "tailcall retval");
915
916	i = 0;
917	err = bpf_map_lookup_elem(data_fd, &i, &val);
918	ASSERT_OK(err, "tailcall count");
919	ASSERT_EQ(val.count, 31, "tailcall count");
920
921out:
922	bpf_object__close(obj);
923}
924
925#include "tailcall_bpf2bpf6.skel.h"
926
927/* Tail call counting works even when there is data on stack which is
928 * not aligned to 8 bytes.
929 */
930static void test_tailcall_bpf2bpf_6(void)
931{
932	struct tailcall_bpf2bpf6 *obj;
933	int err, map_fd, prog_fd, main_fd, data_fd, i, val;
934	LIBBPF_OPTS(bpf_test_run_opts, topts,
935		.data_in = &pkt_v4,
936		.data_size_in = sizeof(pkt_v4),
937		.repeat = 1,
938	);
939
940	obj = tailcall_bpf2bpf6__open_and_load();
941	if (!ASSERT_OK_PTR(obj, "open and load"))
942		return;
943
944	main_fd = bpf_program__fd(obj->progs.entry);
945	if (!ASSERT_GE(main_fd, 0, "entry prog fd"))
946		goto out;
947
948	map_fd = bpf_map__fd(obj->maps.jmp_table);
949	if (!ASSERT_GE(map_fd, 0, "jmp_table map fd"))
950		goto out;
951
952	prog_fd = bpf_program__fd(obj->progs.classifier_0);
953	if (!ASSERT_GE(prog_fd, 0, "classifier_0 prog fd"))
954		goto out;
955
956	i = 0;
957	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
958	if (!ASSERT_OK(err, "jmp_table map update"))
959		goto out;
960
961	err = bpf_prog_test_run_opts(main_fd, &topts);
962	ASSERT_OK(err, "entry prog test run");
963	ASSERT_EQ(topts.retval, 0, "tailcall retval");
964
965	data_fd = bpf_map__fd(obj->maps.bss);
966	if (!ASSERT_GE(data_fd, 0, "bss map fd"))
967		goto out;
968
969	i = 0;
970	err = bpf_map_lookup_elem(data_fd, &i, &val);
971	ASSERT_OK(err, "bss map lookup");
972	ASSERT_EQ(val, 1, "done flag is set");
973
974out:
975	tailcall_bpf2bpf6__destroy(obj);
976}
977
978/* test_tailcall_bpf2bpf_fentry checks that the count value of the tail call
979 * limit enforcement matches with expectations when tailcall is preceded with
980 * bpf2bpf call, and the bpf2bpf call is traced by fentry.
981 */
982static void test_tailcall_bpf2bpf_fentry(void)
983{
984	test_tailcall_count("tailcall_bpf2bpf2.bpf.o", true, false);
985}
986
987/* test_tailcall_bpf2bpf_fexit checks that the count value of the tail call
988 * limit enforcement matches with expectations when tailcall is preceded with
989 * bpf2bpf call, and the bpf2bpf call is traced by fexit.
990 */
991static void test_tailcall_bpf2bpf_fexit(void)
992{
993	test_tailcall_count("tailcall_bpf2bpf2.bpf.o", false, true);
994}
995
996/* test_tailcall_bpf2bpf_fentry_fexit checks that the count value of the tail
997 * call limit enforcement matches with expectations when tailcall is preceded
998 * with bpf2bpf call, and the bpf2bpf call is traced by both fentry and fexit.
999 */
1000static void test_tailcall_bpf2bpf_fentry_fexit(void)
1001{
1002	test_tailcall_count("tailcall_bpf2bpf2.bpf.o", true, true);
1003}
1004
1005/* test_tailcall_bpf2bpf_fentry_entry checks that the count value of the tail
1006 * call limit enforcement matches with expectations when tailcall is preceded
1007 * with bpf2bpf call, and the bpf2bpf caller is traced by fentry.
1008 */
1009static void test_tailcall_bpf2bpf_fentry_entry(void)
1010{
1011	struct bpf_object *tgt_obj = NULL, *fentry_obj = NULL;
1012	int err, map_fd, prog_fd, data_fd, i, val;
1013	struct bpf_map *prog_array, *data_map;
1014	struct bpf_link *fentry_link = NULL;
1015	struct bpf_program *prog;
1016	char buff[128] = {};
1017
1018	LIBBPF_OPTS(bpf_test_run_opts, topts,
1019		.data_in = buff,
1020		.data_size_in = sizeof(buff),
1021		.repeat = 1,
1022	);
1023
1024	err = bpf_prog_test_load("tailcall_bpf2bpf2.bpf.o",
1025				 BPF_PROG_TYPE_SCHED_CLS,
1026				 &tgt_obj, &prog_fd);
1027	if (!ASSERT_OK(err, "load tgt_obj"))
1028		return;
1029
1030	prog_array = bpf_object__find_map_by_name(tgt_obj, "jmp_table");
1031	if (!ASSERT_OK_PTR(prog_array, "find jmp_table map"))
1032		goto out;
1033
1034	map_fd = bpf_map__fd(prog_array);
1035	if (!ASSERT_FALSE(map_fd < 0, "find jmp_table map fd"))
1036		goto out;
1037
1038	prog = bpf_object__find_program_by_name(tgt_obj, "classifier_0");
1039	if (!ASSERT_OK_PTR(prog, "find classifier_0 prog"))
1040		goto out;
1041
1042	prog_fd = bpf_program__fd(prog);
1043	if (!ASSERT_FALSE(prog_fd < 0, "find classifier_0 prog fd"))
1044		goto out;
1045
1046	i = 0;
1047	err = bpf_map_update_elem(map_fd, &i, &prog_fd, BPF_ANY);
1048	if (!ASSERT_OK(err, "update jmp_table"))
1049		goto out;
1050
1051	fentry_obj = bpf_object__open_file("tailcall_bpf2bpf_fentry.bpf.o",
1052					   NULL);
1053	if (!ASSERT_OK_PTR(fentry_obj, "open fentry_obj file"))
1054		goto out;
1055
1056	prog = bpf_object__find_program_by_name(fentry_obj, "fentry");
1057	if (!ASSERT_OK_PTR(prog, "find fentry prog"))
1058		goto out;
1059
1060	err = bpf_program__set_attach_target(prog, prog_fd, "classifier_0");
1061	if (!ASSERT_OK(err, "set_attach_target classifier_0"))
1062		goto out;
1063
1064	err = bpf_object__load(fentry_obj);
1065	if (!ASSERT_OK(err, "load fentry_obj"))
1066		goto out;
1067
1068	fentry_link = bpf_program__attach_trace(prog);
1069	if (!ASSERT_OK_PTR(fentry_link, "attach_trace"))
1070		goto out;
1071
1072	err = bpf_prog_test_run_opts(prog_fd, &topts);
1073	ASSERT_OK(err, "tailcall");
1074	ASSERT_EQ(topts.retval, 1, "tailcall retval");
1075
1076	data_map = bpf_object__find_map_by_name(tgt_obj, "tailcall.bss");
1077	if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
1078			  "find tailcall.bss map"))
1079		goto out;
1080
1081	data_fd = bpf_map__fd(data_map);
1082	if (!ASSERT_FALSE(data_fd < 0, "find tailcall.bss map fd"))
1083		goto out;
1084
1085	i = 0;
1086	err = bpf_map_lookup_elem(data_fd, &i, &val);
1087	ASSERT_OK(err, "tailcall count");
1088	ASSERT_EQ(val, 34, "tailcall count");
1089
1090	data_map = bpf_object__find_map_by_name(fentry_obj, ".bss");
1091	if (!ASSERT_FALSE(!data_map || !bpf_map__is_internal(data_map),
1092			  "find tailcall_bpf2bpf_fentry.bss map"))
1093		goto out;
1094
1095	data_fd = bpf_map__fd(data_map);
1096	if (!ASSERT_FALSE(data_fd < 0,
1097			  "find tailcall_bpf2bpf_fentry.bss map fd"))
1098		goto out;
1099
1100	i = 0;
1101	err = bpf_map_lookup_elem(data_fd, &i, &val);
1102	ASSERT_OK(err, "fentry count");
1103	ASSERT_EQ(val, 1, "fentry count");
1104
1105out:
1106	bpf_link__destroy(fentry_link);
1107	bpf_object__close(fentry_obj);
1108	bpf_object__close(tgt_obj);
1109}
1110
1111#define JMP_TABLE "/sys/fs/bpf/jmp_table"
1112
1113static int poke_thread_exit;
1114
1115static void *poke_update(void *arg)
1116{
1117	__u32 zero = 0, prog1_fd, prog2_fd, map_fd;
1118	struct tailcall_poke *call = arg;
1119
1120	map_fd = bpf_map__fd(call->maps.jmp_table);
1121	prog1_fd = bpf_program__fd(call->progs.call1);
1122	prog2_fd = bpf_program__fd(call->progs.call2);
1123
1124	while (!poke_thread_exit) {
1125		bpf_map_update_elem(map_fd, &zero, &prog1_fd, BPF_ANY);
1126		bpf_map_update_elem(map_fd, &zero, &prog2_fd, BPF_ANY);
1127	}
1128
1129	return NULL;
1130}
1131
1132/*
1133 * We are trying to hit prog array update during another program load
1134 * that shares the same prog array map.
1135 *
1136 * For that we share the jmp_table map between two skeleton instances
1137 * by pinning the jmp_table to same path. Then first skeleton instance
1138 * periodically updates jmp_table in 'poke update' thread while we load
1139 * the second skeleton instance in the main thread.
1140 */
1141static void test_tailcall_poke(void)
1142{
1143	struct tailcall_poke *call, *test;
1144	int err, cnt = 10;
1145	pthread_t thread;
1146
1147	unlink(JMP_TABLE);
1148
1149	call = tailcall_poke__open_and_load();
1150	if (!ASSERT_OK_PTR(call, "tailcall_poke__open"))
1151		return;
1152
1153	err = bpf_map__pin(call->maps.jmp_table, JMP_TABLE);
1154	if (!ASSERT_OK(err, "bpf_map__pin"))
1155		goto out;
1156
1157	err = pthread_create(&thread, NULL, poke_update, call);
1158	if (!ASSERT_OK(err, "new toggler"))
1159		goto out;
1160
1161	while (cnt--) {
1162		test = tailcall_poke__open();
1163		if (!ASSERT_OK_PTR(test, "tailcall_poke__open"))
1164			break;
1165
1166		err = bpf_map__set_pin_path(test->maps.jmp_table, JMP_TABLE);
1167		if (!ASSERT_OK(err, "bpf_map__pin")) {
1168			tailcall_poke__destroy(test);
1169			break;
1170		}
1171
1172		bpf_program__set_autoload(test->progs.test, true);
1173		bpf_program__set_autoload(test->progs.call1, false);
1174		bpf_program__set_autoload(test->progs.call2, false);
1175
1176		err = tailcall_poke__load(test);
1177		tailcall_poke__destroy(test);
1178		if (!ASSERT_OK(err, "tailcall_poke__load"))
1179			break;
1180	}
1181
1182	poke_thread_exit = 1;
1183	ASSERT_OK(pthread_join(thread, NULL), "pthread_join");
1184
1185out:
1186	bpf_map__unpin(call->maps.jmp_table, JMP_TABLE);
1187	tailcall_poke__destroy(call);
1188}
1189
1190void test_tailcalls(void)
1191{
1192	if (test__start_subtest("tailcall_1"))
1193		test_tailcall_1();
1194	if (test__start_subtest("tailcall_2"))
1195		test_tailcall_2();
1196	if (test__start_subtest("tailcall_3"))
1197		test_tailcall_3();
1198	if (test__start_subtest("tailcall_4"))
1199		test_tailcall_4();
1200	if (test__start_subtest("tailcall_5"))
1201		test_tailcall_5();
1202	if (test__start_subtest("tailcall_6"))
1203		test_tailcall_6();
1204	if (test__start_subtest("tailcall_bpf2bpf_1"))
1205		test_tailcall_bpf2bpf_1();
1206	if (test__start_subtest("tailcall_bpf2bpf_2"))
1207		test_tailcall_bpf2bpf_2();
1208	if (test__start_subtest("tailcall_bpf2bpf_3"))
1209		test_tailcall_bpf2bpf_3();
1210	if (test__start_subtest("tailcall_bpf2bpf_4"))
1211		test_tailcall_bpf2bpf_4(false);
1212	if (test__start_subtest("tailcall_bpf2bpf_5"))
1213		test_tailcall_bpf2bpf_4(true);
1214	if (test__start_subtest("tailcall_bpf2bpf_6"))
1215		test_tailcall_bpf2bpf_6();
1216	if (test__start_subtest("tailcall_bpf2bpf_fentry"))
1217		test_tailcall_bpf2bpf_fentry();
1218	if (test__start_subtest("tailcall_bpf2bpf_fexit"))
1219		test_tailcall_bpf2bpf_fexit();
1220	if (test__start_subtest("tailcall_bpf2bpf_fentry_fexit"))
1221		test_tailcall_bpf2bpf_fentry_fexit();
1222	if (test__start_subtest("tailcall_bpf2bpf_fentry_entry"))
1223		test_tailcall_bpf2bpf_fentry_entry();
1224	if (test__start_subtest("tailcall_poke"))
1225		test_tailcall_poke();
1226}
1227