.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Testsuite for eBPF maps |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2014 PLUMgrid, http://plumgrid.com |
---|
5 | 6 | * 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 | 7 | */ |
---|
11 | 8 | |
---|
12 | 9 | #include <stdio.h> |
---|
.. | .. |
---|
15 | 12 | #include <string.h> |
---|
16 | 13 | #include <assert.h> |
---|
17 | 14 | #include <stdlib.h> |
---|
| 15 | +#include <time.h> |
---|
18 | 16 | |
---|
19 | 17 | #include <sys/wait.h> |
---|
20 | 18 | #include <sys/socket.h> |
---|
.. | .. |
---|
26 | 24 | |
---|
27 | 25 | #include "bpf_util.h" |
---|
28 | 26 | #include "bpf_rlimit.h" |
---|
| 27 | +#include "test_maps.h" |
---|
29 | 28 | |
---|
30 | 29 | #ifndef ENOTSUPP |
---|
31 | 30 | #define ENOTSUPP 524 |
---|
32 | 31 | #endif |
---|
33 | 32 | |
---|
| 33 | +static int skips; |
---|
| 34 | + |
---|
34 | 35 | static int map_flags; |
---|
35 | 36 | |
---|
36 | | -#define CHECK(condition, tag, format...) ({ \ |
---|
37 | | - int __ret = !!(condition); \ |
---|
38 | | - if (__ret) { \ |
---|
39 | | - printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag); \ |
---|
40 | | - printf(format); \ |
---|
41 | | - exit(-1); \ |
---|
42 | | - } \ |
---|
43 | | -}) |
---|
44 | | - |
---|
45 | | -static void test_hashmap(int task, void *data) |
---|
| 37 | +static void test_hashmap(unsigned int task, void *data) |
---|
46 | 38 | { |
---|
47 | 39 | long long key, next_key, first_key, value; |
---|
48 | 40 | int fd; |
---|
.. | .. |
---|
132 | 124 | close(fd); |
---|
133 | 125 | } |
---|
134 | 126 | |
---|
135 | | -static void test_hashmap_sizes(int task, void *data) |
---|
| 127 | +static void test_hashmap_sizes(unsigned int task, void *data) |
---|
136 | 128 | { |
---|
137 | 129 | int fd, i, j; |
---|
138 | 130 | |
---|
.. | .. |
---|
152 | 144 | } |
---|
153 | 145 | } |
---|
154 | 146 | |
---|
155 | | -static void test_hashmap_percpu(int task, void *data) |
---|
| 147 | +static void test_hashmap_percpu(unsigned int task, void *data) |
---|
156 | 148 | { |
---|
157 | 149 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
---|
158 | 150 | BPF_DECLARE_PERCPU(long, value); |
---|
.. | .. |
---|
257 | 249 | close(fd); |
---|
258 | 250 | } |
---|
259 | 251 | |
---|
260 | | -static void test_hashmap_walk(int task, void *data) |
---|
| 252 | +static int helper_fill_hashmap(int max_entries) |
---|
| 253 | +{ |
---|
| 254 | + int i, fd, ret; |
---|
| 255 | + long long key, value; |
---|
| 256 | + |
---|
| 257 | + fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), |
---|
| 258 | + max_entries, map_flags); |
---|
| 259 | + CHECK(fd < 0, |
---|
| 260 | + "failed to create hashmap", |
---|
| 261 | + "err: %s, flags: 0x%x\n", strerror(errno), map_flags); |
---|
| 262 | + |
---|
| 263 | + for (i = 0; i < max_entries; i++) { |
---|
| 264 | + key = i; value = key; |
---|
| 265 | + ret = bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST); |
---|
| 266 | + CHECK(ret != 0, |
---|
| 267 | + "can't update hashmap", |
---|
| 268 | + "err: %s\n", strerror(ret)); |
---|
| 269 | + } |
---|
| 270 | + |
---|
| 271 | + return fd; |
---|
| 272 | +} |
---|
| 273 | + |
---|
| 274 | +static void test_hashmap_walk(unsigned int task, void *data) |
---|
261 | 275 | { |
---|
262 | 276 | int fd, i, max_entries = 1000; |
---|
263 | 277 | long long key, value, next_key; |
---|
264 | 278 | bool next_key_valid = true; |
---|
265 | 279 | |
---|
266 | | - fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), |
---|
267 | | - max_entries, map_flags); |
---|
268 | | - if (fd < 0) { |
---|
269 | | - printf("Failed to create hashmap '%s'!\n", strerror(errno)); |
---|
270 | | - exit(1); |
---|
271 | | - } |
---|
272 | | - |
---|
273 | | - for (i = 0; i < max_entries; i++) { |
---|
274 | | - key = i; value = key; |
---|
275 | | - assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0); |
---|
276 | | - } |
---|
| 280 | + fd = helper_fill_hashmap(max_entries); |
---|
277 | 281 | |
---|
278 | 282 | for (i = 0; bpf_map_get_next_key(fd, !i ? NULL : &key, |
---|
279 | 283 | &next_key) == 0; i++) { |
---|
.. | .. |
---|
305 | 309 | close(fd); |
---|
306 | 310 | } |
---|
307 | 311 | |
---|
308 | | -static void test_arraymap(int task, void *data) |
---|
| 312 | +static void test_hashmap_zero_seed(void) |
---|
| 313 | +{ |
---|
| 314 | + int i, first, second, old_flags; |
---|
| 315 | + long long key, next_first, next_second; |
---|
| 316 | + |
---|
| 317 | + old_flags = map_flags; |
---|
| 318 | + map_flags |= BPF_F_ZERO_SEED; |
---|
| 319 | + |
---|
| 320 | + first = helper_fill_hashmap(3); |
---|
| 321 | + second = helper_fill_hashmap(3); |
---|
| 322 | + |
---|
| 323 | + for (i = 0; ; i++) { |
---|
| 324 | + void *key_ptr = !i ? NULL : &key; |
---|
| 325 | + |
---|
| 326 | + if (bpf_map_get_next_key(first, key_ptr, &next_first) != 0) |
---|
| 327 | + break; |
---|
| 328 | + |
---|
| 329 | + CHECK(bpf_map_get_next_key(second, key_ptr, &next_second) != 0, |
---|
| 330 | + "next_key for second map must succeed", |
---|
| 331 | + "key_ptr: %p", key_ptr); |
---|
| 332 | + CHECK(next_first != next_second, |
---|
| 333 | + "keys must match", |
---|
| 334 | + "i: %d first: %lld second: %lld\n", i, |
---|
| 335 | + next_first, next_second); |
---|
| 336 | + |
---|
| 337 | + key = next_first; |
---|
| 338 | + } |
---|
| 339 | + |
---|
| 340 | + map_flags = old_flags; |
---|
| 341 | + close(first); |
---|
| 342 | + close(second); |
---|
| 343 | +} |
---|
| 344 | + |
---|
| 345 | +static void test_arraymap(unsigned int task, void *data) |
---|
309 | 346 | { |
---|
310 | 347 | int key, next_key, fd; |
---|
311 | 348 | long long value; |
---|
.. | .. |
---|
360 | 397 | close(fd); |
---|
361 | 398 | } |
---|
362 | 399 | |
---|
363 | | -static void test_arraymap_percpu(int task, void *data) |
---|
| 400 | +static void test_arraymap_percpu(unsigned int task, void *data) |
---|
364 | 401 | { |
---|
365 | 402 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
---|
366 | 403 | BPF_DECLARE_PERCPU(long, values); |
---|
.. | .. |
---|
456 | 493 | close(fd); |
---|
457 | 494 | } |
---|
458 | 495 | |
---|
459 | | -static void test_devmap(int task, void *data) |
---|
| 496 | +static void test_devmap(unsigned int task, void *data) |
---|
460 | 497 | { |
---|
461 | 498 | int fd; |
---|
462 | 499 | __u32 key, value; |
---|
.. | .. |
---|
464 | 501 | fd = bpf_create_map(BPF_MAP_TYPE_DEVMAP, sizeof(key), sizeof(value), |
---|
465 | 502 | 2, 0); |
---|
466 | 503 | if (fd < 0) { |
---|
467 | | - printf("Failed to create arraymap '%s'!\n", strerror(errno)); |
---|
| 504 | + printf("Failed to create devmap '%s'!\n", strerror(errno)); |
---|
468 | 505 | exit(1); |
---|
469 | 506 | } |
---|
470 | 507 | |
---|
471 | 508 | close(fd); |
---|
472 | 509 | } |
---|
473 | 510 | |
---|
474 | | -#include <sys/socket.h> |
---|
| 511 | +static void test_devmap_hash(unsigned int task, void *data) |
---|
| 512 | +{ |
---|
| 513 | + int fd; |
---|
| 514 | + __u32 key, value; |
---|
| 515 | + |
---|
| 516 | + fd = bpf_create_map(BPF_MAP_TYPE_DEVMAP_HASH, sizeof(key), sizeof(value), |
---|
| 517 | + 2, 0); |
---|
| 518 | + if (fd < 0) { |
---|
| 519 | + printf("Failed to create devmap_hash '%s'!\n", strerror(errno)); |
---|
| 520 | + exit(1); |
---|
| 521 | + } |
---|
| 522 | + |
---|
| 523 | + close(fd); |
---|
| 524 | +} |
---|
| 525 | + |
---|
| 526 | +static void test_queuemap(unsigned int task, void *data) |
---|
| 527 | +{ |
---|
| 528 | + const int MAP_SIZE = 32; |
---|
| 529 | + __u32 vals[MAP_SIZE + MAP_SIZE/2], val; |
---|
| 530 | + int fd, i; |
---|
| 531 | + |
---|
| 532 | + /* Fill test values to be used */ |
---|
| 533 | + for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++) |
---|
| 534 | + vals[i] = rand(); |
---|
| 535 | + |
---|
| 536 | + /* Invalid key size */ |
---|
| 537 | + fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 4, sizeof(val), MAP_SIZE, |
---|
| 538 | + map_flags); |
---|
| 539 | + assert(fd < 0 && errno == EINVAL); |
---|
| 540 | + |
---|
| 541 | + fd = bpf_create_map(BPF_MAP_TYPE_QUEUE, 0, sizeof(val), MAP_SIZE, |
---|
| 542 | + map_flags); |
---|
| 543 | + /* Queue map does not support BPF_F_NO_PREALLOC */ |
---|
| 544 | + if (map_flags & BPF_F_NO_PREALLOC) { |
---|
| 545 | + assert(fd < 0 && errno == EINVAL); |
---|
| 546 | + return; |
---|
| 547 | + } |
---|
| 548 | + if (fd < 0) { |
---|
| 549 | + printf("Failed to create queuemap '%s'!\n", strerror(errno)); |
---|
| 550 | + exit(1); |
---|
| 551 | + } |
---|
| 552 | + |
---|
| 553 | + /* Push MAP_SIZE elements */ |
---|
| 554 | + for (i = 0; i < MAP_SIZE; i++) |
---|
| 555 | + assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0); |
---|
| 556 | + |
---|
| 557 | + /* Check that element cannot be pushed due to max_entries limit */ |
---|
| 558 | + assert(bpf_map_update_elem(fd, NULL, &val, 0) == -1 && |
---|
| 559 | + errno == E2BIG); |
---|
| 560 | + |
---|
| 561 | + /* Peek element */ |
---|
| 562 | + assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[0]); |
---|
| 563 | + |
---|
| 564 | + /* Replace half elements */ |
---|
| 565 | + for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++) |
---|
| 566 | + assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0); |
---|
| 567 | + |
---|
| 568 | + /* Pop all elements */ |
---|
| 569 | + for (i = MAP_SIZE/2; i < MAP_SIZE + MAP_SIZE/2; i++) |
---|
| 570 | + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 && |
---|
| 571 | + val == vals[i]); |
---|
| 572 | + |
---|
| 573 | + /* Check that there are not elements left */ |
---|
| 574 | + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == -1 && |
---|
| 575 | + errno == ENOENT); |
---|
| 576 | + |
---|
| 577 | + /* Check that non supported functions set errno to EINVAL */ |
---|
| 578 | + assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL); |
---|
| 579 | + assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL); |
---|
| 580 | + |
---|
| 581 | + close(fd); |
---|
| 582 | +} |
---|
| 583 | + |
---|
| 584 | +static void test_stackmap(unsigned int task, void *data) |
---|
| 585 | +{ |
---|
| 586 | + const int MAP_SIZE = 32; |
---|
| 587 | + __u32 vals[MAP_SIZE + MAP_SIZE/2], val; |
---|
| 588 | + int fd, i; |
---|
| 589 | + |
---|
| 590 | + /* Fill test values to be used */ |
---|
| 591 | + for (i = 0; i < MAP_SIZE + MAP_SIZE/2; i++) |
---|
| 592 | + vals[i] = rand(); |
---|
| 593 | + |
---|
| 594 | + /* Invalid key size */ |
---|
| 595 | + fd = bpf_create_map(BPF_MAP_TYPE_STACK, 4, sizeof(val), MAP_SIZE, |
---|
| 596 | + map_flags); |
---|
| 597 | + assert(fd < 0 && errno == EINVAL); |
---|
| 598 | + |
---|
| 599 | + fd = bpf_create_map(BPF_MAP_TYPE_STACK, 0, sizeof(val), MAP_SIZE, |
---|
| 600 | + map_flags); |
---|
| 601 | + /* Stack map does not support BPF_F_NO_PREALLOC */ |
---|
| 602 | + if (map_flags & BPF_F_NO_PREALLOC) { |
---|
| 603 | + assert(fd < 0 && errno == EINVAL); |
---|
| 604 | + return; |
---|
| 605 | + } |
---|
| 606 | + if (fd < 0) { |
---|
| 607 | + printf("Failed to create stackmap '%s'!\n", strerror(errno)); |
---|
| 608 | + exit(1); |
---|
| 609 | + } |
---|
| 610 | + |
---|
| 611 | + /* Push MAP_SIZE elements */ |
---|
| 612 | + for (i = 0; i < MAP_SIZE; i++) |
---|
| 613 | + assert(bpf_map_update_elem(fd, NULL, &vals[i], 0) == 0); |
---|
| 614 | + |
---|
| 615 | + /* Check that element cannot be pushed due to max_entries limit */ |
---|
| 616 | + assert(bpf_map_update_elem(fd, NULL, &val, 0) == -1 && |
---|
| 617 | + errno == E2BIG); |
---|
| 618 | + |
---|
| 619 | + /* Peek element */ |
---|
| 620 | + assert(bpf_map_lookup_elem(fd, NULL, &val) == 0 && val == vals[i - 1]); |
---|
| 621 | + |
---|
| 622 | + /* Replace half elements */ |
---|
| 623 | + for (i = MAP_SIZE; i < MAP_SIZE + MAP_SIZE/2; i++) |
---|
| 624 | + assert(bpf_map_update_elem(fd, NULL, &vals[i], BPF_EXIST) == 0); |
---|
| 625 | + |
---|
| 626 | + /* Pop all elements */ |
---|
| 627 | + for (i = MAP_SIZE + MAP_SIZE/2 - 1; i >= MAP_SIZE/2; i--) |
---|
| 628 | + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == 0 && |
---|
| 629 | + val == vals[i]); |
---|
| 630 | + |
---|
| 631 | + /* Check that there are not elements left */ |
---|
| 632 | + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &val) == -1 && |
---|
| 633 | + errno == ENOENT); |
---|
| 634 | + |
---|
| 635 | + /* Check that non supported functions set errno to EINVAL */ |
---|
| 636 | + assert(bpf_map_delete_elem(fd, NULL) == -1 && errno == EINVAL); |
---|
| 637 | + assert(bpf_map_get_next_key(fd, NULL, NULL) == -1 && errno == EINVAL); |
---|
| 638 | + |
---|
| 639 | + close(fd); |
---|
| 640 | +} |
---|
| 641 | + |
---|
475 | 642 | #include <sys/ioctl.h> |
---|
476 | 643 | #include <arpa/inet.h> |
---|
477 | 644 | #include <sys/select.h> |
---|
.. | .. |
---|
479 | 646 | #define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.o" |
---|
480 | 647 | #define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o" |
---|
481 | 648 | #define SOCKMAP_TCP_MSG_PROG "./sockmap_tcp_msg_prog.o" |
---|
482 | | -static void test_sockmap(int tasks, void *data) |
---|
| 649 | +static void test_sockmap(unsigned int tasks, void *data) |
---|
483 | 650 | { |
---|
484 | 651 | struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_msg, *bpf_map_break; |
---|
485 | 652 | int map_fd_msg = 0, map_fd_rx = 0, map_fd_tx = 0, map_fd_break; |
---|
.. | .. |
---|
563 | 730 | sizeof(key), sizeof(value), |
---|
564 | 731 | 6, 0); |
---|
565 | 732 | if (fd < 0) { |
---|
| 733 | + if (!bpf_probe_map_type(BPF_MAP_TYPE_SOCKMAP, 0)) { |
---|
| 734 | + printf("%s SKIP (unsupported map type BPF_MAP_TYPE_SOCKMAP)\n", |
---|
| 735 | + __func__); |
---|
| 736 | + skips++; |
---|
| 737 | + for (i = 0; i < 6; i++) |
---|
| 738 | + close(sfd[i]); |
---|
| 739 | + return; |
---|
| 740 | + } |
---|
| 741 | + |
---|
566 | 742 | printf("Failed to create sockmap %i\n", fd); |
---|
567 | 743 | goto out_sockmap; |
---|
568 | 744 | } |
---|
.. | .. |
---|
580 | 756 | /* Test update without programs */ |
---|
581 | 757 | for (i = 0; i < 6; i++) { |
---|
582 | 758 | err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); |
---|
583 | | - if (i < 2 && !err) { |
---|
584 | | - printf("Allowed update sockmap '%i:%i' not in ESTABLISHED\n", |
---|
585 | | - i, sfd[i]); |
---|
586 | | - goto out_sockmap; |
---|
587 | | - } else if (i >= 2 && err) { |
---|
| 759 | + if (err) { |
---|
588 | 760 | printf("Failed noprog update sockmap '%i:%i'\n", |
---|
589 | 761 | i, sfd[i]); |
---|
590 | 762 | goto out_sockmap; |
---|
.. | .. |
---|
617 | 789 | } |
---|
618 | 790 | |
---|
619 | 791 | err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER); |
---|
620 | | - if (err) { |
---|
| 792 | + if (!err) { |
---|
621 | 793 | printf("Failed empty parser prog detach\n"); |
---|
622 | 794 | goto out_sockmap; |
---|
623 | 795 | } |
---|
624 | 796 | |
---|
625 | 797 | err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT); |
---|
626 | | - if (err) { |
---|
| 798 | + if (!err) { |
---|
627 | 799 | printf("Failed empty verdict prog detach\n"); |
---|
628 | 800 | goto out_sockmap; |
---|
629 | 801 | } |
---|
630 | 802 | |
---|
631 | 803 | err = bpf_prog_detach(fd, BPF_SK_MSG_VERDICT); |
---|
632 | | - if (err) { |
---|
| 804 | + if (!err) { |
---|
633 | 805 | printf("Failed empty msg verdict prog detach\n"); |
---|
634 | 806 | goto out_sockmap; |
---|
635 | 807 | } |
---|
.. | .. |
---|
918 | 1090 | assert(status == 0); |
---|
919 | 1091 | } |
---|
920 | 1092 | |
---|
921 | | - err = bpf_prog_detach(map_fd_rx, __MAX_BPF_ATTACH_TYPE); |
---|
| 1093 | + err = bpf_prog_detach2(parse_prog, map_fd_rx, __MAX_BPF_ATTACH_TYPE); |
---|
922 | 1094 | if (!err) { |
---|
923 | 1095 | printf("Detached an invalid prog type.\n"); |
---|
924 | 1096 | goto out_sockmap; |
---|
925 | 1097 | } |
---|
926 | 1098 | |
---|
927 | | - err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_PARSER); |
---|
| 1099 | + err = bpf_prog_detach2(parse_prog, map_fd_rx, BPF_SK_SKB_STREAM_PARSER); |
---|
928 | 1100 | if (err) { |
---|
929 | 1101 | printf("Failed parser prog detach\n"); |
---|
930 | 1102 | goto out_sockmap; |
---|
931 | 1103 | } |
---|
932 | 1104 | |
---|
933 | | - err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_VERDICT); |
---|
| 1105 | + err = bpf_prog_detach2(verdict_prog, map_fd_rx, BPF_SK_SKB_STREAM_VERDICT); |
---|
934 | 1106 | if (err) { |
---|
935 | 1107 | printf("Failed parser prog detach\n"); |
---|
936 | 1108 | goto out_sockmap; |
---|
.. | .. |
---|
959 | 1131 | bpf_map_delete_elem(map_fd_rx, &i); |
---|
960 | 1132 | close(sfd[i]); |
---|
961 | 1133 | } |
---|
| 1134 | + close(fd); |
---|
| 1135 | + exit(1); |
---|
| 1136 | +} |
---|
| 1137 | + |
---|
| 1138 | +#define MAPINMAP_PROG "./test_map_in_map.o" |
---|
| 1139 | +static void test_map_in_map(void) |
---|
| 1140 | +{ |
---|
| 1141 | + struct bpf_object *obj; |
---|
| 1142 | + struct bpf_map *map; |
---|
| 1143 | + int mim_fd, fd, err; |
---|
| 1144 | + int pos = 0; |
---|
| 1145 | + |
---|
| 1146 | + obj = bpf_object__open(MAPINMAP_PROG); |
---|
| 1147 | + |
---|
| 1148 | + fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(int), sizeof(int), |
---|
| 1149 | + 2, 0); |
---|
| 1150 | + if (fd < 0) { |
---|
| 1151 | + printf("Failed to create hashmap '%s'!\n", strerror(errno)); |
---|
| 1152 | + exit(1); |
---|
| 1153 | + } |
---|
| 1154 | + |
---|
| 1155 | + map = bpf_object__find_map_by_name(obj, "mim_array"); |
---|
| 1156 | + if (IS_ERR(map)) { |
---|
| 1157 | + printf("Failed to load array of maps from test prog\n"); |
---|
| 1158 | + goto out_map_in_map; |
---|
| 1159 | + } |
---|
| 1160 | + err = bpf_map__set_inner_map_fd(map, fd); |
---|
| 1161 | + if (err) { |
---|
| 1162 | + printf("Failed to set inner_map_fd for array of maps\n"); |
---|
| 1163 | + goto out_map_in_map; |
---|
| 1164 | + } |
---|
| 1165 | + |
---|
| 1166 | + map = bpf_object__find_map_by_name(obj, "mim_hash"); |
---|
| 1167 | + if (IS_ERR(map)) { |
---|
| 1168 | + printf("Failed to load hash of maps from test prog\n"); |
---|
| 1169 | + goto out_map_in_map; |
---|
| 1170 | + } |
---|
| 1171 | + err = bpf_map__set_inner_map_fd(map, fd); |
---|
| 1172 | + if (err) { |
---|
| 1173 | + printf("Failed to set inner_map_fd for hash of maps\n"); |
---|
| 1174 | + goto out_map_in_map; |
---|
| 1175 | + } |
---|
| 1176 | + |
---|
| 1177 | + bpf_object__load(obj); |
---|
| 1178 | + |
---|
| 1179 | + map = bpf_object__find_map_by_name(obj, "mim_array"); |
---|
| 1180 | + if (IS_ERR(map)) { |
---|
| 1181 | + printf("Failed to load array of maps from test prog\n"); |
---|
| 1182 | + goto out_map_in_map; |
---|
| 1183 | + } |
---|
| 1184 | + mim_fd = bpf_map__fd(map); |
---|
| 1185 | + if (mim_fd < 0) { |
---|
| 1186 | + printf("Failed to get descriptor for array of maps\n"); |
---|
| 1187 | + goto out_map_in_map; |
---|
| 1188 | + } |
---|
| 1189 | + |
---|
| 1190 | + err = bpf_map_update_elem(mim_fd, &pos, &fd, 0); |
---|
| 1191 | + if (err) { |
---|
| 1192 | + printf("Failed to update array of maps\n"); |
---|
| 1193 | + goto out_map_in_map; |
---|
| 1194 | + } |
---|
| 1195 | + |
---|
| 1196 | + map = bpf_object__find_map_by_name(obj, "mim_hash"); |
---|
| 1197 | + if (IS_ERR(map)) { |
---|
| 1198 | + printf("Failed to load hash of maps from test prog\n"); |
---|
| 1199 | + goto out_map_in_map; |
---|
| 1200 | + } |
---|
| 1201 | + mim_fd = bpf_map__fd(map); |
---|
| 1202 | + if (mim_fd < 0) { |
---|
| 1203 | + printf("Failed to get descriptor for hash of maps\n"); |
---|
| 1204 | + goto out_map_in_map; |
---|
| 1205 | + } |
---|
| 1206 | + |
---|
| 1207 | + err = bpf_map_update_elem(mim_fd, &pos, &fd, 0); |
---|
| 1208 | + if (err) { |
---|
| 1209 | + printf("Failed to update hash of maps\n"); |
---|
| 1210 | + goto out_map_in_map; |
---|
| 1211 | + } |
---|
| 1212 | + |
---|
| 1213 | + close(fd); |
---|
| 1214 | + bpf_object__close(obj); |
---|
| 1215 | + return; |
---|
| 1216 | + |
---|
| 1217 | +out_map_in_map: |
---|
962 | 1218 | close(fd); |
---|
963 | 1219 | exit(1); |
---|
964 | 1220 | } |
---|
.. | .. |
---|
1008 | 1264 | } |
---|
1009 | 1265 | |
---|
1010 | 1266 | #define run_parallel(N, FN, DATA) \ |
---|
1011 | | - printf("Fork %d tasks to '" #FN "'\n", N); \ |
---|
| 1267 | + printf("Fork %u tasks to '" #FN "'\n", N); \ |
---|
1012 | 1268 | __run_parallel(N, FN, DATA) |
---|
1013 | 1269 | |
---|
1014 | | -static void __run_parallel(int tasks, void (*fn)(int task, void *data), |
---|
| 1270 | +static void __run_parallel(unsigned int tasks, |
---|
| 1271 | + void (*fn)(unsigned int task, void *data), |
---|
1015 | 1272 | void *data) |
---|
1016 | 1273 | { |
---|
1017 | 1274 | pid_t pid[tasks]; |
---|
.. | .. |
---|
1054 | 1311 | #define DO_UPDATE 1 |
---|
1055 | 1312 | #define DO_DELETE 0 |
---|
1056 | 1313 | |
---|
1057 | | -static void test_update_delete(int fn, void *data) |
---|
| 1314 | +static void test_update_delete(unsigned int fn, void *data) |
---|
1058 | 1315 | { |
---|
1059 | 1316 | int do_update = ((int *)data)[1]; |
---|
1060 | 1317 | int fd = ((int *)data)[0]; |
---|
.. | .. |
---|
1139 | 1396 | |
---|
1140 | 1397 | key = 1; |
---|
1141 | 1398 | value = 1234; |
---|
1142 | | - /* Insert key=1 element. */ |
---|
| 1399 | + /* Try to insert key=1 element. */ |
---|
1143 | 1400 | assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == -1 && |
---|
1144 | 1401 | errno == EPERM); |
---|
1145 | 1402 | |
---|
1146 | | - /* Check that key=2 is not found. */ |
---|
| 1403 | + /* Check that key=1 is not found. */ |
---|
1147 | 1404 | assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT); |
---|
1148 | 1405 | assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == ENOENT); |
---|
| 1406 | + |
---|
| 1407 | + close(fd); |
---|
1149 | 1408 | } |
---|
1150 | 1409 | |
---|
1151 | | -static void test_map_wronly(void) |
---|
| 1410 | +static void test_map_wronly_hash(void) |
---|
1152 | 1411 | { |
---|
1153 | 1412 | int fd, key = 0, value = 0; |
---|
1154 | 1413 | |
---|
1155 | 1414 | fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), |
---|
1156 | 1415 | MAP_SIZE, map_flags | BPF_F_WRONLY); |
---|
1157 | 1416 | if (fd < 0) { |
---|
1158 | | - printf("Failed to create map for read only test '%s'!\n", |
---|
| 1417 | + printf("Failed to create map for write only test '%s'!\n", |
---|
1159 | 1418 | strerror(errno)); |
---|
1160 | 1419 | exit(1); |
---|
1161 | 1420 | } |
---|
.. | .. |
---|
1165 | 1424 | /* Insert key=1 element. */ |
---|
1166 | 1425 | assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0); |
---|
1167 | 1426 | |
---|
1168 | | - /* Check that key=2 is not found. */ |
---|
| 1427 | + /* Check that reading elements and keys from the map is not allowed. */ |
---|
1169 | 1428 | assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == EPERM); |
---|
1170 | 1429 | assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM); |
---|
| 1430 | + |
---|
| 1431 | + close(fd); |
---|
1171 | 1432 | } |
---|
1172 | 1433 | |
---|
1173 | | -static void prepare_reuseport_grp(int type, int map_fd, |
---|
| 1434 | +static void test_map_wronly_stack_or_queue(enum bpf_map_type map_type) |
---|
| 1435 | +{ |
---|
| 1436 | + int fd, value = 0; |
---|
| 1437 | + |
---|
| 1438 | + assert(map_type == BPF_MAP_TYPE_QUEUE || |
---|
| 1439 | + map_type == BPF_MAP_TYPE_STACK); |
---|
| 1440 | + fd = bpf_create_map(map_type, 0, sizeof(value), MAP_SIZE, |
---|
| 1441 | + map_flags | BPF_F_WRONLY); |
---|
| 1442 | + /* Stack/Queue maps do not support BPF_F_NO_PREALLOC */ |
---|
| 1443 | + if (map_flags & BPF_F_NO_PREALLOC) { |
---|
| 1444 | + assert(fd < 0 && errno == EINVAL); |
---|
| 1445 | + return; |
---|
| 1446 | + } |
---|
| 1447 | + if (fd < 0) { |
---|
| 1448 | + printf("Failed to create map '%s'!\n", strerror(errno)); |
---|
| 1449 | + exit(1); |
---|
| 1450 | + } |
---|
| 1451 | + |
---|
| 1452 | + value = 1234; |
---|
| 1453 | + assert(bpf_map_update_elem(fd, NULL, &value, BPF_ANY) == 0); |
---|
| 1454 | + |
---|
| 1455 | + /* Peek element should fail */ |
---|
| 1456 | + assert(bpf_map_lookup_elem(fd, NULL, &value) == -1 && errno == EPERM); |
---|
| 1457 | + |
---|
| 1458 | + /* Pop element should fail */ |
---|
| 1459 | + assert(bpf_map_lookup_and_delete_elem(fd, NULL, &value) == -1 && |
---|
| 1460 | + errno == EPERM); |
---|
| 1461 | + |
---|
| 1462 | + close(fd); |
---|
| 1463 | +} |
---|
| 1464 | + |
---|
| 1465 | +static void test_map_wronly(void) |
---|
| 1466 | +{ |
---|
| 1467 | + test_map_wronly_hash(); |
---|
| 1468 | + test_map_wronly_stack_or_queue(BPF_MAP_TYPE_STACK); |
---|
| 1469 | + test_map_wronly_stack_or_queue(BPF_MAP_TYPE_QUEUE); |
---|
| 1470 | +} |
---|
| 1471 | + |
---|
| 1472 | +static void prepare_reuseport_grp(int type, int map_fd, size_t map_elem_size, |
---|
1174 | 1473 | __s64 *fds64, __u64 *sk_cookies, |
---|
1175 | 1474 | unsigned int n) |
---|
1176 | 1475 | { |
---|
.. | .. |
---|
1180 | 1479 | const int optval = 1; |
---|
1181 | 1480 | unsigned int i; |
---|
1182 | 1481 | u64 sk_cookie; |
---|
| 1482 | + void *value; |
---|
| 1483 | + __s32 fd32; |
---|
1183 | 1484 | __s64 fd64; |
---|
1184 | 1485 | int err; |
---|
1185 | 1486 | |
---|
.. | .. |
---|
1201 | 1502 | "err:%d errno:%d\n", err, errno); |
---|
1202 | 1503 | |
---|
1203 | 1504 | /* reuseport_array does not allow unbound sk */ |
---|
1204 | | - err = bpf_map_update_elem(map_fd, &index0, &fd64, |
---|
1205 | | - BPF_ANY); |
---|
| 1505 | + if (map_elem_size == sizeof(__u64)) |
---|
| 1506 | + value = &fd64; |
---|
| 1507 | + else { |
---|
| 1508 | + assert(map_elem_size == sizeof(__u32)); |
---|
| 1509 | + fd32 = (__s32)fd64; |
---|
| 1510 | + value = &fd32; |
---|
| 1511 | + } |
---|
| 1512 | + err = bpf_map_update_elem(map_fd, &index0, value, BPF_ANY); |
---|
1206 | 1513 | CHECK(err != -1 || errno != EINVAL, |
---|
1207 | 1514 | "reuseport array update unbound sk", |
---|
1208 | 1515 | "sock_type:%d err:%d errno:%d\n", |
---|
.. | .. |
---|
1230 | 1537 | * reuseport_array does not allow |
---|
1231 | 1538 | * non-listening tcp sk. |
---|
1232 | 1539 | */ |
---|
1233 | | - err = bpf_map_update_elem(map_fd, &index0, &fd64, |
---|
| 1540 | + err = bpf_map_update_elem(map_fd, &index0, value, |
---|
1234 | 1541 | BPF_ANY); |
---|
1235 | 1542 | CHECK(err != -1 || errno != EINVAL, |
---|
1236 | 1543 | "reuseport array update non-listening sk", |
---|
.. | .. |
---|
1293 | 1600 | for (t = 0; t < ARRAY_SIZE(types); t++) { |
---|
1294 | 1601 | type = types[t]; |
---|
1295 | 1602 | |
---|
1296 | | - prepare_reuseport_grp(type, map_fd, grpa_fds64, |
---|
| 1603 | + prepare_reuseport_grp(type, map_fd, sizeof(__u64), grpa_fds64, |
---|
1297 | 1604 | grpa_cookies, ARRAY_SIZE(grpa_fds64)); |
---|
1298 | 1605 | |
---|
1299 | 1606 | /* Test BPF_* update flags */ |
---|
.. | .. |
---|
1401 | 1708 | sizeof(__u32), sizeof(__u32), array_size, 0); |
---|
1402 | 1709 | CHECK(map_fd == -1, "reuseport array create", |
---|
1403 | 1710 | "map_fd:%d, errno:%d\n", map_fd, errno); |
---|
1404 | | - prepare_reuseport_grp(SOCK_STREAM, map_fd, &fd64, &sk_cookie, 1); |
---|
| 1711 | + prepare_reuseport_grp(SOCK_STREAM, map_fd, sizeof(__u32), &fd64, |
---|
| 1712 | + &sk_cookie, 1); |
---|
1405 | 1713 | fd = fd64; |
---|
1406 | 1714 | err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST); |
---|
1407 | 1715 | CHECK(err == -1, "reuseport array update 32 bit fd", |
---|
.. | .. |
---|
1419 | 1727 | test_hashmap(0, NULL); |
---|
1420 | 1728 | test_hashmap_percpu(0, NULL); |
---|
1421 | 1729 | test_hashmap_walk(0, NULL); |
---|
| 1730 | + test_hashmap_zero_seed(); |
---|
1422 | 1731 | |
---|
1423 | 1732 | test_arraymap(0, NULL); |
---|
1424 | 1733 | test_arraymap_percpu(0, NULL); |
---|
.. | .. |
---|
1426 | 1735 | test_arraymap_percpu_many_keys(); |
---|
1427 | 1736 | |
---|
1428 | 1737 | test_devmap(0, NULL); |
---|
| 1738 | + test_devmap_hash(0, NULL); |
---|
1429 | 1739 | test_sockmap(0, NULL); |
---|
1430 | 1740 | |
---|
1431 | 1741 | test_map_large(); |
---|
.. | .. |
---|
1436 | 1746 | test_map_wronly(); |
---|
1437 | 1747 | |
---|
1438 | 1748 | test_reuseport_array(); |
---|
| 1749 | + |
---|
| 1750 | + test_queuemap(0, NULL); |
---|
| 1751 | + test_stackmap(0, NULL); |
---|
| 1752 | + |
---|
| 1753 | + test_map_in_map(); |
---|
1439 | 1754 | } |
---|
| 1755 | + |
---|
| 1756 | +#define DEFINE_TEST(name) extern void test_##name(void); |
---|
| 1757 | +#include <map_tests/tests.h> |
---|
| 1758 | +#undef DEFINE_TEST |
---|
1440 | 1759 | |
---|
1441 | 1760 | int main(void) |
---|
1442 | 1761 | { |
---|
| 1762 | + srand(time(NULL)); |
---|
| 1763 | + |
---|
1443 | 1764 | map_flags = 0; |
---|
1444 | 1765 | run_all_tests(); |
---|
1445 | 1766 | |
---|
1446 | 1767 | map_flags = BPF_F_NO_PREALLOC; |
---|
1447 | 1768 | run_all_tests(); |
---|
1448 | 1769 | |
---|
1449 | | - printf("test_maps: OK\n"); |
---|
| 1770 | +#define DEFINE_TEST(name) test_##name(); |
---|
| 1771 | +#include <map_tests/tests.h> |
---|
| 1772 | +#undef DEFINE_TEST |
---|
| 1773 | + |
---|
| 1774 | + printf("test_maps: OK, %d SKIPPED\n", skips); |
---|
1450 | 1775 | return 0; |
---|
1451 | 1776 | } |
---|