Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
0003 
0004 #include <assert.h>
0005 #include <errno.h>
0006 #include <fcntl.h>
0007 #include <linux/err.h>
0008 #include <linux/kernel.h>
0009 #include <net/if.h>
0010 #include <stdbool.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <string.h>
0014 #include <unistd.h>
0015 #include <sys/types.h>
0016 #include <sys/stat.h>
0017 
0018 #include <bpf/bpf.h>
0019 #include <bpf/btf.h>
0020 #include <bpf/hashmap.h>
0021 
0022 #include "json_writer.h"
0023 #include "main.h"
0024 
0025 static struct hashmap *map_table;
0026 
0027 static bool map_is_per_cpu(__u32 type)
0028 {
0029     return type == BPF_MAP_TYPE_PERCPU_HASH ||
0030            type == BPF_MAP_TYPE_PERCPU_ARRAY ||
0031            type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
0032            type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
0033 }
0034 
0035 static bool map_is_map_of_maps(__u32 type)
0036 {
0037     return type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
0038            type == BPF_MAP_TYPE_HASH_OF_MAPS;
0039 }
0040 
0041 static bool map_is_map_of_progs(__u32 type)
0042 {
0043     return type == BPF_MAP_TYPE_PROG_ARRAY;
0044 }
0045 
0046 static int map_type_from_str(const char *type)
0047 {
0048     const char *map_type_str;
0049     unsigned int i;
0050 
0051     for (i = 0; ; i++) {
0052         map_type_str = libbpf_bpf_map_type_str(i);
0053         if (!map_type_str)
0054             break;
0055 
0056         /* Don't allow prefixing in case of possible future shadowing */
0057         if (!strcmp(map_type_str, type))
0058             return i;
0059     }
0060     return -1;
0061 }
0062 
0063 static void *alloc_value(struct bpf_map_info *info)
0064 {
0065     if (map_is_per_cpu(info->type))
0066         return malloc(round_up(info->value_size, 8) *
0067                   get_possible_cpus());
0068     else
0069         return malloc(info->value_size);
0070 }
0071 
0072 static int do_dump_btf(const struct btf_dumper *d,
0073                struct bpf_map_info *map_info, void *key,
0074                void *value)
0075 {
0076     __u32 value_id;
0077     int ret = 0;
0078 
0079     /* start of key-value pair */
0080     jsonw_start_object(d->jw);
0081 
0082     if (map_info->btf_key_type_id) {
0083         jsonw_name(d->jw, "key");
0084 
0085         ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
0086         if (ret)
0087             goto err_end_obj;
0088     }
0089 
0090     value_id = map_info->btf_vmlinux_value_type_id ?
0091         : map_info->btf_value_type_id;
0092 
0093     if (!map_is_per_cpu(map_info->type)) {
0094         jsonw_name(d->jw, "value");
0095         ret = btf_dumper_type(d, value_id, value);
0096     } else {
0097         unsigned int i, n, step;
0098 
0099         jsonw_name(d->jw, "values");
0100         jsonw_start_array(d->jw);
0101         n = get_possible_cpus();
0102         step = round_up(map_info->value_size, 8);
0103         for (i = 0; i < n; i++) {
0104             jsonw_start_object(d->jw);
0105             jsonw_int_field(d->jw, "cpu", i);
0106             jsonw_name(d->jw, "value");
0107             ret = btf_dumper_type(d, value_id, value + i * step);
0108             jsonw_end_object(d->jw);
0109             if (ret)
0110                 break;
0111         }
0112         jsonw_end_array(d->jw);
0113     }
0114 
0115 err_end_obj:
0116     /* end of key-value pair */
0117     jsonw_end_object(d->jw);
0118 
0119     return ret;
0120 }
0121 
0122 static json_writer_t *get_btf_writer(void)
0123 {
0124     json_writer_t *jw = jsonw_new(stdout);
0125 
0126     if (!jw)
0127         return NULL;
0128     jsonw_pretty(jw, true);
0129 
0130     return jw;
0131 }
0132 
0133 static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
0134                  unsigned char *value, struct btf *btf)
0135 {
0136     jsonw_start_object(json_wtr);
0137 
0138     if (!map_is_per_cpu(info->type)) {
0139         jsonw_name(json_wtr, "key");
0140         print_hex_data_json(key, info->key_size);
0141         jsonw_name(json_wtr, "value");
0142         print_hex_data_json(value, info->value_size);
0143         if (btf) {
0144             struct btf_dumper d = {
0145                 .btf = btf,
0146                 .jw = json_wtr,
0147                 .is_plain_text = false,
0148             };
0149 
0150             jsonw_name(json_wtr, "formatted");
0151             do_dump_btf(&d, info, key, value);
0152         }
0153     } else {
0154         unsigned int i, n, step;
0155 
0156         n = get_possible_cpus();
0157         step = round_up(info->value_size, 8);
0158 
0159         jsonw_name(json_wtr, "key");
0160         print_hex_data_json(key, info->key_size);
0161 
0162         jsonw_name(json_wtr, "values");
0163         jsonw_start_array(json_wtr);
0164         for (i = 0; i < n; i++) {
0165             jsonw_start_object(json_wtr);
0166 
0167             jsonw_int_field(json_wtr, "cpu", i);
0168 
0169             jsonw_name(json_wtr, "value");
0170             print_hex_data_json(value + i * step,
0171                         info->value_size);
0172 
0173             jsonw_end_object(json_wtr);
0174         }
0175         jsonw_end_array(json_wtr);
0176         if (btf) {
0177             struct btf_dumper d = {
0178                 .btf = btf,
0179                 .jw = json_wtr,
0180                 .is_plain_text = false,
0181             };
0182 
0183             jsonw_name(json_wtr, "formatted");
0184             do_dump_btf(&d, info, key, value);
0185         }
0186     }
0187 
0188     jsonw_end_object(json_wtr);
0189 }
0190 
0191 static void
0192 print_entry_error_msg(struct bpf_map_info *info, unsigned char *key,
0193               const char *error_msg)
0194 {
0195     int msg_size = strlen(error_msg);
0196     bool single_line, break_names;
0197 
0198     break_names = info->key_size > 16 || msg_size > 16;
0199     single_line = info->key_size + msg_size <= 24 && !break_names;
0200 
0201     printf("key:%c", break_names ? '\n' : ' ');
0202     fprint_hex(stdout, key, info->key_size, " ");
0203 
0204     printf(single_line ? "  " : "\n");
0205 
0206     printf("value:%c%s", break_names ? '\n' : ' ', error_msg);
0207 
0208     printf("\n");
0209 }
0210 
0211 static void
0212 print_entry_error(struct bpf_map_info *map_info, void *key, int lookup_errno)
0213 {
0214     /* For prog_array maps or arrays of maps, failure to lookup the value
0215      * means there is no entry for that key. Do not print an error message
0216      * in that case.
0217      */
0218     if ((map_is_map_of_maps(map_info->type) ||
0219          map_is_map_of_progs(map_info->type)) && lookup_errno == ENOENT)
0220         return;
0221 
0222     if (json_output) {
0223         jsonw_start_object(json_wtr);   /* entry */
0224         jsonw_name(json_wtr, "key");
0225         print_hex_data_json(key, map_info->key_size);
0226         jsonw_name(json_wtr, "value");
0227         jsonw_start_object(json_wtr);   /* error */
0228         jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
0229         jsonw_end_object(json_wtr); /* error */
0230         jsonw_end_object(json_wtr); /* entry */
0231     } else {
0232         const char *msg = NULL;
0233 
0234         if (lookup_errno == ENOENT)
0235             msg = "<no entry>";
0236         else if (lookup_errno == ENOSPC &&
0237              map_info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
0238             msg = "<cannot read>";
0239 
0240         print_entry_error_msg(map_info, key,
0241                       msg ? : strerror(lookup_errno));
0242     }
0243 }
0244 
0245 static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
0246                   unsigned char *value)
0247 {
0248     if (!map_is_per_cpu(info->type)) {
0249         bool single_line, break_names;
0250 
0251         break_names = info->key_size > 16 || info->value_size > 16;
0252         single_line = info->key_size + info->value_size <= 24 &&
0253             !break_names;
0254 
0255         if (info->key_size) {
0256             printf("key:%c", break_names ? '\n' : ' ');
0257             fprint_hex(stdout, key, info->key_size, " ");
0258 
0259             printf(single_line ? "  " : "\n");
0260         }
0261 
0262         if (info->value_size) {
0263             printf("value:%c", break_names ? '\n' : ' ');
0264             fprint_hex(stdout, value, info->value_size, " ");
0265         }
0266 
0267         printf("\n");
0268     } else {
0269         unsigned int i, n, step;
0270 
0271         n = get_possible_cpus();
0272         step = round_up(info->value_size, 8);
0273 
0274         if (info->key_size) {
0275             printf("key:\n");
0276             fprint_hex(stdout, key, info->key_size, " ");
0277             printf("\n");
0278         }
0279         if (info->value_size) {
0280             for (i = 0; i < n; i++) {
0281                 printf("value (CPU %02d):%c",
0282                        i, info->value_size > 16 ? '\n' : ' ');
0283                 fprint_hex(stdout, value + i * step,
0284                        info->value_size, " ");
0285                 printf("\n");
0286             }
0287         }
0288     }
0289 }
0290 
0291 static char **parse_bytes(char **argv, const char *name, unsigned char *val,
0292               unsigned int n)
0293 {
0294     unsigned int i = 0, base = 0;
0295     char *endptr;
0296 
0297     if (is_prefix(*argv, "hex")) {
0298         base = 16;
0299         argv++;
0300     }
0301 
0302     while (i < n && argv[i]) {
0303         val[i] = strtoul(argv[i], &endptr, base);
0304         if (*endptr) {
0305             p_err("error parsing byte: %s", argv[i]);
0306             return NULL;
0307         }
0308         i++;
0309     }
0310 
0311     if (i != n) {
0312         p_err("%s expected %d bytes got %d", name, n, i);
0313         return NULL;
0314     }
0315 
0316     return argv + i;
0317 }
0318 
0319 /* on per cpu maps we must copy the provided value on all value instances */
0320 static void fill_per_cpu_value(struct bpf_map_info *info, void *value)
0321 {
0322     unsigned int i, n, step;
0323 
0324     if (!map_is_per_cpu(info->type))
0325         return;
0326 
0327     n = get_possible_cpus();
0328     step = round_up(info->value_size, 8);
0329     for (i = 1; i < n; i++)
0330         memcpy(value + i * step, value, info->value_size);
0331 }
0332 
0333 static int parse_elem(char **argv, struct bpf_map_info *info,
0334               void *key, void *value, __u32 key_size, __u32 value_size,
0335               __u32 *flags, __u32 **value_fd)
0336 {
0337     if (!*argv) {
0338         if (!key && !value)
0339             return 0;
0340         p_err("did not find %s", key ? "key" : "value");
0341         return -1;
0342     }
0343 
0344     if (is_prefix(*argv, "key")) {
0345         if (!key) {
0346             if (key_size)
0347                 p_err("duplicate key");
0348             else
0349                 p_err("unnecessary key");
0350             return -1;
0351         }
0352 
0353         argv = parse_bytes(argv + 1, "key", key, key_size);
0354         if (!argv)
0355             return -1;
0356 
0357         return parse_elem(argv, info, NULL, value, key_size, value_size,
0358                   flags, value_fd);
0359     } else if (is_prefix(*argv, "value")) {
0360         int fd;
0361 
0362         if (!value) {
0363             if (value_size)
0364                 p_err("duplicate value");
0365             else
0366                 p_err("unnecessary value");
0367             return -1;
0368         }
0369 
0370         argv++;
0371 
0372         if (map_is_map_of_maps(info->type)) {
0373             int argc = 2;
0374 
0375             if (value_size != 4) {
0376                 p_err("value smaller than 4B for map in map?");
0377                 return -1;
0378             }
0379             if (!argv[0] || !argv[1]) {
0380                 p_err("not enough value arguments for map in map");
0381                 return -1;
0382             }
0383 
0384             fd = map_parse_fd(&argc, &argv);
0385             if (fd < 0)
0386                 return -1;
0387 
0388             *value_fd = value;
0389             **value_fd = fd;
0390         } else if (map_is_map_of_progs(info->type)) {
0391             int argc = 2;
0392 
0393             if (value_size != 4) {
0394                 p_err("value smaller than 4B for map of progs?");
0395                 return -1;
0396             }
0397             if (!argv[0] || !argv[1]) {
0398                 p_err("not enough value arguments for map of progs");
0399                 return -1;
0400             }
0401             if (is_prefix(*argv, "id"))
0402                 p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
0403                        "         by some process or pinned otherwise update will be lost");
0404 
0405             fd = prog_parse_fd(&argc, &argv);
0406             if (fd < 0)
0407                 return -1;
0408 
0409             *value_fd = value;
0410             **value_fd = fd;
0411         } else {
0412             argv = parse_bytes(argv, "value", value, value_size);
0413             if (!argv)
0414                 return -1;
0415 
0416             fill_per_cpu_value(info, value);
0417         }
0418 
0419         return parse_elem(argv, info, key, NULL, key_size, value_size,
0420                   flags, NULL);
0421     } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
0422            is_prefix(*argv, "exist")) {
0423         if (!flags) {
0424             p_err("flags specified multiple times: %s", *argv);
0425             return -1;
0426         }
0427 
0428         if (is_prefix(*argv, "any"))
0429             *flags = BPF_ANY;
0430         else if (is_prefix(*argv, "noexist"))
0431             *flags = BPF_NOEXIST;
0432         else if (is_prefix(*argv, "exist"))
0433             *flags = BPF_EXIST;
0434 
0435         return parse_elem(argv + 1, info, key, value, key_size,
0436                   value_size, NULL, value_fd);
0437     }
0438 
0439     p_err("expected key or value, got: %s", *argv);
0440     return -1;
0441 }
0442 
0443 static void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
0444 {
0445     const char *map_type_str;
0446 
0447     jsonw_uint_field(wtr, "id", info->id);
0448     map_type_str = libbpf_bpf_map_type_str(info->type);
0449     if (map_type_str)
0450         jsonw_string_field(wtr, "type", map_type_str);
0451     else
0452         jsonw_uint_field(wtr, "type", info->type);
0453 
0454     if (*info->name)
0455         jsonw_string_field(wtr, "name", info->name);
0456 
0457     jsonw_name(wtr, "flags");
0458     jsonw_printf(wtr, "%d", info->map_flags);
0459 }
0460 
0461 static int show_map_close_json(int fd, struct bpf_map_info *info)
0462 {
0463     char *memlock, *frozen_str;
0464     int frozen = 0;
0465 
0466     memlock = get_fdinfo(fd, "memlock");
0467     frozen_str = get_fdinfo(fd, "frozen");
0468 
0469     jsonw_start_object(json_wtr);
0470 
0471     show_map_header_json(info, json_wtr);
0472 
0473     print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
0474 
0475     jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
0476     jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
0477     jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
0478 
0479     if (memlock)
0480         jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock));
0481     free(memlock);
0482 
0483     if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
0484         char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
0485         char *owner_jited = get_fdinfo(fd, "owner_jited");
0486 
0487         if (owner_prog_type) {
0488             unsigned int prog_type = atoi(owner_prog_type);
0489             const char *prog_type_str;
0490 
0491             prog_type_str = libbpf_bpf_prog_type_str(prog_type);
0492             if (prog_type_str)
0493                 jsonw_string_field(json_wtr, "owner_prog_type",
0494                            prog_type_str);
0495             else
0496                 jsonw_uint_field(json_wtr, "owner_prog_type",
0497                          prog_type);
0498         }
0499         if (owner_jited)
0500             jsonw_bool_field(json_wtr, "owner_jited",
0501                      !!atoi(owner_jited));
0502 
0503         free(owner_prog_type);
0504         free(owner_jited);
0505     }
0506     close(fd);
0507 
0508     if (frozen_str) {
0509         frozen = atoi(frozen_str);
0510         free(frozen_str);
0511     }
0512     jsonw_int_field(json_wtr, "frozen", frozen);
0513 
0514     if (info->btf_id)
0515         jsonw_int_field(json_wtr, "btf_id", info->btf_id);
0516 
0517     if (!hashmap__empty(map_table)) {
0518         struct hashmap_entry *entry;
0519 
0520         jsonw_name(json_wtr, "pinned");
0521         jsonw_start_array(json_wtr);
0522         hashmap__for_each_key_entry(map_table, entry,
0523                         u32_as_hash_field(info->id))
0524             jsonw_string(json_wtr, entry->value);
0525         jsonw_end_array(json_wtr);
0526     }
0527 
0528     emit_obj_refs_json(refs_table, info->id, json_wtr);
0529 
0530     jsonw_end_object(json_wtr);
0531 
0532     return 0;
0533 }
0534 
0535 static void show_map_header_plain(struct bpf_map_info *info)
0536 {
0537     const char *map_type_str;
0538 
0539     printf("%u: ", info->id);
0540 
0541     map_type_str = libbpf_bpf_map_type_str(info->type);
0542     if (map_type_str)
0543         printf("%s  ", map_type_str);
0544     else
0545         printf("type %u  ", info->type);
0546 
0547     if (*info->name)
0548         printf("name %s  ", info->name);
0549 
0550     printf("flags 0x%x", info->map_flags);
0551     print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
0552     printf("\n");
0553 }
0554 
0555 static int show_map_close_plain(int fd, struct bpf_map_info *info)
0556 {
0557     char *memlock, *frozen_str;
0558     int frozen = 0;
0559 
0560     memlock = get_fdinfo(fd, "memlock");
0561     frozen_str = get_fdinfo(fd, "frozen");
0562 
0563     show_map_header_plain(info);
0564     printf("\tkey %uB  value %uB  max_entries %u",
0565            info->key_size, info->value_size, info->max_entries);
0566 
0567     if (memlock)
0568         printf("  memlock %sB", memlock);
0569     free(memlock);
0570 
0571     if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
0572         char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
0573         char *owner_jited = get_fdinfo(fd, "owner_jited");
0574 
0575         if (owner_prog_type || owner_jited)
0576             printf("\n\t");
0577         if (owner_prog_type) {
0578             unsigned int prog_type = atoi(owner_prog_type);
0579             const char *prog_type_str;
0580 
0581             prog_type_str = libbpf_bpf_prog_type_str(prog_type);
0582             if (prog_type_str)
0583                 printf("owner_prog_type %s  ", prog_type_str);
0584             else
0585                 printf("owner_prog_type %d  ", prog_type);
0586         }
0587         if (owner_jited)
0588             printf("owner%s jited",
0589                    atoi(owner_jited) ? "" : " not");
0590 
0591         free(owner_prog_type);
0592         free(owner_jited);
0593     }
0594     close(fd);
0595 
0596     if (!hashmap__empty(map_table)) {
0597         struct hashmap_entry *entry;
0598 
0599         hashmap__for_each_key_entry(map_table, entry,
0600                         u32_as_hash_field(info->id))
0601             printf("\n\tpinned %s", (char *)entry->value);
0602     }
0603 
0604     if (frozen_str) {
0605         frozen = atoi(frozen_str);
0606         free(frozen_str);
0607     }
0608 
0609     if (info->btf_id || frozen)
0610         printf("\n\t");
0611 
0612     if (info->btf_id)
0613         printf("btf_id %d", info->btf_id);
0614 
0615     if (frozen)
0616         printf("%sfrozen", info->btf_id ? "  " : "");
0617 
0618     emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
0619 
0620     printf("\n");
0621     return 0;
0622 }
0623 
0624 static int do_show_subset(int argc, char **argv)
0625 {
0626     struct bpf_map_info info = {};
0627     __u32 len = sizeof(info);
0628     int *fds = NULL;
0629     int nb_fds, i;
0630     int err = -1;
0631 
0632     fds = malloc(sizeof(int));
0633     if (!fds) {
0634         p_err("mem alloc failed");
0635         return -1;
0636     }
0637     nb_fds = map_parse_fds(&argc, &argv, &fds);
0638     if (nb_fds < 1)
0639         goto exit_free;
0640 
0641     if (json_output && nb_fds > 1)
0642         jsonw_start_array(json_wtr);    /* root array */
0643     for (i = 0; i < nb_fds; i++) {
0644         err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
0645         if (err) {
0646             p_err("can't get map info: %s",
0647                   strerror(errno));
0648             for (; i < nb_fds; i++)
0649                 close(fds[i]);
0650             break;
0651         }
0652 
0653         if (json_output)
0654             show_map_close_json(fds[i], &info);
0655         else
0656             show_map_close_plain(fds[i], &info);
0657 
0658         close(fds[i]);
0659     }
0660     if (json_output && nb_fds > 1)
0661         jsonw_end_array(json_wtr);  /* root array */
0662 
0663 exit_free:
0664     free(fds);
0665     return err;
0666 }
0667 
0668 static int do_show(int argc, char **argv)
0669 {
0670     struct bpf_map_info info = {};
0671     __u32 len = sizeof(info);
0672     __u32 id = 0;
0673     int err;
0674     int fd;
0675 
0676     if (show_pinned) {
0677         map_table = hashmap__new(hash_fn_for_key_as_id,
0678                      equal_fn_for_key_as_id, NULL);
0679         if (IS_ERR(map_table)) {
0680             p_err("failed to create hashmap for pinned paths");
0681             return -1;
0682         }
0683         build_pinned_obj_table(map_table, BPF_OBJ_MAP);
0684     }
0685     build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
0686 
0687     if (argc == 2)
0688         return do_show_subset(argc, argv);
0689 
0690     if (argc)
0691         return BAD_ARG();
0692 
0693     if (json_output)
0694         jsonw_start_array(json_wtr);
0695     while (true) {
0696         err = bpf_map_get_next_id(id, &id);
0697         if (err) {
0698             if (errno == ENOENT)
0699                 break;
0700             p_err("can't get next map: %s%s", strerror(errno),
0701                   errno == EINVAL ? " -- kernel too old?" : "");
0702             break;
0703         }
0704 
0705         fd = bpf_map_get_fd_by_id(id);
0706         if (fd < 0) {
0707             if (errno == ENOENT)
0708                 continue;
0709             p_err("can't get map by id (%u): %s",
0710                   id, strerror(errno));
0711             break;
0712         }
0713 
0714         err = bpf_obj_get_info_by_fd(fd, &info, &len);
0715         if (err) {
0716             p_err("can't get map info: %s", strerror(errno));
0717             close(fd);
0718             break;
0719         }
0720 
0721         if (json_output)
0722             show_map_close_json(fd, &info);
0723         else
0724             show_map_close_plain(fd, &info);
0725     }
0726     if (json_output)
0727         jsonw_end_array(json_wtr);
0728 
0729     delete_obj_refs_table(refs_table);
0730 
0731     if (show_pinned)
0732         delete_pinned_obj_table(map_table);
0733 
0734     return errno == ENOENT ? 0 : -1;
0735 }
0736 
0737 static int dump_map_elem(int fd, void *key, void *value,
0738              struct bpf_map_info *map_info, struct btf *btf,
0739              json_writer_t *btf_wtr)
0740 {
0741     if (bpf_map_lookup_elem(fd, key, value)) {
0742         print_entry_error(map_info, key, errno);
0743         return -1;
0744     }
0745 
0746     if (json_output) {
0747         print_entry_json(map_info, key, value, btf);
0748     } else if (btf) {
0749         struct btf_dumper d = {
0750             .btf = btf,
0751             .jw = btf_wtr,
0752             .is_plain_text = true,
0753         };
0754 
0755         do_dump_btf(&d, map_info, key, value);
0756     } else {
0757         print_entry_plain(map_info, key, value);
0758     }
0759 
0760     return 0;
0761 }
0762 
0763 static int maps_have_btf(int *fds, int nb_fds)
0764 {
0765     struct bpf_map_info info = {};
0766     __u32 len = sizeof(info);
0767     int err, i;
0768 
0769     for (i = 0; i < nb_fds; i++) {
0770         err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
0771         if (err) {
0772             p_err("can't get map info: %s", strerror(errno));
0773             return -1;
0774         }
0775 
0776         if (!info.btf_id)
0777             return 0;
0778     }
0779 
0780     return 1;
0781 }
0782 
0783 static struct btf *btf_vmlinux;
0784 
0785 static int get_map_kv_btf(const struct bpf_map_info *info, struct btf **btf)
0786 {
0787     int err = 0;
0788 
0789     if (info->btf_vmlinux_value_type_id) {
0790         if (!btf_vmlinux) {
0791             btf_vmlinux = libbpf_find_kernel_btf();
0792             err = libbpf_get_error(btf_vmlinux);
0793             if (err) {
0794                 p_err("failed to get kernel btf");
0795                 return err;
0796             }
0797         }
0798         *btf = btf_vmlinux;
0799     } else if (info->btf_value_type_id) {
0800         *btf = btf__load_from_kernel_by_id(info->btf_id);
0801         err = libbpf_get_error(*btf);
0802         if (err)
0803             p_err("failed to get btf");
0804     } else {
0805         *btf = NULL;
0806     }
0807 
0808     return err;
0809 }
0810 
0811 static void free_map_kv_btf(struct btf *btf)
0812 {
0813     if (!libbpf_get_error(btf) && btf != btf_vmlinux)
0814         btf__free(btf);
0815 }
0816 
0817 static void free_btf_vmlinux(void)
0818 {
0819     if (!libbpf_get_error(btf_vmlinux))
0820         btf__free(btf_vmlinux);
0821 }
0822 
0823 static int
0824 map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
0825      bool show_header)
0826 {
0827     void *key, *value, *prev_key;
0828     unsigned int num_elems = 0;
0829     struct btf *btf = NULL;
0830     int err;
0831 
0832     key = malloc(info->key_size);
0833     value = alloc_value(info);
0834     if (!key || !value) {
0835         p_err("mem alloc failed");
0836         err = -1;
0837         goto exit_free;
0838     }
0839 
0840     prev_key = NULL;
0841 
0842     if (wtr) {
0843         err = get_map_kv_btf(info, &btf);
0844         if (err) {
0845             goto exit_free;
0846         }
0847 
0848         if (show_header) {
0849             jsonw_start_object(wtr);    /* map object */
0850             show_map_header_json(info, wtr);
0851             jsonw_name(wtr, "elements");
0852         }
0853         jsonw_start_array(wtr);     /* elements */
0854     } else if (show_header) {
0855         show_map_header_plain(info);
0856     }
0857 
0858     if (info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
0859         info->value_size != 8) {
0860         const char *map_type_str;
0861 
0862         map_type_str = libbpf_bpf_map_type_str(info->type);
0863         p_info("Warning: cannot read values from %s map with value_size != 8",
0864                map_type_str);
0865     }
0866     while (true) {
0867         err = bpf_map_get_next_key(fd, prev_key, key);
0868         if (err) {
0869             if (errno == ENOENT)
0870                 err = 0;
0871             break;
0872         }
0873         if (!dump_map_elem(fd, key, value, info, btf, wtr))
0874             num_elems++;
0875         prev_key = key;
0876     }
0877 
0878     if (wtr) {
0879         jsonw_end_array(wtr);   /* elements */
0880         if (show_header)
0881             jsonw_end_object(wtr);  /* map object */
0882     } else {
0883         printf("Found %u element%s\n", num_elems,
0884                num_elems != 1 ? "s" : "");
0885     }
0886 
0887 exit_free:
0888     free(key);
0889     free(value);
0890     close(fd);
0891     free_map_kv_btf(btf);
0892 
0893     return err;
0894 }
0895 
0896 static int do_dump(int argc, char **argv)
0897 {
0898     json_writer_t *wtr = NULL, *btf_wtr = NULL;
0899     struct bpf_map_info info = {};
0900     int nb_fds, i = 0;
0901     __u32 len = sizeof(info);
0902     int *fds = NULL;
0903     int err = -1;
0904 
0905     if (argc != 2)
0906         usage();
0907 
0908     fds = malloc(sizeof(int));
0909     if (!fds) {
0910         p_err("mem alloc failed");
0911         return -1;
0912     }
0913     nb_fds = map_parse_fds(&argc, &argv, &fds);
0914     if (nb_fds < 1)
0915         goto exit_free;
0916 
0917     if (json_output) {
0918         wtr = json_wtr;
0919     } else {
0920         int do_plain_btf;
0921 
0922         do_plain_btf = maps_have_btf(fds, nb_fds);
0923         if (do_plain_btf < 0)
0924             goto exit_close;
0925 
0926         if (do_plain_btf) {
0927             btf_wtr = get_btf_writer();
0928             wtr = btf_wtr;
0929             if (!btf_wtr)
0930                 p_info("failed to create json writer for btf. falling back to plain output");
0931         }
0932     }
0933 
0934     if (wtr && nb_fds > 1)
0935         jsonw_start_array(wtr); /* root array */
0936     for (i = 0; i < nb_fds; i++) {
0937         if (bpf_obj_get_info_by_fd(fds[i], &info, &len)) {
0938             p_err("can't get map info: %s", strerror(errno));
0939             break;
0940         }
0941         err = map_dump(fds[i], &info, wtr, nb_fds > 1);
0942         if (!wtr && i != nb_fds - 1)
0943             printf("\n");
0944 
0945         if (err)
0946             break;
0947         close(fds[i]);
0948     }
0949     if (wtr && nb_fds > 1)
0950         jsonw_end_array(wtr);   /* root array */
0951 
0952     if (btf_wtr)
0953         jsonw_destroy(&btf_wtr);
0954 exit_close:
0955     for (; i < nb_fds; i++)
0956         close(fds[i]);
0957 exit_free:
0958     free(fds);
0959     free_btf_vmlinux();
0960     return err;
0961 }
0962 
0963 static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
0964 {
0965     *key = NULL;
0966     *value = NULL;
0967 
0968     if (info->key_size) {
0969         *key = malloc(info->key_size);
0970         if (!*key) {
0971             p_err("key mem alloc failed");
0972             return -1;
0973         }
0974     }
0975 
0976     if (info->value_size) {
0977         *value = alloc_value(info);
0978         if (!*value) {
0979             p_err("value mem alloc failed");
0980             free(*key);
0981             *key = NULL;
0982             return -1;
0983         }
0984     }
0985 
0986     return 0;
0987 }
0988 
0989 static int do_update(int argc, char **argv)
0990 {
0991     struct bpf_map_info info = {};
0992     __u32 len = sizeof(info);
0993     __u32 *value_fd = NULL;
0994     __u32 flags = BPF_ANY;
0995     void *key, *value;
0996     int fd, err;
0997 
0998     if (argc < 2)
0999         usage();
1000 
1001     fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1002     if (fd < 0)
1003         return -1;
1004 
1005     err = alloc_key_value(&info, &key, &value);
1006     if (err)
1007         goto exit_free;
1008 
1009     err = parse_elem(argv, &info, key, value, info.key_size,
1010              info.value_size, &flags, &value_fd);
1011     if (err)
1012         goto exit_free;
1013 
1014     err = bpf_map_update_elem(fd, key, value, flags);
1015     if (err) {
1016         p_err("update failed: %s", strerror(errno));
1017         goto exit_free;
1018     }
1019 
1020 exit_free:
1021     if (value_fd)
1022         close(*value_fd);
1023     free(key);
1024     free(value);
1025     close(fd);
1026 
1027     if (!err && json_output)
1028         jsonw_null(json_wtr);
1029     return err;
1030 }
1031 
1032 static void print_key_value(struct bpf_map_info *info, void *key,
1033                 void *value)
1034 {
1035     json_writer_t *btf_wtr;
1036     struct btf *btf;
1037 
1038     if (get_map_kv_btf(info, &btf))
1039         return;
1040 
1041     if (json_output) {
1042         print_entry_json(info, key, value, btf);
1043     } else if (btf) {
1044         /* if here json_wtr wouldn't have been initialised,
1045          * so let's create separate writer for btf
1046          */
1047         btf_wtr = get_btf_writer();
1048         if (!btf_wtr) {
1049             p_info("failed to create json writer for btf. falling back to plain output");
1050             btf__free(btf);
1051             btf = NULL;
1052             print_entry_plain(info, key, value);
1053         } else {
1054             struct btf_dumper d = {
1055                 .btf = btf,
1056                 .jw = btf_wtr,
1057                 .is_plain_text = true,
1058             };
1059 
1060             do_dump_btf(&d, info, key, value);
1061             jsonw_destroy(&btf_wtr);
1062         }
1063     } else {
1064         print_entry_plain(info, key, value);
1065     }
1066     btf__free(btf);
1067 }
1068 
1069 static int do_lookup(int argc, char **argv)
1070 {
1071     struct bpf_map_info info = {};
1072     __u32 len = sizeof(info);
1073     void *key, *value;
1074     int err;
1075     int fd;
1076 
1077     if (argc < 2)
1078         usage();
1079 
1080     fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1081     if (fd < 0)
1082         return -1;
1083 
1084     err = alloc_key_value(&info, &key, &value);
1085     if (err)
1086         goto exit_free;
1087 
1088     err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
1089     if (err)
1090         goto exit_free;
1091 
1092     err = bpf_map_lookup_elem(fd, key, value);
1093     if (err) {
1094         if (errno == ENOENT) {
1095             if (json_output) {
1096                 jsonw_null(json_wtr);
1097             } else {
1098                 printf("key:\n");
1099                 fprint_hex(stdout, key, info.key_size, " ");
1100                 printf("\n\nNot found\n");
1101             }
1102         } else {
1103             p_err("lookup failed: %s", strerror(errno));
1104         }
1105 
1106         goto exit_free;
1107     }
1108 
1109     /* here means bpf_map_lookup_elem() succeeded */
1110     print_key_value(&info, key, value);
1111 
1112 exit_free:
1113     free(key);
1114     free(value);
1115     close(fd);
1116 
1117     return err;
1118 }
1119 
1120 static int do_getnext(int argc, char **argv)
1121 {
1122     struct bpf_map_info info = {};
1123     __u32 len = sizeof(info);
1124     void *key, *nextkey;
1125     int err;
1126     int fd;
1127 
1128     if (argc < 2)
1129         usage();
1130 
1131     fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1132     if (fd < 0)
1133         return -1;
1134 
1135     key = malloc(info.key_size);
1136     nextkey = malloc(info.key_size);
1137     if (!key || !nextkey) {
1138         p_err("mem alloc failed");
1139         err = -1;
1140         goto exit_free;
1141     }
1142 
1143     if (argc) {
1144         err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
1145                  NULL, NULL);
1146         if (err)
1147             goto exit_free;
1148     } else {
1149         free(key);
1150         key = NULL;
1151     }
1152 
1153     err = bpf_map_get_next_key(fd, key, nextkey);
1154     if (err) {
1155         p_err("can't get next key: %s", strerror(errno));
1156         goto exit_free;
1157     }
1158 
1159     if (json_output) {
1160         jsonw_start_object(json_wtr);
1161         if (key) {
1162             jsonw_name(json_wtr, "key");
1163             print_hex_data_json(key, info.key_size);
1164         } else {
1165             jsonw_null_field(json_wtr, "key");
1166         }
1167         jsonw_name(json_wtr, "next_key");
1168         print_hex_data_json(nextkey, info.key_size);
1169         jsonw_end_object(json_wtr);
1170     } else {
1171         if (key) {
1172             printf("key:\n");
1173             fprint_hex(stdout, key, info.key_size, " ");
1174             printf("\n");
1175         } else {
1176             printf("key: None\n");
1177         }
1178         printf("next key:\n");
1179         fprint_hex(stdout, nextkey, info.key_size, " ");
1180         printf("\n");
1181     }
1182 
1183 exit_free:
1184     free(nextkey);
1185     free(key);
1186     close(fd);
1187 
1188     return err;
1189 }
1190 
1191 static int do_delete(int argc, char **argv)
1192 {
1193     struct bpf_map_info info = {};
1194     __u32 len = sizeof(info);
1195     void *key;
1196     int err;
1197     int fd;
1198 
1199     if (argc < 2)
1200         usage();
1201 
1202     fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1203     if (fd < 0)
1204         return -1;
1205 
1206     key = malloc(info.key_size);
1207     if (!key) {
1208         p_err("mem alloc failed");
1209         err = -1;
1210         goto exit_free;
1211     }
1212 
1213     err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
1214     if (err)
1215         goto exit_free;
1216 
1217     err = bpf_map_delete_elem(fd, key);
1218     if (err)
1219         p_err("delete failed: %s", strerror(errno));
1220 
1221 exit_free:
1222     free(key);
1223     close(fd);
1224 
1225     if (!err && json_output)
1226         jsonw_null(json_wtr);
1227     return err;
1228 }
1229 
1230 static int do_pin(int argc, char **argv)
1231 {
1232     int err;
1233 
1234     err = do_pin_any(argc, argv, map_parse_fd);
1235     if (!err && json_output)
1236         jsonw_null(json_wtr);
1237     return err;
1238 }
1239 
1240 static int do_create(int argc, char **argv)
1241 {
1242     LIBBPF_OPTS(bpf_map_create_opts, attr);
1243     enum bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
1244     __u32 key_size = 0, value_size = 0, max_entries = 0;
1245     const char *map_name = NULL;
1246     const char *pinfile;
1247     int err = -1, fd;
1248 
1249     if (!REQ_ARGS(7))
1250         return -1;
1251     pinfile = GET_ARG();
1252 
1253     while (argc) {
1254         if (!REQ_ARGS(2))
1255             return -1;
1256 
1257         if (is_prefix(*argv, "type")) {
1258             NEXT_ARG();
1259 
1260             if (map_type) {
1261                 p_err("map type already specified");
1262                 goto exit;
1263             }
1264 
1265             map_type = map_type_from_str(*argv);
1266             if ((int)map_type < 0) {
1267                 p_err("unrecognized map type: %s", *argv);
1268                 goto exit;
1269             }
1270             NEXT_ARG();
1271         } else if (is_prefix(*argv, "name")) {
1272             NEXT_ARG();
1273             map_name = GET_ARG();
1274         } else if (is_prefix(*argv, "key")) {
1275             if (parse_u32_arg(&argc, &argv, &key_size,
1276                       "key size"))
1277                 goto exit;
1278         } else if (is_prefix(*argv, "value")) {
1279             if (parse_u32_arg(&argc, &argv, &value_size,
1280                       "value size"))
1281                 goto exit;
1282         } else if (is_prefix(*argv, "entries")) {
1283             if (parse_u32_arg(&argc, &argv, &max_entries,
1284                       "max entries"))
1285                 goto exit;
1286         } else if (is_prefix(*argv, "flags")) {
1287             if (parse_u32_arg(&argc, &argv, &attr.map_flags,
1288                       "flags"))
1289                 goto exit;
1290         } else if (is_prefix(*argv, "dev")) {
1291             NEXT_ARG();
1292 
1293             if (attr.map_ifindex) {
1294                 p_err("offload device already specified");
1295                 goto exit;
1296             }
1297 
1298             attr.map_ifindex = if_nametoindex(*argv);
1299             if (!attr.map_ifindex) {
1300                 p_err("unrecognized netdevice '%s': %s",
1301                       *argv, strerror(errno));
1302                 goto exit;
1303             }
1304             NEXT_ARG();
1305         } else if (is_prefix(*argv, "inner_map")) {
1306             struct bpf_map_info info = {};
1307             __u32 len = sizeof(info);
1308             int inner_map_fd;
1309 
1310             NEXT_ARG();
1311             if (!REQ_ARGS(2))
1312                 usage();
1313             inner_map_fd = map_parse_fd_and_info(&argc, &argv,
1314                                  &info, &len);
1315             if (inner_map_fd < 0)
1316                 return -1;
1317             attr.inner_map_fd = inner_map_fd;
1318         } else {
1319             p_err("unknown arg %s", *argv);
1320             goto exit;
1321         }
1322     }
1323 
1324     if (!map_name) {
1325         p_err("map name not specified");
1326         goto exit;
1327     }
1328 
1329     set_max_rlimit();
1330 
1331     fd = bpf_map_create(map_type, map_name, key_size, value_size, max_entries, &attr);
1332     if (fd < 0) {
1333         p_err("map create failed: %s", strerror(errno));
1334         goto exit;
1335     }
1336 
1337     err = do_pin_fd(fd, pinfile);
1338     close(fd);
1339     if (err)
1340         goto exit;
1341 
1342     if (json_output)
1343         jsonw_null(json_wtr);
1344 
1345 exit:
1346     if (attr.inner_map_fd > 0)
1347         close(attr.inner_map_fd);
1348 
1349     return err;
1350 }
1351 
1352 static int do_pop_dequeue(int argc, char **argv)
1353 {
1354     struct bpf_map_info info = {};
1355     __u32 len = sizeof(info);
1356     void *key, *value;
1357     int err;
1358     int fd;
1359 
1360     if (argc < 2)
1361         usage();
1362 
1363     fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
1364     if (fd < 0)
1365         return -1;
1366 
1367     err = alloc_key_value(&info, &key, &value);
1368     if (err)
1369         goto exit_free;
1370 
1371     err = bpf_map_lookup_and_delete_elem(fd, key, value);
1372     if (err) {
1373         if (errno == ENOENT) {
1374             if (json_output)
1375                 jsonw_null(json_wtr);
1376             else
1377                 printf("Error: empty map\n");
1378         } else {
1379             p_err("pop failed: %s", strerror(errno));
1380         }
1381 
1382         goto exit_free;
1383     }
1384 
1385     print_key_value(&info, key, value);
1386 
1387 exit_free:
1388     free(key);
1389     free(value);
1390     close(fd);
1391 
1392     return err;
1393 }
1394 
1395 static int do_freeze(int argc, char **argv)
1396 {
1397     int err, fd;
1398 
1399     if (!REQ_ARGS(2))
1400         return -1;
1401 
1402     fd = map_parse_fd(&argc, &argv);
1403     if (fd < 0)
1404         return -1;
1405 
1406     if (argc) {
1407         close(fd);
1408         return BAD_ARG();
1409     }
1410 
1411     err = bpf_map_freeze(fd);
1412     close(fd);
1413     if (err) {
1414         p_err("failed to freeze map: %s", strerror(errno));
1415         return err;
1416     }
1417 
1418     if (json_output)
1419         jsonw_null(json_wtr);
1420 
1421     return 0;
1422 }
1423 
1424 static int do_help(int argc, char **argv)
1425 {
1426     if (json_output) {
1427         jsonw_null(json_wtr);
1428         return 0;
1429     }
1430 
1431     fprintf(stderr,
1432         "Usage: %1$s %2$s { show | list }   [MAP]\n"
1433         "       %1$s %2$s create     FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
1434         "                                  entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
1435         "                                  [inner_map MAP] [dev NAME]\n"
1436         "       %1$s %2$s dump       MAP\n"
1437         "       %1$s %2$s update     MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
1438         "       %1$s %2$s lookup     MAP [key DATA]\n"
1439         "       %1$s %2$s getnext    MAP [key DATA]\n"
1440         "       %1$s %2$s delete     MAP  key DATA\n"
1441         "       %1$s %2$s pin        MAP  FILE\n"
1442         "       %1$s %2$s event_pipe MAP [cpu N index M]\n"
1443         "       %1$s %2$s peek       MAP\n"
1444         "       %1$s %2$s push       MAP value VALUE\n"
1445         "       %1$s %2$s pop        MAP\n"
1446         "       %1$s %2$s enqueue    MAP value VALUE\n"
1447         "       %1$s %2$s dequeue    MAP\n"
1448         "       %1$s %2$s freeze     MAP\n"
1449         "       %1$s %2$s help\n"
1450         "\n"
1451         "       " HELP_SPEC_MAP "\n"
1452         "       DATA := { [hex] BYTES }\n"
1453         "       " HELP_SPEC_PROGRAM "\n"
1454         "       VALUE := { DATA | MAP | PROG }\n"
1455         "       UPDATE_FLAGS := { any | exist | noexist }\n"
1456         "       TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
1457         "                 percpu_array | stack_trace | cgroup_array | lru_hash |\n"
1458         "                 lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
1459         "                 devmap | devmap_hash | sockmap | cpumap | xskmap | sockhash |\n"
1460         "                 cgroup_storage | reuseport_sockarray | percpu_cgroup_storage |\n"
1461         "                 queue | stack | sk_storage | struct_ops | ringbuf | inode_storage |\n"
1462         "                 task_storage | bloom_filter }\n"
1463         "       " HELP_SPEC_OPTIONS " |\n"
1464         "                    {-f|--bpffs} | {-n|--nomount} }\n"
1465         "",
1466         bin_name, argv[-2]);
1467 
1468     return 0;
1469 }
1470 
1471 static const struct cmd cmds[] = {
1472     { "show",   do_show },
1473     { "list",   do_show },
1474     { "help",   do_help },
1475     { "dump",   do_dump },
1476     { "update", do_update },
1477     { "lookup", do_lookup },
1478     { "getnext",    do_getnext },
1479     { "delete", do_delete },
1480     { "pin",    do_pin },
1481     { "event_pipe", do_event_pipe },
1482     { "create", do_create },
1483     { "peek",   do_lookup },
1484     { "push",   do_update },
1485     { "enqueue",    do_update },
1486     { "pop",    do_pop_dequeue },
1487     { "dequeue",    do_pop_dequeue },
1488     { "freeze", do_freeze },
1489     { 0 }
1490 };
1491 
1492 int do_map(int argc, char **argv)
1493 {
1494     return cmd_select(cmds, argc, argv, do_help);
1495 }