102ff58dcSJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
202ff58dcSJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
371bb428fSJakub Kicinski
471bb428fSJakub Kicinski #include <errno.h>
571bb428fSJakub Kicinski #include <fcntl.h>
62d3feca8SOkash Khawaja #include <linux/err.h>
7573b3aa6SYonghong Song #include <linux/kernel.h>
80b592b5aSJakub Kicinski #include <net/if.h>
971bb428fSJakub Kicinski #include <stdbool.h>
1071bb428fSJakub Kicinski #include <stdio.h>
1171bb428fSJakub Kicinski #include <stdlib.h>
1271bb428fSJakub Kicinski #include <string.h>
1371bb428fSJakub Kicinski #include <unistd.h>
1471bb428fSJakub Kicinski #include <sys/types.h>
1571bb428fSJakub Kicinski #include <sys/stat.h>
1671bb428fSJakub Kicinski
17229c3b47SToke Høiland-Jørgensen #include <bpf/bpf.h>
18229c3b47SToke Høiland-Jørgensen #include <bpf/btf.h>
198f184732SQuentin Monnet #include <bpf/hashmap.h>
2071bb428fSJakub Kicinski
212d3feca8SOkash Khawaja #include "json_writer.h"
2271bb428fSJakub Kicinski #include "main.h"
2371bb428fSJakub Kicinski
248f184732SQuentin Monnet static struct hashmap *map_table;
2546241271SQuentin Monnet
map_is_per_cpu(__u32 type)2671bb428fSJakub Kicinski static bool map_is_per_cpu(__u32 type)
2771bb428fSJakub Kicinski {
2871bb428fSJakub Kicinski return type == BPF_MAP_TYPE_PERCPU_HASH ||
2971bb428fSJakub Kicinski type == BPF_MAP_TYPE_PERCPU_ARRAY ||
30e5487092SRoman Gushchin type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
31e5487092SRoman Gushchin type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
3271bb428fSJakub Kicinski }
3371bb428fSJakub Kicinski
map_is_map_of_maps(__u32 type)3471bb428fSJakub Kicinski static bool map_is_map_of_maps(__u32 type)
3571bb428fSJakub Kicinski {
3671bb428fSJakub Kicinski return type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
3771bb428fSJakub Kicinski type == BPF_MAP_TYPE_HASH_OF_MAPS;
3871bb428fSJakub Kicinski }
3971bb428fSJakub Kicinski
map_is_map_of_progs(__u32 type)4071bb428fSJakub Kicinski static bool map_is_map_of_progs(__u32 type)
4171bb428fSJakub Kicinski {
4271bb428fSJakub Kicinski return type == BPF_MAP_TYPE_PROG_ARRAY;
4371bb428fSJakub Kicinski }
4471bb428fSJakub Kicinski
map_type_from_str(const char * type)450b592b5aSJakub Kicinski static int map_type_from_str(const char *type)
460b592b5aSJakub Kicinski {
472e98964bSDaniel Müller const char *map_type_str;
480b592b5aSJakub Kicinski unsigned int i;
490b592b5aSJakub Kicinski
502e98964bSDaniel Müller for (i = 0; ; i++) {
512e98964bSDaniel Müller map_type_str = libbpf_bpf_map_type_str(i);
522e98964bSDaniel Müller if (!map_type_str)
532e98964bSDaniel Müller break;
542e98964bSDaniel Müller
550b592b5aSJakub Kicinski /* Don't allow prefixing in case of possible future shadowing */
562e98964bSDaniel Müller if (!strcmp(map_type_str, type))
570b592b5aSJakub Kicinski return i;
582e98964bSDaniel Müller }
590b592b5aSJakub Kicinski return -1;
600b592b5aSJakub Kicinski }
610b592b5aSJakub Kicinski
alloc_value(struct bpf_map_info * info)6271bb428fSJakub Kicinski static void *alloc_value(struct bpf_map_info *info)
6371bb428fSJakub Kicinski {
6471bb428fSJakub Kicinski if (map_is_per_cpu(info->type))
65573b3aa6SYonghong Song return malloc(round_up(info->value_size, 8) *
66573b3aa6SYonghong Song get_possible_cpus());
6771bb428fSJakub Kicinski else
6871bb428fSJakub Kicinski return malloc(info->value_size);
6971bb428fSJakub Kicinski }
7071bb428fSJakub Kicinski
do_dump_btf(const struct btf_dumper * d,struct bpf_map_info * map_info,void * key,void * value)712d3feca8SOkash Khawaja static int do_dump_btf(const struct btf_dumper *d,
722d3feca8SOkash Khawaja struct bpf_map_info *map_info, void *key,
732d3feca8SOkash Khawaja void *value)
742d3feca8SOkash Khawaja {
754e1ea332SMartin KaFai Lau __u32 value_id;
764bbb3583SAndrii Nakryiko int ret = 0;
772d3feca8SOkash Khawaja
782d3feca8SOkash Khawaja /* start of key-value pair */
792d3feca8SOkash Khawaja jsonw_start_object(d->jw);
802d3feca8SOkash Khawaja
81817998afSDaniel Borkmann if (map_info->btf_key_type_id) {
822d3feca8SOkash Khawaja jsonw_name(d->jw, "key");
832d3feca8SOkash Khawaja
842d3feca8SOkash Khawaja ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
852d3feca8SOkash Khawaja if (ret)
862d3feca8SOkash Khawaja goto err_end_obj;
87817998afSDaniel Borkmann }
882d3feca8SOkash Khawaja
894e1ea332SMartin KaFai Lau value_id = map_info->btf_vmlinux_value_type_id ?
904e1ea332SMartin KaFai Lau : map_info->btf_value_type_id;
914e1ea332SMartin KaFai Lau
921a86ad89SYonghong Song if (!map_is_per_cpu(map_info->type)) {
932d3feca8SOkash Khawaja jsonw_name(d->jw, "value");
944e1ea332SMartin KaFai Lau ret = btf_dumper_type(d, value_id, value);
951a86ad89SYonghong Song } else {
961a86ad89SYonghong Song unsigned int i, n, step;
971a86ad89SYonghong Song
981a86ad89SYonghong Song jsonw_name(d->jw, "values");
991a86ad89SYonghong Song jsonw_start_array(d->jw);
1001a86ad89SYonghong Song n = get_possible_cpus();
1011a86ad89SYonghong Song step = round_up(map_info->value_size, 8);
1021a86ad89SYonghong Song for (i = 0; i < n; i++) {
1031a86ad89SYonghong Song jsonw_start_object(d->jw);
1041a86ad89SYonghong Song jsonw_int_field(d->jw, "cpu", i);
1051a86ad89SYonghong Song jsonw_name(d->jw, "value");
1064e1ea332SMartin KaFai Lau ret = btf_dumper_type(d, value_id, value + i * step);
1071a86ad89SYonghong Song jsonw_end_object(d->jw);
1081a86ad89SYonghong Song if (ret)
1091a86ad89SYonghong Song break;
1101a86ad89SYonghong Song }
1111a86ad89SYonghong Song jsonw_end_array(d->jw);
1121a86ad89SYonghong Song }
1132d3feca8SOkash Khawaja
1142d3feca8SOkash Khawaja err_end_obj:
1152d3feca8SOkash Khawaja /* end of key-value pair */
1162d3feca8SOkash Khawaja jsonw_end_object(d->jw);
1172d3feca8SOkash Khawaja
1182d3feca8SOkash Khawaja return ret;
1192d3feca8SOkash Khawaja }
1202d3feca8SOkash Khawaja
get_btf_writer(void)1212d3feca8SOkash Khawaja static json_writer_t *get_btf_writer(void)
1222d3feca8SOkash Khawaja {
1232d3feca8SOkash Khawaja json_writer_t *jw = jsonw_new(stdout);
1242d3feca8SOkash Khawaja
1252d3feca8SOkash Khawaja if (!jw)
1262d3feca8SOkash Khawaja return NULL;
1272d3feca8SOkash Khawaja jsonw_pretty(jw, true);
1282d3feca8SOkash Khawaja
1292d3feca8SOkash Khawaja return jw;
1302d3feca8SOkash Khawaja }
1312d3feca8SOkash Khawaja
print_entry_json(struct bpf_map_info * info,unsigned char * key,unsigned char * value,struct btf * btf)132831a0aafSQuentin Monnet static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
1332d3feca8SOkash Khawaja unsigned char *value, struct btf *btf)
134831a0aafSQuentin Monnet {
135831a0aafSQuentin Monnet jsonw_start_object(json_wtr);
136831a0aafSQuentin Monnet
137831a0aafSQuentin Monnet if (!map_is_per_cpu(info->type)) {
138831a0aafSQuentin Monnet jsonw_name(json_wtr, "key");
139831a0aafSQuentin Monnet print_hex_data_json(key, info->key_size);
140831a0aafSQuentin Monnet jsonw_name(json_wtr, "value");
141831a0aafSQuentin Monnet print_hex_data_json(value, info->value_size);
142bf06c939SXueming Feng if (map_is_map_of_maps(info->type))
143bf06c939SXueming Feng jsonw_uint_field(json_wtr, "inner_map_id",
144bf06c939SXueming Feng *(unsigned int *)value);
1452d3feca8SOkash Khawaja if (btf) {
1462d3feca8SOkash Khawaja struct btf_dumper d = {
1472d3feca8SOkash Khawaja .btf = btf,
1482d3feca8SOkash Khawaja .jw = json_wtr,
1492d3feca8SOkash Khawaja .is_plain_text = false,
1502d3feca8SOkash Khawaja };
1512d3feca8SOkash Khawaja
1522d3feca8SOkash Khawaja jsonw_name(json_wtr, "formatted");
1532d3feca8SOkash Khawaja do_dump_btf(&d, info, key, value);
1542d3feca8SOkash Khawaja }
155831a0aafSQuentin Monnet } else {
156573b3aa6SYonghong Song unsigned int i, n, step;
157831a0aafSQuentin Monnet
158831a0aafSQuentin Monnet n = get_possible_cpus();
159573b3aa6SYonghong Song step = round_up(info->value_size, 8);
160831a0aafSQuentin Monnet
161831a0aafSQuentin Monnet jsonw_name(json_wtr, "key");
162831a0aafSQuentin Monnet print_hex_data_json(key, info->key_size);
163831a0aafSQuentin Monnet
164831a0aafSQuentin Monnet jsonw_name(json_wtr, "values");
165831a0aafSQuentin Monnet jsonw_start_array(json_wtr);
166831a0aafSQuentin Monnet for (i = 0; i < n; i++) {
167831a0aafSQuentin Monnet jsonw_start_object(json_wtr);
168831a0aafSQuentin Monnet
169831a0aafSQuentin Monnet jsonw_int_field(json_wtr, "cpu", i);
170831a0aafSQuentin Monnet
171831a0aafSQuentin Monnet jsonw_name(json_wtr, "value");
172573b3aa6SYonghong Song print_hex_data_json(value + i * step,
173831a0aafSQuentin Monnet info->value_size);
174831a0aafSQuentin Monnet
175831a0aafSQuentin Monnet jsonw_end_object(json_wtr);
176831a0aafSQuentin Monnet }
177831a0aafSQuentin Monnet jsonw_end_array(json_wtr);
1781a86ad89SYonghong Song if (btf) {
1791a86ad89SYonghong Song struct btf_dumper d = {
1801a86ad89SYonghong Song .btf = btf,
1811a86ad89SYonghong Song .jw = json_wtr,
1821a86ad89SYonghong Song .is_plain_text = false,
1831a86ad89SYonghong Song };
1841a86ad89SYonghong Song
1851a86ad89SYonghong Song jsonw_name(json_wtr, "formatted");
1861a86ad89SYonghong Song do_dump_btf(&d, info, key, value);
1871a86ad89SYonghong Song }
188831a0aafSQuentin Monnet }
189831a0aafSQuentin Monnet
190831a0aafSQuentin Monnet jsonw_end_object(json_wtr);
191831a0aafSQuentin Monnet }
192831a0aafSQuentin Monnet
193a20693b6SQuentin Monnet static void
print_entry_error_msg(struct bpf_map_info * info,unsigned char * key,const char * error_msg)194a20693b6SQuentin Monnet print_entry_error_msg(struct bpf_map_info *info, unsigned char *key,
1950478c3bfSBenjamin Poirier const char *error_msg)
1968ec92dc2SPrashant Bhole {
1970478c3bfSBenjamin Poirier int msg_size = strlen(error_msg);
1988ec92dc2SPrashant Bhole bool single_line, break_names;
1998ec92dc2SPrashant Bhole
2000478c3bfSBenjamin Poirier break_names = info->key_size > 16 || msg_size > 16;
2010478c3bfSBenjamin Poirier single_line = info->key_size + msg_size <= 24 && !break_names;
2028ec92dc2SPrashant Bhole
2038ec92dc2SPrashant Bhole printf("key:%c", break_names ? '\n' : ' ');
2048ec92dc2SPrashant Bhole fprint_hex(stdout, key, info->key_size, " ");
2058ec92dc2SPrashant Bhole
2068ec92dc2SPrashant Bhole printf(single_line ? " " : "\n");
2078ec92dc2SPrashant Bhole
2080478c3bfSBenjamin Poirier printf("value:%c%s", break_names ? '\n' : ' ', error_msg);
2098ec92dc2SPrashant Bhole
2108ec92dc2SPrashant Bhole printf("\n");
2118ec92dc2SPrashant Bhole }
2128ec92dc2SPrashant Bhole
213a20693b6SQuentin Monnet static void
print_entry_error(struct bpf_map_info * map_info,void * key,int lookup_errno)214a20693b6SQuentin Monnet print_entry_error(struct bpf_map_info *map_info, void *key, int lookup_errno)
215a20693b6SQuentin Monnet {
216a20693b6SQuentin Monnet /* For prog_array maps or arrays of maps, failure to lookup the value
217a20693b6SQuentin Monnet * means there is no entry for that key. Do not print an error message
218a20693b6SQuentin Monnet * in that case.
219a20693b6SQuentin Monnet */
22086233ce3SQuentin Monnet if ((map_is_map_of_maps(map_info->type) ||
22186233ce3SQuentin Monnet map_is_map_of_progs(map_info->type)) && lookup_errno == ENOENT)
222a20693b6SQuentin Monnet return;
223a20693b6SQuentin Monnet
224a20693b6SQuentin Monnet if (json_output) {
225a20693b6SQuentin Monnet jsonw_start_object(json_wtr); /* entry */
226a20693b6SQuentin Monnet jsonw_name(json_wtr, "key");
227a20693b6SQuentin Monnet print_hex_data_json(key, map_info->key_size);
228a20693b6SQuentin Monnet jsonw_name(json_wtr, "value");
229a20693b6SQuentin Monnet jsonw_start_object(json_wtr); /* error */
230a20693b6SQuentin Monnet jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
231a20693b6SQuentin Monnet jsonw_end_object(json_wtr); /* error */
232a20693b6SQuentin Monnet jsonw_end_object(json_wtr); /* entry */
233a20693b6SQuentin Monnet } else {
234a20693b6SQuentin Monnet const char *msg = NULL;
235a20693b6SQuentin Monnet
236a20693b6SQuentin Monnet if (lookup_errno == ENOENT)
237a20693b6SQuentin Monnet msg = "<no entry>";
238a20693b6SQuentin Monnet else if (lookup_errno == ENOSPC &&
239a20693b6SQuentin Monnet map_info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
240a20693b6SQuentin Monnet msg = "<cannot read>";
241a20693b6SQuentin Monnet
242a20693b6SQuentin Monnet print_entry_error_msg(map_info, key,
243a20693b6SQuentin Monnet msg ? : strerror(lookup_errno));
244a20693b6SQuentin Monnet }
245a20693b6SQuentin Monnet }
246a20693b6SQuentin Monnet
print_entry_plain(struct bpf_map_info * info,unsigned char * key,unsigned char * value)247831a0aafSQuentin Monnet static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
24871bb428fSJakub Kicinski unsigned char *value)
24971bb428fSJakub Kicinski {
25071bb428fSJakub Kicinski if (!map_is_per_cpu(info->type)) {
25171bb428fSJakub Kicinski bool single_line, break_names;
25271bb428fSJakub Kicinski
25371bb428fSJakub Kicinski break_names = info->key_size > 16 || info->value_size > 16;
25471bb428fSJakub Kicinski single_line = info->key_size + info->value_size <= 24 &&
25571bb428fSJakub Kicinski !break_names;
25671bb428fSJakub Kicinski
25704a5d323SStanislav Fomichev if (info->key_size) {
25871bb428fSJakub Kicinski printf("key:%c", break_names ? '\n' : ' ');
2599cbe1f58SQuentin Monnet fprint_hex(stdout, key, info->key_size, " ");
26071bb428fSJakub Kicinski
26171bb428fSJakub Kicinski printf(single_line ? " " : "\n");
26204a5d323SStanislav Fomichev }
26371bb428fSJakub Kicinski
26404a5d323SStanislav Fomichev if (info->value_size) {
265bf06c939SXueming Feng if (map_is_map_of_maps(info->type)) {
266bf06c939SXueming Feng printf("inner_map_id:%c", break_names ? '\n' : ' ');
267bf06c939SXueming Feng printf("%u ", *(unsigned int *)value);
268bf06c939SXueming Feng } else {
26971bb428fSJakub Kicinski printf("value:%c", break_names ? '\n' : ' ');
2700478c3bfSBenjamin Poirier fprint_hex(stdout, value, info->value_size, " ");
27104a5d323SStanislav Fomichev }
272bf06c939SXueming Feng }
27371bb428fSJakub Kicinski
27471bb428fSJakub Kicinski printf("\n");
27571bb428fSJakub Kicinski } else {
276573b3aa6SYonghong Song unsigned int i, n, step;
27771bb428fSJakub Kicinski
27871bb428fSJakub Kicinski n = get_possible_cpus();
279573b3aa6SYonghong Song step = round_up(info->value_size, 8);
28071bb428fSJakub Kicinski
28104a5d323SStanislav Fomichev if (info->key_size) {
28271bb428fSJakub Kicinski printf("key:\n");
2839cbe1f58SQuentin Monnet fprint_hex(stdout, key, info->key_size, " ");
28471bb428fSJakub Kicinski printf("\n");
28504a5d323SStanislav Fomichev }
28604a5d323SStanislav Fomichev if (info->value_size) {
28771bb428fSJakub Kicinski for (i = 0; i < n; i++) {
28871bb428fSJakub Kicinski printf("value (CPU %02d):%c",
28971bb428fSJakub Kicinski i, info->value_size > 16 ? '\n' : ' ');
290573b3aa6SYonghong Song fprint_hex(stdout, value + i * step,
29171bb428fSJakub Kicinski info->value_size, " ");
29271bb428fSJakub Kicinski printf("\n");
29371bb428fSJakub Kicinski }
29471bb428fSJakub Kicinski }
29571bb428fSJakub Kicinski }
29604a5d323SStanislav Fomichev }
29771bb428fSJakub Kicinski
parse_bytes(char ** argv,const char * name,unsigned char * val,unsigned int n)29871bb428fSJakub Kicinski static char **parse_bytes(char **argv, const char *name, unsigned char *val,
29971bb428fSJakub Kicinski unsigned int n)
30071bb428fSJakub Kicinski {
3010c90f224SQuentin Monnet unsigned int i = 0, base = 0;
30271bb428fSJakub Kicinski char *endptr;
30371bb428fSJakub Kicinski
3040c90f224SQuentin Monnet if (is_prefix(*argv, "hex")) {
3050c90f224SQuentin Monnet base = 16;
3060c90f224SQuentin Monnet argv++;
3070c90f224SQuentin Monnet }
3080c90f224SQuentin Monnet
30971bb428fSJakub Kicinski while (i < n && argv[i]) {
3100c90f224SQuentin Monnet val[i] = strtoul(argv[i], &endptr, base);
31171bb428fSJakub Kicinski if (*endptr) {
3129a5ab8bfSQuentin Monnet p_err("error parsing byte: %s", argv[i]);
313d9c0b48dSQuentin Monnet return NULL;
31471bb428fSJakub Kicinski }
31571bb428fSJakub Kicinski i++;
31671bb428fSJakub Kicinski }
31771bb428fSJakub Kicinski
31871bb428fSJakub Kicinski if (i != n) {
3199a5ab8bfSQuentin Monnet p_err("%s expected %d bytes got %d", name, n, i);
32071bb428fSJakub Kicinski return NULL;
32171bb428fSJakub Kicinski }
32271bb428fSJakub Kicinski
32371bb428fSJakub Kicinski return argv + i;
32471bb428fSJakub Kicinski }
32571bb428fSJakub Kicinski
326b0ca5ecbSPaolo Abeni /* on per cpu maps we must copy the provided value on all value instances */
fill_per_cpu_value(struct bpf_map_info * info,void * value)327b0ca5ecbSPaolo Abeni static void fill_per_cpu_value(struct bpf_map_info *info, void *value)
328b0ca5ecbSPaolo Abeni {
329b0ca5ecbSPaolo Abeni unsigned int i, n, step;
330b0ca5ecbSPaolo Abeni
331b0ca5ecbSPaolo Abeni if (!map_is_per_cpu(info->type))
332b0ca5ecbSPaolo Abeni return;
333b0ca5ecbSPaolo Abeni
334b0ca5ecbSPaolo Abeni n = get_possible_cpus();
335b0ca5ecbSPaolo Abeni step = round_up(info->value_size, 8);
336b0ca5ecbSPaolo Abeni for (i = 1; i < n; i++)
337b0ca5ecbSPaolo Abeni memcpy(value + i * step, value, info->value_size);
338b0ca5ecbSPaolo Abeni }
339b0ca5ecbSPaolo Abeni
parse_elem(char ** argv,struct bpf_map_info * info,void * key,void * value,__u32 key_size,__u32 value_size,__u32 * flags,__u32 ** value_fd)34071bb428fSJakub Kicinski static int parse_elem(char **argv, struct bpf_map_info *info,
34171bb428fSJakub Kicinski void *key, void *value, __u32 key_size, __u32 value_size,
34271bb428fSJakub Kicinski __u32 *flags, __u32 **value_fd)
34371bb428fSJakub Kicinski {
34471bb428fSJakub Kicinski if (!*argv) {
34571bb428fSJakub Kicinski if (!key && !value)
34671bb428fSJakub Kicinski return 0;
3479a5ab8bfSQuentin Monnet p_err("did not find %s", key ? "key" : "value");
34871bb428fSJakub Kicinski return -1;
34971bb428fSJakub Kicinski }
35071bb428fSJakub Kicinski
35171bb428fSJakub Kicinski if (is_prefix(*argv, "key")) {
35271bb428fSJakub Kicinski if (!key) {
35371bb428fSJakub Kicinski if (key_size)
3549a5ab8bfSQuentin Monnet p_err("duplicate key");
35571bb428fSJakub Kicinski else
3569a5ab8bfSQuentin Monnet p_err("unnecessary key");
35771bb428fSJakub Kicinski return -1;
35871bb428fSJakub Kicinski }
35971bb428fSJakub Kicinski
36071bb428fSJakub Kicinski argv = parse_bytes(argv + 1, "key", key, key_size);
36171bb428fSJakub Kicinski if (!argv)
36271bb428fSJakub Kicinski return -1;
36371bb428fSJakub Kicinski
36471bb428fSJakub Kicinski return parse_elem(argv, info, NULL, value, key_size, value_size,
36571bb428fSJakub Kicinski flags, value_fd);
36671bb428fSJakub Kicinski } else if (is_prefix(*argv, "value")) {
36771bb428fSJakub Kicinski int fd;
36871bb428fSJakub Kicinski
36971bb428fSJakub Kicinski if (!value) {
37071bb428fSJakub Kicinski if (value_size)
3719a5ab8bfSQuentin Monnet p_err("duplicate value");
37271bb428fSJakub Kicinski else
3739a5ab8bfSQuentin Monnet p_err("unnecessary value");
37471bb428fSJakub Kicinski return -1;
37571bb428fSJakub Kicinski }
37671bb428fSJakub Kicinski
37771bb428fSJakub Kicinski argv++;
37871bb428fSJakub Kicinski
37971bb428fSJakub Kicinski if (map_is_map_of_maps(info->type)) {
38071bb428fSJakub Kicinski int argc = 2;
38171bb428fSJakub Kicinski
38271bb428fSJakub Kicinski if (value_size != 4) {
3839a5ab8bfSQuentin Monnet p_err("value smaller than 4B for map in map?");
38471bb428fSJakub Kicinski return -1;
38571bb428fSJakub Kicinski }
38671bb428fSJakub Kicinski if (!argv[0] || !argv[1]) {
3879a5ab8bfSQuentin Monnet p_err("not enough value arguments for map in map");
38871bb428fSJakub Kicinski return -1;
38971bb428fSJakub Kicinski }
39071bb428fSJakub Kicinski
39171bb428fSJakub Kicinski fd = map_parse_fd(&argc, &argv);
39271bb428fSJakub Kicinski if (fd < 0)
39371bb428fSJakub Kicinski return -1;
39471bb428fSJakub Kicinski
39571bb428fSJakub Kicinski *value_fd = value;
39671bb428fSJakub Kicinski **value_fd = fd;
39771bb428fSJakub Kicinski } else if (map_is_map_of_progs(info->type)) {
39871bb428fSJakub Kicinski int argc = 2;
39971bb428fSJakub Kicinski
40071bb428fSJakub Kicinski if (value_size != 4) {
4019a5ab8bfSQuentin Monnet p_err("value smaller than 4B for map of progs?");
40271bb428fSJakub Kicinski return -1;
40371bb428fSJakub Kicinski }
40471bb428fSJakub Kicinski if (!argv[0] || !argv[1]) {
4059a5ab8bfSQuentin Monnet p_err("not enough value arguments for map of progs");
40671bb428fSJakub Kicinski return -1;
40771bb428fSJakub Kicinski }
408d76198b0SJakub Kicinski if (is_prefix(*argv, "id"))
409d76198b0SJakub Kicinski p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
410d76198b0SJakub Kicinski " by some process or pinned otherwise update will be lost");
41171bb428fSJakub Kicinski
41271bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv);
41371bb428fSJakub Kicinski if (fd < 0)
41471bb428fSJakub Kicinski return -1;
41571bb428fSJakub Kicinski
41671bb428fSJakub Kicinski *value_fd = value;
41771bb428fSJakub Kicinski **value_fd = fd;
41871bb428fSJakub Kicinski } else {
41971bb428fSJakub Kicinski argv = parse_bytes(argv, "value", value, value_size);
42071bb428fSJakub Kicinski if (!argv)
42171bb428fSJakub Kicinski return -1;
422b0ca5ecbSPaolo Abeni
423b0ca5ecbSPaolo Abeni fill_per_cpu_value(info, value);
42471bb428fSJakub Kicinski }
42571bb428fSJakub Kicinski
42671bb428fSJakub Kicinski return parse_elem(argv, info, key, NULL, key_size, value_size,
42771bb428fSJakub Kicinski flags, NULL);
42871bb428fSJakub Kicinski } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
42971bb428fSJakub Kicinski is_prefix(*argv, "exist")) {
43071bb428fSJakub Kicinski if (!flags) {
4319a5ab8bfSQuentin Monnet p_err("flags specified multiple times: %s", *argv);
43271bb428fSJakub Kicinski return -1;
43371bb428fSJakub Kicinski }
43471bb428fSJakub Kicinski
43571bb428fSJakub Kicinski if (is_prefix(*argv, "any"))
43671bb428fSJakub Kicinski *flags = BPF_ANY;
43771bb428fSJakub Kicinski else if (is_prefix(*argv, "noexist"))
43871bb428fSJakub Kicinski *flags = BPF_NOEXIST;
43971bb428fSJakub Kicinski else if (is_prefix(*argv, "exist"))
44071bb428fSJakub Kicinski *flags = BPF_EXIST;
44171bb428fSJakub Kicinski
44271bb428fSJakub Kicinski return parse_elem(argv + 1, info, key, value, key_size,
44371bb428fSJakub Kicinski value_size, NULL, value_fd);
44471bb428fSJakub Kicinski }
44571bb428fSJakub Kicinski
4469a5ab8bfSQuentin Monnet p_err("expected key or value, got: %s", *argv);
44771bb428fSJakub Kicinski return -1;
44871bb428fSJakub Kicinski }
44971bb428fSJakub Kicinski
show_map_header_json(struct bpf_map_info * info,json_writer_t * wtr)45099f9863aSPaul Chaignon static void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
45199f9863aSPaul Chaignon {
4522e98964bSDaniel Müller const char *map_type_str;
4532e98964bSDaniel Müller
45499f9863aSPaul Chaignon jsonw_uint_field(wtr, "id", info->id);
4552e98964bSDaniel Müller map_type_str = libbpf_bpf_map_type_str(info->type);
4562e98964bSDaniel Müller if (map_type_str)
4572e98964bSDaniel Müller jsonw_string_field(wtr, "type", map_type_str);
45899f9863aSPaul Chaignon else
45999f9863aSPaul Chaignon jsonw_uint_field(wtr, "type", info->type);
46099f9863aSPaul Chaignon
46199f9863aSPaul Chaignon if (*info->name)
46299f9863aSPaul Chaignon jsonw_string_field(wtr, "name", info->name);
46399f9863aSPaul Chaignon
46499f9863aSPaul Chaignon jsonw_name(wtr, "flags");
46599f9863aSPaul Chaignon jsonw_printf(wtr, "%d", info->map_flags);
46699f9863aSPaul Chaignon }
46799f9863aSPaul Chaignon
show_map_close_json(int fd,struct bpf_map_info * info)468831a0aafSQuentin Monnet static int show_map_close_json(int fd, struct bpf_map_info *info)
469831a0aafSQuentin Monnet {
470c354ff2eSQuentin Monnet char *memlock, *frozen_str;
471c354ff2eSQuentin Monnet int frozen = 0;
472831a0aafSQuentin Monnet
473831a0aafSQuentin Monnet memlock = get_fdinfo(fd, "memlock");
474c354ff2eSQuentin Monnet frozen_str = get_fdinfo(fd, "frozen");
475831a0aafSQuentin Monnet
476831a0aafSQuentin Monnet jsonw_start_object(json_wtr);
477831a0aafSQuentin Monnet
47899f9863aSPaul Chaignon show_map_header_json(info, json_wtr);
479064a07cbSJakub Kicinski
480064a07cbSJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
481064a07cbSJakub Kicinski
482831a0aafSQuentin Monnet jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
483831a0aafSQuentin Monnet jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
484831a0aafSQuentin Monnet jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
485831a0aafSQuentin Monnet
486831a0aafSQuentin Monnet if (memlock)
487357b3cc3SChris J Arges jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock));
488831a0aafSQuentin Monnet free(memlock);
489831a0aafSQuentin Monnet
49099a44befSQuentin Monnet if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
49199a44befSQuentin Monnet char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
49299a44befSQuentin Monnet char *owner_jited = get_fdinfo(fd, "owner_jited");
49399a44befSQuentin Monnet
49499a44befSQuentin Monnet if (owner_prog_type) {
49599a44befSQuentin Monnet unsigned int prog_type = atoi(owner_prog_type);
496b700eeb4SDaniel Müller const char *prog_type_str;
49799a44befSQuentin Monnet
498b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(prog_type);
499b700eeb4SDaniel Müller if (prog_type_str)
50099a44befSQuentin Monnet jsonw_string_field(json_wtr, "owner_prog_type",
501b700eeb4SDaniel Müller prog_type_str);
50299a44befSQuentin Monnet else
50399a44befSQuentin Monnet jsonw_uint_field(json_wtr, "owner_prog_type",
50499a44befSQuentin Monnet prog_type);
50599a44befSQuentin Monnet }
5068c79b356SJakub Kicinski if (owner_jited)
5078c79b356SJakub Kicinski jsonw_bool_field(json_wtr, "owner_jited",
5088c79b356SJakub Kicinski !!atoi(owner_jited));
50999a44befSQuentin Monnet
51099a44befSQuentin Monnet free(owner_prog_type);
51199a44befSQuentin Monnet free(owner_jited);
51299a44befSQuentin Monnet }
51399a44befSQuentin Monnet close(fd);
51499a44befSQuentin Monnet
515c354ff2eSQuentin Monnet if (frozen_str) {
516c354ff2eSQuentin Monnet frozen = atoi(frozen_str);
517c354ff2eSQuentin Monnet free(frozen_str);
518c354ff2eSQuentin Monnet }
519c354ff2eSQuentin Monnet jsonw_int_field(json_wtr, "frozen", frozen);
520c354ff2eSQuentin Monnet
521d1b7725dSPrashant Bhole if (info->btf_id)
522d1b7725dSPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id);
523d1b7725dSPrashant Bhole
5248f184732SQuentin Monnet if (!hashmap__empty(map_table)) {
5258f184732SQuentin Monnet struct hashmap_entry *entry;
5264990f1f4SPrashant Bhole
5274990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned");
5284990f1f4SPrashant Bhole jsonw_start_array(json_wtr);
529c302378bSEduard Zingerman hashmap__for_each_key_entry(map_table, entry, info->id)
530c302378bSEduard Zingerman jsonw_string(json_wtr, entry->pvalue);
5314990f1f4SPrashant Bhole jsonw_end_array(json_wtr);
5324990f1f4SPrashant Bhole }
5334990f1f4SPrashant Bhole
534d6699f8eSQuentin Monnet emit_obj_refs_json(refs_table, info->id, json_wtr);
535d53dee3fSAndrii Nakryiko
536831a0aafSQuentin Monnet jsonw_end_object(json_wtr);
537831a0aafSQuentin Monnet
538831a0aafSQuentin Monnet return 0;
539831a0aafSQuentin Monnet }
540831a0aafSQuentin Monnet
show_map_header_plain(struct bpf_map_info * info)54199f9863aSPaul Chaignon static void show_map_header_plain(struct bpf_map_info *info)
54271bb428fSJakub Kicinski {
5432e98964bSDaniel Müller const char *map_type_str;
5442e98964bSDaniel Müller
54571bb428fSJakub Kicinski printf("%u: ", info->id);
5462e98964bSDaniel Müller
5472e98964bSDaniel Müller map_type_str = libbpf_bpf_map_type_str(info->type);
5482e98964bSDaniel Müller if (map_type_str)
5492e98964bSDaniel Müller printf("%s ", map_type_str);
55071bb428fSJakub Kicinski else
55171bb428fSJakub Kicinski printf("type %u ", info->type);
55271bb428fSJakub Kicinski
55371bb428fSJakub Kicinski if (*info->name)
55471bb428fSJakub Kicinski printf("name %s ", info->name);
55571bb428fSJakub Kicinski
556064a07cbSJakub Kicinski printf("flags 0x%x", info->map_flags);
557064a07cbSJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
558064a07cbSJakub Kicinski printf("\n");
55999f9863aSPaul Chaignon }
56099f9863aSPaul Chaignon
show_map_close_plain(int fd,struct bpf_map_info * info)56199f9863aSPaul Chaignon static int show_map_close_plain(int fd, struct bpf_map_info *info)
56299f9863aSPaul Chaignon {
56399f9863aSPaul Chaignon char *memlock, *frozen_str;
56499f9863aSPaul Chaignon int frozen = 0;
56599f9863aSPaul Chaignon
56699f9863aSPaul Chaignon memlock = get_fdinfo(fd, "memlock");
56799f9863aSPaul Chaignon frozen_str = get_fdinfo(fd, "frozen");
56899f9863aSPaul Chaignon
56999f9863aSPaul Chaignon show_map_header_plain(info);
57071bb428fSJakub Kicinski printf("\tkey %uB value %uB max_entries %u",
57171bb428fSJakub Kicinski info->key_size, info->value_size, info->max_entries);
57271bb428fSJakub Kicinski
57371bb428fSJakub Kicinski if (memlock)
57471bb428fSJakub Kicinski printf(" memlock %sB", memlock);
57571bb428fSJakub Kicinski free(memlock);
57671bb428fSJakub Kicinski
57799a44befSQuentin Monnet if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
57899a44befSQuentin Monnet char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
57999a44befSQuentin Monnet char *owner_jited = get_fdinfo(fd, "owner_jited");
58099a44befSQuentin Monnet
5818c79b356SJakub Kicinski if (owner_prog_type || owner_jited)
58299a44befSQuentin Monnet printf("\n\t");
58399a44befSQuentin Monnet if (owner_prog_type) {
58499a44befSQuentin Monnet unsigned int prog_type = atoi(owner_prog_type);
585b700eeb4SDaniel Müller const char *prog_type_str;
58699a44befSQuentin Monnet
587b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(prog_type);
588b700eeb4SDaniel Müller if (prog_type_str)
589b700eeb4SDaniel Müller printf("owner_prog_type %s ", prog_type_str);
59099a44befSQuentin Monnet else
59199a44befSQuentin Monnet printf("owner_prog_type %d ", prog_type);
59299a44befSQuentin Monnet }
5938c79b356SJakub Kicinski if (owner_jited)
5948c79b356SJakub Kicinski printf("owner%s jited",
5958c79b356SJakub Kicinski atoi(owner_jited) ? "" : " not");
59699a44befSQuentin Monnet
59799a44befSQuentin Monnet free(owner_prog_type);
59899a44befSQuentin Monnet free(owner_jited);
59999a44befSQuentin Monnet }
60099a44befSQuentin Monnet close(fd);
60199a44befSQuentin Monnet
6028f184732SQuentin Monnet if (!hashmap__empty(map_table)) {
6038f184732SQuentin Monnet struct hashmap_entry *entry;
60471bb428fSJakub Kicinski
605c302378bSEduard Zingerman hashmap__for_each_key_entry(map_table, entry, info->id)
606c302378bSEduard Zingerman printf("\n\tpinned %s", (char *)entry->pvalue);
6074990f1f4SPrashant Bhole }
608c354ff2eSQuentin Monnet
609c354ff2eSQuentin Monnet if (frozen_str) {
610c354ff2eSQuentin Monnet frozen = atoi(frozen_str);
611c354ff2eSQuentin Monnet free(frozen_str);
612c354ff2eSQuentin Monnet }
613c354ff2eSQuentin Monnet
6141824d8eaSYafang Shao if (info->btf_id || frozen)
6151824d8eaSYafang Shao printf("\n\t");
616d459b59eSPrashant Bhole
617d1b7725dSPrashant Bhole if (info->btf_id)
618c354ff2eSQuentin Monnet printf("btf_id %d", info->btf_id);
619c354ff2eSQuentin Monnet
620c354ff2eSQuentin Monnet if (frozen)
621c354ff2eSQuentin Monnet printf("%sfrozen", info->btf_id ? " " : "");
622d1b7725dSPrashant Bhole
623d6699f8eSQuentin Monnet emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
624d53dee3fSAndrii Nakryiko
625d459b59eSPrashant Bhole printf("\n");
62671bb428fSJakub Kicinski return 0;
62771bb428fSJakub Kicinski }
62871bb428fSJakub Kicinski
do_show_subset(int argc,char ** argv)62999f9863aSPaul Chaignon static int do_show_subset(int argc, char **argv)
63099f9863aSPaul Chaignon {
63199f9863aSPaul Chaignon struct bpf_map_info info = {};
63299f9863aSPaul Chaignon __u32 len = sizeof(info);
63399f9863aSPaul Chaignon int *fds = NULL;
63499f9863aSPaul Chaignon int nb_fds, i;
63599f9863aSPaul Chaignon int err = -1;
63699f9863aSPaul Chaignon
63799f9863aSPaul Chaignon fds = malloc(sizeof(int));
63899f9863aSPaul Chaignon if (!fds) {
63999f9863aSPaul Chaignon p_err("mem alloc failed");
64099f9863aSPaul Chaignon return -1;
64199f9863aSPaul Chaignon }
64299f9863aSPaul Chaignon nb_fds = map_parse_fds(&argc, &argv, &fds);
64399f9863aSPaul Chaignon if (nb_fds < 1)
64499f9863aSPaul Chaignon goto exit_free;
64599f9863aSPaul Chaignon
64699f9863aSPaul Chaignon if (json_output && nb_fds > 1)
64799f9863aSPaul Chaignon jsonw_start_array(json_wtr); /* root array */
64899f9863aSPaul Chaignon for (i = 0; i < nb_fds; i++) {
64938f0408eSIlya Leoshkevich err = bpf_map_get_info_by_fd(fds[i], &info, &len);
65099f9863aSPaul Chaignon if (err) {
65199f9863aSPaul Chaignon p_err("can't get map info: %s",
65299f9863aSPaul Chaignon strerror(errno));
65399f9863aSPaul Chaignon for (; i < nb_fds; i++)
65499f9863aSPaul Chaignon close(fds[i]);
65599f9863aSPaul Chaignon break;
65699f9863aSPaul Chaignon }
65799f9863aSPaul Chaignon
65899f9863aSPaul Chaignon if (json_output)
65999f9863aSPaul Chaignon show_map_close_json(fds[i], &info);
66099f9863aSPaul Chaignon else
66199f9863aSPaul Chaignon show_map_close_plain(fds[i], &info);
66299f9863aSPaul Chaignon
66399f9863aSPaul Chaignon close(fds[i]);
66499f9863aSPaul Chaignon }
66599f9863aSPaul Chaignon if (json_output && nb_fds > 1)
66699f9863aSPaul Chaignon jsonw_end_array(json_wtr); /* root array */
66799f9863aSPaul Chaignon
66899f9863aSPaul Chaignon exit_free:
66999f9863aSPaul Chaignon free(fds);
67099f9863aSPaul Chaignon return err;
67199f9863aSPaul Chaignon }
67299f9863aSPaul Chaignon
do_show(int argc,char ** argv)67371bb428fSJakub Kicinski static int do_show(int argc, char **argv)
67471bb428fSJakub Kicinski {
67571bb428fSJakub Kicinski struct bpf_map_info info = {};
67671bb428fSJakub Kicinski __u32 len = sizeof(info);
67771bb428fSJakub Kicinski __u32 id = 0;
67871bb428fSJakub Kicinski int err;
67971bb428fSJakub Kicinski int fd;
68071bb428fSJakub Kicinski
68146241271SQuentin Monnet if (show_pinned) {
6828f184732SQuentin Monnet map_table = hashmap__new(hash_fn_for_key_as_id,
6838f184732SQuentin Monnet equal_fn_for_key_as_id, NULL);
684622a5b58SMauricio Vásquez if (IS_ERR(map_table)) {
6858f184732SQuentin Monnet p_err("failed to create hashmap for pinned paths");
6868f184732SQuentin Monnet return -1;
6878f184732SQuentin Monnet }
6888f184732SQuentin Monnet build_pinned_obj_table(map_table, BPF_OBJ_MAP);
68946241271SQuentin Monnet }
690d53dee3fSAndrii Nakryiko build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
6914990f1f4SPrashant Bhole
69299f9863aSPaul Chaignon if (argc == 2)
69399f9863aSPaul Chaignon return do_show_subset(argc, argv);
69471bb428fSJakub Kicinski
69571bb428fSJakub Kicinski if (argc)
69671bb428fSJakub Kicinski return BAD_ARG();
69771bb428fSJakub Kicinski
698831a0aafSQuentin Monnet if (json_output)
699831a0aafSQuentin Monnet jsonw_start_array(json_wtr);
70071bb428fSJakub Kicinski while (true) {
70171bb428fSJakub Kicinski err = bpf_map_get_next_id(id, &id);
70271bb428fSJakub Kicinski if (err) {
70371bb428fSJakub Kicinski if (errno == ENOENT)
70471bb428fSJakub Kicinski break;
7059a5ab8bfSQuentin Monnet p_err("can't get next map: %s%s", strerror(errno),
7069a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : "");
707b3b1b653SJakub Kicinski break;
70871bb428fSJakub Kicinski }
70971bb428fSJakub Kicinski
71071bb428fSJakub Kicinski fd = bpf_map_get_fd_by_id(id);
71171bb428fSJakub Kicinski if (fd < 0) {
7128207c6ddSJakub Kicinski if (errno == ENOENT)
7138207c6ddSJakub Kicinski continue;
7149a5ab8bfSQuentin Monnet p_err("can't get map by id (%u): %s",
71571bb428fSJakub Kicinski id, strerror(errno));
716b3b1b653SJakub Kicinski break;
71771bb428fSJakub Kicinski }
71871bb428fSJakub Kicinski
71938f0408eSIlya Leoshkevich err = bpf_map_get_info_by_fd(fd, &info, &len);
72071bb428fSJakub Kicinski if (err) {
7219a5ab8bfSQuentin Monnet p_err("can't get map info: %s", strerror(errno));
72271bb428fSJakub Kicinski close(fd);
723b3b1b653SJakub Kicinski break;
72471bb428fSJakub Kicinski }
72571bb428fSJakub Kicinski
726831a0aafSQuentin Monnet if (json_output)
727831a0aafSQuentin Monnet show_map_close_json(fd, &info);
728831a0aafSQuentin Monnet else
729831a0aafSQuentin Monnet show_map_close_plain(fd, &info);
73071bb428fSJakub Kicinski }
731831a0aafSQuentin Monnet if (json_output)
732831a0aafSQuentin Monnet jsonw_end_array(json_wtr);
73371bb428fSJakub Kicinski
734d6699f8eSQuentin Monnet delete_obj_refs_table(refs_table);
735d53dee3fSAndrii Nakryiko
73646241271SQuentin Monnet if (show_pinned)
7378f184732SQuentin Monnet delete_pinned_obj_table(map_table);
73846241271SQuentin Monnet
73971bb428fSJakub Kicinski return errno == ENOENT ? 0 : -1;
74071bb428fSJakub Kicinski }
74171bb428fSJakub Kicinski
dump_map_elem(int fd,void * key,void * value,struct bpf_map_info * map_info,struct btf * btf,json_writer_t * btf_wtr)74218a781daSPrashant Bhole static int dump_map_elem(int fd, void *key, void *value,
74318a781daSPrashant Bhole struct bpf_map_info *map_info, struct btf *btf,
74418a781daSPrashant Bhole json_writer_t *btf_wtr)
74518a781daSPrashant Bhole {
746a20693b6SQuentin Monnet if (bpf_map_lookup_elem(fd, key, value)) {
747a20693b6SQuentin Monnet print_entry_error(map_info, key, errno);
748a20693b6SQuentin Monnet return -1;
749a20693b6SQuentin Monnet }
75018a781daSPrashant Bhole
75118a781daSPrashant Bhole if (json_output) {
75218a781daSPrashant Bhole print_entry_json(map_info, key, value, btf);
753a20693b6SQuentin Monnet } else if (btf) {
75418a781daSPrashant Bhole struct btf_dumper d = {
75518a781daSPrashant Bhole .btf = btf,
75618a781daSPrashant Bhole .jw = btf_wtr,
75718a781daSPrashant Bhole .is_plain_text = true,
75818a781daSPrashant Bhole };
75918a781daSPrashant Bhole
76018a781daSPrashant Bhole do_dump_btf(&d, map_info, key, value);
76118a781daSPrashant Bhole } else {
76218a781daSPrashant Bhole print_entry_plain(map_info, key, value);
76318a781daSPrashant Bhole }
76418a781daSPrashant Bhole
76518a781daSPrashant Bhole return 0;
76618a781daSPrashant Bhole }
76718a781daSPrashant Bhole
maps_have_btf(int * fds,int nb_fds)76899f9863aSPaul Chaignon static int maps_have_btf(int *fds, int nb_fds)
76971bb428fSJakub Kicinski {
7702d3feca8SOkash Khawaja struct bpf_map_info info = {};
77199f9863aSPaul Chaignon __u32 len = sizeof(info);
77299f9863aSPaul Chaignon int err, i;
77399f9863aSPaul Chaignon
77499f9863aSPaul Chaignon for (i = 0; i < nb_fds; i++) {
77538f0408eSIlya Leoshkevich err = bpf_map_get_info_by_fd(fds[i], &info, &len);
77699f9863aSPaul Chaignon if (err) {
77799f9863aSPaul Chaignon p_err("can't get map info: %s", strerror(errno));
778d7de7267SMartin KaFai Lau return -1;
77999f9863aSPaul Chaignon }
78099f9863aSPaul Chaignon
781d7de7267SMartin KaFai Lau if (!info.btf_id)
78299f9863aSPaul Chaignon return 0;
78399f9863aSPaul Chaignon }
78499f9863aSPaul Chaignon
78599f9863aSPaul Chaignon return 1;
78699f9863aSPaul Chaignon }
78799f9863aSPaul Chaignon
7884e1ea332SMartin KaFai Lau static struct btf *btf_vmlinux;
7894e1ea332SMartin KaFai Lau
get_map_kv_btf(const struct bpf_map_info * info,struct btf ** btf)790f76d8507SJiri Olsa static int get_map_kv_btf(const struct bpf_map_info *info, struct btf **btf)
7914e1ea332SMartin KaFai Lau {
792f76d8507SJiri Olsa int err = 0;
7934e1ea332SMartin KaFai Lau
7944e1ea332SMartin KaFai Lau if (info->btf_vmlinux_value_type_id) {
7954e1ea332SMartin KaFai Lau if (!btf_vmlinux) {
7964e1ea332SMartin KaFai Lau btf_vmlinux = libbpf_find_kernel_btf();
797d1313e01SSahid Orentino Ferdjaoui if (!btf_vmlinux) {
798f76d8507SJiri Olsa p_err("failed to get kernel btf");
799d1313e01SSahid Orentino Ferdjaoui return -errno;
8004e1ea332SMartin KaFai Lau }
8014e1ea332SMartin KaFai Lau }
802f76d8507SJiri Olsa *btf = btf_vmlinux;
803f76d8507SJiri Olsa } else if (info->btf_value_type_id) {
804f76d8507SJiri Olsa *btf = btf__load_from_kernel_by_id(info->btf_id);
805d1313e01SSahid Orentino Ferdjaoui if (!*btf) {
806d1313e01SSahid Orentino Ferdjaoui err = -errno;
807f76d8507SJiri Olsa p_err("failed to get btf");
808d1313e01SSahid Orentino Ferdjaoui }
809f76d8507SJiri Olsa } else {
810f76d8507SJiri Olsa *btf = NULL;
811f76d8507SJiri Olsa }
8124e1ea332SMartin KaFai Lau
813f76d8507SJiri Olsa return err;
8144e1ea332SMartin KaFai Lau }
8154e1ea332SMartin KaFai Lau
free_map_kv_btf(struct btf * btf)8164e1ea332SMartin KaFai Lau static void free_map_kv_btf(struct btf *btf)
8174e1ea332SMartin KaFai Lau {
818d1313e01SSahid Orentino Ferdjaoui if (btf != btf_vmlinux)
8194e1ea332SMartin KaFai Lau btf__free(btf);
8204e1ea332SMartin KaFai Lau }
8214e1ea332SMartin KaFai Lau
82299f9863aSPaul Chaignon static int
map_dump(int fd,struct bpf_map_info * info,json_writer_t * wtr,bool show_header)82399f9863aSPaul Chaignon map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
824188a4866SMartin KaFai Lau bool show_header)
82599f9863aSPaul Chaignon {
82671bb428fSJakub Kicinski void *key, *value, *prev_key;
82771bb428fSJakub Kicinski unsigned int num_elems = 0;
8282d3feca8SOkash Khawaja struct btf *btf = NULL;
82971bb428fSJakub Kicinski int err;
83071bb428fSJakub Kicinski
83199f9863aSPaul Chaignon key = malloc(info->key_size);
83299f9863aSPaul Chaignon value = alloc_value(info);
83371bb428fSJakub Kicinski if (!key || !value) {
8349a5ab8bfSQuentin Monnet p_err("mem alloc failed");
83571bb428fSJakub Kicinski err = -1;
83671bb428fSJakub Kicinski goto exit_free;
83771bb428fSJakub Kicinski }
83871bb428fSJakub Kicinski
83971bb428fSJakub Kicinski prev_key = NULL;
8402d3feca8SOkash Khawaja
841188a4866SMartin KaFai Lau if (wtr) {
842f76d8507SJiri Olsa err = get_map_kv_btf(info, &btf);
843e5043894SHengqi Chen if (err) {
8442d3feca8SOkash Khawaja goto exit_free;
8452d3feca8SOkash Khawaja }
8462d3feca8SOkash Khawaja
84799f9863aSPaul Chaignon if (show_header) {
84899f9863aSPaul Chaignon jsonw_start_object(wtr); /* map object */
84999f9863aSPaul Chaignon show_map_header_json(info, wtr);
85099f9863aSPaul Chaignon jsonw_name(wtr, "elements");
85199f9863aSPaul Chaignon }
85299f9863aSPaul Chaignon jsonw_start_array(wtr); /* elements */
85399f9863aSPaul Chaignon } else if (show_header) {
85499f9863aSPaul Chaignon show_map_header_plain(info);
85599f9863aSPaul Chaignon }
85699f9863aSPaul Chaignon
85799f9863aSPaul Chaignon if (info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
8582e98964bSDaniel Müller info->value_size != 8) {
8592e98964bSDaniel Müller const char *map_type_str;
8602e98964bSDaniel Müller
8612e98964bSDaniel Müller map_type_str = libbpf_bpf_map_type_str(info->type);
8623da6e7e4SBenjamin Poirier p_info("Warning: cannot read values from %s map with value_size != 8",
8632e98964bSDaniel Müller map_type_str);
8642e98964bSDaniel Müller }
86571bb428fSJakub Kicinski while (true) {
86671bb428fSJakub Kicinski err = bpf_map_get_next_key(fd, prev_key, key);
86771bb428fSJakub Kicinski if (err) {
86871bb428fSJakub Kicinski if (errno == ENOENT)
86971bb428fSJakub Kicinski err = 0;
87071bb428fSJakub Kicinski break;
87171bb428fSJakub Kicinski }
872a20693b6SQuentin Monnet if (!dump_map_elem(fd, key, value, info, btf, wtr))
873a20693b6SQuentin Monnet num_elems++;
87471bb428fSJakub Kicinski prev_key = key;
87571bb428fSJakub Kicinski }
87671bb428fSJakub Kicinski
87799f9863aSPaul Chaignon if (wtr) {
87899f9863aSPaul Chaignon jsonw_end_array(wtr); /* elements */
87999f9863aSPaul Chaignon if (show_header)
88099f9863aSPaul Chaignon jsonw_end_object(wtr); /* map object */
8812d3feca8SOkash Khawaja } else {
882831a0aafSQuentin Monnet printf("Found %u element%s\n", num_elems,
883831a0aafSQuentin Monnet num_elems != 1 ? "s" : "");
8842d3feca8SOkash Khawaja }
88571bb428fSJakub Kicinski
88671bb428fSJakub Kicinski exit_free:
88771bb428fSJakub Kicinski free(key);
88871bb428fSJakub Kicinski free(value);
88971bb428fSJakub Kicinski close(fd);
8904e1ea332SMartin KaFai Lau free_map_kv_btf(btf);
89171bb428fSJakub Kicinski
89271bb428fSJakub Kicinski return err;
89371bb428fSJakub Kicinski }
89471bb428fSJakub Kicinski
do_dump(int argc,char ** argv)89599f9863aSPaul Chaignon static int do_dump(int argc, char **argv)
89699f9863aSPaul Chaignon {
89799f9863aSPaul Chaignon json_writer_t *wtr = NULL, *btf_wtr = NULL;
89899f9863aSPaul Chaignon struct bpf_map_info info = {};
899188a4866SMartin KaFai Lau int nb_fds, i = 0;
90099f9863aSPaul Chaignon __u32 len = sizeof(info);
90199f9863aSPaul Chaignon int *fds = NULL;
90299f9863aSPaul Chaignon int err = -1;
90399f9863aSPaul Chaignon
90499f9863aSPaul Chaignon if (argc != 2)
90599f9863aSPaul Chaignon usage();
90699f9863aSPaul Chaignon
90799f9863aSPaul Chaignon fds = malloc(sizeof(int));
90899f9863aSPaul Chaignon if (!fds) {
90999f9863aSPaul Chaignon p_err("mem alloc failed");
91099f9863aSPaul Chaignon return -1;
91199f9863aSPaul Chaignon }
91299f9863aSPaul Chaignon nb_fds = map_parse_fds(&argc, &argv, &fds);
91399f9863aSPaul Chaignon if (nb_fds < 1)
91499f9863aSPaul Chaignon goto exit_free;
91599f9863aSPaul Chaignon
91699f9863aSPaul Chaignon if (json_output) {
91799f9863aSPaul Chaignon wtr = json_wtr;
91899f9863aSPaul Chaignon } else {
919188a4866SMartin KaFai Lau int do_plain_btf;
920188a4866SMartin KaFai Lau
921188a4866SMartin KaFai Lau do_plain_btf = maps_have_btf(fds, nb_fds);
922188a4866SMartin KaFai Lau if (do_plain_btf < 0)
92399f9863aSPaul Chaignon goto exit_close;
924188a4866SMartin KaFai Lau
925188a4866SMartin KaFai Lau if (do_plain_btf) {
92699f9863aSPaul Chaignon btf_wtr = get_btf_writer();
92799f9863aSPaul Chaignon wtr = btf_wtr;
928188a4866SMartin KaFai Lau if (!btf_wtr)
92999f9863aSPaul Chaignon p_info("failed to create json writer for btf. falling back to plain output");
93099f9863aSPaul Chaignon }
93199f9863aSPaul Chaignon }
93299f9863aSPaul Chaignon
93399f9863aSPaul Chaignon if (wtr && nb_fds > 1)
93499f9863aSPaul Chaignon jsonw_start_array(wtr); /* root array */
93599f9863aSPaul Chaignon for (i = 0; i < nb_fds; i++) {
93638f0408eSIlya Leoshkevich if (bpf_map_get_info_by_fd(fds[i], &info, &len)) {
93799f9863aSPaul Chaignon p_err("can't get map info: %s", strerror(errno));
93899f9863aSPaul Chaignon break;
93999f9863aSPaul Chaignon }
940188a4866SMartin KaFai Lau err = map_dump(fds[i], &info, wtr, nb_fds > 1);
94199f9863aSPaul Chaignon if (!wtr && i != nb_fds - 1)
94299f9863aSPaul Chaignon printf("\n");
94399f9863aSPaul Chaignon
94499f9863aSPaul Chaignon if (err)
94599f9863aSPaul Chaignon break;
94699f9863aSPaul Chaignon close(fds[i]);
94799f9863aSPaul Chaignon }
94899f9863aSPaul Chaignon if (wtr && nb_fds > 1)
94999f9863aSPaul Chaignon jsonw_end_array(wtr); /* root array */
95099f9863aSPaul Chaignon
951188a4866SMartin KaFai Lau if (btf_wtr)
95299f9863aSPaul Chaignon jsonw_destroy(&btf_wtr);
95399f9863aSPaul Chaignon exit_close:
95499f9863aSPaul Chaignon for (; i < nb_fds; i++)
95599f9863aSPaul Chaignon close(fds[i]);
95699f9863aSPaul Chaignon exit_free:
95799f9863aSPaul Chaignon free(fds);
95852df1a8aSSahid Orentino Ferdjaoui btf__free(btf_vmlinux);
95999f9863aSPaul Chaignon return err;
96099f9863aSPaul Chaignon }
96199f9863aSPaul Chaignon
alloc_key_value(struct bpf_map_info * info,void ** key,void ** value)9627d7209cbSStanislav Fomichev static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
9637d7209cbSStanislav Fomichev {
9647d7209cbSStanislav Fomichev *key = NULL;
9657d7209cbSStanislav Fomichev *value = NULL;
9667d7209cbSStanislav Fomichev
9677d7209cbSStanislav Fomichev if (info->key_size) {
9687d7209cbSStanislav Fomichev *key = malloc(info->key_size);
9697d7209cbSStanislav Fomichev if (!*key) {
9707d7209cbSStanislav Fomichev p_err("key mem alloc failed");
9717d7209cbSStanislav Fomichev return -1;
9727d7209cbSStanislav Fomichev }
9737d7209cbSStanislav Fomichev }
9747d7209cbSStanislav Fomichev
9757d7209cbSStanislav Fomichev if (info->value_size) {
9767d7209cbSStanislav Fomichev *value = alloc_value(info);
9777d7209cbSStanislav Fomichev if (!*value) {
9787d7209cbSStanislav Fomichev p_err("value mem alloc failed");
9797d7209cbSStanislav Fomichev free(*key);
9807d7209cbSStanislav Fomichev *key = NULL;
9817d7209cbSStanislav Fomichev return -1;
9827d7209cbSStanislav Fomichev }
9837d7209cbSStanislav Fomichev }
9847d7209cbSStanislav Fomichev
9857d7209cbSStanislav Fomichev return 0;
9867d7209cbSStanislav Fomichev }
9877d7209cbSStanislav Fomichev
do_update(int argc,char ** argv)98871bb428fSJakub Kicinski static int do_update(int argc, char **argv)
98971bb428fSJakub Kicinski {
99071bb428fSJakub Kicinski struct bpf_map_info info = {};
99171bb428fSJakub Kicinski __u32 len = sizeof(info);
99271bb428fSJakub Kicinski __u32 *value_fd = NULL;
99371bb428fSJakub Kicinski __u32 flags = BPF_ANY;
99471bb428fSJakub Kicinski void *key, *value;
99571bb428fSJakub Kicinski int fd, err;
99671bb428fSJakub Kicinski
99771bb428fSJakub Kicinski if (argc < 2)
99871bb428fSJakub Kicinski usage();
99971bb428fSJakub Kicinski
100071bb428fSJakub Kicinski fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
100171bb428fSJakub Kicinski if (fd < 0)
100271bb428fSJakub Kicinski return -1;
100371bb428fSJakub Kicinski
10047d7209cbSStanislav Fomichev err = alloc_key_value(&info, &key, &value);
10057d7209cbSStanislav Fomichev if (err)
100671bb428fSJakub Kicinski goto exit_free;
100771bb428fSJakub Kicinski
100871bb428fSJakub Kicinski err = parse_elem(argv, &info, key, value, info.key_size,
100971bb428fSJakub Kicinski info.value_size, &flags, &value_fd);
101071bb428fSJakub Kicinski if (err)
101171bb428fSJakub Kicinski goto exit_free;
101271bb428fSJakub Kicinski
101371bb428fSJakub Kicinski err = bpf_map_update_elem(fd, key, value, flags);
101471bb428fSJakub Kicinski if (err) {
10159a5ab8bfSQuentin Monnet p_err("update failed: %s", strerror(errno));
101671bb428fSJakub Kicinski goto exit_free;
101771bb428fSJakub Kicinski }
101871bb428fSJakub Kicinski
101971bb428fSJakub Kicinski exit_free:
102071bb428fSJakub Kicinski if (value_fd)
102171bb428fSJakub Kicinski close(*value_fd);
102271bb428fSJakub Kicinski free(key);
102371bb428fSJakub Kicinski free(value);
102471bb428fSJakub Kicinski close(fd);
102571bb428fSJakub Kicinski
1026004b45c0SQuentin Monnet if (!err && json_output)
1027004b45c0SQuentin Monnet jsonw_null(json_wtr);
102871bb428fSJakub Kicinski return err;
102971bb428fSJakub Kicinski }
103071bb428fSJakub Kicinski
print_key_value(struct bpf_map_info * info,void * key,void * value)103174f312efSStanislav Fomichev static void print_key_value(struct bpf_map_info *info, void *key,
103274f312efSStanislav Fomichev void *value)
103374f312efSStanislav Fomichev {
103474f312efSStanislav Fomichev json_writer_t *btf_wtr;
103586f4b7f2SQuentin Monnet struct btf *btf;
103674f312efSStanislav Fomichev
1037f76d8507SJiri Olsa if (get_map_kv_btf(info, &btf))
103874f312efSStanislav Fomichev return;
103974f312efSStanislav Fomichev
104074f312efSStanislav Fomichev if (json_output) {
104174f312efSStanislav Fomichev print_entry_json(info, key, value, btf);
104274f312efSStanislav Fomichev } else if (btf) {
104374f312efSStanislav Fomichev /* if here json_wtr wouldn't have been initialised,
104474f312efSStanislav Fomichev * so let's create separate writer for btf
104574f312efSStanislav Fomichev */
104674f312efSStanislav Fomichev btf_wtr = get_btf_writer();
104774f312efSStanislav Fomichev if (!btf_wtr) {
104874f312efSStanislav Fomichev p_info("failed to create json writer for btf. falling back to plain output");
104974f312efSStanislav Fomichev btf__free(btf);
105074f312efSStanislav Fomichev btf = NULL;
105174f312efSStanislav Fomichev print_entry_plain(info, key, value);
105274f312efSStanislav Fomichev } else {
105374f312efSStanislav Fomichev struct btf_dumper d = {
105474f312efSStanislav Fomichev .btf = btf,
105574f312efSStanislav Fomichev .jw = btf_wtr,
105674f312efSStanislav Fomichev .is_plain_text = true,
105774f312efSStanislav Fomichev };
105874f312efSStanislav Fomichev
105974f312efSStanislav Fomichev do_dump_btf(&d, info, key, value);
106074f312efSStanislav Fomichev jsonw_destroy(&btf_wtr);
106174f312efSStanislav Fomichev }
106274f312efSStanislav Fomichev } else {
106374f312efSStanislav Fomichev print_entry_plain(info, key, value);
106474f312efSStanislav Fomichev }
106574f312efSStanislav Fomichev btf__free(btf);
106674f312efSStanislav Fomichev }
106774f312efSStanislav Fomichev
do_lookup(int argc,char ** argv)106871bb428fSJakub Kicinski static int do_lookup(int argc, char **argv)
106971bb428fSJakub Kicinski {
107071bb428fSJakub Kicinski struct bpf_map_info info = {};
107171bb428fSJakub Kicinski __u32 len = sizeof(info);
107271bb428fSJakub Kicinski void *key, *value;
107371bb428fSJakub Kicinski int err;
107471bb428fSJakub Kicinski int fd;
107571bb428fSJakub Kicinski
107671bb428fSJakub Kicinski if (argc < 2)
107771bb428fSJakub Kicinski usage();
107871bb428fSJakub Kicinski
107971bb428fSJakub Kicinski fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
108071bb428fSJakub Kicinski if (fd < 0)
108171bb428fSJakub Kicinski return -1;
108271bb428fSJakub Kicinski
10838a89fff6SStanislav Fomichev err = alloc_key_value(&info, &key, &value);
10848a89fff6SStanislav Fomichev if (err)
108571bb428fSJakub Kicinski goto exit_free;
108671bb428fSJakub Kicinski
108771bb428fSJakub Kicinski err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
108871bb428fSJakub Kicinski if (err)
108971bb428fSJakub Kicinski goto exit_free;
109071bb428fSJakub Kicinski
109171bb428fSJakub Kicinski err = bpf_map_lookup_elem(fd, key, value);
10922d3feca8SOkash Khawaja if (err) {
10932d3feca8SOkash Khawaja if (errno == ENOENT) {
1094831a0aafSQuentin Monnet if (json_output) {
1095831a0aafSQuentin Monnet jsonw_null(json_wtr);
1096831a0aafSQuentin Monnet } else {
109771bb428fSJakub Kicinski printf("key:\n");
10989cbe1f58SQuentin Monnet fprint_hex(stdout, key, info.key_size, " ");
109971bb428fSJakub Kicinski printf("\n\nNot found\n");
1100831a0aafSQuentin Monnet }
110171bb428fSJakub Kicinski } else {
11029a5ab8bfSQuentin Monnet p_err("lookup failed: %s", strerror(errno));
110371bb428fSJakub Kicinski }
110471bb428fSJakub Kicinski
11052d3feca8SOkash Khawaja goto exit_free;
11062d3feca8SOkash Khawaja }
11072d3feca8SOkash Khawaja
11082d3feca8SOkash Khawaja /* here means bpf_map_lookup_elem() succeeded */
110974f312efSStanislav Fomichev print_key_value(&info, key, value);
11102d3feca8SOkash Khawaja
111171bb428fSJakub Kicinski exit_free:
111271bb428fSJakub Kicinski free(key);
111371bb428fSJakub Kicinski free(value);
111471bb428fSJakub Kicinski close(fd);
111571bb428fSJakub Kicinski
111671bb428fSJakub Kicinski return err;
111771bb428fSJakub Kicinski }
111871bb428fSJakub Kicinski
do_getnext(int argc,char ** argv)111971bb428fSJakub Kicinski static int do_getnext(int argc, char **argv)
112071bb428fSJakub Kicinski {
112171bb428fSJakub Kicinski struct bpf_map_info info = {};
112271bb428fSJakub Kicinski __u32 len = sizeof(info);
112371bb428fSJakub Kicinski void *key, *nextkey;
112471bb428fSJakub Kicinski int err;
112571bb428fSJakub Kicinski int fd;
112671bb428fSJakub Kicinski
112771bb428fSJakub Kicinski if (argc < 2)
112871bb428fSJakub Kicinski usage();
112971bb428fSJakub Kicinski
113071bb428fSJakub Kicinski fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
113171bb428fSJakub Kicinski if (fd < 0)
113271bb428fSJakub Kicinski return -1;
113371bb428fSJakub Kicinski
113471bb428fSJakub Kicinski key = malloc(info.key_size);
113571bb428fSJakub Kicinski nextkey = malloc(info.key_size);
113671bb428fSJakub Kicinski if (!key || !nextkey) {
11379a5ab8bfSQuentin Monnet p_err("mem alloc failed");
113871bb428fSJakub Kicinski err = -1;
113971bb428fSJakub Kicinski goto exit_free;
114071bb428fSJakub Kicinski }
114171bb428fSJakub Kicinski
114271bb428fSJakub Kicinski if (argc) {
114371bb428fSJakub Kicinski err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
114471bb428fSJakub Kicinski NULL, NULL);
114571bb428fSJakub Kicinski if (err)
114671bb428fSJakub Kicinski goto exit_free;
114771bb428fSJakub Kicinski } else {
114871bb428fSJakub Kicinski free(key);
114971bb428fSJakub Kicinski key = NULL;
115071bb428fSJakub Kicinski }
115171bb428fSJakub Kicinski
115271bb428fSJakub Kicinski err = bpf_map_get_next_key(fd, key, nextkey);
115371bb428fSJakub Kicinski if (err) {
11549a5ab8bfSQuentin Monnet p_err("can't get next key: %s", strerror(errno));
115571bb428fSJakub Kicinski goto exit_free;
115671bb428fSJakub Kicinski }
115771bb428fSJakub Kicinski
1158831a0aafSQuentin Monnet if (json_output) {
1159831a0aafSQuentin Monnet jsonw_start_object(json_wtr);
1160831a0aafSQuentin Monnet if (key) {
1161831a0aafSQuentin Monnet jsonw_name(json_wtr, "key");
1162831a0aafSQuentin Monnet print_hex_data_json(key, info.key_size);
1163831a0aafSQuentin Monnet } else {
1164831a0aafSQuentin Monnet jsonw_null_field(json_wtr, "key");
1165831a0aafSQuentin Monnet }
1166831a0aafSQuentin Monnet jsonw_name(json_wtr, "next_key");
1167831a0aafSQuentin Monnet print_hex_data_json(nextkey, info.key_size);
1168831a0aafSQuentin Monnet jsonw_end_object(json_wtr);
1169831a0aafSQuentin Monnet } else {
117071bb428fSJakub Kicinski if (key) {
117171bb428fSJakub Kicinski printf("key:\n");
11729cbe1f58SQuentin Monnet fprint_hex(stdout, key, info.key_size, " ");
117371bb428fSJakub Kicinski printf("\n");
117471bb428fSJakub Kicinski } else {
117571bb428fSJakub Kicinski printf("key: None\n");
117671bb428fSJakub Kicinski }
117771bb428fSJakub Kicinski printf("next key:\n");
11789cbe1f58SQuentin Monnet fprint_hex(stdout, nextkey, info.key_size, " ");
117971bb428fSJakub Kicinski printf("\n");
1180831a0aafSQuentin Monnet }
118171bb428fSJakub Kicinski
118271bb428fSJakub Kicinski exit_free:
118371bb428fSJakub Kicinski free(nextkey);
118471bb428fSJakub Kicinski free(key);
118571bb428fSJakub Kicinski close(fd);
118671bb428fSJakub Kicinski
118771bb428fSJakub Kicinski return err;
118871bb428fSJakub Kicinski }
118971bb428fSJakub Kicinski
do_delete(int argc,char ** argv)119071bb428fSJakub Kicinski static int do_delete(int argc, char **argv)
119171bb428fSJakub Kicinski {
119271bb428fSJakub Kicinski struct bpf_map_info info = {};
119371bb428fSJakub Kicinski __u32 len = sizeof(info);
119471bb428fSJakub Kicinski void *key;
119571bb428fSJakub Kicinski int err;
119671bb428fSJakub Kicinski int fd;
119771bb428fSJakub Kicinski
119871bb428fSJakub Kicinski if (argc < 2)
119971bb428fSJakub Kicinski usage();
120071bb428fSJakub Kicinski
120171bb428fSJakub Kicinski fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
120271bb428fSJakub Kicinski if (fd < 0)
120371bb428fSJakub Kicinski return -1;
120471bb428fSJakub Kicinski
120571bb428fSJakub Kicinski key = malloc(info.key_size);
120671bb428fSJakub Kicinski if (!key) {
12079a5ab8bfSQuentin Monnet p_err("mem alloc failed");
120871bb428fSJakub Kicinski err = -1;
120971bb428fSJakub Kicinski goto exit_free;
121071bb428fSJakub Kicinski }
121171bb428fSJakub Kicinski
121271bb428fSJakub Kicinski err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
121371bb428fSJakub Kicinski if (err)
121471bb428fSJakub Kicinski goto exit_free;
121571bb428fSJakub Kicinski
121671bb428fSJakub Kicinski err = bpf_map_delete_elem(fd, key);
121771bb428fSJakub Kicinski if (err)
12189a5ab8bfSQuentin Monnet p_err("delete failed: %s", strerror(errno));
121971bb428fSJakub Kicinski
122071bb428fSJakub Kicinski exit_free:
122171bb428fSJakub Kicinski free(key);
122271bb428fSJakub Kicinski close(fd);
122371bb428fSJakub Kicinski
1224004b45c0SQuentin Monnet if (!err && json_output)
1225004b45c0SQuentin Monnet jsonw_null(json_wtr);
122671bb428fSJakub Kicinski return err;
122771bb428fSJakub Kicinski }
122871bb428fSJakub Kicinski
do_pin(int argc,char ** argv)122971bb428fSJakub Kicinski static int do_pin(int argc, char **argv)
123071bb428fSJakub Kicinski {
1231004b45c0SQuentin Monnet int err;
1232004b45c0SQuentin Monnet
123375a1e792SQuentin Monnet err = do_pin_any(argc, argv, map_parse_fd);
1234004b45c0SQuentin Monnet if (!err && json_output)
1235004b45c0SQuentin Monnet jsonw_null(json_wtr);
1236004b45c0SQuentin Monnet return err;
123771bb428fSJakub Kicinski }
123871bb428fSJakub Kicinski
do_create(int argc,char ** argv)12390b592b5aSJakub Kicinski static int do_create(int argc, char **argv)
12400b592b5aSJakub Kicinski {
1241a15d408bSAndrii Nakryiko LIBBPF_OPTS(bpf_map_create_opts, attr);
1242a15d408bSAndrii Nakryiko enum bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
1243a15d408bSAndrii Nakryiko __u32 key_size = 0, value_size = 0, max_entries = 0;
1244a15d408bSAndrii Nakryiko const char *map_name = NULL;
12450b592b5aSJakub Kicinski const char *pinfile;
1246e3b9626fSQuentin Monnet int err = -1, fd;
12470b592b5aSJakub Kicinski
12480b592b5aSJakub Kicinski if (!REQ_ARGS(7))
12490b592b5aSJakub Kicinski return -1;
12500b592b5aSJakub Kicinski pinfile = GET_ARG();
12510b592b5aSJakub Kicinski
12520b592b5aSJakub Kicinski while (argc) {
12530b592b5aSJakub Kicinski if (!REQ_ARGS(2))
12540b592b5aSJakub Kicinski return -1;
12550b592b5aSJakub Kicinski
12560b592b5aSJakub Kicinski if (is_prefix(*argv, "type")) {
12570b592b5aSJakub Kicinski NEXT_ARG();
12580b592b5aSJakub Kicinski
1259a15d408bSAndrii Nakryiko if (map_type) {
12600b592b5aSJakub Kicinski p_err("map type already specified");
1261e3b9626fSQuentin Monnet goto exit;
12620b592b5aSJakub Kicinski }
12630b592b5aSJakub Kicinski
1264a15d408bSAndrii Nakryiko map_type = map_type_from_str(*argv);
1265a15d408bSAndrii Nakryiko if ((int)map_type < 0) {
12660b592b5aSJakub Kicinski p_err("unrecognized map type: %s", *argv);
1267e3b9626fSQuentin Monnet goto exit;
12680b592b5aSJakub Kicinski }
12690b592b5aSJakub Kicinski NEXT_ARG();
12700b592b5aSJakub Kicinski } else if (is_prefix(*argv, "name")) {
12710b592b5aSJakub Kicinski NEXT_ARG();
1272a15d408bSAndrii Nakryiko map_name = GET_ARG();
12730b592b5aSJakub Kicinski } else if (is_prefix(*argv, "key")) {
1274a15d408bSAndrii Nakryiko if (parse_u32_arg(&argc, &argv, &key_size,
12750b592b5aSJakub Kicinski "key size"))
1276e3b9626fSQuentin Monnet goto exit;
12770b592b5aSJakub Kicinski } else if (is_prefix(*argv, "value")) {
1278a15d408bSAndrii Nakryiko if (parse_u32_arg(&argc, &argv, &value_size,
12790b592b5aSJakub Kicinski "value size"))
1280e3b9626fSQuentin Monnet goto exit;
12810b592b5aSJakub Kicinski } else if (is_prefix(*argv, "entries")) {
1282a15d408bSAndrii Nakryiko if (parse_u32_arg(&argc, &argv, &max_entries,
12830b592b5aSJakub Kicinski "max entries"))
1284e3b9626fSQuentin Monnet goto exit;
12850b592b5aSJakub Kicinski } else if (is_prefix(*argv, "flags")) {
12860b592b5aSJakub Kicinski if (parse_u32_arg(&argc, &argv, &attr.map_flags,
12870b592b5aSJakub Kicinski "flags"))
1288e3b9626fSQuentin Monnet goto exit;
12890b592b5aSJakub Kicinski } else if (is_prefix(*argv, "dev")) {
1290*f46392eeSLarysa Zaremba p_info("Warning: 'bpftool map create [...] dev <ifname>' syntax is deprecated.\n"
1291*f46392eeSLarysa Zaremba "Going further, please use 'offload_dev <ifname>' to request hardware offload for the map.");
1292*f46392eeSLarysa Zaremba goto offload_dev;
1293*f46392eeSLarysa Zaremba } else if (is_prefix(*argv, "offload_dev")) {
1294*f46392eeSLarysa Zaremba offload_dev:
12950b592b5aSJakub Kicinski NEXT_ARG();
12960b592b5aSJakub Kicinski
12970b592b5aSJakub Kicinski if (attr.map_ifindex) {
12980b592b5aSJakub Kicinski p_err("offload device already specified");
1299e3b9626fSQuentin Monnet goto exit;
13000b592b5aSJakub Kicinski }
13010b592b5aSJakub Kicinski
13020b592b5aSJakub Kicinski attr.map_ifindex = if_nametoindex(*argv);
13030b592b5aSJakub Kicinski if (!attr.map_ifindex) {
13040b592b5aSJakub Kicinski p_err("unrecognized netdevice '%s': %s",
13050b592b5aSJakub Kicinski *argv, strerror(errno));
1306e3b9626fSQuentin Monnet goto exit;
13070b592b5aSJakub Kicinski }
13080b592b5aSJakub Kicinski NEXT_ARG();
1309e3b9626fSQuentin Monnet } else if (is_prefix(*argv, "inner_map")) {
1310e3b9626fSQuentin Monnet struct bpf_map_info info = {};
1311e3b9626fSQuentin Monnet __u32 len = sizeof(info);
1312e3b9626fSQuentin Monnet int inner_map_fd;
1313e3b9626fSQuentin Monnet
1314e3b9626fSQuentin Monnet NEXT_ARG();
1315e3b9626fSQuentin Monnet if (!REQ_ARGS(2))
1316e3b9626fSQuentin Monnet usage();
1317e3b9626fSQuentin Monnet inner_map_fd = map_parse_fd_and_info(&argc, &argv,
1318e3b9626fSQuentin Monnet &info, &len);
1319e3b9626fSQuentin Monnet if (inner_map_fd < 0)
1320e3b9626fSQuentin Monnet return -1;
1321e3b9626fSQuentin Monnet attr.inner_map_fd = inner_map_fd;
13228694d8c1SAlban Crequy } else {
13238694d8c1SAlban Crequy p_err("unknown arg %s", *argv);
1324e3b9626fSQuentin Monnet goto exit;
13250b592b5aSJakub Kicinski }
13260b592b5aSJakub Kicinski }
13270b592b5aSJakub Kicinski
1328a15d408bSAndrii Nakryiko if (!map_name) {
13290b592b5aSJakub Kicinski p_err("map name not specified");
1330e3b9626fSQuentin Monnet goto exit;
13310b592b5aSJakub Kicinski }
13320b592b5aSJakub Kicinski
13336b4384ffSQuentin Monnet set_max_rlimit();
13346b4384ffSQuentin Monnet
1335a15d408bSAndrii Nakryiko fd = bpf_map_create(map_type, map_name, key_size, value_size, max_entries, &attr);
13360b592b5aSJakub Kicinski if (fd < 0) {
13370b592b5aSJakub Kicinski p_err("map create failed: %s", strerror(errno));
1338e3b9626fSQuentin Monnet goto exit;
13390b592b5aSJakub Kicinski }
13400b592b5aSJakub Kicinski
13410b592b5aSJakub Kicinski err = do_pin_fd(fd, pinfile);
13420b592b5aSJakub Kicinski close(fd);
13430b592b5aSJakub Kicinski if (err)
1344e3b9626fSQuentin Monnet goto exit;
13450b592b5aSJakub Kicinski
13460b592b5aSJakub Kicinski if (json_output)
13470b592b5aSJakub Kicinski jsonw_null(json_wtr);
1348e3b9626fSQuentin Monnet
1349e3b9626fSQuentin Monnet exit:
1350e3b9626fSQuentin Monnet if (attr.inner_map_fd > 0)
1351e3b9626fSQuentin Monnet close(attr.inner_map_fd);
1352e3b9626fSQuentin Monnet
1353e3b9626fSQuentin Monnet return err;
13540b592b5aSJakub Kicinski }
13550b592b5aSJakub Kicinski
do_pop_dequeue(int argc,char ** argv)135674f312efSStanislav Fomichev static int do_pop_dequeue(int argc, char **argv)
135774f312efSStanislav Fomichev {
135874f312efSStanislav Fomichev struct bpf_map_info info = {};
135974f312efSStanislav Fomichev __u32 len = sizeof(info);
136074f312efSStanislav Fomichev void *key, *value;
136174f312efSStanislav Fomichev int err;
136274f312efSStanislav Fomichev int fd;
136374f312efSStanislav Fomichev
136474f312efSStanislav Fomichev if (argc < 2)
136574f312efSStanislav Fomichev usage();
136674f312efSStanislav Fomichev
136774f312efSStanislav Fomichev fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
136874f312efSStanislav Fomichev if (fd < 0)
136974f312efSStanislav Fomichev return -1;
137074f312efSStanislav Fomichev
137174f312efSStanislav Fomichev err = alloc_key_value(&info, &key, &value);
137274f312efSStanislav Fomichev if (err)
137374f312efSStanislav Fomichev goto exit_free;
137474f312efSStanislav Fomichev
137574f312efSStanislav Fomichev err = bpf_map_lookup_and_delete_elem(fd, key, value);
137674f312efSStanislav Fomichev if (err) {
137774f312efSStanislav Fomichev if (errno == ENOENT) {
137874f312efSStanislav Fomichev if (json_output)
137974f312efSStanislav Fomichev jsonw_null(json_wtr);
138074f312efSStanislav Fomichev else
138174f312efSStanislav Fomichev printf("Error: empty map\n");
138274f312efSStanislav Fomichev } else {
138374f312efSStanislav Fomichev p_err("pop failed: %s", strerror(errno));
138474f312efSStanislav Fomichev }
138574f312efSStanislav Fomichev
138674f312efSStanislav Fomichev goto exit_free;
138774f312efSStanislav Fomichev }
138874f312efSStanislav Fomichev
138974f312efSStanislav Fomichev print_key_value(&info, key, value);
139074f312efSStanislav Fomichev
139174f312efSStanislav Fomichev exit_free:
139274f312efSStanislav Fomichev free(key);
139374f312efSStanislav Fomichev free(value);
139474f312efSStanislav Fomichev close(fd);
139574f312efSStanislav Fomichev
139674f312efSStanislav Fomichev return err;
139774f312efSStanislav Fomichev }
139874f312efSStanislav Fomichev
do_freeze(int argc,char ** argv)13990bb52b0dSQuentin Monnet static int do_freeze(int argc, char **argv)
14000bb52b0dSQuentin Monnet {
14010bb52b0dSQuentin Monnet int err, fd;
14020bb52b0dSQuentin Monnet
14030bb52b0dSQuentin Monnet if (!REQ_ARGS(2))
14040bb52b0dSQuentin Monnet return -1;
14050bb52b0dSQuentin Monnet
14060bb52b0dSQuentin Monnet fd = map_parse_fd(&argc, &argv);
14070bb52b0dSQuentin Monnet if (fd < 0)
14080bb52b0dSQuentin Monnet return -1;
14090bb52b0dSQuentin Monnet
14100bb52b0dSQuentin Monnet if (argc) {
14110bb52b0dSQuentin Monnet close(fd);
14120bb52b0dSQuentin Monnet return BAD_ARG();
14130bb52b0dSQuentin Monnet }
14140bb52b0dSQuentin Monnet
14150bb52b0dSQuentin Monnet err = bpf_map_freeze(fd);
14160bb52b0dSQuentin Monnet close(fd);
14170bb52b0dSQuentin Monnet if (err) {
14180bb52b0dSQuentin Monnet p_err("failed to freeze map: %s", strerror(errno));
14190bb52b0dSQuentin Monnet return err;
14200bb52b0dSQuentin Monnet }
14210bb52b0dSQuentin Monnet
14220bb52b0dSQuentin Monnet if (json_output)
14230bb52b0dSQuentin Monnet jsonw_null(json_wtr);
14240bb52b0dSQuentin Monnet
14250bb52b0dSQuentin Monnet return 0;
14260bb52b0dSQuentin Monnet }
14270bb52b0dSQuentin Monnet
do_help(int argc,char ** argv)142871bb428fSJakub Kicinski static int do_help(int argc, char **argv)
142971bb428fSJakub Kicinski {
1430004b45c0SQuentin Monnet if (json_output) {
1431004b45c0SQuentin Monnet jsonw_null(json_wtr);
1432004b45c0SQuentin Monnet return 0;
1433004b45c0SQuentin Monnet }
1434004b45c0SQuentin Monnet
143571bb428fSJakub Kicinski fprintf(stderr,
143690040351SQuentin Monnet "Usage: %1$s %2$s { show | list } [MAP]\n"
143790040351SQuentin Monnet " %1$s %2$s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
14380b592b5aSJakub Kicinski " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
1439*f46392eeSLarysa Zaremba " [inner_map MAP] [offload_dev NAME]\n"
144090040351SQuentin Monnet " %1$s %2$s dump MAP\n"
144190040351SQuentin Monnet " %1$s %2$s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
144290040351SQuentin Monnet " %1$s %2$s lookup MAP [key DATA]\n"
144390040351SQuentin Monnet " %1$s %2$s getnext MAP [key DATA]\n"
144490040351SQuentin Monnet " %1$s %2$s delete MAP key DATA\n"
144590040351SQuentin Monnet " %1$s %2$s pin MAP FILE\n"
144690040351SQuentin Monnet " %1$s %2$s event_pipe MAP [cpu N index M]\n"
144790040351SQuentin Monnet " %1$s %2$s peek MAP\n"
144890040351SQuentin Monnet " %1$s %2$s push MAP value VALUE\n"
144990040351SQuentin Monnet " %1$s %2$s pop MAP\n"
145090040351SQuentin Monnet " %1$s %2$s enqueue MAP value VALUE\n"
145190040351SQuentin Monnet " %1$s %2$s dequeue MAP\n"
145290040351SQuentin Monnet " %1$s %2$s freeze MAP\n"
145390040351SQuentin Monnet " %1$s %2$s help\n"
145471bb428fSJakub Kicinski "\n"
14553ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n"
1456c642ea26SJakub Kicinski " DATA := { [hex] BYTES }\n"
145771bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n"
1458c642ea26SJakub Kicinski " VALUE := { DATA | MAP | PROG }\n"
145971bb428fSJakub Kicinski " UPDATE_FLAGS := { any | exist | noexist }\n"
14600b592b5aSJakub Kicinski " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
14610b592b5aSJakub Kicinski " percpu_array | stack_trace | cgroup_array | lru_hash |\n"
14620b592b5aSJakub Kicinski " lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
14631375dc4aSToke Høiland-Jørgensen " devmap | devmap_hash | sockmap | cpumap | xskmap | sockhash |\n"
1464c8caa0bbSQuentin Monnet " cgroup_storage | reuseport_sockarray | percpu_cgroup_storage |\n"
1465864ab061SKP Singh " queue | stack | sk_storage | struct_ops | ringbuf | inode_storage |\n"
1466f7f0f165SYonghong Song " task_storage | bloom_filter | user_ringbuf | cgrp_storage }\n"
1467c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n"
1468c07ba629SQuentin Monnet " {-f|--bpffs} | {-n|--nomount} }\n"
146971bb428fSJakub Kicinski "",
14700bb52b0dSQuentin Monnet bin_name, argv[-2]);
147171bb428fSJakub Kicinski
147271bb428fSJakub Kicinski return 0;
147371bb428fSJakub Kicinski }
147471bb428fSJakub Kicinski
147571bb428fSJakub Kicinski static const struct cmd cmds[] = {
147671bb428fSJakub Kicinski { "show", do_show },
14776ebe6dbdSJakub Kicinski { "list", do_show },
147871bb428fSJakub Kicinski { "help", do_help },
147971bb428fSJakub Kicinski { "dump", do_dump },
148071bb428fSJakub Kicinski { "update", do_update },
148171bb428fSJakub Kicinski { "lookup", do_lookup },
148271bb428fSJakub Kicinski { "getnext", do_getnext },
148371bb428fSJakub Kicinski { "delete", do_delete },
148471bb428fSJakub Kicinski { "pin", do_pin },
1485f412eed9SJakub Kicinski { "event_pipe", do_event_pipe },
14860b592b5aSJakub Kicinski { "create", do_create },
148766cf6e0bSStanislav Fomichev { "peek", do_lookup },
1488549d4d3dSStanislav Fomichev { "push", do_update },
1489549d4d3dSStanislav Fomichev { "enqueue", do_update },
149074f312efSStanislav Fomichev { "pop", do_pop_dequeue },
149174f312efSStanislav Fomichev { "dequeue", do_pop_dequeue },
14920bb52b0dSQuentin Monnet { "freeze", do_freeze },
149371bb428fSJakub Kicinski { 0 }
149471bb428fSJakub Kicinski };
149571bb428fSJakub Kicinski
do_map(int argc,char ** argv)149671bb428fSJakub Kicinski int do_map(int argc, char **argv)
149771bb428fSJakub Kicinski {
149871bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help);
149971bb428fSJakub Kicinski }
1500