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