2 * Copyright (C) 2017 Netronome Systems, Inc.
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.
9 * The BSD 2-Clause License:
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
15 * 1. Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
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.
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
34 /* Author: Jakub Kicinski <kubakici@wp.pl> */
45 #include <sys/types.h>
52 static const char * const map_type_name
[] = {
53 [BPF_MAP_TYPE_UNSPEC
] = "unspec",
54 [BPF_MAP_TYPE_HASH
] = "hash",
55 [BPF_MAP_TYPE_ARRAY
] = "array",
56 [BPF_MAP_TYPE_PROG_ARRAY
] = "prog_array",
57 [BPF_MAP_TYPE_PERF_EVENT_ARRAY
] = "perf_event_array",
58 [BPF_MAP_TYPE_PERCPU_HASH
] = "percpu_hash",
59 [BPF_MAP_TYPE_PERCPU_ARRAY
] = "percpu_array",
60 [BPF_MAP_TYPE_STACK_TRACE
] = "stack_trace",
61 [BPF_MAP_TYPE_CGROUP_ARRAY
] = "cgroup_array",
62 [BPF_MAP_TYPE_LRU_HASH
] = "lru_hash",
63 [BPF_MAP_TYPE_LRU_PERCPU_HASH
] = "lru_percpu_hash",
64 [BPF_MAP_TYPE_LPM_TRIE
] = "lpm_trie",
65 [BPF_MAP_TYPE_ARRAY_OF_MAPS
] = "array_of_maps",
66 [BPF_MAP_TYPE_HASH_OF_MAPS
] = "hash_of_maps",
67 [BPF_MAP_TYPE_DEVMAP
] = "devmap",
68 [BPF_MAP_TYPE_SOCKMAP
] = "sockmap",
71 static unsigned int get_possible_cpus(void)
73 static unsigned int result
;
82 fd
= open("/sys/devices/system/cpu/possible", O_RDONLY
);
84 p_err("can't open sysfs possible cpus");
88 n
= read(fd
, buf
, sizeof(buf
));
90 p_err("can't read sysfs possible cpus");
95 if (n
== sizeof(buf
)) {
96 p_err("read sysfs possible cpus overflow");
102 while (*ptr
&& *ptr
!= '\n') {
105 if (sscanf(ptr
, "%u-%u", &a
, &b
) == 2) {
108 ptr
= strchr(ptr
, '-') + 1;
109 } else if (sscanf(ptr
, "%u", &a
) == 1) {
115 while (isdigit(*ptr
))
126 static bool map_is_per_cpu(__u32 type
)
128 return type
== BPF_MAP_TYPE_PERCPU_HASH
||
129 type
== BPF_MAP_TYPE_PERCPU_ARRAY
||
130 type
== BPF_MAP_TYPE_LRU_PERCPU_HASH
;
133 static bool map_is_map_of_maps(__u32 type
)
135 return type
== BPF_MAP_TYPE_ARRAY_OF_MAPS
||
136 type
== BPF_MAP_TYPE_HASH_OF_MAPS
;
139 static bool map_is_map_of_progs(__u32 type
)
141 return type
== BPF_MAP_TYPE_PROG_ARRAY
;
144 static void *alloc_value(struct bpf_map_info
*info
)
146 if (map_is_per_cpu(info
->type
))
147 return malloc(info
->value_size
* get_possible_cpus());
149 return malloc(info
->value_size
);
152 static int map_parse_fd(int *argc
, char ***argv
)
156 if (is_prefix(**argv
, "id")) {
162 id
= strtoul(**argv
, &endptr
, 0);
164 p_err("can't parse %s as ID", **argv
);
169 fd
= bpf_map_get_fd_by_id(id
);
171 p_err("get map by id (%u): %s", id
, strerror(errno
));
173 } else if (is_prefix(**argv
, "pinned")) {
181 return open_obj_pinned_any(path
, BPF_OBJ_MAP
);
184 p_err("expected 'id' or 'pinned', got: '%s'?", **argv
);
189 map_parse_fd_and_info(int *argc
, char ***argv
, void *info
, __u32
*info_len
)
194 fd
= map_parse_fd(argc
, argv
);
198 err
= bpf_obj_get_info_by_fd(fd
, info
, info_len
);
200 p_err("can't get map info: %s", strerror(errno
));
208 static void print_entry_json(struct bpf_map_info
*info
, unsigned char *key
,
209 unsigned char *value
)
211 jsonw_start_object(json_wtr
);
213 if (!map_is_per_cpu(info
->type
)) {
214 jsonw_name(json_wtr
, "key");
215 print_hex_data_json(key
, info
->key_size
);
216 jsonw_name(json_wtr
, "value");
217 print_hex_data_json(value
, info
->value_size
);
221 n
= get_possible_cpus();
223 jsonw_name(json_wtr
, "key");
224 print_hex_data_json(key
, info
->key_size
);
226 jsonw_name(json_wtr
, "values");
227 jsonw_start_array(json_wtr
);
228 for (i
= 0; i
< n
; i
++) {
229 jsonw_start_object(json_wtr
);
231 jsonw_int_field(json_wtr
, "cpu", i
);
233 jsonw_name(json_wtr
, "value");
234 print_hex_data_json(value
+ i
* info
->value_size
,
237 jsonw_end_object(json_wtr
);
239 jsonw_end_array(json_wtr
);
242 jsonw_end_object(json_wtr
);
245 static void print_entry_plain(struct bpf_map_info
*info
, unsigned char *key
,
246 unsigned char *value
)
248 if (!map_is_per_cpu(info
->type
)) {
249 bool single_line
, break_names
;
251 break_names
= info
->key_size
> 16 || info
->value_size
> 16;
252 single_line
= info
->key_size
+ info
->value_size
<= 24 &&
255 printf("key:%c", break_names
? '\n' : ' ');
256 fprint_hex(stdout
, key
, info
->key_size
, " ");
258 printf(single_line
? " " : "\n");
260 printf("value:%c", break_names
? '\n' : ' ');
261 fprint_hex(stdout
, value
, info
->value_size
, " ");
267 n
= get_possible_cpus();
270 fprint_hex(stdout
, key
, info
->key_size
, " ");
272 for (i
= 0; i
< n
; i
++) {
273 printf("value (CPU %02d):%c",
274 i
, info
->value_size
> 16 ? '\n' : ' ');
275 fprint_hex(stdout
, value
+ i
* info
->value_size
,
276 info
->value_size
, " ");
282 static char **parse_bytes(char **argv
, const char *name
, unsigned char *val
,
288 while (i
< n
&& argv
[i
]) {
289 val
[i
] = strtoul(argv
[i
], &endptr
, 0);
291 p_err("error parsing byte: %s", argv
[i
]);
298 p_err("%s expected %d bytes got %d", name
, n
, i
);
305 static int parse_elem(char **argv
, struct bpf_map_info
*info
,
306 void *key
, void *value
, __u32 key_size
, __u32 value_size
,
307 __u32
*flags
, __u32
**value_fd
)
312 p_err("did not find %s", key
? "key" : "value");
316 if (is_prefix(*argv
, "key")) {
319 p_err("duplicate key");
321 p_err("unnecessary key");
325 argv
= parse_bytes(argv
+ 1, "key", key
, key_size
);
329 return parse_elem(argv
, info
, NULL
, value
, key_size
, value_size
,
331 } else if (is_prefix(*argv
, "value")) {
336 p_err("duplicate value");
338 p_err("unnecessary value");
344 if (map_is_map_of_maps(info
->type
)) {
347 if (value_size
!= 4) {
348 p_err("value smaller than 4B for map in map?");
351 if (!argv
[0] || !argv
[1]) {
352 p_err("not enough value arguments for map in map");
356 fd
= map_parse_fd(&argc
, &argv
);
362 } else if (map_is_map_of_progs(info
->type
)) {
365 if (value_size
!= 4) {
366 p_err("value smaller than 4B for map of progs?");
369 if (!argv
[0] || !argv
[1]) {
370 p_err("not enough value arguments for map of progs");
374 fd
= prog_parse_fd(&argc
, &argv
);
381 argv
= parse_bytes(argv
, "value", value
, value_size
);
386 return parse_elem(argv
, info
, key
, NULL
, key_size
, value_size
,
388 } else if (is_prefix(*argv
, "any") || is_prefix(*argv
, "noexist") ||
389 is_prefix(*argv
, "exist")) {
391 p_err("flags specified multiple times: %s", *argv
);
395 if (is_prefix(*argv
, "any"))
397 else if (is_prefix(*argv
, "noexist"))
398 *flags
= BPF_NOEXIST
;
399 else if (is_prefix(*argv
, "exist"))
402 return parse_elem(argv
+ 1, info
, key
, value
, key_size
,
403 value_size
, NULL
, value_fd
);
406 p_err("expected key or value, got: %s", *argv
);
410 static int show_map_close_json(int fd
, struct bpf_map_info
*info
)
414 memlock
= get_fdinfo(fd
, "memlock");
417 jsonw_start_object(json_wtr
);
419 jsonw_uint_field(json_wtr
, "id", info
->id
);
420 if (info
->type
< ARRAY_SIZE(map_type_name
))
421 jsonw_string_field(json_wtr
, "type",
422 map_type_name
[info
->type
]);
424 jsonw_uint_field(json_wtr
, "type", info
->type
);
427 jsonw_string_field(json_wtr
, "name", info
->name
);
429 jsonw_name(json_wtr
, "flags");
430 jsonw_printf(json_wtr
, "%#x", info
->map_flags
);
431 jsonw_uint_field(json_wtr
, "bytes_key", info
->key_size
);
432 jsonw_uint_field(json_wtr
, "bytes_value", info
->value_size
);
433 jsonw_uint_field(json_wtr
, "max_entries", info
->max_entries
);
436 jsonw_int_field(json_wtr
, "bytes_memlock", atoi(memlock
));
439 if (!hash_empty(map_table
.table
)) {
440 struct pinned_obj
*obj
;
442 jsonw_name(json_wtr
, "pinned");
443 jsonw_start_array(json_wtr
);
444 hash_for_each_possible(map_table
.table
, obj
, hash
, info
->id
) {
445 if (obj
->id
== info
->id
)
446 jsonw_string(json_wtr
, obj
->path
);
448 jsonw_end_array(json_wtr
);
451 jsonw_end_object(json_wtr
);
456 static int show_map_close_plain(int fd
, struct bpf_map_info
*info
)
460 memlock
= get_fdinfo(fd
, "memlock");
463 printf("%u: ", info
->id
);
464 if (info
->type
< ARRAY_SIZE(map_type_name
))
465 printf("%s ", map_type_name
[info
->type
]);
467 printf("type %u ", info
->type
);
470 printf("name %s ", info
->name
);
472 printf("flags 0x%x\n", info
->map_flags
);
473 printf("\tkey %uB value %uB max_entries %u",
474 info
->key_size
, info
->value_size
, info
->max_entries
);
477 printf(" memlock %sB", memlock
);
481 if (!hash_empty(map_table
.table
)) {
482 struct pinned_obj
*obj
;
484 hash_for_each_possible(map_table
.table
, obj
, hash
, info
->id
) {
485 if (obj
->id
== info
->id
)
486 printf("\tpinned %s\n", obj
->path
);
492 static int do_show(int argc
, char **argv
)
494 struct bpf_map_info info
= {};
495 __u32 len
= sizeof(info
);
501 build_pinned_obj_table(&map_table
, BPF_OBJ_MAP
);
504 fd
= map_parse_fd_and_info(&argc
, &argv
, &info
, &len
);
509 return show_map_close_json(fd
, &info
);
511 return show_map_close_plain(fd
, &info
);
518 jsonw_start_array(json_wtr
);
520 err
= bpf_map_get_next_id(id
, &id
);
524 p_err("can't get next map: %s%s", strerror(errno
),
525 errno
== EINVAL
? " -- kernel too old?" : "");
529 fd
= bpf_map_get_fd_by_id(id
);
531 p_err("can't get map by id (%u): %s",
532 id
, strerror(errno
));
536 err
= bpf_obj_get_info_by_fd(fd
, &info
, &len
);
538 p_err("can't get map info: %s", strerror(errno
));
544 show_map_close_json(fd
, &info
);
546 show_map_close_plain(fd
, &info
);
549 jsonw_end_array(json_wtr
);
551 return errno
== ENOENT
? 0 : -1;
554 static int do_dump(int argc
, char **argv
)
556 void *key
, *value
, *prev_key
;
557 unsigned int num_elems
= 0;
558 struct bpf_map_info info
= {};
559 __u32 len
= sizeof(info
);
566 fd
= map_parse_fd_and_info(&argc
, &argv
, &info
, &len
);
570 if (map_is_map_of_maps(info
.type
) || map_is_map_of_progs(info
.type
)) {
571 p_err("Dumping maps of maps and program maps not supported");
576 key
= malloc(info
.key_size
);
577 value
= alloc_value(&info
);
578 if (!key
|| !value
) {
579 p_err("mem alloc failed");
586 jsonw_start_array(json_wtr
);
588 err
= bpf_map_get_next_key(fd
, prev_key
, key
);
595 if (!bpf_map_lookup_elem(fd
, key
, value
)) {
597 print_entry_json(&info
, key
, value
);
599 print_entry_plain(&info
, key
, value
);
602 jsonw_name(json_wtr
, "key");
603 print_hex_data_json(key
, info
.key_size
);
604 jsonw_name(json_wtr
, "value");
605 jsonw_start_object(json_wtr
);
606 jsonw_string_field(json_wtr
, "error",
607 "can't lookup element");
608 jsonw_end_object(json_wtr
);
610 p_info("can't lookup element with key: ");
611 fprint_hex(stderr
, key
, info
.key_size
, " ");
612 fprintf(stderr
, "\n");
621 jsonw_end_array(json_wtr
);
623 printf("Found %u element%s\n", num_elems
,
624 num_elems
!= 1 ? "s" : "");
634 static int do_update(int argc
, char **argv
)
636 struct bpf_map_info info
= {};
637 __u32 len
= sizeof(info
);
638 __u32
*value_fd
= NULL
;
639 __u32 flags
= BPF_ANY
;
646 fd
= map_parse_fd_and_info(&argc
, &argv
, &info
, &len
);
650 key
= malloc(info
.key_size
);
651 value
= alloc_value(&info
);
652 if (!key
|| !value
) {
653 p_err("mem alloc failed");
658 err
= parse_elem(argv
, &info
, key
, value
, info
.key_size
,
659 info
.value_size
, &flags
, &value_fd
);
663 err
= bpf_map_update_elem(fd
, key
, value
, flags
);
665 p_err("update failed: %s", strerror(errno
));
676 if (!err
&& json_output
)
677 jsonw_null(json_wtr
);
681 static int do_lookup(int argc
, char **argv
)
683 struct bpf_map_info info
= {};
684 __u32 len
= sizeof(info
);
692 fd
= map_parse_fd_and_info(&argc
, &argv
, &info
, &len
);
696 key
= malloc(info
.key_size
);
697 value
= alloc_value(&info
);
698 if (!key
|| !value
) {
699 p_err("mem alloc failed");
704 err
= parse_elem(argv
, &info
, key
, NULL
, info
.key_size
, 0, NULL
, NULL
);
708 err
= bpf_map_lookup_elem(fd
, key
, value
);
711 print_entry_json(&info
, key
, value
);
713 print_entry_plain(&info
, key
, value
);
714 } else if (errno
== ENOENT
) {
716 jsonw_null(json_wtr
);
719 fprint_hex(stdout
, key
, info
.key_size
, " ");
720 printf("\n\nNot found\n");
723 p_err("lookup failed: %s", strerror(errno
));
734 static int do_getnext(int argc
, char **argv
)
736 struct bpf_map_info info
= {};
737 __u32 len
= sizeof(info
);
745 fd
= map_parse_fd_and_info(&argc
, &argv
, &info
, &len
);
749 key
= malloc(info
.key_size
);
750 nextkey
= malloc(info
.key_size
);
751 if (!key
|| !nextkey
) {
752 p_err("mem alloc failed");
758 err
= parse_elem(argv
, &info
, key
, NULL
, info
.key_size
, 0,
767 err
= bpf_map_get_next_key(fd
, key
, nextkey
);
769 p_err("can't get next key: %s", strerror(errno
));
774 jsonw_start_object(json_wtr
);
776 jsonw_name(json_wtr
, "key");
777 print_hex_data_json(key
, info
.key_size
);
779 jsonw_null_field(json_wtr
, "key");
781 jsonw_name(json_wtr
, "next_key");
782 print_hex_data_json(nextkey
, info
.key_size
);
783 jsonw_end_object(json_wtr
);
787 fprint_hex(stdout
, key
, info
.key_size
, " ");
790 printf("key: None\n");
792 printf("next key:\n");
793 fprint_hex(stdout
, nextkey
, info
.key_size
, " ");
805 static int do_delete(int argc
, char **argv
)
807 struct bpf_map_info info
= {};
808 __u32 len
= sizeof(info
);
816 fd
= map_parse_fd_and_info(&argc
, &argv
, &info
, &len
);
820 key
= malloc(info
.key_size
);
822 p_err("mem alloc failed");
827 err
= parse_elem(argv
, &info
, key
, NULL
, info
.key_size
, 0, NULL
, NULL
);
831 err
= bpf_map_delete_elem(fd
, key
);
833 p_err("delete failed: %s", strerror(errno
));
839 if (!err
&& json_output
)
840 jsonw_null(json_wtr
);
844 static int do_pin(int argc
, char **argv
)
848 err
= do_pin_any(argc
, argv
, bpf_map_get_fd_by_id
);
849 if (!err
&& json_output
)
850 jsonw_null(json_wtr
);
854 static int do_help(int argc
, char **argv
)
857 jsonw_null(json_wtr
);
862 "Usage: %s %s show [MAP]\n"
864 " %s %s update MAP key BYTES value VALUE [UPDATE_FLAGS]\n"
865 " %s %s lookup MAP key BYTES\n"
866 " %s %s getnext MAP [key BYTES]\n"
867 " %s %s delete MAP key BYTES\n"
868 " %s %s pin MAP FILE\n"
871 " MAP := { id MAP_ID | pinned FILE }\n"
872 " " HELP_SPEC_PROGRAM
"\n"
873 " VALUE := { BYTES | MAP | PROG }\n"
874 " UPDATE_FLAGS := { any | exist | noexist }\n"
875 " " HELP_SPEC_OPTIONS
"\n"
877 bin_name
, argv
[-2], bin_name
, argv
[-2], bin_name
, argv
[-2],
878 bin_name
, argv
[-2], bin_name
, argv
[-2], bin_name
, argv
[-2],
879 bin_name
, argv
[-2], bin_name
, argv
[-2]);
884 static const struct cmd cmds
[] = {
888 { "update", do_update
},
889 { "lookup", do_lookup
},
890 { "getnext", do_getnext
},
891 { "delete", do_delete
},
896 int do_map(int argc
, char **argv
)
898 return cmd_select(cmds
, argc
, argv
, do_help
);