bpftool: add pop and dequeue commands
authorStanislav Fomichev <sdf@google.com>
Wed, 16 Jan 2019 19:10:04 +0000 (11:10 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Thu, 17 Jan 2019 09:30:32 +0000 (10:30 +0100)
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>
tools/bpf/bpftool/Documentation/bpftool-map.rst
tools/bpf/bpftool/map.c

index 435a79d2eed5673ecfae48746ea3e41513ac6157..0584c31d3fe2582b5165ab477c1f15e0136edbac 100644 (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.
 
index 6b5fcbe2d9d4b59a962cc3495123ca488c7bb109..850c99ac980f9e2613a69f403e0b9de983aef727 100644 (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 }
 };