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 /* Author: Jakub Kicinski <kubakici@wp.pl> */ 35 36 #include <assert.h> 37 #include <errno.h> 38 #include <fcntl.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 "main.h" 50 51 static const char * const map_type_name[] = { 52 [BPF_MAP_TYPE_UNSPEC] = "unspec", 53 [BPF_MAP_TYPE_HASH] = "hash", 54 [BPF_MAP_TYPE_ARRAY] = "array", 55 [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array", 56 [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array", 57 [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash", 58 [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array", 59 [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace", 60 [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array", 61 [BPF_MAP_TYPE_LRU_HASH] = "lru_hash", 62 [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash", 63 [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie", 64 [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps", 65 [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps", 66 [BPF_MAP_TYPE_DEVMAP] = "devmap", 67 [BPF_MAP_TYPE_SOCKMAP] = "sockmap", 68 [BPF_MAP_TYPE_CPUMAP] = "cpumap", 69 }; 70 71 static bool map_is_per_cpu(__u32 type) 72 { 73 return type == BPF_MAP_TYPE_PERCPU_HASH || 74 type == BPF_MAP_TYPE_PERCPU_ARRAY || 75 type == BPF_MAP_TYPE_LRU_PERCPU_HASH; 76 } 77 78 static bool map_is_map_of_maps(__u32 type) 79 { 80 return type == BPF_MAP_TYPE_ARRAY_OF_MAPS || 81 type == BPF_MAP_TYPE_HASH_OF_MAPS; 82 } 83 84 static bool map_is_map_of_progs(__u32 type) 85 { 86 return type == BPF_MAP_TYPE_PROG_ARRAY; 87 } 88 89 static void *alloc_value(struct bpf_map_info *info) 90 { 91 if (map_is_per_cpu(info->type)) 92 return malloc(info->value_size * get_possible_cpus()); 93 else 94 return malloc(info->value_size); 95 } 96 97 static int map_parse_fd(int *argc, char ***argv) 98 { 99 int fd; 100 101 if (is_prefix(**argv, "id")) { 102 unsigned int id; 103 char *endptr; 104 105 NEXT_ARGP(); 106 107 id = strtoul(**argv, &endptr, 0); 108 if (*endptr) { 109 p_err("can't parse %s as ID", **argv); 110 return -1; 111 } 112 NEXT_ARGP(); 113 114 fd = bpf_map_get_fd_by_id(id); 115 if (fd < 0) 116 p_err("get map by id (%u): %s", id, strerror(errno)); 117 return fd; 118 } else if (is_prefix(**argv, "pinned")) { 119 char *path; 120 121 NEXT_ARGP(); 122 123 path = **argv; 124 NEXT_ARGP(); 125 126 return open_obj_pinned_any(path, BPF_OBJ_MAP); 127 } 128 129 p_err("expected 'id' or 'pinned', got: '%s'?", **argv); 130 return -1; 131 } 132 133 int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) 134 { 135 int err; 136 int fd; 137 138 fd = map_parse_fd(argc, argv); 139 if (fd < 0) 140 return -1; 141 142 err = bpf_obj_get_info_by_fd(fd, info, info_len); 143 if (err) { 144 p_err("can't get map info: %s", strerror(errno)); 145 close(fd); 146 return err; 147 } 148 149 return fd; 150 } 151 152 static void print_entry_json(struct bpf_map_info *info, unsigned char *key, 153 unsigned char *value) 154 { 155 jsonw_start_object(json_wtr); 156 157 if (!map_is_per_cpu(info->type)) { 158 jsonw_name(json_wtr, "key"); 159 print_hex_data_json(key, info->key_size); 160 jsonw_name(json_wtr, "value"); 161 print_hex_data_json(value, info->value_size); 162 } else { 163 unsigned int i, n; 164 165 n = get_possible_cpus(); 166 167 jsonw_name(json_wtr, "key"); 168 print_hex_data_json(key, info->key_size); 169 170 jsonw_name(json_wtr, "values"); 171 jsonw_start_array(json_wtr); 172 for (i = 0; i < n; i++) { 173 jsonw_start_object(json_wtr); 174 175 jsonw_int_field(json_wtr, "cpu", i); 176 177 jsonw_name(json_wtr, "value"); 178 print_hex_data_json(value + i * info->value_size, 179 info->value_size); 180 181 jsonw_end_object(json_wtr); 182 } 183 jsonw_end_array(json_wtr); 184 } 185 186 jsonw_end_object(json_wtr); 187 } 188 189 static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, 190 unsigned char *value) 191 { 192 if (!map_is_per_cpu(info->type)) { 193 bool single_line, break_names; 194 195 break_names = info->key_size > 16 || info->value_size > 16; 196 single_line = info->key_size + info->value_size <= 24 && 197 !break_names; 198 199 printf("key:%c", break_names ? '\n' : ' '); 200 fprint_hex(stdout, key, info->key_size, " "); 201 202 printf(single_line ? " " : "\n"); 203 204 printf("value:%c", break_names ? '\n' : ' '); 205 fprint_hex(stdout, value, info->value_size, " "); 206 207 printf("\n"); 208 } else { 209 unsigned int i, n; 210 211 n = get_possible_cpus(); 212 213 printf("key:\n"); 214 fprint_hex(stdout, key, info->key_size, " "); 215 printf("\n"); 216 for (i = 0; i < n; i++) { 217 printf("value (CPU %02d):%c", 218 i, info->value_size > 16 ? '\n' : ' '); 219 fprint_hex(stdout, value + i * info->value_size, 220 info->value_size, " "); 221 printf("\n"); 222 } 223 } 224 } 225 226 static char **parse_bytes(char **argv, const char *name, unsigned char *val, 227 unsigned int n) 228 { 229 unsigned int i = 0, base = 0; 230 char *endptr; 231 232 if (is_prefix(*argv, "hex")) { 233 base = 16; 234 argv++; 235 } 236 237 while (i < n && argv[i]) { 238 val[i] = strtoul(argv[i], &endptr, base); 239 if (*endptr) { 240 p_err("error parsing byte: %s", argv[i]); 241 return NULL; 242 } 243 i++; 244 } 245 246 if (i != n) { 247 p_err("%s expected %d bytes got %d", name, n, i); 248 return NULL; 249 } 250 251 return argv + i; 252 } 253 254 static int parse_elem(char **argv, struct bpf_map_info *info, 255 void *key, void *value, __u32 key_size, __u32 value_size, 256 __u32 *flags, __u32 **value_fd) 257 { 258 if (!*argv) { 259 if (!key && !value) 260 return 0; 261 p_err("did not find %s", key ? "key" : "value"); 262 return -1; 263 } 264 265 if (is_prefix(*argv, "key")) { 266 if (!key) { 267 if (key_size) 268 p_err("duplicate key"); 269 else 270 p_err("unnecessary key"); 271 return -1; 272 } 273 274 argv = parse_bytes(argv + 1, "key", key, key_size); 275 if (!argv) 276 return -1; 277 278 return parse_elem(argv, info, NULL, value, key_size, value_size, 279 flags, value_fd); 280 } else if (is_prefix(*argv, "value")) { 281 int fd; 282 283 if (!value) { 284 if (value_size) 285 p_err("duplicate value"); 286 else 287 p_err("unnecessary value"); 288 return -1; 289 } 290 291 argv++; 292 293 if (map_is_map_of_maps(info->type)) { 294 int argc = 2; 295 296 if (value_size != 4) { 297 p_err("value smaller than 4B for map in map?"); 298 return -1; 299 } 300 if (!argv[0] || !argv[1]) { 301 p_err("not enough value arguments for map in map"); 302 return -1; 303 } 304 305 fd = map_parse_fd(&argc, &argv); 306 if (fd < 0) 307 return -1; 308 309 *value_fd = value; 310 **value_fd = fd; 311 } else if (map_is_map_of_progs(info->type)) { 312 int argc = 2; 313 314 if (value_size != 4) { 315 p_err("value smaller than 4B for map of progs?"); 316 return -1; 317 } 318 if (!argv[0] || !argv[1]) { 319 p_err("not enough value arguments for map of progs"); 320 return -1; 321 } 322 323 fd = prog_parse_fd(&argc, &argv); 324 if (fd < 0) 325 return -1; 326 327 *value_fd = value; 328 **value_fd = fd; 329 } else { 330 argv = parse_bytes(argv, "value", value, value_size); 331 if (!argv) 332 return -1; 333 } 334 335 return parse_elem(argv, info, key, NULL, key_size, value_size, 336 flags, NULL); 337 } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") || 338 is_prefix(*argv, "exist")) { 339 if (!flags) { 340 p_err("flags specified multiple times: %s", *argv); 341 return -1; 342 } 343 344 if (is_prefix(*argv, "any")) 345 *flags = BPF_ANY; 346 else if (is_prefix(*argv, "noexist")) 347 *flags = BPF_NOEXIST; 348 else if (is_prefix(*argv, "exist")) 349 *flags = BPF_EXIST; 350 351 return parse_elem(argv + 1, info, key, value, key_size, 352 value_size, NULL, value_fd); 353 } 354 355 p_err("expected key or value, got: %s", *argv); 356 return -1; 357 } 358 359 static int show_map_close_json(int fd, struct bpf_map_info *info) 360 { 361 char *memlock; 362 363 memlock = get_fdinfo(fd, "memlock"); 364 close(fd); 365 366 jsonw_start_object(json_wtr); 367 368 jsonw_uint_field(json_wtr, "id", info->id); 369 if (info->type < ARRAY_SIZE(map_type_name)) 370 jsonw_string_field(json_wtr, "type", 371 map_type_name[info->type]); 372 else 373 jsonw_uint_field(json_wtr, "type", info->type); 374 375 if (*info->name) 376 jsonw_string_field(json_wtr, "name", info->name); 377 378 jsonw_name(json_wtr, "flags"); 379 jsonw_printf(json_wtr, "%d", info->map_flags); 380 381 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 382 383 jsonw_uint_field(json_wtr, "bytes_key", info->key_size); 384 jsonw_uint_field(json_wtr, "bytes_value", info->value_size); 385 jsonw_uint_field(json_wtr, "max_entries", info->max_entries); 386 387 if (memlock) 388 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 389 free(memlock); 390 391 if (!hash_empty(map_table.table)) { 392 struct pinned_obj *obj; 393 394 jsonw_name(json_wtr, "pinned"); 395 jsonw_start_array(json_wtr); 396 hash_for_each_possible(map_table.table, obj, hash, info->id) { 397 if (obj->id == info->id) 398 jsonw_string(json_wtr, obj->path); 399 } 400 jsonw_end_array(json_wtr); 401 } 402 403 jsonw_end_object(json_wtr); 404 405 return 0; 406 } 407 408 static int show_map_close_plain(int fd, struct bpf_map_info *info) 409 { 410 char *memlock; 411 412 memlock = get_fdinfo(fd, "memlock"); 413 close(fd); 414 415 printf("%u: ", info->id); 416 if (info->type < ARRAY_SIZE(map_type_name)) 417 printf("%s ", map_type_name[info->type]); 418 else 419 printf("type %u ", info->type); 420 421 if (*info->name) 422 printf("name %s ", info->name); 423 424 printf("flags 0x%x", info->map_flags); 425 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 426 printf("\n"); 427 printf("\tkey %uB value %uB max_entries %u", 428 info->key_size, info->value_size, info->max_entries); 429 430 if (memlock) 431 printf(" memlock %sB", memlock); 432 free(memlock); 433 434 printf("\n"); 435 if (!hash_empty(map_table.table)) { 436 struct pinned_obj *obj; 437 438 hash_for_each_possible(map_table.table, obj, hash, info->id) { 439 if (obj->id == info->id) 440 printf("\tpinned %s\n", obj->path); 441 } 442 } 443 return 0; 444 } 445 446 static int do_show(int argc, char **argv) 447 { 448 struct bpf_map_info info = {}; 449 __u32 len = sizeof(info); 450 __u32 id = 0; 451 int err; 452 int fd; 453 454 if (show_pinned) 455 build_pinned_obj_table(&map_table, BPF_OBJ_MAP); 456 457 if (argc == 2) { 458 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 459 if (fd < 0) 460 return -1; 461 462 if (json_output) 463 return show_map_close_json(fd, &info); 464 else 465 return show_map_close_plain(fd, &info); 466 } 467 468 if (argc) 469 return BAD_ARG(); 470 471 if (json_output) 472 jsonw_start_array(json_wtr); 473 while (true) { 474 err = bpf_map_get_next_id(id, &id); 475 if (err) { 476 if (errno == ENOENT) 477 break; 478 p_err("can't get next map: %s%s", strerror(errno), 479 errno == EINVAL ? " -- kernel too old?" : ""); 480 break; 481 } 482 483 fd = bpf_map_get_fd_by_id(id); 484 if (fd < 0) { 485 if (errno == ENOENT) 486 continue; 487 p_err("can't get map by id (%u): %s", 488 id, strerror(errno)); 489 break; 490 } 491 492 err = bpf_obj_get_info_by_fd(fd, &info, &len); 493 if (err) { 494 p_err("can't get map info: %s", strerror(errno)); 495 close(fd); 496 break; 497 } 498 499 if (json_output) 500 show_map_close_json(fd, &info); 501 else 502 show_map_close_plain(fd, &info); 503 } 504 if (json_output) 505 jsonw_end_array(json_wtr); 506 507 return errno == ENOENT ? 0 : -1; 508 } 509 510 static int do_dump(int argc, char **argv) 511 { 512 void *key, *value, *prev_key; 513 unsigned int num_elems = 0; 514 struct bpf_map_info info = {}; 515 __u32 len = sizeof(info); 516 int err; 517 int fd; 518 519 if (argc != 2) 520 usage(); 521 522 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 523 if (fd < 0) 524 return -1; 525 526 if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) { 527 p_err("Dumping maps of maps and program maps not supported"); 528 close(fd); 529 return -1; 530 } 531 532 key = malloc(info.key_size); 533 value = alloc_value(&info); 534 if (!key || !value) { 535 p_err("mem alloc failed"); 536 err = -1; 537 goto exit_free; 538 } 539 540 prev_key = NULL; 541 if (json_output) 542 jsonw_start_array(json_wtr); 543 while (true) { 544 err = bpf_map_get_next_key(fd, prev_key, key); 545 if (err) { 546 if (errno == ENOENT) 547 err = 0; 548 break; 549 } 550 551 if (!bpf_map_lookup_elem(fd, key, value)) { 552 if (json_output) 553 print_entry_json(&info, key, value); 554 else 555 print_entry_plain(&info, key, value); 556 } else { 557 if (json_output) { 558 jsonw_name(json_wtr, "key"); 559 print_hex_data_json(key, info.key_size); 560 jsonw_name(json_wtr, "value"); 561 jsonw_start_object(json_wtr); 562 jsonw_string_field(json_wtr, "error", 563 "can't lookup element"); 564 jsonw_end_object(json_wtr); 565 } else { 566 p_info("can't lookup element with key: "); 567 fprint_hex(stderr, key, info.key_size, " "); 568 fprintf(stderr, "\n"); 569 } 570 } 571 572 prev_key = key; 573 num_elems++; 574 } 575 576 if (json_output) 577 jsonw_end_array(json_wtr); 578 else 579 printf("Found %u element%s\n", num_elems, 580 num_elems != 1 ? "s" : ""); 581 582 exit_free: 583 free(key); 584 free(value); 585 close(fd); 586 587 return err; 588 } 589 590 static int do_update(int argc, char **argv) 591 { 592 struct bpf_map_info info = {}; 593 __u32 len = sizeof(info); 594 __u32 *value_fd = NULL; 595 __u32 flags = BPF_ANY; 596 void *key, *value; 597 int fd, err; 598 599 if (argc < 2) 600 usage(); 601 602 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 603 if (fd < 0) 604 return -1; 605 606 key = malloc(info.key_size); 607 value = alloc_value(&info); 608 if (!key || !value) { 609 p_err("mem alloc failed"); 610 err = -1; 611 goto exit_free; 612 } 613 614 err = parse_elem(argv, &info, key, value, info.key_size, 615 info.value_size, &flags, &value_fd); 616 if (err) 617 goto exit_free; 618 619 err = bpf_map_update_elem(fd, key, value, flags); 620 if (err) { 621 p_err("update failed: %s", strerror(errno)); 622 goto exit_free; 623 } 624 625 exit_free: 626 if (value_fd) 627 close(*value_fd); 628 free(key); 629 free(value); 630 close(fd); 631 632 if (!err && json_output) 633 jsonw_null(json_wtr); 634 return err; 635 } 636 637 static int do_lookup(int argc, char **argv) 638 { 639 struct bpf_map_info info = {}; 640 __u32 len = sizeof(info); 641 void *key, *value; 642 int err; 643 int fd; 644 645 if (argc < 2) 646 usage(); 647 648 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 649 if (fd < 0) 650 return -1; 651 652 key = malloc(info.key_size); 653 value = alloc_value(&info); 654 if (!key || !value) { 655 p_err("mem alloc failed"); 656 err = -1; 657 goto exit_free; 658 } 659 660 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); 661 if (err) 662 goto exit_free; 663 664 err = bpf_map_lookup_elem(fd, key, value); 665 if (!err) { 666 if (json_output) 667 print_entry_json(&info, key, value); 668 else 669 print_entry_plain(&info, key, value); 670 } else if (errno == ENOENT) { 671 if (json_output) { 672 jsonw_null(json_wtr); 673 } else { 674 printf("key:\n"); 675 fprint_hex(stdout, key, info.key_size, " "); 676 printf("\n\nNot found\n"); 677 } 678 } else { 679 p_err("lookup failed: %s", strerror(errno)); 680 } 681 682 exit_free: 683 free(key); 684 free(value); 685 close(fd); 686 687 return err; 688 } 689 690 static int do_getnext(int argc, char **argv) 691 { 692 struct bpf_map_info info = {}; 693 __u32 len = sizeof(info); 694 void *key, *nextkey; 695 int err; 696 int fd; 697 698 if (argc < 2) 699 usage(); 700 701 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 702 if (fd < 0) 703 return -1; 704 705 key = malloc(info.key_size); 706 nextkey = malloc(info.key_size); 707 if (!key || !nextkey) { 708 p_err("mem alloc failed"); 709 err = -1; 710 goto exit_free; 711 } 712 713 if (argc) { 714 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, 715 NULL, NULL); 716 if (err) 717 goto exit_free; 718 } else { 719 free(key); 720 key = NULL; 721 } 722 723 err = bpf_map_get_next_key(fd, key, nextkey); 724 if (err) { 725 p_err("can't get next key: %s", strerror(errno)); 726 goto exit_free; 727 } 728 729 if (json_output) { 730 jsonw_start_object(json_wtr); 731 if (key) { 732 jsonw_name(json_wtr, "key"); 733 print_hex_data_json(key, info.key_size); 734 } else { 735 jsonw_null_field(json_wtr, "key"); 736 } 737 jsonw_name(json_wtr, "next_key"); 738 print_hex_data_json(nextkey, info.key_size); 739 jsonw_end_object(json_wtr); 740 } else { 741 if (key) { 742 printf("key:\n"); 743 fprint_hex(stdout, key, info.key_size, " "); 744 printf("\n"); 745 } else { 746 printf("key: None\n"); 747 } 748 printf("next key:\n"); 749 fprint_hex(stdout, nextkey, info.key_size, " "); 750 printf("\n"); 751 } 752 753 exit_free: 754 free(nextkey); 755 free(key); 756 close(fd); 757 758 return err; 759 } 760 761 static int do_delete(int argc, char **argv) 762 { 763 struct bpf_map_info info = {}; 764 __u32 len = sizeof(info); 765 void *key; 766 int err; 767 int fd; 768 769 if (argc < 2) 770 usage(); 771 772 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 773 if (fd < 0) 774 return -1; 775 776 key = malloc(info.key_size); 777 if (!key) { 778 p_err("mem alloc failed"); 779 err = -1; 780 goto exit_free; 781 } 782 783 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); 784 if (err) 785 goto exit_free; 786 787 err = bpf_map_delete_elem(fd, key); 788 if (err) 789 p_err("delete failed: %s", strerror(errno)); 790 791 exit_free: 792 free(key); 793 close(fd); 794 795 if (!err && json_output) 796 jsonw_null(json_wtr); 797 return err; 798 } 799 800 static int do_pin(int argc, char **argv) 801 { 802 int err; 803 804 err = do_pin_any(argc, argv, bpf_map_get_fd_by_id); 805 if (!err && json_output) 806 jsonw_null(json_wtr); 807 return err; 808 } 809 810 static int do_help(int argc, char **argv) 811 { 812 if (json_output) { 813 jsonw_null(json_wtr); 814 return 0; 815 } 816 817 fprintf(stderr, 818 "Usage: %s %s { show | list } [MAP]\n" 819 " %s %s dump MAP\n" 820 " %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n" 821 " %s %s lookup MAP key DATA\n" 822 " %s %s getnext MAP [key DATA]\n" 823 " %s %s delete MAP key DATA\n" 824 " %s %s pin MAP FILE\n" 825 " %s %s event_pipe MAP [cpu N index M]\n" 826 " %s %s help\n" 827 "\n" 828 " MAP := { id MAP_ID | pinned FILE }\n" 829 " DATA := { [hex] BYTES }\n" 830 " " HELP_SPEC_PROGRAM "\n" 831 " VALUE := { DATA | MAP | PROG }\n" 832 " UPDATE_FLAGS := { any | exist | noexist }\n" 833 " " HELP_SPEC_OPTIONS "\n" 834 "", 835 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 836 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 837 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 838 839 return 0; 840 } 841 842 static const struct cmd cmds[] = { 843 { "show", do_show }, 844 { "list", do_show }, 845 { "help", do_help }, 846 { "dump", do_dump }, 847 { "update", do_update }, 848 { "lookup", do_lookup }, 849 { "getnext", do_getnext }, 850 { "delete", do_delete }, 851 { "pin", do_pin }, 852 { "event_pipe", do_event_pipe }, 853 { 0 } 854 }; 855 856 int do_map(int argc, char **argv) 857 { 858 return cmd_select(cmds, argc, argv, do_help); 859 } 860