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