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