Merge branch 'bpftool-flow-dissector'
Stanislav Fomichev says: ==================== v5 changes: * FILE -> PATH for load/loadall (can be either file or directory now) * simpler implementation for __bpf_program__pin_name * removed p_err for REQ_ARGS checks * parse_atach_detach_args -> parse_attach_detach_args * for -> while in bpf_object__pin_{programs,maps} recovery v4 changes: * addressed another round of comments/style issues from Jakub Kicinski & Quentin Monnet (thanks!) * implemented bpf_object__pin_maps and bpf_object__pin_programs helpers and used them in bpf_program__pin * added new pin_name to bpf_program so bpf_program__pin works with sections that contain '/' * moved *loadall* command implementation into a separate patch * added patch that implements *pinmaps* to pin maps when doing load/loadall v3 changes: * (maybe) better cleanup for partial failure in bpf_object__pin * added special case in bpf_program__pin for programs with single instances v2 changes: * addressed comments/style issues from Jakub Kicinski & Quentin Monnet * removed logic that populates jump table * added cleanup for partial failure in bpf_object__pin This patch series adds support for loading and attaching flow dissector programs from the bpftool: * first patch fixes flow dissector section name in the selftests (so libbpf auto-detection works) * second patch adds proper cleanup to bpf_object__pin, parts of which are now being used to attach all flow dissector progs/maps * third patch adds special case in bpf_program__pin for programs with single instances (we don't create <prog>/0 pin anymore, just <prog>) * forth patch adds pin_name to the bpf_program struct which is now used as a pin name in bpf_program__pin et al * fifth patch adds *loadall* command that pins all programs, not just the first one * sixth patch adds *pinmaps* argument to load/loadall to let users pin all maps of the obj file * seventh patch adds actual flow_dissector support to the bpftool and an example ==================== Acked-by: Quentin Monnet <quentin.monnet@netronome.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Коммит
f2cbf95826
|
@ -15,7 +15,8 @@ SYNOPSIS
|
|||
*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
|
||||
|
||||
*COMMANDS* :=
|
||||
{ **show** | **list** | **dump xlated** | **dump jited** | **pin** | **load** | **help** }
|
||||
{ **show** | **list** | **dump xlated** | **dump jited** | **pin** | **load**
|
||||
| **loadall** | **help** }
|
||||
|
||||
MAP COMMANDS
|
||||
=============
|
||||
|
@ -24,9 +25,9 @@ MAP COMMANDS
|
|||
| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
|
||||
| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
|
||||
| **bpftool** **prog pin** *PROG* *FILE*
|
||||
| **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
|
||||
| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* *MAP*
|
||||
| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* *MAP*
|
||||
| **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
|
||||
| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*]
|
||||
| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*]
|
||||
| **bpftool** **prog help**
|
||||
|
|
||||
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
|
||||
|
@ -39,7 +40,9 @@ MAP COMMANDS
|
|||
| **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** |
|
||||
| **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6**
|
||||
| }
|
||||
| *ATTACH_TYPE* := { **msg_verdict** | **skb_verdict** | **skb_parse** }
|
||||
| *ATTACH_TYPE* := {
|
||||
| **msg_verdict** | **skb_verdict** | **skb_parse** | **flow_dissector**
|
||||
| }
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
@ -79,8 +82,11 @@ DESCRIPTION
|
|||
contain a dot character ('.'), which is reserved for future
|
||||
extensions of *bpffs*.
|
||||
|
||||
**bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
|
||||
Load bpf program from binary *OBJ* and pin as *FILE*.
|
||||
**bpftool prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*]
|
||||
Load bpf program(s) from binary *OBJ* and pin as *PATH*.
|
||||
**bpftool prog load** pins only the first program from the
|
||||
*OBJ* as *PATH*. **bpftool prog loadall** pins all programs
|
||||
from the *OBJ* under *PATH* directory.
|
||||
**type** is optional, if not specified program type will be
|
||||
inferred from section names.
|
||||
By default bpftool will create new maps as declared in the ELF
|
||||
|
@ -92,18 +98,24 @@ DESCRIPTION
|
|||
use, referring to it by **id** or through a **pinned** file.
|
||||
If **dev** *NAME* is specified program will be loaded onto
|
||||
given networking device (offload).
|
||||
Optional **pinmaps** argument can be provided to pin all
|
||||
maps under *MAP_DIR* directory.
|
||||
|
||||
Note: *FILE* must be located in *bpffs* mount. It must not
|
||||
Note: *PATH* must be located in *bpffs* mount. It must not
|
||||
contain a dot character ('.'), which is reserved for future
|
||||
extensions of *bpffs*.
|
||||
|
||||
**bpftool prog attach** *PROG* *ATTACH_TYPE* *MAP*
|
||||
Attach bpf program *PROG* (with type specified by *ATTACH_TYPE*)
|
||||
to the map *MAP*.
|
||||
**bpftool prog attach** *PROG* *ATTACH_TYPE* [*MAP*]
|
||||
Attach bpf program *PROG* (with type specified by
|
||||
*ATTACH_TYPE*). Most *ATTACH_TYPEs* require a *MAP*
|
||||
parameter, with the exception of *flow_dissector* which is
|
||||
attached to current networking name space.
|
||||
|
||||
**bpftool prog detach** *PROG* *ATTACH_TYPE* *MAP*
|
||||
Detach bpf program *PROG* (with type specified by *ATTACH_TYPE*)
|
||||
from the map *MAP*.
|
||||
**bpftool prog detach** *PROG* *ATTACH_TYPE* [*MAP*]
|
||||
Detach bpf program *PROG* (with type specified by
|
||||
*ATTACH_TYPE*). Most *ATTACH_TYPEs* require a *MAP*
|
||||
parameter, with the exception of *flow_dissector* which is
|
||||
detached from the current networking name space.
|
||||
|
||||
**bpftool prog help**
|
||||
Print short help message.
|
||||
|
|
|
@ -243,7 +243,7 @@ _bpftool()
|
|||
# Completion depends on object and command in use
|
||||
case $object in
|
||||
prog)
|
||||
if [[ $command != "load" ]]; then
|
||||
if [[ $command != "load" && $command != "loadall" ]]; then
|
||||
case $prev in
|
||||
id)
|
||||
_bpftool_get_prog_ids
|
||||
|
@ -299,7 +299,8 @@ _bpftool()
|
|||
fi
|
||||
|
||||
if [[ ${#words[@]} == 6 ]]; then
|
||||
COMPREPLY=( $( compgen -W "msg_verdict skb_verdict skb_parse" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "msg_verdict skb_verdict \
|
||||
skb_parse flow_dissector" -- "$cur" ) )
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
@ -309,7 +310,7 @@ _bpftool()
|
|||
fi
|
||||
return 0
|
||||
;;
|
||||
load)
|
||||
load|loadall)
|
||||
local obj
|
||||
|
||||
if [[ ${#words[@]} -lt 6 ]]; then
|
||||
|
@ -338,7 +339,16 @@ _bpftool()
|
|||
|
||||
case $prev in
|
||||
type)
|
||||
COMPREPLY=( $( compgen -W "socket kprobe kretprobe classifier action tracepoint raw_tracepoint xdp perf_event cgroup/skb cgroup/sock cgroup/dev lwt_in lwt_out lwt_xmit lwt_seg6local sockops sk_skb sk_msg lirc_mode2 cgroup/bind4 cgroup/bind6 cgroup/connect4 cgroup/connect6 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/post_bind4 cgroup/post_bind6" -- \
|
||||
COMPREPLY=( $( compgen -W "socket kprobe \
|
||||
kretprobe classifier flow_dissector \
|
||||
action tracepoint raw_tracepoint \
|
||||
xdp perf_event cgroup/skb cgroup/sock \
|
||||
cgroup/dev lwt_in lwt_out lwt_xmit \
|
||||
lwt_seg6local sockops sk_skb sk_msg \
|
||||
lirc_mode2 cgroup/bind4 cgroup/bind6 \
|
||||
cgroup/connect4 cgroup/connect6 \
|
||||
cgroup/sendmsg4 cgroup/sendmsg6 \
|
||||
cgroup/post_bind4 cgroup/post_bind6" -- \
|
||||
"$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
|
@ -346,7 +356,7 @@ _bpftool()
|
|||
_bpftool_get_map_ids
|
||||
return 0
|
||||
;;
|
||||
pinned)
|
||||
pinned|pinmaps)
|
||||
_filedir
|
||||
return 0
|
||||
;;
|
||||
|
@ -358,6 +368,7 @@ _bpftool()
|
|||
COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
|
||||
_bpftool_once_attr 'type'
|
||||
_bpftool_once_attr 'dev'
|
||||
_bpftool_once_attr 'pinmaps'
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -177,34 +177,23 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
|
|||
return fd;
|
||||
}
|
||||
|
||||
int do_pin_fd(int fd, const char *name)
|
||||
int mount_bpffs_for_pin(const char *name)
|
||||
{
|
||||
char err_str[ERR_MAX_LEN];
|
||||
char *file;
|
||||
char *dir;
|
||||
int err = 0;
|
||||
|
||||
err = bpf_obj_pin(fd, name);
|
||||
if (!err)
|
||||
goto out;
|
||||
|
||||
file = malloc(strlen(name) + 1);
|
||||
strcpy(file, name);
|
||||
dir = dirname(file);
|
||||
|
||||
if (errno != EPERM || is_bpffs(dir)) {
|
||||
p_err("can't pin the object (%s): %s", name, strerror(errno));
|
||||
if (is_bpffs(dir))
|
||||
/* nothing to do if already mounted */
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Attempt to mount bpffs, then retry pinning. */
|
||||
err = mnt_bpffs(dir, err_str, ERR_MAX_LEN);
|
||||
if (!err) {
|
||||
err = bpf_obj_pin(fd, name);
|
||||
if (err)
|
||||
p_err("can't pin the object (%s): %s", name,
|
||||
strerror(errno));
|
||||
} else {
|
||||
if (err) {
|
||||
err_str[ERR_MAX_LEN - 1] = '\0';
|
||||
p_err("can't mount BPF file system to pin the object (%s): %s",
|
||||
name, err_str);
|
||||
|
@ -212,10 +201,20 @@ int do_pin_fd(int fd, const char *name)
|
|||
|
||||
out_free:
|
||||
free(file);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int do_pin_fd(int fd, const char *name)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mount_bpffs_for_pin(name);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return bpf_obj_pin(fd, name);
|
||||
}
|
||||
|
||||
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
|
||||
{
|
||||
unsigned int id;
|
||||
|
|
|
@ -131,6 +131,7 @@ const char *get_fd_type_name(enum bpf_obj_type type);
|
|||
char *get_fdinfo(int fd, const char *key);
|
||||
int open_obj_pinned(char *path);
|
||||
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type);
|
||||
int mount_bpffs_for_pin(const char *name);
|
||||
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32));
|
||||
int do_pin_fd(int fd, const char *name);
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ static const char * const attach_type_strings[] = {
|
|||
[BPF_SK_SKB_STREAM_PARSER] = "stream_parser",
|
||||
[BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict",
|
||||
[BPF_SK_MSG_VERDICT] = "msg_verdict",
|
||||
[BPF_FLOW_DISSECTOR] = "flow_dissector",
|
||||
[__MAX_BPF_ATTACH_TYPE] = NULL,
|
||||
};
|
||||
|
||||
|
@ -721,30 +722,49 @@ int map_replace_compar(const void *p1, const void *p2)
|
|||
return a->idx - b->idx;
|
||||
}
|
||||
|
||||
static int parse_attach_detach_args(int argc, char **argv, int *progfd,
|
||||
enum bpf_attach_type *attach_type,
|
||||
int *mapfd)
|
||||
{
|
||||
if (!REQ_ARGS(3))
|
||||
return -EINVAL;
|
||||
|
||||
*progfd = prog_parse_fd(&argc, &argv);
|
||||
if (*progfd < 0)
|
||||
return *progfd;
|
||||
|
||||
*attach_type = parse_attach_type(*argv);
|
||||
if (*attach_type == __MAX_BPF_ATTACH_TYPE) {
|
||||
p_err("invalid attach/detach type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (*attach_type == BPF_FLOW_DISSECTOR) {
|
||||
*mapfd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NEXT_ARG();
|
||||
if (!REQ_ARGS(2))
|
||||
return -EINVAL;
|
||||
|
||||
*mapfd = map_parse_fd(&argc, &argv);
|
||||
if (*mapfd < 0)
|
||||
return *mapfd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_attach(int argc, char **argv)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
int err, mapfd, progfd;
|
||||
int err, progfd;
|
||||
int mapfd;
|
||||
|
||||
if (!REQ_ARGS(5)) {
|
||||
p_err("too few parameters for map attach");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
progfd = prog_parse_fd(&argc, &argv);
|
||||
if (progfd < 0)
|
||||
return progfd;
|
||||
|
||||
attach_type = parse_attach_type(*argv);
|
||||
if (attach_type == __MAX_BPF_ATTACH_TYPE) {
|
||||
p_err("invalid attach type");
|
||||
return -EINVAL;
|
||||
}
|
||||
NEXT_ARG();
|
||||
|
||||
mapfd = map_parse_fd(&argc, &argv);
|
||||
if (mapfd < 0)
|
||||
return mapfd;
|
||||
err = parse_attach_detach_args(argc, argv,
|
||||
&progfd, &attach_type, &mapfd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_prog_attach(progfd, mapfd, attach_type, 0);
|
||||
if (err) {
|
||||
|
@ -760,27 +780,13 @@ static int do_attach(int argc, char **argv)
|
|||
static int do_detach(int argc, char **argv)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
int err, mapfd, progfd;
|
||||
int err, progfd;
|
||||
int mapfd;
|
||||
|
||||
if (!REQ_ARGS(5)) {
|
||||
p_err("too few parameters for map detach");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
progfd = prog_parse_fd(&argc, &argv);
|
||||
if (progfd < 0)
|
||||
return progfd;
|
||||
|
||||
attach_type = parse_attach_type(*argv);
|
||||
if (attach_type == __MAX_BPF_ATTACH_TYPE) {
|
||||
p_err("invalid attach type");
|
||||
return -EINVAL;
|
||||
}
|
||||
NEXT_ARG();
|
||||
|
||||
mapfd = map_parse_fd(&argc, &argv);
|
||||
if (mapfd < 0)
|
||||
return mapfd;
|
||||
err = parse_attach_detach_args(argc, argv,
|
||||
&progfd, &attach_type, &mapfd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_prog_detach2(progfd, mapfd, attach_type);
|
||||
if (err) {
|
||||
|
@ -792,15 +798,17 @@ static int do_detach(int argc, char **argv)
|
|||
jsonw_null(json_wtr);
|
||||
return 0;
|
||||
}
|
||||
static int do_load(int argc, char **argv)
|
||||
|
||||
static int load_with_options(int argc, char **argv, bool first_prog_only)
|
||||
{
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
struct bpf_object_open_attr attr = {
|
||||
.prog_type = BPF_PROG_TYPE_UNSPEC,
|
||||
};
|
||||
struct map_replace *map_replace = NULL;
|
||||
struct bpf_program *prog = NULL, *pos;
|
||||
unsigned int old_map_fds = 0;
|
||||
struct bpf_program *prog;
|
||||
const char *pinmaps = NULL;
|
||||
struct bpf_object *obj;
|
||||
struct bpf_map *map;
|
||||
const char *pinfile;
|
||||
|
@ -905,6 +913,13 @@ static int do_load(int argc, char **argv)
|
|||
goto err_free_reuse_maps;
|
||||
}
|
||||
NEXT_ARG();
|
||||
} else if (is_prefix(*argv, "pinmaps")) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (!REQ_ARGS(1))
|
||||
goto err_free_reuse_maps;
|
||||
|
||||
pinmaps = GET_ARG();
|
||||
} else {
|
||||
p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?",
|
||||
*argv);
|
||||
|
@ -918,26 +933,25 @@ static int do_load(int argc, char **argv)
|
|||
goto err_free_reuse_maps;
|
||||
}
|
||||
|
||||
prog = bpf_program__next(NULL, obj);
|
||||
if (!prog) {
|
||||
p_err("object file doesn't contain any bpf program");
|
||||
goto err_close_obj;
|
||||
}
|
||||
bpf_object__for_each_program(pos, obj) {
|
||||
enum bpf_prog_type prog_type = attr.prog_type;
|
||||
|
||||
bpf_program__set_ifindex(prog, ifindex);
|
||||
if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) {
|
||||
const char *sec_name = bpf_program__title(prog, false);
|
||||
if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) {
|
||||
const char *sec_name = bpf_program__title(pos, false);
|
||||
|
||||
err = libbpf_prog_type_by_name(sec_name, &attr.prog_type,
|
||||
&expected_attach_type);
|
||||
if (err < 0) {
|
||||
p_err("failed to guess program type based on section name %s\n",
|
||||
sec_name);
|
||||
goto err_close_obj;
|
||||
err = libbpf_prog_type_by_name(sec_name, &prog_type,
|
||||
&expected_attach_type);
|
||||
if (err < 0) {
|
||||
p_err("failed to guess program type based on section name %s\n",
|
||||
sec_name);
|
||||
goto err_close_obj;
|
||||
}
|
||||
}
|
||||
|
||||
bpf_program__set_ifindex(pos, ifindex);
|
||||
bpf_program__set_type(pos, prog_type);
|
||||
bpf_program__set_expected_attach_type(pos, expected_attach_type);
|
||||
}
|
||||
bpf_program__set_type(prog, attr.prog_type);
|
||||
bpf_program__set_expected_attach_type(prog, expected_attach_type);
|
||||
|
||||
qsort(map_replace, old_map_fds, sizeof(*map_replace),
|
||||
map_replace_compar);
|
||||
|
@ -1003,9 +1017,39 @@ static int do_load(int argc, char **argv)
|
|||
goto err_close_obj;
|
||||
}
|
||||
|
||||
if (do_pin_fd(bpf_program__fd(prog), pinfile))
|
||||
err = mount_bpffs_for_pin(pinfile);
|
||||
if (err)
|
||||
goto err_close_obj;
|
||||
|
||||
if (first_prog_only) {
|
||||
prog = bpf_program__next(NULL, obj);
|
||||
if (!prog) {
|
||||
p_err("object file doesn't contain any bpf program");
|
||||
goto err_close_obj;
|
||||
}
|
||||
|
||||
err = bpf_obj_pin(bpf_program__fd(prog), pinfile);
|
||||
if (err) {
|
||||
p_err("failed to pin program %s",
|
||||
bpf_program__title(prog, false));
|
||||
goto err_close_obj;
|
||||
}
|
||||
} else {
|
||||
err = bpf_object__pin_programs(obj, pinfile);
|
||||
if (err) {
|
||||
p_err("failed to pin all programs");
|
||||
goto err_close_obj;
|
||||
}
|
||||
}
|
||||
|
||||
if (pinmaps) {
|
||||
err = bpf_object__pin_maps(obj, pinmaps);
|
||||
if (err) {
|
||||
p_err("failed to pin all maps");
|
||||
goto err_unpin;
|
||||
}
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_null(json_wtr);
|
||||
|
||||
|
@ -1016,6 +1060,11 @@ static int do_load(int argc, char **argv)
|
|||
|
||||
return 0;
|
||||
|
||||
err_unpin:
|
||||
if (first_prog_only)
|
||||
unlink(pinfile);
|
||||
else
|
||||
bpf_object__unpin_programs(obj, pinfile);
|
||||
err_close_obj:
|
||||
bpf_object__close(obj);
|
||||
err_free_reuse_maps:
|
||||
|
@ -1025,6 +1074,16 @@ err_free_reuse_maps:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int do_load(int argc, char **argv)
|
||||
{
|
||||
return load_with_options(argc, argv, true);
|
||||
}
|
||||
|
||||
static int do_loadall(int argc, char **argv)
|
||||
{
|
||||
return load_with_options(argc, argv, false);
|
||||
}
|
||||
|
||||
static int do_help(int argc, char **argv)
|
||||
{
|
||||
if (json_output) {
|
||||
|
@ -1037,10 +1096,12 @@ static int do_help(int argc, char **argv)
|
|||
" %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
|
||||
" %s %s dump jited PROG [{ file FILE | opcodes }]\n"
|
||||
" %s %s pin PROG FILE\n"
|
||||
" %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n"
|
||||
" [map { idx IDX | name NAME } MAP]\n"
|
||||
" %s %s attach PROG ATTACH_TYPE MAP\n"
|
||||
" %s %s detach PROG ATTACH_TYPE MAP\n"
|
||||
" %s %s { load | loadall } OBJ PATH \\\n"
|
||||
" [type TYPE] [dev NAME] \\\n"
|
||||
" [map { idx IDX | name NAME } MAP]\\\n"
|
||||
" [pinmaps MAP_DIR]\n"
|
||||
" %s %s attach PROG ATTACH_TYPE [MAP]\n"
|
||||
" %s %s detach PROG ATTACH_TYPE [MAP]\n"
|
||||
" %s %s help\n"
|
||||
"\n"
|
||||
" " HELP_SPEC_MAP "\n"
|
||||
|
@ -1052,7 +1113,8 @@ static int do_help(int argc, char **argv)
|
|||
" cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
|
||||
" cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
|
||||
" cgroup/sendmsg4 | cgroup/sendmsg6 }\n"
|
||||
" ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse }\n"
|
||||
" ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse |\n"
|
||||
" flow_dissector }\n"
|
||||
" " HELP_SPEC_OPTIONS "\n"
|
||||
"",
|
||||
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
|
||||
|
@ -1069,6 +1131,7 @@ static const struct cmd cmds[] = {
|
|||
{ "dump", do_dump },
|
||||
{ "pin", do_pin },
|
||||
{ "load", do_load },
|
||||
{ "loadall", do_loadall },
|
||||
{ "attach", do_attach },
|
||||
{ "detach", do_detach },
|
||||
{ 0 }
|
||||
|
|
|
@ -124,6 +124,10 @@ struct bpf_program {
|
|||
char *name;
|
||||
int prog_ifindex;
|
||||
char *section_name;
|
||||
/* section_name with / replaced by _; makes recursive pinning
|
||||
* in bpf_object__pin_programs easier
|
||||
*/
|
||||
char *pin_name;
|
||||
struct bpf_insn *insns;
|
||||
size_t insns_cnt, main_prog_cnt;
|
||||
enum bpf_prog_type type;
|
||||
|
@ -253,6 +257,7 @@ static void bpf_program__exit(struct bpf_program *prog)
|
|||
bpf_program__unload(prog);
|
||||
zfree(&prog->name);
|
||||
zfree(&prog->section_name);
|
||||
zfree(&prog->pin_name);
|
||||
zfree(&prog->insns);
|
||||
zfree(&prog->reloc_desc);
|
||||
|
||||
|
@ -261,6 +266,17 @@ static void bpf_program__exit(struct bpf_program *prog)
|
|||
prog->idx = -1;
|
||||
}
|
||||
|
||||
static char *__bpf_program__pin_name(struct bpf_program *prog)
|
||||
{
|
||||
char *name, *p;
|
||||
|
||||
name = p = strdup(prog->section_name);
|
||||
while ((p = strchr(p, '/')))
|
||||
*p = '_';
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_program__init(void *data, size_t size, char *section_name, int idx,
|
||||
struct bpf_program *prog)
|
||||
|
@ -279,6 +295,13 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
|
|||
goto errout;
|
||||
}
|
||||
|
||||
prog->pin_name = __bpf_program__pin_name(prog);
|
||||
if (!prog->pin_name) {
|
||||
pr_warning("failed to alloc pin name for prog under section(%d) %s\n",
|
||||
idx, section_name);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
prog->insns = malloc(size);
|
||||
if (!prog->insns) {
|
||||
pr_warning("failed to alloc insns for prog under section %s\n",
|
||||
|
@ -1699,6 +1722,34 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bpf_program__unpin_instance(struct bpf_program *prog, const char *path,
|
||||
int instance)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (prog == NULL) {
|
||||
pr_warning("invalid program pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (instance < 0 || instance >= prog->instances.nr) {
|
||||
pr_warning("invalid prog instance %d of prog %s (max %d)\n",
|
||||
instance, prog->section_name, prog->instances.nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = unlink(path);
|
||||
if (err != 0)
|
||||
return -errno;
|
||||
pr_debug("unpinned program '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int make_dir(const char *path)
|
||||
{
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
|
@ -1733,10 +1784,78 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prog->instances.nr == 1) {
|
||||
/* don't create subdirs when pinning single instance */
|
||||
return bpf_program__pin_instance(prog, path, 0);
|
||||
}
|
||||
|
||||
err = make_dir(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < prog->instances.nr; i++) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%d", path, i);
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin;
|
||||
}
|
||||
|
||||
err = bpf_program__pin_instance(prog, buf, i);
|
||||
if (err)
|
||||
goto err_unpin;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin:
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%d", path, i);
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_program__unpin_instance(prog, buf, i);
|
||||
}
|
||||
|
||||
rmdir(path);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_program__unpin(struct bpf_program *prog, const char *path)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (prog == NULL) {
|
||||
pr_warning("invalid program pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prog->instances.nr <= 0) {
|
||||
pr_warning("no instances of prog %s to pin\n",
|
||||
prog->section_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prog->instances.nr == 1) {
|
||||
/* don't create subdirs when pinning single instance */
|
||||
return bpf_program__unpin_instance(prog, path, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < prog->instances.nr; i++) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
@ -1747,11 +1866,15 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
|
|||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_program__pin_instance(prog, buf, i);
|
||||
err = bpf_program__unpin_instance(prog, buf, i);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rmdir(path);
|
||||
if (err)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1776,12 +1899,33 @@ int bpf_map__pin(struct bpf_map *map, const char *path)
|
|||
}
|
||||
|
||||
pr_debug("pinned map '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
int bpf_map__unpin(struct bpf_map *map, const char *path)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (map == NULL) {
|
||||
pr_warning("invalid map pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = unlink(path);
|
||||
if (err != 0)
|
||||
return -errno;
|
||||
pr_debug("unpinned map '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin_maps(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
|
||||
|
@ -1797,6 +1941,53 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
bpf_map__for_each(map, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
bpf_map__name(map));
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin_maps;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin_maps;
|
||||
}
|
||||
|
||||
err = bpf_map__pin(map, buf);
|
||||
if (err)
|
||||
goto err_unpin_maps;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin_maps:
|
||||
while ((map = bpf_map__prev(map, obj))) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
bpf_map__name(map));
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_map__unpin(map, buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_object__unpin_maps(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
bpf_map__for_each(map, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
@ -1808,23 +1999,90 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
|||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_map__pin(map, buf);
|
||||
err = bpf_map__unpin(map, buf);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin_programs(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
if (!obj->loaded) {
|
||||
pr_warning("object not yet loaded; load it first\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = make_dir(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->section_name);
|
||||
prog->pin_name);
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin_programs;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin_programs;
|
||||
}
|
||||
|
||||
err = bpf_program__pin(prog, buf);
|
||||
if (err)
|
||||
goto err_unpin_programs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin_programs:
|
||||
while ((prog = bpf_program__prev(prog, obj))) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->pin_name);
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_program__unpin(prog, buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_object__unpin_programs(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->pin_name);
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_program__pin(prog, buf);
|
||||
err = bpf_program__unpin(prog, buf);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -1832,6 +2090,23 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bpf_object__pin_maps(obj, path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_object__pin_programs(obj, path);
|
||||
if (err) {
|
||||
bpf_object__unpin_maps(obj, path);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bpf_object__close(struct bpf_object *obj)
|
||||
{
|
||||
size_t i;
|
||||
|
@ -1918,23 +2193,20 @@ void *bpf_object__priv(struct bpf_object *obj)
|
|||
}
|
||||
|
||||
static struct bpf_program *
|
||||
__bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
|
||||
__bpf_program__iter(struct bpf_program *p, struct bpf_object *obj, int i)
|
||||
{
|
||||
size_t idx;
|
||||
ssize_t idx;
|
||||
|
||||
if (!obj->programs)
|
||||
return NULL;
|
||||
/* First handler */
|
||||
if (prev == NULL)
|
||||
return &obj->programs[0];
|
||||
|
||||
if (prev->obj != obj) {
|
||||
if (p->obj != obj) {
|
||||
pr_warning("error: program handler doesn't match object\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idx = (prev - obj->programs) + 1;
|
||||
if (idx >= obj->nr_programs)
|
||||
idx = (p - obj->programs) + i;
|
||||
if (idx >= obj->nr_programs || idx < 0)
|
||||
return NULL;
|
||||
return &obj->programs[idx];
|
||||
}
|
||||
|
@ -1944,8 +2216,29 @@ bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
|
|||
{
|
||||
struct bpf_program *prog = prev;
|
||||
|
||||
if (prev == NULL)
|
||||
return obj->programs;
|
||||
|
||||
do {
|
||||
prog = __bpf_program__next(prog, obj);
|
||||
prog = __bpf_program__iter(prog, obj, 1);
|
||||
} while (prog && bpf_program__is_function_storage(prog, obj));
|
||||
|
||||
return prog;
|
||||
}
|
||||
|
||||
struct bpf_program *
|
||||
bpf_program__prev(struct bpf_program *next, struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_program *prog = next;
|
||||
|
||||
if (next == NULL) {
|
||||
if (!obj->nr_programs)
|
||||
return NULL;
|
||||
return obj->programs + obj->nr_programs - 1;
|
||||
}
|
||||
|
||||
do {
|
||||
prog = __bpf_program__iter(prog, obj, -1);
|
||||
} while (prog && bpf_program__is_function_storage(prog, obj));
|
||||
|
||||
return prog;
|
||||
|
@ -2272,10 +2565,10 @@ void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
|
|||
map->map_ifindex = ifindex;
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
||||
static struct bpf_map *
|
||||
__bpf_map__iter(struct bpf_map *m, struct bpf_object *obj, int i)
|
||||
{
|
||||
size_t idx;
|
||||
ssize_t idx;
|
||||
struct bpf_map *s, *e;
|
||||
|
||||
if (!obj || !obj->maps)
|
||||
|
@ -2284,21 +2577,39 @@ bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
|||
s = obj->maps;
|
||||
e = obj->maps + obj->nr_maps;
|
||||
|
||||
if (prev == NULL)
|
||||
return s;
|
||||
|
||||
if ((prev < s) || (prev >= e)) {
|
||||
if ((m < s) || (m >= e)) {
|
||||
pr_warning("error in %s: map handler doesn't belong to object\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idx = (prev - obj->maps) + 1;
|
||||
if (idx >= obj->nr_maps)
|
||||
idx = (m - obj->maps) + i;
|
||||
if (idx >= obj->nr_maps || idx < 0)
|
||||
return NULL;
|
||||
return &obj->maps[idx];
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
||||
{
|
||||
if (prev == NULL)
|
||||
return obj->maps;
|
||||
|
||||
return __bpf_map__iter(prev, obj, 1);
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__prev(struct bpf_map *next, struct bpf_object *obj)
|
||||
{
|
||||
if (next == NULL) {
|
||||
if (!obj->nr_maps)
|
||||
return NULL;
|
||||
return obj->maps + obj->nr_maps - 1;
|
||||
}
|
||||
|
||||
return __bpf_map__iter(next, obj, -1);
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_object__find_map_by_name(struct bpf_object *obj, const char *name)
|
||||
{
|
||||
|
|
|
@ -71,6 +71,13 @@ struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr,
|
|||
LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf,
|
||||
size_t obj_buf_sz,
|
||||
const char *name);
|
||||
LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path);
|
||||
LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
|
||||
LIBBPF_API void bpf_object__close(struct bpf_object *object);
|
||||
|
||||
|
@ -112,6 +119,9 @@ LIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog,
|
|||
(pos) != NULL; \
|
||||
(pos) = bpf_program__next((pos), (obj)))
|
||||
|
||||
LIBBPF_API struct bpf_program *bpf_program__prev(struct bpf_program *prog,
|
||||
struct bpf_object *obj);
|
||||
|
||||
typedef void (*bpf_program_clear_priv_t)(struct bpf_program *,
|
||||
void *);
|
||||
|
||||
|
@ -131,7 +141,11 @@ LIBBPF_API int bpf_program__fd(struct bpf_program *prog);
|
|||
LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog,
|
||||
const char *path,
|
||||
int instance);
|
||||
LIBBPF_API int bpf_program__unpin_instance(struct bpf_program *prog,
|
||||
const char *path,
|
||||
int instance);
|
||||
LIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path);
|
||||
LIBBPF_API int bpf_program__unpin(struct bpf_program *prog, const char *path);
|
||||
LIBBPF_API void bpf_program__unload(struct bpf_program *prog);
|
||||
|
||||
struct bpf_insn;
|
||||
|
@ -260,6 +274,9 @@ bpf_map__next(struct bpf_map *map, struct bpf_object *obj);
|
|||
(pos) != NULL; \
|
||||
(pos) = bpf_map__next((pos), (obj)))
|
||||
|
||||
LIBBPF_API struct bpf_map *
|
||||
bpf_map__prev(struct bpf_map *map, struct bpf_object *obj);
|
||||
|
||||
LIBBPF_API int bpf_map__fd(struct bpf_map *map);
|
||||
LIBBPF_API const struct bpf_map_def *bpf_map__def(struct bpf_map *map);
|
||||
LIBBPF_API const char *bpf_map__name(struct bpf_map *map);
|
||||
|
@ -274,6 +291,7 @@ LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd);
|
|||
LIBBPF_API bool bpf_map__is_offload_neutral(struct bpf_map *map);
|
||||
LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
|
||||
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
||||
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
||||
|
||||
LIBBPF_API long libbpf_get_error(const void *ptr);
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ static __always_inline int parse_eth_proto(struct __sk_buff *skb, __be16 proto)
|
|||
return BPF_DROP;
|
||||
}
|
||||
|
||||
SEC("dissect")
|
||||
SEC("flow_dissector")
|
||||
int _dissect(struct __sk_buff *skb)
|
||||
{
|
||||
if (!skb->vlan_present)
|
||||
|
|
|
@ -59,7 +59,7 @@ else
|
|||
fi
|
||||
|
||||
# Attach BPF program
|
||||
./flow_dissector_load -p bpf_flow.o -s dissect
|
||||
./flow_dissector_load -p bpf_flow.o -s flow_dissector
|
||||
|
||||
# Setup
|
||||
tc qdisc add dev lo ingress
|
||||
|
|
Загрузка…
Ссылка в новой задаче