bpftool: add pop and dequeue commands

This is intended to be used with queues and stacks, it pops and prints
the last element via bpf_map_lookup_and_delete_elem.

Example:

bpftool map create /sys/fs/bpf/q type queue value 4 entries 10 name q
bpftool map push pinned /sys/fs/bpf/q value 0 1 2 3
bpftool map pop pinned /sys/fs/bpf/q
value: 00 01 02 03
bpftool map pop pinned /sys/fs/bpf/q
Error: empty map

bpftool map create /sys/fs/bpf/s type stack value 4 entries 10 name s
bpftool map enqueue pinned /sys/fs/bpf/s value 0 1 2 3
bpftool map dequeue pinned /sys/fs/bpf/s
value: 00 01 02 03
bpftool map dequeue pinned /sys/fs/bpf/s
Error: empty map

Signed-off-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
Stanislav Fomichev 2019-01-16 11:10:04 -08:00 committed by Daniel Borkmann
parent 549d4d3da7
commit 74f312ef84
2 changed files with 98 additions and 35 deletions

View File

@ -33,7 +33,9 @@ MAP COMMANDS
| **bpftool** **map event_pipe** *MAP* [**cpu** *N* **index** *M*]
| **bpftool** **map peek** *MAP*
| **bpftool** **map push** *MAP* **value** *VALUE*
| **bpftool** **map pop** *MAP*
| **bpftool** **map enqueue** *MAP* **value** *VALUE*
| **bpftool** **map dequeue** *MAP*
| **bpftool** **map help**
|
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
@ -116,9 +118,15 @@ DESCRIPTION
**bpftool map push** *MAP* **value** *VALUE*
Push **value** onto the stack.
**bpftool map pop** *MAP*
Pop and print **value** from the stack.
**bpftool map enqueue** *MAP* **value** *VALUE*
Enqueue **value** into the queue.
**bpftool map dequeue** *MAP*
Dequeue and print **value** from the queue.
**bpftool map help**
Print short help message.

View File

@ -857,12 +857,51 @@ exit_free:
return err;
}
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);
}
static int do_lookup(int argc, char **argv)
{
struct bpf_map_info info = {};
__u32 len = sizeof(info);
json_writer_t *btf_wtr;
struct btf *btf = NULL;
void *key, *value;
int err;
int fd;
@ -900,43 +939,12 @@ static int do_lookup(int argc, char **argv)
}
/* here means bpf_map_lookup_elem() succeeded */
err = btf__get_from_id(info.btf_id, &btf);
if (err) {
p_err("failed to get btf");
goto exit_free;
}
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);
}
print_key_value(&info, key, value);
exit_free:
free(key);
free(value);
close(fd);
btf__free(btf);
return err;
}
@ -1149,6 +1157,49 @@ static int do_create(int argc, char **argv)
return 0;
}
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;
}
static int do_help(int argc, char **argv)
{
if (json_output) {
@ -1170,7 +1221,9 @@ static int do_help(int argc, char **argv)
" %s %s event_pipe MAP [cpu N index M]\n"
" %s %s peek MAP\n"
" %s %s push MAP value VALUE\n"
" %s %s pop MAP\n"
" %s %s enqueue MAP value VALUE\n"
" %s %s dequeue MAP\n"
" %s %s help\n"
"\n"
" " HELP_SPEC_MAP "\n"
@ -1189,7 +1242,7 @@ static int do_help(int argc, char **argv)
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
bin_name, argv[-2]);
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
return 0;
}
@ -1209,6 +1262,8 @@ static const struct cmd cmds[] = {
{ "peek", do_lookup },
{ "push", do_update },
{ "enqueue", do_update },
{ "pop", do_pop_dequeue },
{ "dequeue", do_pop_dequeue },
{ 0 }
};