xref: /aosp_15_r20/external/iproute2/examples/bpf/bpf_tailcall.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker #include "../../include/bpf_api.h"
2*de1e4e89SAndroid Build Coastguard Worker 
3*de1e4e89SAndroid Build Coastguard Worker #define ENTRY_INIT	3
4*de1e4e89SAndroid Build Coastguard Worker #define ENTRY_0		0
5*de1e4e89SAndroid Build Coastguard Worker #define ENTRY_1		1
6*de1e4e89SAndroid Build Coastguard Worker #define MAX_JMP_SIZE	2
7*de1e4e89SAndroid Build Coastguard Worker 
8*de1e4e89SAndroid Build Coastguard Worker #define FOO		42
9*de1e4e89SAndroid Build Coastguard Worker #define BAR		43
10*de1e4e89SAndroid Build Coastguard Worker 
11*de1e4e89SAndroid Build Coastguard Worker /* This example doesn't really do anything useful, but it's purpose is to
12*de1e4e89SAndroid Build Coastguard Worker  * demonstrate eBPF tail calls on a very simple example.
13*de1e4e89SAndroid Build Coastguard Worker  *
14*de1e4e89SAndroid Build Coastguard Worker  * cls_entry() is our classifier entry point, from there we jump based on
15*de1e4e89SAndroid Build Coastguard Worker  * skb->hash into cls_case1() or cls_case2(). They are both part of the
16*de1e4e89SAndroid Build Coastguard Worker  * program array jmp_tc. Indicated via __section_tail(), the tc loader
17*de1e4e89SAndroid Build Coastguard Worker  * populates the program arrays with the loaded file descriptors already.
18*de1e4e89SAndroid Build Coastguard Worker  *
19*de1e4e89SAndroid Build Coastguard Worker  * To demonstrate nested jumps, cls_case2() jumps within the same jmp_tc
20*de1e4e89SAndroid Build Coastguard Worker  * array to cls_case1(). And whenever we arrive at cls_case1(), we jump
21*de1e4e89SAndroid Build Coastguard Worker  * into cls_exit(), part of the jump array jmp_ex.
22*de1e4e89SAndroid Build Coastguard Worker  *
23*de1e4e89SAndroid Build Coastguard Worker  * Also, to show it's possible, all programs share map_sh and dump the value
24*de1e4e89SAndroid Build Coastguard Worker  * that the entry point incremented. The sections that are loaded into a
25*de1e4e89SAndroid Build Coastguard Worker  * program array can be atomically replaced during run-time, e.g. to change
26*de1e4e89SAndroid Build Coastguard Worker  * classifier behaviour.
27*de1e4e89SAndroid Build Coastguard Worker  */
28*de1e4e89SAndroid Build Coastguard Worker 
29*de1e4e89SAndroid Build Coastguard Worker struct bpf_elf_map __section_maps jmp_tc = {
30*de1e4e89SAndroid Build Coastguard Worker 	.type		= BPF_MAP_TYPE_PROG_ARRAY,
31*de1e4e89SAndroid Build Coastguard Worker 	.id		= FOO,
32*de1e4e89SAndroid Build Coastguard Worker 	.size_key	= sizeof(uint32_t),
33*de1e4e89SAndroid Build Coastguard Worker 	.size_value	= sizeof(uint32_t),
34*de1e4e89SAndroid Build Coastguard Worker 	.pinning	= PIN_OBJECT_NS,
35*de1e4e89SAndroid Build Coastguard Worker 	.max_elem	= MAX_JMP_SIZE,
36*de1e4e89SAndroid Build Coastguard Worker };
37*de1e4e89SAndroid Build Coastguard Worker 
38*de1e4e89SAndroid Build Coastguard Worker struct bpf_elf_map __section_maps jmp_ex = {
39*de1e4e89SAndroid Build Coastguard Worker 	.type		= BPF_MAP_TYPE_PROG_ARRAY,
40*de1e4e89SAndroid Build Coastguard Worker 	.id		= BAR,
41*de1e4e89SAndroid Build Coastguard Worker 	.size_key	= sizeof(uint32_t),
42*de1e4e89SAndroid Build Coastguard Worker 	.size_value	= sizeof(uint32_t),
43*de1e4e89SAndroid Build Coastguard Worker 	.pinning	= PIN_OBJECT_NS,
44*de1e4e89SAndroid Build Coastguard Worker 	.max_elem	= 1,
45*de1e4e89SAndroid Build Coastguard Worker };
46*de1e4e89SAndroid Build Coastguard Worker 
47*de1e4e89SAndroid Build Coastguard Worker struct bpf_elf_map __section_maps map_sh = {
48*de1e4e89SAndroid Build Coastguard Worker 	.type		= BPF_MAP_TYPE_ARRAY,
49*de1e4e89SAndroid Build Coastguard Worker 	.size_key	= sizeof(uint32_t),
50*de1e4e89SAndroid Build Coastguard Worker 	.size_value	= sizeof(uint32_t),
51*de1e4e89SAndroid Build Coastguard Worker 	.pinning	= PIN_OBJECT_NS,
52*de1e4e89SAndroid Build Coastguard Worker 	.max_elem	= 1,
53*de1e4e89SAndroid Build Coastguard Worker };
54*de1e4e89SAndroid Build Coastguard Worker 
__section_tail(FOO,ENTRY_0)55*de1e4e89SAndroid Build Coastguard Worker __section_tail(FOO, ENTRY_0)
56*de1e4e89SAndroid Build Coastguard Worker int cls_case1(struct __sk_buff *skb)
57*de1e4e89SAndroid Build Coastguard Worker {
58*de1e4e89SAndroid Build Coastguard Worker 	int key = 0, *val;
59*de1e4e89SAndroid Build Coastguard Worker 
60*de1e4e89SAndroid Build Coastguard Worker 	val = map_lookup_elem(&map_sh, &key);
61*de1e4e89SAndroid Build Coastguard Worker 	if (val)
62*de1e4e89SAndroid Build Coastguard Worker 		printt("case1: map-val: %d from:%u\n", *val, skb->cb[0]);
63*de1e4e89SAndroid Build Coastguard Worker 
64*de1e4e89SAndroid Build Coastguard Worker 	skb->cb[0] = ENTRY_0;
65*de1e4e89SAndroid Build Coastguard Worker 	tail_call(skb, &jmp_ex, ENTRY_0);
66*de1e4e89SAndroid Build Coastguard Worker 
67*de1e4e89SAndroid Build Coastguard Worker 	return BPF_H_DEFAULT;
68*de1e4e89SAndroid Build Coastguard Worker }
69*de1e4e89SAndroid Build Coastguard Worker 
__section_tail(FOO,ENTRY_1)70*de1e4e89SAndroid Build Coastguard Worker __section_tail(FOO, ENTRY_1)
71*de1e4e89SAndroid Build Coastguard Worker int cls_case2(struct __sk_buff *skb)
72*de1e4e89SAndroid Build Coastguard Worker {
73*de1e4e89SAndroid Build Coastguard Worker 	int key = 0, *val;
74*de1e4e89SAndroid Build Coastguard Worker 
75*de1e4e89SAndroid Build Coastguard Worker 	val = map_lookup_elem(&map_sh, &key);
76*de1e4e89SAndroid Build Coastguard Worker 	if (val)
77*de1e4e89SAndroid Build Coastguard Worker 		printt("case2: map-val: %d from:%u\n", *val, skb->cb[0]);
78*de1e4e89SAndroid Build Coastguard Worker 
79*de1e4e89SAndroid Build Coastguard Worker 	skb->cb[0] = ENTRY_1;
80*de1e4e89SAndroid Build Coastguard Worker 	tail_call(skb, &jmp_tc, ENTRY_0);
81*de1e4e89SAndroid Build Coastguard Worker 
82*de1e4e89SAndroid Build Coastguard Worker 	return BPF_H_DEFAULT;
83*de1e4e89SAndroid Build Coastguard Worker }
84*de1e4e89SAndroid Build Coastguard Worker 
__section_tail(BAR,ENTRY_0)85*de1e4e89SAndroid Build Coastguard Worker __section_tail(BAR, ENTRY_0)
86*de1e4e89SAndroid Build Coastguard Worker int cls_exit(struct __sk_buff *skb)
87*de1e4e89SAndroid Build Coastguard Worker {
88*de1e4e89SAndroid Build Coastguard Worker 	int key = 0, *val;
89*de1e4e89SAndroid Build Coastguard Worker 
90*de1e4e89SAndroid Build Coastguard Worker 	val = map_lookup_elem(&map_sh, &key);
91*de1e4e89SAndroid Build Coastguard Worker 	if (val)
92*de1e4e89SAndroid Build Coastguard Worker 		printt("exit: map-val: %d from:%u\n", *val, skb->cb[0]);
93*de1e4e89SAndroid Build Coastguard Worker 
94*de1e4e89SAndroid Build Coastguard Worker 	/* Termination point. */
95*de1e4e89SAndroid Build Coastguard Worker 	return BPF_H_DEFAULT;
96*de1e4e89SAndroid Build Coastguard Worker }
97*de1e4e89SAndroid Build Coastguard Worker 
98*de1e4e89SAndroid Build Coastguard Worker __section_cls_entry
cls_entry(struct __sk_buff * skb)99*de1e4e89SAndroid Build Coastguard Worker int cls_entry(struct __sk_buff *skb)
100*de1e4e89SAndroid Build Coastguard Worker {
101*de1e4e89SAndroid Build Coastguard Worker 	int key = 0, *val;
102*de1e4e89SAndroid Build Coastguard Worker 
103*de1e4e89SAndroid Build Coastguard Worker 	/* For transferring state, we can use skb->cb[0] ... skb->cb[4]. */
104*de1e4e89SAndroid Build Coastguard Worker 	val = map_lookup_elem(&map_sh, &key);
105*de1e4e89SAndroid Build Coastguard Worker 	if (val) {
106*de1e4e89SAndroid Build Coastguard Worker 		lock_xadd(val, 1);
107*de1e4e89SAndroid Build Coastguard Worker 
108*de1e4e89SAndroid Build Coastguard Worker 		skb->cb[0] = ENTRY_INIT;
109*de1e4e89SAndroid Build Coastguard Worker 		tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1));
110*de1e4e89SAndroid Build Coastguard Worker 	}
111*de1e4e89SAndroid Build Coastguard Worker 
112*de1e4e89SAndroid Build Coastguard Worker 	printt("fallthrough\n");
113*de1e4e89SAndroid Build Coastguard Worker 	return BPF_H_DEFAULT;
114*de1e4e89SAndroid Build Coastguard Worker }
115*de1e4e89SAndroid Build Coastguard Worker 
116*de1e4e89SAndroid Build Coastguard Worker BPF_LICENSE("GPL");
117