xref: /linux/tools/testing/selftests/bpf/progs/bpf_loop.c (revision 0e1bf9ed2000c16fa8e0703e255a23d64a4adb27)
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 
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 
474e5070b6SJoanne Koong static int empty_callback(__u32 index, void *data)
484e5070b6SJoanne Koong {
494e5070b6SJoanne Koong 	return 0;
504e5070b6SJoanne Koong }
514e5070b6SJoanne Koong 
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 
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")
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")
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")
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")
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 
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 
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")
139*0e1bf9edSEduard Zingerman int prog_non_constant_callback(void *ctx)
140*0e1bf9edSEduard Zingerman {
141*0e1bf9edSEduard Zingerman 	struct callback_ctx data = {};
142*0e1bf9edSEduard Zingerman 
143*0e1bf9edSEduard Zingerman 	if (bpf_get_current_pid_tgid() >> 32 != pid)
144*0e1bf9edSEduard Zingerman 		return 0;
145*0e1bf9edSEduard Zingerman 
146*0e1bf9edSEduard Zingerman 	int (*callback)(int i, void *ctx);
147*0e1bf9edSEduard Zingerman 
148*0e1bf9edSEduard Zingerman 	g_output = 0;
149*0e1bf9edSEduard Zingerman 
150*0e1bf9edSEduard Zingerman 	if (callback_selector == 0x0F)
151*0e1bf9edSEduard Zingerman 		callback = callback_set_0f;
152*0e1bf9edSEduard Zingerman 	else
153*0e1bf9edSEduard Zingerman 		callback = callback_set_f0;
154*0e1bf9edSEduard Zingerman 
155*0e1bf9edSEduard Zingerman 	bpf_loop(1, callback, NULL, 0);
156*0e1bf9edSEduard Zingerman 
157*0e1bf9edSEduard Zingerman 	return 0;
158*0e1bf9edSEduard Zingerman }
159*0e1bf9edSEduard Zingerman 
160*0e1bf9edSEduard Zingerman static int stack_check_inner_callback(void *ctx)
161*0e1bf9edSEduard Zingerman {
162*0e1bf9edSEduard Zingerman 	return 0;
163*0e1bf9edSEduard Zingerman }
164*0e1bf9edSEduard Zingerman 
165*0e1bf9edSEduard Zingerman static int map1_lookup_elem(int key)
166*0e1bf9edSEduard Zingerman {
167*0e1bf9edSEduard Zingerman 	int *val = bpf_map_lookup_elem(&map1, &key);
168*0e1bf9edSEduard Zingerman 
169*0e1bf9edSEduard Zingerman 	return val ? *val : -1;
170*0e1bf9edSEduard Zingerman }
171*0e1bf9edSEduard Zingerman 
172*0e1bf9edSEduard Zingerman static void map1_update_elem(int key, int val)
173*0e1bf9edSEduard Zingerman {
174*0e1bf9edSEduard Zingerman 	bpf_map_update_elem(&map1, &key, &val, BPF_ANY);
175*0e1bf9edSEduard Zingerman }
176*0e1bf9edSEduard Zingerman 
177*0e1bf9edSEduard Zingerman static int stack_check_outer_callback(void *ctx)
178*0e1bf9edSEduard Zingerman {
179*0e1bf9edSEduard Zingerman 	int a = map1_lookup_elem(1);
180*0e1bf9edSEduard Zingerman 	int b = map1_lookup_elem(2);
181*0e1bf9edSEduard Zingerman 	int c = map1_lookup_elem(3);
182*0e1bf9edSEduard Zingerman 	int d = map1_lookup_elem(4);
183*0e1bf9edSEduard Zingerman 	int e = map1_lookup_elem(5);
184*0e1bf9edSEduard Zingerman 	int f = map1_lookup_elem(6);
185*0e1bf9edSEduard Zingerman 
186*0e1bf9edSEduard Zingerman 	bpf_loop(1, stack_check_inner_callback, NULL, 0);
187*0e1bf9edSEduard Zingerman 
188*0e1bf9edSEduard Zingerman 	map1_update_elem(1, a + 1);
189*0e1bf9edSEduard Zingerman 	map1_update_elem(2, b + 1);
190*0e1bf9edSEduard Zingerman 	map1_update_elem(3, c + 1);
191*0e1bf9edSEduard Zingerman 	map1_update_elem(4, d + 1);
192*0e1bf9edSEduard Zingerman 	map1_update_elem(5, e + 1);
193*0e1bf9edSEduard Zingerman 	map1_update_elem(6, f + 1);
194*0e1bf9edSEduard Zingerman 
195*0e1bf9edSEduard Zingerman 	return 0;
196*0e1bf9edSEduard Zingerman }
197*0e1bf9edSEduard Zingerman 
198*0e1bf9edSEduard Zingerman /* Some of the local variables in stack_check and
199*0e1bf9edSEduard Zingerman  * stack_check_outer_callback would be allocated on stack by
200*0e1bf9edSEduard Zingerman  * compiler. This test should verify that stack content for these
201*0e1bf9edSEduard Zingerman  * variables is preserved between calls to bpf_loop (might be an issue
202*0e1bf9edSEduard Zingerman  * if loop inlining allocates stack slots incorrectly).
203*0e1bf9edSEduard Zingerman  */
204*0e1bf9edSEduard Zingerman SEC("fentry/" SYS_PREFIX "sys_nanosleep")
205*0e1bf9edSEduard Zingerman int stack_check(void *ctx)
206*0e1bf9edSEduard Zingerman {
207*0e1bf9edSEduard Zingerman 	if (bpf_get_current_pid_tgid() >> 32 != pid)
208*0e1bf9edSEduard Zingerman 		return 0;
209*0e1bf9edSEduard Zingerman 
210*0e1bf9edSEduard Zingerman 	int a = map1_lookup_elem(7);
211*0e1bf9edSEduard Zingerman 	int b = map1_lookup_elem(8);
212*0e1bf9edSEduard Zingerman 	int c = map1_lookup_elem(9);
213*0e1bf9edSEduard Zingerman 	int d = map1_lookup_elem(10);
214*0e1bf9edSEduard Zingerman 	int e = map1_lookup_elem(11);
215*0e1bf9edSEduard Zingerman 	int f = map1_lookup_elem(12);
216*0e1bf9edSEduard Zingerman 
217*0e1bf9edSEduard Zingerman 	bpf_loop(1, stack_check_outer_callback, NULL, 0);
218*0e1bf9edSEduard Zingerman 
219*0e1bf9edSEduard Zingerman 	map1_update_elem(7,  a + 1);
220*0e1bf9edSEduard Zingerman 	map1_update_elem(8, b + 1);
221*0e1bf9edSEduard Zingerman 	map1_update_elem(9, c + 1);
222*0e1bf9edSEduard Zingerman 	map1_update_elem(10, d + 1);
223*0e1bf9edSEduard Zingerman 	map1_update_elem(11, e + 1);
224*0e1bf9edSEduard Zingerman 	map1_update_elem(12, f + 1);
225*0e1bf9edSEduard Zingerman 
226*0e1bf9edSEduard Zingerman 	return 0;
227*0e1bf9edSEduard Zingerman }
228