Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2cbf958 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

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: default avatarQuentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 0157edc8 092f0892
Loading
Loading
Loading
Loading
+27 −15
Original line number Diff line number Diff line
@@ -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 detach** *PROG* *ATTACH_TYPE* *MAP*
                  Detach bpf program *PROG* (with type specified by *ATTACH_TYPE*)
                  from 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*). 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.
+16 −5
Original line number Diff line number Diff line
@@ -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
+15 −16
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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);

+123 −60
Original line number Diff line number Diff line
@@ -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 do_attach(int argc, char **argv)
static int parse_attach_detach_args(int argc, char **argv, int *progfd,
				    enum bpf_attach_type *attach_type,
				    int *mapfd)
{
	enum bpf_attach_type attach_type;
	int err, mapfd, progfd;
	if (!REQ_ARGS(3))
		return -EINVAL;

	if (!REQ_ARGS(5)) {
		p_err("too few parameters for map attach");
	*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;
	}

	progfd = prog_parse_fd(&argc, &argv);
	if (progfd < 0)
		return progfd;
	if (*attach_type == BPF_FLOW_DISSECTOR) {
		*mapfd = -1;
		return 0;
	}

	attach_type = parse_attach_type(*argv);
	if (attach_type == __MAX_BPF_ATTACH_TYPE) {
		p_err("invalid attach type");
	NEXT_ARG();
	if (!REQ_ARGS(2))
		return -EINVAL;

	*mapfd = map_parse_fd(&argc, &argv);
	if (*mapfd < 0)
		return *mapfd;

	return 0;
}
	NEXT_ARG();

	mapfd = map_parse_fd(&argc, &argv);
	if (mapfd < 0)
		return mapfd;
static int do_attach(int argc, char **argv)
{
	enum bpf_attach_type attach_type;
	int err, progfd;
	int 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,17 +933,13 @@ 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);
			const char *sec_name = bpf_program__title(pos, false);

		err = libbpf_prog_type_by_name(sec_name, &attr.prog_type,
			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",
@@ -936,8 +947,11 @@ static int do_load(int argc, char **argv)
				goto err_close_obj;
			}
		}
	bpf_program__set_type(prog, attr.prog_type);
	bpf_program__set_expected_attach_type(prog, expected_attach_type);

		bpf_program__set_ifindex(pos, ifindex);
		bpf_program__set_type(pos, prog_type);
		bpf_program__set_expected_attach_type(pos, expected_attach_type);
	}

	qsort(map_replace, old_map_fds, sizeof(*map_replace),
	      map_replace_compar);
@@ -1003,8 +1017,38 @@ 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 @@ static int do_load(int argc, char **argv)
	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 }
Loading