1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2021 Facebook */ 3 4 #include <test_progs.h> 5 #include <network_helpers.h> 6 #include "bpf_loop.skel.h" 7 8 static void check_nr_loops(struct bpf_loop *skel) 9 { 10 struct bpf_link *link; 11 12 link = bpf_program__attach(skel->progs.test_prog); 13 if (!ASSERT_OK_PTR(link, "link")) 14 return; 15 16 /* test 0 loops */ 17 skel->bss->nr_loops = 0; 18 19 usleep(1); 20 21 ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops, 22 "0 loops"); 23 24 /* test 500 loops */ 25 skel->bss->nr_loops = 500; 26 27 usleep(1); 28 29 ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops, 30 "500 loops"); 31 ASSERT_EQ(skel->bss->g_output, (500 * 499) / 2, "g_output"); 32 33 /* test exceeding the max limit */ 34 skel->bss->nr_loops = -1; 35 36 usleep(1); 37 38 ASSERT_EQ(skel->bss->err, -E2BIG, "over max limit"); 39 40 bpf_link__destroy(link); 41 } 42 43 static void check_callback_fn_stop(struct bpf_loop *skel) 44 { 45 struct bpf_link *link; 46 47 link = bpf_program__attach(skel->progs.test_prog); 48 if (!ASSERT_OK_PTR(link, "link")) 49 return; 50 51 /* testing that loop is stopped when callback_fn returns 1 */ 52 skel->bss->nr_loops = 400; 53 skel->data->stop_index = 50; 54 55 usleep(1); 56 57 ASSERT_EQ(skel->bss->nr_loops_returned, skel->data->stop_index + 1, 58 "nr_loops_returned"); 59 ASSERT_EQ(skel->bss->g_output, (50 * 49) / 2, 60 "g_output"); 61 62 bpf_link__destroy(link); 63 } 64 65 static void check_null_callback_ctx(struct bpf_loop *skel) 66 { 67 struct bpf_link *link; 68 69 /* check that user is able to pass in a null callback_ctx */ 70 link = bpf_program__attach(skel->progs.prog_null_ctx); 71 if (!ASSERT_OK_PTR(link, "link")) 72 return; 73 74 skel->bss->nr_loops = 10; 75 76 usleep(1); 77 78 ASSERT_EQ(skel->bss->nr_loops_returned, skel->bss->nr_loops, 79 "nr_loops_returned"); 80 81 bpf_link__destroy(link); 82 } 83 84 static void check_invalid_flags(struct bpf_loop *skel) 85 { 86 struct bpf_link *link; 87 88 /* check that passing in non-zero flags returns -EINVAL */ 89 link = bpf_program__attach(skel->progs.prog_invalid_flags); 90 if (!ASSERT_OK_PTR(link, "link")) 91 return; 92 93 usleep(1); 94 95 ASSERT_EQ(skel->bss->err, -EINVAL, "err"); 96 97 bpf_link__destroy(link); 98 } 99 100 static void check_nested_calls(struct bpf_loop *skel) 101 { 102 __u32 nr_loops = 100, nested_callback_nr_loops = 4; 103 struct bpf_link *link; 104 105 /* check that nested calls are supported */ 106 link = bpf_program__attach(skel->progs.prog_nested_calls); 107 if (!ASSERT_OK_PTR(link, "link")) 108 return; 109 110 skel->bss->nr_loops = nr_loops; 111 skel->bss->nested_callback_nr_loops = nested_callback_nr_loops; 112 113 usleep(1); 114 115 ASSERT_EQ(skel->bss->nr_loops_returned, nr_loops * nested_callback_nr_loops 116 * nested_callback_nr_loops, "nr_loops_returned"); 117 ASSERT_EQ(skel->bss->g_output, (4 * 3) / 2 * nested_callback_nr_loops 118 * nr_loops, "g_output"); 119 120 bpf_link__destroy(link); 121 } 122 123 void test_bpf_loop(void) 124 { 125 struct bpf_loop *skel; 126 127 skel = bpf_loop__open_and_load(); 128 if (!ASSERT_OK_PTR(skel, "bpf_loop__open_and_load")) 129 return; 130 131 skel->bss->pid = getpid(); 132 133 if (test__start_subtest("check_nr_loops")) 134 check_nr_loops(skel); 135 if (test__start_subtest("check_callback_fn_stop")) 136 check_callback_fn_stop(skel); 137 if (test__start_subtest("check_null_callback_ctx")) 138 check_null_callback_ctx(skel); 139 if (test__start_subtest("check_invalid_flags")) 140 check_invalid_flags(skel); 141 if (test__start_subtest("check_nested_calls")) 142 check_nested_calls(skel); 143 144 bpf_loop__destroy(skel); 145 } 146