1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 #include <network_helpers.h> 4 5 #include "map_kptr.skel.h" 6 #include "map_kptr_fail.skel.h" 7 #include "rcu_tasks_trace_gp.skel.h" 8 9 static void test_map_kptr_success(bool test_run) 10 { 11 LIBBPF_OPTS(bpf_test_run_opts, lopts); 12 LIBBPF_OPTS(bpf_test_run_opts, opts, 13 .data_in = &pkt_v4, 14 .data_size_in = sizeof(pkt_v4), 15 .repeat = 1, 16 ); 17 int key = 0, ret, cpu; 18 struct map_kptr *skel; 19 char buf[16], *pbuf; 20 21 skel = map_kptr__open_and_load(); 22 if (!ASSERT_OK_PTR(skel, "map_kptr__open_and_load")) 23 return; 24 25 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref1), &opts); 26 ASSERT_OK(ret, "test_map_kptr_ref1 refcount"); 27 ASSERT_OK(opts.retval, "test_map_kptr_ref1 retval"); 28 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref2), &opts); 29 ASSERT_OK(ret, "test_map_kptr_ref2 refcount"); 30 ASSERT_OK(opts.retval, "test_map_kptr_ref2 retval"); 31 32 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_ls_map_kptr_ref1), &lopts); 33 ASSERT_OK(ret, "test_ls_map_kptr_ref1 refcount"); 34 ASSERT_OK(lopts.retval, "test_ls_map_kptr_ref1 retval"); 35 36 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_ls_map_kptr_ref2), &lopts); 37 ASSERT_OK(ret, "test_ls_map_kptr_ref2 refcount"); 38 ASSERT_OK(lopts.retval, "test_ls_map_kptr_ref2 retval"); 39 40 if (test_run) 41 goto exit; 42 43 cpu = libbpf_num_possible_cpus(); 44 if (!ASSERT_GT(cpu, 0, "libbpf_num_possible_cpus")) 45 goto exit; 46 47 pbuf = calloc(cpu, sizeof(buf)); 48 if (!ASSERT_OK_PTR(pbuf, "calloc(pbuf)")) 49 goto exit; 50 51 ret = bpf_map__update_elem(skel->maps.array_map, 52 &key, sizeof(key), buf, sizeof(buf), 0); 53 ASSERT_OK(ret, "array_map update"); 54 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts); 55 ASSERT_OK(ret, "test_map_kptr_ref3 refcount"); 56 ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval"); 57 58 ret = bpf_map__update_elem(skel->maps.pcpu_array_map, 59 &key, sizeof(key), pbuf, cpu * sizeof(buf), 0); 60 ASSERT_OK(ret, "pcpu_array_map update"); 61 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts); 62 ASSERT_OK(ret, "test_map_kptr_ref3 refcount"); 63 ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval"); 64 65 ret = bpf_map__delete_elem(skel->maps.hash_map, &key, sizeof(key), 0); 66 ASSERT_OK(ret, "hash_map delete"); 67 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts); 68 ASSERT_OK(ret, "test_map_kptr_ref3 refcount"); 69 ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval"); 70 71 ret = bpf_map__delete_elem(skel->maps.pcpu_hash_map, &key, sizeof(key), 0); 72 ASSERT_OK(ret, "pcpu_hash_map delete"); 73 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts); 74 ASSERT_OK(ret, "test_map_kptr_ref3 refcount"); 75 ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval"); 76 77 ret = bpf_map__delete_elem(skel->maps.hash_malloc_map, &key, sizeof(key), 0); 78 ASSERT_OK(ret, "hash_malloc_map delete"); 79 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts); 80 ASSERT_OK(ret, "test_map_kptr_ref3 refcount"); 81 ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval"); 82 83 ret = bpf_map__delete_elem(skel->maps.pcpu_hash_malloc_map, &key, sizeof(key), 0); 84 ASSERT_OK(ret, "pcpu_hash_malloc_map delete"); 85 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts); 86 ASSERT_OK(ret, "test_map_kptr_ref3 refcount"); 87 ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval"); 88 89 ret = bpf_map__delete_elem(skel->maps.lru_hash_map, &key, sizeof(key), 0); 90 ASSERT_OK(ret, "lru_hash_map delete"); 91 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts); 92 ASSERT_OK(ret, "test_map_kptr_ref3 refcount"); 93 ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval"); 94 95 ret = bpf_map__delete_elem(skel->maps.lru_pcpu_hash_map, &key, sizeof(key), 0); 96 ASSERT_OK(ret, "lru_pcpu_hash_map delete"); 97 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref3), &opts); 98 ASSERT_OK(ret, "test_map_kptr_ref3 refcount"); 99 ASSERT_OK(opts.retval, "test_map_kptr_ref3 retval"); 100 101 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_ls_map_kptr_ref_del), &lopts); 102 ASSERT_OK(ret, "test_ls_map_kptr_ref_del delete"); 103 skel->data->ref--; 104 ASSERT_OK(lopts.retval, "test_ls_map_kptr_ref_del retval"); 105 106 free(pbuf); 107 exit: 108 map_kptr__destroy(skel); 109 } 110 111 static int kern_sync_rcu_tasks_trace(struct rcu_tasks_trace_gp *rcu) 112 { 113 LIBBPF_OPTS(bpf_test_run_opts, opts); 114 int ret; 115 116 WRITE_ONCE(rcu->bss->done, 0); 117 ret = bpf_prog_test_run_opts(bpf_program__fd(rcu->progs.call_rcu_tasks_trace), &opts); 118 if (!ASSERT_OK(ret, "call_rcu_tasks_trace")) 119 return -EFAULT; 120 if (!ASSERT_OK(opts.retval, "call_rcu_tasks_trace retval")) 121 return -EFAULT; 122 while (!READ_ONCE(rcu->bss->done)) 123 sched_yield(); 124 return 0; 125 } 126 127 static void wait_for_map_release(void) 128 { 129 LIBBPF_OPTS(bpf_test_run_opts, lopts); 130 struct map_kptr *skel; 131 int ret; 132 133 skel = map_kptr__open_and_load(); 134 if (!ASSERT_OK_PTR(skel, "map_kptr__open_and_load")) 135 return; 136 137 do { 138 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.count_ref), &lopts); 139 ASSERT_OK(ret, "count_ref ret"); 140 ASSERT_OK(lopts.retval, "count_ref retval"); 141 } while (skel->bss->num_of_refs != 2); 142 143 map_kptr__destroy(skel); 144 } 145 146 enum map_update_kptr_case { 147 MAP_UPDATE_KPTR_ARRAY, 148 MAP_UPDATE_KPTR_HASH, 149 MAP_UPDATE_KPTR_HASH_MALLOC, 150 }; 151 152 static struct bpf_program *map_update_kptr_prog(struct map_kptr *skel, 153 enum map_update_kptr_case test) 154 { 155 switch (test) { 156 case MAP_UPDATE_KPTR_ARRAY: 157 return skel->progs.test_array_map_update_kptr; 158 case MAP_UPDATE_KPTR_HASH: 159 return skel->progs.test_hash_map_update_kptr; 160 case MAP_UPDATE_KPTR_HASH_MALLOC: 161 return skel->progs.test_hash_malloc_map_update_kptr; 162 } 163 164 return NULL; 165 } 166 167 static void test_map_update_kptr(enum map_update_kptr_case test) 168 { 169 LIBBPF_OPTS(bpf_test_run_opts, opts); 170 struct map_kptr *skel; 171 struct bpf_program *prog; 172 int ret; 173 174 skel = map_kptr__open_and_load(); 175 if (!ASSERT_OK_PTR(skel, "map_kptr__open_and_load")) 176 return; 177 178 prog = map_update_kptr_prog(skel, test); 179 if (!ASSERT_OK_PTR(prog, "map_update_kptr_prog")) 180 goto out; 181 182 ret = bpf_prog_test_run_opts(bpf_program__fd(prog), &opts); 183 if (!ASSERT_OK(ret, "map_update_kptr")) 184 goto out; 185 if (!ASSERT_OK(opts.retval, "map_update_kptr retval")) 186 goto out; 187 188 ASSERT_EQ(skel->bss->num_of_refs, 3, "refs_after_update"); 189 190 out: 191 map_kptr__destroy(skel); 192 wait_for_map_release(); 193 } 194 195 void serial_test_map_kptr(void) 196 { 197 struct rcu_tasks_trace_gp *skel; 198 199 RUN_TESTS(map_kptr_fail); 200 201 if (test__start_subtest("update_array_map_kptr")) 202 test_map_update_kptr(MAP_UPDATE_KPTR_ARRAY); 203 if (test__start_subtest("update_hash_map_kptr")) 204 test_map_update_kptr(MAP_UPDATE_KPTR_HASH); 205 if (test__start_subtest("update_hash_malloc_map_kptr")) 206 test_map_update_kptr(MAP_UPDATE_KPTR_HASH_MALLOC); 207 208 skel = rcu_tasks_trace_gp__open_and_load(); 209 if (!ASSERT_OK_PTR(skel, "rcu_tasks_trace_gp__open_and_load")) 210 return; 211 212 if (test__start_subtest("success-map")) { 213 test_map_kptr_success(true); 214 215 ASSERT_OK(kern_sync_rcu_tasks_trace(skel), "sync rcu_tasks_trace"); 216 ASSERT_OK(kern_sync_rcu(), "sync rcu"); 217 wait_for_map_release(); 218 219 /* Observe refcount dropping to 1 on bpf_map_free_deferred */ 220 test_map_kptr_success(false); 221 222 ASSERT_OK(kern_sync_rcu_tasks_trace(skel), "sync rcu_tasks_trace"); 223 ASSERT_OK(kern_sync_rcu(), "sync rcu"); 224 wait_for_map_release(); 225 226 /* Observe refcount dropping to 1 on map release. */ 227 test_map_kptr_success(true); 228 } 229 230 rcu_tasks_trace_gp__destroy(skel); 231 } 232