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