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/bpf.h>
19 #include <bpf/btf.h>
20 #include <bpf/hashmap.h>
21
22 #include "json_writer.h"
23 #include "main.h"
24
25 const char * const map_type_name[] = {
26 [BPF_MAP_TYPE_UNSPEC] = "unspec",
27 [BPF_MAP_TYPE_HASH] = "hash",
28 [BPF_MAP_TYPE_ARRAY] = "array",
29 [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array",
30 [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array",
31 [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash",
32 [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array",
33 [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace",
34 [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array",
35 [BPF_MAP_TYPE_LRU_HASH] = "lru_hash",
36 [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash",
37 [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie",
38 [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps",
39 [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps",
40 [BPF_MAP_TYPE_DEVMAP] = "devmap",
41 [BPF_MAP_TYPE_DEVMAP_HASH] = "devmap_hash",
42 [BPF_MAP_TYPE_SOCKMAP] = "sockmap",
43 [BPF_MAP_TYPE_CPUMAP] = "cpumap",
44 [BPF_MAP_TYPE_XSKMAP] = "xskmap",
45 [BPF_MAP_TYPE_SOCKHASH] = "sockhash",
46 [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage",
47 [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray",
48 [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE] = "percpu_cgroup_storage",
49 [BPF_MAP_TYPE_QUEUE] = "queue",
50 [BPF_MAP_TYPE_STACK] = "stack",
51 [BPF_MAP_TYPE_SK_STORAGE] = "sk_storage",
52 [BPF_MAP_TYPE_STRUCT_OPS] = "struct_ops",
53 [BPF_MAP_TYPE_RINGBUF] = "ringbuf",
54 [BPF_MAP_TYPE_INODE_STORAGE] = "inode_storage",
55 [BPF_MAP_TYPE_TASK_STORAGE] = "task_storage",
56 };
57
58 const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
59
60 static struct hashmap *map_table;
61
map_is_per_cpu(__u32 type)62 static bool map_is_per_cpu(__u32 type)
63 {
64 return type == BPF_MAP_TYPE_PERCPU_HASH ||
65 type == BPF_MAP_TYPE_PERCPU_ARRAY ||
66 type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
67 type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
68 }
69
map_is_map_of_maps(__u32 type)70 static bool map_is_map_of_maps(__u32 type)
71 {
72 return type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
73 type == BPF_MAP_TYPE_HASH_OF_MAPS;
74 }
75
map_is_map_of_progs(__u32 type)76 static bool map_is_map_of_progs(__u32 type)
77 {
78 return type == BPF_MAP_TYPE_PROG_ARRAY;
79 }
80
map_type_from_str(const char * type)81 static int map_type_from_str(const char *type)
82 {
83 unsigned int i;
84
85 for (i = 0; i < ARRAY_SIZE(map_type_name); i++)
86 /* Don't allow prefixing in case of possible future shadowing */
87 if (map_type_name[i] && !strcmp(map_type_name[i], type))
88 return i;
89 return -1;
90 }
91
alloc_value(struct bpf_map_info * info)92 static void *alloc_value(struct bpf_map_info *info)
93 {
94 if (map_is_per_cpu(info->type))
95 return malloc(round_up(info->value_size, 8) *
96 get_possible_cpus());
97 else
98 return malloc(info->value_size);
99 }
100
do_dump_btf(const struct btf_dumper * d,struct bpf_map_info * map_info,void * key,void * value)101 static int do_dump_btf(const struct btf_dumper *d,
102 struct bpf_map_info *map_info, void *key,
103 void *value)
104 {
105 __u32 value_id;
106 int ret = 0;
107
108 /* start of key-value pair */
109 jsonw_start_object(d->jw);
110
111 if (map_info->btf_key_type_id) {
112 jsonw_name(d->jw, "key");
113
114 ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
115 if (ret)
116 goto err_end_obj;
117 }
118
119 value_id = map_info->btf_vmlinux_value_type_id ?
120 : map_info->btf_value_type_id;
121
122 if (!map_is_per_cpu(map_info->type)) {
123 jsonw_name(d->jw, "value");
124 ret = btf_dumper_type(d, value_id, value);
125 } else {
126 unsigned int i, n, step;
127
128 jsonw_name(d->jw, "values");
129 jsonw_start_array(d->jw);
130 n = get_possible_cpus();
131 step = round_up(map_info->value_size, 8);
132 for (i = 0; i < n; i++) {
133 jsonw_start_object(d->jw);
134 jsonw_int_field(d->jw, "cpu", i);
135 jsonw_name(d->jw, "value");
136 ret = btf_dumper_type(d, value_id, value + i * step);
137 jsonw_end_object(d->jw);
138 if (ret)
139 break;
140 }
141 jsonw_end_array(d->jw);
142 }
143
144 err_end_obj:
145 /* end of key-value pair */
146 jsonw_end_object(d->jw);
147
148 return ret;
149 }
150
get_btf_writer(void)151 static json_writer_t *get_btf_writer(void)
152 {
153 json_writer_t *jw = jsonw_new(stdout);
154
155 if (!jw)
156 return NULL;
157 jsonw_pretty(jw, true);
158
159 return jw;
160 }
161
print_entry_json(struct bpf_map_info * info,unsigned char * key,unsigned char * value,struct btf * btf)162 static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
163 unsigned char *value, struct btf *btf)
164 {
165 jsonw_start_object(json_wtr);
166
167 if (!map_is_per_cpu(info->type)) {
168 jsonw_name(json_wtr, "key");
169 print_hex_data_json(key, info->key_size);
170 jsonw_name(json_wtr, "value");
171 print_hex_data_json(value, info->value_size);
172 if (btf) {
173 struct btf_dumper d = {
174 .btf = btf,
175 .jw = json_wtr,
176 .is_plain_text = false,
177 };
178
179 jsonw_name(json_wtr, "formatted");
180 do_dump_btf(&d, info, key, value);
181 }
182 } else {
183 unsigned int i, n, step;
184
185 n = get_possible_cpus();
186 step = round_up(info->value_size, 8);
187
188 jsonw_name(json_wtr, "key");
189 print_hex_data_json(key, info->key_size);
190
191 jsonw_name(json_wtr, "values");
192 jsonw_start_array(json_wtr);
193 for (i = 0; i < n; i++) {
194 jsonw_start_object(json_wtr);
195
196 jsonw_int_field(json_wtr, "cpu", i);
197
198 jsonw_name(json_wtr, "value");
199 print_hex_data_json(value + i * step,
200 info->value_size);
201
202 jsonw_end_object(json_wtr);
203 }
204 jsonw_end_array(json_wtr);
205 if (btf) {
206 struct btf_dumper d = {
207 .btf = btf,
208 .jw = json_wtr,
209 .is_plain_text = false,
210 };
211
212 jsonw_name(json_wtr, "formatted");
213 do_dump_btf(&d, info, key, value);
214 }
215 }
216
217 jsonw_end_object(json_wtr);
218 }
219
220 static void
print_entry_error_msg(struct bpf_map_info * info,unsigned char * key,const char * error_msg)221 print_entry_error_msg(struct bpf_map_info *info, unsigned char *key,
222 const char *error_msg)
223 {
224 int msg_size = strlen(error_msg);
225 bool single_line, break_names;
226
227 break_names = info->key_size > 16 || msg_size > 16;
228 single_line = info->key_size + msg_size <= 24 && !break_names;
229
230 printf("key:%c", break_names ? '\n' : ' ');
231 fprint_hex(stdout, key, info->key_size, " ");
232
233 printf(single_line ? " " : "\n");
234
235 printf("value:%c%s", break_names ? '\n' : ' ', error_msg);
236
237 printf("\n");
238 }
239
240 static void
print_entry_error(struct bpf_map_info * map_info,void * key,int lookup_errno)241 print_entry_error(struct bpf_map_info *map_info, void *key, int lookup_errno)
242 {
243 /* For prog_array maps or arrays of maps, failure to lookup the value
244 * means there is no entry for that key. Do not print an error message
245 * in that case.
246 */
247 if ((map_is_map_of_maps(map_info->type) ||
248 map_is_map_of_progs(map_info->type)) && lookup_errno == ENOENT)
249 return;
250
251 if (json_output) {
252 jsonw_start_object(json_wtr); /* entry */
253 jsonw_name(json_wtr, "key");
254 print_hex_data_json(key, map_info->key_size);
255 jsonw_name(json_wtr, "value");
256 jsonw_start_object(json_wtr); /* error */
257 jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
258 jsonw_end_object(json_wtr); /* error */
259 jsonw_end_object(json_wtr); /* entry */
260 } else {
261 const char *msg = NULL;
262
263 if (lookup_errno == ENOENT)
264 msg = "<no entry>";
265 else if (lookup_errno == ENOSPC &&
266 map_info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
267 msg = "<cannot read>";
268
269 print_entry_error_msg(map_info, key,
270 msg ? : strerror(lookup_errno));
271 }
272 }
273
print_entry_plain(struct bpf_map_info * info,unsigned char * key,unsigned char * value)274 static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
275 unsigned char *value)
276 {
277 if (!map_is_per_cpu(info->type)) {
278 bool single_line, break_names;
279
280 break_names = info->key_size > 16 || info->value_size > 16;
281 single_line = info->key_size + info->value_size <= 24 &&
282 !break_names;
283
284 if (info->key_size) {
285 printf("key:%c", break_names ? '\n' : ' ');
286 fprint_hex(stdout, key, info->key_size, " ");
287
288 printf(single_line ? " " : "\n");
289 }
290
291 if (info->value_size) {
292 printf("value:%c", break_names ? '\n' : ' ');
293 fprint_hex(stdout, value, info->value_size, " ");
294 }
295
296 printf("\n");
297 } else {
298 unsigned int i, n, step;
299
300 n = get_possible_cpus();
301 step = round_up(info->value_size, 8);
302
303 if (info->key_size) {
304 printf("key:\n");
305 fprint_hex(stdout, key, info->key_size, " ");
306 printf("\n");
307 }
308 if (info->value_size) {
309 for (i = 0; i < n; i++) {
310 printf("value (CPU %02d):%c",
311 i, info->value_size > 16 ? '\n' : ' ');
312 fprint_hex(stdout, value + i * step,
313 info->value_size, " ");
314 printf("\n");
315 }
316 }
317 }
318 }
319
parse_bytes(char ** argv,const char * name,unsigned char * val,unsigned int n)320 static char **parse_bytes(char **argv, const char *name, unsigned char *val,
321 unsigned int n)
322 {
323 unsigned int i = 0, base = 0;
324 char *endptr;
325
326 if (is_prefix(*argv, "hex")) {
327 base = 16;
328 argv++;
329 }
330
331 while (i < n && argv[i]) {
332 val[i] = strtoul(argv[i], &endptr, base);
333 if (*endptr) {
334 p_err("error parsing byte: %s", argv[i]);
335 return NULL;
336 }
337 i++;
338 }
339
340 if (i != n) {
341 p_err("%s expected %d bytes got %d", name, n, i);
342 return NULL;
343 }
344
345 return argv + i;
346 }
347
348 /* on per cpu maps we must copy the provided value on all value instances */
fill_per_cpu_value(struct bpf_map_info * info,void * value)349 static void fill_per_cpu_value(struct bpf_map_info *info, void *value)
350 {
351 unsigned int i, n, step;
352
353 if (!map_is_per_cpu(info->type))
354 return;
355
356 n = get_possible_cpus();
357 step = round_up(info->value_size, 8);
358 for (i = 1; i < n; i++)
359 memcpy(value + i * step, value, info->value_size);
360 }
361
parse_elem(char ** argv,struct bpf_map_info * info,void * key,void * value,__u32 key_size,__u32 value_size,__u32 * flags,__u32 ** value_fd)362 static int parse_elem(char **argv, struct bpf_map_info *info,
363 void *key, void *value, __u32 key_size, __u32 value_size,
364 __u32 *flags, __u32 **value_fd)
365 {
366 if (!*argv) {
367 if (!key && !value)
368 return 0;
369 p_err("did not find %s", key ? "key" : "value");
370 return -1;
371 }
372
373 if (is_prefix(*argv, "key")) {
374 if (!key) {
375 if (key_size)
376 p_err("duplicate key");
377 else
378 p_err("unnecessary key");
379 return -1;
380 }
381
382 argv = parse_bytes(argv + 1, "key", key, key_size);
383 if (!argv)
384 return -1;
385
386 return parse_elem(argv, info, NULL, value, key_size, value_size,
387 flags, value_fd);
388 } else if (is_prefix(*argv, "value")) {
389 int fd;
390
391 if (!value) {
392 if (value_size)
393 p_err("duplicate value");
394 else
395 p_err("unnecessary value");
396 return -1;
397 }
398
399 argv++;
400
401 if (map_is_map_of_maps(info->type)) {
402 int argc = 2;
403
404 if (value_size != 4) {
405 p_err("value smaller than 4B for map in map?");
406 return -1;
407 }
408 if (!argv[0] || !argv[1]) {
409 p_err("not enough value arguments for map in map");
410 return -1;
411 }
412
413 fd = map_parse_fd(&argc, &argv);
414 if (fd < 0)
415 return -1;
416
417 *value_fd = value;
418 **value_fd = fd;
419 } else if (map_is_map_of_progs(info->type)) {
420 int argc = 2;
421
422 if (value_size != 4) {
423 p_err("value smaller than 4B for map of progs?");
424 return -1;
425 }
426 if (!argv[0] || !argv[1]) {
427 p_err("not enough value arguments for map of progs");
428 return -1;
429 }
430 if (is_prefix(*argv, "id"))
431 p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
432 " by some process or pinned otherwise update will be lost");
433
434 fd = prog_parse_fd(&argc, &argv);
435 if (fd < 0)
436 return -1;
437
438 *value_fd = value;
439 **value_fd = fd;
440 } else {
441 argv = parse_bytes(argv, "value", value, value_size);
442 if (!argv)
443 return -1;
444
445 fill_per_cpu_value(info, value);
446 }
447
448 return parse_elem(argv, info, key, NULL, key_size, value_size,
449 flags, NULL);
450 } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
451 is_prefix(*argv, "exist")) {
452 if (!flags) {
453 p_err("flags specified multiple times: %s", *argv);
454 return -1;
455 }
456
457 if (is_prefix(*argv, "any"))
458 *flags = BPF_ANY;
459 else if (is_prefix(*argv, "noexist"))
460 *flags = BPF_NOEXIST;
461 else if (is_prefix(*argv, "exist"))
462 *flags = BPF_EXIST;
463
464 return parse_elem(argv + 1, info, key, value, key_size,
465 value_size, NULL, value_fd);
466 }
467
468 p_err("expected key or value, got: %s", *argv);
469 return -1;
470 }
471
show_map_header_json(struct bpf_map_info * info,json_writer_t * wtr)472 static void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
473 {
474 jsonw_uint_field(wtr, "id", info->id);
475 if (info->type < ARRAY_SIZE(map_type_name))
476 jsonw_string_field(wtr, "type", map_type_name[info->type]);
477 else
478 jsonw_uint_field(wtr, "type", info->type);
479
480 if (*info->name)
481 jsonw_string_field(wtr, "name", info->name);
482
483 jsonw_name(wtr, "flags");
484 jsonw_printf(wtr, "%d", info->map_flags);
485 }
486
show_map_close_json(int fd,struct bpf_map_info * info)487 static int show_map_close_json(int fd, struct bpf_map_info *info)
488 {
489 char *memlock, *frozen_str;
490 int frozen = 0;
491
492 memlock = get_fdinfo(fd, "memlock");
493 frozen_str = get_fdinfo(fd, "frozen");
494
495 jsonw_start_object(json_wtr);
496
497 show_map_header_json(info, json_wtr);
498
499 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
500
501 jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
502 jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
503 jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
504
505 if (memlock)
506 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
507 free(memlock);
508
509 if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
510 char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
511 char *owner_jited = get_fdinfo(fd, "owner_jited");
512
513 if (owner_prog_type) {
514 unsigned int prog_type = atoi(owner_prog_type);
515
516 if (prog_type < prog_type_name_size)
517 jsonw_string_field(json_wtr, "owner_prog_type",
518 prog_type_name[prog_type]);
519 else
520 jsonw_uint_field(json_wtr, "owner_prog_type",
521 prog_type);
522 }
523 if (owner_jited)
524 jsonw_bool_field(json_wtr, "owner_jited",
525 !!atoi(owner_jited));
526
527 free(owner_prog_type);
528 free(owner_jited);
529 }
530 close(fd);
531
532 if (frozen_str) {
533 frozen = atoi(frozen_str);
534 free(frozen_str);
535 }
536 jsonw_int_field(json_wtr, "frozen", frozen);
537
538 if (info->btf_id)
539 jsonw_int_field(json_wtr, "btf_id", info->btf_id);
540
541 if (!hashmap__empty(map_table)) {
542 struct hashmap_entry *entry;
543
544 jsonw_name(json_wtr, "pinned");
545 jsonw_start_array(json_wtr);
546 hashmap__for_each_key_entry(map_table, entry,
547 u32_as_hash_field(info->id))
548 jsonw_string(json_wtr, entry->value);
549 jsonw_end_array(json_wtr);
550 }
551
552 emit_obj_refs_json(refs_table, info->id, json_wtr);
553
554 jsonw_end_object(json_wtr);
555
556 return 0;
557 }
558
show_map_header_plain(struct bpf_map_info * info)559 static void show_map_header_plain(struct bpf_map_info *info)
560 {
561 printf("%u: ", info->id);
562 if (info->type < ARRAY_SIZE(map_type_name))
563 printf("%s ", map_type_name[info->type]);
564 else
565 printf("type %u ", info->type);
566
567 if (*info->name)
568 printf("name %s ", info->name);
569
570 printf("flags 0x%x", info->map_flags);
571 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
572 printf("\n");
573 }
574
show_map_close_plain(int fd,struct bpf_map_info * info)575 static int show_map_close_plain(int fd, struct bpf_map_info *info)
576 {
577 char *memlock, *frozen_str;
578 int frozen = 0;
579
580 memlock = get_fdinfo(fd, "memlock");
581 frozen_str = get_fdinfo(fd, "frozen");
582
583 show_map_header_plain(info);
584 printf("\tkey %uB value %uB max_entries %u",
585 info->key_size, info->value_size, info->max_entries);
586
587 if (memlock)
588 printf(" memlock %sB", memlock);
589 free(memlock);
590
591 if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
592 char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
593 char *owner_jited = get_fdinfo(fd, "owner_jited");
594
595 if (owner_prog_type || owner_jited)
596 printf("\n\t");
597 if (owner_prog_type) {
598 unsigned int prog_type = atoi(owner_prog_type);
599
600 if (prog_type < prog_type_name_size)
601 printf("owner_prog_type %s ",
602 prog_type_name[prog_type]);
603 else
604 printf("owner_prog_type %d ", prog_type);
605 }
606 if (owner_jited)
607 printf("owner%s jited",
608 atoi(owner_jited) ? "" : " not");
609
610 free(owner_prog_type);
611 free(owner_jited);
612 }
613 close(fd);
614
615 if (!hashmap__empty(map_table)) {
616 struct hashmap_entry *entry;
617
618 hashmap__for_each_key_entry(map_table, entry,
619 u32_as_hash_field(info->id))
620 printf("\n\tpinned %s", (char *)entry->value);
621 }
622 printf("\n");
623
624 if (frozen_str) {
625 frozen = atoi(frozen_str);
626 free(frozen_str);
627 }
628
629 if (!info->btf_id && !frozen)
630 return 0;
631
632 printf("\t");
633
634 if (info->btf_id)
635 printf("btf_id %d", info->btf_id);
636
637 if (frozen)
638 printf("%sfrozen", info->btf_id ? " " : "");
639
640 emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
641
642 printf("\n");
643 return 0;
644 }
645
do_show_subset(int argc,char ** argv)646 static int do_show_subset(int argc, char **argv)
647 {
648 struct bpf_map_info info = {};
649 __u32 len = sizeof(info);
650 int *fds = NULL;
651 int nb_fds, i;
652 int err = -1;
653
654 fds = malloc(sizeof(int));
655 if (!fds) {
656 p_err("mem alloc failed");
657 return -1;
658 }
659 nb_fds = map_parse_fds(&argc, &argv, &fds);
660 if (nb_fds < 1)
661 goto exit_free;
662
663 if (json_output && nb_fds > 1)
664 jsonw_start_array(json_wtr); /* root array */
665 for (i = 0; i < nb_fds; i++) {
666 err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
667 if (err) {
668 p_err("can't get map info: %s",
669 strerror(errno));
670 for (; i < nb_fds; i++)
671 close(fds[i]);
672 break;
673 }
674
675 if (json_output)
676 show_map_close_json(fds[i], &info);
677 else
678 show_map_close_plain(fds[i], &info);
679
680 close(fds[i]);
681 }
682 if (json_output && nb_fds > 1)
683 jsonw_end_array(json_wtr); /* root array */
684
685 exit_free:
686 free(fds);
687 return err;
688 }
689
do_show(int argc,char ** argv)690 static int do_show(int argc, char **argv)
691 {
692 struct bpf_map_info info = {};
693 __u32 len = sizeof(info);
694 __u32 id = 0;
695 int err;
696 int fd;
697
698 if (show_pinned) {
699 map_table = hashmap__new(hash_fn_for_key_as_id,
700 equal_fn_for_key_as_id, NULL);
701 if (!map_table) {
702 p_err("failed to create hashmap for pinned paths");
703 return -1;
704 }
705 build_pinned_obj_table(map_table, BPF_OBJ_MAP);
706 }
707 build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
708
709 if (argc == 2)
710 return do_show_subset(argc, argv);
711
712 if (argc)
713 return BAD_ARG();
714
715 if (json_output)
716 jsonw_start_array(json_wtr);
717 while (true) {
718 err = bpf_map_get_next_id(id, &id);
719 if (err) {
720 if (errno == ENOENT)
721 break;
722 p_err("can't get next map: %s%s", strerror(errno),
723 errno == EINVAL ? " -- kernel too old?" : "");
724 break;
725 }
726
727 fd = bpf_map_get_fd_by_id(id);
728 if (fd < 0) {
729 if (errno == ENOENT)
730 continue;
731 p_err("can't get map by id (%u): %s",
732 id, strerror(errno));
733 break;
734 }
735
736 err = bpf_obj_get_info_by_fd(fd, &info, &len);
737 if (err) {
738 p_err("can't get map info: %s", strerror(errno));
739 close(fd);
740 break;
741 }
742
743 if (json_output)
744 show_map_close_json(fd, &info);
745 else
746 show_map_close_plain(fd, &info);
747 }
748 if (json_output)
749 jsonw_end_array(json_wtr);
750
751 delete_obj_refs_table(refs_table);
752
753 if (show_pinned)
754 delete_pinned_obj_table(map_table);
755
756 return errno == ENOENT ? 0 : -1;
757 }
758
dump_map_elem(int fd,void * key,void * value,struct bpf_map_info * map_info,struct btf * btf,json_writer_t * btf_wtr)759 static int dump_map_elem(int fd, void *key, void *value,
760 struct bpf_map_info *map_info, struct btf *btf,
761 json_writer_t *btf_wtr)
762 {
763 if (bpf_map_lookup_elem(fd, key, value)) {
764 print_entry_error(map_info, key, errno);
765 return -1;
766 }
767
768 if (json_output) {
769 print_entry_json(map_info, key, value, btf);
770 } else if (btf) {
771 struct btf_dumper d = {
772 .btf = btf,
773 .jw = btf_wtr,
774 .is_plain_text = true,
775 };
776
777 do_dump_btf(&d, map_info, key, value);
778 } else {
779 print_entry_plain(map_info, key, value);
780 }
781
782 return 0;
783 }
784
maps_have_btf(int * fds,int nb_fds)785 static int maps_have_btf(int *fds, int nb_fds)
786 {
787 struct bpf_map_info info = {};
788 __u32 len = sizeof(info);
789 int err, i;
790
791 for (i = 0; i < nb_fds; i++) {
792 err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
793 if (err) {
794 p_err("can't get map info: %s", strerror(errno));
795 return -1;
796 }
797
798 if (!info.btf_id)
799 return 0;
800 }
801
802 return 1;
803 }
804
805 static struct btf *btf_vmlinux;
806
get_map_kv_btf(const struct bpf_map_info * info)807 static struct btf *get_map_kv_btf(const struct bpf_map_info *info)
808 {
809 struct btf *btf = NULL;
810
811 if (info->btf_vmlinux_value_type_id) {
812 if (!btf_vmlinux) {
813 btf_vmlinux = libbpf_find_kernel_btf();
814 if (IS_ERR(btf_vmlinux))
815 p_err("failed to get kernel btf");
816 }
817 return btf_vmlinux;
818 } else if (info->btf_value_type_id) {
819 int err;
820
821 btf = btf__load_from_kernel_by_id(info->btf_id);
822 err = libbpf_get_error(btf);
823 if (err) {
824 p_err("failed to get btf");
825 btf = ERR_PTR(err);
826 }
827 }
828
829 return btf;
830 }
831
free_map_kv_btf(struct btf * btf)832 static void free_map_kv_btf(struct btf *btf)
833 {
834 if (!IS_ERR(btf) && btf != btf_vmlinux)
835 btf__free(btf);
836 }
837
free_btf_vmlinux(void)838 static void free_btf_vmlinux(void)
839 {
840 if (!IS_ERR(btf_vmlinux))
841 btf__free(btf_vmlinux);
842 }
843
844 static int
map_dump(int fd,struct bpf_map_info * info,json_writer_t * wtr,bool show_header)845 map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
846 bool show_header)
847 {
848 void *key, *value, *prev_key;
849 unsigned int num_elems = 0;
850 struct btf *btf = NULL;
851 int err;
852
853 key = malloc(info->key_size);
854 value = alloc_value(info);
855 if (!key || !value) {
856 p_err("mem alloc failed");
857 err = -1;
858 goto exit_free;
859 }
860
861 prev_key = NULL;
862
863 if (wtr) {
864 btf = get_map_kv_btf(info);
865 if (IS_ERR(btf)) {
866 err = PTR_ERR(btf);
867 goto exit_free;
868 }
869
870 if (show_header) {
871 jsonw_start_object(wtr); /* map object */
872 show_map_header_json(info, wtr);
873 jsonw_name(wtr, "elements");
874 }
875 jsonw_start_array(wtr); /* elements */
876 } else if (show_header) {
877 show_map_header_plain(info);
878 }
879
880 if (info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
881 info->value_size != 8)
882 p_info("Warning: cannot read values from %s map with value_size != 8",
883 map_type_name[info->type]);
884 while (true) {
885 err = bpf_map_get_next_key(fd, prev_key, key);
886 if (err) {
887 if (errno == ENOENT)
888 err = 0;
889 break;
890 }
891 if (!dump_map_elem(fd, key, value, info, btf, wtr))
892 num_elems++;
893 prev_key = key;
894 }
895
896 if (wtr) {
897 jsonw_end_array(wtr); /* elements */
898 if (show_header)
899 jsonw_end_object(wtr); /* map object */
900 } else {
901 printf("Found %u element%s\n", num_elems,
902 num_elems != 1 ? "s" : "");
903 }
904
905 exit_free:
906 free(key);
907 free(value);
908 close(fd);
909 free_map_kv_btf(btf);
910
911 return err;
912 }
913
do_dump(int argc,char ** argv)914 static int do_dump(int argc, char **argv)
915 {
916 json_writer_t *wtr = NULL, *btf_wtr = NULL;
917 struct bpf_map_info info = {};
918 int nb_fds, i = 0;
919 __u32 len = sizeof(info);
920 int *fds = NULL;
921 int err = -1;
922
923 if (argc != 2)
924 usage();
925
926 fds = malloc(sizeof(int));
927 if (!fds) {
928 p_err("mem alloc failed");
929 return -1;
930 }
931 nb_fds = map_parse_fds(&argc, &argv, &fds);
932 if (nb_fds < 1)
933 goto exit_free;
934
935 if (json_output) {
936 wtr = json_wtr;
937 } else {
938 int do_plain_btf;
939
940 do_plain_btf = maps_have_btf(fds, nb_fds);
941 if (do_plain_btf < 0)
942 goto exit_close;
943
944 if (do_plain_btf) {
945 btf_wtr = get_btf_writer();
946 wtr = btf_wtr;
947 if (!btf_wtr)
948 p_info("failed to create json writer for btf. falling back to plain output");
949 }
950 }
951
952 if (wtr && nb_fds > 1)
953 jsonw_start_array(wtr); /* root array */
954 for (i = 0; i < nb_fds; i++) {
955 if (bpf_obj_get_info_by_fd(fds[i], &info, &len)) {
956 p_err("can't get map info: %s", strerror(errno));
957 break;
958 }
959 err = map_dump(fds[i], &info, wtr, nb_fds > 1);
960 if (!wtr && i != nb_fds - 1)
961 printf("\n");
962
963 if (err)
964 break;
965 close(fds[i]);
966 }
967 if (wtr && nb_fds > 1)
968 jsonw_end_array(wtr); /* root array */
969
970 if (btf_wtr)
971 jsonw_destroy(&btf_wtr);
972 exit_close:
973 for (; i < nb_fds; i++)
974 close(fds[i]);
975 exit_free:
976 free(fds);
977 free_btf_vmlinux();
978 return err;
979 }
980
alloc_key_value(struct bpf_map_info * info,void ** key,void ** value)981 static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
982 {
983 *key = NULL;
984 *value = NULL;
985
986 if (info->key_size) {
987 *key = malloc(info->key_size);
988 if (!*key) {
989 p_err("key mem alloc failed");
990 return -1;
991 }
992 }
993
994 if (info->value_size) {
995 *value = alloc_value(info);
996 if (!*value) {
997 p_err("value mem alloc failed");
998 free(*key);
999 *key = NULL;
1000 return -1;
1001 }
1002 }
1003
1004 return 0;
1005 }
1006
do_update(int argc,char ** argv)1007 static int do_update(int argc, char **argv)
1008 {
1009 struct bpf_map_info info = {};
1010 __u32 len = sizeof(info);
1011 __u32 *value_fd = NULL;
1012 __u32 flags = BPF_ANY;
1013 void *key, *value;
1014 int fd, err;
1015
1016 if (argc < 2)
1017 usage();
1018
1019 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1020 if (fd < 0)
1021 return -1;
1022
1023 err = alloc_key_value(&info, &key, &value);
1024 if (err)
1025 goto exit_free;
1026
1027 err = parse_elem(argv, &info, key, value, info.key_size,
1028 info.value_size, &flags, &value_fd);
1029 if (err)
1030 goto exit_free;
1031
1032 err = bpf_map_update_elem(fd, key, value, flags);
1033 if (err) {
1034 p_err("update failed: %s", strerror(errno));
1035 goto exit_free;
1036 }
1037
1038 exit_free:
1039 if (value_fd)
1040 close(*value_fd);
1041 free(key);
1042 free(value);
1043 close(fd);
1044
1045 if (!err && json_output)
1046 jsonw_null(json_wtr);
1047 return err;
1048 }
1049
print_key_value(struct bpf_map_info * info,void * key,void * value)1050 static void print_key_value(struct bpf_map_info *info, void *key,
1051 void *value)
1052 {
1053 json_writer_t *btf_wtr;
1054 struct btf *btf;
1055
1056 btf = btf__load_from_kernel_by_id(info->btf_id);
1057 if (libbpf_get_error(btf)) {
1058 p_err("failed to get btf");
1059 return;
1060 }
1061
1062 if (json_output) {
1063 print_entry_json(info, key, value, btf);
1064 } else if (btf) {
1065 /* if here json_wtr wouldn't have been initialised,
1066 * so let's create separate writer for btf
1067 */
1068 btf_wtr = get_btf_writer();
1069 if (!btf_wtr) {
1070 p_info("failed to create json writer for btf. falling back to plain output");
1071 btf__free(btf);
1072 btf = NULL;
1073 print_entry_plain(info, key, value);
1074 } else {
1075 struct btf_dumper d = {
1076 .btf = btf,
1077 .jw = btf_wtr,
1078 .is_plain_text = true,
1079 };
1080
1081 do_dump_btf(&d, info, key, value);
1082 jsonw_destroy(&btf_wtr);
1083 }
1084 } else {
1085 print_entry_plain(info, key, value);
1086 }
1087 btf__free(btf);
1088 }
1089
do_lookup(int argc,char ** argv)1090 static int do_lookup(int argc, char **argv)
1091 {
1092 struct bpf_map_info info = {};
1093 __u32 len = sizeof(info);
1094 void *key, *value;
1095 int err;
1096 int fd;
1097
1098 if (argc < 2)
1099 usage();
1100
1101 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1102 if (fd < 0)
1103 return -1;
1104
1105 err = alloc_key_value(&info, &key, &value);
1106 if (err)
1107 goto exit_free;
1108
1109 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
1110 if (err)
1111 goto exit_free;
1112
1113 err = bpf_map_lookup_elem(fd, key, value);
1114 if (err) {
1115 if (errno == ENOENT) {
1116 if (json_output) {
1117 jsonw_null(json_wtr);
1118 } else {
1119 printf("key:\n");
1120 fprint_hex(stdout, key, info.key_size, " ");
1121 printf("\n\nNot found\n");
1122 }
1123 } else {
1124 p_err("lookup failed: %s", strerror(errno));
1125 }
1126
1127 goto exit_free;
1128 }
1129
1130 /* here means bpf_map_lookup_elem() succeeded */
1131 print_key_value(&info, key, value);
1132
1133 exit_free:
1134 free(key);
1135 free(value);
1136 close(fd);
1137
1138 return err;
1139 }
1140
do_getnext(int argc,char ** argv)1141 static int do_getnext(int argc, char **argv)
1142 {
1143 struct bpf_map_info info = {};
1144 __u32 len = sizeof(info);
1145 void *key, *nextkey;
1146 int err;
1147 int fd;
1148
1149 if (argc < 2)
1150 usage();
1151
1152 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1153 if (fd < 0)
1154 return -1;
1155
1156 key = malloc(info.key_size);
1157 nextkey = malloc(info.key_size);
1158 if (!key || !nextkey) {
1159 p_err("mem alloc failed");
1160 err = -1;
1161 goto exit_free;
1162 }
1163
1164 if (argc) {
1165 err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
1166 NULL, NULL);
1167 if (err)
1168 goto exit_free;
1169 } else {
1170 free(key);
1171 key = NULL;
1172 }
1173
1174 err = bpf_map_get_next_key(fd, key, nextkey);
1175 if (err) {
1176 p_err("can't get next key: %s", strerror(errno));
1177 goto exit_free;
1178 }
1179
1180 if (json_output) {
1181 jsonw_start_object(json_wtr);
1182 if (key) {
1183 jsonw_name(json_wtr, "key");
1184 print_hex_data_json(key, info.key_size);
1185 } else {
1186 jsonw_null_field(json_wtr, "key");
1187 }
1188 jsonw_name(json_wtr, "next_key");
1189 print_hex_data_json(nextkey, info.key_size);
1190 jsonw_end_object(json_wtr);
1191 } else {
1192 if (key) {
1193 printf("key:\n");
1194 fprint_hex(stdout, key, info.key_size, " ");
1195 printf("\n");
1196 } else {
1197 printf("key: None\n");
1198 }
1199 printf("next key:\n");
1200 fprint_hex(stdout, nextkey, info.key_size, " ");
1201 printf("\n");
1202 }
1203
1204 exit_free:
1205 free(nextkey);
1206 free(key);
1207 close(fd);
1208
1209 return err;
1210 }
1211
do_delete(int argc,char ** argv)1212 static int do_delete(int argc, char **argv)
1213 {
1214 struct bpf_map_info info = {};
1215 __u32 len = sizeof(info);
1216 void *key;
1217 int err;
1218 int fd;
1219
1220 if (argc < 2)
1221 usage();
1222
1223 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1224 if (fd < 0)
1225 return -1;
1226
1227 key = malloc(info.key_size);
1228 if (!key) {
1229 p_err("mem alloc failed");
1230 err = -1;
1231 goto exit_free;
1232 }
1233
1234 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
1235 if (err)
1236 goto exit_free;
1237
1238 err = bpf_map_delete_elem(fd, key);
1239 if (err)
1240 p_err("delete failed: %s", strerror(errno));
1241
1242 exit_free:
1243 free(key);
1244 close(fd);
1245
1246 if (!err && json_output)
1247 jsonw_null(json_wtr);
1248 return err;
1249 }
1250
do_pin(int argc,char ** argv)1251 static int do_pin(int argc, char **argv)
1252 {
1253 int err;
1254
1255 err = do_pin_any(argc, argv, map_parse_fd);
1256 if (!err && json_output)
1257 jsonw_null(json_wtr);
1258 return err;
1259 }
1260
do_create(int argc,char ** argv)1261 static int do_create(int argc, char **argv)
1262 {
1263 struct bpf_create_map_attr attr = { NULL, };
1264 const char *pinfile;
1265 int err = -1, fd;
1266
1267 if (!REQ_ARGS(7))
1268 return -1;
1269 pinfile = GET_ARG();
1270
1271 while (argc) {
1272 if (!REQ_ARGS(2))
1273 return -1;
1274
1275 if (is_prefix(*argv, "type")) {
1276 NEXT_ARG();
1277
1278 if (attr.map_type) {
1279 p_err("map type already specified");
1280 goto exit;
1281 }
1282
1283 attr.map_type = map_type_from_str(*argv);
1284 if ((int)attr.map_type < 0) {
1285 p_err("unrecognized map type: %s", *argv);
1286 goto exit;
1287 }
1288 NEXT_ARG();
1289 } else if (is_prefix(*argv, "name")) {
1290 NEXT_ARG();
1291 attr.name = GET_ARG();
1292 } else if (is_prefix(*argv, "key")) {
1293 if (parse_u32_arg(&argc, &argv, &attr.key_size,
1294 "key size"))
1295 goto exit;
1296 } else if (is_prefix(*argv, "value")) {
1297 if (parse_u32_arg(&argc, &argv, &attr.value_size,
1298 "value size"))
1299 goto exit;
1300 } else if (is_prefix(*argv, "entries")) {
1301 if (parse_u32_arg(&argc, &argv, &attr.max_entries,
1302 "max entries"))
1303 goto exit;
1304 } else if (is_prefix(*argv, "flags")) {
1305 if (parse_u32_arg(&argc, &argv, &attr.map_flags,
1306 "flags"))
1307 goto exit;
1308 } else if (is_prefix(*argv, "dev")) {
1309 NEXT_ARG();
1310
1311 if (attr.map_ifindex) {
1312 p_err("offload device already specified");
1313 goto exit;
1314 }
1315
1316 attr.map_ifindex = if_nametoindex(*argv);
1317 if (!attr.map_ifindex) {
1318 p_err("unrecognized netdevice '%s': %s",
1319 *argv, strerror(errno));
1320 goto exit;
1321 }
1322 NEXT_ARG();
1323 } else if (is_prefix(*argv, "inner_map")) {
1324 struct bpf_map_info info = {};
1325 __u32 len = sizeof(info);
1326 int inner_map_fd;
1327
1328 NEXT_ARG();
1329 if (!REQ_ARGS(2))
1330 usage();
1331 inner_map_fd = map_parse_fd_and_info(&argc, &argv,
1332 &info, &len);
1333 if (inner_map_fd < 0)
1334 return -1;
1335 attr.inner_map_fd = inner_map_fd;
1336 } else {
1337 p_err("unknown arg %s", *argv);
1338 goto exit;
1339 }
1340 }
1341
1342 if (!attr.name) {
1343 p_err("map name not specified");
1344 goto exit;
1345 }
1346
1347 set_max_rlimit();
1348
1349 fd = bpf_create_map_xattr(&attr);
1350 if (fd < 0) {
1351 p_err("map create failed: %s", strerror(errno));
1352 goto exit;
1353 }
1354
1355 err = do_pin_fd(fd, pinfile);
1356 close(fd);
1357 if (err)
1358 goto exit;
1359
1360 if (json_output)
1361 jsonw_null(json_wtr);
1362
1363 exit:
1364 if (attr.inner_map_fd > 0)
1365 close(attr.inner_map_fd);
1366
1367 return err;
1368 }
1369
do_pop_dequeue(int argc,char ** argv)1370 static int do_pop_dequeue(int argc, char **argv)
1371 {
1372 struct bpf_map_info info = {};
1373 __u32 len = sizeof(info);
1374 void *key, *value;
1375 int err;
1376 int fd;
1377
1378 if (argc < 2)
1379 usage();
1380
1381 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1382 if (fd < 0)
1383 return -1;
1384
1385 err = alloc_key_value(&info, &key, &value);
1386 if (err)
1387 goto exit_free;
1388
1389 err = bpf_map_lookup_and_delete_elem(fd, key, value);
1390 if (err) {
1391 if (errno == ENOENT) {
1392 if (json_output)
1393 jsonw_null(json_wtr);
1394 else
1395 printf("Error: empty map\n");
1396 } else {
1397 p_err("pop failed: %s", strerror(errno));
1398 }
1399
1400 goto exit_free;
1401 }
1402
1403 print_key_value(&info, key, value);
1404
1405 exit_free:
1406 free(key);
1407 free(value);
1408 close(fd);
1409
1410 return err;
1411 }
1412
do_freeze(int argc,char ** argv)1413 static int do_freeze(int argc, char **argv)
1414 {
1415 int err, fd;
1416
1417 if (!REQ_ARGS(2))
1418 return -1;
1419
1420 fd = map_parse_fd(&argc, &argv);
1421 if (fd < 0)
1422 return -1;
1423
1424 if (argc) {
1425 close(fd);
1426 return BAD_ARG();
1427 }
1428
1429 err = bpf_map_freeze(fd);
1430 close(fd);
1431 if (err) {
1432 p_err("failed to freeze map: %s", strerror(errno));
1433 return err;
1434 }
1435
1436 if (json_output)
1437 jsonw_null(json_wtr);
1438
1439 return 0;
1440 }
1441
do_help(int argc,char ** argv)1442 static int do_help(int argc, char **argv)
1443 {
1444 if (json_output) {
1445 jsonw_null(json_wtr);
1446 return 0;
1447 }
1448
1449 fprintf(stderr,
1450 "Usage: %1$s %2$s { show | list } [MAP]\n"
1451 " %1$s %2$s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
1452 " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
1453 " [inner_map MAP] [dev NAME]\n"
1454 " %1$s %2$s dump MAP\n"
1455 " %1$s %2$s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
1456 " %1$s %2$s lookup MAP [key DATA]\n"
1457 " %1$s %2$s getnext MAP [key DATA]\n"
1458 " %1$s %2$s delete MAP key DATA\n"
1459 " %1$s %2$s pin MAP FILE\n"
1460 " %1$s %2$s event_pipe MAP [cpu N index M]\n"
1461 " %1$s %2$s peek MAP\n"
1462 " %1$s %2$s push MAP value VALUE\n"
1463 " %1$s %2$s pop MAP\n"
1464 " %1$s %2$s enqueue MAP value VALUE\n"
1465 " %1$s %2$s dequeue MAP\n"
1466 " %1$s %2$s freeze MAP\n"
1467 " %1$s %2$s help\n"
1468 "\n"
1469 " " HELP_SPEC_MAP "\n"
1470 " DATA := { [hex] BYTES }\n"
1471 " " HELP_SPEC_PROGRAM "\n"
1472 " VALUE := { DATA | MAP | PROG }\n"
1473 " UPDATE_FLAGS := { any | exist | noexist }\n"
1474 " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
1475 " percpu_array | stack_trace | cgroup_array | lru_hash |\n"
1476 " lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
1477 " devmap | devmap_hash | sockmap | cpumap | xskmap | sockhash |\n"
1478 " cgroup_storage | reuseport_sockarray | percpu_cgroup_storage |\n"
1479 " queue | stack | sk_storage | struct_ops | ringbuf | inode_storage |\n"
1480 " task_storage }\n"
1481 " " HELP_SPEC_OPTIONS " |\n"
1482 " {-f|--bpffs} | {-n|--nomount} }\n"
1483 "",
1484 bin_name, argv[-2]);
1485
1486 return 0;
1487 }
1488
1489 static const struct cmd cmds[] = {
1490 { "show", do_show },
1491 { "list", do_show },
1492 { "help", do_help },
1493 { "dump", do_dump },
1494 { "update", do_update },
1495 { "lookup", do_lookup },
1496 { "getnext", do_getnext },
1497 { "delete", do_delete },
1498 { "pin", do_pin },
1499 { "event_pipe", do_event_pipe },
1500 { "create", do_create },
1501 { "peek", do_lookup },
1502 { "push", do_update },
1503 { "enqueue", do_update },
1504 { "pop", do_pop_dequeue },
1505 { "dequeue", do_pop_dequeue },
1506 { "freeze", do_freeze },
1507 { 0 }
1508 };
1509
do_map(int argc,char ** argv)1510 int do_map(int argc, char **argv)
1511 {
1512 return cmd_select(cmds, argc, argv, do_help);
1513 }
1514