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