Message ID | 20200507053936.1545284-1-yhs@fb.com |
---|---|
State | Changes Requested |
Delegated to: | BPF Maintainers |
Headers | show |
Series | bpf: implement bpf iterator for kernel data | expand |
On Wed, May 6, 2020 at 10:40 PM Yonghong Song <yhs@fb.com> wrote: > > Currently, only one command is supported > bpftool iter pin <bpf_prog.o> <path> > > It will pin the trace/iter bpf program in > the object file <bpf_prog.o> to the <path> > where <path> should be on a bpffs mount. > > For example, > $ bpftool iter pin ./bpf_iter_ipv6_route.o \ > /sys/fs/bpf/my_route > User can then do a `cat` to print out the results: > $ cat /sys/fs/bpf/my_route > fe800000000000000000000000000000 40 00000000000000000000000000000000 ... > 00000000000000000000000000000000 00 00000000000000000000000000000000 ... > 00000000000000000000000000000001 80 00000000000000000000000000000000 ... > fe800000000000008c0162fffebdfd57 80 00000000000000000000000000000000 ... > ff000000000000000000000000000000 08 00000000000000000000000000000000 ... > 00000000000000000000000000000000 00 00000000000000000000000000000000 ... > > The implementation for ipv6_route iterator is in one of subsequent > patches. > > This patch also added BPF_LINK_TYPE_ITER to link query. > > In the future, we may add additional parameters to pin command > by parameterizing the bpf iterator. For example, a map_id or pid > may be added to let bpf program only traverses a single map or task, > similar to kernel seq_file single_open(). > > We may also add introspection command for targets/iterators by > leveraging the bpf_iter itself. > > Signed-off-by: Yonghong Song <yhs@fb.com> > --- > .../bpftool/Documentation/bpftool-iter.rst | 83 ++++++++++++++++++ > tools/bpf/bpftool/bash-completion/bpftool | 13 +++ > tools/bpf/bpftool/iter.c | 84 +++++++++++++++++++ > tools/bpf/bpftool/link.c | 1 + > tools/bpf/bpftool/main.c | 3 +- > tools/bpf/bpftool/main.h | 1 + > 6 files changed, 184 insertions(+), 1 deletion(-) > create mode 100644 tools/bpf/bpftool/Documentation/bpftool-iter.rst > create mode 100644 tools/bpf/bpftool/iter.c > [...] > diff --git a/tools/bpf/bpftool/iter.c b/tools/bpf/bpftool/iter.c > new file mode 100644 > index 000000000000..a8fb1349c103 > --- /dev/null > +++ b/tools/bpf/bpftool/iter.c > @@ -0,0 +1,84 @@ > +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > +// Copyright (C) 2020 Facebook > + > +#define _GNU_SOURCE > +#include <linux/err.h> > +#include <bpf/libbpf.h> > + > +#include "main.h" > + > +static int do_pin(int argc, char **argv) > +{ > + const char *objfile, *path; > + struct bpf_program *prog; > + struct bpf_object *obj; > + struct bpf_link *link; > + int err; > + > + if (!REQ_ARGS(2)) > + usage(); > + > + objfile = GET_ARG(); > + path = GET_ARG(); > + > + obj = bpf_object__open(objfile); > + if (IS_ERR_OR_NULL(obj)) { nit: can't be NULL > + p_err("can't open objfile %s", objfile); > + return -1; > + } > + > + err = bpf_object__load(obj); > + if (err) { > + p_err("can't load objfile %s", objfile); > + goto close_obj; > + } > + > + prog = bpf_program__next(NULL, obj); check for null and printf error? Crashing is not good. > + link = bpf_program__attach_iter(prog, NULL); > + if (IS_ERR(link)) { > + err = PTR_ERR(link); > + p_err("attach_iter failed for program %s", > + bpf_program__name(prog)); > + goto close_obj; > + } > + > + err = mount_bpffs_for_pin(path); > + if (err) > + goto close_link; > + > + err = bpf_link__pin(link, path); > + if (err) { > + p_err("pin_iter failed for program %s to path %s", > + bpf_program__name(prog), path); > + goto close_link; > + } > + > +close_link: > + bpf_link__disconnect(link); this is wrong, just destroy() > + bpf_link__destroy(link); > +close_obj: > + bpf_object__close(obj); > + return err; > +} > + [...]
On 5/8/20 12:51 PM, Andrii Nakryiko wrote: > On Wed, May 6, 2020 at 10:40 PM Yonghong Song <yhs@fb.com> wrote: >> >> Currently, only one command is supported >> bpftool iter pin <bpf_prog.o> <path> >> >> It will pin the trace/iter bpf program in >> the object file <bpf_prog.o> to the <path> >> where <path> should be on a bpffs mount. >> >> For example, >> $ bpftool iter pin ./bpf_iter_ipv6_route.o \ >> /sys/fs/bpf/my_route >> User can then do a `cat` to print out the results: >> $ cat /sys/fs/bpf/my_route >> fe800000000000000000000000000000 40 00000000000000000000000000000000 ... >> 00000000000000000000000000000000 00 00000000000000000000000000000000 ... >> 00000000000000000000000000000001 80 00000000000000000000000000000000 ... >> fe800000000000008c0162fffebdfd57 80 00000000000000000000000000000000 ... >> ff000000000000000000000000000000 08 00000000000000000000000000000000 ... >> 00000000000000000000000000000000 00 00000000000000000000000000000000 ... >> >> The implementation for ipv6_route iterator is in one of subsequent >> patches. >> >> This patch also added BPF_LINK_TYPE_ITER to link query. >> >> In the future, we may add additional parameters to pin command >> by parameterizing the bpf iterator. For example, a map_id or pid >> may be added to let bpf program only traverses a single map or task, >> similar to kernel seq_file single_open(). >> >> We may also add introspection command for targets/iterators by >> leveraging the bpf_iter itself. >> >> Signed-off-by: Yonghong Song <yhs@fb.com> >> --- >> .../bpftool/Documentation/bpftool-iter.rst | 83 ++++++++++++++++++ >> tools/bpf/bpftool/bash-completion/bpftool | 13 +++ >> tools/bpf/bpftool/iter.c | 84 +++++++++++++++++++ >> tools/bpf/bpftool/link.c | 1 + >> tools/bpf/bpftool/main.c | 3 +- >> tools/bpf/bpftool/main.h | 1 + >> 6 files changed, 184 insertions(+), 1 deletion(-) >> create mode 100644 tools/bpf/bpftool/Documentation/bpftool-iter.rst >> create mode 100644 tools/bpf/bpftool/iter.c >> > > [...] > >> diff --git a/tools/bpf/bpftool/iter.c b/tools/bpf/bpftool/iter.c >> new file mode 100644 >> index 000000000000..a8fb1349c103 >> --- /dev/null >> +++ b/tools/bpf/bpftool/iter.c >> @@ -0,0 +1,84 @@ >> +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) >> +// Copyright (C) 2020 Facebook >> + >> +#define _GNU_SOURCE >> +#include <linux/err.h> >> +#include <bpf/libbpf.h> >> + >> +#include "main.h" >> + >> +static int do_pin(int argc, char **argv) >> +{ >> + const char *objfile, *path; >> + struct bpf_program *prog; >> + struct bpf_object *obj; >> + struct bpf_link *link; >> + int err; >> + >> + if (!REQ_ARGS(2)) >> + usage(); >> + >> + objfile = GET_ARG(); >> + path = GET_ARG(); >> + >> + obj = bpf_object__open(objfile); >> + if (IS_ERR_OR_NULL(obj)) { > > nit: can't be NULL Ack. Will change. > >> + p_err("can't open objfile %s", objfile); >> + return -1; >> + } >> + >> + err = bpf_object__load(obj); >> + if (err) { >> + p_err("can't load objfile %s", objfile); >> + goto close_obj; >> + } >> + >> + prog = bpf_program__next(NULL, obj); > > check for null and printf error? Crashing is not good. Make sense. Will change. > >> + link = bpf_program__attach_iter(prog, NULL); >> + if (IS_ERR(link)) { >> + err = PTR_ERR(link); >> + p_err("attach_iter failed for program %s", >> + bpf_program__name(prog)); >> + goto close_obj; >> + } >> + >> + err = mount_bpffs_for_pin(path); >> + if (err) >> + goto close_link; >> + >> + err = bpf_link__pin(link, path); >> + if (err) { >> + p_err("pin_iter failed for program %s to path %s", >> + bpf_program__name(prog), path); >> + goto close_link; >> + } >> + >> +close_link: >> + bpf_link__disconnect(link); > > this is wrong, just destroy() Will change. > >> + bpf_link__destroy(link); >> +close_obj: >> + bpf_object__close(obj); >> + return err; >> +} >> + > > [...] >
diff --git a/tools/bpf/bpftool/Documentation/bpftool-iter.rst b/tools/bpf/bpftool/Documentation/bpftool-iter.rst new file mode 100644 index 000000000000..13b173d93890 --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-iter.rst @@ -0,0 +1,83 @@ +============ +bpftool-iter +============ +------------------------------------------------------------------------------- +tool to create BPF iterators +------------------------------------------------------------------------------- + +:Manual section: 8 + +SYNOPSIS +======== + + **bpftool** [*OPTIONS*] **iter** *COMMAND* + + *COMMANDS* := { **pin** | **help** } + +ITER COMMANDS +=================== + +| **bpftool** **iter pin** *OBJ* *PATH* +| **bpftool** **iter help** +| +| *OBJ* := /a/file/of/bpf_iter_target.o + + +DESCRIPTION +=========== + **bpftool iter pin** *OBJ* *PATH* + A bpf iterator combines a kernel iterating of + particular kernel data (e.g., tasks, bpf_maps, etc.) + and a bpf program called for each kernel data object + (e.g., one task, one bpf_map, etc.). User space can + *read* kernel iterator output through *read()* syscall. + + The *pin* command creates a bpf iterator from *OBJ*, + and pin it to *PATH*. The *PATH* should be located + in *bpffs* mount. It must not contain a dot + character ('.'), which is reserved for future extensions + of *bpffs*. + + User can then *cat PATH* to see the bpf iterator output. + + **bpftool iter help** + Print short help message. + +OPTIONS +======= + -h, --help + Print short generic help message (similar to **bpftool help**). + + -V, --version + Print version number (similar to **bpftool version**). + + -d, --debug + Print all logs available, even debug-level information. This + includes logs from libbpf as well as from the verifier, when + attempting to load programs. + +EXAMPLES +======== +**# bpftool iter pin bpf_iter_netlink.o /sys/fs/bpf/my_netlink** + +:: + + Create a file-based bpf iterator from bpf_iter_netlink.o and pin it + to /sys/fs/bpf/my_netlink + + +SEE ALSO +======== + **bpf**\ (2), + **bpf-helpers**\ (7), + **bpftool**\ (8), + **bpftool-prog**\ (8), + **bpftool-map**\ (8), + **bpftool-link**\ (8), + **bpftool-cgroup**\ (8), + **bpftool-feature**\ (8), + **bpftool-net**\ (8), + **bpftool-perf**\ (8), + **bpftool-btf**\ (8) + **bpftool-gen**\ (8) + **bpftool-struct_ops**\ (8) diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index fc989ead7313..9f0f20e73b87 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -610,6 +610,19 @@ _bpftool() ;; esac ;; + iter) + case $command in + pin) + _filedir + return 0 + ;; + *) + [[ $prev == $object ]] && \ + COMPREPLY=( $( compgen -W 'pin help' \ + -- "$cur" ) ) + ;; + esac + ;; map) local MAP_TYPE='id pinned name' case $command in diff --git a/tools/bpf/bpftool/iter.c b/tools/bpf/bpftool/iter.c new file mode 100644 index 000000000000..a8fb1349c103 --- /dev/null +++ b/tools/bpf/bpftool/iter.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +// Copyright (C) 2020 Facebook + +#define _GNU_SOURCE +#include <linux/err.h> +#include <bpf/libbpf.h> + +#include "main.h" + +static int do_pin(int argc, char **argv) +{ + const char *objfile, *path; + struct bpf_program *prog; + struct bpf_object *obj; + struct bpf_link *link; + int err; + + if (!REQ_ARGS(2)) + usage(); + + objfile = GET_ARG(); + path = GET_ARG(); + + obj = bpf_object__open(objfile); + if (IS_ERR_OR_NULL(obj)) { + p_err("can't open objfile %s", objfile); + return -1; + } + + err = bpf_object__load(obj); + if (err) { + p_err("can't load objfile %s", objfile); + goto close_obj; + } + + prog = bpf_program__next(NULL, obj); + link = bpf_program__attach_iter(prog, NULL); + if (IS_ERR(link)) { + err = PTR_ERR(link); + p_err("attach_iter failed for program %s", + bpf_program__name(prog)); + goto close_obj; + } + + err = mount_bpffs_for_pin(path); + if (err) + goto close_link; + + err = bpf_link__pin(link, path); + if (err) { + p_err("pin_iter failed for program %s to path %s", + bpf_program__name(prog), path); + goto close_link; + } + +close_link: + bpf_link__disconnect(link); + bpf_link__destroy(link); +close_obj: + bpf_object__close(obj); + return err; +} + +static int do_help(int argc, char **argv) +{ + fprintf(stderr, + "Usage: %s %s pin OBJ PATH\n" + " %s %s help\n" + "\n", + bin_name, argv[-2], bin_name, argv[-2]); + + return 0; +} + +static const struct cmd cmds[] = { + { "help", do_help }, + { "pin", do_pin }, + { 0 } +}; + +int do_iter(int argc, char **argv) +{ + return cmd_select(cmds, argc, argv, do_help); +} diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index adc7dc431ed8..b6a0b35c78ae 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -16,6 +16,7 @@ static const char * const link_type_name[] = { [BPF_LINK_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", [BPF_LINK_TYPE_TRACING] = "tracing", [BPF_LINK_TYPE_CGROUP] = "cgroup", + [BPF_LINK_TYPE_ITER] = "iter", }; static int link_parse_fd(int *argc, char ***argv) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 1413a154806e..46bd716a9d86 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -59,7 +59,7 @@ static int do_help(int argc, char **argv) " %s batch file FILE\n" " %s version\n" "\n" - " OBJECT := { prog | map | link | cgroup | perf | net | feature | btf | gen | struct_ops }\n" + " OBJECT := { prog | map | link | cgroup | perf | net | feature | btf | gen | struct_ops | iter }\n" " " HELP_SPEC_OPTIONS "\n" "", bin_name, bin_name, bin_name); @@ -224,6 +224,7 @@ static const struct cmd cmds[] = { { "btf", do_btf }, { "gen", do_gen }, { "struct_ops", do_struct_ops }, + { "iter", do_iter }, { "version", do_version }, { 0 } }; diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 9b1fb81a8331..a41cefabccaf 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -199,6 +199,7 @@ int do_feature(int argc, char **argv); int do_btf(int argc, char **argv); int do_gen(int argc, char **argv); int do_struct_ops(int argc, char **argv); +int do_iter(int argc, char **argv); int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what); int prog_parse_fd(int *argc, char ***argv);
Currently, only one command is supported bpftool iter pin <bpf_prog.o> <path> It will pin the trace/iter bpf program in the object file <bpf_prog.o> to the <path> where <path> should be on a bpffs mount. For example, $ bpftool iter pin ./bpf_iter_ipv6_route.o \ /sys/fs/bpf/my_route User can then do a `cat` to print out the results: $ cat /sys/fs/bpf/my_route fe800000000000000000000000000000 40 00000000000000000000000000000000 ... 00000000000000000000000000000000 00 00000000000000000000000000000000 ... 00000000000000000000000000000001 80 00000000000000000000000000000000 ... fe800000000000008c0162fffebdfd57 80 00000000000000000000000000000000 ... ff000000000000000000000000000000 08 00000000000000000000000000000000 ... 00000000000000000000000000000000 00 00000000000000000000000000000000 ... The implementation for ipv6_route iterator is in one of subsequent patches. This patch also added BPF_LINK_TYPE_ITER to link query. In the future, we may add additional parameters to pin command by parameterizing the bpf iterator. For example, a map_id or pid may be added to let bpf program only traverses a single map or task, similar to kernel seq_file single_open(). We may also add introspection command for targets/iterators by leveraging the bpf_iter itself. Signed-off-by: Yonghong Song <yhs@fb.com> --- .../bpftool/Documentation/bpftool-iter.rst | 83 ++++++++++++++++++ tools/bpf/bpftool/bash-completion/bpftool | 13 +++ tools/bpf/bpftool/iter.c | 84 +++++++++++++++++++ tools/bpf/bpftool/link.c | 1 + tools/bpf/bpftool/main.c | 3 +- tools/bpf/bpftool/main.h | 1 + 6 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 tools/bpf/bpftool/Documentation/bpftool-iter.rst create mode 100644 tools/bpf/bpftool/iter.c