2018-12-13 11:59:25 +08:00
|
|
|
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
|
|
/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
#include <linux/err.h>
|
2018-07-30 23:49:03 +08:00
|
|
|
#include <linux/kernel.h>
|
2018-10-16 07:30:36 +08:00
|
|
|
#include <net/if.h>
|
2017-10-05 11:10:04 +08:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <bpf.h>
|
|
|
|
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
#include "btf.h"
|
|
|
|
#include "json_writer.h"
|
2017-10-05 11:10:04 +08:00
|
|
|
#include "main.h"
|
|
|
|
|
2019-01-17 23:27:54 +08:00
|
|
|
const char * const map_type_name[] = {
|
2018-11-24 07:58:39 +08:00
|
|
|
[BPF_MAP_TYPE_UNSPEC] = "unspec",
|
|
|
|
[BPF_MAP_TYPE_HASH] = "hash",
|
|
|
|
[BPF_MAP_TYPE_ARRAY] = "array",
|
|
|
|
[BPF_MAP_TYPE_PROG_ARRAY] = "prog_array",
|
|
|
|
[BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array",
|
|
|
|
[BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash",
|
|
|
|
[BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array",
|
|
|
|
[BPF_MAP_TYPE_STACK_TRACE] = "stack_trace",
|
|
|
|
[BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array",
|
|
|
|
[BPF_MAP_TYPE_LRU_HASH] = "lru_hash",
|
|
|
|
[BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash",
|
|
|
|
[BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie",
|
|
|
|
[BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps",
|
|
|
|
[BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps",
|
|
|
|
[BPF_MAP_TYPE_DEVMAP] = "devmap",
|
|
|
|
[BPF_MAP_TYPE_SOCKMAP] = "sockmap",
|
|
|
|
[BPF_MAP_TYPE_CPUMAP] = "cpumap",
|
|
|
|
[BPF_MAP_TYPE_XSKMAP] = "xskmap",
|
|
|
|
[BPF_MAP_TYPE_SOCKHASH] = "sockhash",
|
|
|
|
[BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage",
|
|
|
|
[BPF_MAP_TYPE_REUSEPORT_SOCKARRAY] = "reuseport_sockarray",
|
2018-09-28 22:45:51 +08:00
|
|
|
[BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE] = "percpu_cgroup_storage",
|
2018-11-24 07:58:39 +08:00
|
|
|
[BPF_MAP_TYPE_QUEUE] = "queue",
|
|
|
|
[BPF_MAP_TYPE_STACK] = "stack",
|
2017-10-05 11:10:04 +08:00
|
|
|
};
|
|
|
|
|
2019-01-17 23:27:54 +08:00
|
|
|
const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
static bool map_is_per_cpu(__u32 type)
|
|
|
|
{
|
|
|
|
return type == BPF_MAP_TYPE_PERCPU_HASH ||
|
|
|
|
type == BPF_MAP_TYPE_PERCPU_ARRAY ||
|
2018-09-28 22:45:51 +08:00
|
|
|
type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
|
|
|
|
type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool map_is_map_of_maps(__u32 type)
|
|
|
|
{
|
|
|
|
return type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
|
|
|
|
type == BPF_MAP_TYPE_HASH_OF_MAPS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool map_is_map_of_progs(__u32 type)
|
|
|
|
{
|
|
|
|
return type == BPF_MAP_TYPE_PROG_ARRAY;
|
|
|
|
}
|
|
|
|
|
2018-10-16 07:30:36 +08:00
|
|
|
static int map_type_from_str(const char *type)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(map_type_name); i++)
|
|
|
|
/* Don't allow prefixing in case of possible future shadowing */
|
|
|
|
if (map_type_name[i] && !strcmp(map_type_name[i], type))
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
static void *alloc_value(struct bpf_map_info *info)
|
|
|
|
{
|
|
|
|
if (map_is_per_cpu(info->type))
|
2018-07-30 23:49:03 +08:00
|
|
|
return malloc(round_up(info->value_size, 8) *
|
|
|
|
get_possible_cpus());
|
2017-10-05 11:10:04 +08:00
|
|
|
else
|
|
|
|
return malloc(info->value_size);
|
|
|
|
}
|
|
|
|
|
2018-07-11 05:43:07 +08:00
|
|
|
int map_parse_fd(int *argc, char ***argv)
|
2017-10-05 11:10:04 +08:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (is_prefix(**argv, "id")) {
|
|
|
|
unsigned int id;
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
id = strtoul(**argv, &endptr, 0);
|
|
|
|
if (*endptr) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("can't parse %s as ID", **argv);
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
fd = bpf_map_get_fd_by_id(id);
|
|
|
|
if (fd < 0)
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("get map by id (%u): %s", id, strerror(errno));
|
2017-10-05 11:10:04 +08:00
|
|
|
return fd;
|
|
|
|
} else if (is_prefix(**argv, "pinned")) {
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
path = **argv;
|
|
|
|
NEXT_ARGP();
|
|
|
|
|
|
|
|
return open_obj_pinned_any(path, BPF_OBJ_MAP);
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-05-04 09:37:16 +08:00
|
|
|
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
|
2017-10-05 11:10:04 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = map_parse_fd(argc, argv);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
err = bpf_obj_get_info_by_fd(fd, info, info_len);
|
|
|
|
if (err) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("can't get map info: %s", strerror(errno));
|
2017-10-05 11:10:04 +08:00
|
|
|
close(fd);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
static int do_dump_btf(const struct btf_dumper *d,
|
|
|
|
struct bpf_map_info *map_info, void *key,
|
|
|
|
void *value)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* start of key-value pair */
|
|
|
|
jsonw_start_object(d->jw);
|
|
|
|
|
|
|
|
jsonw_name(d->jw, "key");
|
|
|
|
|
|
|
|
ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
|
|
|
|
if (ret)
|
|
|
|
goto err_end_obj;
|
|
|
|
|
tools/bpf: bpftool: add btf percpu map formated dump
The btf pretty print is added to percpu arraymap,
percpu hashmap and percpu lru hashmap.
For each <key, value> pair, the following will be
added to plain/json output:
{
"key": <pretty_print_key>,
"values": [{
"cpu": 0,
"value": <pretty_print_value_on_cpu0>
},{
"cpu": 1,
"value": <pretty_print_value_on_cpu1>
},{
....
},{
"cpu": n,
"value": <pretty_print_value_on_cpun>
}
]
}
For example, the following could be part of plain or json formatted
output:
{
"key": 0,
"values": [{
"cpu": 0,
"value": {
"ui32": 0,
"ui16": 0,
}
},{
"cpu": 1,
"value": {
"ui32": 1,
"ui16": 0,
}
},{
"cpu": 2,
"value": {
"ui32": 2,
"ui16": 0,
}
},{
"cpu": 3,
"value": {
"ui32": 3,
"ui16": 0,
}
}
]
}
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-08-30 05:43:15 +08:00
|
|
|
if (!map_is_per_cpu(map_info->type)) {
|
|
|
|
jsonw_name(d->jw, "value");
|
|
|
|
ret = btf_dumper_type(d, map_info->btf_value_type_id, value);
|
|
|
|
} else {
|
|
|
|
unsigned int i, n, step;
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
|
tools/bpf: bpftool: add btf percpu map formated dump
The btf pretty print is added to percpu arraymap,
percpu hashmap and percpu lru hashmap.
For each <key, value> pair, the following will be
added to plain/json output:
{
"key": <pretty_print_key>,
"values": [{
"cpu": 0,
"value": <pretty_print_value_on_cpu0>
},{
"cpu": 1,
"value": <pretty_print_value_on_cpu1>
},{
....
},{
"cpu": n,
"value": <pretty_print_value_on_cpun>
}
]
}
For example, the following could be part of plain or json formatted
output:
{
"key": 0,
"values": [{
"cpu": 0,
"value": {
"ui32": 0,
"ui16": 0,
}
},{
"cpu": 1,
"value": {
"ui32": 1,
"ui16": 0,
}
},{
"cpu": 2,
"value": {
"ui32": 2,
"ui16": 0,
}
},{
"cpu": 3,
"value": {
"ui32": 3,
"ui16": 0,
}
}
]
}
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-08-30 05:43:15 +08:00
|
|
|
jsonw_name(d->jw, "values");
|
|
|
|
jsonw_start_array(d->jw);
|
|
|
|
n = get_possible_cpus();
|
|
|
|
step = round_up(map_info->value_size, 8);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
jsonw_start_object(d->jw);
|
|
|
|
jsonw_int_field(d->jw, "cpu", i);
|
|
|
|
jsonw_name(d->jw, "value");
|
|
|
|
ret = btf_dumper_type(d, map_info->btf_value_type_id,
|
|
|
|
value + i * step);
|
|
|
|
jsonw_end_object(d->jw);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
jsonw_end_array(d->jw);
|
|
|
|
}
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
|
|
|
|
err_end_obj:
|
|
|
|
/* end of key-value pair */
|
|
|
|
jsonw_end_object(d->jw);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static json_writer_t *get_btf_writer(void)
|
|
|
|
{
|
|
|
|
json_writer_t *jw = jsonw_new(stdout);
|
|
|
|
|
|
|
|
if (!jw)
|
|
|
|
return NULL;
|
|
|
|
jsonw_pretty(jw, true);
|
|
|
|
|
|
|
|
return jw;
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
unsigned char *value, struct btf *btf)
|
2017-10-24 00:24:11 +08:00
|
|
|
{
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
|
|
|
|
if (!map_is_per_cpu(info->type)) {
|
|
|
|
jsonw_name(json_wtr, "key");
|
|
|
|
print_hex_data_json(key, info->key_size);
|
|
|
|
jsonw_name(json_wtr, "value");
|
|
|
|
print_hex_data_json(value, info->value_size);
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
if (btf) {
|
|
|
|
struct btf_dumper d = {
|
|
|
|
.btf = btf,
|
|
|
|
.jw = json_wtr,
|
|
|
|
.is_plain_text = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "formatted");
|
|
|
|
do_dump_btf(&d, info, key, value);
|
|
|
|
}
|
2017-10-24 00:24:11 +08:00
|
|
|
} else {
|
2018-07-30 23:49:03 +08:00
|
|
|
unsigned int i, n, step;
|
2017-10-24 00:24:11 +08:00
|
|
|
|
|
|
|
n = get_possible_cpus();
|
2018-07-30 23:49:03 +08:00
|
|
|
step = round_up(info->value_size, 8);
|
2017-10-24 00:24:11 +08:00
|
|
|
|
|
|
|
jsonw_name(json_wtr, "key");
|
|
|
|
print_hex_data_json(key, info->key_size);
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "values");
|
|
|
|
jsonw_start_array(json_wtr);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
|
|
|
|
jsonw_int_field(json_wtr, "cpu", i);
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "value");
|
2018-07-30 23:49:03 +08:00
|
|
|
print_hex_data_json(value + i * step,
|
2017-10-24 00:24:11 +08:00
|
|
|
info->value_size);
|
|
|
|
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
}
|
|
|
|
jsonw_end_array(json_wtr);
|
tools/bpf: bpftool: add btf percpu map formated dump
The btf pretty print is added to percpu arraymap,
percpu hashmap and percpu lru hashmap.
For each <key, value> pair, the following will be
added to plain/json output:
{
"key": <pretty_print_key>,
"values": [{
"cpu": 0,
"value": <pretty_print_value_on_cpu0>
},{
"cpu": 1,
"value": <pretty_print_value_on_cpu1>
},{
....
},{
"cpu": n,
"value": <pretty_print_value_on_cpun>
}
]
}
For example, the following could be part of plain or json formatted
output:
{
"key": 0,
"values": [{
"cpu": 0,
"value": {
"ui32": 0,
"ui16": 0,
}
},{
"cpu": 1,
"value": {
"ui32": 1,
"ui16": 0,
}
},{
"cpu": 2,
"value": {
"ui32": 2,
"ui16": 0,
}
},{
"cpu": 3,
"value": {
"ui32": 3,
"ui16": 0,
}
}
]
}
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-08-30 05:43:15 +08:00
|
|
|
if (btf) {
|
|
|
|
struct btf_dumper d = {
|
|
|
|
.btf = btf,
|
|
|
|
.jw = json_wtr,
|
|
|
|
.is_plain_text = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "formatted");
|
|
|
|
do_dump_btf(&d, info, key, value);
|
|
|
|
}
|
2017-10-24 00:24:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
}
|
|
|
|
|
tools/bpf: bpftool, print strerror when map lookup error occurs
Since map lookup error can be ENOENT or EOPNOTSUPP, let's print
strerror() as error message in normal and JSON output.
This patch adds helper function print_entry_error() to print
entry from lookup error occurs
Example: Following example dumps a map which does not support lookup.
Output before:
root# bpftool map -jp dump id 40
[
"key": ["0x0a","0x00","0x00","0x00"
],
"value": {
"error": "can\'t lookup element"
},
"key": ["0x0b","0x00","0x00","0x00"
],
"value": {
"error": "can\'t lookup element"
}
]
root# bpftool map dump id 40
can't lookup element with key:
0a 00 00 00
can't lookup element with key:
0b 00 00 00
Found 0 elements
Output after changes:
root# bpftool map dump -jp id 45
[
"key": ["0x0a","0x00","0x00","0x00"
],
"value": {
"error": "Operation not supported"
},
"key": ["0x0b","0x00","0x00","0x00"
],
"value": {
"error": "Operation not supported"
}
]
root# bpftool map dump id 45
key:
0a 00 00 00
value:
Operation not supported
key:
0b 00 00 00
value:
Operation not supported
Found 0 elements
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-10-09 09:04:52 +08:00
|
|
|
static void print_entry_error(struct bpf_map_info *info, unsigned char *key,
|
|
|
|
const char *value)
|
|
|
|
{
|
|
|
|
int value_size = strlen(value);
|
|
|
|
bool single_line, break_names;
|
|
|
|
|
|
|
|
break_names = info->key_size > 16 || value_size > 16;
|
|
|
|
single_line = info->key_size + value_size <= 24 && !break_names;
|
|
|
|
|
|
|
|
printf("key:%c", break_names ? '\n' : ' ');
|
|
|
|
fprint_hex(stdout, key, info->key_size, " ");
|
|
|
|
|
|
|
|
printf(single_line ? " " : "\n");
|
|
|
|
|
|
|
|
printf("value:%c%s", break_names ? '\n' : ' ', value);
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
|
|
|
|
unsigned char *value)
|
2017-10-05 11:10:04 +08:00
|
|
|
{
|
|
|
|
if (!map_is_per_cpu(info->type)) {
|
|
|
|
bool single_line, break_names;
|
|
|
|
|
|
|
|
break_names = info->key_size > 16 || info->value_size > 16;
|
|
|
|
single_line = info->key_size + info->value_size <= 24 &&
|
|
|
|
!break_names;
|
|
|
|
|
2019-01-17 03:10:01 +08:00
|
|
|
if (info->key_size) {
|
|
|
|
printf("key:%c", break_names ? '\n' : ' ');
|
|
|
|
fprint_hex(stdout, key, info->key_size, " ");
|
2017-10-05 11:10:04 +08:00
|
|
|
|
2019-01-17 03:10:01 +08:00
|
|
|
printf(single_line ? " " : "\n");
|
|
|
|
}
|
2017-10-05 11:10:04 +08:00
|
|
|
|
2019-01-17 03:10:01 +08:00
|
|
|
if (info->value_size) {
|
|
|
|
printf("value:%c", break_names ? '\n' : ' ');
|
|
|
|
if (value)
|
|
|
|
fprint_hex(stdout, value, info->value_size,
|
|
|
|
" ");
|
|
|
|
else
|
|
|
|
printf("<no entry>");
|
|
|
|
}
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
} else {
|
2018-07-30 23:49:03 +08:00
|
|
|
unsigned int i, n, step;
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
n = get_possible_cpus();
|
2018-07-30 23:49:03 +08:00
|
|
|
step = round_up(info->value_size, 8);
|
2017-10-05 11:10:04 +08:00
|
|
|
|
2019-01-17 03:10:01 +08:00
|
|
|
if (info->key_size) {
|
|
|
|
printf("key:\n");
|
|
|
|
fprint_hex(stdout, key, info->key_size, " ");
|
2017-10-05 11:10:04 +08:00
|
|
|
printf("\n");
|
|
|
|
}
|
2019-01-17 03:10:01 +08:00
|
|
|
if (info->value_size) {
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
printf("value (CPU %02d):%c",
|
|
|
|
i, info->value_size > 16 ? '\n' : ' ');
|
|
|
|
if (value)
|
|
|
|
fprint_hex(stdout, value + i * step,
|
|
|
|
info->value_size, " ");
|
|
|
|
else
|
|
|
|
printf("<no entry>");
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char **parse_bytes(char **argv, const char *name, unsigned char *val,
|
|
|
|
unsigned int n)
|
|
|
|
{
|
tools: bpftool: make it easier to feed hex bytes to bpftool
bpftool uses hexadecimal values when it dumps map contents:
# bpftool map dump id 1337
key: ff 13 37 ff value: a1 b2 c3 d4 ff ff ff ff
Found 1 element
In order to lookup or update values with bpftool, the natural reflex is
then to copy and paste the values to the command line, and to try to run
something like:
# bpftool map update id 1337 key ff 13 37 ff \
value 00 00 00 00 00 00 1a 2b
Error: error parsing byte: ff
bpftool complains, because it uses strtoul() with a 0 base to parse the
bytes, and that without a "0x" prefix, the bytes are considered as
decimal values (or even octal if they start with "0").
To feed hexadecimal values instead, one needs to add "0x" prefixes
everywhere necessary:
# bpftool map update id 1337 key 0xff 0x13 0x37 0xff \
value 0 0 0 0 0 0 0x1a 0x2b
To make it easier to use hexadecimal values, add an optional "hex"
keyword to put after "key" or "value" to tell bpftool to consider the
digits as hexadecimal. We can now do:
# bpftool map update id 1337 key hex ff 13 37 ff \
value hex 0 0 0 0 0 0 1a 2b
Without the "hex" keyword, the bytes are still parsed according to
normal integer notation (decimal if no prefix, or hexadecimal or octal
if "0x" or "0" prefix is used, respectively).
The patch also add related documentation and bash completion for the
"hex" keyword.
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Suggested-by: David Beckett <david.beckett@netronome.com>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-04-18 10:46:34 +08:00
|
|
|
unsigned int i = 0, base = 0;
|
2017-10-05 11:10:04 +08:00
|
|
|
char *endptr;
|
|
|
|
|
tools: bpftool: make it easier to feed hex bytes to bpftool
bpftool uses hexadecimal values when it dumps map contents:
# bpftool map dump id 1337
key: ff 13 37 ff value: a1 b2 c3 d4 ff ff ff ff
Found 1 element
In order to lookup or update values with bpftool, the natural reflex is
then to copy and paste the values to the command line, and to try to run
something like:
# bpftool map update id 1337 key ff 13 37 ff \
value 00 00 00 00 00 00 1a 2b
Error: error parsing byte: ff
bpftool complains, because it uses strtoul() with a 0 base to parse the
bytes, and that without a "0x" prefix, the bytes are considered as
decimal values (or even octal if they start with "0").
To feed hexadecimal values instead, one needs to add "0x" prefixes
everywhere necessary:
# bpftool map update id 1337 key 0xff 0x13 0x37 0xff \
value 0 0 0 0 0 0 0x1a 0x2b
To make it easier to use hexadecimal values, add an optional "hex"
keyword to put after "key" or "value" to tell bpftool to consider the
digits as hexadecimal. We can now do:
# bpftool map update id 1337 key hex ff 13 37 ff \
value hex 0 0 0 0 0 0 1a 2b
Without the "hex" keyword, the bytes are still parsed according to
normal integer notation (decimal if no prefix, or hexadecimal or octal
if "0x" or "0" prefix is used, respectively).
The patch also add related documentation and bash completion for the
"hex" keyword.
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Suggested-by: David Beckett <david.beckett@netronome.com>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-04-18 10:46:34 +08:00
|
|
|
if (is_prefix(*argv, "hex")) {
|
|
|
|
base = 16;
|
|
|
|
argv++;
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
while (i < n && argv[i]) {
|
tools: bpftool: make it easier to feed hex bytes to bpftool
bpftool uses hexadecimal values when it dumps map contents:
# bpftool map dump id 1337
key: ff 13 37 ff value: a1 b2 c3 d4 ff ff ff ff
Found 1 element
In order to lookup or update values with bpftool, the natural reflex is
then to copy and paste the values to the command line, and to try to run
something like:
# bpftool map update id 1337 key ff 13 37 ff \
value 00 00 00 00 00 00 1a 2b
Error: error parsing byte: ff
bpftool complains, because it uses strtoul() with a 0 base to parse the
bytes, and that without a "0x" prefix, the bytes are considered as
decimal values (or even octal if they start with "0").
To feed hexadecimal values instead, one needs to add "0x" prefixes
everywhere necessary:
# bpftool map update id 1337 key 0xff 0x13 0x37 0xff \
value 0 0 0 0 0 0 0x1a 0x2b
To make it easier to use hexadecimal values, add an optional "hex"
keyword to put after "key" or "value" to tell bpftool to consider the
digits as hexadecimal. We can now do:
# bpftool map update id 1337 key hex ff 13 37 ff \
value hex 0 0 0 0 0 0 1a 2b
Without the "hex" keyword, the bytes are still parsed according to
normal integer notation (decimal if no prefix, or hexadecimal or octal
if "0x" or "0" prefix is used, respectively).
The patch also add related documentation and bash completion for the
"hex" keyword.
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Suggested-by: David Beckett <david.beckett@netronome.com>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-04-18 10:46:34 +08:00
|
|
|
val[i] = strtoul(argv[i], &endptr, base);
|
2017-10-05 11:10:04 +08:00
|
|
|
if (*endptr) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("error parsing byte: %s", argv[i]);
|
2017-10-20 06:46:23 +08:00
|
|
|
return NULL;
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i != n) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("%s expected %d bytes got %d", name, n, i);
|
2017-10-05 11:10:04 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return argv + i;
|
|
|
|
}
|
|
|
|
|
2019-01-21 19:36:12 +08:00
|
|
|
/* on per cpu maps we must copy the provided value on all value instances */
|
|
|
|
static void fill_per_cpu_value(struct bpf_map_info *info, void *value)
|
|
|
|
{
|
|
|
|
unsigned int i, n, step;
|
|
|
|
|
|
|
|
if (!map_is_per_cpu(info->type))
|
|
|
|
return;
|
|
|
|
|
|
|
|
n = get_possible_cpus();
|
|
|
|
step = round_up(info->value_size, 8);
|
|
|
|
for (i = 1; i < n; i++)
|
|
|
|
memcpy(value + i * step, value, info->value_size);
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
static int parse_elem(char **argv, struct bpf_map_info *info,
|
|
|
|
void *key, void *value, __u32 key_size, __u32 value_size,
|
|
|
|
__u32 *flags, __u32 **value_fd)
|
|
|
|
{
|
|
|
|
if (!*argv) {
|
|
|
|
if (!key && !value)
|
|
|
|
return 0;
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("did not find %s", key ? "key" : "value");
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_prefix(*argv, "key")) {
|
|
|
|
if (!key) {
|
|
|
|
if (key_size)
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("duplicate key");
|
2017-10-05 11:10:04 +08:00
|
|
|
else
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("unnecessary key");
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
argv = parse_bytes(argv + 1, "key", key, key_size);
|
|
|
|
if (!argv)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return parse_elem(argv, info, NULL, value, key_size, value_size,
|
|
|
|
flags, value_fd);
|
|
|
|
} else if (is_prefix(*argv, "value")) {
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (!value) {
|
|
|
|
if (value_size)
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("duplicate value");
|
2017-10-05 11:10:04 +08:00
|
|
|
else
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("unnecessary value");
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
argv++;
|
|
|
|
|
|
|
|
if (map_is_map_of_maps(info->type)) {
|
|
|
|
int argc = 2;
|
|
|
|
|
|
|
|
if (value_size != 4) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("value smaller than 4B for map in map?");
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!argv[0] || !argv[1]) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("not enough value arguments for map in map");
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = map_parse_fd(&argc, &argv);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*value_fd = value;
|
|
|
|
**value_fd = fd;
|
|
|
|
} else if (map_is_map_of_progs(info->type)) {
|
|
|
|
int argc = 2;
|
|
|
|
|
|
|
|
if (value_size != 4) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("value smaller than 4B for map of progs?");
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!argv[0] || !argv[1]) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("not enough value arguments for map of progs");
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2019-01-29 02:29:15 +08:00
|
|
|
if (is_prefix(*argv, "id"))
|
|
|
|
p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
|
|
|
|
" by some process or pinned otherwise update will be lost");
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
fd = prog_parse_fd(&argc, &argv);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*value_fd = value;
|
|
|
|
**value_fd = fd;
|
|
|
|
} else {
|
|
|
|
argv = parse_bytes(argv, "value", value, value_size);
|
|
|
|
if (!argv)
|
|
|
|
return -1;
|
2019-01-21 19:36:12 +08:00
|
|
|
|
|
|
|
fill_per_cpu_value(info, value);
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return parse_elem(argv, info, key, NULL, key_size, value_size,
|
|
|
|
flags, NULL);
|
|
|
|
} else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
|
|
|
|
is_prefix(*argv, "exist")) {
|
|
|
|
if (!flags) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("flags specified multiple times: %s", *argv);
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_prefix(*argv, "any"))
|
|
|
|
*flags = BPF_ANY;
|
|
|
|
else if (is_prefix(*argv, "noexist"))
|
|
|
|
*flags = BPF_NOEXIST;
|
|
|
|
else if (is_prefix(*argv, "exist"))
|
|
|
|
*flags = BPF_EXIST;
|
|
|
|
|
|
|
|
return parse_elem(argv + 1, info, key, value, key_size,
|
|
|
|
value_size, NULL, value_fd);
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("expected key or value, got: %s", *argv);
|
2017-10-05 11:10:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
static int show_map_close_json(int fd, struct bpf_map_info *info)
|
|
|
|
{
|
|
|
|
char *memlock;
|
|
|
|
|
|
|
|
memlock = get_fdinfo(fd, "memlock");
|
|
|
|
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
|
|
|
|
jsonw_uint_field(json_wtr, "id", info->id);
|
|
|
|
if (info->type < ARRAY_SIZE(map_type_name))
|
|
|
|
jsonw_string_field(json_wtr, "type",
|
|
|
|
map_type_name[info->type]);
|
|
|
|
else
|
|
|
|
jsonw_uint_field(json_wtr, "type", info->type);
|
|
|
|
|
|
|
|
if (*info->name)
|
|
|
|
jsonw_string_field(json_wtr, "name", info->name);
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "flags");
|
2018-03-24 10:45:12 +08:00
|
|
|
jsonw_printf(json_wtr, "%d", info->map_flags);
|
2018-01-18 11:13:29 +08:00
|
|
|
|
|
|
|
print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
|
|
|
|
jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
|
|
|
|
jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
|
|
|
|
|
|
|
|
if (memlock)
|
|
|
|
jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
|
|
|
|
free(memlock);
|
|
|
|
|
tools: bpftool: add owner_prog_type and owner_jited to bpftool output
For prog array maps, the type of the owner program, and the JIT-ed state
of that program, are available from the file descriptor information
under /proc. Add them to "bpftool map show" output. Example output:
# bpftool map show
158225: prog_array name jmp_table flags 0x0
key 4B value 4B max_entries 8 memlock 4096B
owner_prog_type flow_dissector owner jited
# bpftool --json --pretty map show
[{
"id": 1337,
"type": "prog_array",
"name": "jmp_table",
"flags": 0,
"bytes_key": 4,
"bytes_value": 4,
"max_entries": 8,
"bytes_memlock": 4096,
"owner_prog_type": "flow_dissector",
"owner_jited": true
}
]
As we move the table used for associating names to program types,
complete it with the missing types (lwt_seg6local and sk_reuseport).
Also add missing types to the help message for "bpftool prog"
(sk_reuseport and flow_dissector).
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-01 00:25:48 +08:00
|
|
|
if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
|
|
|
|
char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
|
|
|
|
char *owner_jited = get_fdinfo(fd, "owner_jited");
|
|
|
|
|
|
|
|
if (owner_prog_type) {
|
|
|
|
unsigned int prog_type = atoi(owner_prog_type);
|
|
|
|
|
|
|
|
if (prog_type < ARRAY_SIZE(prog_type_name))
|
|
|
|
jsonw_string_field(json_wtr, "owner_prog_type",
|
|
|
|
prog_type_name[prog_type]);
|
|
|
|
else
|
|
|
|
jsonw_uint_field(json_wtr, "owner_prog_type",
|
|
|
|
prog_type);
|
|
|
|
}
|
2019-01-29 02:01:21 +08:00
|
|
|
if (owner_jited)
|
|
|
|
jsonw_bool_field(json_wtr, "owner_jited",
|
|
|
|
!!atoi(owner_jited));
|
tools: bpftool: add owner_prog_type and owner_jited to bpftool output
For prog array maps, the type of the owner program, and the JIT-ed state
of that program, are available from the file descriptor information
under /proc. Add them to "bpftool map show" output. Example output:
# bpftool map show
158225: prog_array name jmp_table flags 0x0
key 4B value 4B max_entries 8 memlock 4096B
owner_prog_type flow_dissector owner jited
# bpftool --json --pretty map show
[{
"id": 1337,
"type": "prog_array",
"name": "jmp_table",
"flags": 0,
"bytes_key": 4,
"bytes_value": 4,
"max_entries": 8,
"bytes_memlock": 4096,
"owner_prog_type": "flow_dissector",
"owner_jited": true
}
]
As we move the table used for associating names to program types,
complete it with the missing types (lwt_seg6local and sk_reuseport).
Also add missing types to the help message for "bpftool prog"
(sk_reuseport and flow_dissector).
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-01 00:25:48 +08:00
|
|
|
|
|
|
|
free(owner_prog_type);
|
|
|
|
free(owner_jited);
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
if (!hash_empty(map_table.table)) {
|
|
|
|
struct pinned_obj *obj;
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "pinned");
|
|
|
|
jsonw_start_array(json_wtr);
|
|
|
|
hash_for_each_possible(map_table.table, obj, hash, info->id) {
|
|
|
|
if (obj->id == info->id)
|
|
|
|
jsonw_string(json_wtr, obj->path);
|
|
|
|
}
|
|
|
|
jsonw_end_array(json_wtr);
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int show_map_close_plain(int fd, struct bpf_map_info *info)
|
2017-10-05 11:10:04 +08:00
|
|
|
{
|
|
|
|
char *memlock;
|
|
|
|
|
|
|
|
memlock = get_fdinfo(fd, "memlock");
|
|
|
|
|
|
|
|
printf("%u: ", info->id);
|
|
|
|
if (info->type < ARRAY_SIZE(map_type_name))
|
|
|
|
printf("%s ", map_type_name[info->type]);
|
|
|
|
else
|
|
|
|
printf("type %u ", info->type);
|
|
|
|
|
|
|
|
if (*info->name)
|
|
|
|
printf("name %s ", info->name);
|
|
|
|
|
2018-01-18 11:13:29 +08:00
|
|
|
printf("flags 0x%x", info->map_flags);
|
|
|
|
print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
|
|
|
|
printf("\n");
|
2017-10-05 11:10:04 +08:00
|
|
|
printf("\tkey %uB value %uB max_entries %u",
|
|
|
|
info->key_size, info->value_size, info->max_entries);
|
|
|
|
|
|
|
|
if (memlock)
|
|
|
|
printf(" memlock %sB", memlock);
|
|
|
|
free(memlock);
|
|
|
|
|
tools: bpftool: add owner_prog_type and owner_jited to bpftool output
For prog array maps, the type of the owner program, and the JIT-ed state
of that program, are available from the file descriptor information
under /proc. Add them to "bpftool map show" output. Example output:
# bpftool map show
158225: prog_array name jmp_table flags 0x0
key 4B value 4B max_entries 8 memlock 4096B
owner_prog_type flow_dissector owner jited
# bpftool --json --pretty map show
[{
"id": 1337,
"type": "prog_array",
"name": "jmp_table",
"flags": 0,
"bytes_key": 4,
"bytes_value": 4,
"max_entries": 8,
"bytes_memlock": 4096,
"owner_prog_type": "flow_dissector",
"owner_jited": true
}
]
As we move the table used for associating names to program types,
complete it with the missing types (lwt_seg6local and sk_reuseport).
Also add missing types to the help message for "bpftool prog"
(sk_reuseport and flow_dissector).
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-01 00:25:48 +08:00
|
|
|
if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
|
|
|
|
char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
|
|
|
|
char *owner_jited = get_fdinfo(fd, "owner_jited");
|
|
|
|
|
2019-01-29 02:01:21 +08:00
|
|
|
if (owner_prog_type || owner_jited)
|
|
|
|
printf("\n\t");
|
tools: bpftool: add owner_prog_type and owner_jited to bpftool output
For prog array maps, the type of the owner program, and the JIT-ed state
of that program, are available from the file descriptor information
under /proc. Add them to "bpftool map show" output. Example output:
# bpftool map show
158225: prog_array name jmp_table flags 0x0
key 4B value 4B max_entries 8 memlock 4096B
owner_prog_type flow_dissector owner jited
# bpftool --json --pretty map show
[{
"id": 1337,
"type": "prog_array",
"name": "jmp_table",
"flags": 0,
"bytes_key": 4,
"bytes_value": 4,
"max_entries": 8,
"bytes_memlock": 4096,
"owner_prog_type": "flow_dissector",
"owner_jited": true
}
]
As we move the table used for associating names to program types,
complete it with the missing types (lwt_seg6local and sk_reuseport).
Also add missing types to the help message for "bpftool prog"
(sk_reuseport and flow_dissector).
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-01 00:25:48 +08:00
|
|
|
if (owner_prog_type) {
|
|
|
|
unsigned int prog_type = atoi(owner_prog_type);
|
|
|
|
|
|
|
|
if (prog_type < ARRAY_SIZE(prog_type_name))
|
|
|
|
printf("owner_prog_type %s ",
|
|
|
|
prog_type_name[prog_type]);
|
|
|
|
else
|
|
|
|
printf("owner_prog_type %d ", prog_type);
|
|
|
|
}
|
2019-01-29 02:01:21 +08:00
|
|
|
if (owner_jited)
|
|
|
|
printf("owner%s jited",
|
|
|
|
atoi(owner_jited) ? "" : " not");
|
tools: bpftool: add owner_prog_type and owner_jited to bpftool output
For prog array maps, the type of the owner program, and the JIT-ed state
of that program, are available from the file descriptor information
under /proc. Add them to "bpftool map show" output. Example output:
# bpftool map show
158225: prog_array name jmp_table flags 0x0
key 4B value 4B max_entries 8 memlock 4096B
owner_prog_type flow_dissector owner jited
# bpftool --json --pretty map show
[{
"id": 1337,
"type": "prog_array",
"name": "jmp_table",
"flags": 0,
"bytes_key": 4,
"bytes_value": 4,
"max_entries": 8,
"bytes_memlock": 4096,
"owner_prog_type": "flow_dissector",
"owner_jited": true
}
]
As we move the table used for associating names to program types,
complete it with the missing types (lwt_seg6local and sk_reuseport).
Also add missing types to the help message for "bpftool prog"
(sk_reuseport and flow_dissector).
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-01 00:25:48 +08:00
|
|
|
|
|
|
|
free(owner_prog_type);
|
|
|
|
free(owner_jited);
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
printf("\n");
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
if (!hash_empty(map_table.table)) {
|
|
|
|
struct pinned_obj *obj;
|
2017-10-05 11:10:04 +08:00
|
|
|
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
hash_for_each_possible(map_table.table, obj, hash, info->id) {
|
|
|
|
if (obj->id == info->id)
|
|
|
|
printf("\tpinned %s\n", obj->path);
|
|
|
|
}
|
|
|
|
}
|
2017-10-05 11:10:04 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_show(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
__u32 id = 0;
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
2017-11-08 12:55:49 +08:00
|
|
|
if (show_pinned)
|
|
|
|
build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
|
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 12:55:48 +08:00
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
if (argc == 2) {
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
return show_map_close_json(fd, &info);
|
|
|
|
else
|
|
|
|
return show_map_close_plain(fd, &info);
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (argc)
|
|
|
|
return BAD_ARG();
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
jsonw_start_array(json_wtr);
|
2017-10-05 11:10:04 +08:00
|
|
|
while (true) {
|
|
|
|
err = bpf_map_get_next_id(id, &id);
|
|
|
|
if (err) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
break;
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("can't get next map: %s%s", strerror(errno),
|
|
|
|
errno == EINVAL ? " -- kernel too old?" : "");
|
2017-12-23 03:36:05 +08:00
|
|
|
break;
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fd = bpf_map_get_fd_by_id(id);
|
|
|
|
if (fd < 0) {
|
2017-12-23 03:36:06 +08:00
|
|
|
if (errno == ENOENT)
|
|
|
|
continue;
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("can't get map by id (%u): %s",
|
|
|
|
id, strerror(errno));
|
2017-12-23 03:36:05 +08:00
|
|
|
break;
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
err = bpf_obj_get_info_by_fd(fd, &info, &len);
|
|
|
|
if (err) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("can't get map info: %s", strerror(errno));
|
2017-10-05 11:10:04 +08:00
|
|
|
close(fd);
|
2017-12-23 03:36:05 +08:00
|
|
|
break;
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
show_map_close_json(fd, &info);
|
|
|
|
else
|
|
|
|
show_map_close_plain(fd, &info);
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(json_wtr);
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
return errno == ENOENT ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
2018-10-09 09:04:51 +08:00
|
|
|
static int dump_map_elem(int fd, void *key, void *value,
|
|
|
|
struct bpf_map_info *map_info, struct btf *btf,
|
|
|
|
json_writer_t *btf_wtr)
|
|
|
|
{
|
|
|
|
int num_elems = 0;
|
tools/bpf: bpftool, print strerror when map lookup error occurs
Since map lookup error can be ENOENT or EOPNOTSUPP, let's print
strerror() as error message in normal and JSON output.
This patch adds helper function print_entry_error() to print
entry from lookup error occurs
Example: Following example dumps a map which does not support lookup.
Output before:
root# bpftool map -jp dump id 40
[
"key": ["0x0a","0x00","0x00","0x00"
],
"value": {
"error": "can\'t lookup element"
},
"key": ["0x0b","0x00","0x00","0x00"
],
"value": {
"error": "can\'t lookup element"
}
]
root# bpftool map dump id 40
can't lookup element with key:
0a 00 00 00
can't lookup element with key:
0b 00 00 00
Found 0 elements
Output after changes:
root# bpftool map dump -jp id 45
[
"key": ["0x0a","0x00","0x00","0x00"
],
"value": {
"error": "Operation not supported"
},
"key": ["0x0b","0x00","0x00","0x00"
],
"value": {
"error": "Operation not supported"
}
]
root# bpftool map dump id 45
key:
0a 00 00 00
value:
Operation not supported
key:
0b 00 00 00
value:
Operation not supported
Found 0 elements
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-10-09 09:04:52 +08:00
|
|
|
int lookup_errno;
|
2018-10-09 09:04:51 +08:00
|
|
|
|
|
|
|
if (!bpf_map_lookup_elem(fd, key, value)) {
|
|
|
|
if (json_output) {
|
|
|
|
print_entry_json(map_info, key, value, btf);
|
|
|
|
} else {
|
|
|
|
if (btf) {
|
|
|
|
struct btf_dumper d = {
|
|
|
|
.btf = btf,
|
|
|
|
.jw = btf_wtr,
|
|
|
|
.is_plain_text = true,
|
|
|
|
};
|
|
|
|
|
|
|
|
do_dump_btf(&d, map_info, key, value);
|
|
|
|
} else {
|
|
|
|
print_entry_plain(map_info, key, value);
|
|
|
|
}
|
|
|
|
num_elems++;
|
|
|
|
}
|
|
|
|
return num_elems;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lookup error handling */
|
tools/bpf: bpftool, print strerror when map lookup error occurs
Since map lookup error can be ENOENT or EOPNOTSUPP, let's print
strerror() as error message in normal and JSON output.
This patch adds helper function print_entry_error() to print
entry from lookup error occurs
Example: Following example dumps a map which does not support lookup.
Output before:
root# bpftool map -jp dump id 40
[
"key": ["0x0a","0x00","0x00","0x00"
],
"value": {
"error": "can\'t lookup element"
},
"key": ["0x0b","0x00","0x00","0x00"
],
"value": {
"error": "can\'t lookup element"
}
]
root# bpftool map dump id 40
can't lookup element with key:
0a 00 00 00
can't lookup element with key:
0b 00 00 00
Found 0 elements
Output after changes:
root# bpftool map dump -jp id 45
[
"key": ["0x0a","0x00","0x00","0x00"
],
"value": {
"error": "Operation not supported"
},
"key": ["0x0b","0x00","0x00","0x00"
],
"value": {
"error": "Operation not supported"
}
]
root# bpftool map dump id 45
key:
0a 00 00 00
value:
Operation not supported
key:
0b 00 00 00
value:
Operation not supported
Found 0 elements
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-10-09 09:04:52 +08:00
|
|
|
lookup_errno = errno;
|
|
|
|
|
2018-10-09 09:04:51 +08:00
|
|
|
if (map_is_map_of_maps(map_info->type) ||
|
|
|
|
map_is_map_of_progs(map_info->type))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_name(json_wtr, "key");
|
|
|
|
print_hex_data_json(key, map_info->key_size);
|
|
|
|
jsonw_name(json_wtr, "value");
|
|
|
|
jsonw_start_object(json_wtr);
|
tools/bpf: bpftool, print strerror when map lookup error occurs
Since map lookup error can be ENOENT or EOPNOTSUPP, let's print
strerror() as error message in normal and JSON output.
This patch adds helper function print_entry_error() to print
entry from lookup error occurs
Example: Following example dumps a map which does not support lookup.
Output before:
root# bpftool map -jp dump id 40
[
"key": ["0x0a","0x00","0x00","0x00"
],
"value": {
"error": "can\'t lookup element"
},
"key": ["0x0b","0x00","0x00","0x00"
],
"value": {
"error": "can\'t lookup element"
}
]
root# bpftool map dump id 40
can't lookup element with key:
0a 00 00 00
can't lookup element with key:
0b 00 00 00
Found 0 elements
Output after changes:
root# bpftool map dump -jp id 45
[
"key": ["0x0a","0x00","0x00","0x00"
],
"value": {
"error": "Operation not supported"
},
"key": ["0x0b","0x00","0x00","0x00"
],
"value": {
"error": "Operation not supported"
}
]
root# bpftool map dump id 45
key:
0a 00 00 00
value:
Operation not supported
key:
0b 00 00 00
value:
Operation not supported
Found 0 elements
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-10-09 09:04:52 +08:00
|
|
|
jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
|
2018-10-09 09:04:51 +08:00
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
} else {
|
2018-11-09 05:00:07 +08:00
|
|
|
if (errno == ENOENT)
|
|
|
|
print_entry_plain(map_info, key, NULL);
|
|
|
|
else
|
|
|
|
print_entry_error(map_info, key,
|
|
|
|
strerror(lookup_errno));
|
2018-10-09 09:04:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
static int do_dump(int argc, char **argv)
|
|
|
|
{
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
struct bpf_map_info info = {};
|
2017-10-05 11:10:04 +08:00
|
|
|
void *key, *value, *prev_key;
|
|
|
|
unsigned int num_elems = 0;
|
|
|
|
__u32 len = sizeof(info);
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
json_writer_t *btf_wtr;
|
|
|
|
struct btf *btf = NULL;
|
2017-10-05 11:10:04 +08:00
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (argc != 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
key = malloc(info.key_size);
|
|
|
|
value = alloc_value(&info);
|
|
|
|
if (!key || !value) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("mem alloc failed");
|
2017-10-05 11:10:04 +08:00
|
|
|
err = -1;
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev_key = NULL;
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
|
2018-11-24 08:44:32 +08:00
|
|
|
err = btf__get_from_id(info.btf_id, &btf);
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
if (err) {
|
|
|
|
p_err("failed to get btf");
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
jsonw_start_array(json_wtr);
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
else
|
|
|
|
if (btf) {
|
|
|
|
btf_wtr = get_btf_writer();
|
|
|
|
if (!btf_wtr) {
|
|
|
|
p_info("failed to create json writer for btf. falling back to plain output");
|
|
|
|
btf__free(btf);
|
|
|
|
btf = NULL;
|
|
|
|
} else {
|
|
|
|
jsonw_start_array(btf_wtr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
while (true) {
|
|
|
|
err = bpf_map_get_next_key(fd, prev_key, key);
|
|
|
|
if (err) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
}
|
2018-10-09 09:04:51 +08:00
|
|
|
num_elems += dump_map_elem(fd, key, value, &info, btf, btf_wtr);
|
2017-10-05 11:10:04 +08:00
|
|
|
prev_key = key;
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(json_wtr);
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
else if (btf) {
|
|
|
|
jsonw_end_array(btf_wtr);
|
|
|
|
jsonw_destroy(&btf_wtr);
|
|
|
|
} else {
|
2017-10-24 00:24:11 +08:00
|
|
|
printf("Found %u element%s\n", num_elems,
|
|
|
|
num_elems != 1 ? "s" : "");
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
}
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
exit_free:
|
|
|
|
free(key);
|
|
|
|
free(value);
|
|
|
|
close(fd);
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
btf__free(btf);
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-01-17 03:09:59 +08:00
|
|
|
static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
|
|
|
|
{
|
|
|
|
*key = NULL;
|
|
|
|
*value = NULL;
|
|
|
|
|
|
|
|
if (info->key_size) {
|
|
|
|
*key = malloc(info->key_size);
|
|
|
|
if (!*key) {
|
|
|
|
p_err("key mem alloc failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->value_size) {
|
|
|
|
*value = alloc_value(info);
|
|
|
|
if (!*value) {
|
|
|
|
p_err("value mem alloc failed");
|
|
|
|
free(*key);
|
|
|
|
*key = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
static int do_update(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
__u32 *value_fd = NULL;
|
|
|
|
__u32 flags = BPF_ANY;
|
|
|
|
void *key, *value;
|
|
|
|
int fd, err;
|
|
|
|
|
|
|
|
if (argc < 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-01-17 03:09:59 +08:00
|
|
|
err = alloc_key_value(&info, &key, &value);
|
|
|
|
if (err)
|
2017-10-05 11:10:04 +08:00
|
|
|
goto exit_free;
|
|
|
|
|
|
|
|
err = parse_elem(argv, &info, key, value, info.key_size,
|
|
|
|
info.value_size, &flags, &value_fd);
|
|
|
|
if (err)
|
|
|
|
goto exit_free;
|
|
|
|
|
|
|
|
err = bpf_map_update_elem(fd, key, value, flags);
|
|
|
|
if (err) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("update failed: %s", strerror(errno));
|
2017-10-05 11:10:04 +08:00
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
exit_free:
|
|
|
|
if (value_fd)
|
|
|
|
close(*value_fd);
|
|
|
|
free(key);
|
|
|
|
free(value);
|
|
|
|
close(fd);
|
|
|
|
|
2017-10-24 00:24:14 +08:00
|
|
|
if (!err && json_output)
|
|
|
|
jsonw_null(json_wtr);
|
2017-10-05 11:10:04 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-01-17 03:10:04 +08:00
|
|
|
static void print_key_value(struct bpf_map_info *info, void *key,
|
|
|
|
void *value)
|
|
|
|
{
|
|
|
|
json_writer_t *btf_wtr;
|
|
|
|
struct btf *btf = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = btf__get_from_id(info->btf_id, &btf);
|
|
|
|
if (err) {
|
|
|
|
p_err("failed to get btf");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (json_output) {
|
|
|
|
print_entry_json(info, key, value, btf);
|
|
|
|
} else if (btf) {
|
|
|
|
/* if here json_wtr wouldn't have been initialised,
|
|
|
|
* so let's create separate writer for btf
|
|
|
|
*/
|
|
|
|
btf_wtr = get_btf_writer();
|
|
|
|
if (!btf_wtr) {
|
|
|
|
p_info("failed to create json writer for btf. falling back to plain output");
|
|
|
|
btf__free(btf);
|
|
|
|
btf = NULL;
|
|
|
|
print_entry_plain(info, key, value);
|
|
|
|
} else {
|
|
|
|
struct btf_dumper d = {
|
|
|
|
.btf = btf,
|
|
|
|
.jw = btf_wtr,
|
|
|
|
.is_plain_text = true,
|
|
|
|
};
|
|
|
|
|
|
|
|
do_dump_btf(&d, info, key, value);
|
|
|
|
jsonw_destroy(&btf_wtr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
print_entry_plain(info, key, value);
|
|
|
|
}
|
|
|
|
btf__free(btf);
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
static int do_lookup(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
void *key, *value;
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (argc < 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-01-17 03:10:00 +08:00
|
|
|
err = alloc_key_value(&info, &key, &value);
|
|
|
|
if (err)
|
2017-10-05 11:10:04 +08:00
|
|
|
goto exit_free;
|
|
|
|
|
|
|
|
err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
|
|
|
|
if (err)
|
|
|
|
goto exit_free;
|
|
|
|
|
|
|
|
err = bpf_map_lookup_elem(fd, key, value);
|
bpf: btf: print map dump and lookup with btf info
This patch augments the output of bpftool's map dump and map lookup
commands to print data along side btf info, if the correspondin btf
info is available. The outputs for each of map dump and map lookup
commands are augmented in two ways:
1. when neither of -j and -p are supplied, btf-ful map data is printed
whose aim is human readability. This means no commitments for json- or
backward- compatibility.
2. when either -j or -p are supplied, a new json object named
"formatted" is added for each key-value pair. This object contains the
same data as the key-value pair, but with btf info. "formatted" object
promises json- and backward- compatibility. Below is a sample output.
$ bpftool map dump -p id 8
[{
"key": ["0x0f","0x00","0x00","0x00"
],
"value": ["0x03", "0x00", "0x00", "0x00", ...
],
"formatted": {
"key": 15,
"value": {
"int_field": 3,
...
}
}
}
]
This patch calls btf_dumper introduced in previous patch to accomplish
the above. Indeed, btf-ful info is only displayed if btf data for the
given map is available. Otherwise existing output is displayed as-is.
Signed-off-by: Okash Khawaja <osk@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-07-14 12:57:04 +08:00
|
|
|
if (err) {
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
if (json_output) {
|
|
|
|
jsonw_null(json_wtr);
|
|
|
|
} else {
|
|
|
|
printf("key:\n");
|
|
|
|
fprint_hex(stdout, key, info.key_size, " ");
|
|
|
|
printf("\n\nNot found\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
p_err("lookup failed: %s", strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* here means bpf_map_lookup_elem() succeeded */
|
2019-01-17 03:10:04 +08:00
|
|
|
print_key_value(&info, key, value);
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
exit_free:
|
|
|
|
free(key);
|
|
|
|
free(value);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_getnext(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
void *key, *nextkey;
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (argc < 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
key = malloc(info.key_size);
|
|
|
|
nextkey = malloc(info.key_size);
|
|
|
|
if (!key || !nextkey) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("mem alloc failed");
|
2017-10-05 11:10:04 +08:00
|
|
|
err = -1;
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc) {
|
|
|
|
err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
|
|
|
|
NULL, NULL);
|
|
|
|
if (err)
|
|
|
|
goto exit_free;
|
|
|
|
} else {
|
|
|
|
free(key);
|
|
|
|
key = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bpf_map_get_next_key(fd, key, nextkey);
|
|
|
|
if (err) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("can't get next key: %s", strerror(errno));
|
2017-10-05 11:10:04 +08:00
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
if (key) {
|
|
|
|
jsonw_name(json_wtr, "key");
|
|
|
|
print_hex_data_json(key, info.key_size);
|
|
|
|
} else {
|
|
|
|
jsonw_null_field(json_wtr, "key");
|
|
|
|
}
|
|
|
|
jsonw_name(json_wtr, "next_key");
|
|
|
|
print_hex_data_json(nextkey, info.key_size);
|
|
|
|
jsonw_end_object(json_wtr);
|
2017-10-05 11:10:04 +08:00
|
|
|
} else {
|
2017-10-24 00:24:11 +08:00
|
|
|
if (key) {
|
|
|
|
printf("key:\n");
|
|
|
|
fprint_hex(stdout, key, info.key_size, " ");
|
|
|
|
printf("\n");
|
|
|
|
} else {
|
|
|
|
printf("key: None\n");
|
|
|
|
}
|
|
|
|
printf("next key:\n");
|
|
|
|
fprint_hex(stdout, nextkey, info.key_size, " ");
|
|
|
|
printf("\n");
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
exit_free:
|
|
|
|
free(nextkey);
|
|
|
|
free(key);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_delete(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
void *key;
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (argc < 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
key = malloc(info.key_size);
|
|
|
|
if (!key) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("mem alloc failed");
|
2017-10-05 11:10:04 +08:00
|
|
|
err = -1;
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
|
|
|
|
if (err)
|
|
|
|
goto exit_free;
|
|
|
|
|
|
|
|
err = bpf_map_delete_elem(fd, key);
|
|
|
|
if (err)
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("delete failed: %s", strerror(errno));
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
exit_free:
|
|
|
|
free(key);
|
|
|
|
close(fd);
|
|
|
|
|
2017-10-24 00:24:14 +08:00
|
|
|
if (!err && json_output)
|
|
|
|
jsonw_null(json_wtr);
|
2017-10-05 11:10:04 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_pin(int argc, char **argv)
|
|
|
|
{
|
2017-10-24 00:24:14 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = do_pin_any(argc, argv, bpf_map_get_fd_by_id);
|
|
|
|
if (!err && json_output)
|
|
|
|
jsonw_null(json_wtr);
|
|
|
|
return err;
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
2018-10-16 07:30:36 +08:00
|
|
|
static int do_create(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct bpf_create_map_attr attr = { NULL, };
|
|
|
|
const char *pinfile;
|
|
|
|
int err, fd;
|
|
|
|
|
|
|
|
if (!REQ_ARGS(7))
|
|
|
|
return -1;
|
|
|
|
pinfile = GET_ARG();
|
|
|
|
|
|
|
|
while (argc) {
|
|
|
|
if (!REQ_ARGS(2))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (is_prefix(*argv, "type")) {
|
|
|
|
NEXT_ARG();
|
|
|
|
|
|
|
|
if (attr.map_type) {
|
|
|
|
p_err("map type already specified");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
attr.map_type = map_type_from_str(*argv);
|
|
|
|
if ((int)attr.map_type < 0) {
|
|
|
|
p_err("unrecognized map type: %s", *argv);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARG();
|
|
|
|
} else if (is_prefix(*argv, "name")) {
|
|
|
|
NEXT_ARG();
|
|
|
|
attr.name = GET_ARG();
|
|
|
|
} else if (is_prefix(*argv, "key")) {
|
|
|
|
if (parse_u32_arg(&argc, &argv, &attr.key_size,
|
|
|
|
"key size"))
|
|
|
|
return -1;
|
|
|
|
} else if (is_prefix(*argv, "value")) {
|
|
|
|
if (parse_u32_arg(&argc, &argv, &attr.value_size,
|
|
|
|
"value size"))
|
|
|
|
return -1;
|
|
|
|
} else if (is_prefix(*argv, "entries")) {
|
|
|
|
if (parse_u32_arg(&argc, &argv, &attr.max_entries,
|
|
|
|
"max entries"))
|
|
|
|
return -1;
|
|
|
|
} else if (is_prefix(*argv, "flags")) {
|
|
|
|
if (parse_u32_arg(&argc, &argv, &attr.map_flags,
|
|
|
|
"flags"))
|
|
|
|
return -1;
|
|
|
|
} else if (is_prefix(*argv, "dev")) {
|
|
|
|
NEXT_ARG();
|
|
|
|
|
|
|
|
if (attr.map_ifindex) {
|
|
|
|
p_err("offload device already specified");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
attr.map_ifindex = if_nametoindex(*argv);
|
|
|
|
if (!attr.map_ifindex) {
|
|
|
|
p_err("unrecognized netdevice '%s': %s",
|
|
|
|
*argv, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
NEXT_ARG();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!attr.name) {
|
|
|
|
p_err("map name not specified");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
tools: bpftool: adjust rlimit RLIMIT_MEMLOCK when loading programs, maps
The limit for memory locked in the kernel by a process is usually set to
64 kbytes by default. This can be an issue when creating large BPF maps
and/or loading many programs. A workaround is to raise this limit for
the current process before trying to create a new BPF map. Changing the
hard limit requires the CAP_SYS_RESOURCE and can usually only be done by
root user (for non-root users, a call to setrlimit fails (and sets
errno) and the program simply goes on with its rlimit unchanged).
There is no API to get the current amount of memory locked for a user,
therefore we cannot raise the limit only when required. One solution,
used by bcc, is to try to create the map, and on getting a EPERM error,
raising the limit to infinity before giving another try. Another
approach, used in iproute2, is to raise the limit in all cases, before
trying to create the map.
Here we do the same as in iproute2: the rlimit is raised to infinity
before trying to load programs or to create maps with bpftool.
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2018-11-07 20:29:30 +08:00
|
|
|
set_max_rlimit();
|
|
|
|
|
2018-10-16 07:30:36 +08:00
|
|
|
fd = bpf_create_map_xattr(&attr);
|
|
|
|
if (fd < 0) {
|
|
|
|
p_err("map create failed: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = do_pin_fd(fd, pinfile);
|
|
|
|
close(fd);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (json_output)
|
|
|
|
jsonw_null(json_wtr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-17 03:10:04 +08:00
|
|
|
static int do_pop_dequeue(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
void *key, *value;
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (argc < 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
err = alloc_key_value(&info, &key, &value);
|
|
|
|
if (err)
|
|
|
|
goto exit_free;
|
|
|
|
|
|
|
|
err = bpf_map_lookup_and_delete_elem(fd, key, value);
|
|
|
|
if (err) {
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
if (json_output)
|
|
|
|
jsonw_null(json_wtr);
|
|
|
|
else
|
|
|
|
printf("Error: empty map\n");
|
|
|
|
} else {
|
|
|
|
p_err("pop failed: %s", strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
goto exit_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
print_key_value(&info, key, value);
|
|
|
|
|
|
|
|
exit_free:
|
|
|
|
free(key);
|
|
|
|
free(value);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
static int do_help(int argc, char **argv)
|
|
|
|
{
|
2017-10-24 00:24:14 +08:00
|
|
|
if (json_output) {
|
|
|
|
jsonw_null(json_wtr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-05 11:10:04 +08:00
|
|
|
fprintf(stderr,
|
2018-01-03 06:48:36 +08:00
|
|
|
"Usage: %s %s { show | list } [MAP]\n"
|
2018-10-16 07:30:36 +08:00
|
|
|
" %s %s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
|
|
|
|
" entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
|
|
|
|
" [dev NAME]\n"
|
2018-05-04 09:37:16 +08:00
|
|
|
" %s %s dump MAP\n"
|
2019-01-17 03:09:59 +08:00
|
|
|
" %s %s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
|
2019-01-17 03:10:00 +08:00
|
|
|
" %s %s lookup MAP [key DATA]\n"
|
2018-05-04 09:37:16 +08:00
|
|
|
" %s %s getnext MAP [key DATA]\n"
|
|
|
|
" %s %s delete MAP key DATA\n"
|
|
|
|
" %s %s pin MAP FILE\n"
|
|
|
|
" %s %s event_pipe MAP [cpu N index M]\n"
|
2019-01-17 03:10:02 +08:00
|
|
|
" %s %s peek MAP\n"
|
2019-01-17 03:10:03 +08:00
|
|
|
" %s %s push MAP value VALUE\n"
|
2019-01-17 03:10:04 +08:00
|
|
|
" %s %s pop MAP\n"
|
2019-01-17 03:10:03 +08:00
|
|
|
" %s %s enqueue MAP value VALUE\n"
|
2019-01-17 03:10:04 +08:00
|
|
|
" %s %s dequeue MAP\n"
|
2017-10-05 11:10:04 +08:00
|
|
|
" %s %s help\n"
|
|
|
|
"\n"
|
2018-07-11 05:43:07 +08:00
|
|
|
" " HELP_SPEC_MAP "\n"
|
2018-05-04 09:37:14 +08:00
|
|
|
" DATA := { [hex] BYTES }\n"
|
2017-10-05 11:10:04 +08:00
|
|
|
" " HELP_SPEC_PROGRAM "\n"
|
2018-05-04 09:37:14 +08:00
|
|
|
" VALUE := { DATA | MAP | PROG }\n"
|
2017-10-05 11:10:04 +08:00
|
|
|
" UPDATE_FLAGS := { any | exist | noexist }\n"
|
2018-10-16 07:30:36 +08:00
|
|
|
" TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
|
|
|
|
" percpu_array | stack_trace | cgroup_array | lru_hash |\n"
|
|
|
|
" lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
|
|
|
|
" devmap | sockmap | cpumap | xskmap | sockhash |\n"
|
|
|
|
" cgroup_storage | reuseport_sockarray | percpu_cgroup_storage }\n"
|
2017-10-24 00:24:16 +08:00
|
|
|
" " HELP_SPEC_OPTIONS "\n"
|
2017-10-05 11:10:04 +08:00
|
|
|
"",
|
|
|
|
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
|
|
|
|
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
|
2018-10-16 07:30:36 +08:00
|
|
|
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
|
2019-01-17 03:10:03 +08:00
|
|
|
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
|
2019-01-17 03:10:04 +08:00
|
|
|
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct cmd cmds[] = {
|
|
|
|
{ "show", do_show },
|
2018-01-03 06:48:36 +08:00
|
|
|
{ "list", do_show },
|
2017-10-05 11:10:04 +08:00
|
|
|
{ "help", do_help },
|
|
|
|
{ "dump", do_dump },
|
|
|
|
{ "update", do_update },
|
|
|
|
{ "lookup", do_lookup },
|
|
|
|
{ "getnext", do_getnext },
|
|
|
|
{ "delete", do_delete },
|
|
|
|
{ "pin", do_pin },
|
2018-05-04 09:37:16 +08:00
|
|
|
{ "event_pipe", do_event_pipe },
|
2018-10-16 07:30:36 +08:00
|
|
|
{ "create", do_create },
|
2019-01-17 03:10:02 +08:00
|
|
|
{ "peek", do_lookup },
|
2019-01-17 03:10:03 +08:00
|
|
|
{ "push", do_update },
|
|
|
|
{ "enqueue", do_update },
|
2019-01-17 03:10:04 +08:00
|
|
|
{ "pop", do_pop_dequeue },
|
|
|
|
{ "dequeue", do_pop_dequeue },
|
2017-10-05 11:10:04 +08:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
int do_map(int argc, char **argv)
|
|
|
|
{
|
|
|
|
return cmd_select(cmds, argc, argv, do_help);
|
|
|
|
}
|