xref: /linux/tools/testing/selftests/bpf/progs/bpf_loop.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
14e5070b6SJoanne Koong // SPDX-License-Identifier: GPL-2.0
24e5070b6SJoanne Koong /* Copyright (c) 2021 Facebook */
34e5070b6SJoanne Koong 
44e5070b6SJoanne Koong #include "vmlinux.h"
54e5070b6SJoanne Koong #include <bpf/bpf_helpers.h>
6e91d280cSNaveen N. Rao #include "bpf_misc.h"
74e5070b6SJoanne Koong 
84e5070b6SJoanne Koong char _license[] SEC("license") = "GPL";
94e5070b6SJoanne Koong 
104e5070b6SJoanne Koong struct callback_ctx {
114e5070b6SJoanne Koong 	int output;
124e5070b6SJoanne Koong };
134e5070b6SJoanne Koong 
14*0e1bf9edSEduard Zingerman struct {
15*0e1bf9edSEduard Zingerman 	__uint(type, BPF_MAP_TYPE_HASH);
16*0e1bf9edSEduard Zingerman 	__uint(max_entries, 32);
17*0e1bf9edSEduard Zingerman 	__type(key, int);
18*0e1bf9edSEduard Zingerman 	__type(value, int);
19*0e1bf9edSEduard Zingerman } map1 SEC(".maps");
20*0e1bf9edSEduard Zingerman 
214e5070b6SJoanne Koong /* These should be set by the user program */
224e5070b6SJoanne Koong u32 nested_callback_nr_loops;
234e5070b6SJoanne Koong u32 stop_index = -1;
244e5070b6SJoanne Koong u32 nr_loops;
254e5070b6SJoanne Koong int pid;
26*0e1bf9edSEduard Zingerman int callback_selector;
274e5070b6SJoanne Koong 
284e5070b6SJoanne Koong /* Making these global variables so that the userspace program
294e5070b6SJoanne Koong  * can verify the output through the skeleton
304e5070b6SJoanne Koong  */
314e5070b6SJoanne Koong int nr_loops_returned;
324e5070b6SJoanne Koong int g_output;
334e5070b6SJoanne Koong int err;
344e5070b6SJoanne Koong 
callback(__u32 index,void * data)354e5070b6SJoanne Koong static int callback(__u32 index, void *data)
364e5070b6SJoanne Koong {
374e5070b6SJoanne Koong 	struct callback_ctx *ctx = data;
384e5070b6SJoanne Koong 
394e5070b6SJoanne Koong 	if (index >= stop_index)
404e5070b6SJoanne Koong 		return 1;
414e5070b6SJoanne Koong 
424e5070b6SJoanne Koong 	ctx->output += index;
434e5070b6SJoanne Koong 
444e5070b6SJoanne Koong 	return 0;
454e5070b6SJoanne Koong }
464e5070b6SJoanne Koong 
empty_callback(__u32 index,void * data)474e5070b6SJoanne Koong static int empty_callback(__u32 index, void *data)
484e5070b6SJoanne Koong {
494e5070b6SJoanne Koong 	return 0;
504e5070b6SJoanne Koong }
514e5070b6SJoanne Koong 
nested_callback2(__u32 index,void * data)524e5070b6SJoanne Koong static int nested_callback2(__u32 index, void *data)
534e5070b6SJoanne Koong {
544e5070b6SJoanne Koong 	nr_loops_returned += bpf_loop(nested_callback_nr_loops, callback, data, 0);
554e5070b6SJoanne Koong 
564e5070b6SJoanne Koong 	return 0;
574e5070b6SJoanne Koong }
584e5070b6SJoanne Koong 
nested_callback1(__u32 index,void * data)594e5070b6SJoanne Koong static int nested_callback1(__u32 index, void *data)
604e5070b6SJoanne Koong {
614e5070b6SJoanne Koong 	bpf_loop(nested_callback_nr_loops, nested_callback2, data, 0);
624e5070b6SJoanne Koong 	return 0;
634e5070b6SJoanne Koong }
644e5070b6SJoanne Koong 
65e91d280cSNaveen N. Rao SEC("fentry/" SYS_PREFIX "sys_nanosleep")
test_prog(void * ctx)664e5070b6SJoanne Koong int test_prog(void *ctx)
674e5070b6SJoanne Koong {
684e5070b6SJoanne Koong 	struct callback_ctx data = {};
694e5070b6SJoanne Koong 
704e5070b6SJoanne Koong 	if (bpf_get_current_pid_tgid() >> 32 != pid)
714e5070b6SJoanne Koong 		return 0;
724e5070b6SJoanne Koong 
734e5070b6SJoanne Koong 	nr_loops_returned = bpf_loop(nr_loops, callback, &data, 0);
744e5070b6SJoanne Koong 
754e5070b6SJoanne Koong 	if (nr_loops_returned < 0)
764e5070b6SJoanne Koong 		err = nr_loops_returned;
774e5070b6SJoanne Koong 	else
784e5070b6SJoanne Koong 		g_output = data.output;
794e5070b6SJoanne Koong 
804e5070b6SJoanne Koong 	return 0;
814e5070b6SJoanne Koong }
824e5070b6SJoanne Koong 
83e91d280cSNaveen N. Rao SEC("fentry/" SYS_PREFIX "sys_nanosleep")
prog_null_ctx(void * ctx)844e5070b6SJoanne Koong int prog_null_ctx(void *ctx)
854e5070b6SJoanne Koong {
864e5070b6SJoanne Koong 	if (bpf_get_current_pid_tgid() >> 32 != pid)
874e5070b6SJoanne Koong 		return 0;
884e5070b6SJoanne Koong 
894e5070b6SJoanne Koong 	nr_loops_returned = bpf_loop(nr_loops, empty_callback, NULL, 0);
904e5070b6SJoanne Koong 
914e5070b6SJoanne Koong 	return 0;
924e5070b6SJoanne Koong }
934e5070b6SJoanne Koong 
94e91d280cSNaveen N. Rao SEC("fentry/" SYS_PREFIX "sys_nanosleep")
prog_invalid_flags(void * ctx)954e5070b6SJoanne Koong int prog_invalid_flags(void *ctx)
964e5070b6SJoanne Koong {
974e5070b6SJoanne Koong 	struct callback_ctx data = {};
984e5070b6SJoanne Koong 
994e5070b6SJoanne Koong 	if (bpf_get_current_pid_tgid() >> 32 != pid)
1004e5070b6SJoanne Koong 		return 0;
1014e5070b6SJoanne Koong 
1024e5070b6SJoanne Koong 	err = bpf_loop(nr_loops, callback, &data, 1);
1034e5070b6SJoanne Koong 
1044e5070b6SJoanne Koong 	return 0;
1054e5070b6SJoanne Koong }
1064e5070b6SJoanne Koong 
107e91d280cSNaveen N. Rao SEC("fentry/" SYS_PREFIX "sys_nanosleep")
prog_nested_calls(void * ctx)1084e5070b6SJoanne Koong int prog_nested_calls(void *ctx)
1094e5070b6SJoanne Koong {
1104e5070b6SJoanne Koong 	struct callback_ctx data = {};
1114e5070b6SJoanne Koong 
1124e5070b6SJoanne Koong 	if (bpf_get_current_pid_tgid() >> 32 != pid)
1134e5070b6SJoanne Koong 		return 0;
1144e5070b6SJoanne Koong 
1154e5070b6SJoanne Koong 	nr_loops_returned = 0;
1164e5070b6SJoanne Koong 	bpf_loop(nr_loops, nested_callback1, &data, 0);
1174e5070b6SJoanne Koong 
1184e5070b6SJoanne Koong 	g_output = data.output;
1194e5070b6SJoanne Koong 
1204e5070b6SJoanne Koong 	return 0;
1214e5070b6SJoanne Koong }
122*0e1bf9edSEduard Zingerman 
callback_set_f0(int i,void * ctx)123*0e1bf9edSEduard Zingerman static int callback_set_f0(int i, void *ctx)
124*0e1bf9edSEduard Zingerman {
125*0e1bf9edSEduard Zingerman 	g_output = 0xF0;
126*0e1bf9edSEduard Zingerman 	return 0;
127*0e1bf9edSEduard Zingerman }
128*0e1bf9edSEduard Zingerman 
callback_set_0f(int i,void * ctx)129*0e1bf9edSEduard Zingerman static int callback_set_0f(int i, void *ctx)
130*0e1bf9edSEduard Zingerman {
131*0e1bf9edSEduard Zingerman 	g_output = 0x0F;
132*0e1bf9edSEduard Zingerman 	return 0;
133*0e1bf9edSEduard Zingerman }
134*0e1bf9edSEduard Zingerman 
135*0e1bf9edSEduard Zingerman /*
136*0e1bf9edSEduard Zingerman  * non-constant callback is a corner case for bpf_loop inline logic
137*0e1bf9edSEduard Zingerman  */
138*0e1bf9edSEduard Zingerman SEC("fentry/" SYS_PREFIX "sys_nanosleep")
prog_non_constant_callback(void * ctx)139*0e1bf9edSEduard Zingerman int prog_non_constant_callback(void *ctx)
140*0e1bf9edSEduard Zingerman {
141*0e1bf9edSEduard Zingerman 	if (bpf_get_current_pid_tgid() >> 32 != pid)
142*0e1bf9edSEduard Zingerman 		return 0;
143*0e1bf9edSEduard Zingerman 
144*0e1bf9edSEduard Zingerman 	int (*callback)(int i, void *ctx);
145*0e1bf9edSEduard Zingerman 
146*0e1bf9edSEduard Zingerman 	g_output = 0;
147*0e1bf9edSEduard Zingerman 
148*0e1bf9edSEduard Zingerman 	if (callback_selector == 0x0F)
149*0e1bf9edSEduard Zingerman 		callback = callback_set_0f;
150*0e1bf9edSEduard Zingerman 	else
151*0e1bf9edSEduard Zingerman 		callback = callback_set_f0;
152*0e1bf9edSEduard Zingerman 
153*0e1bf9edSEduard Zingerman 	bpf_loop(1, callback, NULL, 0);
154*0e1bf9edSEduard Zingerman 
155*0e1bf9edSEduard Zingerman 	return 0;
156*0e1bf9edSEduard Zingerman }
157*0e1bf9edSEduard Zingerman 
stack_check_inner_callback(void * ctx)158*0e1bf9edSEduard Zingerman static int stack_check_inner_callback(void *ctx)
159*0e1bf9edSEduard Zingerman {
160*0e1bf9edSEduard Zingerman 	return 0;
161*0e1bf9edSEduard Zingerman }
162*0e1bf9edSEduard Zingerman 
map1_lookup_elem(int key)163*0e1bf9edSEduard Zingerman static int map1_lookup_elem(int key)
164*0e1bf9edSEduard Zingerman {
165*0e1bf9edSEduard Zingerman 	int *val = bpf_map_lookup_elem(&map1, &key);
166*0e1bf9edSEduard Zingerman 
167*0e1bf9edSEduard Zingerman 	return val ? *val : -1;
168*0e1bf9edSEduard Zingerman }
169*0e1bf9edSEduard Zingerman 
map1_update_elem(int key,int val)170*0e1bf9edSEduard Zingerman static void map1_update_elem(int key, int val)
171*0e1bf9edSEduard Zingerman {
172*0e1bf9edSEduard Zingerman 	bpf_map_update_elem(&map1, &key, &val, BPF_ANY);
173*0e1bf9edSEduard Zingerman }
174*0e1bf9edSEduard Zingerman 
stack_check_outer_callback(void * ctx)175*0e1bf9edSEduard Zingerman static int stack_check_outer_callback(void *ctx)
176*0e1bf9edSEduard Zingerman {
177*0e1bf9edSEduard Zingerman 	int a = map1_lookup_elem(1);
178*0e1bf9edSEduard Zingerman 	int b = map1_lookup_elem(2);
179*0e1bf9edSEduard Zingerman 	int c = map1_lookup_elem(3);
180*0e1bf9edSEduard Zingerman 	int d = map1_lookup_elem(4);
181*0e1bf9edSEduard Zingerman 	int e = map1_lookup_elem(5);
182*0e1bf9edSEduard Zingerman 	int f = map1_lookup_elem(6);
183*0e1bf9edSEduard Zingerman 
184*0e1bf9edSEduard Zingerman 	bpf_loop(1, stack_check_inner_callback, NULL, 0);
185*0e1bf9edSEduard Zingerman 
186*0e1bf9edSEduard Zingerman 	map1_update_elem(1, a + 1);
187*0e1bf9edSEduard Zingerman 	map1_update_elem(2, b + 1);
188*0e1bf9edSEduard Zingerman 	map1_update_elem(3, c + 1);
189*0e1bf9edSEduard Zingerman 	map1_update_elem(4, d + 1);
190*0e1bf9edSEduard Zingerman 	map1_update_elem(5, e + 1);
191*0e1bf9edSEduard Zingerman 	map1_update_elem(6, f + 1);
192*0e1bf9edSEduard Zingerman 
193*0e1bf9edSEduard Zingerman 	return 0;
194*0e1bf9edSEduard Zingerman }
195*0e1bf9edSEduard Zingerman 
196*0e1bf9edSEduard Zingerman /* Some of the local variables in stack_check and
197*0e1bf9edSEduard Zingerman  * stack_check_outer_callback would be allocated on stack by
198*0e1bf9edSEduard Zingerman  * compiler. This test should verify that stack content for these
199*0e1bf9edSEduard Zingerman  * variables is preserved between calls to bpf_loop (might be an issue
200*0e1bf9edSEduard Zingerman  * if loop inlining allocates stack slots incorrectly).
201*0e1bf9edSEduard Zingerman  */
202*0e1bf9edSEduard Zingerman SEC("fentry/" SYS_PREFIX "sys_nanosleep")
stack_check(void * ctx)203*0e1bf9edSEduard Zingerman int stack_check(void *ctx)
204*0e1bf9edSEduard Zingerman {
205*0e1bf9edSEduard Zingerman 	if (bpf_get_current_pid_tgid() >> 32 != pid)
206*0e1bf9edSEduard Zingerman 		return 0;
207*0e1bf9edSEduard Zingerman 
208*0e1bf9edSEduard Zingerman 	int a = map1_lookup_elem(7);
209*0e1bf9edSEduard Zingerman 	int b = map1_lookup_elem(8);
210*0e1bf9edSEduard Zingerman 	int c = map1_lookup_elem(9);
211*0e1bf9edSEduard Zingerman 	int d = map1_lookup_elem(10);
212*0e1bf9edSEduard Zingerman 	int e = map1_lookup_elem(11);
213*0e1bf9edSEduard Zingerman 	int f = map1_lookup_elem(12);
214*0e1bf9edSEduard Zingerman 
215*0e1bf9edSEduard Zingerman 	bpf_loop(1, stack_check_outer_callback, NULL, 0);
216*0e1bf9edSEduard Zingerman 
217*0e1bf9edSEduard Zingerman 	map1_update_elem(7,  a + 1);
218*0e1bf9edSEduard Zingerman 	map1_update_elem(8, b + 1);
219*0e1bf9edSEduard Zingerman 	map1_update_elem(9, c + 1);
220*0e1bf9edSEduard Zingerman 	map1_update_elem(10, d + 1);
221*0e1bf9edSEduard Zingerman 	map1_update_elem(11, e + 1);
222*0e1bf9edSEduard Zingerman 	map1_update_elem(12, f + 1);
223*0e1bf9edSEduard Zingerman 
224*0e1bf9edSEduard Zingerman 	return 0;
225*0e1bf9edSEduard Zingerman }
226