14e5070b6SJoanne Koong // SPDX-License-Identifier: GPL-2.0
24e5070b6SJoanne Koong /* Copyright (c) 2021 Facebook */
34e5070b6SJoanne Koong 
44e5070b6SJoanne Koong #include <test_progs.h>
54e5070b6SJoanne Koong #include <network_helpers.h>
64e5070b6SJoanne Koong #include "bpf_loop.skel.h"
74e5070b6SJoanne Koong 
check_nr_loops(struct bpf_loop * skel)84e5070b6SJoanne Koong static void check_nr_loops(struct bpf_loop *skel)
94e5070b6SJoanne Koong {
104e5070b6SJoanne Koong 	struct bpf_link *link;
114e5070b6SJoanne Koong 
124e5070b6SJoanne Koong 	link = bpf_program__attach(skel->progs.test_prog);
134e5070b6SJoanne Koong 	if (!ASSERT_OK_PTR(link, "link"))
144e5070b6SJoanne Koong 		return;
154e5070b6SJoanne Koong 
164e5070b6SJoanne Koong 	/* test 0 loops */
174e5070b6SJoanne Koong 	skel->bss->nr_loops = 0;
184e5070b6SJoanne Koong 
194e5070b6SJoanne Koong 	usleep(1);
204e5070b6SJoanne Koong 
214e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops,
224e5070b6SJoanne Koong 		  "0 loops");
234e5070b6SJoanne Koong 
244e5070b6SJoanne Koong 	/* test 500 loops */
254e5070b6SJoanne Koong 	skel->bss->nr_loops = 500;
264e5070b6SJoanne Koong 
274e5070b6SJoanne Koong 	usleep(1);
284e5070b6SJoanne Koong 
294e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops,
304e5070b6SJoanne Koong 		  "500 loops");
314e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->g_output, (500 * 499) / 2, "g_output");
324e5070b6SJoanne Koong 
334e5070b6SJoanne Koong 	/* test exceeding the max limit */
344e5070b6SJoanne Koong 	skel->bss->nr_loops = -1;
354e5070b6SJoanne Koong 
364e5070b6SJoanne Koong 	usleep(1);
374e5070b6SJoanne Koong 
384e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->err, -E2BIG, "over max limit");
394e5070b6SJoanne Koong 
404e5070b6SJoanne Koong 	bpf_link__destroy(link);
414e5070b6SJoanne Koong }
424e5070b6SJoanne Koong 
check_callback_fn_stop(struct bpf_loop * skel)434e5070b6SJoanne Koong static void check_callback_fn_stop(struct bpf_loop *skel)
444e5070b6SJoanne Koong {
454e5070b6SJoanne Koong 	struct bpf_link *link;
464e5070b6SJoanne Koong 
474e5070b6SJoanne Koong 	link = bpf_program__attach(skel->progs.test_prog);
484e5070b6SJoanne Koong 	if (!ASSERT_OK_PTR(link, "link"))
494e5070b6SJoanne Koong 		return;
504e5070b6SJoanne Koong 
514e5070b6SJoanne Koong 	/* testing that loop is stopped when callback_fn returns 1 */
524e5070b6SJoanne Koong 	skel->bss->nr_loops = 400;
534e5070b6SJoanne Koong 	skel->data->stop_index = 50;
544e5070b6SJoanne Koong 
554e5070b6SJoanne Koong 	usleep(1);
564e5070b6SJoanne Koong 
574e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->nr_loops_returned, skel->data->stop_index + 1,
584e5070b6SJoanne Koong 		  "nr_loops_returned");
594e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->g_output, (50 * 49) / 2,
604e5070b6SJoanne Koong 		  "g_output");
614e5070b6SJoanne Koong 
624e5070b6SJoanne Koong 	bpf_link__destroy(link);
634e5070b6SJoanne Koong }
644e5070b6SJoanne Koong 
check_null_callback_ctx(struct bpf_loop * skel)654e5070b6SJoanne Koong static void check_null_callback_ctx(struct bpf_loop *skel)
664e5070b6SJoanne Koong {
674e5070b6SJoanne Koong 	struct bpf_link *link;
684e5070b6SJoanne Koong 
694e5070b6SJoanne Koong 	/* check that user is able to pass in a null callback_ctx */
704e5070b6SJoanne Koong 	link = bpf_program__attach(skel->progs.prog_null_ctx);
714e5070b6SJoanne Koong 	if (!ASSERT_OK_PTR(link, "link"))
724e5070b6SJoanne Koong 		return;
734e5070b6SJoanne Koong 
744e5070b6SJoanne Koong 	skel->bss->nr_loops = 10;
754e5070b6SJoanne Koong 
764e5070b6SJoanne Koong 	usleep(1);
774e5070b6SJoanne Koong 
784e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops,
794e5070b6SJoanne Koong 		  "nr_loops_returned");
804e5070b6SJoanne Koong 
814e5070b6SJoanne Koong 	bpf_link__destroy(link);
824e5070b6SJoanne Koong }
834e5070b6SJoanne Koong 
check_invalid_flags(struct bpf_loop * skel)844e5070b6SJoanne Koong static void check_invalid_flags(struct bpf_loop *skel)
854e5070b6SJoanne Koong {
864e5070b6SJoanne Koong 	struct bpf_link *link;
874e5070b6SJoanne Koong 
884e5070b6SJoanne Koong 	/* check that passing in non-zero flags returns -EINVAL */
894e5070b6SJoanne Koong 	link = bpf_program__attach(skel->progs.prog_invalid_flags);
904e5070b6SJoanne Koong 	if (!ASSERT_OK_PTR(link, "link"))
914e5070b6SJoanne Koong 		return;
924e5070b6SJoanne Koong 
934e5070b6SJoanne Koong 	usleep(1);
944e5070b6SJoanne Koong 
954e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->err, -EINVAL, "err");
964e5070b6SJoanne Koong 
974e5070b6SJoanne Koong 	bpf_link__destroy(link);
984e5070b6SJoanne Koong }
994e5070b6SJoanne Koong 
check_nested_calls(struct bpf_loop * skel)1004e5070b6SJoanne Koong static void check_nested_calls(struct bpf_loop *skel)
1014e5070b6SJoanne Koong {
1024e5070b6SJoanne Koong 	__u32 nr_loops = 100, nested_callback_nr_loops = 4;
1034e5070b6SJoanne Koong 	struct bpf_link *link;
1044e5070b6SJoanne Koong 
1054e5070b6SJoanne Koong 	/* check that nested calls are supported */
1064e5070b6SJoanne Koong 	link = bpf_program__attach(skel->progs.prog_nested_calls);
1074e5070b6SJoanne Koong 	if (!ASSERT_OK_PTR(link, "link"))
1084e5070b6SJoanne Koong 		return;
1094e5070b6SJoanne Koong 
1104e5070b6SJoanne Koong 	skel->bss->nr_loops = nr_loops;
1114e5070b6SJoanne Koong 	skel->bss->nested_callback_nr_loops = nested_callback_nr_loops;
1124e5070b6SJoanne Koong 
1134e5070b6SJoanne Koong 	usleep(1);
1144e5070b6SJoanne Koong 
1154e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->nr_loops_returned, nr_loops * nested_callback_nr_loops
1164e5070b6SJoanne Koong 		  * nested_callback_nr_loops, "nr_loops_returned");
1174e5070b6SJoanne Koong 	ASSERT_EQ(skel->bss->g_output, (4 * 3) / 2 * nested_callback_nr_loops
1184e5070b6SJoanne Koong 		* nr_loops, "g_output");
1194e5070b6SJoanne Koong 
1204e5070b6SJoanne Koong 	bpf_link__destroy(link);
1214e5070b6SJoanne Koong }
1224e5070b6SJoanne Koong 
check_non_constant_callback(struct bpf_loop * skel)123*0e1bf9edSEduard Zingerman static void check_non_constant_callback(struct bpf_loop *skel)
124*0e1bf9edSEduard Zingerman {
125*0e1bf9edSEduard Zingerman 	struct bpf_link *link =
126*0e1bf9edSEduard Zingerman 		bpf_program__attach(skel->progs.prog_non_constant_callback);
127*0e1bf9edSEduard Zingerman 
128*0e1bf9edSEduard Zingerman 	if (!ASSERT_OK_PTR(link, "link"))
129*0e1bf9edSEduard Zingerman 		return;
130*0e1bf9edSEduard Zingerman 
131*0e1bf9edSEduard Zingerman 	skel->bss->callback_selector = 0x0F;
132*0e1bf9edSEduard Zingerman 	usleep(1);
133*0e1bf9edSEduard Zingerman 	ASSERT_EQ(skel->bss->g_output, 0x0F, "g_output #1");
134*0e1bf9edSEduard Zingerman 
135*0e1bf9edSEduard Zingerman 	skel->bss->callback_selector = 0xF0;
136*0e1bf9edSEduard Zingerman 	usleep(1);
137*0e1bf9edSEduard Zingerman 	ASSERT_EQ(skel->bss->g_output, 0xF0, "g_output #2");
138*0e1bf9edSEduard Zingerman 
139*0e1bf9edSEduard Zingerman 	bpf_link__destroy(link);
140*0e1bf9edSEduard Zingerman }
141*0e1bf9edSEduard Zingerman 
check_stack(struct bpf_loop * skel)142*0e1bf9edSEduard Zingerman static void check_stack(struct bpf_loop *skel)
143*0e1bf9edSEduard Zingerman {
144*0e1bf9edSEduard Zingerman 	struct bpf_link *link = bpf_program__attach(skel->progs.stack_check);
145*0e1bf9edSEduard Zingerman 	const int max_key = 12;
146*0e1bf9edSEduard Zingerman 	int key;
147*0e1bf9edSEduard Zingerman 	int map_fd;
148*0e1bf9edSEduard Zingerman 
149*0e1bf9edSEduard Zingerman 	if (!ASSERT_OK_PTR(link, "link"))
150*0e1bf9edSEduard Zingerman 		return;
151*0e1bf9edSEduard Zingerman 
152*0e1bf9edSEduard Zingerman 	map_fd = bpf_map__fd(skel->maps.map1);
153*0e1bf9edSEduard Zingerman 
154*0e1bf9edSEduard Zingerman 	if (!ASSERT_GE(map_fd, 0, "bpf_map__fd"))
155*0e1bf9edSEduard Zingerman 		goto out;
156*0e1bf9edSEduard Zingerman 
157*0e1bf9edSEduard Zingerman 	for (key = 1; key <= max_key; ++key) {
158*0e1bf9edSEduard Zingerman 		int val = key;
159*0e1bf9edSEduard Zingerman 		int err = bpf_map_update_elem(map_fd, &key, &val, BPF_NOEXIST);
160*0e1bf9edSEduard Zingerman 
161*0e1bf9edSEduard Zingerman 		if (!ASSERT_OK(err, "bpf_map_update_elem"))
162*0e1bf9edSEduard Zingerman 			goto out;
163*0e1bf9edSEduard Zingerman 	}
164*0e1bf9edSEduard Zingerman 
165*0e1bf9edSEduard Zingerman 	usleep(1);
166*0e1bf9edSEduard Zingerman 
167*0e1bf9edSEduard Zingerman 	for (key = 1; key <= max_key; ++key) {
168*0e1bf9edSEduard Zingerman 		int val;
169*0e1bf9edSEduard Zingerman 		int err = bpf_map_lookup_elem(map_fd, &key, &val);
170*0e1bf9edSEduard Zingerman 
171*0e1bf9edSEduard Zingerman 		if (!ASSERT_OK(err, "bpf_map_lookup_elem"))
172*0e1bf9edSEduard Zingerman 			goto out;
173*0e1bf9edSEduard Zingerman 		if (!ASSERT_EQ(val, key + 1, "bad value in the map"))
174*0e1bf9edSEduard Zingerman 			goto out;
175*0e1bf9edSEduard Zingerman 	}
176*0e1bf9edSEduard Zingerman 
177*0e1bf9edSEduard Zingerman out:
178*0e1bf9edSEduard Zingerman 	bpf_link__destroy(link);
179*0e1bf9edSEduard Zingerman }
180*0e1bf9edSEduard Zingerman 
test_bpf_loop(void)1814e5070b6SJoanne Koong void test_bpf_loop(void)
1824e5070b6SJoanne Koong {
1834e5070b6SJoanne Koong 	struct bpf_loop *skel;
1844e5070b6SJoanne Koong 
1854e5070b6SJoanne Koong 	skel = bpf_loop__open_and_load();
1864e5070b6SJoanne Koong 	if (!ASSERT_OK_PTR(skel, "bpf_loop__open_and_load"))
1874e5070b6SJoanne Koong 		return;
1884e5070b6SJoanne Koong 
1894e5070b6SJoanne Koong 	skel->bss->pid = getpid();
1904e5070b6SJoanne Koong 
1914e5070b6SJoanne Koong 	if (test__start_subtest("check_nr_loops"))
1924e5070b6SJoanne Koong 		check_nr_loops(skel);
1934e5070b6SJoanne Koong 	if (test__start_subtest("check_callback_fn_stop"))
1944e5070b6SJoanne Koong 		check_callback_fn_stop(skel);
1954e5070b6SJoanne Koong 	if (test__start_subtest("check_null_callback_ctx"))
1964e5070b6SJoanne Koong 		check_null_callback_ctx(skel);
1974e5070b6SJoanne Koong 	if (test__start_subtest("check_invalid_flags"))
1984e5070b6SJoanne Koong 		check_invalid_flags(skel);
1994e5070b6SJoanne Koong 	if (test__start_subtest("check_nested_calls"))
2004e5070b6SJoanne Koong 		check_nested_calls(skel);
201*0e1bf9edSEduard Zingerman 	if (test__start_subtest("check_non_constant_callback"))
202*0e1bf9edSEduard Zingerman 		check_non_constant_callback(skel);
203*0e1bf9edSEduard Zingerman 	if (test__start_subtest("check_stack"))
204*0e1bf9edSEduard Zingerman 		check_stack(skel);
2054e5070b6SJoanne Koong 
2064e5070b6SJoanne Koong 	bpf_loop__destroy(skel);
2074e5070b6SJoanne Koong }
208