forked from mirrors/linux
		
	bpftool: add loadall command
This patch adds new *loadall* command which slightly differs from the existing *load*. *load* command loads all programs from the obj file, but pins only the first programs. *loadall* pins all programs from the obj file under specified directory. The intended usecase is flow_dissector, where we want to load a bunch of progs, pin them all and after that construct a jump table. Signed-off-by: Stanislav Fomichev <sdf@google.com> Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									33a2c75c55
								
							
						
					
					
						commit
						77380998d9
					
				
					 5 changed files with 81 additions and 43 deletions
				
			
		| 
						 | 
					@ -15,7 +15,8 @@ SYNOPSIS
 | 
				
			||||||
	*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
 | 
						*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*COMMANDS* :=
 | 
						*COMMANDS* :=
 | 
				
			||||||
	{ **show** | **list** | **dump xlated** | **dump jited** | **pin** | **load** | **help** }
 | 
						{ **show** | **list** | **dump xlated** | **dump jited** | **pin** | **load**
 | 
				
			||||||
 | 
						| **loadall** | **help** }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MAP COMMANDS
 | 
					MAP COMMANDS
 | 
				
			||||||
=============
 | 
					=============
 | 
				
			||||||
| 
						 | 
					@ -24,7 +25,7 @@ MAP COMMANDS
 | 
				
			||||||
|	**bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
 | 
					|	**bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
 | 
				
			||||||
|	**bpftool** **prog dump jited**  *PROG* [{**file** *FILE* | **opcodes**}]
 | 
					|	**bpftool** **prog dump jited**  *PROG* [{**file** *FILE* | **opcodes**}]
 | 
				
			||||||
|	**bpftool** **prog pin** *PROG* *FILE*
 | 
					|	**bpftool** **prog pin** *PROG* *FILE*
 | 
				
			||||||
|	**bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
 | 
					|	**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 attach** *PROG* *ATTACH_TYPE* *MAP*
 | 
				
			||||||
|       **bpftool** **prog detach** *PROG* *ATTACH_TYPE* *MAP*
 | 
					|       **bpftool** **prog detach** *PROG* *ATTACH_TYPE* *MAP*
 | 
				
			||||||
|	**bpftool** **prog help**
 | 
					|	**bpftool** **prog help**
 | 
				
			||||||
| 
						 | 
					@ -79,8 +80,11 @@ DESCRIPTION
 | 
				
			||||||
		  contain a dot character ('.'), which is reserved for future
 | 
							  contain a dot character ('.'), which is reserved for future
 | 
				
			||||||
		  extensions of *bpffs*.
 | 
							  extensions of *bpffs*.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	**bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
 | 
						**bpftool prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
 | 
				
			||||||
		  Load bpf program from binary *OBJ* and pin as *FILE*.
 | 
							  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
 | 
							  **type** is optional, if not specified program type will be
 | 
				
			||||||
		  inferred from section names.
 | 
							  inferred from section names.
 | 
				
			||||||
		  By default bpftool will create new maps as declared in the ELF
 | 
							  By default bpftool will create new maps as declared in the ELF
 | 
				
			||||||
| 
						 | 
					@ -93,7 +97,7 @@ DESCRIPTION
 | 
				
			||||||
		  If **dev** *NAME* is specified program will be loaded onto
 | 
							  If **dev** *NAME* is specified program will be loaded onto
 | 
				
			||||||
		  given networking device (offload).
 | 
							  given networking device (offload).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		  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
 | 
							  contain a dot character ('.'), which is reserved for future
 | 
				
			||||||
		  extensions of *bpffs*.
 | 
							  extensions of *bpffs*.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -243,7 +243,7 @@ _bpftool()
 | 
				
			||||||
    # Completion depends on object and command in use
 | 
					    # Completion depends on object and command in use
 | 
				
			||||||
    case $object in
 | 
					    case $object in
 | 
				
			||||||
        prog)
 | 
					        prog)
 | 
				
			||||||
            if [[ $command != "load" ]]; then
 | 
					            if [[ $command != "load" && $command != "loadall" ]]; then
 | 
				
			||||||
                case $prev in
 | 
					                case $prev in
 | 
				
			||||||
                    id)
 | 
					                    id)
 | 
				
			||||||
                        _bpftool_get_prog_ids
 | 
					                        _bpftool_get_prog_ids
 | 
				
			||||||
