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