2017-10-05 11:10:04 +08:00
|
|
|
/*
|
2018-05-04 09:37:14 +08:00
|
|
|
* Copyright (C) 2017-2018 Netronome Systems, Inc.
|
2017-10-05 11:10:04 +08:00
|
|
|
*
|
|
|
|
* This software is dual licensed under the GNU General License Version 2,
|
|
|
|
* June 1991 as shown in the file COPYING in the top-level directory of this
|
|
|
|
* source tree or the BSD 2-Clause License provided below. You have the
|
|
|
|
* option to license this software under the complete terms of either license.
|
|
|
|
*
|
|
|
|
* The BSD 2-Clause License:
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or
|
|
|
|
* without modification, are permitted provided that the following
|
|
|
|
* conditions are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above
|
|
|
|
* copyright notice, this list of conditions and the following
|
|
|
|
* disclaimer.
|
|
|
|
*
|
|
|
|
* 2. Redistributions in binary form must reproduce the above
|
|
|
|
* copyright notice, this list of conditions and the following
|
|
|
|
* disclaimer in the documentation and/or other materials
|
|
|
|
* provided with the distribution.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Author: Jakub Kicinski <kubakici@wp.pl> */
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#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>
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
static const char * const map_type_name[] = {
|
|
|
|
[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",
|
2018-01-19 22:17:45 +08:00
|
|
|
[BPF_MAP_TYPE_CPUMAP] = "cpumap",
|
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 ||
|
|
|
|
type == BPF_MAP_TYPE_LRU_PERCPU_HASH;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *alloc_value(struct bpf_map_info *info)
|
|
|
|
{
|
|
|
|
if (map_is_per_cpu(info->type))
|
|
|
|
return malloc(info->value_size * get_possible_cpus());
|
|
|
|
else
|
|
|
|
return malloc(info->value_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int map_parse_fd(int *argc, char ***argv)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
|
|
|
|
unsigned char *value)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
} else {
|
|
|
|
unsigned int i, n;
|
|
|
|
|
|
|
|
n = get_possible_cpus();
|
|
|
|
|
|
|
|
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");
|
|
|
|
print_hex_data_json(value + i * info->value_size,
|
|
|
|
info->value_size);
|
|
|
|
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
}
|
|
|
|
jsonw_end_array(json_wtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
printf("key:%c", break_names ? '\n' : ' ');
|
2017-10-20 06:46:19 +08:00
|
|
|
fprint_hex(stdout, key, info->key_size, " ");
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
printf(single_line ? " " : "\n");
|
|
|
|
|
|
|
|
printf("value:%c", break_names ? '\n' : ' ');
|
2017-10-20 06:46:19 +08:00
|
|
|
fprint_hex(stdout, value, info->value_size, " ");
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
} else {
|
|
|
|
unsigned int i, n;
|
|
|
|
|
|
|
|
n = get_possible_cpus();
|
|
|
|
|
|
|
|
printf("key:\n");
|
2017-10-20 06:46:19 +08:00
|
|
|
fprint_hex(stdout, key, info->key_size, " ");
|
2017-10-05 11:10:04 +08:00
|
|
|
printf("\n");
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
printf("value (CPU %02d):%c",
|
|
|
|
i, info->value_size > 16 ? '\n' : ' ');
|
2017-10-20 06:46:19 +08:00
|
|
|
fprint_hex(stdout, value + i * info->value_size,
|
|
|
|
info->value_size, " ");
|
2017-10-05 11:10:04 +08:00
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
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: 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");
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_dump(int argc, char **argv)
|
|
|
|
{
|
|
|
|
void *key, *value, *prev_key;
|
|
|
|
unsigned int num_elems = 0;
|
|
|
|
struct bpf_map_info info = {};
|
|
|
|
__u32 len = sizeof(info);
|
|
|
|
int err;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (argc != 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("Dumping maps of maps and program maps not supported");
|
2017-10-05 11:10:04 +08:00
|
|
|
close(fd);
|
|
|
|
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;
|
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_key(fd, prev_key, key);
|
|
|
|
if (err) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
err = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bpf_map_lookup_elem(fd, key, value)) {
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
print_entry_json(&info, key, value);
|
|
|
|
else
|
|
|
|
print_entry_plain(&info, key, value);
|
2017-10-05 11:10:04 +08:00
|
|
|
} else {
|
2017-10-24 00:24:13 +08:00
|
|
|
if (json_output) {
|
|
|
|
jsonw_name(json_wtr, "key");
|
|
|
|
print_hex_data_json(key, info.key_size);
|
|
|
|
jsonw_name(json_wtr, "value");
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
jsonw_string_field(json_wtr, "error",
|
|
|
|
"can't lookup element");
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
} else {
|
|
|
|
p_info("can't lookup element with key: ");
|
|
|
|
fprint_hex(stderr, key, info.key_size, " ");
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
2017-10-05 11:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
prev_key = key;
|
|
|
|
num_elems++;
|
|
|
|
}
|
|
|
|
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(json_wtr);
|
|
|
|
else
|
|
|
|
printf("Found %u element%s\n", num_elems,
|
|
|
|
num_elems != 1 ? "s" : "");
|
2017-10-05 11:10:04 +08:00
|
|
|
|
|
|
|
exit_free:
|
|
|
|
free(key);
|
|
|
|
free(value);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
if (!err) {
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output)
|
|
|
|
print_entry_json(&info, key, value);
|
|
|
|
else
|
|
|
|
print_entry_plain(&info, key, value);
|
2017-10-05 11:10:04 +08:00
|
|
|
} else if (errno == ENOENT) {
|
2017-10-24 00:24:11 +08:00
|
|
|
if (json_output) {
|
|
|
|
jsonw_null(json_wtr);
|
|
|
|
} else {
|
|
|
|
printf("key:\n");
|
|
|
|
fprint_hex(stdout, key, info.key_size, " ");
|
|
|
|
printf("\n\nNot found\n");
|
|
|
|
}
|
2017-10-05 11:10:04 +08:00
|
|
|
} else {
|
2017-10-24 00:24:13 +08:00
|
|
|
p_err("lookup failed: %s", strerror(errno));
|
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
|
|
|
}
|
|
|
|
|
|
|
|
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-05-04 09:37:16 +08:00
|
|
|
" %s %s dump MAP\n"
|
|
|
|
" %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n"
|
|
|
|
" %s %s lookup MAP key DATA\n"
|
|
|
|
" %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"
|
2017-10-05 11:10:04 +08:00
|
|
|
" %s %s help\n"
|
|
|
|
"\n"
|
|
|
|
" MAP := { id MAP_ID | pinned FILE }\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"
|
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-05-04 09:37:16 +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 },
|
2017-10-05 11:10:04 +08:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
int do_map(int argc, char **argv)
|
|
|
|
{
|
|
|
|
return cmd_select(cmds, argc, argv, do_help);
|
|
|
|
}
|