| 
						 | 
					@ -309,7 +309,7 @@ _bpftool()
 | 
				
			||||||
                    fi
 | 
					                    fi
 | 
				
			||||||
                    return 0
 | 
					                    return 0
 | 
				
			||||||
                    ;;
 | 
					                    ;;
 | 
				
			||||||
                load)
 | 
					                load|loadall)
 | 
				
			||||||
                    local obj
 | 
					                    local obj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if [[ ${#words[@]} -lt 6 ]]; then
 | 
					                    if [[ ${#words[@]} -lt 6 ]]; then
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,34 +177,23 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
 | 
				
			||||||
	return fd;
 | 
						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 err_str[ERR_MAX_LEN];
 | 
				
			||||||
	char *file;
 | 
						char *file;
 | 
				
			||||||
	char *dir;
 | 
						char *dir;
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = bpf_obj_pin(fd, name);
 | 
					 | 
				
			||||||
	if (!err)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	file = malloc(strlen(name) + 1);
 | 
						file = malloc(strlen(name) + 1);
 | 
				
			||||||
	strcpy(file, name);
 | 
						strcpy(file, name);
 | 
				
			||||||
	dir = dirname(file);
 | 
						dir = dirname(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (errno != EPERM || is_bpffs(dir)) {
 | 
						if (is_bpffs(dir))
 | 
				
			||||||
		p_err("can't pin the object (%s): %s", name, strerror(errno));
 | 
							/* nothing to do if already mounted */
 | 
				
			||||||
		goto out_free;
 | 
							goto out_free;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Attempt to mount bpffs, then retry pinning. */
 | 
					 | 
				
			||||||
	err = mnt_bpffs(dir, err_str, ERR_MAX_LEN);
 | 
						err = mnt_bpffs(dir, err_str, ERR_MAX_LEN);
 | 
				
			||||||
	if (!err) {
 | 
						if (err) {
 | 
				
			||||||
		err = bpf_obj_pin(fd, name);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			p_err("can't pin the object (%s): %s", name,
 | 
					 | 
				
			||||||
			      strerror(errno));
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		err_str[ERR_MAX_LEN - 1] = '\0';
 | 
							err_str[ERR_MAX_LEN - 1] = '\0';
 | 
				
			||||||
		p_err("can't mount BPF file system to pin the object (%s): %s",
 | 
							p_err("can't mount BPF file system to pin the object (%s): %s",
 | 
				
			||||||
		      name, err_str);
 | 
							      name, err_str);
 | 
				
			||||||
| 
						 | 
					@ -212,10 +201,20 @@ int do_pin_fd(int fd, const char *name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_free:
 | 
					out_free:
 | 
				
			||||||
	free(file);
 | 
						free(file);
 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	return err;
 | 
						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))
 | 
					int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int id;
 | 
						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);
 | 
					char *get_fdinfo(int fd, const char *key);
 | 
				
			||||||
int open_obj_pinned(char *path);
 | 
					int open_obj_pinned(char *path);
 | 
				
			||||||
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type);
 | 
					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_any(int argc, char **argv, int (*get_fd_by_id)(__u32));
 | 
				
			||||||
int do_pin_fd(int fd, const char *name);
 | 
					int do_pin_fd(int fd, const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -792,15 +792,16 @@ static int do_detach(int argc, char **argv)
 | 
				
			||||||
		jsonw_null(json_wtr);
 | 
							jsonw_null(json_wtr);
 | 
				
			||||||
	return 0;
 | 
						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;
 | 
						enum bpf_attach_type expected_attach_type;
 | 
				
			||||||
	struct bpf_object_open_attr attr = {
 | 
						struct bpf_object_open_attr attr = {
 | 
				
			||||||
		.prog_type	= BPF_PROG_TYPE_UNSPEC,
 | 
							.prog_type	= BPF_PROG_TYPE_UNSPEC,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct map_replace *map_replace = NULL;
 | 
						struct map_replace *map_replace = NULL;
 | 
				
			||||||
 | 
						struct bpf_program *prog = NULL, *pos;
 | 
				
			||||||
	unsigned int old_map_fds = 0;
 | 
						unsigned int old_map_fds = 0;
 | 
				
			||||||
	struct bpf_program *prog;
 | 
					 | 
				
			||||||
	struct bpf_object *obj;
 | 
						struct bpf_object *obj;
 | 
				
			||||||
	struct bpf_map *map;
 | 
						struct bpf_map *map;
 | 
				
			||||||
	const char *pinfile;
 | 
						const char *pinfile;
 | 
				
			||||||
| 
						 | 
					@ -918,26 +919,25 @@ static int do_load(int argc, char **argv)
 | 
				
			||||||
		goto err_free_reuse_maps;
 | 
							goto err_free_reuse_maps;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	prog = bpf_program__next(NULL, obj);
 | 
						bpf_object__for_each_program(pos, obj) {
 | 
				
			||||||
	if (!prog) {
 | 
							enum bpf_prog_type prog_type = attr.prog_type;
 | 
				
			||||||
		p_err("object file doesn't contain any bpf program");
 | 
					 | 
				
			||||||
		goto err_close_obj;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bpf_program__set_ifindex(prog, ifindex);
 | 
							if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) {
 | 
				
			||||||
	if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) {
 | 
								const char *sec_name = bpf_program__title(pos, false);
 | 
				
			||||||
		const char *sec_name = bpf_program__title(prog, 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);
 | 
											       &expected_attach_type);
 | 
				
			||||||
		if (err < 0) {
 | 
								if (err < 0) {
 | 
				
			||||||
			p_err("failed to guess program type based on section name %s\n",
 | 
									p_err("failed to guess program type based on section name %s\n",
 | 
				
			||||||
			      sec_name);
 | 
									      sec_name);
 | 
				
			||||||
			goto err_close_obj;
 | 
									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),
 | 
						qsort(map_replace, old_map_fds, sizeof(*map_replace),
 | 
				
			||||||
	      map_replace_compar);
 | 
						      map_replace_compar);
 | 
				
			||||||
| 
						 | 
					@ -1003,9 +1003,31 @@ static int do_load(int argc, char **argv)
 | 
				
			||||||
		goto err_close_obj;
 | 
							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;
 | 
							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 (json_output)
 | 
						if (json_output)
 | 
				
			||||||
		jsonw_null(json_wtr);
 | 
							jsonw_null(json_wtr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1025,6 +1047,16 @@ static int do_load(int argc, char **argv)
 | 
				
			||||||
	return -1;
 | 
						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)
 | 
					static int do_help(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (json_output) {
 | 
						if (json_output) {
 | 
				
			||||||
| 
						 | 
					@ -1037,7 +1069,8 @@ static int do_help(int argc, char **argv)
 | 
				
			||||||
		"       %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
 | 
							"       %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
 | 
				
			||||||
		"       %s %s dump jited  PROG [{ file FILE | opcodes }]\n"
 | 
							"       %s %s dump jited  PROG [{ file FILE | opcodes }]\n"
 | 
				
			||||||
		"       %s %s pin   PROG FILE\n"
 | 
							"       %s %s pin   PROG FILE\n"
 | 
				
			||||||
		"       %s %s load  OBJ  FILE [type TYPE] [dev NAME] \\\n"
 | 
							"       %s %s { load | loadall } OBJ  PATH \\\n"
 | 
				
			||||||
 | 
							"                         [type TYPE] [dev NAME] \\\n"
 | 
				
			||||||
		"                         [map { idx IDX | name NAME } MAP]\n"
 | 
							"                         [map { idx IDX | name NAME } MAP]\n"
 | 
				
			||||||
		"       %s %s attach PROG ATTACH_TYPE MAP\n"
 | 
							"       %s %s attach PROG ATTACH_TYPE MAP\n"
 | 
				
			||||||
		"       %s %s detach PROG ATTACH_TYPE MAP\n"
 | 
							"       %s %s detach PROG ATTACH_TYPE MAP\n"
 | 
				
			||||||
| 
						 | 
					@ -1069,6 +1102,7 @@ static const struct cmd cmds[] = {
 | 
				
			||||||
	{ "dump",	do_dump },
 | 
						{ "dump",	do_dump },
 | 
				
			||||||
	{ "pin",	do_pin },
 | 
						{ "pin",	do_pin },
 | 
				
			||||||
	{ "load",	do_load },
 | 
						{ "load",	do_load },
 | 
				
			||||||
 | 
						{ "loadall",	do_loadall },
 | 
				
			||||||
	{ "attach",	do_attach },
 | 
						{ "attach",	do_attach },
 | 
				
			||||||
	{ "detach",	do_detach },
 | 
						{ "detach",	do_detach },
 | 
				
			||||||
	{ 0 }
 | 
						{ 0 }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue