1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Testsuite for eBPF maps
4 *
5 * Copyright (c) 2014 PLUMgrid, http://plumgrid.com
6 * Copyright (c) 2016 Facebook
7 */
8
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <assert.h>
14 #include <stdlib.h>
15 #include <time.h>
16
17 #include <sys/wait.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <linux/bpf.h>
21
22 #include <bpf/bpf.h>
23 #include <bpf/libbpf.h>
24
25 #include "bpf_util.h"
26 #include "test_maps.h"
27 #include "testing_helpers.h"
28
29 int skips;
30
31 static struct bpf_map_create_opts map_opts = { .sz = sizeof(map_opts) };
32
test_hashmap(unsigned int task,void * data)33 static void test_hashmap(unsigned int task, void *data)
34 {
35 long long key, next_key, first_key, value;
36 int fd;
37
38 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value), 2, &map_opts);
39 if (fd < 0) {
40 printf("Failed to create hashmap '%s'!\n", strerror(errno));
41 exit(1);
42 }
43
44 key = 1;
45 value = 1234;
46 /* Insert key=1 element. */
47 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
48
49 value = 0;
50 /* BPF_NOEXIST means add new element if it doesn't exist. */
51 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
52 /* key=1 already exists. */
53 errno == EEXIST);
54
55 /* -1 is an invalid flag. */
56 assert(bpf_map_update_elem(fd, &key, &value, -1) < 0 &&
57 errno == EINVAL);
58
59 /* Check that key=1 can be found. */
60 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234);
61
62 key = 2;
63 value = 1234;
64 /* Insert key=2 element. */
65 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
66
67 /* Check that key=2 matches the value and delete it */
68 assert(bpf_map_lookup_and_delete_elem(fd, &key, &value) == 0 && value == 1234);
69
70 /* Check that key=2 is not found. */
71 assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT);
72
73 /* BPF_EXIST means update existing element. */
74 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) < 0 &&
75 /* key=2 is not there. */
76 errno == ENOENT);
77
78 /* Insert key=2 element. */
79 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
80
81 /* key=1 and key=2 were inserted, check that key=0 cannot be
82 * inserted due to max_entries limit.
83 */
84 key = 0;
85 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
86 errno == E2BIG);
87
88 /* Update existing element, though the map is full. */
89 key = 1;
90 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0);
91 key = 2;
92 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
93 key = 3;
94 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
95 errno == E2BIG);
96
97 /* Check that key = 0 doesn't exist. */
98 key = 0;
99 assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT);
100
101 /* Iterate over two elements. */
102 assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 &&
103 (first_key == 1 || first_key == 2));
104 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
105 (next_key == first_key));
106 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
107 (next_key == 1 || next_key == 2) &&
108 (next_key != first_key));
109 assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 &&
110 errno == ENOENT);
111
112 /* Delete both elements. */
113 key = 1;
114 assert(bpf_map_delete_elem(fd, &key) == 0);
115 key = 2;
116 assert(bpf_map_delete_elem(fd, &key) == 0);
117 assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT);
118
119 key = 0;
120 /* Check that map is empty. */
121 assert(bpf_map_get_next_key(fd, NULL, &next_key) < 0 &&
122 errno == ENOENT);
123 assert(bpf_map_get_next_key(fd, &key, &next_key) < 0 &&
124 errno == ENOENT);
125
126 close(fd);
127 }
128
test_hashmap_sizes(unsigned int task,void * data)129 static void test_hashmap_sizes(unsigned int task, void *data)
130 {
131 int fd, i, j;
132
133 for (i = 1; i <= 512; i <<= 1)
134 for (j = 1; j <= 1 << 18; j <<= 1) {
135 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, i, j, 2, &map_opts);
136 if (fd < 0) {
137 if (errno == ENOMEM)
138 return;
139 printf("Failed to create hashmap key=%d value=%d '%s'\n",
140 i, j, strerror(errno));
141 exit(1);
142 }
143 close(fd);
144 usleep(10); /* give kernel time to destroy */
145 }
146 }
147
test_hashmap_percpu(unsigned int task,void * data)148 static void test_hashmap_percpu(unsigned int task, void *data)
149 {
150 unsigned int nr_cpus = bpf_num_possible_cpus();
151 BPF_DECLARE_PERCPU(long, value);
152 long long key, next_key, first_key;
153 int expected_key_mask = 0;
154 int fd, i;
155
156 fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_HASH, NULL, sizeof(key),
157 sizeof(bpf_percpu(value, 0)), 2, &map_opts);
158 if (fd < 0) {
159 printf("Failed to create hashmap '%s'!\n", strerror(errno));
160 exit(1);
161 }
162
163 for (i = 0; i < nr_cpus; i++)
164 bpf_percpu(value, i) = i + 100;
165
166 key = 1;
167 /* Insert key=1 element. */
168 assert(!(expected_key_mask & key));
169 assert(bpf_map_update_elem(fd, &key, value, BPF_ANY) == 0);
170
171 /* Lookup and delete elem key=1 and check value. */
172 assert(bpf_map_lookup_and_delete_elem(fd, &key, value) == 0 &&
173 bpf_percpu(value,0) == 100);
174
175 for (i = 0; i < nr_cpus; i++)
176 bpf_percpu(value,i) = i + 100;
177
178 /* Insert key=1 element which should not exist. */
179 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0);
180 expected_key_mask |= key;
181
182 /* BPF_NOEXIST means add new element if it doesn't exist. */
183 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) < 0 &&
184 /* key=1 already exists. */
185 errno == EEXIST);
186
187 /* -1 is an invalid flag. */
188 assert(bpf_map_update_elem(fd, &key, value, -1) < 0 &&
189 errno == EINVAL);
190
191 /* Check that key=1 can be found. Value could be 0 if the lookup
192 * was run from a different CPU.
193 */
194 bpf_percpu(value, 0) = 1;
195 assert(bpf_map_lookup_elem(fd, &key, value) == 0 &&
196 bpf_percpu(value, 0) == 100);
197
198 key = 2;
199 /* Check that key=2 is not found. */
200 assert(bpf_map_lookup_elem(fd, &key, value) < 0 && errno == ENOENT);
201
202 /* BPF_EXIST means update existing element. */
203 assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) < 0 &&
204 /* key=2 is not there. */
205 errno == ENOENT);
206
207 /* Insert key=2 element. */
208 assert(!(expected_key_mask & key));
209 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0);
210 expected_key_mask |= key;
211
212 /* key=1 and key=2 were inserted, check that key=0 cannot be
213 * inserted due to max_entries limit.
214 */
215 key = 0;
216 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) < 0 &&
217 errno == E2BIG);
218
219 /* Check that key = 0 doesn't exist. */
220 assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT);
221
222 /* Iterate over two elements. */
223 assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 &&
224 ((expected_key_mask & first_key) == first_key));
225 while (!bpf_map_get_next_key(fd, &key, &next_key)) {
226 if (first_key) {
227 assert(next_key == first_key);
228 first_key = 0;
229 }
230 assert((expected_key_mask & next_key) == next_key);
231 expected_key_mask &= ~next_key;
232
233 assert(bpf_map_lookup_elem(fd, &next_key, value) == 0);
234
235 for (i = 0; i < nr_cpus; i++)
236 assert(bpf_percpu(value, i) == i + 100);
237
238 key = next_key;
239 }
240 assert(errno == ENOENT);
241
242 /* Update with BPF_EXIST. */
243 key = 1;
244 assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0);
245
246 /* Delete both elements. */
247 key = 1;
248 assert(bpf_map_delete_elem(fd, &key) == 0);
249 key = 2;
250 assert(bpf_map_delete_elem(fd, &key) == 0);
251 assert(bpf_map_delete_elem(fd, &key) < 0 && errno == ENOENT);
252
253 key = 0;
254 /* Check that map is empty. */
255 assert(bpf_map_get_next_key(fd, NULL, &next_key) < 0 &&
256 errno == ENOENT);
257 assert(bpf_map_get_next_key(fd, &key, &next_key) < 0 &&
258 errno == ENOENT);
259
260 close(fd);
261 }
262
263 #define MAP_RETRIES 20
264
can_retry(int err)265 static bool can_retry(int err)
266 {
267 return (err == EAGAIN || err == EBUSY ||
268 ((err == ENOMEM || err == E2BIG) &&
269 map_opts.map_flags == BPF_F_NO_PREALLOC));
270 }
271
272
273 #define VALUE_SIZE 3
helper_fill_hashmap(int max_entries)274 static int helper_fill_hashmap(int max_entries)
275 {
276 int i, fd, ret;
277 long long key, value[VALUE_SIZE] = {};
278
279 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
280 max_entries, &map_opts);
281 CHECK(fd < 0,
282 "failed to create hashmap",
283 "err: %s, flags: 0x%x\n", strerror(errno), map_opts.map_flags);
284
285 for (i = 0; i < max_entries; i++) {
286 key = i; value[0] = key;
287 ret = map_update_retriable(fd, &key, value, BPF_NOEXIST,
288 MAP_RETRIES, can_retry);
289 CHECK(ret != 0,
290 "can't update hashmap",
291 "err: %s\n", strerror(-ret));
292 }
293
294 return fd;
295 }
296
test_hashmap_walk(unsigned int task,void * data)297 static void test_hashmap_walk(unsigned int task, void *data)
298 {
299 int fd, i, max_entries = 10000;
300 long long key, value[VALUE_SIZE], next_key;
301 bool next_key_valid = true;
302
303 fd = helper_fill_hashmap(max_entries);
304
305 for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
306 &next_key) == 0; i++) {
307 key = next_key;
308 assert(bpf_map_lookup_elem(fd, &key, value) == 0);
309 }
310
311 assert(i == max_entries);
312
313 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
314 for (i = 0; next_key_valid; i++) {
315 next_key_valid = bpf_map_get_next_key(fd, &key, &next_key) == 0;
316 assert(bpf_map_lookup_elem(fd, &key, value) == 0);
317 value[0]++;
318 assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0);
319 key = next_key;
320 }
321
322 assert(i == max_entries);
323
324 for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key,
325 &next_key) == 0; i++) {
326 key = next_key;
327 assert(bpf_map_lookup_elem(fd, &key, value) == 0);
328 assert(value[0] - 1 == key);
329 }
330
331 assert(i == max_entries);
332 close(fd);
333 }
334
test_hashmap_zero_seed(void)335 static void test_hashmap_zero_seed(void)
336 {
337 int i, first, second, old_flags;
338 long long key, next_first, next_second;
339
340 old_flags = map_opts.map_flags;
341 map_opts.map_flags |= BPF_F_ZERO_SEED;
342
343 first = helper_fill_hashmap(3);
344 second = helper_fill_hashmap(3);
345
346 for (i = 0; ; i++) {
347 void *key_ptr = !i ? NULL : &key;
348
349 if (bpf_map_get_next_key(first, key_ptr, &next_first) != 0)
350 break;
351
352 CHECK(bpf_map_get_next_key(second, key_ptr, &next_second) != 0,
353 "next_key for second map must succeed",
354 "key_ptr: %p", key_ptr);
355 CHECK(next_first != next_second,
356 "keys must match",
357 "i: %d first: %lld second: %lld\n", i,
358 next_first, next_second);
359
360 key = next_first;
361 }
362
363 map_opts.map_flags = old_flags;
364 close(first);
365 close(second);
366 }
367
test_arraymap(unsigned int task,void * data)368 static void test_arraymap(unsigned int task, void *data)
369 {
370 int key, next_key, fd;
371 long long value;
372
373 fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(key), sizeof(value), 2, NULL);
374 if (fd < 0) {
375 printf("Failed to create arraymap '%s'!\n", strerror(errno));
376 exit(1);
377 }
378
379 key = 1;
380 value = 1234;
381 /* Insert key=1 element. */
382 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
383
384 value = 0;
385 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
386 errno == EEXIST);
387
388 /* Check that key=1 can be found. */
389 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234);
390
391 key = 0;
392 /* Check that key=0 is also found and zero initialized. */
393 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0);
394
395 /* key=0 and key=1 were inserted, check that key=2 cannot be inserted
396 * due to max_entries limit.
397 */
398 key = 2;
399 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) < 0 &&
400 errno == E2BIG);
401
402 /* Check that key = 2 doesn't exist. */
403 assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT);
404
405 /* Iterate over two elements. */
406 assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 &&
407 next_key == 0);
408 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
409 next_key == 0);
410 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
411 next_key == 1);
412 assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 &&
413 errno == ENOENT);
414
415 /* Delete shouldn't succeed. */
416 key = 1;
417 assert(bpf_map_delete_elem(fd, &key) < 0 && errno == EINVAL);
418
419 close(fd);
420 }
421
test_arraymap_percpu(unsigned int task,void * data)422 static void test_arraymap_percpu(unsigned int task, void *data)
423 {
424 unsigned int nr_cpus = bpf_num_possible_cpus();
425 BPF_DECLARE_PERCPU(long, values);
426 int key, next_key, fd, i;
427
428 fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, NULL, sizeof(key),
429 sizeof(bpf_percpu(values, 0)), 2, NULL);
430 if (fd < 0) {
431 printf("Failed to create arraymap '%s'!\n", strerror(errno));
432 exit(1);
433 }
434
435 for (i = 0; i < nr_cpus; i++)
436 bpf_percpu(values, i) = i + 100;
437
438 key = 1;
439 /* Insert key=1 element. */
440 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
441
442 bpf_percpu(values, 0) = 0;
443 assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) < 0 &&
444 errno == EEXIST);
445
446 /* Check that key=1 can be found. */
447 assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
448 bpf_percpu(values, 0) == 100);
449
450 key = 0;
451 /* Check that key=0 is also found and zero initialized. */
452 assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
453 bpf_percpu(values, 0) == 0 &&
454 bpf_percpu(values, nr_cpus - 1) == 0);
455
456 /* Check that key=2 cannot be inserted due to max_entries limit. */
457 key = 2;
458 assert(bpf_map_update_elem(fd, &key, values, BPF_EXIST) < 0 &&
459 errno == E2BIG);
460
461 /* Check that key = 2 doesn't exist. */
462 assert(bpf_map_lookup_elem(fd, &key, values) < 0 && errno == ENOENT);
463
464 /* Iterate over two elements. */
465 assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 &&
466 next_key == 0);
467 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
468 next_key == 0);
469 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
470 next_key == 1);
471 assert(bpf_map_get_next_key(fd, &next_key, &next_key) < 0 &&
472 errno == ENOENT);
473
474 /* Delete shouldn't succeed. */
475 key = 1;
476 assert(bpf_map_delete_elem(fd, &key) < 0 && errno == EINVAL);
477
478 close(fd);
479 }
480
test_arraymap_percpu_many_keys(void)481 static void test_arraymap_percpu_many_keys(void)
482 {
483 unsigned int nr_cpus = bpf_num_possible_cpus();
484 BPF_DECLARE_PERCPU(long, values);
485 /* nr_keys is not too large otherwise the test stresses percpu
486 * allocator more than anything else
487 */
488 unsigned int nr_keys = 2000;
489 int key, fd, i;
490
491 fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, NULL, sizeof(key),
492 sizeof(bpf_percpu(values, 0)), nr_keys, NULL);
493 if (fd < 0) {
494 printf("Failed to create per-cpu arraymap '%s'!\n",
495 strerror(errno));
496 exit(1);
497 }
498
499 for (i = 0; i < nr_cpus; i++)
500 bpf_percpu(values, i) = i + 10;
501
502 for (key = 0; key < nr_keys; key++)
503 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
504
505 for (key = 0; key < nr_keys; key++) {
506 for (i = 0; i < nr_cpus; i++)
507 bpf_percpu(values, i) = 0;
508
509 assert(bpf_map_lookup_elem(fd, &key, values) == 0);
510
511 for (i = 0; i < nr_cpus; i++)
512 assert(bpf_percpu(values, i) == i + 10);
513 }
514
515 close(fd);
516 }
517
test_devmap(unsigned int task,void * data)518 static void test_devmap(unsigned int task, void *data)
519 {
520 int fd;
521 __u32 key, value;
522
523 fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP, NULL, sizeof(key), sizeof(value), 2, NULL);
524 if (fd < 0) {
525 printf("Failed to create devmap '%s'!\n", strerror(errno));
526 exit(1);
527 }
528
529 close(fd);
530 }
531
test_devmap_hash(unsigned int task,void * data)532 static void test_devmap_hash(unsigned int task, void *data)
533 {
534 int fd;
535 __u32 key, value;
536
537 fd = bpf_map_create(BPF_MAP_TYPE_DEVMAP_HASH, NULL, sizeof(key), sizeof(value), 2, NULL);
538 if (fd < 0) {
539 printf("Failed to create devmap_hash '%s'!\n", strerror(errno));
540 exit(1);
541 }
542
543 close(fd);
544 }
545
test_queuemap(unsigned int task,void * data)546 static void test_queuemap(unsigned int task, void *data)
547 {
548 const int MAP_SIZE = 32;
549 __u32 vals[MAP_SIZE + MAP_SIZE/2], val = 0;
550 int fd, i;
551
552 /* Fill test values to be used */
553 for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++)
554 vals[i] = rand();
555
556 /* Invalid key size */
557 fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 4, sizeof(val), MAP_SIZE, &map_opts);
558 assert(fd < 0 && errno == EINVAL);
559
560 fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0, sizeof(val), MAP_SIZE, &map_opts);
561 /* Queue map does not support BPF_F_NO_PREALLOC */
562 if (map_opts.map_flags & BPF_F_NO_PREALLOC) {
563 assert(fd < 0 && errno == EINVAL);
564 return;
565 }
566 if (fd < 0) {
567 printf("Failed to create queuemap '%s'!\n", strerror(errno));
568 exit(1);
569 }
570
571 /* Push MAP_SIZE elements */
572 for (i = 0; i < MAP_SIZE; i++)
573 assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0);
574
575 /* Check that element cannot be pushed due to max_entries limit */
576 assert(bpf_map_update_elem(fd, NULL, &val, 0) < 0 &&
577 errno == E2BIG);
578
579 /* Peek element */
580 assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[0]);
581
582 /* Replace half elements */
583 for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++)
584 assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0);
585
586 /* Pop all elements */
587 for (i = MAP_SIZE/2; i < MAP_SIZE + MAP_SIZE/2; i++)
588 assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 &&
589 val == vals[i]);
590
591 /* Check that there are not elements left */
592 assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) < 0 &&
593 errno == ENOENT);
594
595 /* Check that non supported functions set errno to EINVAL */
596 assert(bpf_map_delete_elem(fd, NULL) < 0 && errno == EINVAL);
597 assert(bpf_map_get_next_key(fd, NULL, NULL) < 0 && errno == EINVAL);
598
599 close(fd);
600 }
601
test_stackmap(unsigned int task,void * data)602 static void test_stackmap(unsigned int task, void *data)
603 {
604 const int MAP_SIZE = 32;
605 __u32 vals[MAP_SIZE + MAP_SIZE/2], val = 0;
606 int fd, i;
607
608 /* Fill test values to be used */
609 for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++)
610 vals[i] = rand();
611
612 /* Invalid key size */
613 fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 4, sizeof(val), MAP_SIZE, &map_opts);
614 assert(fd < 0 && errno == EINVAL);
615
616 fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL, 0, sizeof(val), MAP_SIZE, &map_opts);
617 /* Stack map does not support BPF_F_NO_PREALLOC */
618 if (map_opts.map_flags & BPF_F_NO_PREALLOC) {
619 assert(fd < 0 && errno == EINVAL);
620 return;
621 }
622 if (fd < 0) {
623 printf("Failed to create stackmap '%s'!\n", strerror(errno));
624 exit(1);
625 }
626
627 /* Push MAP_SIZE elements */
628 for (i = 0; i < MAP_SIZE; i++)
629 assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0);
630
631 /* Check that element cannot be pushed due to max_entries limit */
632 assert(bpf_map_update_elem(fd, NULL, &val, 0) < 0 &&
633 errno == E2BIG);
634
635 /* Peek element */
636 assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[i - 1]);
637
638 /* Replace half elements */
639 for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++)
640 assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0);
641
642 /* Pop all elements */
643 for (i = MAP_SIZE + MAP_SIZE/2 - 1; i >= MAP_SIZE/2; i--)
644 assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 &&
645 val == vals[i]);
646
647 /* Check that there are not elements left */
648 assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) < 0 &&
649 errno == ENOENT);
650
651 /* Check that non supported functions set errno to EINVAL */
652 assert(bpf_map_delete_elem(fd, NULL) < 0 && errno == EINVAL);
653 assert(bpf_map_get_next_key(fd, NULL, NULL) < 0 && errno == EINVAL);
654
655 close(fd);
656 }
657
658 #include <sys/ioctl.h>
659 #include <arpa/inet.h>
660 #include <sys/select.h>
661 #include <linux/err.h>
662 #define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.bpf.o"
663 #define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.bpf.o"
664 #define SOCKMAP_TCP_MSG_PROG "./sockmap_tcp_msg_prog.bpf.o"
test_sockmap(unsigned int tasks,void * data)665 static void test_sockmap(unsigned int tasks, void *data)
666 {
667 struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_msg, *bpf_map_break;
668 int map_fd_msg = 0, map_fd_rx = 0, map_fd_tx = 0, map_fd_break;
669 struct bpf_object *parse_obj, *verdict_obj, *msg_obj;
670 int ports[] = {50200, 50201, 50202, 50204};
671 int err, i, fd, udp, sfd[6] = {0xdeadbeef};
672 u8 buf[20] = {0x0, 0x5, 0x3, 0x2, 0x1, 0x0};
673 int parse_prog, verdict_prog, msg_prog;
674 struct sockaddr_in addr;
675 int one = 1, s, sc, rc;
676 struct timeval to;
677 __u32 key, value;
678 pid_t pid[tasks];
679 fd_set w;
680
681 /* Create some sockets to use with sockmap */
682 for (i = 0; i < 2; i++) {
683 sfd[i] = socket(AF_INET, SOCK_STREAM, 0);
684 if (sfd[i] < 0)
685 goto out;
686 err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR,
687 (char *)&one, sizeof(one));
688 if (err) {
689 printf("failed to setsockopt\n");
690 goto out;
691 }
692 err = ioctl(sfd[i], FIONBIO, (char *)&one);
693 if (err < 0) {
694 printf("failed to ioctl\n");
695 goto out;
696 }
697 memset(&addr, 0, sizeof(struct sockaddr_in));
698 addr.sin_family = AF_INET;
699 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
700 addr.sin_port = htons(ports[i]);
701 err = bind(sfd[i], (struct sockaddr *)&addr, sizeof(addr));
702 if (err < 0) {
703 printf("failed to bind: err %i: %i:%i\n",
704 err, i, sfd[i]);
705 goto out;
706 }
707 err = listen(sfd[i], 32);
708 if (err < 0) {
709 printf("failed to listen\n");
710 goto out;
711 }
712 }
713
714 for (i = 2; i < 4; i++) {
715 sfd[i] = socket(AF_INET, SOCK_STREAM, 0);
716 if (sfd[i] < 0)
717 goto out;
718 err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR,
719 (char *)&one, sizeof(one));
720 if (err) {
721 printf("set sock opt\n");
722 goto out;
723 }
724 memset(&addr, 0, sizeof(struct sockaddr_in));
725 addr.sin_family = AF_INET;
726 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
727 addr.sin_port = htons(ports[i - 2]);
728 err = connect(sfd[i], (struct sockaddr *)&addr, sizeof(addr));
729 if (err) {
730 printf("failed to connect\n");
731 goto out;
732 }
733 }
734
735
736 for (i = 4; i < 6; i++) {
737 sfd[i] = accept(sfd[i - 4], NULL, NULL);
738 if (sfd[i] < 0) {
739 printf("accept failed\n");
740 goto out;
741 }
742 }
743
744 /* Test sockmap with connected sockets */
745 fd = bpf_map_create(BPF_MAP_TYPE_SOCKMAP, NULL,
746 sizeof(key), sizeof(value),
747 6, NULL);
748 if (fd < 0) {
749 if (!libbpf_probe_bpf_map_type(BPF_MAP_TYPE_SOCKMAP, NULL)) {
750 printf("%s SKIP (unsupported map type BPF_MAP_TYPE_SOCKMAP)\n",
751 __func__);
752 skips++;
753 for (i = 0; i < 6; i++)
754 close(sfd[i]);
755 return;
756 }
757
758 printf("Failed to create sockmap %i\n", fd);
759 goto out_sockmap;
760 }
761
762 /* Test update with unsupported unbound UDP socket */
763 udp = socket(AF_INET, SOCK_DGRAM, 0);
764 CHECK(udp < 0, "socket(AF_INET, SOCK_DGRAM)", "errno:%d\n", errno);
765 err = bpf_map_update_elem(fd, &(int){0}, &udp, BPF_ANY);
766 close(udp);
767 if (!err) {
768 printf("Unexpectedly succeeded unbound UDP update '0:%i'\n", udp);
769 goto out_sockmap;
770 }
771
772 /* Test update without programs */
773 for (i = 0; i < 6; i++) {
774 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
775 if (err) {
776 printf("Failed noprog update sockmap '%i:%i'\n",
777 i, sfd[i]);
778 goto out_sockmap;
779 }
780 }
781
782 /* Test attaching/detaching bad fds */
783 err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0);
784 if (!err) {
785 printf("Failed invalid parser prog attach\n");
786 goto out_sockmap;
787 }
788
789 err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_VERDICT, 0);
790 if (!err) {
791 printf("Failed invalid verdict prog attach\n");
792 goto out_sockmap;
793 }
794
795 err = bpf_prog_attach(-1, fd, BPF_SK_MSG_VERDICT, 0);
796 if (!err) {
797 printf("Failed invalid msg verdict prog attach\n");
798 goto out_sockmap;
799 }
800
801 err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0);
802 if (!err) {
803 printf("Failed unknown prog attach\n");
804 goto out_sockmap;
805 }
806
807 err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER);
808 if (!err) {
809 printf("Failed empty parser prog detach\n");
810 goto out_sockmap;
811 }
812
813 err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT);
814 if (!err) {
815 printf("Failed empty verdict prog detach\n");
816 goto out_sockmap;
817 }
818
819 err = bpf_prog_detach(fd, BPF_SK_MSG_VERDICT);
820 if (!err) {
821 printf("Failed empty msg verdict prog detach\n");
822 goto out_sockmap;
823 }
824
825 err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE);
826 if (!err) {
827 printf("Detach invalid prog successful\n");
828 goto out_sockmap;
829 }
830
831 /* Load SK_SKB program and Attach */
832 err = bpf_prog_test_load(SOCKMAP_PARSE_PROG,
833 BPF_PROG_TYPE_SK_SKB, &parse_obj, &parse_prog);
834 if (err) {
835 printf("Failed to load SK_SKB parse prog\n");
836 goto out_sockmap;
837 }
838
839 err = bpf_prog_test_load(SOCKMAP_TCP_MSG_PROG,
840 BPF_PROG_TYPE_SK_MSG, &msg_obj, &msg_prog);
841 if (err) {
842 printf("Failed to load SK_SKB msg prog\n");
843 goto out_sockmap;
844 }
845
846 err = bpf_prog_test_load(SOCKMAP_VERDICT_PROG,
847 BPF_PROG_TYPE_SK_SKB, &verdict_obj, &verdict_prog);
848 if (err) {
849 printf("Failed to load SK_SKB verdict prog\n");
850 goto out_sockmap;
851 }
852
853 bpf_map_rx = bpf_object__find_map_by_name(verdict_obj, "sock_map_rx");
854 if (!bpf_map_rx) {
855 printf("Failed to load map rx from verdict prog\n");
856 goto out_sockmap;
857 }
858
859 map_fd_rx = bpf_map__fd(bpf_map_rx);
860 if (map_fd_rx < 0) {
861 printf("Failed to get map rx fd\n");
862 goto out_sockmap;
863 }
864
865 bpf_map_tx = bpf_object__find_map_by_name(verdict_obj, "sock_map_tx");
866 if (!bpf_map_tx) {
867 printf("Failed to load map tx from verdict prog\n");
868 goto out_sockmap;
869 }
870
871 map_fd_tx = bpf_map__fd(bpf_map_tx);
872 if (map_fd_tx < 0) {
873 printf("Failed to get map tx fd\n");
874 goto out_sockmap;
875 }
876
877 bpf_map_msg = bpf_object__find_map_by_name(verdict_obj, "sock_map_msg");
878 if (!bpf_map_msg) {
879 printf("Failed to load map msg from msg_verdict prog\n");
880 goto out_sockmap;
881 }
882
883 map_fd_msg = bpf_map__fd(bpf_map_msg);
884 if (map_fd_msg < 0) {
885 printf("Failed to get map msg fd\n");
886 goto out_sockmap;
887 }
888
889 bpf_map_break = bpf_object__find_map_by_name(verdict_obj, "sock_map_break");
890 if (!bpf_map_break) {
891 printf("Failed to load map tx from verdict prog\n");
892 goto out_sockmap;
893 }
894
895 map_fd_break = bpf_map__fd(bpf_map_break);
896 if (map_fd_break < 0) {
897 printf("Failed to get map tx fd\n");
898 goto out_sockmap;
899 }
900
901 err = bpf_prog_attach(parse_prog, map_fd_break,
902 BPF_SK_SKB_STREAM_PARSER, 0);
903 if (!err) {
904 printf("Allowed attaching SK_SKB program to invalid map\n");
905 goto out_sockmap;
906 }
907
908 err = bpf_prog_attach(parse_prog, map_fd_rx,
909 BPF_SK_SKB_STREAM_PARSER, 0);
910 if (err) {
911 printf("Failed stream parser bpf prog attach\n");
912 goto out_sockmap;
913 }
914
915 err = bpf_prog_attach(verdict_prog, map_fd_rx,
916 BPF_SK_SKB_STREAM_VERDICT, 0);
917 if (err) {
918 printf("Failed stream verdict bpf prog attach\n");
919 goto out_sockmap;
920 }
921
922 err = bpf_prog_attach(msg_prog, map_fd_msg, BPF_SK_MSG_VERDICT, 0);
923 if (err) {
924 printf("Failed msg verdict bpf prog attach\n");
925 goto out_sockmap;
926 }
927
928 err = bpf_prog_attach(verdict_prog, map_fd_rx,
929 __MAX_BPF_ATTACH_TYPE, 0);
930 if (!err) {
931 printf("Attached unknown bpf prog\n");
932 goto out_sockmap;
933 }
934
935 /* Test map update elem afterwards fd lives in fd and map_fd */
936 for (i = 2; i < 6; i++) {
937 err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY);
938 if (err) {
939 printf("Failed map_fd_rx update sockmap %i '%i:%i'\n",
940 err, i, sfd[i]);
941 goto out_sockmap;
942 }
943 err = bpf_map_update_elem(map_fd_tx, &i, &sfd[i], BPF_ANY);
944 if (err) {
945 printf("Failed map_fd_tx update sockmap %i '%i:%i'\n",
946 err, i, sfd[i]);
947 goto out_sockmap;
948 }
949 }
950
951 /* Test map delete elem and remove send/recv sockets */
952 for (i = 2; i < 4; i++) {
953 err = bpf_map_delete_elem(map_fd_rx, &i);
954 if (err) {
955 printf("Failed delete sockmap rx %i '%i:%i'\n",
956 err, i, sfd[i]);
957 goto out_sockmap;
958 }
959 err = bpf_map_delete_elem(map_fd_tx, &i);
960 if (err) {
961 printf("Failed delete sockmap tx %i '%i:%i'\n",
962 err, i, sfd[i]);
963 goto out_sockmap;
964 }
965 }
966
967 /* Put sfd[2] (sending fd below) into msg map to test sendmsg bpf */
968 i = 0;
969 err = bpf_map_update_elem(map_fd_msg, &i, &sfd[2], BPF_ANY);
970 if (err) {
971 printf("Failed map_fd_msg update sockmap %i\n", err);
972 goto out_sockmap;
973 }
974
975 /* Test map send/recv */
976 for (i = 0; i < 2; i++) {
977 buf[0] = i;
978 buf[1] = 0x5;
979 sc = send(sfd[2], buf, 20, 0);
980 if (sc < 0) {
981 printf("Failed sockmap send\n");
982 goto out_sockmap;
983 }
984
985 FD_ZERO(&w);
986 FD_SET(sfd[3], &w);
987 to.tv_sec = 30;
988 to.tv_usec = 0;
989 s = select(sfd[3] + 1, &w, NULL, NULL, &to);
990 if (s == -1) {
991 perror("Failed sockmap select()");
992 goto out_sockmap;
993 } else if (!s) {
994 printf("Failed sockmap unexpected timeout\n");
995 goto out_sockmap;
996 }
997
998 if (!FD_ISSET(sfd[3], &w)) {
999 printf("Failed sockmap select/recv\n");
1000 goto out_sockmap;
1001 }
1002
1003 rc = recv(sfd[3], buf, sizeof(buf), 0);
1004 if (rc < 0) {
1005 printf("Failed sockmap recv\n");
1006 goto out_sockmap;
1007 }
1008 }
1009
1010 /* Negative null entry lookup from datapath should be dropped */
1011 buf[0] = 1;
1012 buf[1] = 12;
1013 sc = send(sfd[2], buf, 20, 0);
1014 if (sc < 0) {
1015 printf("Failed sockmap send\n");
1016 goto out_sockmap;
1017 }
1018
1019 /* Push fd into same slot */
1020 i = 2;
1021 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST);
1022 if (!err) {
1023 printf("Failed allowed sockmap dup slot BPF_NOEXIST\n");
1024 goto out_sockmap;
1025 }
1026
1027 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
1028 if (err) {
1029 printf("Failed sockmap update new slot BPF_ANY\n");
1030 goto out_sockmap;
1031 }
1032
1033 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST);
1034 if (err) {
1035 printf("Failed sockmap update new slot BPF_EXIST\n");
1036 goto out_sockmap;
1037 }
1038
1039 /* Delete the elems without programs */
1040 for (i = 2; i < 6; i++) {
1041 err = bpf_map_delete_elem(fd, &i);
1042 if (err) {
1043 printf("Failed delete sockmap %i '%i:%i'\n",
1044 err, i, sfd[i]);
1045 }
1046 }
1047
1048 /* Test having multiple maps open and set with programs on same fds */
1049 err = bpf_prog_attach(parse_prog, fd,
1050 BPF_SK_SKB_STREAM_PARSER, 0);
1051 if (err) {
1052 printf("Failed fd bpf parse prog attach\n");
1053 goto out_sockmap;
1054 }
1055 err = bpf_prog_attach(verdict_prog, fd,
1056 BPF_SK_SKB_STREAM_VERDICT, 0);
1057 if (err) {
1058 printf("Failed fd bpf verdict prog attach\n");
1059 goto out_sockmap;
1060 }
1061
1062 for (i = 4; i < 6; i++) {
1063 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY);
1064 if (!err) {
1065 printf("Failed allowed duplicate programs in update ANY sockmap %i '%i:%i'\n",
1066 err, i, sfd[i]);
1067 goto out_sockmap;
1068 }
1069 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST);
1070 if (!err) {
1071 printf("Failed allowed duplicate program in update NOEXIST sockmap %i '%i:%i'\n",
1072 err, i, sfd[i]);
1073 goto out_sockmap;
1074 }
1075 err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST);
1076 if (!err) {
1077 printf("Failed allowed duplicate program in update EXIST sockmap %i '%i:%i'\n",
1078 err, i, sfd[i]);
1079 goto out_sockmap;
1080 }
1081 }
1082
1083 /* Test tasks number of forked operations */
1084 for (i = 0; i < tasks; i++) {
1085 pid[i] = fork();
1086 if (pid[i] == 0) {
1087 for (i = 0; i < 6; i++) {
1088 bpf_map_delete_elem(map_fd_tx, &i);
1089 bpf_map_delete_elem(map_fd_rx, &i);
1090 bpf_map_update_elem(map_fd_tx, &i,
1091 &sfd[i], BPF_ANY);
1092 bpf_map_update_elem(map_fd_rx, &i,
1093 &sfd[i], BPF_ANY);
1094 }
1095 exit(0);
1096 } else if (pid[i] == -1) {
1097 printf("Couldn't spawn #%d process!\n", i);
1098 exit(1);
1099 }
1100 }
1101
1102 for (i = 0; i < tasks; i++) {
1103 int status;
1104
1105 assert(waitpid(pid[i], &status, 0) == pid[i]);
1106 assert(status == 0);
1107 }
1108
1109 err = bpf_prog_detach2(parse_prog, map_fd_rx, __MAX_BPF_ATTACH_TYPE);
1110 if (!err) {
1111 printf("Detached an invalid prog type.\n");
1112 goto out_sockmap;
1113 }
1114
1115 err = bpf_prog_detach2(parse_prog, map_fd_rx, BPF_SK_SKB_STREAM_PARSER);
1116 if (err) {
1117 printf("Failed parser prog detach\n");
1118 goto out_sockmap;
1119 }
1120
1121 err = bpf_prog_detach2(verdict_prog, map_fd_rx, BPF_SK_SKB_STREAM_VERDICT);
1122 if (err) {
1123 printf("Failed parser prog detach\n");
1124 goto out_sockmap;
1125 }
1126
1127 /* Test map close sockets and empty maps */
1128 for (i = 0; i < 6; i++) {
1129 bpf_map_delete_elem(map_fd_tx, &i);
1130 bpf_map_delete_elem(map_fd_rx, &i);
1131 close(sfd[i]);
1132 }
1133 close(fd);
1134 close(map_fd_rx);
1135 bpf_object__close(parse_obj);
1136 bpf_object__close(msg_obj);
1137 bpf_object__close(verdict_obj);
1138 return;
1139 out:
1140 for (i = 0; i < 6; i++)
1141 close(sfd[i]);
1142 printf("Failed to create sockmap '%i:%s'!\n", i, strerror(errno));
1143 exit(1);
1144 out_sockmap:
1145 for (i = 0; i < 6; i++) {
1146 if (map_fd_tx)
1147 bpf_map_delete_elem(map_fd_tx, &i);
1148 if (map_fd_rx)
1149 bpf_map_delete_elem(map_fd_rx, &i);
1150 close(sfd[i]);
1151 }
1152 close(fd);
1153 exit(1);
1154 }
1155
1156 #define MAPINMAP_PROG "./test_map_in_map.bpf.o"
1157 #define MAPINMAP_INVALID_PROG "./test_map_in_map_invalid.bpf.o"
test_map_in_map(void)1158 static void test_map_in_map(void)
1159 {
1160 struct bpf_object *obj;
1161 struct bpf_map *map;
1162 int mim_fd, fd, err;
1163 int pos = 0;
1164 struct bpf_map_info info = {};
1165 __u32 len = sizeof(info);
1166 __u32 id = 0;
1167 libbpf_print_fn_t old_print_fn;
1168
1169 obj = bpf_object__open(MAPINMAP_PROG);
1170
1171 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(int), sizeof(int), 2, NULL);
1172 if (fd < 0) {
1173 printf("Failed to create hashmap '%s'!\n", strerror(errno));
1174 exit(1);
1175 }
1176
1177 map = bpf_object__find_map_by_name(obj, "mim_array");
1178 if (!map) {
1179 printf("Failed to load array of maps from test prog\n");
1180 goto out_map_in_map;
1181 }
1182 err = bpf_map__set_inner_map_fd(map, fd);
1183 if (err) {
1184 printf("Failed to set inner_map_fd for array of maps\n");
1185 goto out_map_in_map;
1186 }
1187
1188 map = bpf_object__find_map_by_name(obj, "mim_hash");
1189 if (!map) {
1190 printf("Failed to load hash of maps from test prog\n");
1191 goto out_map_in_map;
1192 }
1193 err = bpf_map__set_inner_map_fd(map, fd);
1194 if (err) {
1195 printf("Failed to set inner_map_fd for hash of maps\n");
1196 goto out_map_in_map;
1197 }
1198
1199 err = bpf_object__load(obj);
1200 if (err) {
1201 printf("Failed to load test prog\n");
1202 goto out_map_in_map;
1203 }
1204
1205 map = bpf_object__find_map_by_name(obj, "mim_array");
1206 if (!map) {
1207 printf("Failed to load array of maps from test prog\n");
1208 goto out_map_in_map;
1209 }
1210 mim_fd = bpf_map__fd(map);
1211 if (mim_fd < 0) {
1212 printf("Failed to get descriptor for array of maps\n");
1213 goto out_map_in_map;
1214 }
1215
1216 err = bpf_map_update_elem(mim_fd, &pos, &fd, 0);
1217 if (err) {
1218 printf("Failed to update array of maps\n");
1219 goto out_map_in_map;
1220 }
1221
1222 map = bpf_object__find_map_by_name(obj, "mim_hash");
1223 if (!map) {
1224 printf("Failed to load hash of maps from test prog\n");
1225 goto out_map_in_map;
1226 }
1227 mim_fd = bpf_map__fd(map);
1228 if (mim_fd < 0) {
1229 printf("Failed to get descriptor for hash of maps\n");
1230 goto out_map_in_map;
1231 }
1232
1233 err = bpf_map_update_elem(mim_fd, &pos, &fd, 0);
1234 if (err) {
1235 printf("Failed to update hash of maps\n");
1236 goto out_map_in_map;
1237 }
1238
1239 close(fd);
1240 fd = -1;
1241 bpf_object__close(obj);
1242
1243 /* Test that failing bpf_object__create_map() destroys the inner map */
1244 obj = bpf_object__open(MAPINMAP_INVALID_PROG);
1245 err = libbpf_get_error(obj);
1246 if (err) {
1247 printf("Failed to load %s program: %d %d",
1248 MAPINMAP_INVALID_PROG, err, errno);
1249 goto out_map_in_map;
1250 }
1251
1252 map = bpf_object__find_map_by_name(obj, "mim");
1253 if (!map) {
1254 printf("Failed to load array of maps from test prog\n");
1255 goto out_map_in_map;
1256 }
1257
1258 old_print_fn = libbpf_set_print(NULL);
1259
1260 err = bpf_object__load(obj);
1261 if (!err) {
1262 printf("Loading obj supposed to fail\n");
1263 goto out_map_in_map;
1264 }
1265
1266 libbpf_set_print(old_print_fn);
1267
1268 /* Iterate over all maps to check whether the internal map
1269 * ("mim.internal") has been destroyed.
1270 */
1271 while (true) {
1272 err = bpf_map_get_next_id(id, &id);
1273 if (err) {
1274 if (errno == ENOENT)
1275 break;
1276 printf("Failed to get next map: %d", errno);
1277 goto out_map_in_map;
1278 }
1279
1280 fd = bpf_map_get_fd_by_id(id);
1281 if (fd < 0) {
1282 if (errno == ENOENT)
1283 continue;
1284 printf("Failed to get map by id %u: %d", id, errno);
1285 goto out_map_in_map;
1286 }
1287
1288 err = bpf_map_get_info_by_fd(fd, &info, &len);
1289 if (err) {
1290 printf("Failed to get map info by fd %d: %d", fd,
1291 errno);
1292 goto out_map_in_map;
1293 }
1294
1295 if (!strcmp(info.name, "mim.inner")) {
1296 printf("Inner map mim.inner was not destroyed\n");
1297 goto out_map_in_map;
1298 }
1299
1300 close(fd);
1301 }
1302
1303 bpf_object__close(obj);
1304 return;
1305
1306 out_map_in_map:
1307 if (fd >= 0)
1308 close(fd);
1309 exit(1);
1310 }
1311
1312 #define MAP_SIZE (32 * 1024)
1313
test_map_large(void)1314 static void test_map_large(void)
1315 {
1316
1317 struct bigkey {
1318 int a;
1319 char b[4096];
1320 long long c;
1321 } key;
1322 int fd, i, value;
1323
1324 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
1325 MAP_SIZE, &map_opts);
1326 if (fd < 0) {
1327 printf("Failed to create large map '%s'!\n", strerror(errno));
1328 exit(1);
1329 }
1330
1331 for (i = 0; i < MAP_SIZE; i++) {
1332 key = (struct bigkey) { .c = i };
1333 value = i;
1334
1335 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
1336 }
1337
1338 key.c = -1;
1339 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
1340 errno == E2BIG);
1341
1342 /* Iterate through all elements. */
1343 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
1344 key.c = -1;
1345 for (i = 0; i < MAP_SIZE; i++)
1346 assert(bpf_map_get_next_key(fd, &key, &key) == 0);
1347 assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT);
1348
1349 key.c = 0;
1350 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0);
1351 key.a = 1;
1352 assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT);
1353
1354 close(fd);
1355 }
1356
1357 #define run_parallel(N, FN, DATA) \
1358 printf("Fork %u tasks to '" #FN "'\n", N); \
1359 __run_parallel(N, FN, DATA)
1360
__run_parallel(unsigned int tasks,void (* fn)(unsigned int task,void * data),void * data)1361 static void __run_parallel(unsigned int tasks,
1362 void (*fn)(unsigned int task, void *data),
1363 void *data)
1364 {
1365 pid_t pid[tasks];
1366 int i;
1367
1368 fflush(stdout);
1369
1370 for (i = 0; i < tasks; i++) {
1371 pid[i] = fork();
1372 if (pid[i] == 0) {
1373 fn(i, data);
1374 exit(0);
1375 } else if (pid[i] == -1) {
1376 printf("Couldn't spawn #%d process!\n", i);
1377 exit(1);
1378 }
1379 }
1380
1381 for (i = 0; i < tasks; i++) {
1382 int status;
1383
1384 assert(waitpid(pid[i], &status, 0) == pid[i]);
1385 assert(status == 0);
1386 }
1387 }
1388
test_map_stress(void)1389 static void test_map_stress(void)
1390 {
1391 run_parallel(100, test_hashmap_walk, NULL);
1392 run_parallel(100, test_hashmap, NULL);
1393 run_parallel(100, test_hashmap_percpu, NULL);
1394 run_parallel(100, test_hashmap_sizes, NULL);
1395
1396 run_parallel(100, test_arraymap, NULL);
1397 run_parallel(100, test_arraymap_percpu, NULL);
1398 }
1399
1400 #define TASKS 100
1401
1402 #define DO_UPDATE 1
1403 #define DO_DELETE 0
1404
1405 #define MAX_DELAY_US 50000
1406 #define MIN_DELAY_RANGE_US 5000
1407
map_update_retriable(int map_fd,const void * key,const void * value,int flags,int attempts,retry_for_error_fn need_retry)1408 int map_update_retriable(int map_fd, const void *key, const void *value, int flags, int attempts,
1409 retry_for_error_fn need_retry)
1410 {
1411 int delay = rand() % MIN_DELAY_RANGE_US;
1412
1413 while (bpf_map_update_elem(map_fd, key, value, flags)) {
1414 if (!attempts || !need_retry(errno))
1415 return -errno;
1416
1417 if (delay <= MAX_DELAY_US / 2)
1418 delay *= 2;
1419
1420 usleep(delay);
1421 attempts--;
1422 }
1423
1424 return 0;
1425 }
1426
map_delete_retriable(int map_fd,const void * key,int attempts)1427 static int map_delete_retriable(int map_fd, const void *key, int attempts)
1428 {
1429 int delay = rand() % MIN_DELAY_RANGE_US;
1430
1431 while (bpf_map_delete_elem(map_fd, key)) {
1432 if (!attempts || (errno != EAGAIN && errno != EBUSY))
1433 return -errno;
1434
1435 if (delay <= MAX_DELAY_US / 2)
1436 delay *= 2;
1437
1438 usleep(delay);
1439 attempts--;
1440 }
1441
1442 return 0;
1443 }
1444
test_update_delete(unsigned int fn,void * data)1445 static void test_update_delete(unsigned int fn, void *data)
1446 {
1447 int do_update = ((int *)data)[1];
1448 int fd = ((int *)data)[0];
1449 int i, key, value, err;
1450
1451 if (fn & 1)
1452 test_hashmap_walk(fn, NULL);
1453 for (i = fn; i < MAP_SIZE; i += TASKS) {
1454 key = value = i;
1455
1456 if (do_update) {
1457 err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES,
1458 can_retry);
1459 if (err)
1460 printf("error %d %d\n", err, errno);
1461 assert(err == 0);
1462 err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES,
1463 can_retry);
1464 if (err)
1465 printf("error %d %d\n", err, errno);
1466 assert(err == 0);
1467 } else {
1468 err = map_delete_retriable(fd, &key, MAP_RETRIES);
1469 if (err)
1470 printf("error %d %d\n", err, errno);
1471 assert(err == 0);
1472 }
1473 }
1474 }
1475
test_map_parallel(void)1476 static void test_map_parallel(void)
1477 {
1478 int i, fd, key = 0, value = 0, j = 0;
1479 int data[2];
1480
1481 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
1482 MAP_SIZE, &map_opts);
1483 if (fd < 0) {
1484 printf("Failed to create map for parallel test '%s'!\n",
1485 strerror(errno));
1486 exit(1);
1487 }
1488
1489 again:
1490 /* Use the same fd in children to add elements to this map:
1491 * child_0 adds key=0, key=1024, key=2048, ...
1492 * child_1 adds key=1, key=1025, key=2049, ...
1493 * child_1023 adds key=1023, ...
1494 */
1495 data[0] = fd;
1496 data[1] = DO_UPDATE;
1497 run_parallel(TASKS, test_update_delete, data);
1498
1499 /* Check that key=0 is already there. */
1500 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) < 0 &&
1501 errno == EEXIST);
1502
1503 /* Check that all elements were inserted. */
1504 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
1505 key = -1;
1506 for (i = 0; i < MAP_SIZE; i++)
1507 assert(bpf_map_get_next_key(fd, &key, &key) == 0);
1508 assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT);
1509
1510 /* Another check for all elements */
1511 for (i = 0; i < MAP_SIZE; i++) {
1512 key = MAP_SIZE - i - 1;
1513
1514 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 &&
1515 value == key);
1516 }
1517
1518 /* Now let's delete all elements in parallel. */
1519 data[1] = DO_DELETE;
1520 run_parallel(TASKS, test_update_delete, data);
1521
1522 /* Nothing should be left. */
1523 key = -1;
1524 assert(bpf_map_get_next_key(fd, NULL, &key) < 0 && errno == ENOENT);
1525 assert(bpf_map_get_next_key(fd, &key, &key) < 0 && errno == ENOENT);
1526
1527 key = 0;
1528 bpf_map_delete_elem(fd, &key);
1529 if (j++ < 5)
1530 goto again;
1531 close(fd);
1532 }
1533
test_map_rdonly(void)1534 static void test_map_rdonly(void)
1535 {
1536 int fd, key = 0, value = 0;
1537 __u32 old_flags;
1538
1539 old_flags = map_opts.map_flags;
1540 map_opts.map_flags |= BPF_F_RDONLY;
1541 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
1542 MAP_SIZE, &map_opts);
1543 map_opts.map_flags = old_flags;
1544 if (fd < 0) {
1545 printf("Failed to create map for read only test '%s'!\n",
1546 strerror(errno));
1547 exit(1);
1548 }
1549
1550 key = 1;
1551 value = 1234;
1552 /* Try to insert key=1 element. */
1553 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) < 0 &&
1554 errno == EPERM);
1555
1556 /* Check that key=1 is not found. */
1557 assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == ENOENT);
1558 assert(bpf_map_get_next_key(fd, &key, &value) < 0 && errno == ENOENT);
1559
1560 close(fd);
1561 }
1562
test_map_wronly_hash(void)1563 static void test_map_wronly_hash(void)
1564 {
1565 int fd, key = 0, value = 0;
1566 __u32 old_flags;
1567
1568 old_flags = map_opts.map_flags;
1569 map_opts.map_flags |= BPF_F_WRONLY;
1570 fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(key), sizeof(value),
1571 MAP_SIZE, &map_opts);
1572 map_opts.map_flags = old_flags;
1573 if (fd < 0) {
1574 printf("Failed to create map for write only test '%s'!\n",
1575 strerror(errno));
1576 exit(1);
1577 }
1578
1579 key = 1;
1580 value = 1234;
1581 /* Insert key=1 element. */
1582 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
1583
1584 /* Check that reading elements and keys from the map is not allowed. */
1585 assert(bpf_map_lookup_elem(fd, &key, &value) < 0 && errno == EPERM);
1586 assert(bpf_map_get_next_key(fd, &key, &value) < 0 && errno == EPERM);
1587
1588 close(fd);
1589 }
1590
test_map_wronly_stack_or_queue(enum bpf_map_type map_type)1591 static void test_map_wronly_stack_or_queue(enum bpf_map_type map_type)
1592 {
1593 int fd, value = 0;
1594 __u32 old_flags;
1595
1596
1597 assert(map_type == BPF_MAP_TYPE_QUEUE ||
1598 map_type == BPF_MAP_TYPE_STACK);
1599 old_flags = map_opts.map_flags;
1600 map_opts.map_flags |= BPF_F_WRONLY;
1601 fd = bpf_map_create(map_type, NULL, 0, sizeof(value), MAP_SIZE, &map_opts);
1602 map_opts.map_flags = old_flags;
1603 /* Stack/Queue maps do not support BPF_F_NO_PREALLOC */
1604 if (map_opts.map_flags & BPF_F_NO_PREALLOC) {
1605 assert(fd < 0 && errno == EINVAL);
1606 return;
1607 }
1608 if (fd < 0) {
1609 printf("Failed to create map '%s'!\n", strerror(errno));
1610 exit(1);
1611 }
1612
1613 value = 1234;
1614 assert(bpf_map_update_elem(fd, NULL, &value, BPF_ANY) == 0);
1615
1616 /* Peek element should fail */
1617 assert(bpf_map_lookup_elem(fd, NULL, &value) < 0 && errno == EPERM);
1618
1619 /* Pop element should fail */
1620 assert(bpf_map_lookup_and_delete_elem(fd, NULL, &value) < 0 &&
1621 errno == EPERM);
1622
1623 close(fd);
1624 }
1625
test_map_wronly(void)1626 static void test_map_wronly(void)
1627 {
1628 test_map_wronly_hash();
1629 test_map_wronly_stack_or_queue(BPF_MAP_TYPE_STACK);
1630 test_map_wronly_stack_or_queue(BPF_MAP_TYPE_QUEUE);
1631 }
1632
prepare_reuseport_grp(int type,int map_fd,size_t map_elem_size,__s64 * fds64,__u64 * sk_cookies,unsigned int n)1633 static void prepare_reuseport_grp(int type, int map_fd, size_t map_elem_size,
1634 __s64 *fds64, __u64 *sk_cookies,
1635 unsigned int n)
1636 {
1637 socklen_t optlen, addrlen;
1638 struct sockaddr_in6 s6;
1639 const __u32 index0 = 0;
1640 const int optval = 1;
1641 unsigned int i;
1642 u64 sk_cookie;
1643 void *value;
1644 __s32 fd32;
1645 __s64 fd64;
1646 int err;
1647
1648 s6.sin6_family = AF_INET6;
1649 s6.sin6_addr = in6addr_any;
1650 s6.sin6_port = 0;
1651 addrlen = sizeof(s6);
1652 optlen = sizeof(sk_cookie);
1653
1654 for (i = 0; i < n; i++) {
1655 fd64 = socket(AF_INET6, type, 0);
1656 CHECK(fd64 == -1, "socket()",
1657 "sock_type:%d fd64:%lld errno:%d\n",
1658 type, fd64, errno);
1659
1660 err = setsockopt(fd64, SOL_SOCKET, SO_REUSEPORT,
1661 &optval, sizeof(optval));
1662 CHECK(err == -1, "setsockopt(SO_REUSEPORT)",
1663 "err:%d errno:%d\n", err, errno);
1664
1665 /* reuseport_array does not allow unbound sk */
1666 if (map_elem_size == sizeof(__u64))
1667 value = &fd64;
1668 else {
1669 assert(map_elem_size == sizeof(__u32));
1670 fd32 = (__s32)fd64;
1671 value = &fd32;
1672 }
1673 err = bpf_map_update_elem(map_fd, &index0, value, BPF_ANY);
1674 CHECK(err >= 0 || errno != EINVAL,
1675 "reuseport array update unbound sk",
1676 "sock_type:%d err:%d errno:%d\n",
1677 type, err, errno);
1678
1679 err = bind(fd64, (struct sockaddr *)&s6, sizeof(s6));
1680 CHECK(err == -1, "bind()",
1681 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1682
1683 if (i == 0) {
1684 err = getsockname(fd64, (struct sockaddr *)&s6,
1685 &addrlen);
1686 CHECK(err == -1, "getsockname()",
1687 "sock_type:%d err:%d errno:%d\n",
1688 type, err, errno);
1689 }
1690
1691 err = getsockopt(fd64, SOL_SOCKET, SO_COOKIE, &sk_cookie,
1692 &optlen);
1693 CHECK(err == -1, "getsockopt(SO_COOKIE)",
1694 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1695
1696 if (type == SOCK_STREAM) {
1697 /*
1698 * reuseport_array does not allow
1699 * non-listening tcp sk.
1700 */
1701 err = bpf_map_update_elem(map_fd, &index0, value,
1702 BPF_ANY);
1703 CHECK(err >= 0 || errno != EINVAL,
1704 "reuseport array update non-listening sk",
1705 "sock_type:%d err:%d errno:%d\n",
1706 type, err, errno);
1707 err = listen(fd64, 0);
1708 CHECK(err == -1, "listen()",
1709 "sock_type:%d, err:%d errno:%d\n",
1710 type, err, errno);
1711 }
1712
1713 fds64[i] = fd64;
1714 sk_cookies[i] = sk_cookie;
1715 }
1716 }
1717
test_reuseport_array(void)1718 static void test_reuseport_array(void)
1719 {
1720 #define REUSEPORT_FD_IDX(err, last) ({ (err) ? last : !last; })
1721
1722 const __u32 array_size = 4, index0 = 0, index3 = 3;
1723 int types[2] = { SOCK_STREAM, SOCK_DGRAM }, type;
1724 __u64 grpa_cookies[2], sk_cookie, map_cookie;
1725 __s64 grpa_fds64[2] = { -1, -1 }, fd64 = -1;
1726 const __u32 bad_index = array_size;
1727 int map_fd, err, t, f;
1728 __u32 fds_idx = 0;
1729 int fd;
1730
1731 map_fd = bpf_map_create(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, NULL,
1732 sizeof(__u32), sizeof(__u64), array_size, NULL);
1733 CHECK(map_fd < 0, "reuseport array create",
1734 "map_fd:%d, errno:%d\n", map_fd, errno);
1735
1736 /* Test lookup/update/delete with invalid index */
1737 err = bpf_map_delete_elem(map_fd, &bad_index);
1738 CHECK(err >= 0 || errno != E2BIG, "reuseport array del >=max_entries",
1739 "err:%d errno:%d\n", err, errno);
1740
1741 err = bpf_map_update_elem(map_fd, &bad_index, &fd64, BPF_ANY);
1742 CHECK(err >= 0 || errno != E2BIG,
1743 "reuseport array update >=max_entries",
1744 "err:%d errno:%d\n", err, errno);
1745
1746 err = bpf_map_lookup_elem(map_fd, &bad_index, &map_cookie);
1747 CHECK(err >= 0 || errno != ENOENT,
1748 "reuseport array update >=max_entries",
1749 "err:%d errno:%d\n", err, errno);
1750
1751 /* Test lookup/delete non existence elem */
1752 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1753 CHECK(err >= 0 || errno != ENOENT,
1754 "reuseport array lookup not-exist elem",
1755 "err:%d errno:%d\n", err, errno);
1756 err = bpf_map_delete_elem(map_fd, &index3);
1757 CHECK(err >= 0 || errno != ENOENT,
1758 "reuseport array del not-exist elem",
1759 "err:%d errno:%d\n", err, errno);
1760
1761 for (t = 0; t < ARRAY_SIZE(types); t++) {
1762 type = types[t];
1763
1764 prepare_reuseport_grp(type, map_fd, sizeof(__u64), grpa_fds64,
1765 grpa_cookies, ARRAY_SIZE(grpa_fds64));
1766
1767 /* Test BPF_* update flags */
1768 /* BPF_EXIST failure case */
1769 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1770 BPF_EXIST);
1771 CHECK(err >= 0 || errno != ENOENT,
1772 "reuseport array update empty elem BPF_EXIST",
1773 "sock_type:%d err:%d errno:%d\n",
1774 type, err, errno);
1775 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1776
1777 /* BPF_NOEXIST success case */
1778 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1779 BPF_NOEXIST);
1780 CHECK(err < 0,
1781 "reuseport array update empty elem BPF_NOEXIST",
1782 "sock_type:%d err:%d errno:%d\n",
1783 type, err, errno);
1784 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1785
1786 /* BPF_EXIST success case. */
1787 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1788 BPF_EXIST);
1789 CHECK(err < 0,
1790 "reuseport array update same elem BPF_EXIST",
1791 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1792 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1793
1794 /* BPF_NOEXIST failure case */
1795 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1796 BPF_NOEXIST);
1797 CHECK(err >= 0 || errno != EEXIST,
1798 "reuseport array update non-empty elem BPF_NOEXIST",
1799 "sock_type:%d err:%d errno:%d\n",
1800 type, err, errno);
1801 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1802
1803 /* BPF_ANY case (always succeed) */
1804 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1805 BPF_ANY);
1806 CHECK(err < 0,
1807 "reuseport array update same sk with BPF_ANY",
1808 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1809
1810 fd64 = grpa_fds64[fds_idx];
1811 sk_cookie = grpa_cookies[fds_idx];
1812
1813 /* The same sk cannot be added to reuseport_array twice */
1814 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_ANY);
1815 CHECK(err >= 0 || errno != EBUSY,
1816 "reuseport array update same sk with same index",
1817 "sock_type:%d err:%d errno:%d\n",
1818 type, err, errno);
1819
1820 err = bpf_map_update_elem(map_fd, &index0, &fd64, BPF_ANY);
1821 CHECK(err >= 0 || errno != EBUSY,
1822 "reuseport array update same sk with different index",
1823 "sock_type:%d err:%d errno:%d\n",
1824 type, err, errno);
1825
1826 /* Test delete elem */
1827 err = bpf_map_delete_elem(map_fd, &index3);
1828 CHECK(err < 0, "reuseport array delete sk",
1829 "sock_type:%d err:%d errno:%d\n",
1830 type, err, errno);
1831
1832 /* Add it back with BPF_NOEXIST */
1833 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
1834 CHECK(err < 0,
1835 "reuseport array re-add with BPF_NOEXIST after del",
1836 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1837
1838 /* Test cookie */
1839 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1840 CHECK(err < 0 || sk_cookie != map_cookie,
1841 "reuseport array lookup re-added sk",
1842 "sock_type:%d err:%d errno:%d sk_cookie:0x%llx map_cookie:0x%llxn",
1843 type, err, errno, sk_cookie, map_cookie);
1844
1845 /* Test elem removed by close() */
1846 for (f = 0; f < ARRAY_SIZE(grpa_fds64); f++)
1847 close(grpa_fds64[f]);
1848 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1849 CHECK(err >= 0 || errno != ENOENT,
1850 "reuseport array lookup after close()",
1851 "sock_type:%d err:%d errno:%d\n",
1852 type, err, errno);
1853 }
1854
1855 /* Test SOCK_RAW */
1856 fd64 = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
1857 CHECK(fd64 == -1, "socket(SOCK_RAW)", "err:%d errno:%d\n",
1858 err, errno);
1859 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
1860 CHECK(err >= 0 || errno != ENOTSUPP, "reuseport array update SOCK_RAW",
1861 "err:%d errno:%d\n", err, errno);
1862 close(fd64);
1863
1864 /* Close the 64 bit value map */
1865 close(map_fd);
1866
1867 /* Test 32 bit fd */
1868 map_fd = bpf_map_create(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, NULL,
1869 sizeof(__u32), sizeof(__u32), array_size, NULL);
1870 CHECK(map_fd < 0, "reuseport array create",
1871 "map_fd:%d, errno:%d\n", map_fd, errno);
1872 prepare_reuseport_grp(SOCK_STREAM, map_fd, sizeof(__u32), &fd64,
1873 &sk_cookie, 1);
1874 fd = fd64;
1875 err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST);
1876 CHECK(err < 0, "reuseport array update 32 bit fd",
1877 "err:%d errno:%d\n", err, errno);
1878 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1879 CHECK(err >= 0 || errno != ENOSPC,
1880 "reuseport array lookup 32 bit fd",
1881 "err:%d errno:%d\n", err, errno);
1882 close(fd);
1883 close(map_fd);
1884 }
1885
run_all_tests(void)1886 static void run_all_tests(void)
1887 {
1888 test_hashmap(0, NULL);
1889 test_hashmap_percpu(0, NULL);
1890 test_hashmap_walk(0, NULL);
1891 test_hashmap_zero_seed();
1892
1893 test_arraymap(0, NULL);
1894 test_arraymap_percpu(0, NULL);
1895
1896 test_arraymap_percpu_many_keys();
1897
1898 test_devmap(0, NULL);
1899 test_devmap_hash(0, NULL);
1900 test_sockmap(0, NULL);
1901
1902 test_map_large();
1903 test_map_parallel();
1904 test_map_stress();
1905
1906 test_map_rdonly();
1907 test_map_wronly();
1908
1909 test_reuseport_array();
1910
1911 test_queuemap(0, NULL);
1912 test_stackmap(0, NULL);
1913
1914 test_map_in_map();
1915 }
1916
1917 #define DEFINE_TEST(name) extern void test_##name(void);
1918 #include <map_tests/tests.h>
1919 #undef DEFINE_TEST
1920
main(void)1921 int main(void)
1922 {
1923 srand(time(NULL));
1924
1925 libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
1926
1927 map_opts.map_flags = 0;
1928 run_all_tests();
1929
1930 map_opts.map_flags = BPF_F_NO_PREALLOC;
1931 run_all_tests();
1932
1933 #define DEFINE_TEST(name) test_##name();
1934 #include <map_tests/tests.h>
1935 #undef DEFINE_TEST
1936
1937 printf("test_maps: OK, %d SKIPPED\n", skips);
1938 return 0;
1939 }
1940