diff options
Diffstat (limited to 'tools/lib/bpf')
| -rw-r--r-- | tools/lib/bpf/bpf.c | 89 | ||||
| -rw-r--r-- | tools/lib/bpf/bpf.h | 27 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.c | 179 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.h | 1 | 
4 files changed, 220 insertions, 76 deletions
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 1d6907d379c9..5128677e4117 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -46,6 +46,8 @@  # endif  #endif +#define min(x, y) ((x) < (y) ? (x) : (y)) +  static inline __u64 ptr_to_u64(const void *ptr)  {  	return (__u64) (unsigned long) ptr; @@ -57,10 +59,11 @@ static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,  	return syscall(__NR_bpf, cmd, attr, size);  } -int bpf_create_map_node(enum bpf_map_type map_type, int key_size, -			int value_size, int max_entries, __u32 map_flags, -			int node) +int bpf_create_map_node(enum bpf_map_type map_type, const char *name, +			int key_size, int value_size, int max_entries, +			__u32 map_flags, int node)  { +	__u32 name_len = name ? strlen(name) : 0;  	union bpf_attr attr;  	memset(&attr, '\0', sizeof(attr)); @@ -70,6 +73,8 @@ int bpf_create_map_node(enum bpf_map_type map_type, int key_size,  	attr.value_size = value_size;  	attr.max_entries = max_entries;  	attr.map_flags = map_flags; +	memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1)); +  	if (node >= 0) {  		attr.map_flags |= BPF_F_NUMA_NODE;  		attr.numa_node = node; @@ -81,14 +86,23 @@ int bpf_create_map_node(enum bpf_map_type map_type, int key_size,  int bpf_create_map(enum bpf_map_type map_type, int key_size,  		   int value_size, int max_entries, __u32 map_flags)  { -	return bpf_create_map_node(map_type, key_size, value_size, +	return bpf_create_map_node(map_type, NULL, key_size, value_size,  				   max_entries, map_flags, -1);  } -int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, -			       int inner_map_fd, int max_entries, +int bpf_create_map_name(enum bpf_map_type map_type, const char *name, +			int key_size, int value_size, int max_entries, +			__u32 map_flags) +{ +	return bpf_create_map_node(map_type, name, key_size, value_size, +				   max_entries, map_flags, -1); +} + +int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, +			       int key_size, int inner_map_fd, int max_entries,  			       __u32 map_flags, int node)  { +	__u32 name_len = name ? strlen(name) : 0;  	union bpf_attr attr;  	memset(&attr, '\0', sizeof(attr)); @@ -99,6 +113,8 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size,  	attr.inner_map_fd = inner_map_fd;  	attr.max_entries = max_entries;  	attr.map_flags = map_flags; +	memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1)); +  	if (node >= 0) {  		attr.map_flags |= BPF_F_NUMA_NODE;  		attr.numa_node = node; @@ -107,19 +123,24 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size,  	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));  } -int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, -			  int inner_map_fd, int max_entries, __u32 map_flags) +int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, +			  int key_size, int inner_map_fd, int max_entries, +			  __u32 map_flags)  { -	return bpf_create_map_in_map_node(map_type, key_size, inner_map_fd, -					  max_entries, map_flags, -1); +	return bpf_create_map_in_map_node(map_type, name, key_size, +					  inner_map_fd, max_entries, map_flags, +					  -1);  } -int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, -		     size_t insns_cnt, const char *license, -		     __u32 kern_version, char *log_buf, size_t log_buf_sz) +int bpf_load_program_name(enum bpf_prog_type type, const char *name, +			  const struct bpf_insn *insns, +			  size_t insns_cnt, const char *license, +			  __u32 kern_version, char *log_buf, +			  size_t log_buf_sz)  {  	int fd;  	union bpf_attr attr; +	__u32 name_len = name ? strlen(name) : 0;  	bzero(&attr, sizeof(attr));  	attr.prog_type = type; @@ -130,6 +151,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,  	attr.log_size = 0;  	attr.log_level = 0;  	attr.kern_version = kern_version; +	memcpy(attr.prog_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1));  	fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));  	if (fd >= 0 || !log_buf || !log_buf_sz) @@ -143,6 +165,15 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,  	return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));  } +int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, +		     size_t insns_cnt, const char *license, +		     __u32 kern_version, char *log_buf, +		     size_t log_buf_sz) +{ +	return bpf_load_program_name(type, NULL, insns, insns_cnt, license, +				     kern_version, log_buf, log_buf_sz); +} +  int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,  		       size_t insns_cnt, int strict_alignment,  		       const char *license, __u32 kern_version, @@ -260,6 +291,38 @@ int bpf_prog_detach(int target_fd, enum bpf_attach_type type)  	return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));  } +int bpf_prog_detach2(int prog_fd, int target_fd, enum bpf_attach_type type) +{ +	union bpf_attr attr; + +	bzero(&attr, sizeof(attr)); +	attr.target_fd	 = target_fd; +	attr.attach_bpf_fd = prog_fd; +	attr.attach_type = type; + +	return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); +} + +int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, +		   __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt) +{ +	union bpf_attr attr; +	int ret; + +	bzero(&attr, sizeof(attr)); +	attr.query.target_fd	= target_fd; +	attr.query.attach_type	= type; +	attr.query.query_flags	= query_flags; +	attr.query.prog_cnt	= *prog_cnt; +	attr.query.prog_ids	= ptr_to_u64(prog_ids); + +	ret = sys_bpf(BPF_PROG_QUERY, &attr, sizeof(attr)); +	if (attach_flags) +		*attach_flags = attr.query.attach_flags; +	*prog_cnt = attr.query.prog_cnt; +	return ret; +} +  int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,  		      void *data_out, __u32 *size_out, __u32 *retval,  		      __u32 *duration) diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index b8ea5843c39e..6534889e2b2f 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -24,19 +24,28 @@  #include <linux/bpf.h>  #include <stddef.h> -int bpf_create_map_node(enum bpf_map_type map_type, int key_size, -			int value_size, int max_entries, __u32 map_flags, -			int node); +int bpf_create_map_node(enum bpf_map_type map_type, const char *name, +			int key_size, int value_size, int max_entries, +			__u32 map_flags, int node); +int bpf_create_map_name(enum bpf_map_type map_type, const char *name, +			int key_size, int value_size, int max_entries, +			__u32 map_flags);  int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,  		   int max_entries, __u32 map_flags); -int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, -			       int inner_map_fd, int max_entries, +int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, +			       int key_size, int inner_map_fd, int max_entries,  			       __u32 map_flags, int node); -int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, -			  int inner_map_fd, int max_entries, __u32 map_flags); +int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, +			  int key_size, int inner_map_fd, int max_entries, +			  __u32 map_flags);  /* Recommend log buffer size */  #define BPF_LOG_BUF_SIZE 65536 +int bpf_load_program_name(enum bpf_prog_type type, const char *name, +			  const struct bpf_insn *insns, +			  size_t insns_cnt, const char *license, +			  __u32 kern_version, char *log_buf, +			  size_t log_buf_sz);  int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,  		     size_t insns_cnt, const char *license,  		     __u32 kern_version, char *log_buf, @@ -57,6 +66,7 @@ int bpf_obj_get(const char *pathname);  int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type,  		    unsigned int flags);  int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); +int bpf_prog_detach2(int prog_fd, int attachable_fd, enum bpf_attach_type type);  int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,  		      void *data_out, __u32 *size_out, __u32 *retval,  		      __u32 *duration); @@ -65,5 +75,6 @@ int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);  int bpf_prog_get_fd_by_id(__u32 id);  int bpf_map_get_fd_by_id(__u32 id);  int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); - +int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, +		   __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt);  #endif diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 35f6dfcdc565..5aa45f89da93 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -171,6 +171,7 @@ int libbpf_strerror(int err, char *buf, size_t size)  struct bpf_program {  	/* Index in elf obj file, for relocation use. */  	int idx; +	char *name;  	char *section_name;  	struct bpf_insn *insns;  	size_t insns_cnt; @@ -283,6 +284,7 @@ static void bpf_program__exit(struct bpf_program *prog)  	prog->clear_priv = NULL;  	bpf_program__unload(prog); +	zfree(&prog->name);  	zfree(&prog->section_name);  	zfree(&prog->insns);  	zfree(&prog->reloc_desc); @@ -293,26 +295,27 @@ static void bpf_program__exit(struct bpf_program *prog)  }  static int -bpf_program__init(void *data, size_t size, char *name, int idx, -		    struct bpf_program *prog) +bpf_program__init(void *data, size_t size, char *section_name, int idx, +		  struct bpf_program *prog)  {  	if (size < sizeof(struct bpf_insn)) { -		pr_warning("corrupted section '%s'\n", name); +		pr_warning("corrupted section '%s'\n", section_name);  		return -EINVAL;  	}  	bzero(prog, sizeof(*prog)); -	prog->section_name = strdup(name); +	prog->section_name = strdup(section_name);  	if (!prog->section_name) { -		pr_warning("failed to alloc name for prog %s\n", -			   name); +		pr_warning("failed to alloc name for prog under section %s\n", +			   section_name);  		goto errout;  	}  	prog->insns = malloc(size);  	if (!prog->insns) { -		pr_warning("failed to alloc insns for %s\n", name); +		pr_warning("failed to alloc insns for prog under section %s\n", +			   section_name);  		goto errout;  	}  	prog->insns_cnt = size / sizeof(struct bpf_insn); @@ -331,12 +334,12 @@ errout:  static int  bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, -			char *name, int idx) +			char *section_name, int idx)  {  	struct bpf_program prog, *progs;  	int nr_progs, err; -	err = bpf_program__init(data, size, name, idx, &prog); +	err = bpf_program__init(data, size, section_name, idx, &prog);  	if (err)  		return err; @@ -350,8 +353,8 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,  		 * is still valid, so don't need special treat for  		 * bpf_close_object().  		 */ -		pr_warning("failed to alloc a new program '%s'\n", -			   name); +		pr_warning("failed to alloc a new program under section '%s'\n", +			   section_name);  		bpf_program__exit(&prog);  		return -ENOMEM;  	} @@ -364,6 +367,54 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,  	return 0;  } +static int +bpf_object__init_prog_names(struct bpf_object *obj) +{ +	Elf_Data *symbols = obj->efile.symbols; +	struct bpf_program *prog; +	size_t pi, si; + +	for (pi = 0; pi < obj->nr_programs; pi++) { +		char *name = NULL; + +		prog = &obj->programs[pi]; + +		for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name; +		     si++) { +			GElf_Sym sym; + +			if (!gelf_getsym(symbols, si, &sym)) +				continue; +			if (sym.st_shndx != prog->idx) +				continue; + +			name = elf_strptr(obj->efile.elf, +					  obj->efile.strtabidx, +					  sym.st_name); +			if (!name) { +				pr_warning("failed to get sym name string for prog %s\n", +					   prog->section_name); +				return -LIBBPF_ERRNO__LIBELF; +			} +		} + +		if (!name) { +			pr_warning("failed to find sym for prog %s\n", +				   prog->section_name); +			return -EINVAL; +		} + +		prog->name = strdup(name); +		if (!prog->name) { +			pr_warning("failed to allocate memory for prog sym %s\n", +				   name); +			return -ENOMEM; +		} +	} + +	return 0; +} +  static struct bpf_object *bpf_object__new(const char *path,  					  void *obj_buf,  					  size_t obj_buf_sz) @@ -528,31 +579,6 @@ bpf_object__init_kversion(struct bpf_object *obj,  	return 0;  } -static int -bpf_object__validate_maps(struct bpf_object *obj) -{ -	int i; - -	/* -	 * If there's only 1 map, the only error case should have been -	 * catched in bpf_object__init_maps(). -	 */ -	if (!obj->maps || !obj->nr_maps || (obj->nr_maps == 1)) -		return 0; - -	for (i = 1; i < obj->nr_maps; i++) { -		const struct bpf_map *a = &obj->maps[i - 1]; -		const struct bpf_map *b = &obj->maps[i]; - -		if (b->offset - a->offset < sizeof(struct bpf_map_def)) { -			pr_warning("corrupted map section in %s: map \"%s\" too small\n", -				   obj->path, a->name); -			return -EINVAL; -		} -	} -	return 0; -} -  static int compare_bpf_map(const void *_a, const void *_b)  {  	const struct bpf_map *a = _a; @@ -564,7 +590,7 @@ static int compare_bpf_map(const void *_a, const void *_b)  static int  bpf_object__init_maps(struct bpf_object *obj)  { -	int i, map_idx, nr_maps = 0; +	int i, map_idx, map_def_sz, nr_maps = 0;  	Elf_Scn *scn;  	Elf_Data *data;  	Elf_Data *symbols = obj->efile.symbols; @@ -607,6 +633,15 @@ bpf_object__init_maps(struct bpf_object *obj)  	if (!nr_maps)  		return 0; +	/* Assume equally sized map definitions */ +	map_def_sz = data->d_size / nr_maps; +	if (!data->d_size || (data->d_size % nr_maps) != 0) { +		pr_warning("unable to determine map definition size " +			   "section %s, %d maps in %zd bytes\n", +			   obj->path, nr_maps, data->d_size); +		return -EINVAL; +	} +  	obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));  	if (!obj->maps) {  		pr_warning("alloc maps for object failed\n"); @@ -639,7 +674,7 @@ bpf_object__init_maps(struct bpf_object *obj)  				      obj->efile.strtabidx,  				      sym.st_name);  		obj->maps[map_idx].offset = sym.st_value; -		if (sym.st_value + sizeof(struct bpf_map_def) > data->d_size) { +		if (sym.st_value + map_def_sz > data->d_size) {  			pr_warning("corrupted maps section in %s: last map \"%s\" too small\n",  				   obj->path, map_name);  			return -EINVAL; @@ -653,12 +688,40 @@ bpf_object__init_maps(struct bpf_object *obj)  		pr_debug("map %d is \"%s\"\n", map_idx,  			 obj->maps[map_idx].name);  		def = (struct bpf_map_def *)(data->d_buf + sym.st_value); -		obj->maps[map_idx].def = *def; +		/* +		 * If the definition of the map in the object file fits in +		 * bpf_map_def, copy it.  Any extra fields in our version +		 * of bpf_map_def will default to zero as a result of the +		 * calloc above. +		 */ +		if (map_def_sz <= sizeof(struct bpf_map_def)) { +			memcpy(&obj->maps[map_idx].def, def, map_def_sz); +		} else { +			/* +			 * Here the map structure being read is bigger than what +			 * we expect, truncate if the excess bits are all zero. +			 * If they are not zero, reject this map as +			 * incompatible. +			 */ +			char *b; +			for (b = ((char *)def) + sizeof(struct bpf_map_def); +			     b < ((char *)def) + map_def_sz; b++) { +				if (*b != 0) { +					pr_warning("maps section in %s: \"%s\" " +						   "has unrecognized, non-zero " +						   "options\n", +						   obj->path, map_name); +					return -EINVAL; +				} +			} +			memcpy(&obj->maps[map_idx].def, def, +			       sizeof(struct bpf_map_def)); +		}  		map_idx++;  	}  	qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map); -	return bpf_object__validate_maps(obj); +	return 0;  }  static int bpf_object__elf_collect(struct bpf_object *obj) @@ -766,8 +829,12 @@ static int bpf_object__elf_collect(struct bpf_object *obj)  		pr_warning("Corrupted ELF file: index of strtab invalid\n");  		return LIBBPF_ERRNO__FORMAT;  	} -	if (obj->efile.maps_shndx >= 0) +	if (obj->efile.maps_shndx >= 0) {  		err = bpf_object__init_maps(obj); +		if (err) +			goto out; +	} +	err = bpf_object__init_prog_names(obj);  out:  	return err;  } @@ -870,11 +937,12 @@ bpf_object__create_maps(struct bpf_object *obj)  		struct bpf_map_def *def = &obj->maps[i].def;  		int *pfd = &obj->maps[i].fd; -		*pfd = bpf_create_map(def->type, -				      def->key_size, -				      def->value_size, -				      def->max_entries, -				      0); +		*pfd = bpf_create_map_name(def->type, +					   obj->maps[i].name, +					   def->key_size, +					   def->value_size, +					   def->max_entries, +					   def->map_flags);  		if (*pfd < 0) {  			size_t j;  			int err = *pfd; @@ -982,7 +1050,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)  }  static int -load_program(enum bpf_prog_type type, struct bpf_insn *insns, +load_program(enum bpf_prog_type type, const char *name, struct bpf_insn *insns,  	     int insns_cnt, char *license, u32 kern_version, int *pfd)  {  	int ret; @@ -995,8 +1063,8 @@ load_program(enum bpf_prog_type type, struct bpf_insn *insns,  	if (!log_buf)  		pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); -	ret = bpf_load_program(type, insns, insns_cnt, license, -			       kern_version, log_buf, BPF_LOG_BUF_SIZE); +	ret = bpf_load_program_name(type, name, insns, insns_cnt, license, +				    kern_version, log_buf, BPF_LOG_BUF_SIZE);  	if (ret >= 0) {  		*pfd = ret; @@ -1021,9 +1089,9 @@ load_program(enum bpf_prog_type type, struct bpf_insn *insns,  		if (type != BPF_PROG_TYPE_KPROBE) {  			int fd; -			fd = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns, -					      insns_cnt, license, kern_version, -					      NULL, 0); +			fd = bpf_load_program_name(BPF_PROG_TYPE_KPROBE, name, +						   insns, insns_cnt, license, +						   kern_version, NULL, 0);  			if (fd >= 0) {  				close(fd);  				ret = -LIBBPF_ERRNO__PROGTYPE; @@ -1067,8 +1135,8 @@ bpf_program__load(struct bpf_program *prog,  			pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",  				   prog->section_name, prog->instances.nr);  		} -		err = load_program(prog->type, prog->insns, prog->insns_cnt, -				   license, kern_version, &fd); +		err = load_program(prog->type, prog->name, prog->insns, +				   prog->insns_cnt, license, kern_version, &fd);  		if (!err)  			prog->instances.fds[0] = fd;  		goto out; @@ -1096,7 +1164,8 @@ bpf_program__load(struct bpf_program *prog,  			continue;  		} -		err = load_program(prog->type, result.new_insn_ptr, +		err = load_program(prog->type, prog->name, +				   result.new_insn_ptr,  				   result.new_insn_cnt,  				   license, kern_version, &fd); diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 7959086eb9c9..6e20003109e0 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -207,6 +207,7 @@ struct bpf_map_def {  	unsigned int key_size;  	unsigned int value_size;  	unsigned int max_entries; +	unsigned int map_flags;  };  /*  | 
