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