Commit 12f96823 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'bpftool: Add autoattach for bpf prog load|loadall'

Wang Yufen says:

====================

This patchset add "autoattach" optional for "bpftool prog load(_all)" to support
one-step load-attach-pin_link.

v8 -> v9: fix link leak, and change pathname_concat(specify not just buffer
	  pointer, but also it's size)
v7 -> v8: for the programs not supporting autoattach, fall back to reguler pinning
	  instead of skipping
v6 -> v7: add info msg print and update doc for the skip program
v5 -> v6: skip the programs not supporting auto-attach,
	  and change optional name from "auto_attach" to "autoattach"
v4 -> v5: some formatting nits of doc
v3 -> v4: rename functions, update doc, bash and do_help()
v2 -> v3: switch to extend prog load command instead of extend perf
v2: https://patchwork.kernel.org/project/netdevbpf/patch/20220824033837.458197-1-weiyongjun1@huawei.com/
v1: https://patchwork.kernel.org/project/netdevbpf/patch/20220816151725.153343-1-weiyongjun1@huawei.com/


====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 98af3746 b81a6774
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ PROG COMMANDS
|	**bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual** | **linum**}]
|	**bpftool** **prog dump jited**  *PROG* [{**file** *FILE* | **opcodes** | **linum**}]
|	**bpftool** **prog pin** *PROG* *FILE*
|	**bpftool** **prog** { **load** | **loadall** } *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*]
|	**bpftool** **prog** { **load** | **loadall** } *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**]
|	**bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*]
|	**bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*]
|	**bpftool** **prog tracelog**
@@ -131,7 +131,7 @@ DESCRIPTION
		  contain a dot character ('.'), which is reserved for future
		  extensions of *bpffs*.

	**bpftool prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*]
	**bpftool prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**]
		  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
@@ -150,6 +150,17 @@ DESCRIPTION
		  Optional **pinmaps** argument can be provided to pin all
		  maps under *MAP_DIR* directory.

		  If **autoattach** is specified program will be attached
		  before pin. In that case, only the link (representing the
		  program attached to its hook) is pinned, not the program as
		  such, so the path won't show in **bpftool prog show -f**,
		  only show in **bpftool link show -f**. Also, this only works
		  when bpftool (libbpf) is able to infer all necessary
		  information from the object file, in particular, it's not
		  supported for all program types. If a program does not
		  support autoattach, bpftool falls back to regular pinning
		  for that program instead.

		  Note: *PATH* must be located in *bpffs* mount. It must not
		  contain a dot character ('.'), which is reserved for future
		  extensions of *bpffs*.
+1 −0
Original line number Diff line number Diff line
@@ -505,6 +505,7 @@ _bpftool()
                            _bpftool_once_attr 'type'
                            _bpftool_once_attr 'dev'
                            _bpftool_once_attr 'pinmaps'
                            _bpftool_once_attr 'autoattach'
                            return 0
                            ;;
                    esac
+74 −2
Original line number Diff line number Diff line
@@ -1453,6 +1453,67 @@ get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
	return ret;
}

static int
auto_attach_program(struct bpf_program *prog, const char *path)
{
	struct bpf_link *link;
	int err;

	link = bpf_program__attach(prog);
	if (!link) {
		p_info("Program %s does not support autoattach, falling back to pinning",
		       bpf_program__name(prog));
		return bpf_obj_pin(bpf_program__fd(prog), path);
	}

	err = bpf_link__pin(link, path);
	bpf_link__destroy(link);
	return err;
}

static int pathname_concat(char *buf, size_t buf_sz, const char *path, const char *name)
{
	int len;

	len = snprintf(buf, buf_sz, "%s/%s", path, name);
	if (len < 0)
		return -EINVAL;
	if ((size_t)len >= buf_sz)
		return -ENAMETOOLONG;

	return 0;
}

static int
auto_attach_programs(struct bpf_object *obj, const char *path)
{
	struct bpf_program *prog;
	char buf[PATH_MAX];
	int err;

	bpf_object__for_each_program(prog, obj) {
		err = pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog));
		if (err)
			goto err_unpin_programs;

		err = auto_attach_program(prog, buf);
		if (err)
			goto err_unpin_programs;
	}

	return 0;

err_unpin_programs:
	while ((prog = bpf_object__prev_program(obj, prog))) {
		if (pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog)))
			continue;

		bpf_program__unpin(prog, buf);
	}

	return err;
}

static int load_with_options(int argc, char **argv, bool first_prog_only)
{
	enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC;
@@ -1464,6 +1525,7 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
	struct bpf_program *prog = NULL, *pos;
	unsigned int old_map_fds = 0;
	const char *pinmaps = NULL;
	bool auto_attach = false;
	struct bpf_object *obj;
	struct bpf_map *map;
	const char *pinfile;
@@ -1583,6 +1645,9 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
				goto err_free_reuse_maps;

			pinmaps = GET_ARG();
		} else if (is_prefix(*argv, "autoattach")) {
			auto_attach = true;
			NEXT_ARG();
		} else {
			p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?",
			      *argv);
@@ -1692,6 +1757,9 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
			goto err_close_obj;
		}

		if (auto_attach)
			err = auto_attach_program(prog, pinfile);
		else
			err = bpf_obj_pin(bpf_program__fd(prog), pinfile);
		if (err) {
			p_err("failed to pin program %s",
@@ -1699,6 +1767,9 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
			goto err_close_obj;
		}
	} else {
		if (auto_attach)
			err = auto_attach_programs(obj, pinfile);
		else
			err = bpf_object__pin_programs(obj, pinfile);
		if (err) {
			p_err("failed to pin all programs");
@@ -2338,6 +2409,7 @@ static int do_help(int argc, char **argv)
		"                         [type TYPE] [dev NAME] \\\n"
		"                         [map { idx IDX | name NAME } MAP]\\\n"
		"                         [pinmaps MAP_DIR]\n"
		"                         [autoattach]\n"
		"       %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n"
		"       %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n"
		"       %1$s %2$s run PROG \\\n"