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