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