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