cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

map.c (33444B)


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