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