1 /* 2 * Copyright (C) 2017-2018 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 #include <assert.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <linux/err.h> 38 #include <linux/kernel.h> 39 #include <stdbool.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 47 #include <bpf.h> 48 49 #include "btf.h" 50 #include "json_writer.h" 51 #include "main.h" 52 53 static const char * const map_type_name[] = { 54 [BPF_MAP_TYPE_UNSPEC] = "unspec", 55 [BPF_MAP_TYPE_HASH] = "hash", 56 [BPF_MAP_TYPE_ARRAY] = "array", 57 [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array", 58 [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array", 59 [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash", 60 [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array", 61 [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace", 62 [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array", 63 [BPF_MAP_TYPE_LRU_HASH] = "lru_hash", 64 [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash", 65 [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie", 66 [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps", 67 [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps", 68 [BPF_MAP_TYPE_DEVMAP] = "devmap", 69 [BPF_MAP_TYPE_SOCKMAP] = "sockmap", 70 [BPF_MAP_TYPE_CPUMAP] = "cpumap", 71 [BPF_MAP_TYPE_XSKMAP] = "xskmap", 72 [BPF_MAP_TYPE_SOCKHASH] = "sockhash", 73 [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage", 74 }; 75 76 static bool map_is_per_cpu(__u32 type) 77 { 78 return type == BPF_MAP_TYPE_PERCPU_HASH || 79 type == BPF_MAP_TYPE_PERCPU_ARRAY || 80 type == BPF_MAP_TYPE_LRU_PERCPU_HASH; 81 } 82 83 static bool map_is_map_of_maps(__u32 type) 84 { 85 return type == BPF_MAP_TYPE_ARRAY_OF_MAPS || 86 type == BPF_MAP_TYPE_HASH_OF_MAPS; 87 } 88 89 static bool map_is_map_of_progs(__u32 type) 90 { 91 return type == BPF_MAP_TYPE_PROG_ARRAY; 92 } 93 94 static void *alloc_value(struct bpf_map_info *info) 95 { 96 if (map_is_per_cpu(info->type)) 97 return malloc(round_up(info->value_size, 8) * 98 get_possible_cpus()); 99 else 100 return malloc(info->value_size); 101 } 102 103 int map_parse_fd(int *argc, char ***argv) 104 { 105 int fd; 106 107 if (is_prefix(**argv, "id")) { 108 unsigned int id; 109 char *endptr; 110 111 NEXT_ARGP(); 112 113 id = strtoul(**argv, &endptr, 0); 114 if (*endptr) { 115 p_err("can't parse %s as ID", **argv); 116 return -1; 117 } 118 NEXT_ARGP(); 119 120 fd = bpf_map_get_fd_by_id(id); 121 if (fd < 0) 122 p_err("get map by id (%u): %s", id, strerror(errno)); 123 return fd; 124 } else if (is_prefix(**argv, "pinned")) { 125 char *path; 126 127 NEXT_ARGP(); 128 129 path = **argv; 130 NEXT_ARGP(); 131 132 return open_obj_pinned_any(path, BPF_OBJ_MAP); 133 } 134 135 p_err("expected 'id' or 'pinned', got: '%s'?", **argv); 136 return -1; 137 } 138 139 int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) 140 { 141 int err; 142 int fd; 143 144 fd = map_parse_fd(argc, argv); 145 if (fd < 0) 146 return -1; 147 148 err = bpf_obj_get_info_by_fd(fd, info, info_len); 149 if (err) { 150 p_err("can't get map info: %s", strerror(errno)); 151 close(fd); 152 return err; 153 } 154 155 return fd; 156 } 157 158 static int do_dump_btf(const struct btf_dumper *d, 159 struct bpf_map_info *map_info, void *key, 160 void *value) 161 { 162 int ret; 163 164 /* start of key-value pair */ 165 jsonw_start_object(d->jw); 166 167 jsonw_name(d->jw, "key"); 168 169 ret = btf_dumper_type(d, map_info->btf_key_type_id, key); 170 if (ret) 171 goto err_end_obj; 172 173 jsonw_name(d->jw, "value"); 174 175 ret = btf_dumper_type(d, map_info->btf_value_type_id, value); 176 177 err_end_obj: 178 /* end of key-value pair */ 179 jsonw_end_object(d->jw); 180 181 return ret; 182 } 183 184 static int get_btf(struct bpf_map_info *map_info, struct btf **btf) 185 { 186 struct bpf_btf_info btf_info = { 0 }; 187 __u32 len = sizeof(btf_info); 188 __u32 last_size; 189 int btf_fd; 190 void *ptr; 191 int err; 192 193 err = 0; 194 *btf = NULL; 195 btf_fd = bpf_btf_get_fd_by_id(map_info->btf_id); 196 if (btf_fd < 0) 197 return 0; 198 199 /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so 200 * let's start with a sane default - 4KiB here - and resize it only if 201 * bpf_obj_get_info_by_fd() needs a bigger buffer. 202 */ 203 btf_info.btf_size = 4096; 204 last_size = btf_info.btf_size; 205 ptr = malloc(last_size); 206 if (!ptr) { 207 err = -ENOMEM; 208 goto exit_free; 209 } 210 211 bzero(ptr, last_size); 212 btf_info.btf = ptr_to_u64(ptr); 213 err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); 214 215 if (!err && btf_info.btf_size > last_size) { 216 void *temp_ptr; 217 218 last_size = btf_info.btf_size; 219 temp_ptr = realloc(ptr, last_size); 220 if (!temp_ptr) { 221 err = -ENOMEM; 222 goto exit_free; 223 } 224 ptr = temp_ptr; 225 bzero(ptr, last_size); 226 btf_info.btf = ptr_to_u64(ptr); 227 err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); 228 } 229 230 if (err || btf_info.btf_size > last_size) { 231 err = errno; 232 goto exit_free; 233 } 234 235 *btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL); 236 if (IS_ERR(*btf)) { 237 err = PTR_ERR(*btf); 238 *btf = NULL; 239 } 240 241 exit_free: 242 close(btf_fd); 243 free(ptr); 244 245 return err; 246 } 247 248 static json_writer_t *get_btf_writer(void) 249 { 250 json_writer_t *jw = jsonw_new(stdout); 251 252 if (!jw) 253 return NULL; 254 jsonw_pretty(jw, true); 255 256 return jw; 257 } 258 259 static void print_entry_json(struct bpf_map_info *info, unsigned char *key, 260 unsigned char *value, struct btf *btf) 261 { 262 jsonw_start_object(json_wtr); 263 264 if (!map_is_per_cpu(info->type)) { 265 jsonw_name(json_wtr, "key"); 266 print_hex_data_json(key, info->key_size); 267 jsonw_name(json_wtr, "value"); 268 print_hex_data_json(value, info->value_size); 269 if (btf) { 270 struct btf_dumper d = { 271 .btf = btf, 272 .jw = json_wtr, 273 .is_plain_text = false, 274 }; 275 276 jsonw_name(json_wtr, "formatted"); 277 do_dump_btf(&d, info, key, value); 278 } 279 } else { 280 unsigned int i, n, step; 281 282 n = get_possible_cpus(); 283 step = round_up(info->value_size, 8); 284 285 jsonw_name(json_wtr, "key"); 286 print_hex_data_json(key, info->key_size); 287 288 jsonw_name(json_wtr, "values"); 289 jsonw_start_array(json_wtr); 290 for (i = 0; i < n; i++) { 291 jsonw_start_object(json_wtr); 292 293 jsonw_int_field(json_wtr, "cpu", i); 294 295 jsonw_name(json_wtr, "value"); 296 print_hex_data_json(value + i * step, 297 info->value_size); 298 299 jsonw_end_object(json_wtr); 300 } 301 jsonw_end_array(json_wtr); 302 } 303 304 jsonw_end_object(json_wtr); 305 } 306 307 static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, 308 unsigned char *value) 309 { 310 if (!map_is_per_cpu(info->type)) { 311 bool single_line, break_names; 312 313 break_names = info->key_size > 16 || info->value_size > 16; 314 single_line = info->key_size + info->value_size <= 24 && 315 !break_names; 316 317 printf("key:%c", break_names ? '\n' : ' '); 318 fprint_hex(stdout, key, info->key_size, " "); 319 320 printf(single_line ? " " : "\n"); 321 322 printf("value:%c", break_names ? '\n' : ' '); 323 fprint_hex(stdout, value, info->value_size, " "); 324 325 printf("\n"); 326 } else { 327 unsigned int i, n, step; 328 329 n = get_possible_cpus(); 330 step = round_up(info->value_size, 8); 331 332 printf("key:\n"); 333 fprint_hex(stdout, key, info->key_size, " "); 334 printf("\n"); 335 for (i = 0; i < n; i++) { 336 printf("value (CPU %02d):%c", 337 i, info->value_size > 16 ? '\n' : ' '); 338 fprint_hex(stdout, value + i * step, 339 info->value_size, " "); 340 printf("\n"); 341 } 342 } 343 } 344 345 static char **parse_bytes(char **argv, const char *name, unsigned char *val, 346 unsigned int n) 347 { 348 unsigned int i = 0, base = 0; 349 char *endptr; 350 351 if (is_prefix(*argv, "hex")) { 352 base = 16; 353 argv++; 354 } 355 356 while (i < n && argv[i]) { 357 val[i] = strtoul(argv[i], &endptr, base); 358 if (*endptr) { 359 p_err("error parsing byte: %s", argv[i]); 360 return NULL; 361 } 362 i++; 363 } 364 365 if (i != n) { 366 p_err("%s expected %d bytes got %d", name, n, i); 367 return NULL; 368 } 369 370 return argv + i; 371 } 372 373 static int parse_elem(char **argv, struct bpf_map_info *info, 374 void *key, void *value, __u32 key_size, __u32 value_size, 375 __u32 *flags, __u32 **value_fd) 376 { 377 if (!*argv) { 378 if (!key && !value) 379 return 0; 380 p_err("did not find %s", key ? "key" : "value"); 381 return -1; 382 } 383 384 if (is_prefix(*argv, "key")) { 385 if (!key) { 386 if (key_size) 387 p_err("duplicate key"); 388 else 389 p_err("unnecessary key"); 390 return -1; 391 } 392 393 argv = parse_bytes(argv + 1, "key", key, key_size); 394 if (!argv) 395 return -1; 396 397 return parse_elem(argv, info, NULL, value, key_size, value_size, 398 flags, value_fd); 399 } else if (is_prefix(*argv, "value")) { 400 int fd; 401 402 if (!value) { 403 if (value_size) 404 p_err("duplicate value"); 405 else 406 p_err("unnecessary value"); 407 return -1; 408 } 409 410 argv++; 411 412 if (map_is_map_of_maps(info->type)) { 413 int argc = 2; 414 415 if (value_size != 4) { 416 p_err("value smaller than 4B for map in map?"); 417 return -1; 418 } 419 if (!argv[0] || !argv[1]) { 420 p_err("not enough value arguments for map in map"); 421 return -1; 422 } 423 424 fd = map_parse_fd(&argc, &argv); 425 if (fd < 0) 426 return -1; 427 428 *value_fd = value; 429 **value_fd = fd; 430 } else if (map_is_map_of_progs(info->type)) { 431 int argc = 2; 432 433 if (value_size != 4) { 434 p_err("value smaller than 4B for map of progs?"); 435 return -1; 436 } 437 if (!argv[0] || !argv[1]) { 438 p_err("not enough value arguments for map of progs"); 439 return -1; 440 } 441 442 fd = prog_parse_fd(&argc, &argv); 443 if (fd < 0) 444 return -1; 445 446 *value_fd = value; 447 **value_fd = fd; 448 } else { 449 argv = parse_bytes(argv, "value", value, value_size); 450 if (!argv) 451 return -1; 452 } 453 454 return parse_elem(argv, info, key, NULL, key_size, value_size, 455 flags, NULL); 456 } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") || 457 is_prefix(*argv, "exist")) { 458 if (!flags) { 459 p_err("flags specified multiple times: %s", *argv); 460 return -1; 461 } 462 463 if (is_prefix(*argv, "any")) 464 *flags = BPF_ANY; 465 else if (is_prefix(*argv, "noexist")) 466 *flags = BPF_NOEXIST; 467 else if (is_prefix(*argv, "exist")) 468 *flags = BPF_EXIST; 469 470 return parse_elem(argv + 1, info, key, value, key_size, 471 value_size, NULL, value_fd); 472 } 473 474 p_err("expected key or value, got: %s", *argv); 475 return -1; 476 } 477 478 static int show_map_close_json(int fd, struct bpf_map_info *info) 479 { 480 char *memlock; 481 482 memlock = get_fdinfo(fd, "memlock"); 483 close(fd); 484 485 jsonw_start_object(json_wtr); 486 487 jsonw_uint_field(json_wtr, "id", info->id); 488 if (info->type < ARRAY_SIZE(map_type_name)) 489 jsonw_string_field(json_wtr, "type", 490 map_type_name[info->type]); 491 else 492 jsonw_uint_field(json_wtr, "type", info->type); 493 494 if (*info->name) 495 jsonw_string_field(json_wtr, "name", info->name); 496 497 jsonw_name(json_wtr, "flags"); 498 jsonw_printf(json_wtr, "%d", info->map_flags); 499 500 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 501 502 jsonw_uint_field(json_wtr, "bytes_key", info->key_size); 503 jsonw_uint_field(json_wtr, "bytes_value", info->value_size); 504 jsonw_uint_field(json_wtr, "max_entries", info->max_entries); 505 506 if (memlock) 507 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 508 free(memlock); 509 510 if (!hash_empty(map_table.table)) { 511 struct pinned_obj *obj; 512 513 jsonw_name(json_wtr, "pinned"); 514 jsonw_start_array(json_wtr); 515 hash_for_each_possible(map_table.table, obj, hash, info->id) { 516 if (obj->id == info->id) 517 jsonw_string(json_wtr, obj->path); 518 } 519 jsonw_end_array(json_wtr); 520 } 521 522 jsonw_end_object(json_wtr); 523 524 return 0; 525 } 526 527 static int show_map_close_plain(int fd, struct bpf_map_info *info) 528 { 529 char *memlock; 530 531 memlock = get_fdinfo(fd, "memlock"); 532 close(fd); 533 534 printf("%u: ", info->id); 535 if (info->type < ARRAY_SIZE(map_type_name)) 536 printf("%s ", map_type_name[info->type]); 537 else 538 printf("type %u ", info->type); 539 540 if (*info->name) 541 printf("name %s ", info->name); 542 543 printf("flags 0x%x", info->map_flags); 544 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 545 printf("\n"); 546 printf("\tkey %uB value %uB max_entries %u", 547 info->key_size, info->value_size, info->max_entries); 548 549 if (memlock) 550 printf(" memlock %sB", memlock); 551 free(memlock); 552 553 printf("\n"); 554 if (!hash_empty(map_table.table)) { 555 struct pinned_obj *obj; 556 557 hash_for_each_possible(map_table.table, obj, hash, info->id) { 558 if (obj->id == info->id) 559 printf("\tpinned %s\n", obj->path); 560 } 561 } 562 return 0; 563 } 564 565 static int do_show(int argc, char **argv) 566 { 567 struct bpf_map_info info = {}; 568 __u32 len = sizeof(info); 569 __u32 id = 0; 570 int err; 571 int fd; 572 573 if (show_pinned) 574 build_pinned_obj_table(&map_table, BPF_OBJ_MAP); 575 576 if (argc == 2) { 577 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 578 if (fd < 0) 579 return -1; 580 581 if (json_output) 582 return show_map_close_json(fd, &info); 583 else 584 return show_map_close_plain(fd, &info); 585 } 586 587 if (argc) 588 return BAD_ARG(); 589 590 if (json_output) 591 jsonw_start_array(json_wtr); 592 while (true) { 593 err = bpf_map_get_next_id(id, &id); 594 if (err) { 595 if (errno == ENOENT) 596 break; 597 p_err("can't get next map: %s%s", strerror(errno), 598 errno == EINVAL ? " -- kernel too old?" : ""); 599 break; 600 } 601 602 fd = bpf_map_get_fd_by_id(id); 603 if (fd < 0) { 604 if (errno == ENOENT) 605 continue; 606 p_err("can't get map by id (%u): %s", 607 id, strerror(errno)); 608 break; 609 } 610 611 err = bpf_obj_get_info_by_fd(fd, &info, &len); 612 if (err) { 613 p_err("can't get map info: %s", strerror(errno)); 614 close(fd); 615 break; 616 } 617 618 if (json_output) 619 show_map_close_json(fd, &info); 620 else 621 show_map_close_plain(fd, &info); 622 } 623 if (json_output) 624 jsonw_end_array(json_wtr); 625 626 return errno == ENOENT ? 0 : -1; 627 } 628 629 static int do_dump(int argc, char **argv) 630 { 631 struct bpf_map_info info = {}; 632 void *key, *value, *prev_key; 633 unsigned int num_elems = 0; 634 __u32 len = sizeof(info); 635 json_writer_t *btf_wtr; 636 struct btf *btf = NULL; 637 int err; 638 int fd; 639 640 if (argc != 2) 641 usage(); 642 643 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 644 if (fd < 0) 645 return -1; 646 647 if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) { 648 p_err("Dumping maps of maps and program maps not supported"); 649 close(fd); 650 return -1; 651 } 652 653 key = malloc(info.key_size); 654 value = alloc_value(&info); 655 if (!key || !value) { 656 p_err("mem alloc failed"); 657 err = -1; 658 goto exit_free; 659 } 660 661 prev_key = NULL; 662 663 err = get_btf(&info, &btf); 664 if (err) { 665 p_err("failed to get btf"); 666 goto exit_free; 667 } 668 669 if (json_output) 670 jsonw_start_array(json_wtr); 671 else 672 if (btf) { 673 btf_wtr = get_btf_writer(); 674 if (!btf_wtr) { 675 p_info("failed to create json writer for btf. falling back to plain output"); 676 btf__free(btf); 677 btf = NULL; 678 } else { 679 jsonw_start_array(btf_wtr); 680 } 681 } 682 683 while (true) { 684 err = bpf_map_get_next_key(fd, prev_key, key); 685 if (err) { 686 if (errno == ENOENT) 687 err = 0; 688 break; 689 } 690 691 if (!bpf_map_lookup_elem(fd, key, value)) { 692 if (json_output) 693 print_entry_json(&info, key, value, btf); 694 else 695 if (btf) { 696 struct btf_dumper d = { 697 .btf = btf, 698 .jw = btf_wtr, 699 .is_plain_text = true, 700 }; 701 702 do_dump_btf(&d, &info, key, value); 703 } else { 704 print_entry_plain(&info, key, value); 705 } 706 } else { 707 if (json_output) { 708 jsonw_name(json_wtr, "key"); 709 print_hex_data_json(key, info.key_size); 710 jsonw_name(json_wtr, "value"); 711 jsonw_start_object(json_wtr); 712 jsonw_string_field(json_wtr, "error", 713 "can't lookup element"); 714 jsonw_end_object(json_wtr); 715 } else { 716 p_info("can't lookup element with key: "); 717 fprint_hex(stderr, key, info.key_size, " "); 718 fprintf(stderr, "\n"); 719 } 720 } 721 722 prev_key = key; 723 num_elems++; 724 } 725 726 if (json_output) 727 jsonw_end_array(json_wtr); 728 else if (btf) { 729 jsonw_end_array(btf_wtr); 730 jsonw_destroy(&btf_wtr); 731 } else { 732 printf("Found %u element%s\n", num_elems, 733 num_elems != 1 ? "s" : ""); 734 } 735 736 exit_free: 737 free(key); 738 free(value); 739 close(fd); 740 btf__free(btf); 741 742 return err; 743 } 744 745 static int do_update(int argc, char **argv) 746 { 747 struct bpf_map_info info = {}; 748 __u32 len = sizeof(info); 749 __u32 *value_fd = NULL; 750 __u32 flags = BPF_ANY; 751 void *key, *value; 752 int fd, err; 753 754 if (argc < 2) 755 usage(); 756 757 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 758 if (fd < 0) 759 return -1; 760 761 key = malloc(info.key_size); 762 value = alloc_value(&info); 763 if (!key || !value) { 764 p_err("mem alloc failed"); 765 err = -1; 766 goto exit_free; 767 } 768 769 err = parse_elem(argv, &info, key, value, info.key_size, 770 info.value_size, &flags, &value_fd); 771 if (err) 772 goto exit_free; 773 774 err = bpf_map_update_elem(fd, key, value, flags); 775 if (err) { 776 p_err("update failed: %s", strerror(errno)); 777 goto exit_free; 778 } 779 780 exit_free: 781 if (value_fd) 782 close(*value_fd); 783 free(key); 784 free(value); 785 close(fd); 786 787 if (!err && json_output) 788 jsonw_null(json_wtr); 789 return err; 790 } 791 792 static int do_lookup(int argc, char **argv) 793 { 794 struct bpf_map_info info = {}; 795 __u32 len = sizeof(info); 796 json_writer_t *btf_wtr; 797 struct btf *btf = NULL; 798 void *key, *value; 799 int err; 800 int fd; 801 802 if (argc < 2) 803 usage(); 804 805 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 806 if (fd < 0) 807 return -1; 808 809 key = malloc(info.key_size); 810 value = alloc_value(&info); 811 if (!key || !value) { 812 p_err("mem alloc failed"); 813 err = -1; 814 goto exit_free; 815 } 816 817 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); 818 if (err) 819 goto exit_free; 820 821 err = bpf_map_lookup_elem(fd, key, value); 822 if (err) { 823 if (errno == ENOENT) { 824 if (json_output) { 825 jsonw_null(json_wtr); 826 } else { 827 printf("key:\n"); 828 fprint_hex(stdout, key, info.key_size, " "); 829 printf("\n\nNot found\n"); 830 } 831 } else { 832 p_err("lookup failed: %s", strerror(errno)); 833 } 834 835 goto exit_free; 836 } 837 838 /* here means bpf_map_lookup_elem() succeeded */ 839 err = get_btf(&info, &btf); 840 if (err) { 841 p_err("failed to get btf"); 842 goto exit_free; 843 } 844 845 if (json_output) { 846 print_entry_json(&info, key, value, btf); 847 } else if (btf) { 848 /* if here json_wtr wouldn't have been initialised, 849 * so let's create separate writer for btf 850 */ 851 btf_wtr = get_btf_writer(); 852 if (!btf_wtr) { 853 p_info("failed to create json writer for btf. falling back to plain output"); 854 btf__free(btf); 855 btf = NULL; 856 print_entry_plain(&info, key, value); 857 } else { 858 struct btf_dumper d = { 859 .btf = btf, 860 .jw = btf_wtr, 861 .is_plain_text = true, 862 }; 863 864 do_dump_btf(&d, &info, key, value); 865 jsonw_destroy(&btf_wtr); 866 } 867 } else { 868 print_entry_plain(&info, key, value); 869 } 870 871 exit_free: 872 free(key); 873 free(value); 874 close(fd); 875 btf__free(btf); 876 877 return err; 878 } 879 880 static int do_getnext(int argc, char **argv) 881 { 882 struct bpf_map_info info = {}; 883 __u32 len = sizeof(info); 884 void *key, *nextkey; 885 int err; 886 int fd; 887 888 if (argc < 2) 889 usage(); 890 891 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 892 if (fd < 0) 893 return -1; 894 895 key = malloc(info.key_size); 896 nextkey = malloc(info.key_size); 897 if (!key || !nextkey) { 898 p_err("mem alloc failed"); 899 err = -1; 900 goto exit_free; 901 } 902 903 if (argc) { 904 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, 905 NULL, NULL); 906 if (err) 907 goto exit_free; 908 } else { 909 free(key); 910 key = NULL; 911 } 912 913 err = bpf_map_get_next_key(fd, key, nextkey); 914 if (err) { 915 p_err("can't get next key: %s", strerror(errno)); 916 goto exit_free; 917 } 918 919 if (json_output) { 920 jsonw_start_object(json_wtr); 921 if (key) { 922 jsonw_name(json_wtr, "key"); 923 print_hex_data_json(key, info.key_size); 924 } else { 925 jsonw_null_field(json_wtr, "key"); 926 } 927 jsonw_name(json_wtr, "next_key"); 928 print_hex_data_json(nextkey, info.key_size); 929 jsonw_end_object(json_wtr); 930 } else { 931 if (key) { 932 printf("key:\n"); 933 fprint_hex(stdout, key, info.key_size, " "); 934 printf("\n"); 935 } else { 936 printf("key: None\n"); 937 } 938 printf("next key:\n"); 939 fprint_hex(stdout, nextkey, info.key_size, " "); 940 printf("\n"); 941 } 942 943 exit_free: 944 free(nextkey); 945 free(key); 946 close(fd); 947 948 return err; 949 } 950 951 static int do_delete(int argc, char **argv) 952 { 953 struct bpf_map_info info = {}; 954 __u32 len = sizeof(info); 955 void *key; 956 int err; 957 int fd; 958 959 if (argc < 2) 960 usage(); 961 962 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 963 if (fd < 0) 964 return -1; 965 966 key = malloc(info.key_size); 967 if (!key) { 968 p_err("mem alloc failed"); 969 err = -1; 970 goto exit_free; 971 } 972 973 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); 974 if (err) 975 goto exit_free; 976 977 err = bpf_map_delete_elem(fd, key); 978 if (err) 979 p_err("delete failed: %s", strerror(errno)); 980 981 exit_free: 982 free(key); 983 close(fd); 984 985 if (!err && json_output) 986 jsonw_null(json_wtr); 987 return err; 988 } 989 990 static int do_pin(int argc, char **argv) 991 { 992 int err; 993 994 err = do_pin_any(argc, argv, bpf_map_get_fd_by_id); 995 if (!err && json_output) 996 jsonw_null(json_wtr); 997 return err; 998 } 999 1000 static int do_help(int argc, char **argv) 1001 { 1002 if (json_output) { 1003 jsonw_null(json_wtr); 1004 return 0; 1005 } 1006 1007 fprintf(stderr, 1008 "Usage: %s %s { show | list } [MAP]\n" 1009 " %s %s dump MAP\n" 1010 " %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n" 1011 " %s %s lookup MAP key DATA\n" 1012 " %s %s getnext MAP [key DATA]\n" 1013 " %s %s delete MAP key DATA\n" 1014 " %s %s pin MAP FILE\n" 1015 " %s %s event_pipe MAP [cpu N index M]\n" 1016 " %s %s help\n" 1017 "\n" 1018 " " HELP_SPEC_MAP "\n" 1019 " DATA := { [hex] BYTES }\n" 1020 " " HELP_SPEC_PROGRAM "\n" 1021 " VALUE := { DATA | MAP | PROG }\n" 1022 " UPDATE_FLAGS := { any | exist | noexist }\n" 1023 " " HELP_SPEC_OPTIONS "\n" 1024 "", 1025 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1026 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1027 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 1028 1029 return 0; 1030 } 1031 1032 static const struct cmd cmds[] = { 1033 { "show", do_show }, 1034 { "list", do_show }, 1035 { "help", do_help }, 1036 { "dump", do_dump }, 1037 { "update", do_update }, 1038 { "lookup", do_lookup }, 1039 { "getnext", do_getnext }, 1040 { "delete", do_delete }, 1041 { "pin", do_pin }, 1042 { "event_pipe", do_event_pipe }, 1043 { 0 } 1044 }; 1045 1046 int do_map(int argc, char **argv) 1047 { 1048 return cmd_select(cmds, argc, argv, do_help); 1049 } 1050