]>
Commit | Line | Data |
---|---|---|
5aa5bd14 DB |
1 | /* |
2 | * Testsuite for eBPF maps | |
3 | * | |
4 | * Copyright (c) 2014 PLUMgrid, http://plumgrid.com | |
5 | * Copyright (c) 2016 Facebook | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of version 2 of the GNU General Public | |
9 | * License as published by the Free Software Foundation. | |
10 | */ | |
11 | ||
12 | #include <stdio.h> | |
13 | #include <unistd.h> | |
14 | #include <errno.h> | |
15 | #include <string.h> | |
16 | #include <assert.h> | |
17 | #include <stdlib.h> | |
18 | ||
19 | #include <sys/wait.h> | |
20 | #include <sys/resource.h> | |
21 | ||
22 | #include <linux/bpf.h> | |
23 | ||
10ecc728 | 24 | #include <bpf/bpf.h> |
e00c7b21 | 25 | #include "bpf_util.h" |
5aa5bd14 DB |
26 | |
27 | static int map_flags; | |
28 | ||
29 | static void test_hashmap(int task, void *data) | |
30 | { | |
31 | long long key, next_key, value; | |
32 | int fd; | |
33 | ||
f4874d01 | 34 | fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), |
5aa5bd14 DB |
35 | 2, map_flags); |
36 | if (fd < 0) { | |
37 | printf("Failed to create hashmap '%s'!\n", strerror(errno)); | |
38 | exit(1); | |
39 | } | |
40 | ||
41 | key = 1; | |
42 | value = 1234; | |
43 | /* Insert key=1 element. */ | |
10ecc728 | 44 | assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); |
5aa5bd14 DB |
45 | |
46 | value = 0; | |
47 | /* BPF_NOEXIST means add new element if it doesn't exist. */ | |
10ecc728 | 48 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 && |
5aa5bd14 DB |
49 | /* key=1 already exists. */ |
50 | errno == EEXIST); | |
51 | ||
52 | /* -1 is an invalid flag. */ | |
10ecc728 MS |
53 | assert(bpf_map_update_elem(fd, &key, &value, -1) == -1 && |
54 | errno == EINVAL); | |
5aa5bd14 DB |
55 | |
56 | /* Check that key=1 can be found. */ | |
e5ff7c40 | 57 | assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234); |
5aa5bd14 DB |
58 | |
59 | key = 2; | |
60 | /* Check that key=2 is not found. */ | |
e5ff7c40 | 61 | assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT); |
5aa5bd14 DB |
62 | |
63 | /* BPF_EXIST means update existing element. */ | |
10ecc728 | 64 | assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == -1 && |
5aa5bd14 DB |
65 | /* key=2 is not there. */ |
66 | errno == ENOENT); | |
67 | ||
68 | /* Insert key=2 element. */ | |
10ecc728 | 69 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0); |
5aa5bd14 DB |
70 | |
71 | /* key=1 and key=2 were inserted, check that key=0 cannot be | |
72 | * inserted due to max_entries limit. | |
73 | */ | |
74 | key = 0; | |
10ecc728 | 75 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 && |
5aa5bd14 DB |
76 | errno == E2BIG); |
77 | ||
78 | /* Update existing element, though the map is full. */ | |
79 | key = 1; | |
10ecc728 | 80 | assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0); |
5aa5bd14 | 81 | key = 2; |
10ecc728 | 82 | assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); |
8c290e60 AS |
83 | key = 3; |
84 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 && | |
85 | errno == E2BIG); | |
5aa5bd14 DB |
86 | |
87 | /* Check that key = 0 doesn't exist. */ | |
88 | key = 0; | |
e58383b8 | 89 | assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT); |
5aa5bd14 DB |
90 | |
91 | /* Iterate over two elements. */ | |
5f155c25 | 92 | assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && |
5aa5bd14 | 93 | (next_key == 1 || next_key == 2)); |
5f155c25 | 94 | assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && |
5aa5bd14 | 95 | (next_key == 1 || next_key == 2)); |
5f155c25 | 96 | assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 && |
5aa5bd14 DB |
97 | errno == ENOENT); |
98 | ||
99 | /* Delete both elements. */ | |
100 | key = 1; | |
e58383b8 | 101 | assert(bpf_map_delete_elem(fd, &key) == 0); |
5aa5bd14 | 102 | key = 2; |
e58383b8 MS |
103 | assert(bpf_map_delete_elem(fd, &key) == 0); |
104 | assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT); | |
5aa5bd14 DB |
105 | |
106 | key = 0; | |
107 | /* Check that map is empty. */ | |
5f155c25 | 108 | assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 && |
5aa5bd14 DB |
109 | errno == ENOENT); |
110 | ||
111 | close(fd); | |
112 | } | |
113 | ||
8c290e60 AS |
114 | static void test_hashmap_sizes(int task, void *data) |
115 | { | |
116 | int fd, i, j; | |
117 | ||
118 | for (i = 1; i <= 512; i <<= 1) | |
119 | for (j = 1; j <= 1 << 18; j <<= 1) { | |
120 | fd = bpf_create_map(BPF_MAP_TYPE_HASH, i, j, | |
121 | 2, map_flags); | |
122 | if (fd < 0) { | |
123 | printf("Failed to create hashmap key=%d value=%d '%s'\n", | |
124 | i, j, strerror(errno)); | |
125 | exit(1); | |
126 | } | |
127 | close(fd); | |
128 | usleep(10); /* give kernel time to destroy */ | |
129 | } | |
130 | } | |
131 | ||
5aa5bd14 DB |
132 | static void test_hashmap_percpu(int task, void *data) |
133 | { | |
e00c7b21 | 134 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
5aa5bd14 DB |
135 | long long value[nr_cpus]; |
136 | long long key, next_key; | |
137 | int expected_key_mask = 0; | |
138 | int fd, i; | |
139 | ||
f4874d01 | 140 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key), |
5aa5bd14 DB |
141 | sizeof(value[0]), 2, map_flags); |
142 | if (fd < 0) { | |
143 | printf("Failed to create hashmap '%s'!\n", strerror(errno)); | |
144 | exit(1); | |
145 | } | |
146 | ||
147 | for (i = 0; i < nr_cpus; i++) | |
148 | value[i] = i + 100; | |
149 | ||
150 | key = 1; | |
151 | /* Insert key=1 element. */ | |
152 | assert(!(expected_key_mask & key)); | |
10ecc728 | 153 | assert(bpf_map_update_elem(fd, &key, value, BPF_ANY) == 0); |
5aa5bd14 DB |
154 | expected_key_mask |= key; |
155 | ||
156 | /* BPF_NOEXIST means add new element if it doesn't exist. */ | |
10ecc728 | 157 | assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == -1 && |
5aa5bd14 DB |
158 | /* key=1 already exists. */ |
159 | errno == EEXIST); | |
160 | ||
161 | /* -1 is an invalid flag. */ | |
10ecc728 MS |
162 | assert(bpf_map_update_elem(fd, &key, value, -1) == -1 && |
163 | errno == EINVAL); | |
5aa5bd14 DB |
164 | |
165 | /* Check that key=1 can be found. Value could be 0 if the lookup | |
166 | * was run from a different CPU. | |
167 | */ | |
168 | value[0] = 1; | |
e5ff7c40 | 169 | assert(bpf_map_lookup_elem(fd, &key, value) == 0 && value[0] == 100); |
5aa5bd14 DB |
170 | |
171 | key = 2; | |
172 | /* Check that key=2 is not found. */ | |
e5ff7c40 | 173 | assert(bpf_map_lookup_elem(fd, &key, value) == -1 && errno == ENOENT); |
5aa5bd14 DB |
174 | |
175 | /* BPF_EXIST means update existing element. */ | |
10ecc728 | 176 | assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == -1 && |
5aa5bd14 DB |
177 | /* key=2 is not there. */ |
178 | errno == ENOENT); | |
179 | ||
180 | /* Insert key=2 element. */ | |
181 | assert(!(expected_key_mask & key)); | |
10ecc728 | 182 | assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0); |
5aa5bd14 DB |
183 | expected_key_mask |= key; |
184 | ||
185 | /* key=1 and key=2 were inserted, check that key=0 cannot be | |
186 | * inserted due to max_entries limit. | |
187 | */ | |
188 | key = 0; | |
10ecc728 | 189 | assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == -1 && |
5aa5bd14 DB |
190 | errno == E2BIG); |
191 | ||
192 | /* Check that key = 0 doesn't exist. */ | |
e58383b8 | 193 | assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT); |
5aa5bd14 DB |
194 | |
195 | /* Iterate over two elements. */ | |
5f155c25 | 196 | while (!bpf_map_get_next_key(fd, &key, &next_key)) { |
5aa5bd14 DB |
197 | assert((expected_key_mask & next_key) == next_key); |
198 | expected_key_mask &= ~next_key; | |
199 | ||
e5ff7c40 | 200 | assert(bpf_map_lookup_elem(fd, &next_key, value) == 0); |
5aa5bd14 DB |
201 | |
202 | for (i = 0; i < nr_cpus; i++) | |
203 | assert(value[i] == i + 100); | |
204 | ||
205 | key = next_key; | |
206 | } | |
207 | assert(errno == ENOENT); | |
208 | ||
209 | /* Update with BPF_EXIST. */ | |
210 | key = 1; | |
10ecc728 | 211 | assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0); |
5aa5bd14 DB |
212 | |
213 | /* Delete both elements. */ | |
214 | key = 1; | |
e58383b8 | 215 | assert(bpf_map_delete_elem(fd, &key) == 0); |
5aa5bd14 | 216 | key = 2; |
e58383b8 MS |
217 | assert(bpf_map_delete_elem(fd, &key) == 0); |
218 | assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT); | |
5aa5bd14 DB |
219 | |
220 | key = 0; | |
221 | /* Check that map is empty. */ | |
5f155c25 | 222 | assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 && |
5aa5bd14 DB |
223 | errno == ENOENT); |
224 | ||
225 | close(fd); | |
226 | } | |
227 | ||
228 | static void test_arraymap(int task, void *data) | |
229 | { | |
230 | int key, next_key, fd; | |
231 | long long value; | |
232 | ||
f4874d01 | 233 | fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), |
5aa5bd14 DB |
234 | 2, 0); |
235 | if (fd < 0) { | |
236 | printf("Failed to create arraymap '%s'!\n", strerror(errno)); | |
237 | exit(1); | |
238 | } | |
239 | ||
240 | key = 1; | |
241 | value = 1234; | |
242 | /* Insert key=1 element. */ | |
10ecc728 | 243 | assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); |
5aa5bd14 DB |
244 | |
245 | value = 0; | |
10ecc728 | 246 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 && |
5aa5bd14 DB |
247 | errno == EEXIST); |
248 | ||
249 | /* Check that key=1 can be found. */ | |
e5ff7c40 | 250 | assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234); |
5aa5bd14 DB |
251 | |
252 | key = 0; | |
253 | /* Check that key=0 is also found and zero initialized. */ | |
e5ff7c40 | 254 | assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0); |
5aa5bd14 DB |
255 | |
256 | /* key=0 and key=1 were inserted, check that key=2 cannot be inserted | |
257 | * due to max_entries limit. | |
258 | */ | |
259 | key = 2; | |
10ecc728 | 260 | assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == -1 && |
5aa5bd14 DB |
261 | errno == E2BIG); |
262 | ||
263 | /* Check that key = 2 doesn't exist. */ | |
e5ff7c40 | 264 | assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT); |
5aa5bd14 DB |
265 | |
266 | /* Iterate over two elements. */ | |
5f155c25 | 267 | assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && |
5aa5bd14 | 268 | next_key == 0); |
5f155c25 | 269 | assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && |
5aa5bd14 | 270 | next_key == 1); |
5f155c25 | 271 | assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 && |
5aa5bd14 DB |
272 | errno == ENOENT); |
273 | ||
274 | /* Delete shouldn't succeed. */ | |
275 | key = 1; | |
e58383b8 | 276 | assert(bpf_map_delete_elem(fd, &key) == -1 && errno == EINVAL); |
5aa5bd14 DB |
277 | |
278 | close(fd); | |
279 | } | |
280 | ||
281 | static void test_arraymap_percpu(int task, void *data) | |
282 | { | |
e00c7b21 | 283 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
5aa5bd14 DB |
284 | int key, next_key, fd, i; |
285 | long values[nr_cpus]; | |
286 | ||
f4874d01 | 287 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), |
5aa5bd14 DB |
288 | sizeof(values[0]), 2, 0); |
289 | if (fd < 0) { | |
290 | printf("Failed to create arraymap '%s'!\n", strerror(errno)); | |
291 | exit(1); | |
292 | } | |
293 | ||
294 | for (i = 0; i < nr_cpus; i++) | |
295 | values[i] = i + 100; | |
296 | ||
297 | key = 1; | |
298 | /* Insert key=1 element. */ | |
10ecc728 | 299 | assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); |
5aa5bd14 DB |
300 | |
301 | values[0] = 0; | |
10ecc728 | 302 | assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) == -1 && |
5aa5bd14 DB |
303 | errno == EEXIST); |
304 | ||
305 | /* Check that key=1 can be found. */ | |
e5ff7c40 | 306 | assert(bpf_map_lookup_elem(fd, &key, values) == 0 && values[0] == 100); |
5aa5bd14 DB |
307 | |
308 | key = 0; | |
309 | /* Check that key=0 is also found and zero initialized. */ | |
e5ff7c40 | 310 | assert(bpf_map_lookup_elem(fd, &key, values) == 0 && |
5aa5bd14 DB |
311 | values[0] == 0 && values[nr_cpus - 1] == 0); |
312 | ||
313 | /* Check that key=2 cannot be inserted due to max_entries limit. */ | |
314 | key = 2; | |
10ecc728 | 315 | assert(bpf_map_update_elem(fd, &key, values, BPF_EXIST) == -1 && |
5aa5bd14 DB |
316 | errno == E2BIG); |
317 | ||
318 | /* Check that key = 2 doesn't exist. */ | |
e5ff7c40 | 319 | assert(bpf_map_lookup_elem(fd, &key, values) == -1 && errno == ENOENT); |
5aa5bd14 DB |
320 | |
321 | /* Iterate over two elements. */ | |
5f155c25 | 322 | assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && |
5aa5bd14 | 323 | next_key == 0); |
5f155c25 | 324 | assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && |
5aa5bd14 | 325 | next_key == 1); |
5f155c25 | 326 | assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 && |
5aa5bd14 DB |
327 | errno == ENOENT); |
328 | ||
329 | /* Delete shouldn't succeed. */ | |
330 | key = 1; | |
e58383b8 | 331 | assert(bpf_map_delete_elem(fd, &key) == -1 && errno == EINVAL); |
5aa5bd14 DB |
332 | |
333 | close(fd); | |
334 | } | |
335 | ||
336 | static void test_arraymap_percpu_many_keys(void) | |
337 | { | |
e00c7b21 | 338 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
8c290e60 AS |
339 | /* nr_keys is not too large otherwise the test stresses percpu |
340 | * allocator more than anything else | |
341 | */ | |
342 | unsigned int nr_keys = 2000; | |
5aa5bd14 DB |
343 | long values[nr_cpus]; |
344 | int key, fd, i; | |
345 | ||
f4874d01 | 346 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), |
5aa5bd14 DB |
347 | sizeof(values[0]), nr_keys, 0); |
348 | if (fd < 0) { | |
349 | printf("Failed to create per-cpu arraymap '%s'!\n", | |
350 | strerror(errno)); | |
351 | exit(1); | |
352 | } | |
353 | ||
354 | for (i = 0; i < nr_cpus; i++) | |
355 | values[i] = i + 10; | |
356 | ||
357 | for (key = 0; key < nr_keys; key++) | |
10ecc728 | 358 | assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); |
5aa5bd14 DB |
359 | |
360 | for (key = 0; key < nr_keys; key++) { | |
361 | for (i = 0; i < nr_cpus; i++) | |
362 | values[i] = 0; | |
363 | ||
e5ff7c40 | 364 | assert(bpf_map_lookup_elem(fd, &key, values) == 0); |
5aa5bd14 DB |
365 | |
366 | for (i = 0; i < nr_cpus; i++) | |
367 | assert(values[i] == i + 10); | |
368 | } | |
369 | ||
370 | close(fd); | |
371 | } | |
372 | ||
373 | #define MAP_SIZE (32 * 1024) | |
374 | ||
375 | static void test_map_large(void) | |
376 | { | |
377 | struct bigkey { | |
378 | int a; | |
379 | char b[116]; | |
380 | long long c; | |
381 | } key; | |
382 | int fd, i, value; | |
383 | ||
f4874d01 | 384 | fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), |
5aa5bd14 DB |
385 | MAP_SIZE, map_flags); |
386 | if (fd < 0) { | |
387 | printf("Failed to create large map '%s'!\n", strerror(errno)); | |
388 | exit(1); | |
389 | } | |
390 | ||
391 | for (i = 0; i < MAP_SIZE; i++) { | |
392 | key = (struct bigkey) { .c = i }; | |
393 | value = i; | |
394 | ||
10ecc728 | 395 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0); |
5aa5bd14 DB |
396 | } |
397 | ||
398 | key.c = -1; | |
10ecc728 | 399 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 && |
5aa5bd14 DB |
400 | errno == E2BIG); |
401 | ||
402 | /* Iterate through all elements. */ | |
403 | for (i = 0; i < MAP_SIZE; i++) | |
5f155c25 MS |
404 | assert(bpf_map_get_next_key(fd, &key, &key) == 0); |
405 | assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT); | |
5aa5bd14 DB |
406 | |
407 | key.c = 0; | |
e5ff7c40 | 408 | assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0); |
5aa5bd14 | 409 | key.a = 1; |
e5ff7c40 | 410 | assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT); |
5aa5bd14 DB |
411 | |
412 | close(fd); | |
413 | } | |
414 | ||
415 | static void run_parallel(int tasks, void (*fn)(int task, void *data), | |
416 | void *data) | |
417 | { | |
418 | pid_t pid[tasks]; | |
419 | int i; | |
420 | ||
421 | for (i = 0; i < tasks; i++) { | |
422 | pid[i] = fork(); | |
423 | if (pid[i] == 0) { | |
424 | fn(i, data); | |
425 | exit(0); | |
426 | } else if (pid[i] == -1) { | |
427 | printf("Couldn't spawn #%d process!\n", i); | |
428 | exit(1); | |
429 | } | |
430 | } | |
431 | ||
432 | for (i = 0; i < tasks; i++) { | |
433 | int status; | |
434 | ||
435 | assert(waitpid(pid[i], &status, 0) == pid[i]); | |
436 | assert(status == 0); | |
437 | } | |
438 | } | |
439 | ||
440 | static void test_map_stress(void) | |
441 | { | |
442 | run_parallel(100, test_hashmap, NULL); | |
443 | run_parallel(100, test_hashmap_percpu, NULL); | |
8c290e60 | 444 | run_parallel(100, test_hashmap_sizes, NULL); |
5aa5bd14 DB |
445 | |
446 | run_parallel(100, test_arraymap, NULL); | |
447 | run_parallel(100, test_arraymap_percpu, NULL); | |
448 | } | |
449 | ||
450 | #define TASKS 1024 | |
451 | ||
452 | #define DO_UPDATE 1 | |
453 | #define DO_DELETE 0 | |
454 | ||
455 | static void do_work(int fn, void *data) | |
456 | { | |
457 | int do_update = ((int *)data)[1]; | |
458 | int fd = ((int *)data)[0]; | |
459 | int i, key, value; | |
460 | ||
461 | for (i = fn; i < MAP_SIZE; i += TASKS) { | |
462 | key = value = i; | |
463 | ||
464 | if (do_update) { | |
10ecc728 MS |
465 | assert(bpf_map_update_elem(fd, &key, &value, |
466 | BPF_NOEXIST) == 0); | |
467 | assert(bpf_map_update_elem(fd, &key, &value, | |
468 | BPF_EXIST) == 0); | |
5aa5bd14 | 469 | } else { |
e58383b8 | 470 | assert(bpf_map_delete_elem(fd, &key) == 0); |
5aa5bd14 DB |
471 | } |
472 | } | |
473 | } | |
474 | ||
475 | static void test_map_parallel(void) | |
476 | { | |
477 | int i, fd, key = 0, value = 0; | |
478 | int data[2]; | |
479 | ||
f4874d01 | 480 | fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), |
5aa5bd14 DB |
481 | MAP_SIZE, map_flags); |
482 | if (fd < 0) { | |
483 | printf("Failed to create map for parallel test '%s'!\n", | |
484 | strerror(errno)); | |
485 | exit(1); | |
486 | } | |
487 | ||
488 | /* Use the same fd in children to add elements to this map: | |
489 | * child_0 adds key=0, key=1024, key=2048, ... | |
490 | * child_1 adds key=1, key=1025, key=2049, ... | |
491 | * child_1023 adds key=1023, ... | |
492 | */ | |
493 | data[0] = fd; | |
494 | data[1] = DO_UPDATE; | |
495 | run_parallel(TASKS, do_work, data); | |
496 | ||
497 | /* Check that key=0 is already there. */ | |
10ecc728 | 498 | assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 && |
5aa5bd14 DB |
499 | errno == EEXIST); |
500 | ||
501 | /* Check that all elements were inserted. */ | |
502 | key = -1; | |
503 | for (i = 0; i < MAP_SIZE; i++) | |
5f155c25 MS |
504 | assert(bpf_map_get_next_key(fd, &key, &key) == 0); |
505 | assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT); | |
5aa5bd14 DB |
506 | |
507 | /* Another check for all elements */ | |
508 | for (i = 0; i < MAP_SIZE; i++) { | |
509 | key = MAP_SIZE - i - 1; | |
510 | ||
e5ff7c40 | 511 | assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && |
5aa5bd14 DB |
512 | value == key); |
513 | } | |
514 | ||
515 | /* Now let's delete all elemenets in parallel. */ | |
516 | data[1] = DO_DELETE; | |
517 | run_parallel(TASKS, do_work, data); | |
518 | ||
519 | /* Nothing should be left. */ | |
520 | key = -1; | |
5f155c25 | 521 | assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT); |
5aa5bd14 DB |
522 | } |
523 | ||
524 | static void run_all_tests(void) | |
525 | { | |
526 | test_hashmap(0, NULL); | |
527 | test_hashmap_percpu(0, NULL); | |
528 | ||
529 | test_arraymap(0, NULL); | |
530 | test_arraymap_percpu(0, NULL); | |
531 | ||
532 | test_arraymap_percpu_many_keys(); | |
533 | ||
534 | test_map_large(); | |
535 | test_map_parallel(); | |
536 | test_map_stress(); | |
537 | } | |
538 | ||
539 | int main(void) | |
540 | { | |
541 | struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; | |
542 | ||
543 | setrlimit(RLIMIT_MEMLOCK, &rinf); | |
544 | ||
545 | map_flags = 0; | |
546 | run_all_tests(); | |
547 | ||
548 | map_flags = BPF_F_NO_PREALLOC; | |
549 | run_all_tests(); | |
550 | ||
551 | printf("test_maps: OK\n"); | |
552 | return 0; | |
553 | } |