1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <test_progs.h> 4 #include "test_lookup_and_delete.skel.h" 5 6 #define START_VALUE 1234 7 #define NEW_VALUE 4321 8 #define MAX_ENTRIES 2 9 10 static int duration; 11 static int nr_cpus; 12 13 static int fill_values(int map_fd) 14 { 15 __u64 key, value = START_VALUE; 16 int err; 17 18 for (key = 1; key < MAX_ENTRIES + 1; key++) { 19 err = bpf_map_update_elem(map_fd, &key, &value, BPF_NOEXIST); 20 if (!ASSERT_OK(err, "bpf_map_update_elem")) 21 return -1; 22 } 23 24 return 0; 25 } 26 27 static int fill_values_percpu(int map_fd) 28 { 29 __u64 key, value[nr_cpus]; 30 int i, err; 31 32 for (i = 0; i < nr_cpus; i++) 33 value[i] = START_VALUE; 34 35 for (key = 1; key < MAX_ENTRIES + 1; key++) { 36 err = bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST); 37 if (!ASSERT_OK(err, "bpf_map_update_elem")) 38 return -1; 39 } 40 41 return 0; 42 } 43 44 static struct test_lookup_and_delete *setup_prog(enum bpf_map_type map_type, 45 int *map_fd) 46 { 47 struct test_lookup_and_delete *skel; 48 int err; 49 50 skel = test_lookup_and_delete__open(); 51 if (!ASSERT_OK_PTR(skel, "test_lookup_and_delete__open")) 52 return NULL; 53 54 err = bpf_map__set_type(skel->maps.hash_map, map_type); 55 if (!ASSERT_OK(err, "bpf_map__set_type")) 56 goto cleanup; 57 58 err = bpf_map__set_max_entries(skel->maps.hash_map, MAX_ENTRIES); 59 if (!ASSERT_OK(err, "bpf_map__set_max_entries")) 60 goto cleanup; 61 62 err = test_lookup_and_delete__load(skel); 63 if (!ASSERT_OK(err, "test_lookup_and_delete__load")) 64 goto cleanup; 65 66 *map_fd = bpf_map__fd(skel->maps.hash_map); 67 if (!ASSERT_GE(*map_fd, 0, "bpf_map__fd")) 68 goto cleanup; 69 70 return skel; 71 72 cleanup: 73 test_lookup_and_delete__destroy(skel); 74 return NULL; 75 } 76 77 /* Triggers BPF program that updates map with given key and value */ 78 static int trigger_tp(struct test_lookup_and_delete *skel, __u64 key, 79 __u64 value) 80 { 81 int err; 82 83 skel->bss->set_pid = getpid(); 84 skel->bss->set_key = key; 85 skel->bss->set_value = value; 86 87 err = test_lookup_and_delete__attach(skel); 88 if (!ASSERT_OK(err, "test_lookup_and_delete__attach")) 89 return -1; 90 91 syscall(__NR_getpgid); 92 93 test_lookup_and_delete__detach(skel); 94 95 return 0; 96 } 97 98 static void test_lookup_and_delete_hash(void) 99 { 100 struct test_lookup_and_delete *skel; 101 __u64 key, value; 102 int map_fd, err; 103 104 /* Setup program and fill the map. */ 105 skel = setup_prog(BPF_MAP_TYPE_HASH, &map_fd); 106 if (!ASSERT_OK_PTR(skel, "setup_prog")) 107 return; 108 109 err = fill_values(map_fd); 110 if (!ASSERT_OK(err, "fill_values")) 111 goto cleanup; 112 113 /* Lookup and delete element. */ 114 key = 1; 115 err = bpf_map__lookup_and_delete_elem(skel->maps.hash_map, 116 &key, sizeof(key), &value, sizeof(value), 0); 117 if (!ASSERT_OK(err, "bpf_map_lookup_and_delete_elem")) 118 goto cleanup; 119 120 /* Fetched value should match the initially set value. */ 121 if (CHECK(value != START_VALUE, "bpf_map_lookup_and_delete_elem", 122 "unexpected value=%lld\n", value)) 123 goto cleanup; 124 125 /* Check that the entry is non existent. */ 126 err = bpf_map_lookup_elem(map_fd, &key, &value); 127 if (!ASSERT_ERR(err, "bpf_map_lookup_elem")) 128 goto cleanup; 129 130 cleanup: 131 test_lookup_and_delete__destroy(skel); 132 } 133 134 static void test_lookup_and_delete_percpu_hash(void) 135 { 136 struct test_lookup_and_delete *skel; 137 __u64 key, val, value[nr_cpus]; 138 int map_fd, err, i; 139 140 /* Setup program and fill the map. */ 141 skel = setup_prog(BPF_MAP_TYPE_PERCPU_HASH, &map_fd); 142 if (!ASSERT_OK_PTR(skel, "setup_prog")) 143 return; 144 145 err = fill_values_percpu(map_fd); 146 if (!ASSERT_OK(err, "fill_values_percpu")) 147 goto cleanup; 148 149 /* Lookup and delete element. */ 150 key = 1; 151 err = bpf_map__lookup_and_delete_elem(skel->maps.hash_map, 152 &key, sizeof(key), value, sizeof(value), 0); 153 if (!ASSERT_OK(err, "bpf_map_lookup_and_delete_elem")) 154 goto cleanup; 155 156 for (i = 0; i < nr_cpus; i++) { 157 val = value[i]; 158 159 /* Fetched value should match the initially set value. */ 160 if (CHECK(val != START_VALUE, "map value", 161 "unexpected for cpu %d: %lld\n", i, val)) 162 goto cleanup; 163 } 164 165 /* Check that the entry is non existent. */ 166 err = bpf_map_lookup_elem(map_fd, &key, value); 167 if (!ASSERT_ERR(err, "bpf_map_lookup_elem")) 168 goto cleanup; 169 170 cleanup: 171 test_lookup_and_delete__destroy(skel); 172 } 173 174 static void test_lookup_and_delete_lru_hash(void) 175 { 176 struct test_lookup_and_delete *skel; 177 __u64 key, value; 178 int map_fd, err; 179 180 /* Setup program and fill the LRU map. */ 181 skel = setup_prog(BPF_MAP_TYPE_LRU_HASH, &map_fd); 182 if (!ASSERT_OK_PTR(skel, "setup_prog")) 183 return; 184 185 err = fill_values(map_fd); 186 if (!ASSERT_OK(err, "fill_values")) 187 goto cleanup; 188 189 /* Insert new element at key=3, should reuse LRU element. */ 190 key = 3; 191 err = trigger_tp(skel, key, NEW_VALUE); 192 if (!ASSERT_OK(err, "trigger_tp")) 193 goto cleanup; 194 195 /* Lookup and delete element 3. */ 196 err = bpf_map__lookup_and_delete_elem(skel->maps.hash_map, 197 &key, sizeof(key), &value, sizeof(value), 0); 198 if (!ASSERT_OK(err, "bpf_map_lookup_and_delete_elem")) 199 goto cleanup; 200 201 /* Value should match the new value. */ 202 if (CHECK(value != NEW_VALUE, "bpf_map_lookup_and_delete_elem", 203 "unexpected value=%lld\n", value)) 204 goto cleanup; 205 206 /* Check that entries 3 and 1 are non existent. */ 207 err = bpf_map_lookup_elem(map_fd, &key, &value); 208 if (!ASSERT_ERR(err, "bpf_map_lookup_elem")) 209 goto cleanup; 210 211 key = 1; 212 err = bpf_map_lookup_elem(map_fd, &key, &value); 213 if (!ASSERT_ERR(err, "bpf_map_lookup_elem")) 214 goto cleanup; 215 216 cleanup: 217 test_lookup_and_delete__destroy(skel); 218 } 219 220 static void test_lookup_and_delete_lru_percpu_hash(void) 221 { 222 struct test_lookup_and_delete *skel; 223 __u64 key, val, value[nr_cpus]; 224 int map_fd, err, i, cpucnt = 0; 225 226 /* Setup program and fill the LRU map. */ 227 skel = setup_prog(BPF_MAP_TYPE_LRU_PERCPU_HASH, &map_fd); 228 if (!ASSERT_OK_PTR(skel, "setup_prog")) 229 return; 230 231 err = fill_values_percpu(map_fd); 232 if (!ASSERT_OK(err, "fill_values_percpu")) 233 goto cleanup; 234 235 /* Insert new element at key=3, should reuse LRU element 1. */ 236 key = 3; 237 err = trigger_tp(skel, key, NEW_VALUE); 238 if (!ASSERT_OK(err, "trigger_tp")) 239 goto cleanup; 240 241 /* Clean value. */ 242 for (i = 0; i < nr_cpus; i++) 243 value[i] = 0; 244 245 /* Lookup and delete element 3. */ 246 err = bpf_map__lookup_and_delete_elem(skel->maps.hash_map, 247 &key, sizeof(key), value, sizeof(value), 0); 248 if (!ASSERT_OK(err, "bpf_map_lookup_and_delete_elem")) 249 goto cleanup; 250 251 /* Check if only one CPU has set the value. */ 252 for (i = 0; i < nr_cpus; i++) { 253 val = value[i]; 254 if (val) { 255 if (CHECK(val != NEW_VALUE, "map value", 256 "unexpected for cpu %d: %lld\n", i, val)) 257 goto cleanup; 258 cpucnt++; 259 } 260 } 261 if (CHECK(cpucnt != 1, "map value", "set for %d CPUs instead of 1!\n", 262 cpucnt)) 263 goto cleanup; 264 265 /* Check that entries 3 and 1 are non existent. */ 266 err = bpf_map_lookup_elem(map_fd, &key, &value); 267 if (!ASSERT_ERR(err, "bpf_map_lookup_elem")) 268 goto cleanup; 269 270 key = 1; 271 err = bpf_map_lookup_elem(map_fd, &key, &value); 272 if (!ASSERT_ERR(err, "bpf_map_lookup_elem")) 273 goto cleanup; 274 275 cleanup: 276 test_lookup_and_delete__destroy(skel); 277 } 278 279 void test_lookup_and_delete(void) 280 { 281 nr_cpus = bpf_num_possible_cpus(); 282 283 if (test__start_subtest("lookup_and_delete")) 284 test_lookup_and_delete_hash(); 285 if (test__start_subtest("lookup_and_delete_percpu")) 286 test_lookup_and_delete_percpu_hash(); 287 if (test__start_subtest("lookup_and_delete_lru")) 288 test_lookup_and_delete_lru_hash(); 289 if (test__start_subtest("lookup_and_delete_lru_percpu")) 290 test_lookup_and_delete_lru_percpu_hash(); 291 } 292