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