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_start_object(json_wtr);
720 jsonw_name(json_wtr, "key");
721 print_hex_data_json(key, map_info->key_size);
722 jsonw_name(json_wtr, "value");
723 jsonw_start_object(json_wtr);
724 jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
725 jsonw_end_object(json_wtr);
726 jsonw_end_object(json_wtr);
727 } else {
728 const char *msg = NULL;
729
730 if (lookup_errno == ENOENT)
731 msg = "<no entry>";
732 else if (lookup_errno == ENOSPC &&
733 map_info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
734 msg = "<cannot read>";
735
736 print_entry_error(map_info, key,
737 msg ? : strerror(lookup_errno));
738 }
739
740 return 0;
741}
742
743static int do_dump(int argc, char **argv)
744{
745 struct bpf_map_info info = {};
746 void *key, *value, *prev_key;
747 unsigned int num_elems = 0;
748 __u32 len = sizeof(info);
749 json_writer_t *btf_wtr;
750 struct btf *btf = NULL;
751 int err;
752 int fd;
753
754 if (argc != 2)
755 usage();
756
757 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
758 if (fd < 0)
759 return -1;
760
761 key = malloc(info.key_size);
762 value = alloc_value(&info);
763 if (!key || !value) {
764 p_err("mem alloc failed");
765 err = -1;
766 goto exit_free;
767 }
768
769 prev_key = NULL;
770
771 err = btf__get_from_id(info.btf_id, &btf);
772 if (err) {
773 p_err("failed to get btf");
774 goto exit_free;
775 }
776
777 if (json_output)
778 jsonw_start_array(json_wtr);
779 else
780 if (btf) {
781 btf_wtr = get_btf_writer();
782 if (!btf_wtr) {
783 p_info("failed to create json writer for btf. falling back to plain output");
784 btf__free(btf);
785 btf = NULL;
786 } else {
787 jsonw_start_array(btf_wtr);
788 }
789 }
790
791 if (info.type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
792 info.value_size != 8)
793 p_info("Warning: cannot read values from %s map with value_size != 8",
794 map_type_name[info.type]);
795 while (true) {
796 err = bpf_map_get_next_key(fd, prev_key, key);
797 if (err) {
798 if (errno == ENOENT)
799 err = 0;
800 break;
801 }
802 num_elems += dump_map_elem(fd, key, value, &info, btf, btf_wtr);
803 prev_key = key;
804 }
805
806 if (json_output)
807 jsonw_end_array(json_wtr);
808 else if (btf) {
809 jsonw_end_array(btf_wtr);
810 jsonw_destroy(&btf_wtr);
811 } else {
812 printf("Found %u element%s\n", num_elems,
813 num_elems != 1 ? "s" : "");
814 }
815
816exit_free:
817 free(key);
818 free(value);
819 close(fd);
820 btf__free(btf);
821
822 return err;
823}
824
825static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
826{
827 *key = NULL;
828 *value = NULL;
829
830 if (info->key_size) {
831 *key = malloc(info->key_size);
832 if (!*key) {
833 p_err("key mem alloc failed");
834 return -1;
835 }
836 }
837
838 if (info->value_size) {
839 *value = alloc_value(info);
840 if (!*value) {
841 p_err("value mem alloc failed");
842 free(*key);
843 *key = NULL;
844 return -1;
845 }
846 }
847
848 return 0;
849}
850
851static int do_update(int argc, char **argv)
852{
853 struct bpf_map_info info = {};
854 __u32 len = sizeof(info);
855 __u32 *value_fd = NULL;
856 __u32 flags = BPF_ANY;
857 void *key, *value;
858 int fd, err;
859
860 if (argc < 2)
861 usage();
862
863 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
864 if (fd < 0)
865 return -1;
866
867 err = alloc_key_value(&info, &key, &value);
868 if (err)
869 goto exit_free;
870
871 err = parse_elem(argv, &info, key, value, info.key_size,
872 info.value_size, &flags, &value_fd);
873 if (err)
874 goto exit_free;
875
876 err = bpf_map_update_elem(fd, key, value, flags);
877 if (err) {
878 p_err("update failed: %s", strerror(errno));
879 goto exit_free;
880 }
881
882exit_free:
883 if (value_fd)
884 close(*value_fd);
885 free(key);
886 free(value);
887 close(fd);
888
889 if (!err && json_output)
890 jsonw_null(json_wtr);
891 return err;
892}
893
894static void print_key_value(struct bpf_map_info *info, void *key,
895 void *value)
896{
897 json_writer_t *btf_wtr;
898 struct btf *btf = NULL;
899 int err;
900
901 err = btf__get_from_id(info->btf_id, &btf);
902 if (err) {
903 p_err("failed to get btf");
904 return;
905 }
906
907 if (json_output) {
908 print_entry_json(info, key, value, btf);
909 } else if (btf) {
910 /* if here json_wtr wouldn't have been initialised,
911 * so let's create separate writer for btf
912 */
913 btf_wtr = get_btf_writer();
914 if (!btf_wtr) {
915 p_info("failed to create json writer for btf. falling back to plain output");
916 btf__free(btf);
917 btf = NULL;
918 print_entry_plain(info, key, value);
919 } else {
920 struct btf_dumper d = {
921 .btf = btf,
922 .jw = btf_wtr,
923 .is_plain_text = true,
924 };
925
926 do_dump_btf(&d, info, key, value);
927 jsonw_destroy(&btf_wtr);
928 }
929 } else {
930 print_entry_plain(info, key, value);
931 }
932 btf__free(btf);
933}
934
935static int do_lookup(int argc, char **argv)
936{
937 struct bpf_map_info info = {};
938 __u32 len = sizeof(info);
939 void *key, *value;
940 int err;
941 int fd;
942
943 if (argc < 2)
944 usage();
945
946 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
947 if (fd < 0)
948 return -1;
949
950 err = alloc_key_value(&info, &key, &value);
951 if (err)
952 goto exit_free;
953
954 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
955 if (err)
956 goto exit_free;
957
958 err = bpf_map_lookup_elem(fd, key, value);
959 if (err) {
960 if (errno == ENOENT) {
961 if (json_output) {
962 jsonw_null(json_wtr);
963 } else {
964 printf("key:\n");
965 fprint_hex(stdout, key, info.key_size, " ");
966 printf("\n\nNot found\n");
967 }
968 } else {
969 p_err("lookup failed: %s", strerror(errno));
970 }
971
972 goto exit_free;
973 }
974
975 /* here means bpf_map_lookup_elem() succeeded */
976 print_key_value(&info, key, value);
977
978exit_free:
979 free(key);
980 free(value);
981 close(fd);
982
983 return err;
984}
985
986static int do_getnext(int argc, char **argv)
987{
988 struct bpf_map_info info = {};
989 __u32 len = sizeof(info);
990 void *key, *nextkey;
991 int err;
992 int fd;
993
994 if (argc < 2)
995 usage();
996
997 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
998 if (fd < 0)
999 return -1;
1000
1001 key = malloc(info.key_size);
1002 nextkey = malloc(info.key_size);
1003 if (!key || !nextkey) {
1004 p_err("mem alloc failed");
1005 err = -1;
1006 goto exit_free;
1007 }
1008
1009 if (argc) {
1010 err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
1011 NULL, NULL);
1012 if (err)
1013 goto exit_free;
1014 } else {
1015 free(key);
1016 key = NULL;
1017 }
1018
1019 err = bpf_map_get_next_key(fd, key, nextkey);
1020 if (err) {
1021 p_err("can't get next key: %s", strerror(errno));
1022 goto exit_free;
1023 }
1024
1025 if (json_output) {
1026 jsonw_start_object(json_wtr);
1027 if (key) {
1028 jsonw_name(json_wtr, "key");
1029 print_hex_data_json(key, info.key_size);
1030 } else {
1031 jsonw_null_field(json_wtr, "key");
1032 }
1033 jsonw_name(json_wtr, "next_key");
1034 print_hex_data_json(nextkey, info.key_size);
1035 jsonw_end_object(json_wtr);
1036 } else {
1037 if (key) {
1038 printf("key:\n");
1039 fprint_hex(stdout, key, info.key_size, " ");
1040 printf("\n");
1041 } else {
1042 printf("key: None\n");
1043 }
1044 printf("next key:\n");
1045 fprint_hex(stdout, nextkey, info.key_size, " ");
1046 printf("\n");
1047 }
1048
1049exit_free:
1050 free(nextkey);
1051 free(key);
1052 close(fd);
1053
1054 return err;
1055}
1056
1057static int do_delete(int argc, char **argv)
1058{
1059 struct bpf_map_info info = {};
1060 __u32 len = sizeof(info);
1061 void *key;
1062 int err;
1063 int fd;
1064
1065 if (argc < 2)
1066 usage();
1067
1068 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1069 if (fd < 0)
1070 return -1;
1071
1072 key = malloc(info.key_size);
1073 if (!key) {
1074 p_err("mem alloc failed");
1075 err = -1;
1076 goto exit_free;
1077 }
1078
1079 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
1080 if (err)
1081 goto exit_free;
1082
1083 err = bpf_map_delete_elem(fd, key);
1084 if (err)
1085 p_err("delete failed: %s", strerror(errno));
1086
1087exit_free:
1088 free(key);
1089 close(fd);
1090
1091 if (!err && json_output)
1092 jsonw_null(json_wtr);
1093 return err;
1094}
1095
1096static int do_pin(int argc, char **argv)
1097{
1098 int err;
1099
1100 err = do_pin_any(argc, argv, bpf_map_get_fd_by_id);
1101 if (!err && json_output)
1102 jsonw_null(json_wtr);
1103 return err;
1104}
1105
1106static int do_create(int argc, char **argv)
1107{
1108 struct bpf_create_map_attr attr = { NULL, };
1109 const char *pinfile;
1110 int err, fd;
1111
1112 if (!REQ_ARGS(7))
1113 return -1;
1114 pinfile = GET_ARG();
1115
1116 while (argc) {
1117 if (!REQ_ARGS(2))
1118 return -1;
1119
1120 if (is_prefix(*argv, "type")) {
1121 NEXT_ARG();
1122
1123 if (attr.map_type) {
1124 p_err("map type already specified");
1125 return -1;
1126 }
1127
1128 attr.map_type = map_type_from_str(*argv);
1129 if ((int)attr.map_type < 0) {
1130 p_err("unrecognized map type: %s", *argv);
1131 return -1;
1132 }
1133 NEXT_ARG();
1134 } else if (is_prefix(*argv, "name")) {
1135 NEXT_ARG();
1136 attr.name = GET_ARG();
1137 } else if (is_prefix(*argv, "key")) {
1138 if (parse_u32_arg(&argc, &argv, &attr.key_size,
1139 "key size"))
1140 return -1;
1141 } else if (is_prefix(*argv, "value")) {
1142 if (parse_u32_arg(&argc, &argv, &attr.value_size,
1143 "value size"))
1144 return -1;
1145 } else if (is_prefix(*argv, "entries")) {
1146 if (parse_u32_arg(&argc, &argv, &attr.max_entries,
1147 "max entries"))
1148 return -1;
1149 } else if (is_prefix(*argv, "flags")) {
1150 if (parse_u32_arg(&argc, &argv, &attr.map_flags,
1151 "flags"))
1152 return -1;
1153 } else if (is_prefix(*argv, "dev")) {
1154 NEXT_ARG();
1155
1156 if (attr.map_ifindex) {
1157 p_err("offload device already specified");
1158 return -1;
1159 }
1160
1161 attr.map_ifindex = if_nametoindex(*argv);
1162 if (!attr.map_ifindex) {
1163 p_err("unrecognized netdevice '%s': %s",
1164 *argv, strerror(errno));
1165 return -1;
1166 }
1167 NEXT_ARG();
1168 } else {
1169 p_err("unknown arg %s", *argv);
1170 return -1;
1171 }
1172 }
1173
1174 if (!attr.name) {
1175 p_err("map name not specified");
1176 return -1;
1177 }
1178
1179 set_max_rlimit();
1180
1181 fd = bpf_create_map_xattr(&attr);
1182 if (fd < 0) {
1183 p_err("map create failed: %s", strerror(errno));
1184 return -1;
1185 }
1186
1187 err = do_pin_fd(fd, pinfile);
1188 close(fd);
1189 if (err)
1190 return err;
1191
1192 if (json_output)
1193 jsonw_null(json_wtr);
1194 return 0;
1195}
1196
1197static int do_pop_dequeue(int argc, char **argv)
1198{
1199 struct bpf_map_info info = {};
1200 __u32 len = sizeof(info);
1201 void *key, *value;
1202 int err;
1203 int fd;
1204
1205 if (argc < 2)
1206 usage();
1207
1208 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1209 if (fd < 0)
1210 return -1;
1211
1212 err = alloc_key_value(&info, &key, &value);
1213 if (err)
1214 goto exit_free;
1215
1216 err = bpf_map_lookup_and_delete_elem(fd, key, value);
1217 if (err) {
1218 if (errno == ENOENT) {
1219 if (json_output)
1220 jsonw_null(json_wtr);
1221 else
1222 printf("Error: empty map\n");
1223 } else {
1224 p_err("pop failed: %s", strerror(errno));
1225 }
1226
1227 goto exit_free;
1228 }
1229
1230 print_key_value(&info, key, value);
1231
1232exit_free:
1233 free(key);
1234 free(value);
1235 close(fd);
1236
1237 return err;
1238}
1239
1240static int do_help(int argc, char **argv)
1241{
1242 if (json_output) {
1243 jsonw_null(json_wtr);
1244 return 0;
1245 }
1246
1247 fprintf(stderr,
1248 "Usage: %s %s { show | list } [MAP]\n"
1249 " %s %s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
1250 " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
1251 " [dev NAME]\n"
1252 " %s %s dump MAP\n"
1253 " %s %s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
1254 " %s %s lookup MAP [key DATA]\n"
1255 " %s %s getnext MAP [key DATA]\n"
1256 " %s %s delete MAP key DATA\n"
1257 " %s %s pin MAP FILE\n"
1258 " %s %s event_pipe MAP [cpu N index M]\n"
1259 " %s %s peek MAP\n"
1260 " %s %s push MAP value VALUE\n"
1261 " %s %s pop MAP\n"
1262 " %s %s enqueue MAP value VALUE\n"
1263 " %s %s dequeue MAP\n"
1264 " %s %s help\n"
1265 "\n"
1266 " " HELP_SPEC_MAP "\n"
1267 " DATA := { [hex] BYTES }\n"
1268 " " HELP_SPEC_PROGRAM "\n"
1269 " VALUE := { DATA | MAP | PROG }\n"
1270 " UPDATE_FLAGS := { any | exist | noexist }\n"
1271 " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
1272 " percpu_array | stack_trace | cgroup_array | lru_hash |\n"
1273 " lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
1274 " devmap | sockmap | cpumap | xskmap | sockhash |\n"
1275 " cgroup_storage | reuseport_sockarray | percpu_cgroup_storage }\n"
1276 " " HELP_SPEC_OPTIONS "\n"
1277 "",
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 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
1282 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
1283
1284 return 0;
1285}
1286
1287static const struct cmd cmds[] = {
1288 { "show", do_show },
1289 { "list", do_show },
1290 { "help", do_help },
1291 { "dump", do_dump },
1292 { "update", do_update },
1293 { "lookup", do_lookup },
1294 { "getnext", do_getnext },
1295 { "delete", do_delete },
1296 { "pin", do_pin },
1297 { "event_pipe", do_event_pipe },
1298 { "create", do_create },
1299 { "peek", do_lookup },
1300 { "push", do_update },
1301 { "enqueue", do_update },
1302 { "pop", do_pop_dequeue },
1303 { "dequeue", do_pop_dequeue },
1304 { 0 }
1305};
1306
1307int do_map(int argc, char **argv)
1308{
1309 return cmd_select(cmds, argc, argv, do_help);
1310}