1 /* 2 * Copyright (C) 2017 Netronome Systems, Inc. 3 * 4 * This software is dual licensed under the GNU General License Version 2, 5 * June 1991 as shown in the file COPYING in the top-level directory of this 6 * source tree or the BSD 2-Clause License provided below. You have the 7 * option to license this software under the complete terms of either license. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 /* Author: Jakub Kicinski <kubakici@wp.pl> */ 35 36 #include <assert.h> 37 #include <ctype.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <stdbool.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 48 #include <bpf.h> 49 50 #include "main.h" 51 52 static const char * const map_type_name[] = { 53 [BPF_MAP_TYPE_UNSPEC] = "unspec", 54 [BPF_MAP_TYPE_HASH] = "hash", 55 [BPF_MAP_TYPE_ARRAY] = "array", 56 [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array", 57 [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array", 58 [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash", 59 [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array", 60 [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace", 61 [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array", 62 [BPF_MAP_TYPE_LRU_HASH] = "lru_hash", 63 [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash", 64 [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie", 65 [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps", 66 [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps", 67 [BPF_MAP_TYPE_DEVMAP] = "devmap", 68 [BPF_MAP_TYPE_SOCKMAP] = "sockmap", 69 }; 70 71 static unsigned int get_possible_cpus(void) 72 { 73 static unsigned int result; 74 char buf[128]; 75 long int n; 76 char *ptr; 77 int fd; 78 79 if (result) 80 return result; 81 82 fd = open("/sys/devices/system/cpu/possible", O_RDONLY); 83 if (fd < 0) { 84 err("can't open sysfs possible cpus\n"); 85 exit(-1); 86 } 87 88 n = read(fd, buf, sizeof(buf)); 89 if (n < 2) { 90 err("can't read sysfs possible cpus\n"); 91 exit(-1); 92 } 93 close(fd); 94 95 if (n == sizeof(buf)) { 96 err("read sysfs possible cpus overflow\n"); 97 exit(-1); 98 } 99 100 ptr = buf; 101 n = 0; 102 while (*ptr && *ptr != '\n') { 103 unsigned int a, b; 104 105 if (sscanf(ptr, "%u-%u", &a, &b) == 2) { 106 n += b - a + 1; 107 108 ptr = strchr(ptr, '-') + 1; 109 } else if (sscanf(ptr, "%u", &a) == 1) { 110 n++; 111 } else { 112 assert(0); 113 } 114 115 while (isdigit(*ptr)) 116 ptr++; 117 if (*ptr == ',') 118 ptr++; 119 } 120 121 result = n; 122 123 return result; 124 } 125 126 static bool map_is_per_cpu(__u32 type) 127 { 128 return type == BPF_MAP_TYPE_PERCPU_HASH || 129 type == BPF_MAP_TYPE_PERCPU_ARRAY || 130 type == BPF_MAP_TYPE_LRU_PERCPU_HASH; 131 } 132 133 static bool map_is_map_of_maps(__u32 type) 134 { 135 return type == BPF_MAP_TYPE_ARRAY_OF_MAPS || 136 type == BPF_MAP_TYPE_HASH_OF_MAPS; 137 } 138 139 static bool map_is_map_of_progs(__u32 type) 140 { 141 return type == BPF_MAP_TYPE_PROG_ARRAY; 142 } 143 144 static void *alloc_value(struct bpf_map_info *info) 145 { 146 if (map_is_per_cpu(info->type)) 147 return malloc(info->value_size * get_possible_cpus()); 148 else 149 return malloc(info->value_size); 150 } 151 152 static int map_parse_fd(int *argc, char ***argv) 153 { 154 int fd; 155 156 if (is_prefix(**argv, "id")) { 157 unsigned int id; 158 char *endptr; 159 160 NEXT_ARGP(); 161 162 id = strtoul(**argv, &endptr, 0); 163 if (*endptr) { 164 err("can't parse %s as ID\n", **argv); 165 return -1; 166 } 167 NEXT_ARGP(); 168 169 fd = bpf_map_get_fd_by_id(id); 170 if (fd < 0) 171 err("get map by id (%u): %s\n", id, strerror(errno)); 172 return fd; 173 } else if (is_prefix(**argv, "pinned")) { 174 char *path; 175 176 NEXT_ARGP(); 177 178 path = **argv; 179 NEXT_ARGP(); 180 181 return open_obj_pinned_any(path, BPF_OBJ_MAP); 182 } 183 184 err("expected 'id' or 'pinned', got: '%s'?\n", **argv); 185 return -1; 186 } 187 188 static int 189 map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) 190 { 191 int err; 192 int fd; 193 194 fd = map_parse_fd(argc, argv); 195 if (fd < 0) 196 return -1; 197 198 err = bpf_obj_get_info_by_fd(fd, info, info_len); 199 if (err) { 200 err("can't get map info: %s\n", strerror(errno)); 201 close(fd); 202 return err; 203 } 204 205 return fd; 206 } 207 208 static void print_entry(struct bpf_map_info *info, unsigned char *key, 209 unsigned char *value) 210 { 211 if (!map_is_per_cpu(info->type)) { 212 bool single_line, break_names; 213 214 break_names = info->key_size > 16 || info->value_size > 16; 215 single_line = info->key_size + info->value_size <= 24 && 216 !break_names; 217 218 printf("key:%c", break_names ? '\n' : ' '); 219 print_hex(key, info->key_size, " "); 220 221 printf(single_line ? " " : "\n"); 222 223 printf("value:%c", break_names ? '\n' : ' '); 224 print_hex(value, info->value_size, " "); 225 226 printf("\n"); 227 } else { 228 unsigned int i, n; 229 230 n = get_possible_cpus(); 231 232 printf("key:\n"); 233 print_hex(key, info->key_size, " "); 234 printf("\n"); 235 for (i = 0; i < n; i++) { 236 printf("value (CPU %02d):%c", 237 i, info->value_size > 16 ? '\n' : ' '); 238 print_hex(value + i * info->value_size, 239 info->value_size, " "); 240 printf("\n"); 241 } 242 } 243 } 244 245 static char **parse_bytes(char **argv, const char *name, unsigned char *val, 246 unsigned int n) 247 { 248 unsigned int i = 0; 249 char *endptr; 250 251 while (i < n && argv[i]) { 252 val[i] = strtoul(argv[i], &endptr, 0); 253 if (*endptr) { 254 err("error parsing byte: %s\n", argv[i]); 255 break; 256 } 257 i++; 258 } 259 260 if (i != n) { 261 err("%s expected %d bytes got %d\n", name, n, i); 262 return NULL; 263 } 264 265 return argv + i; 266 } 267 268 static int parse_elem(char **argv, struct bpf_map_info *info, 269 void *key, void *value, __u32 key_size, __u32 value_size, 270 __u32 *flags, __u32 **value_fd) 271 { 272 if (!*argv) { 273 if (!key && !value) 274 return 0; 275 err("did not find %s\n", key ? "key" : "value"); 276 return -1; 277 } 278 279 if (is_prefix(*argv, "key")) { 280 if (!key) { 281 if (key_size) 282 err("duplicate key\n"); 283 else 284 err("unnecessary key\n"); 285 return -1; 286 } 287 288 argv = parse_bytes(argv + 1, "key", key, key_size); 289 if (!argv) 290 return -1; 291 292 return parse_elem(argv, info, NULL, value, key_size, value_size, 293 flags, value_fd); 294 } else if (is_prefix(*argv, "value")) { 295 int fd; 296 297 if (!value) { 298 if (value_size) 299 err("duplicate value\n"); 300 else 301 err("unnecessary value\n"); 302 return -1; 303 } 304 305 argv++; 306 307 if (map_is_map_of_maps(info->type)) { 308 int argc = 2; 309 310 if (value_size != 4) { 311 err("value smaller than 4B for map in map?\n"); 312 return -1; 313 } 314 if (!argv[0] || !argv[1]) { 315 err("not enough value arguments for map in map\n"); 316 return -1; 317 } 318 319 fd = map_parse_fd(&argc, &argv); 320 if (fd < 0) 321 return -1; 322 323 *value_fd = value; 324 **value_fd = fd; 325 } else if (map_is_map_of_progs(info->type)) { 326 int argc = 2; 327 328 if (value_size != 4) { 329 err("value smaller than 4B for map of progs?\n"); 330 return -1; 331 } 332 if (!argv[0] || !argv[1]) { 333 err("not enough value arguments for map of progs\n"); 334 return -1; 335 } 336 337 fd = prog_parse_fd(&argc, &argv); 338 if (fd < 0) 339 return -1; 340 341 *value_fd = value; 342 **value_fd = fd; 343 } else { 344 argv = parse_bytes(argv, "value", value, value_size); 345 if (!argv) 346 return -1; 347 } 348 349 return parse_elem(argv, info, key, NULL, key_size, value_size, 350 flags, NULL); 351 } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") || 352 is_prefix(*argv, "exist")) { 353 if (!flags) { 354 err("flags specified multiple times: %s\n", *argv); 355 return -1; 356 } 357 358 if (is_prefix(*argv, "any")) 359 *flags = BPF_ANY; 360 else if (is_prefix(*argv, "noexist")) 361 *flags = BPF_NOEXIST; 362 else if (is_prefix(*argv, "exist")) 363 *flags = BPF_EXIST; 364 365 return parse_elem(argv + 1, info, key, value, key_size, 366 value_size, NULL, value_fd); 367 } 368 369 err("expected key or value, got: %s\n", *argv); 370 return -1; 371 } 372 373 static int show_map_close(int fd, struct bpf_map_info *info) 374 { 375 char *memlock; 376 377 memlock = get_fdinfo(fd, "memlock"); 378 close(fd); 379 380 printf("%u: ", info->id); 381 if (info->type < ARRAY_SIZE(map_type_name)) 382 printf("%s ", map_type_name[info->type]); 383 else 384 printf("type %u ", info->type); 385 386 if (*info->name) 387 printf("name %s ", info->name); 388 389 printf("flags 0x%x\n", info->map_flags); 390 printf("\tkey %uB value %uB max_entries %u", 391 info->key_size, info->value_size, info->max_entries); 392 393 if (memlock) 394 printf(" memlock %sB", memlock); 395 free(memlock); 396 397 printf("\n"); 398 399 return 0; 400 } 401 402 static int do_show(int argc, char **argv) 403 { 404 struct bpf_map_info info = {}; 405 __u32 len = sizeof(info); 406 __u32 id = 0; 407 int err; 408 int fd; 409 410 if (argc == 2) { 411 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 412 if (fd < 0) 413 return -1; 414 415 return show_map_close(fd, &info); 416 } 417 418 if (argc) 419 return BAD_ARG(); 420 421 while (true) { 422 err = bpf_map_get_next_id(id, &id); 423 if (err) { 424 if (errno == ENOENT) 425 break; 426 err("can't get next map: %s\n", strerror(errno)); 427 if (errno == EINVAL) 428 err("kernel too old?\n"); 429 return -1; 430 } 431 432 fd = bpf_map_get_fd_by_id(id); 433 if (fd < 0) { 434 err("can't get map by id (%u): %s\n", 435 id, strerror(errno)); 436 return -1; 437 } 438 439 err = bpf_obj_get_info_by_fd(fd, &info, &len); 440 if (err) { 441 err("can't get map info: %s\n", strerror(errno)); 442 close(fd); 443 return -1; 444 } 445 446 show_map_close(fd, &info); 447 } 448 449 return errno == ENOENT ? 0 : -1; 450 } 451 452 static int do_dump(int argc, char **argv) 453 { 454 void *key, *value, *prev_key; 455 unsigned int num_elems = 0; 456 struct bpf_map_info info = {}; 457 __u32 len = sizeof(info); 458 int err; 459 int fd; 460 461 if (argc != 2) 462 usage(); 463 464 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 465 if (fd < 0) 466 return -1; 467 468 if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) { 469 err("Dumping maps of maps and program maps not supported\n"); 470 close(fd); 471 return -1; 472 } 473 474 key = malloc(info.key_size); 475 value = alloc_value(&info); 476 if (!key || !value) { 477 err("mem alloc failed\n"); 478 err = -1; 479 goto exit_free; 480 } 481 482 prev_key = NULL; 483 while (true) { 484 err = bpf_map_get_next_key(fd, prev_key, key); 485 if (err) { 486 if (errno == ENOENT) 487 err = 0; 488 break; 489 } 490 491 if (!bpf_map_lookup_elem(fd, key, value)) { 492 print_entry(&info, key, value); 493 } else { 494 info("can't lookup element with key: "); 495 print_hex(key, info.key_size, " "); 496 printf("\n"); 497 } 498 499 prev_key = key; 500 num_elems++; 501 } 502 503 printf("Found %u element%s\n", num_elems, num_elems != 1 ? "s" : ""); 504 505 exit_free: 506 free(key); 507 free(value); 508 close(fd); 509 510 return err; 511 } 512 513 static int do_update(int argc, char **argv) 514 { 515 struct bpf_map_info info = {}; 516 __u32 len = sizeof(info); 517 __u32 *value_fd = NULL; 518 __u32 flags = BPF_ANY; 519 void *key, *value; 520 int fd, err; 521 522 if (argc < 2) 523 usage(); 524 525 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 526 if (fd < 0) 527 return -1; 528 529 key = malloc(info.key_size); 530 value = alloc_value(&info); 531 if (!key || !value) { 532 err("mem alloc failed"); 533 err = -1; 534 goto exit_free; 535 } 536 537 err = parse_elem(argv, &info, key, value, info.key_size, 538 info.value_size, &flags, &value_fd); 539 if (err) 540 goto exit_free; 541 542 err = bpf_map_update_elem(fd, key, value, flags); 543 if (err) { 544 err("update failed: %s\n", strerror(errno)); 545 goto exit_free; 546 } 547 548 exit_free: 549 if (value_fd) 550 close(*value_fd); 551 free(key); 552 free(value); 553 close(fd); 554 555 return err; 556 } 557 558 static int do_lookup(int argc, char **argv) 559 { 560 struct bpf_map_info info = {}; 561 __u32 len = sizeof(info); 562 void *key, *value; 563 int err; 564 int fd; 565 566 if (argc < 2) 567 usage(); 568 569 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 570 if (fd < 0) 571 return -1; 572 573 key = malloc(info.key_size); 574 value = alloc_value(&info); 575 if (!key || !value) { 576 err("mem alloc failed"); 577 err = -1; 578 goto exit_free; 579 } 580 581 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); 582 if (err) 583 goto exit_free; 584 585 err = bpf_map_lookup_elem(fd, key, value); 586 if (!err) { 587 print_entry(&info, key, value); 588 } else if (errno == ENOENT) { 589 printf("key:\n"); 590 print_hex(key, info.key_size, " "); 591 printf("\n\nNot found\n"); 592 } else { 593 err("lookup failed: %s\n", strerror(errno)); 594 } 595 596 exit_free: 597 free(key); 598 free(value); 599 close(fd); 600 601 return err; 602 } 603 604 static int do_getnext(int argc, char **argv) 605 { 606 struct bpf_map_info info = {}; 607 __u32 len = sizeof(info); 608 void *key, *nextkey; 609 int err; 610 int fd; 611 612 if (argc < 2) 613 usage(); 614 615 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 616 if (fd < 0) 617 return -1; 618 619 key = malloc(info.key_size); 620 nextkey = malloc(info.key_size); 621 if (!key || !nextkey) { 622 err("mem alloc failed"); 623 err = -1; 624 goto exit_free; 625 } 626 627 if (argc) { 628 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, 629 NULL, NULL); 630 if (err) 631 goto exit_free; 632 } else { 633 free(key); 634 key = NULL; 635 } 636 637 err = bpf_map_get_next_key(fd, key, nextkey); 638 if (err) { 639 err("can't get next key: %s\n", strerror(errno)); 640 goto exit_free; 641 } 642 643 if (key) { 644 printf("key:\n"); 645 print_hex(key, info.key_size, " "); 646 printf("\n"); 647 } else { 648 printf("key: None\n"); 649 } 650 651 printf("next key:\n"); 652 print_hex(nextkey, info.key_size, " "); 653 printf("\n"); 654 655 exit_free: 656 free(nextkey); 657 free(key); 658 close(fd); 659 660 return err; 661 } 662 663 static int do_delete(int argc, char **argv) 664 { 665 struct bpf_map_info info = {}; 666 __u32 len = sizeof(info); 667 void *key; 668 int err; 669 int fd; 670 671 if (argc < 2) 672 usage(); 673 674 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 675 if (fd < 0) 676 return -1; 677 678 key = malloc(info.key_size); 679 if (!key) { 680 err("mem alloc failed"); 681 err = -1; 682 goto exit_free; 683 } 684 685 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); 686 if (err) 687 goto exit_free; 688 689 err = bpf_map_delete_elem(fd, key); 690 if (err) 691 err("delete failed: %s\n", strerror(errno)); 692 693 exit_free: 694 free(key); 695 close(fd); 696 697 return err; 698 } 699 700 static int do_pin(int argc, char **argv) 701 { 702 return do_pin_any(argc, argv, bpf_map_get_fd_by_id); 703 } 704 705 static int do_help(int argc, char **argv) 706 { 707 fprintf(stderr, 708 "Usage: %s %s show [MAP]\n" 709 " %s %s dump MAP\n" 710 " %s %s update MAP key BYTES value VALUE [UPDATE_FLAGS]\n" 711 " %s %s lookup MAP key BYTES\n" 712 " %s %s getnext MAP [key BYTES]\n" 713 " %s %s delete MAP key BYTES\n" 714 " %s %s pin MAP FILE\n" 715 " %s %s help\n" 716 "\n" 717 " MAP := { id MAP_ID | pinned FILE }\n" 718 " " HELP_SPEC_PROGRAM "\n" 719 " VALUE := { BYTES | MAP | PROG }\n" 720 " UPDATE_FLAGS := { any | exist | noexist }\n" 721 "", 722 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 723 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 724 bin_name, argv[-2], bin_name, argv[-2]); 725 726 return 0; 727 } 728 729 static const struct cmd cmds[] = { 730 { "show", do_show }, 731 { "help", do_help }, 732 { "dump", do_dump }, 733 { "update", do_update }, 734 { "lookup", do_lookup }, 735 { "getnext", do_getnext }, 736 { "delete", do_delete }, 737 { "pin", do_pin }, 738 { 0 } 739 }; 740 741 int do_map(int argc, char **argv) 742 { 743 return cmd_select(cmds, argc, argv, do_help); 744 } 745