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