xref: /linux/tools/testing/selftests/bpf/progs/tailcall_callback.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bpf.h>
3 #include <bpf/bpf_helpers.h>
4 #include "bpf_misc.h"
5 #include "bpf_test_utils.h"
6 
7 int classifier_0(struct __sk_buff *skb);
8 
9 struct {
10 	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
11 	__uint(max_entries, 1);
12 	__uint(key_size, sizeof(__u32));
13 	__array(values, void (void));
14 } jmp_table SEC(".maps") = {
15 	.values = {
16 		[0] = (void *) &classifier_0,
17 	},
18 };
19 
20 __auxiliary
21 SEC("tc")
classifier_0(struct __sk_buff * skb)22 int classifier_0(struct __sk_buff *skb)
23 {
24 	return 0;
25 }
26 
27 static __noinline
subprog_tail0(struct __sk_buff * skb)28 int subprog_tail0(struct __sk_buff *skb)
29 {
30 	int ret = 0;
31 
32 	bpf_tail_call_static(skb, &jmp_table, 0);
33 	barrier_var(ret);
34 	return ret;
35 }
36 
37 static __noinline
callback_loop(int index,void ** cb_ctx)38 int callback_loop(int index, void **cb_ctx)
39 {
40 	int ret;
41 
42 	ret = subprog_tail0(*cb_ctx);
43 	barrier_var(ret);
44 	return ret ? 1 : 0;
45 }
46 
47 static __noinline
callback_empty(int index,void * data)48 int callback_empty(int index, void *data)
49 {
50 	return 0;
51 }
52 
53 /* callback involving subprog with tail call is rejected */
54 SEC("tc")
55 __failure __msg("cannot tail call within callback")
tailcall_callback_1(struct __sk_buff * skb)56 int tailcall_callback_1(struct __sk_buff *skb)
57 {
58 	clobber_regs_stack();
59 
60 	bpf_loop(1, callback_loop, &skb, 0);
61 	return 0;
62 }
63 
64 /* subprogs with tailcall do not affect no-tailcall callback */
65 SEC("tc")
66 __success
67 __retval(0)
tailcall_callback_2(struct __sk_buff * skb)68 int tailcall_callback_2(struct __sk_buff *skb)
69 {
70 	int ret;
71 
72 	clobber_regs_stack();
73 
74 	ret = subprog_tail0(skb);
75 	__sink(ret);
76 
77 	bpf_loop(1, callback_empty, NULL, 0);
78 	return 0;
79 }
80 
81 char __license[] SEC("license") = "GPL";
82