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