162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <errno.h>
562306a36Sopenharmony_ci#include <fcntl.h>
662306a36Sopenharmony_ci#include <linux/err.h>
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <net/if.h>
962306a36Sopenharmony_ci#include <stdbool.h>
1062306a36Sopenharmony_ci#include <stdio.h>
1162306a36Sopenharmony_ci#include <stdlib.h>
1262306a36Sopenharmony_ci#include <string.h>
1362306a36Sopenharmony_ci#include <unistd.h>
1462306a36Sopenharmony_ci#include <sys/types.h>
1562306a36Sopenharmony_ci#include <sys/stat.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <bpf/bpf.h>
1862306a36Sopenharmony_ci#include <bpf/btf.h>
1962306a36Sopenharmony_ci#include <bpf/hashmap.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "json_writer.h"
2262306a36Sopenharmony_ci#include "main.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic struct hashmap *map_table;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic bool map_is_per_cpu(__u32 type)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	return type == BPF_MAP_TYPE_PERCPU_HASH ||
2962306a36Sopenharmony_ci	       type == BPF_MAP_TYPE_PERCPU_ARRAY ||
3062306a36Sopenharmony_ci	       type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
3162306a36Sopenharmony_ci	       type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic bool map_is_map_of_maps(__u32 type)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	return type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
3762306a36Sopenharmony_ci	       type == BPF_MAP_TYPE_HASH_OF_MAPS;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic bool map_is_map_of_progs(__u32 type)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return type == BPF_MAP_TYPE_PROG_ARRAY;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int map_type_from_str(const char *type)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	const char *map_type_str;
4862306a36Sopenharmony_ci	unsigned int i;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	for (i = 0; ; i++) {
5162306a36Sopenharmony_ci		map_type_str = libbpf_bpf_map_type_str(i);
5262306a36Sopenharmony_ci		if (!map_type_str)
5362306a36Sopenharmony_ci			break;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci		/* Don't allow prefixing in case of possible future shadowing */
5662306a36Sopenharmony_ci		if (!strcmp(map_type_str, type))
5762306a36Sopenharmony_ci			return i;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci	return -1;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void *alloc_value(struct bpf_map_info *info)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	if (map_is_per_cpu(info->type))
6562306a36Sopenharmony_ci		return malloc(round_up(info->value_size, 8) *
6662306a36Sopenharmony_ci			      get_possible_cpus());
6762306a36Sopenharmony_ci	else
6862306a36Sopenharmony_ci		return malloc(info->value_size);
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int do_dump_btf(const struct btf_dumper *d,
7262306a36Sopenharmony_ci		       struct bpf_map_info *map_info, void *key,
7362306a36Sopenharmony_ci		       void *value)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	__u32 value_id;
7662306a36Sopenharmony_ci	int ret = 0;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* start of key-value pair */
7962306a36Sopenharmony_ci	jsonw_start_object(d->jw);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (map_info->btf_key_type_id) {
8262306a36Sopenharmony_ci		jsonw_name(d->jw, "key");
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
8562306a36Sopenharmony_ci		if (ret)
8662306a36Sopenharmony_ci			goto err_end_obj;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	value_id = map_info->btf_vmlinux_value_type_id ?
9062306a36Sopenharmony_ci		: map_info->btf_value_type_id;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (!map_is_per_cpu(map_info->type)) {
9362306a36Sopenharmony_ci		jsonw_name(d->jw, "value");
9462306a36Sopenharmony_ci		ret = btf_dumper_type(d, value_id, value);
9562306a36Sopenharmony_ci	} else {
9662306a36Sopenharmony_ci		unsigned int i, n, step;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		jsonw_name(d->jw, "values");
9962306a36Sopenharmony_ci		jsonw_start_array(d->jw);
10062306a36Sopenharmony_ci		n = get_possible_cpus();
10162306a36Sopenharmony_ci		step = round_up(map_info->value_size, 8);
10262306a36Sopenharmony_ci		for (i = 0; i < n; i++) {
10362306a36Sopenharmony_ci			jsonw_start_object(d->jw);
10462306a36Sopenharmony_ci			jsonw_int_field(d->jw, "cpu", i);
10562306a36Sopenharmony_ci			jsonw_name(d->jw, "value");
10662306a36Sopenharmony_ci			ret = btf_dumper_type(d, value_id, value + i * step);
10762306a36Sopenharmony_ci			jsonw_end_object(d->jw);
10862306a36Sopenharmony_ci			if (ret)
10962306a36Sopenharmony_ci				break;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci		jsonw_end_array(d->jw);
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cierr_end_obj:
11562306a36Sopenharmony_ci	/* end of key-value pair */
11662306a36Sopenharmony_ci	jsonw_end_object(d->jw);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	return ret;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic json_writer_t *get_btf_writer(void)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	json_writer_t *jw = jsonw_new(stdout);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (!jw)
12662306a36Sopenharmony_ci		return NULL;
12762306a36Sopenharmony_ci	jsonw_pretty(jw, true);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	return jw;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic void print_entry_json(struct bpf_map_info *info, unsigned char *key,
13362306a36Sopenharmony_ci			     unsigned char *value, struct btf *btf)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	jsonw_start_object(json_wtr);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (!map_is_per_cpu(info->type)) {
13862306a36Sopenharmony_ci		jsonw_name(json_wtr, "key");
13962306a36Sopenharmony_ci		print_hex_data_json(key, info->key_size);
14062306a36Sopenharmony_ci		jsonw_name(json_wtr, "value");
14162306a36Sopenharmony_ci		print_hex_data_json(value, info->value_size);
14262306a36Sopenharmony_ci		if (map_is_map_of_maps(info->type))
14362306a36Sopenharmony_ci			jsonw_uint_field(json_wtr, "inner_map_id",
14462306a36Sopenharmony_ci					 *(unsigned int *)value);
14562306a36Sopenharmony_ci		if (btf) {
14662306a36Sopenharmony_ci			struct btf_dumper d = {
14762306a36Sopenharmony_ci				.btf = btf,
14862306a36Sopenharmony_ci				.jw = json_wtr,
14962306a36Sopenharmony_ci				.is_plain_text = false,
15062306a36Sopenharmony_ci			};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci			jsonw_name(json_wtr, "formatted");
15362306a36Sopenharmony_ci			do_dump_btf(&d, info, key, value);
15462306a36Sopenharmony_ci		}
15562306a36Sopenharmony_ci	} else {
15662306a36Sopenharmony_ci		unsigned int i, n, step;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		n = get_possible_cpus();
15962306a36Sopenharmony_ci		step = round_up(info->value_size, 8);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		jsonw_name(json_wtr, "key");
16262306a36Sopenharmony_ci		print_hex_data_json(key, info->key_size);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		jsonw_name(json_wtr, "values");
16562306a36Sopenharmony_ci		jsonw_start_array(json_wtr);
16662306a36Sopenharmony_ci		for (i = 0; i < n; i++) {
16762306a36Sopenharmony_ci			jsonw_start_object(json_wtr);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci			jsonw_int_field(json_wtr, "cpu", i);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci			jsonw_name(json_wtr, "value");
17262306a36Sopenharmony_ci			print_hex_data_json(value + i * step,
17362306a36Sopenharmony_ci					    info->value_size);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci			jsonw_end_object(json_wtr);
17662306a36Sopenharmony_ci		}
17762306a36Sopenharmony_ci		jsonw_end_array(json_wtr);
17862306a36Sopenharmony_ci		if (btf) {
17962306a36Sopenharmony_ci			struct btf_dumper d = {
18062306a36Sopenharmony_ci				.btf = btf,
18162306a36Sopenharmony_ci				.jw = json_wtr,
18262306a36Sopenharmony_ci				.is_plain_text = false,
18362306a36Sopenharmony_ci			};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci			jsonw_name(json_wtr, "formatted");
18662306a36Sopenharmony_ci			do_dump_btf(&d, info, key, value);
18762306a36Sopenharmony_ci		}
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	jsonw_end_object(json_wtr);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic void
19462306a36Sopenharmony_ciprint_entry_error_msg(struct bpf_map_info *info, unsigned char *key,
19562306a36Sopenharmony_ci		      const char *error_msg)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	int msg_size = strlen(error_msg);
19862306a36Sopenharmony_ci	bool single_line, break_names;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	break_names = info->key_size > 16 || msg_size > 16;
20162306a36Sopenharmony_ci	single_line = info->key_size + msg_size <= 24 && !break_names;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	printf("key:%c", break_names ? '\n' : ' ');
20462306a36Sopenharmony_ci	fprint_hex(stdout, key, info->key_size, " ");
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	printf(single_line ? "  " : "\n");
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	printf("value:%c%s", break_names ? '\n' : ' ', error_msg);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	printf("\n");
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic void
21462306a36Sopenharmony_ciprint_entry_error(struct bpf_map_info *map_info, void *key, int lookup_errno)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	/* For prog_array maps or arrays of maps, failure to lookup the value
21762306a36Sopenharmony_ci	 * means there is no entry for that key. Do not print an error message
21862306a36Sopenharmony_ci	 * in that case.
21962306a36Sopenharmony_ci	 */
22062306a36Sopenharmony_ci	if ((map_is_map_of_maps(map_info->type) ||
22162306a36Sopenharmony_ci	     map_is_map_of_progs(map_info->type)) && lookup_errno == ENOENT)
22262306a36Sopenharmony_ci		return;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (json_output) {
22562306a36Sopenharmony_ci		jsonw_start_object(json_wtr);	/* entry */
22662306a36Sopenharmony_ci		jsonw_name(json_wtr, "key");
22762306a36Sopenharmony_ci		print_hex_data_json(key, map_info->key_size);
22862306a36Sopenharmony_ci		jsonw_name(json_wtr, "value");
22962306a36Sopenharmony_ci		jsonw_start_object(json_wtr);	/* error */
23062306a36Sopenharmony_ci		jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
23162306a36Sopenharmony_ci		jsonw_end_object(json_wtr);	/* error */
23262306a36Sopenharmony_ci		jsonw_end_object(json_wtr);	/* entry */
23362306a36Sopenharmony_ci	} else {
23462306a36Sopenharmony_ci		const char *msg = NULL;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		if (lookup_errno == ENOENT)
23762306a36Sopenharmony_ci			msg = "<no entry>";
23862306a36Sopenharmony_ci		else if (lookup_errno == ENOSPC &&
23962306a36Sopenharmony_ci			 map_info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
24062306a36Sopenharmony_ci			msg = "<cannot read>";
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		print_entry_error_msg(map_info, key,
24362306a36Sopenharmony_ci				      msg ? : strerror(lookup_errno));
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
24862306a36Sopenharmony_ci			      unsigned char *value)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	if (!map_is_per_cpu(info->type)) {
25162306a36Sopenharmony_ci		bool single_line, break_names;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		break_names = info->key_size > 16 || info->value_size > 16;
25462306a36Sopenharmony_ci		single_line = info->key_size + info->value_size <= 24 &&
25562306a36Sopenharmony_ci			!break_names;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		if (info->key_size) {
25862306a36Sopenharmony_ci			printf("key:%c", break_names ? '\n' : ' ');
25962306a36Sopenharmony_ci			fprint_hex(stdout, key, info->key_size, " ");
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci			printf(single_line ? "  " : "\n");
26262306a36Sopenharmony_ci		}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		if (info->value_size) {
26562306a36Sopenharmony_ci			if (map_is_map_of_maps(info->type)) {
26662306a36Sopenharmony_ci				printf("inner_map_id:%c", break_names ? '\n' : ' ');
26762306a36Sopenharmony_ci				printf("%u ", *(unsigned int *)value);
26862306a36Sopenharmony_ci			} else {
26962306a36Sopenharmony_ci				printf("value:%c", break_names ? '\n' : ' ');
27062306a36Sopenharmony_ci				fprint_hex(stdout, value, info->value_size, " ");
27162306a36Sopenharmony_ci			}
27262306a36Sopenharmony_ci		}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		printf("\n");
27562306a36Sopenharmony_ci	} else {
27662306a36Sopenharmony_ci		unsigned int i, n, step;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		n = get_possible_cpus();
27962306a36Sopenharmony_ci		step = round_up(info->value_size, 8);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		if (info->key_size) {
28262306a36Sopenharmony_ci			printf("key:\n");
28362306a36Sopenharmony_ci			fprint_hex(stdout, key, info->key_size, " ");
28462306a36Sopenharmony_ci			printf("\n");
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci		if (info->value_size) {
28762306a36Sopenharmony_ci			for (i = 0; i < n; i++) {
28862306a36Sopenharmony_ci				printf("value (CPU %02d):%c",
28962306a36Sopenharmony_ci				       i, info->value_size > 16 ? '\n' : ' ');
29062306a36Sopenharmony_ci				fprint_hex(stdout, value + i * step,
29162306a36Sopenharmony_ci					   info->value_size, " ");
29262306a36Sopenharmony_ci				printf("\n");
29362306a36Sopenharmony_ci			}
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic char **parse_bytes(char **argv, const char *name, unsigned char *val,
29962306a36Sopenharmony_ci			  unsigned int n)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	unsigned int i = 0, base = 0;
30262306a36Sopenharmony_ci	char *endptr;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (is_prefix(*argv, "hex")) {
30562306a36Sopenharmony_ci		base = 16;
30662306a36Sopenharmony_ci		argv++;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	while (i < n && argv[i]) {
31062306a36Sopenharmony_ci		val[i] = strtoul(argv[i], &endptr, base);
31162306a36Sopenharmony_ci		if (*endptr) {
31262306a36Sopenharmony_ci			p_err("error parsing byte: %s", argv[i]);
31362306a36Sopenharmony_ci			return NULL;
31462306a36Sopenharmony_ci		}
31562306a36Sopenharmony_ci		i++;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (i != n) {
31962306a36Sopenharmony_ci		p_err("%s expected %d bytes got %d", name, n, i);
32062306a36Sopenharmony_ci		return NULL;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return argv + i;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/* on per cpu maps we must copy the provided value on all value instances */
32762306a36Sopenharmony_cistatic void fill_per_cpu_value(struct bpf_map_info *info, void *value)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	unsigned int i, n, step;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (!map_is_per_cpu(info->type))
33262306a36Sopenharmony_ci		return;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	n = get_possible_cpus();
33562306a36Sopenharmony_ci	step = round_up(info->value_size, 8);
33662306a36Sopenharmony_ci	for (i = 1; i < n; i++)
33762306a36Sopenharmony_ci		memcpy(value + i * step, value, info->value_size);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int parse_elem(char **argv, struct bpf_map_info *info,
34162306a36Sopenharmony_ci		      void *key, void *value, __u32 key_size, __u32 value_size,
34262306a36Sopenharmony_ci		      __u32 *flags, __u32 **value_fd)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	if (!*argv) {
34562306a36Sopenharmony_ci		if (!key && !value)
34662306a36Sopenharmony_ci			return 0;
34762306a36Sopenharmony_ci		p_err("did not find %s", key ? "key" : "value");
34862306a36Sopenharmony_ci		return -1;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (is_prefix(*argv, "key")) {
35262306a36Sopenharmony_ci		if (!key) {
35362306a36Sopenharmony_ci			if (key_size)
35462306a36Sopenharmony_ci				p_err("duplicate key");
35562306a36Sopenharmony_ci			else
35662306a36Sopenharmony_ci				p_err("unnecessary key");
35762306a36Sopenharmony_ci			return -1;
35862306a36Sopenharmony_ci		}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		argv = parse_bytes(argv + 1, "key", key, key_size);
36162306a36Sopenharmony_ci		if (!argv)
36262306a36Sopenharmony_ci			return -1;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		return parse_elem(argv, info, NULL, value, key_size, value_size,
36562306a36Sopenharmony_ci				  flags, value_fd);
36662306a36Sopenharmony_ci	} else if (is_prefix(*argv, "value")) {
36762306a36Sopenharmony_ci		int fd;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		if (!value) {
37062306a36Sopenharmony_ci			if (value_size)
37162306a36Sopenharmony_ci				p_err("duplicate value");
37262306a36Sopenharmony_ci			else
37362306a36Sopenharmony_ci				p_err("unnecessary value");
37462306a36Sopenharmony_ci			return -1;
37562306a36Sopenharmony_ci		}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		argv++;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		if (map_is_map_of_maps(info->type)) {
38062306a36Sopenharmony_ci			int argc = 2;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci			if (value_size != 4) {
38362306a36Sopenharmony_ci				p_err("value smaller than 4B for map in map?");
38462306a36Sopenharmony_ci				return -1;
38562306a36Sopenharmony_ci			}
38662306a36Sopenharmony_ci			if (!argv[0] || !argv[1]) {
38762306a36Sopenharmony_ci				p_err("not enough value arguments for map in map");
38862306a36Sopenharmony_ci				return -1;
38962306a36Sopenharmony_ci			}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci			fd = map_parse_fd(&argc, &argv);
39262306a36Sopenharmony_ci			if (fd < 0)
39362306a36Sopenharmony_ci				return -1;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci			*value_fd = value;
39662306a36Sopenharmony_ci			**value_fd = fd;
39762306a36Sopenharmony_ci		} else if (map_is_map_of_progs(info->type)) {
39862306a36Sopenharmony_ci			int argc = 2;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci			if (value_size != 4) {
40162306a36Sopenharmony_ci				p_err("value smaller than 4B for map of progs?");
40262306a36Sopenharmony_ci				return -1;
40362306a36Sopenharmony_ci			}
40462306a36Sopenharmony_ci			if (!argv[0] || !argv[1]) {
40562306a36Sopenharmony_ci				p_err("not enough value arguments for map of progs");
40662306a36Sopenharmony_ci				return -1;
40762306a36Sopenharmony_ci			}
40862306a36Sopenharmony_ci			if (is_prefix(*argv, "id"))
40962306a36Sopenharmony_ci				p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
41062306a36Sopenharmony_ci				       "         by some process or pinned otherwise update will be lost");
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci			fd = prog_parse_fd(&argc, &argv);
41362306a36Sopenharmony_ci			if (fd < 0)
41462306a36Sopenharmony_ci				return -1;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci			*value_fd = value;
41762306a36Sopenharmony_ci			**value_fd = fd;
41862306a36Sopenharmony_ci		} else {
41962306a36Sopenharmony_ci			argv = parse_bytes(argv, "value", value, value_size);
42062306a36Sopenharmony_ci			if (!argv)
42162306a36Sopenharmony_ci				return -1;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci			fill_per_cpu_value(info, value);
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		return parse_elem(argv, info, key, NULL, key_size, value_size,
42762306a36Sopenharmony_ci				  flags, NULL);
42862306a36Sopenharmony_ci	} else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
42962306a36Sopenharmony_ci		   is_prefix(*argv, "exist")) {
43062306a36Sopenharmony_ci		if (!flags) {
43162306a36Sopenharmony_ci			p_err("flags specified multiple times: %s", *argv);
43262306a36Sopenharmony_ci			return -1;
43362306a36Sopenharmony_ci		}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		if (is_prefix(*argv, "any"))
43662306a36Sopenharmony_ci			*flags = BPF_ANY;
43762306a36Sopenharmony_ci		else if (is_prefix(*argv, "noexist"))
43862306a36Sopenharmony_ci			*flags = BPF_NOEXIST;
43962306a36Sopenharmony_ci		else if (is_prefix(*argv, "exist"))
44062306a36Sopenharmony_ci			*flags = BPF_EXIST;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		return parse_elem(argv + 1, info, key, value, key_size,
44362306a36Sopenharmony_ci				  value_size, NULL, value_fd);
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	p_err("expected key or value, got: %s", *argv);
44762306a36Sopenharmony_ci	return -1;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	const char *map_type_str;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	jsonw_uint_field(wtr, "id", info->id);
45562306a36Sopenharmony_ci	map_type_str = libbpf_bpf_map_type_str(info->type);
45662306a36Sopenharmony_ci	if (map_type_str)
45762306a36Sopenharmony_ci		jsonw_string_field(wtr, "type", map_type_str);
45862306a36Sopenharmony_ci	else
45962306a36Sopenharmony_ci		jsonw_uint_field(wtr, "type", info->type);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (*info->name)
46262306a36Sopenharmony_ci		jsonw_string_field(wtr, "name", info->name);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	jsonw_name(wtr, "flags");
46562306a36Sopenharmony_ci	jsonw_printf(wtr, "%d", info->map_flags);
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic int show_map_close_json(int fd, struct bpf_map_info *info)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	char *memlock, *frozen_str;
47162306a36Sopenharmony_ci	int frozen = 0;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	memlock = get_fdinfo(fd, "memlock");
47462306a36Sopenharmony_ci	frozen_str = get_fdinfo(fd, "frozen");
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	jsonw_start_object(json_wtr);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	show_map_header_json(info, json_wtr);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
48362306a36Sopenharmony_ci	jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
48462306a36Sopenharmony_ci	jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (memlock)
48762306a36Sopenharmony_ci		jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock));
48862306a36Sopenharmony_ci	free(memlock);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
49162306a36Sopenharmony_ci		char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
49262306a36Sopenharmony_ci		char *owner_jited = get_fdinfo(fd, "owner_jited");
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		if (owner_prog_type) {
49562306a36Sopenharmony_ci			unsigned int prog_type = atoi(owner_prog_type);
49662306a36Sopenharmony_ci			const char *prog_type_str;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci			prog_type_str = libbpf_bpf_prog_type_str(prog_type);
49962306a36Sopenharmony_ci			if (prog_type_str)
50062306a36Sopenharmony_ci				jsonw_string_field(json_wtr, "owner_prog_type",
50162306a36Sopenharmony_ci						   prog_type_str);
50262306a36Sopenharmony_ci			else
50362306a36Sopenharmony_ci				jsonw_uint_field(json_wtr, "owner_prog_type",
50462306a36Sopenharmony_ci						 prog_type);
50562306a36Sopenharmony_ci		}
50662306a36Sopenharmony_ci		if (owner_jited)
50762306a36Sopenharmony_ci			jsonw_bool_field(json_wtr, "owner_jited",
50862306a36Sopenharmony_ci					 !!atoi(owner_jited));
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		free(owner_prog_type);
51162306a36Sopenharmony_ci		free(owner_jited);
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci	close(fd);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (frozen_str) {
51662306a36Sopenharmony_ci		frozen = atoi(frozen_str);
51762306a36Sopenharmony_ci		free(frozen_str);
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci	jsonw_int_field(json_wtr, "frozen", frozen);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (info->btf_id)
52262306a36Sopenharmony_ci		jsonw_int_field(json_wtr, "btf_id", info->btf_id);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (!hashmap__empty(map_table)) {
52562306a36Sopenharmony_ci		struct hashmap_entry *entry;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		jsonw_name(json_wtr, "pinned");
52862306a36Sopenharmony_ci		jsonw_start_array(json_wtr);
52962306a36Sopenharmony_ci		hashmap__for_each_key_entry(map_table, entry, info->id)
53062306a36Sopenharmony_ci			jsonw_string(json_wtr, entry->pvalue);
53162306a36Sopenharmony_ci		jsonw_end_array(json_wtr);
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	emit_obj_refs_json(refs_table, info->id, json_wtr);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	jsonw_end_object(json_wtr);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic void show_map_header_plain(struct bpf_map_info *info)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	const char *map_type_str;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	printf("%u: ", info->id);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	map_type_str = libbpf_bpf_map_type_str(info->type);
54862306a36Sopenharmony_ci	if (map_type_str)
54962306a36Sopenharmony_ci		printf("%s  ", map_type_str);
55062306a36Sopenharmony_ci	else
55162306a36Sopenharmony_ci		printf("type %u  ", info->type);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (*info->name)
55462306a36Sopenharmony_ci		printf("name %s  ", info->name);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	printf("flags 0x%x", info->map_flags);
55762306a36Sopenharmony_ci	print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
55862306a36Sopenharmony_ci	printf("\n");
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic int show_map_close_plain(int fd, struct bpf_map_info *info)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	char *memlock, *frozen_str;
56462306a36Sopenharmony_ci	int frozen = 0;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	memlock = get_fdinfo(fd, "memlock");
56762306a36Sopenharmony_ci	frozen_str = get_fdinfo(fd, "frozen");
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	show_map_header_plain(info);
57062306a36Sopenharmony_ci	printf("\tkey %uB  value %uB  max_entries %u",
57162306a36Sopenharmony_ci	       info->key_size, info->value_size, info->max_entries);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (memlock)
57462306a36Sopenharmony_ci		printf("  memlock %sB", memlock);
57562306a36Sopenharmony_ci	free(memlock);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
57862306a36Sopenharmony_ci		char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
57962306a36Sopenharmony_ci		char *owner_jited = get_fdinfo(fd, "owner_jited");
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci		if (owner_prog_type || owner_jited)
58262306a36Sopenharmony_ci			printf("\n\t");
58362306a36Sopenharmony_ci		if (owner_prog_type) {
58462306a36Sopenharmony_ci			unsigned int prog_type = atoi(owner_prog_type);
58562306a36Sopenharmony_ci			const char *prog_type_str;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci			prog_type_str = libbpf_bpf_prog_type_str(prog_type);
58862306a36Sopenharmony_ci			if (prog_type_str)
58962306a36Sopenharmony_ci				printf("owner_prog_type %s  ", prog_type_str);
59062306a36Sopenharmony_ci			else
59162306a36Sopenharmony_ci				printf("owner_prog_type %d  ", prog_type);
59262306a36Sopenharmony_ci		}
59362306a36Sopenharmony_ci		if (owner_jited)
59462306a36Sopenharmony_ci			printf("owner%s jited",
59562306a36Sopenharmony_ci			       atoi(owner_jited) ? "" : " not");
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		free(owner_prog_type);
59862306a36Sopenharmony_ci		free(owner_jited);
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci	close(fd);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (!hashmap__empty(map_table)) {
60362306a36Sopenharmony_ci		struct hashmap_entry *entry;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		hashmap__for_each_key_entry(map_table, entry, info->id)
60662306a36Sopenharmony_ci			printf("\n\tpinned %s", (char *)entry->pvalue);
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (frozen_str) {
61062306a36Sopenharmony_ci		frozen = atoi(frozen_str);
61162306a36Sopenharmony_ci		free(frozen_str);
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (info->btf_id || frozen)
61562306a36Sopenharmony_ci		printf("\n\t");
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (info->btf_id)
61862306a36Sopenharmony_ci		printf("btf_id %d", info->btf_id);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (frozen)
62162306a36Sopenharmony_ci		printf("%sfrozen", info->btf_id ? "  " : "");
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	printf("\n");
62662306a36Sopenharmony_ci	return 0;
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic int do_show_subset(int argc, char **argv)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct bpf_map_info info = {};
63262306a36Sopenharmony_ci	__u32 len = sizeof(info);
63362306a36Sopenharmony_ci	int *fds = NULL;
63462306a36Sopenharmony_ci	int nb_fds, i;
63562306a36Sopenharmony_ci	int err = -1;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	fds = malloc(sizeof(int));
63862306a36Sopenharmony_ci	if (!fds) {
63962306a36Sopenharmony_ci		p_err("mem alloc failed");
64062306a36Sopenharmony_ci		return -1;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci	nb_fds = map_parse_fds(&argc, &argv, &fds);
64362306a36Sopenharmony_ci	if (nb_fds < 1)
64462306a36Sopenharmony_ci		goto exit_free;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	if (json_output && nb_fds > 1)
64762306a36Sopenharmony_ci		jsonw_start_array(json_wtr);	/* root array */
64862306a36Sopenharmony_ci	for (i = 0; i < nb_fds; i++) {
64962306a36Sopenharmony_ci		err = bpf_map_get_info_by_fd(fds[i], &info, &len);
65062306a36Sopenharmony_ci		if (err) {
65162306a36Sopenharmony_ci			p_err("can't get map info: %s",
65262306a36Sopenharmony_ci			      strerror(errno));
65362306a36Sopenharmony_ci			for (; i < nb_fds; i++)
65462306a36Sopenharmony_ci				close(fds[i]);
65562306a36Sopenharmony_ci			break;
65662306a36Sopenharmony_ci		}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		if (json_output)
65962306a36Sopenharmony_ci			show_map_close_json(fds[i], &info);
66062306a36Sopenharmony_ci		else
66162306a36Sopenharmony_ci			show_map_close_plain(fds[i], &info);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		close(fds[i]);
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci	if (json_output && nb_fds > 1)
66662306a36Sopenharmony_ci		jsonw_end_array(json_wtr);	/* root array */
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ciexit_free:
66962306a36Sopenharmony_ci	free(fds);
67062306a36Sopenharmony_ci	return err;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic int do_show(int argc, char **argv)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	struct bpf_map_info info = {};
67662306a36Sopenharmony_ci	__u32 len = sizeof(info);
67762306a36Sopenharmony_ci	__u32 id = 0;
67862306a36Sopenharmony_ci	int err;
67962306a36Sopenharmony_ci	int fd;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (show_pinned) {
68262306a36Sopenharmony_ci		map_table = hashmap__new(hash_fn_for_key_as_id,
68362306a36Sopenharmony_ci					 equal_fn_for_key_as_id, NULL);
68462306a36Sopenharmony_ci		if (IS_ERR(map_table)) {
68562306a36Sopenharmony_ci			p_err("failed to create hashmap for pinned paths");
68662306a36Sopenharmony_ci			return -1;
68762306a36Sopenharmony_ci		}
68862306a36Sopenharmony_ci		build_pinned_obj_table(map_table, BPF_OBJ_MAP);
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci	build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (argc == 2)
69362306a36Sopenharmony_ci		return do_show_subset(argc, argv);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (argc)
69662306a36Sopenharmony_ci		return BAD_ARG();
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (json_output)
69962306a36Sopenharmony_ci		jsonw_start_array(json_wtr);
70062306a36Sopenharmony_ci	while (true) {
70162306a36Sopenharmony_ci		err = bpf_map_get_next_id(id, &id);
70262306a36Sopenharmony_ci		if (err) {
70362306a36Sopenharmony_ci			if (errno == ENOENT)
70462306a36Sopenharmony_ci				break;
70562306a36Sopenharmony_ci			p_err("can't get next map: %s%s", strerror(errno),
70662306a36Sopenharmony_ci			      errno == EINVAL ? " -- kernel too old?" : "");
70762306a36Sopenharmony_ci			break;
70862306a36Sopenharmony_ci		}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		fd = bpf_map_get_fd_by_id(id);
71162306a36Sopenharmony_ci		if (fd < 0) {
71262306a36Sopenharmony_ci			if (errno == ENOENT)
71362306a36Sopenharmony_ci				continue;
71462306a36Sopenharmony_ci			p_err("can't get map by id (%u): %s",
71562306a36Sopenharmony_ci			      id, strerror(errno));
71662306a36Sopenharmony_ci			break;
71762306a36Sopenharmony_ci		}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci		err = bpf_map_get_info_by_fd(fd, &info, &len);
72062306a36Sopenharmony_ci		if (err) {
72162306a36Sopenharmony_ci			p_err("can't get map info: %s", strerror(errno));
72262306a36Sopenharmony_ci			close(fd);
72362306a36Sopenharmony_ci			break;
72462306a36Sopenharmony_ci		}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci		if (json_output)
72762306a36Sopenharmony_ci			show_map_close_json(fd, &info);
72862306a36Sopenharmony_ci		else
72962306a36Sopenharmony_ci			show_map_close_plain(fd, &info);
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci	if (json_output)
73262306a36Sopenharmony_ci		jsonw_end_array(json_wtr);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	delete_obj_refs_table(refs_table);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (show_pinned)
73762306a36Sopenharmony_ci		delete_pinned_obj_table(map_table);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	return errno == ENOENT ? 0 : -1;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic int dump_map_elem(int fd, void *key, void *value,
74362306a36Sopenharmony_ci			 struct bpf_map_info *map_info, struct btf *btf,
74462306a36Sopenharmony_ci			 json_writer_t *btf_wtr)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	if (bpf_map_lookup_elem(fd, key, value)) {
74762306a36Sopenharmony_ci		print_entry_error(map_info, key, errno);
74862306a36Sopenharmony_ci		return -1;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (json_output) {
75262306a36Sopenharmony_ci		print_entry_json(map_info, key, value, btf);
75362306a36Sopenharmony_ci	} else if (btf) {
75462306a36Sopenharmony_ci		struct btf_dumper d = {
75562306a36Sopenharmony_ci			.btf = btf,
75662306a36Sopenharmony_ci			.jw = btf_wtr,
75762306a36Sopenharmony_ci			.is_plain_text = true,
75862306a36Sopenharmony_ci		};
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		do_dump_btf(&d, map_info, key, value);
76162306a36Sopenharmony_ci	} else {
76262306a36Sopenharmony_ci		print_entry_plain(map_info, key, value);
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	return 0;
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic int maps_have_btf(int *fds, int nb_fds)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct bpf_map_info info = {};
77162306a36Sopenharmony_ci	__u32 len = sizeof(info);
77262306a36Sopenharmony_ci	int err, i;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	for (i = 0; i < nb_fds; i++) {
77562306a36Sopenharmony_ci		err = bpf_map_get_info_by_fd(fds[i], &info, &len);
77662306a36Sopenharmony_ci		if (err) {
77762306a36Sopenharmony_ci			p_err("can't get map info: %s", strerror(errno));
77862306a36Sopenharmony_ci			return -1;
77962306a36Sopenharmony_ci		}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci		if (!info.btf_id)
78262306a36Sopenharmony_ci			return 0;
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	return 1;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic struct btf *btf_vmlinux;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cistatic int get_map_kv_btf(const struct bpf_map_info *info, struct btf **btf)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	int err = 0;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if (info->btf_vmlinux_value_type_id) {
79562306a36Sopenharmony_ci		if (!btf_vmlinux) {
79662306a36Sopenharmony_ci			btf_vmlinux = libbpf_find_kernel_btf();
79762306a36Sopenharmony_ci			if (!btf_vmlinux) {
79862306a36Sopenharmony_ci				p_err("failed to get kernel btf");
79962306a36Sopenharmony_ci				return -errno;
80062306a36Sopenharmony_ci			}
80162306a36Sopenharmony_ci		}
80262306a36Sopenharmony_ci		*btf = btf_vmlinux;
80362306a36Sopenharmony_ci	} else if (info->btf_value_type_id) {
80462306a36Sopenharmony_ci		*btf = btf__load_from_kernel_by_id(info->btf_id);
80562306a36Sopenharmony_ci		if (!*btf) {
80662306a36Sopenharmony_ci			err = -errno;
80762306a36Sopenharmony_ci			p_err("failed to get btf");
80862306a36Sopenharmony_ci		}
80962306a36Sopenharmony_ci	} else {
81062306a36Sopenharmony_ci		*btf = NULL;
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return err;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cistatic void free_map_kv_btf(struct btf *btf)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	if (btf != btf_vmlinux)
81962306a36Sopenharmony_ci		btf__free(btf);
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int
82362306a36Sopenharmony_cimap_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
82462306a36Sopenharmony_ci	 bool show_header)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	void *key, *value, *prev_key;
82762306a36Sopenharmony_ci	unsigned int num_elems = 0;
82862306a36Sopenharmony_ci	struct btf *btf = NULL;
82962306a36Sopenharmony_ci	int err;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	key = malloc(info->key_size);
83262306a36Sopenharmony_ci	value = alloc_value(info);
83362306a36Sopenharmony_ci	if (!key || !value) {
83462306a36Sopenharmony_ci		p_err("mem alloc failed");
83562306a36Sopenharmony_ci		err = -1;
83662306a36Sopenharmony_ci		goto exit_free;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	prev_key = NULL;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	if (wtr) {
84262306a36Sopenharmony_ci		err = get_map_kv_btf(info, &btf);
84362306a36Sopenharmony_ci		if (err) {
84462306a36Sopenharmony_ci			goto exit_free;
84562306a36Sopenharmony_ci		}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		if (show_header) {
84862306a36Sopenharmony_ci			jsonw_start_object(wtr);	/* map object */
84962306a36Sopenharmony_ci			show_map_header_json(info, wtr);
85062306a36Sopenharmony_ci			jsonw_name(wtr, "elements");
85162306a36Sopenharmony_ci		}
85262306a36Sopenharmony_ci		jsonw_start_array(wtr);		/* elements */
85362306a36Sopenharmony_ci	} else if (show_header) {
85462306a36Sopenharmony_ci		show_map_header_plain(info);
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
85862306a36Sopenharmony_ci	    info->value_size != 8) {
85962306a36Sopenharmony_ci		const char *map_type_str;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		map_type_str = libbpf_bpf_map_type_str(info->type);
86262306a36Sopenharmony_ci		p_info("Warning: cannot read values from %s map with value_size != 8",
86362306a36Sopenharmony_ci		       map_type_str);
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci	while (true) {
86662306a36Sopenharmony_ci		err = bpf_map_get_next_key(fd, prev_key, key);
86762306a36Sopenharmony_ci		if (err) {
86862306a36Sopenharmony_ci			if (errno == ENOENT)
86962306a36Sopenharmony_ci				err = 0;
87062306a36Sopenharmony_ci			break;
87162306a36Sopenharmony_ci		}
87262306a36Sopenharmony_ci		if (!dump_map_elem(fd, key, value, info, btf, wtr))
87362306a36Sopenharmony_ci			num_elems++;
87462306a36Sopenharmony_ci		prev_key = key;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	if (wtr) {
87862306a36Sopenharmony_ci		jsonw_end_array(wtr);	/* elements */
87962306a36Sopenharmony_ci		if (show_header)
88062306a36Sopenharmony_ci			jsonw_end_object(wtr);	/* map object */
88162306a36Sopenharmony_ci	} else {
88262306a36Sopenharmony_ci		printf("Found %u element%s\n", num_elems,
88362306a36Sopenharmony_ci		       num_elems != 1 ? "s" : "");
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ciexit_free:
88762306a36Sopenharmony_ci	free(key);
88862306a36Sopenharmony_ci	free(value);
88962306a36Sopenharmony_ci	close(fd);
89062306a36Sopenharmony_ci	free_map_kv_btf(btf);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	return err;
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic int do_dump(int argc, char **argv)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	json_writer_t *wtr = NULL, *btf_wtr = NULL;
89862306a36Sopenharmony_ci	struct bpf_map_info info = {};
89962306a36Sopenharmony_ci	int nb_fds, i = 0;
90062306a36Sopenharmony_ci	__u32 len = sizeof(info);
90162306a36Sopenharmony_ci	int *fds = NULL;
90262306a36Sopenharmony_ci	int err = -1;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (argc != 2)
90562306a36Sopenharmony_ci		usage();
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	fds = malloc(sizeof(int));
90862306a36Sopenharmony_ci	if (!fds) {
90962306a36Sopenharmony_ci		p_err("mem alloc failed");
91062306a36Sopenharmony_ci		return -1;
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci	nb_fds = map_parse_fds(&argc, &argv, &fds);
91362306a36Sopenharmony_ci	if (nb_fds < 1)
91462306a36Sopenharmony_ci		goto exit_free;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	if (json_output) {
91762306a36Sopenharmony_ci		wtr = json_wtr;
91862306a36Sopenharmony_ci	} else {
91962306a36Sopenharmony_ci		int do_plain_btf;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci		do_plain_btf = maps_have_btf(fds, nb_fds);
92262306a36Sopenharmony_ci		if (do_plain_btf < 0)
92362306a36Sopenharmony_ci			goto exit_close;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci		if (do_plain_btf) {
92662306a36Sopenharmony_ci			btf_wtr = get_btf_writer();
92762306a36Sopenharmony_ci			wtr = btf_wtr;
92862306a36Sopenharmony_ci			if (!btf_wtr)
92962306a36Sopenharmony_ci				p_info("failed to create json writer for btf. falling back to plain output");
93062306a36Sopenharmony_ci		}
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	if (wtr && nb_fds > 1)
93462306a36Sopenharmony_ci		jsonw_start_array(wtr);	/* root array */
93562306a36Sopenharmony_ci	for (i = 0; i < nb_fds; i++) {
93662306a36Sopenharmony_ci		if (bpf_map_get_info_by_fd(fds[i], &info, &len)) {
93762306a36Sopenharmony_ci			p_err("can't get map info: %s", strerror(errno));
93862306a36Sopenharmony_ci			break;
93962306a36Sopenharmony_ci		}
94062306a36Sopenharmony_ci		err = map_dump(fds[i], &info, wtr, nb_fds > 1);
94162306a36Sopenharmony_ci		if (!wtr && i != nb_fds - 1)
94262306a36Sopenharmony_ci			printf("\n");
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		if (err)
94562306a36Sopenharmony_ci			break;
94662306a36Sopenharmony_ci		close(fds[i]);
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci	if (wtr && nb_fds > 1)
94962306a36Sopenharmony_ci		jsonw_end_array(wtr);	/* root array */
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (btf_wtr)
95262306a36Sopenharmony_ci		jsonw_destroy(&btf_wtr);
95362306a36Sopenharmony_ciexit_close:
95462306a36Sopenharmony_ci	for (; i < nb_fds; i++)
95562306a36Sopenharmony_ci		close(fds[i]);
95662306a36Sopenharmony_ciexit_free:
95762306a36Sopenharmony_ci	free(fds);
95862306a36Sopenharmony_ci	btf__free(btf_vmlinux);
95962306a36Sopenharmony_ci	return err;
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	*key = NULL;
96562306a36Sopenharmony_ci	*value = NULL;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	if (info->key_size) {
96862306a36Sopenharmony_ci		*key = malloc(info->key_size);
96962306a36Sopenharmony_ci		if (!*key) {
97062306a36Sopenharmony_ci			p_err("key mem alloc failed");
97162306a36Sopenharmony_ci			return -1;
97262306a36Sopenharmony_ci		}
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (info->value_size) {
97662306a36Sopenharmony_ci		*value = alloc_value(info);
97762306a36Sopenharmony_ci		if (!*value) {
97862306a36Sopenharmony_ci			p_err("value mem alloc failed");
97962306a36Sopenharmony_ci			free(*key);
98062306a36Sopenharmony_ci			*key = NULL;
98162306a36Sopenharmony_ci			return -1;
98262306a36Sopenharmony_ci		}
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	return 0;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cistatic int do_update(int argc, char **argv)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	struct bpf_map_info info = {};
99162306a36Sopenharmony_ci	__u32 len = sizeof(info);
99262306a36Sopenharmony_ci	__u32 *value_fd = NULL;
99362306a36Sopenharmony_ci	__u32 flags = BPF_ANY;
99462306a36Sopenharmony_ci	void *key, *value;
99562306a36Sopenharmony_ci	int fd, err;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (argc < 2)
99862306a36Sopenharmony_ci		usage();
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
100162306a36Sopenharmony_ci	if (fd < 0)
100262306a36Sopenharmony_ci		return -1;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	err = alloc_key_value(&info, &key, &value);
100562306a36Sopenharmony_ci	if (err)
100662306a36Sopenharmony_ci		goto exit_free;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	err = parse_elem(argv, &info, key, value, info.key_size,
100962306a36Sopenharmony_ci			 info.value_size, &flags, &value_fd);
101062306a36Sopenharmony_ci	if (err)
101162306a36Sopenharmony_ci		goto exit_free;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	err = bpf_map_update_elem(fd, key, value, flags);
101462306a36Sopenharmony_ci	if (err) {
101562306a36Sopenharmony_ci		p_err("update failed: %s", strerror(errno));
101662306a36Sopenharmony_ci		goto exit_free;
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ciexit_free:
102062306a36Sopenharmony_ci	if (value_fd)
102162306a36Sopenharmony_ci		close(*value_fd);
102262306a36Sopenharmony_ci	free(key);
102362306a36Sopenharmony_ci	free(value);
102462306a36Sopenharmony_ci	close(fd);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	if (!err && json_output)
102762306a36Sopenharmony_ci		jsonw_null(json_wtr);
102862306a36Sopenharmony_ci	return err;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic void print_key_value(struct bpf_map_info *info, void *key,
103262306a36Sopenharmony_ci			    void *value)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci	json_writer_t *btf_wtr;
103562306a36Sopenharmony_ci	struct btf *btf;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (get_map_kv_btf(info, &btf))
103862306a36Sopenharmony_ci		return;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (json_output) {
104162306a36Sopenharmony_ci		print_entry_json(info, key, value, btf);
104262306a36Sopenharmony_ci	} else if (btf) {
104362306a36Sopenharmony_ci		/* if here json_wtr wouldn't have been initialised,
104462306a36Sopenharmony_ci		 * so let's create separate writer for btf
104562306a36Sopenharmony_ci		 */
104662306a36Sopenharmony_ci		btf_wtr = get_btf_writer();
104762306a36Sopenharmony_ci		if (!btf_wtr) {
104862306a36Sopenharmony_ci			p_info("failed to create json writer for btf. falling back to plain output");
104962306a36Sopenharmony_ci			btf__free(btf);
105062306a36Sopenharmony_ci			btf = NULL;
105162306a36Sopenharmony_ci			print_entry_plain(info, key, value);
105262306a36Sopenharmony_ci		} else {
105362306a36Sopenharmony_ci			struct btf_dumper d = {
105462306a36Sopenharmony_ci				.btf = btf,
105562306a36Sopenharmony_ci				.jw = btf_wtr,
105662306a36Sopenharmony_ci				.is_plain_text = true,
105762306a36Sopenharmony_ci			};
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci			do_dump_btf(&d, info, key, value);
106062306a36Sopenharmony_ci			jsonw_destroy(&btf_wtr);
106162306a36Sopenharmony_ci		}
106262306a36Sopenharmony_ci	} else {
106362306a36Sopenharmony_ci		print_entry_plain(info, key, value);
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci	btf__free(btf);
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic int do_lookup(int argc, char **argv)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	struct bpf_map_info info = {};
107162306a36Sopenharmony_ci	__u32 len = sizeof(info);
107262306a36Sopenharmony_ci	void *key, *value;
107362306a36Sopenharmony_ci	int err;
107462306a36Sopenharmony_ci	int fd;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (argc < 2)
107762306a36Sopenharmony_ci		usage();
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
108062306a36Sopenharmony_ci	if (fd < 0)
108162306a36Sopenharmony_ci		return -1;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	err = alloc_key_value(&info, &key, &value);
108462306a36Sopenharmony_ci	if (err)
108562306a36Sopenharmony_ci		goto exit_free;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
108862306a36Sopenharmony_ci	if (err)
108962306a36Sopenharmony_ci		goto exit_free;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	err = bpf_map_lookup_elem(fd, key, value);
109262306a36Sopenharmony_ci	if (err) {
109362306a36Sopenharmony_ci		if (errno == ENOENT) {
109462306a36Sopenharmony_ci			if (json_output) {
109562306a36Sopenharmony_ci				jsonw_null(json_wtr);
109662306a36Sopenharmony_ci			} else {
109762306a36Sopenharmony_ci				printf("key:\n");
109862306a36Sopenharmony_ci				fprint_hex(stdout, key, info.key_size, " ");
109962306a36Sopenharmony_ci				printf("\n\nNot found\n");
110062306a36Sopenharmony_ci			}
110162306a36Sopenharmony_ci		} else {
110262306a36Sopenharmony_ci			p_err("lookup failed: %s", strerror(errno));
110362306a36Sopenharmony_ci		}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci		goto exit_free;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/* here means bpf_map_lookup_elem() succeeded */
110962306a36Sopenharmony_ci	print_key_value(&info, key, value);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ciexit_free:
111262306a36Sopenharmony_ci	free(key);
111362306a36Sopenharmony_ci	free(value);
111462306a36Sopenharmony_ci	close(fd);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return err;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic int do_getnext(int argc, char **argv)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	struct bpf_map_info info = {};
112262306a36Sopenharmony_ci	__u32 len = sizeof(info);
112362306a36Sopenharmony_ci	void *key, *nextkey;
112462306a36Sopenharmony_ci	int err;
112562306a36Sopenharmony_ci	int fd;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	if (argc < 2)
112862306a36Sopenharmony_ci		usage();
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
113162306a36Sopenharmony_ci	if (fd < 0)
113262306a36Sopenharmony_ci		return -1;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	key = malloc(info.key_size);
113562306a36Sopenharmony_ci	nextkey = malloc(info.key_size);
113662306a36Sopenharmony_ci	if (!key || !nextkey) {
113762306a36Sopenharmony_ci		p_err("mem alloc failed");
113862306a36Sopenharmony_ci		err = -1;
113962306a36Sopenharmony_ci		goto exit_free;
114062306a36Sopenharmony_ci	}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	if (argc) {
114362306a36Sopenharmony_ci		err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
114462306a36Sopenharmony_ci				 NULL, NULL);
114562306a36Sopenharmony_ci		if (err)
114662306a36Sopenharmony_ci			goto exit_free;
114762306a36Sopenharmony_ci	} else {
114862306a36Sopenharmony_ci		free(key);
114962306a36Sopenharmony_ci		key = NULL;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	err = bpf_map_get_next_key(fd, key, nextkey);
115362306a36Sopenharmony_ci	if (err) {
115462306a36Sopenharmony_ci		p_err("can't get next key: %s", strerror(errno));
115562306a36Sopenharmony_ci		goto exit_free;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (json_output) {
115962306a36Sopenharmony_ci		jsonw_start_object(json_wtr);
116062306a36Sopenharmony_ci		if (key) {
116162306a36Sopenharmony_ci			jsonw_name(json_wtr, "key");
116262306a36Sopenharmony_ci			print_hex_data_json(key, info.key_size);
116362306a36Sopenharmony_ci		} else {
116462306a36Sopenharmony_ci			jsonw_null_field(json_wtr, "key");
116562306a36Sopenharmony_ci		}
116662306a36Sopenharmony_ci		jsonw_name(json_wtr, "next_key");
116762306a36Sopenharmony_ci		print_hex_data_json(nextkey, info.key_size);
116862306a36Sopenharmony_ci		jsonw_end_object(json_wtr);
116962306a36Sopenharmony_ci	} else {
117062306a36Sopenharmony_ci		if (key) {
117162306a36Sopenharmony_ci			printf("key:\n");
117262306a36Sopenharmony_ci			fprint_hex(stdout, key, info.key_size, " ");
117362306a36Sopenharmony_ci			printf("\n");
117462306a36Sopenharmony_ci		} else {
117562306a36Sopenharmony_ci			printf("key: None\n");
117662306a36Sopenharmony_ci		}
117762306a36Sopenharmony_ci		printf("next key:\n");
117862306a36Sopenharmony_ci		fprint_hex(stdout, nextkey, info.key_size, " ");
117962306a36Sopenharmony_ci		printf("\n");
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ciexit_free:
118362306a36Sopenharmony_ci	free(nextkey);
118462306a36Sopenharmony_ci	free(key);
118562306a36Sopenharmony_ci	close(fd);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	return err;
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic int do_delete(int argc, char **argv)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	struct bpf_map_info info = {};
119362306a36Sopenharmony_ci	__u32 len = sizeof(info);
119462306a36Sopenharmony_ci	void *key;
119562306a36Sopenharmony_ci	int err;
119662306a36Sopenharmony_ci	int fd;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	if (argc < 2)
119962306a36Sopenharmony_ci		usage();
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
120262306a36Sopenharmony_ci	if (fd < 0)
120362306a36Sopenharmony_ci		return -1;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	key = malloc(info.key_size);
120662306a36Sopenharmony_ci	if (!key) {
120762306a36Sopenharmony_ci		p_err("mem alloc failed");
120862306a36Sopenharmony_ci		err = -1;
120962306a36Sopenharmony_ci		goto exit_free;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
121362306a36Sopenharmony_ci	if (err)
121462306a36Sopenharmony_ci		goto exit_free;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	err = bpf_map_delete_elem(fd, key);
121762306a36Sopenharmony_ci	if (err)
121862306a36Sopenharmony_ci		p_err("delete failed: %s", strerror(errno));
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ciexit_free:
122162306a36Sopenharmony_ci	free(key);
122262306a36Sopenharmony_ci	close(fd);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if (!err && json_output)
122562306a36Sopenharmony_ci		jsonw_null(json_wtr);
122662306a36Sopenharmony_ci	return err;
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cistatic int do_pin(int argc, char **argv)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	int err;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	err = do_pin_any(argc, argv, map_parse_fd);
123462306a36Sopenharmony_ci	if (!err && json_output)
123562306a36Sopenharmony_ci		jsonw_null(json_wtr);
123662306a36Sopenharmony_ci	return err;
123762306a36Sopenharmony_ci}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_cistatic int do_create(int argc, char **argv)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	LIBBPF_OPTS(bpf_map_create_opts, attr);
124262306a36Sopenharmony_ci	enum bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
124362306a36Sopenharmony_ci	__u32 key_size = 0, value_size = 0, max_entries = 0;
124462306a36Sopenharmony_ci	const char *map_name = NULL;
124562306a36Sopenharmony_ci	const char *pinfile;
124662306a36Sopenharmony_ci	int err = -1, fd;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	if (!REQ_ARGS(7))
124962306a36Sopenharmony_ci		return -1;
125062306a36Sopenharmony_ci	pinfile = GET_ARG();
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	while (argc) {
125362306a36Sopenharmony_ci		if (!REQ_ARGS(2))
125462306a36Sopenharmony_ci			return -1;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci		if (is_prefix(*argv, "type")) {
125762306a36Sopenharmony_ci			NEXT_ARG();
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci			if (map_type) {
126062306a36Sopenharmony_ci				p_err("map type already specified");
126162306a36Sopenharmony_ci				goto exit;
126262306a36Sopenharmony_ci			}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci			map_type = map_type_from_str(*argv);
126562306a36Sopenharmony_ci			if ((int)map_type < 0) {
126662306a36Sopenharmony_ci				p_err("unrecognized map type: %s", *argv);
126762306a36Sopenharmony_ci				goto exit;
126862306a36Sopenharmony_ci			}
126962306a36Sopenharmony_ci			NEXT_ARG();
127062306a36Sopenharmony_ci		} else if (is_prefix(*argv, "name")) {
127162306a36Sopenharmony_ci			NEXT_ARG();
127262306a36Sopenharmony_ci			map_name = GET_ARG();
127362306a36Sopenharmony_ci		} else if (is_prefix(*argv, "key")) {
127462306a36Sopenharmony_ci			if (parse_u32_arg(&argc, &argv, &key_size,
127562306a36Sopenharmony_ci					  "key size"))
127662306a36Sopenharmony_ci				goto exit;
127762306a36Sopenharmony_ci		} else if (is_prefix(*argv, "value")) {
127862306a36Sopenharmony_ci			if (parse_u32_arg(&argc, &argv, &value_size,
127962306a36Sopenharmony_ci					  "value size"))
128062306a36Sopenharmony_ci				goto exit;
128162306a36Sopenharmony_ci		} else if (is_prefix(*argv, "entries")) {
128262306a36Sopenharmony_ci			if (parse_u32_arg(&argc, &argv, &max_entries,
128362306a36Sopenharmony_ci					  "max entries"))
128462306a36Sopenharmony_ci				goto exit;
128562306a36Sopenharmony_ci		} else if (is_prefix(*argv, "flags")) {
128662306a36Sopenharmony_ci			if (parse_u32_arg(&argc, &argv, &attr.map_flags,
128762306a36Sopenharmony_ci					  "flags"))
128862306a36Sopenharmony_ci				goto exit;
128962306a36Sopenharmony_ci		} else if (is_prefix(*argv, "dev")) {
129062306a36Sopenharmony_ci			p_info("Warning: 'bpftool map create [...] dev <ifname>' syntax is deprecated.\n"
129162306a36Sopenharmony_ci			       "Going further, please use 'offload_dev <ifname>' to request hardware offload for the map.");
129262306a36Sopenharmony_ci			goto offload_dev;
129362306a36Sopenharmony_ci		} else if (is_prefix(*argv, "offload_dev")) {
129462306a36Sopenharmony_cioffload_dev:
129562306a36Sopenharmony_ci			NEXT_ARG();
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci			if (attr.map_ifindex) {
129862306a36Sopenharmony_ci				p_err("offload device already specified");
129962306a36Sopenharmony_ci				goto exit;
130062306a36Sopenharmony_ci			}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci			attr.map_ifindex = if_nametoindex(*argv);
130362306a36Sopenharmony_ci			if (!attr.map_ifindex) {
130462306a36Sopenharmony_ci				p_err("unrecognized netdevice '%s': %s",
130562306a36Sopenharmony_ci				      *argv, strerror(errno));
130662306a36Sopenharmony_ci				goto exit;
130762306a36Sopenharmony_ci			}
130862306a36Sopenharmony_ci			NEXT_ARG();
130962306a36Sopenharmony_ci		} else if (is_prefix(*argv, "inner_map")) {
131062306a36Sopenharmony_ci			struct bpf_map_info info = {};
131162306a36Sopenharmony_ci			__u32 len = sizeof(info);
131262306a36Sopenharmony_ci			int inner_map_fd;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci			NEXT_ARG();
131562306a36Sopenharmony_ci			if (!REQ_ARGS(2))
131662306a36Sopenharmony_ci				usage();
131762306a36Sopenharmony_ci			inner_map_fd = map_parse_fd_and_info(&argc, &argv,
131862306a36Sopenharmony_ci							     &info, &len);
131962306a36Sopenharmony_ci			if (inner_map_fd < 0)
132062306a36Sopenharmony_ci				return -1;
132162306a36Sopenharmony_ci			attr.inner_map_fd = inner_map_fd;
132262306a36Sopenharmony_ci		} else {
132362306a36Sopenharmony_ci			p_err("unknown arg %s", *argv);
132462306a36Sopenharmony_ci			goto exit;
132562306a36Sopenharmony_ci		}
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (!map_name) {
132962306a36Sopenharmony_ci		p_err("map name not specified");
133062306a36Sopenharmony_ci		goto exit;
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	set_max_rlimit();
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	fd = bpf_map_create(map_type, map_name, key_size, value_size, max_entries, &attr);
133662306a36Sopenharmony_ci	if (fd < 0) {
133762306a36Sopenharmony_ci		p_err("map create failed: %s", strerror(errno));
133862306a36Sopenharmony_ci		goto exit;
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	err = do_pin_fd(fd, pinfile);
134262306a36Sopenharmony_ci	close(fd);
134362306a36Sopenharmony_ci	if (err)
134462306a36Sopenharmony_ci		goto exit;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (json_output)
134762306a36Sopenharmony_ci		jsonw_null(json_wtr);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ciexit:
135062306a36Sopenharmony_ci	if (attr.inner_map_fd > 0)
135162306a36Sopenharmony_ci		close(attr.inner_map_fd);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	return err;
135462306a36Sopenharmony_ci}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_cistatic int do_pop_dequeue(int argc, char **argv)
135762306a36Sopenharmony_ci{
135862306a36Sopenharmony_ci	struct bpf_map_info info = {};
135962306a36Sopenharmony_ci	__u32 len = sizeof(info);
136062306a36Sopenharmony_ci	void *key, *value;
136162306a36Sopenharmony_ci	int err;
136262306a36Sopenharmony_ci	int fd;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	if (argc < 2)
136562306a36Sopenharmony_ci		usage();
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
136862306a36Sopenharmony_ci	if (fd < 0)
136962306a36Sopenharmony_ci		return -1;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	err = alloc_key_value(&info, &key, &value);
137262306a36Sopenharmony_ci	if (err)
137362306a36Sopenharmony_ci		goto exit_free;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	err = bpf_map_lookup_and_delete_elem(fd, key, value);
137662306a36Sopenharmony_ci	if (err) {
137762306a36Sopenharmony_ci		if (errno == ENOENT) {
137862306a36Sopenharmony_ci			if (json_output)
137962306a36Sopenharmony_ci				jsonw_null(json_wtr);
138062306a36Sopenharmony_ci			else
138162306a36Sopenharmony_ci				printf("Error: empty map\n");
138262306a36Sopenharmony_ci		} else {
138362306a36Sopenharmony_ci			p_err("pop failed: %s", strerror(errno));
138462306a36Sopenharmony_ci		}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci		goto exit_free;
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	print_key_value(&info, key, value);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ciexit_free:
139262306a36Sopenharmony_ci	free(key);
139362306a36Sopenharmony_ci	free(value);
139462306a36Sopenharmony_ci	close(fd);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	return err;
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_cistatic int do_freeze(int argc, char **argv)
140062306a36Sopenharmony_ci{
140162306a36Sopenharmony_ci	int err, fd;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	if (!REQ_ARGS(2))
140462306a36Sopenharmony_ci		return -1;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	fd = map_parse_fd(&argc, &argv);
140762306a36Sopenharmony_ci	if (fd < 0)
140862306a36Sopenharmony_ci		return -1;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	if (argc) {
141162306a36Sopenharmony_ci		close(fd);
141262306a36Sopenharmony_ci		return BAD_ARG();
141362306a36Sopenharmony_ci	}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	err = bpf_map_freeze(fd);
141662306a36Sopenharmony_ci	close(fd);
141762306a36Sopenharmony_ci	if (err) {
141862306a36Sopenharmony_ci		p_err("failed to freeze map: %s", strerror(errno));
141962306a36Sopenharmony_ci		return err;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	if (json_output)
142362306a36Sopenharmony_ci		jsonw_null(json_wtr);
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	return 0;
142662306a36Sopenharmony_ci}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cistatic int do_help(int argc, char **argv)
142962306a36Sopenharmony_ci{
143062306a36Sopenharmony_ci	if (json_output) {
143162306a36Sopenharmony_ci		jsonw_null(json_wtr);
143262306a36Sopenharmony_ci		return 0;
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	fprintf(stderr,
143662306a36Sopenharmony_ci		"Usage: %1$s %2$s { show | list }   [MAP]\n"
143762306a36Sopenharmony_ci		"       %1$s %2$s create     FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
143862306a36Sopenharmony_ci		"                                  entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
143962306a36Sopenharmony_ci		"                                  [inner_map MAP] [offload_dev NAME]\n"
144062306a36Sopenharmony_ci		"       %1$s %2$s dump       MAP\n"
144162306a36Sopenharmony_ci		"       %1$s %2$s update     MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
144262306a36Sopenharmony_ci		"       %1$s %2$s lookup     MAP [key DATA]\n"
144362306a36Sopenharmony_ci		"       %1$s %2$s getnext    MAP [key DATA]\n"
144462306a36Sopenharmony_ci		"       %1$s %2$s delete     MAP  key DATA\n"
144562306a36Sopenharmony_ci		"       %1$s %2$s pin        MAP  FILE\n"
144662306a36Sopenharmony_ci		"       %1$s %2$s event_pipe MAP [cpu N index M]\n"
144762306a36Sopenharmony_ci		"       %1$s %2$s peek       MAP\n"
144862306a36Sopenharmony_ci		"       %1$s %2$s push       MAP value VALUE\n"
144962306a36Sopenharmony_ci		"       %1$s %2$s pop        MAP\n"
145062306a36Sopenharmony_ci		"       %1$s %2$s enqueue    MAP value VALUE\n"
145162306a36Sopenharmony_ci		"       %1$s %2$s dequeue    MAP\n"
145262306a36Sopenharmony_ci		"       %1$s %2$s freeze     MAP\n"
145362306a36Sopenharmony_ci		"       %1$s %2$s help\n"
145462306a36Sopenharmony_ci		"\n"
145562306a36Sopenharmony_ci		"       " HELP_SPEC_MAP "\n"
145662306a36Sopenharmony_ci		"       DATA := { [hex] BYTES }\n"
145762306a36Sopenharmony_ci		"       " HELP_SPEC_PROGRAM "\n"
145862306a36Sopenharmony_ci		"       VALUE := { DATA | MAP | PROG }\n"
145962306a36Sopenharmony_ci		"       UPDATE_FLAGS := { any | exist | noexist }\n"
146062306a36Sopenharmony_ci		"       TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
146162306a36Sopenharmony_ci		"                 percpu_array | stack_trace | cgroup_array | lru_hash |\n"
146262306a36Sopenharmony_ci		"                 lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
146362306a36Sopenharmony_ci		"                 devmap | devmap_hash | sockmap | cpumap | xskmap | sockhash |\n"
146462306a36Sopenharmony_ci		"                 cgroup_storage | reuseport_sockarray | percpu_cgroup_storage |\n"
146562306a36Sopenharmony_ci		"                 queue | stack | sk_storage | struct_ops | ringbuf | inode_storage |\n"
146662306a36Sopenharmony_ci		"                 task_storage | bloom_filter | user_ringbuf | cgrp_storage }\n"
146762306a36Sopenharmony_ci		"       " HELP_SPEC_OPTIONS " |\n"
146862306a36Sopenharmony_ci		"                    {-f|--bpffs} | {-n|--nomount} }\n"
146962306a36Sopenharmony_ci		"",
147062306a36Sopenharmony_ci		bin_name, argv[-2]);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	return 0;
147362306a36Sopenharmony_ci}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cistatic const struct cmd cmds[] = {
147662306a36Sopenharmony_ci	{ "show",	do_show },
147762306a36Sopenharmony_ci	{ "list",	do_show },
147862306a36Sopenharmony_ci	{ "help",	do_help },
147962306a36Sopenharmony_ci	{ "dump",	do_dump },
148062306a36Sopenharmony_ci	{ "update",	do_update },
148162306a36Sopenharmony_ci	{ "lookup",	do_lookup },
148262306a36Sopenharmony_ci	{ "getnext",	do_getnext },
148362306a36Sopenharmony_ci	{ "delete",	do_delete },
148462306a36Sopenharmony_ci	{ "pin",	do_pin },
148562306a36Sopenharmony_ci	{ "event_pipe",	do_event_pipe },
148662306a36Sopenharmony_ci	{ "create",	do_create },
148762306a36Sopenharmony_ci	{ "peek",	do_lookup },
148862306a36Sopenharmony_ci	{ "push",	do_update },
148962306a36Sopenharmony_ci	{ "enqueue",	do_update },
149062306a36Sopenharmony_ci	{ "pop",	do_pop_dequeue },
149162306a36Sopenharmony_ci	{ "dequeue",	do_pop_dequeue },
149262306a36Sopenharmony_ci	{ "freeze",	do_freeze },
149362306a36Sopenharmony_ci	{ 0 }
149462306a36Sopenharmony_ci};
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ciint do_map(int argc, char **argv)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	return cmd_select(cmds, argc, argv, do_help);
149962306a36Sopenharmony_ci}
1500