diff options
Diffstat (limited to 'tools/lib/bpf')
| -rw-r--r-- | tools/lib/bpf/Build | 2 | ||||
| -rw-r--r-- | tools/lib/bpf/Makefile | 3 | ||||
| -rw-r--r-- | tools/lib/bpf/bpf.c | 127 | ||||
| -rw-r--r-- | tools/lib/bpf/bpf.h | 23 | ||||
| -rw-r--r-- | tools/lib/bpf/btf.c | 373 | ||||
| -rw-r--r-- | tools/lib/bpf/btf.h | 22 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.c | 291 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.h | 69 | 
8 files changed, 841 insertions, 69 deletions
| diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build index 64c679d67109..6070e655042d 100644 --- a/tools/lib/bpf/Build +++ b/tools/lib/bpf/Build @@ -1 +1 @@ -libbpf-y := libbpf.o bpf.o nlattr.o +libbpf-y := libbpf.o bpf.o nlattr.o btf.o diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index e6d5f8d1477f..5390e7725e43 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -69,7 +69,7 @@ FEATURE_USER = .libbpf  FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf  FEATURE_DISPLAY = libelf bpf -INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi +INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf  FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES)  check_feat := 1 @@ -189,6 +189,7 @@ install_headers:  	$(call QUIET_INSTALL, headers) \  		$(call do_install,bpf.h,$(prefix)/include/bpf,644); \  		$(call do_install,libbpf.h,$(prefix)/include/bpf,644); +		$(call do_install,btf.h,$(prefix)/include/bpf,644);  install: install_lib diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index acbb3f8b3bec..9ddc89dae962 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -73,43 +73,77 @@ 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, const char *name, -			int key_size, int value_size, int max_entries, -			__u32 map_flags, int node) +int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)  { -	__u32 name_len = name ? strlen(name) : 0; +	__u32 name_len = create_attr->name ? strlen(create_attr->name) : 0;  	union bpf_attr attr;  	memset(&attr, '\0', sizeof(attr)); -	attr.map_type = map_type; -	attr.key_size = 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)); +	attr.map_type = create_attr->map_type; +	attr.key_size = create_attr->key_size; +	attr.value_size = create_attr->value_size; +	attr.max_entries = create_attr->max_entries; +	attr.map_flags = create_attr->map_flags; +	memcpy(attr.map_name, create_attr->name, +	       min(name_len, BPF_OBJ_NAME_LEN - 1)); +	attr.numa_node = create_attr->numa_node; +	attr.btf_fd = create_attr->btf_fd; +	attr.btf_key_type_id = create_attr->btf_key_type_id; +	attr.btf_value_type_id = create_attr->btf_value_type_id; +	attr.map_ifindex = create_attr->map_ifindex; + +	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); +} +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) +{ +	struct bpf_create_map_attr map_attr = {}; + +	map_attr.name = name; +	map_attr.map_type = map_type; +	map_attr.map_flags = map_flags; +	map_attr.key_size = key_size; +	map_attr.value_size = value_size; +	map_attr.max_entries = max_entries;  	if (node >= 0) { -		attr.map_flags |= BPF_F_NUMA_NODE; -		attr.numa_node = node; +		map_attr.numa_node = node; +		map_attr.map_flags |= BPF_F_NUMA_NODE;  	} -	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); +	return bpf_create_map_xattr(&map_attr);  }  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, NULL, key_size, value_size, -				   max_entries, map_flags, -1); +	struct bpf_create_map_attr map_attr = {}; + +	map_attr.map_type = map_type; +	map_attr.map_flags = map_flags; +	map_attr.key_size = key_size; +	map_attr.value_size = value_size; +	map_attr.max_entries = max_entries; + +	return bpf_create_map_xattr(&map_attr);  }  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); +	struct bpf_create_map_attr map_attr = {}; + +	map_attr.name = name; +	map_attr.map_type = map_type; +	map_attr.map_flags = map_flags; +	map_attr.key_size = key_size; +	map_attr.value_size = value_size; +	map_attr.max_entries = max_entries; + +	return bpf_create_map_xattr(&map_attr);  }  int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, @@ -168,6 +202,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,  	attr.log_size = 0;  	attr.log_level = 0;  	attr.kern_version = load_attr->kern_version; +	attr.prog_ifindex = load_attr->prog_ifindex;  	memcpy(attr.prog_name, load_attr->name,  	       min(name_len, BPF_OBJ_NAME_LEN - 1)); @@ -425,6 +460,16 @@ int bpf_map_get_fd_by_id(__u32 id)  	return sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));  } +int bpf_btf_get_fd_by_id(__u32 id) +{ +	union bpf_attr attr; + +	bzero(&attr, sizeof(attr)); +	attr.btf_id = id; + +	return sys_bpf(BPF_BTF_GET_FD_BY_ID, &attr, sizeof(attr)); +} +  int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len)  {  	union bpf_attr attr; @@ -573,3 +618,51 @@ cleanup:  	close(sock);  	return ret;  } + +int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, +		 bool do_log) +{ +	union bpf_attr attr = {}; +	int fd; + +	attr.btf = ptr_to_u64(btf); +	attr.btf_size = btf_size; + +retry: +	if (do_log && log_buf && log_buf_size) { +		attr.btf_log_level = 1; +		attr.btf_log_size = log_buf_size; +		attr.btf_log_buf = ptr_to_u64(log_buf); +	} + +	fd = sys_bpf(BPF_BTF_LOAD, &attr, sizeof(attr)); +	if (fd == -1 && !do_log && log_buf && log_buf_size) { +		do_log = true; +		goto retry; +	} + +	return fd; +} + +int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len, +		      __u32 *prog_id, __u32 *fd_type, __u64 *probe_offset, +		      __u64 *probe_addr) +{ +	union bpf_attr attr = {}; +	int err; + +	attr.task_fd_query.pid = pid; +	attr.task_fd_query.fd = fd; +	attr.task_fd_query.flags = flags; +	attr.task_fd_query.buf = ptr_to_u64(buf); +	attr.task_fd_query.buf_len = *buf_len; + +	err = sys_bpf(BPF_TASK_FD_QUERY, &attr, sizeof(attr)); +	*buf_len = attr.task_fd_query.buf_len; +	*prog_id = attr.task_fd_query.prog_id; +	*fd_type = attr.task_fd_query.fd_type; +	*probe_offset = attr.task_fd_query.probe_offset; +	*probe_addr = attr.task_fd_query.probe_addr; + +	return err; +} diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 39f6a0d64a3b..0639a30a457d 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -24,8 +24,24 @@  #define __BPF_BPF_H  #include <linux/bpf.h> +#include <stdbool.h>  #include <stddef.h> +struct bpf_create_map_attr { +	const char *name; +	enum bpf_map_type map_type; +	__u32 map_flags; +	__u32 key_size; +	__u32 value_size; +	__u32 max_entries; +	__u32 numa_node; +	__u32 btf_fd; +	__u32 btf_key_type_id; +	__u32 btf_value_type_id; +	__u32 map_ifindex; +}; + +int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr);  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); @@ -49,6 +65,7 @@ struct bpf_load_program_attr {  	size_t insns_cnt;  	const char *license;  	__u32 kern_version; +	__u32 prog_ifindex;  };  /* Recommend log buffer size */ @@ -83,8 +100,14 @@ int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);  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_btf_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);  int bpf_raw_tracepoint_open(const char *name, int prog_fd); +int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, +		 bool do_log); +int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len, +		      __u32 *prog_id, __u32 *fd_type, __u64 *probe_offset, +		      __u64 *probe_addr);  #endif diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c new file mode 100644 index 000000000000..8c54a4b6f187 --- /dev/null +++ b/tools/lib/bpf/btf.c @@ -0,0 +1,373 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Facebook */ + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/btf.h> +#include "btf.h" +#include "bpf.h" + +#define elog(fmt, ...) { if (err_log) err_log(fmt, ##__VA_ARGS__); } +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#define BTF_MAX_NR_TYPES 65535 + +static struct btf_type btf_void; + +struct btf { +	union { +		struct btf_header *hdr; +		void *data; +	}; +	struct btf_type **types; +	const char *strings; +	void *nohdr_data; +	uint32_t nr_types; +	uint32_t types_size; +	uint32_t data_size; +	int fd; +}; + +static const char *btf_name_by_offset(const struct btf *btf, uint32_t offset) +{ +	if (offset < btf->hdr->str_len) +		return &btf->strings[offset]; +	else +		return NULL; +} + +static int btf_add_type(struct btf *btf, struct btf_type *t) +{ +	if (btf->types_size - btf->nr_types < 2) { +		struct btf_type **new_types; +		u32 expand_by, new_size; + +		if (btf->types_size == BTF_MAX_NR_TYPES) +			return -E2BIG; + +		expand_by = max(btf->types_size >> 2, 16); +		new_size = min(BTF_MAX_NR_TYPES, btf->types_size + expand_by); + +		new_types = realloc(btf->types, sizeof(*new_types) * new_size); +		if (!new_types) +			return -ENOMEM; + +		if (btf->nr_types == 0) +			new_types[0] = &btf_void; + +		btf->types = new_types; +		btf->types_size = new_size; +	} + +	btf->types[++(btf->nr_types)] = t; + +	return 0; +} + +static int btf_parse_hdr(struct btf *btf, btf_print_fn_t err_log) +{ +	const struct btf_header *hdr = btf->hdr; +	u32 meta_left; + +	if (btf->data_size < sizeof(struct btf_header)) { +		elog("BTF header not found\n"); +		return -EINVAL; +	} + +	if (hdr->magic != BTF_MAGIC) { +		elog("Invalid BTF magic:%x\n", hdr->magic); +		return -EINVAL; +	} + +	if (hdr->version != BTF_VERSION) { +		elog("Unsupported BTF version:%u\n", hdr->version); +		return -ENOTSUP; +	} + +	if (hdr->flags) { +		elog("Unsupported BTF flags:%x\n", hdr->flags); +		return -ENOTSUP; +	} + +	meta_left = btf->data_size - sizeof(*hdr); +	if (!meta_left) { +		elog("BTF has no data\n"); +		return -EINVAL; +	} + +	if (meta_left < hdr->type_off) { +		elog("Invalid BTF type section offset:%u\n", hdr->type_off); +		return -EINVAL; +	} + +	if (meta_left < hdr->str_off) { +		elog("Invalid BTF string section offset:%u\n", hdr->str_off); +		return -EINVAL; +	} + +	if (hdr->type_off >= hdr->str_off) { +		elog("BTF type section offset >= string section offset. No type?\n"); +		return -EINVAL; +	} + +	if (hdr->type_off & 0x02) { +		elog("BTF type section is not aligned to 4 bytes\n"); +		return -EINVAL; +	} + +	btf->nohdr_data = btf->hdr + 1; + +	return 0; +} + +static int btf_parse_str_sec(struct btf *btf, btf_print_fn_t err_log) +{ +	const struct btf_header *hdr = btf->hdr; +	const char *start = btf->nohdr_data + hdr->str_off; +	const char *end = start + btf->hdr->str_len; + +	if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_NAME_OFFSET || +	    start[0] || end[-1]) { +		elog("Invalid BTF string section\n"); +		return -EINVAL; +	} + +	btf->strings = start; + +	return 0; +} + +static int btf_parse_type_sec(struct btf *btf, btf_print_fn_t err_log) +{ +	struct btf_header *hdr = btf->hdr; +	void *nohdr_data = btf->nohdr_data; +	void *next_type = nohdr_data + hdr->type_off; +	void *end_type = nohdr_data + hdr->str_off; + +	while (next_type < end_type) { +		struct btf_type *t = next_type; +		uint16_t vlen = BTF_INFO_VLEN(t->info); +		int err; + +		next_type += sizeof(*t); +		switch (BTF_INFO_KIND(t->info)) { +		case BTF_KIND_INT: +			next_type += sizeof(int); +			break; +		case BTF_KIND_ARRAY: +			next_type += sizeof(struct btf_array); +			break; +		case BTF_KIND_STRUCT: +		case BTF_KIND_UNION: +			next_type += vlen * sizeof(struct btf_member); +			break; +		case BTF_KIND_ENUM: +			next_type += vlen * sizeof(struct btf_enum); +			break; +		case BTF_KIND_TYPEDEF: +		case BTF_KIND_PTR: +		case BTF_KIND_FWD: +		case BTF_KIND_VOLATILE: +		case BTF_KIND_CONST: +		case BTF_KIND_RESTRICT: +			break; +		default: +			elog("Unsupported BTF_KIND:%u\n", +			     BTF_INFO_KIND(t->info)); +			return -EINVAL; +		} + +		err = btf_add_type(btf, t); +		if (err) +			return err; +	} + +	return 0; +} + +static const struct btf_type *btf_type_by_id(const struct btf *btf, +					     uint32_t type_id) +{ +	if (type_id > btf->nr_types) +		return NULL; + +	return btf->types[type_id]; +} + +static bool btf_type_is_void(const struct btf_type *t) +{ +	return t == &btf_void || BTF_INFO_KIND(t->info) == BTF_KIND_FWD; +} + +static bool btf_type_is_void_or_null(const struct btf_type *t) +{ +	return !t || btf_type_is_void(t); +} + +static int64_t btf_type_size(const struct btf_type *t) +{ +	switch (BTF_INFO_KIND(t->info)) { +	case BTF_KIND_INT: +	case BTF_KIND_STRUCT: +	case BTF_KIND_UNION: +	case BTF_KIND_ENUM: +		return t->size; +	case BTF_KIND_PTR: +		return sizeof(void *); +	default: +		return -EINVAL; +	} +} + +#define MAX_RESOLVE_DEPTH 32 + +int64_t btf__resolve_size(const struct btf *btf, uint32_t type_id) +{ +	const struct btf_array *array; +	const struct btf_type *t; +	uint32_t nelems = 1; +	int64_t size = -1; +	int i; + +	t = btf_type_by_id(btf, type_id); +	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); +	     i++) { +		size = btf_type_size(t); +		if (size >= 0) +			break; + +		switch (BTF_INFO_KIND(t->info)) { +		case BTF_KIND_TYPEDEF: +		case BTF_KIND_VOLATILE: +		case BTF_KIND_CONST: +		case BTF_KIND_RESTRICT: +			type_id = t->type; +			break; +		case BTF_KIND_ARRAY: +			array = (const struct btf_array *)(t + 1); +			if (nelems && array->nelems > UINT32_MAX / nelems) +				return -E2BIG; +			nelems *= array->nelems; +			type_id = array->type; +			break; +		default: +			return -EINVAL; +		} + +		t = btf_type_by_id(btf, type_id); +	} + +	if (size < 0) +		return -EINVAL; + +	if (nelems && size > UINT32_MAX / nelems) +		return -E2BIG; + +	return nelems * size; +} + +int32_t btf__find_by_name(const struct btf *btf, const char *type_name) +{ +	uint32_t i; + +	if (!strcmp(type_name, "void")) +		return 0; + +	for (i = 1; i <= btf->nr_types; i++) { +		const struct btf_type *t = btf->types[i]; +		const char *name = btf_name_by_offset(btf, t->name_off); + +		if (name && !strcmp(type_name, name)) +			return i; +	} + +	return -ENOENT; +} + +void btf__free(struct btf *btf) +{ +	if (!btf) +		return; + +	if (btf->fd != -1) +		close(btf->fd); + +	free(btf->data); +	free(btf->types); +	free(btf); +} + +struct btf *btf__new(uint8_t *data, uint32_t size, +		     btf_print_fn_t err_log) +{ +	uint32_t log_buf_size = 0; +	char *log_buf = NULL; +	struct btf *btf; +	int err; + +	btf = calloc(1, sizeof(struct btf)); +	if (!btf) +		return ERR_PTR(-ENOMEM); + +	btf->fd = -1; + +	if (err_log) { +		log_buf = malloc(BPF_LOG_BUF_SIZE); +		if (!log_buf) { +			err = -ENOMEM; +			goto done; +		} +		*log_buf = 0; +		log_buf_size = BPF_LOG_BUF_SIZE; +	} + +	btf->data = malloc(size); +	if (!btf->data) { +		err = -ENOMEM; +		goto done; +	} + +	memcpy(btf->data, data, size); +	btf->data_size = size; + +	btf->fd = bpf_load_btf(btf->data, btf->data_size, +			       log_buf, log_buf_size, false); + +	if (btf->fd == -1) { +		err = -errno; +		elog("Error loading BTF: %s(%d)\n", strerror(errno), errno); +		if (log_buf && *log_buf) +			elog("%s\n", log_buf); +		goto done; +	} + +	err = btf_parse_hdr(btf, err_log); +	if (err) +		goto done; + +	err = btf_parse_str_sec(btf, err_log); +	if (err) +		goto done; + +	err = btf_parse_type_sec(btf, err_log); + +done: +	free(log_buf); + +	if (err) { +		btf__free(btf); +		return ERR_PTR(err); +	} + +	return btf; +} + +int btf__fd(const struct btf *btf) +{ +	return btf->fd; +} diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h new file mode 100644 index 000000000000..74bb344035bb --- /dev/null +++ b/tools/lib/bpf/btf.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Facebook */ + +#ifndef __BPF_BTF_H +#define __BPF_BTF_H + +#include <stdint.h> + +#define BTF_ELF_SEC ".BTF" + +struct btf; + +typedef int (*btf_print_fn_t)(const char *, ...) +	__attribute__((format(printf, 1, 2))); + +void btf__free(struct btf *btf); +struct btf *btf__new(uint8_t *data, uint32_t size, btf_print_fn_t err_log); +int32_t btf__find_by_name(const struct btf *btf, const char *type_name); +int64_t btf__resolve_size(const struct btf *btf, uint32_t type_id); +int btf__fd(const struct btf *btf); + +#endif diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 5922443063f0..a1e96b5de5ff 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -31,6 +31,7 @@  #include <unistd.h>  #include <fcntl.h>  #include <errno.h> +#include <perf-sys.h>  #include <asm/unistd.h>  #include <linux/err.h>  #include <linux/kernel.h> @@ -45,6 +46,7 @@  #include "libbpf.h"  #include "bpf.h" +#include "btf.h"  #ifndef EM_BPF  #define EM_BPF 247 @@ -176,6 +178,7 @@ struct bpf_program {  	/* Index in elf obj file, for relocation use. */  	int idx;  	char *name; +	int prog_ifindex;  	char *section_name;  	struct bpf_insn *insns;  	size_t insns_cnt, main_prog_cnt; @@ -211,7 +214,10 @@ struct bpf_map {  	int fd;  	char *name;  	size_t offset; +	int map_ifindex;  	struct bpf_map_def def; +	uint32_t btf_key_type_id; +	uint32_t btf_value_type_id;  	void *priv;  	bpf_map_clear_priv_t clear_priv;  }; @@ -256,6 +262,8 @@ struct bpf_object {  	 */  	struct list_head list; +	struct btf *btf; +  	void *priv;  	bpf_object_clear_priv_t clear_priv; @@ -819,7 +827,15 @@ static int bpf_object__elf_collect(struct bpf_object *obj)  							data->d_size);  		else if (strcmp(name, "maps") == 0)  			obj->efile.maps_shndx = idx; -		else if (sh.sh_type == SHT_SYMTAB) { +		else if (strcmp(name, BTF_ELF_SEC) == 0) { +			obj->btf = btf__new(data->d_buf, data->d_size, +					    __pr_debug); +			if (IS_ERR(obj->btf)) { +				pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n", +					   BTF_ELF_SEC, PTR_ERR(obj->btf)); +				obj->btf = NULL; +			} +		} else if (sh.sh_type == SHT_SYMTAB) {  			if (obj->efile.symbols) {  				pr_warning("bpf: multiple SYMTAB in %s\n",  					   obj->path); @@ -996,33 +1012,127 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,  	return 0;  } +static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) +{ +	struct bpf_map_def *def = &map->def; +	const size_t max_name = 256; +	int64_t key_size, value_size; +	int32_t key_id, value_id; +	char name[max_name]; + +	/* Find key type by name from BTF */ +	if (snprintf(name, max_name, "%s_key", map->name) == max_name) { +		pr_warning("map:%s length of BTF key_type:%s_key is too long\n", +			   map->name, map->name); +		return -EINVAL; +	} + +	key_id = btf__find_by_name(btf, name); +	if (key_id < 0) { +		pr_debug("map:%s key_type:%s cannot be found in BTF\n", +			 map->name, name); +		return key_id; +	} + +	key_size = btf__resolve_size(btf, key_id); +	if (key_size < 0) { +		pr_warning("map:%s key_type:%s cannot get the BTF type_size\n", +			   map->name, name); +		return key_size; +	} + +	if (def->key_size != key_size) { +		pr_warning("map:%s key_type:%s has BTF type_size:%u != key_size:%u\n", +			   map->name, name, (unsigned int)key_size, def->key_size); +		return -EINVAL; +	} + +	/* Find value type from BTF */ +	if (snprintf(name, max_name, "%s_value", map->name) == max_name) { +		pr_warning("map:%s length of BTF value_type:%s_value is too long\n", +			  map->name, map->name); +		return -EINVAL; +	} + +	value_id = btf__find_by_name(btf, name); +	if (value_id < 0) { +		pr_debug("map:%s value_type:%s cannot be found in BTF\n", +			 map->name, name); +		return value_id; +	} + +	value_size = btf__resolve_size(btf, value_id); +	if (value_size < 0) { +		pr_warning("map:%s value_type:%s cannot get the BTF type_size\n", +			   map->name, name); +		return value_size; +	} + +	if (def->value_size != value_size) { +		pr_warning("map:%s value_type:%s has BTF type_size:%u != value_size:%u\n", +			   map->name, name, (unsigned int)value_size, def->value_size); +		return -EINVAL; +	} + +	map->btf_key_type_id = key_id; +	map->btf_value_type_id = value_id; + +	return 0; +} +  static int  bpf_object__create_maps(struct bpf_object *obj)  { +	struct bpf_create_map_attr create_attr = {};  	unsigned int i; +	int err;  	for (i = 0; i < obj->nr_maps; i++) { -		struct bpf_map_def *def = &obj->maps[i].def; -		int *pfd = &obj->maps[i].fd; - -		*pfd = bpf_create_map_name(def->type, -					   obj->maps[i].name, -					   def->key_size, -					   def->value_size, -					   def->max_entries, -					   def->map_flags); +		struct bpf_map *map = &obj->maps[i]; +		struct bpf_map_def *def = &map->def; +		int *pfd = &map->fd; + +		create_attr.name = map->name; +		create_attr.map_ifindex = map->map_ifindex; +		create_attr.map_type = def->type; +		create_attr.map_flags = def->map_flags; +		create_attr.key_size = def->key_size; +		create_attr.value_size = def->value_size; +		create_attr.max_entries = def->max_entries; +		create_attr.btf_fd = 0; +		create_attr.btf_key_type_id = 0; +		create_attr.btf_value_type_id = 0; + +		if (obj->btf && !bpf_map_find_btf_info(map, obj->btf)) { +			create_attr.btf_fd = btf__fd(obj->btf); +			create_attr.btf_key_type_id = map->btf_key_type_id; +			create_attr.btf_value_type_id = map->btf_value_type_id; +		} + +		*pfd = bpf_create_map_xattr(&create_attr); +		if (*pfd < 0 && create_attr.btf_key_type_id) { +			pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", +				   map->name, strerror(errno), errno); +			create_attr.btf_fd = 0; +			create_attr.btf_key_type_id = 0; +			create_attr.btf_value_type_id = 0; +			map->btf_key_type_id = 0; +			map->btf_value_type_id = 0; +			*pfd = bpf_create_map_xattr(&create_attr); +		} +  		if (*pfd < 0) {  			size_t j; -			int err = *pfd; +			err = *pfd;  			pr_warning("failed to create map (name: '%s'): %s\n", -				   obj->maps[i].name, +				   map->name,  				   strerror(errno));  			for (j = 0; j < i; j++)  				zclose(obj->maps[j].fd);  			return err;  		} -		pr_debug("create map %s: fd=%d\n", obj->maps[i].name, *pfd); +		pr_debug("create map %s: fd=%d\n", map->name, *pfd);  	}  	return 0; @@ -1166,7 +1276,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)  static int  load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,  	     const char *name, struct bpf_insn *insns, int insns_cnt, -	     char *license, u32 kern_version, int *pfd) +	     char *license, u32 kern_version, int *pfd, int prog_ifindex)  {  	struct bpf_load_program_attr load_attr;  	char *log_buf; @@ -1180,6 +1290,7 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,  	load_attr.insns_cnt = insns_cnt;  	load_attr.license = license;  	load_attr.kern_version = kern_version; +	load_attr.prog_ifindex = prog_ifindex;  	if (!load_attr.insns || !load_attr.insns_cnt)  		return -EINVAL; @@ -1261,7 +1372,8 @@ bpf_program__load(struct bpf_program *prog,  		}  		err = load_program(prog->type, prog->expected_attach_type,  				   prog->name, prog->insns, prog->insns_cnt, -				   license, kern_version, &fd); +				   license, kern_version, &fd, +				   prog->prog_ifindex);  		if (!err)  			prog->instances.fds[0] = fd;  		goto out; @@ -1292,7 +1404,8 @@ bpf_program__load(struct bpf_program *prog,  		err = load_program(prog->type, prog->expected_attach_type,  				   prog->name, result.new_insn_ptr,  				   result.new_insn_cnt, -				   license, kern_version, &fd); +				   license, kern_version, &fd, +				   prog->prog_ifindex);  		if (err) {  			pr_warning("Loading the %dth instance of program '%s' failed\n", @@ -1331,9 +1444,39 @@ bpf_object__load_progs(struct bpf_object *obj)  	return 0;  } -static int bpf_object__validate(struct bpf_object *obj) +static bool bpf_prog_type__needs_kver(enum bpf_prog_type type) +{ +	switch (type) { +	case BPF_PROG_TYPE_SOCKET_FILTER: +	case BPF_PROG_TYPE_SCHED_CLS: +	case BPF_PROG_TYPE_SCHED_ACT: +	case BPF_PROG_TYPE_XDP: +	case BPF_PROG_TYPE_CGROUP_SKB: +	case BPF_PROG_TYPE_CGROUP_SOCK: +	case BPF_PROG_TYPE_LWT_IN: +	case BPF_PROG_TYPE_LWT_OUT: +	case BPF_PROG_TYPE_LWT_XMIT: +	case BPF_PROG_TYPE_LWT_SEG6LOCAL: +	case BPF_PROG_TYPE_SOCK_OPS: +	case BPF_PROG_TYPE_SK_SKB: +	case BPF_PROG_TYPE_CGROUP_DEVICE: +	case BPF_PROG_TYPE_SK_MSG: +	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: +	case BPF_PROG_TYPE_LIRC_MODE2: +		return false; +	case BPF_PROG_TYPE_UNSPEC: +	case BPF_PROG_TYPE_KPROBE: +	case BPF_PROG_TYPE_TRACEPOINT: +	case BPF_PROG_TYPE_PERF_EVENT: +	case BPF_PROG_TYPE_RAW_TRACEPOINT: +	default: +		return true; +	} +} + +static int bpf_object__validate(struct bpf_object *obj, bool needs_kver)  { -	if (obj->kern_version == 0) { +	if (needs_kver && obj->kern_version == 0) {  		pr_warning("%s doesn't provide kernel version\n",  			   obj->path);  		return -LIBBPF_ERRNO__KVERSION; @@ -1342,7 +1485,8 @@ static int bpf_object__validate(struct bpf_object *obj)  }  static struct bpf_object * -__bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz) +__bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, +		   bool needs_kver)  {  	struct bpf_object *obj;  	int err; @@ -1360,7 +1504,7 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz)  	CHECK_ERR(bpf_object__check_endianness(obj), err, out);  	CHECK_ERR(bpf_object__elf_collect(obj), err, out);  	CHECK_ERR(bpf_object__collect_reloc(obj), err, out); -	CHECK_ERR(bpf_object__validate(obj), err, out); +	CHECK_ERR(bpf_object__validate(obj, needs_kver), err, out);  	bpf_object__elf_finish(obj);  	return obj; @@ -1377,7 +1521,7 @@ struct bpf_object *bpf_object__open(const char *path)  	pr_debug("loading %s\n", path); -	return __bpf_object__open(path, NULL, 0); +	return __bpf_object__open(path, NULL, 0, true);  }  struct bpf_object *bpf_object__open_buffer(void *obj_buf, @@ -1400,7 +1544,7 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf,  	pr_debug("loading object '%s' from buffer\n",  		 name); -	return __bpf_object__open(name, obj_buf, obj_buf_sz); +	return __bpf_object__open(name, obj_buf, obj_buf_sz, true);  }  int bpf_object__unload(struct bpf_object *obj) @@ -1641,6 +1785,7 @@ void bpf_object__close(struct bpf_object *obj)  	bpf_object__elf_finish(obj);  	bpf_object__unload(obj); +	btf__free(obj->btf);  	for (i = 0; i < obj->nr_maps; i++) {  		zfree(&obj->maps[i].name); @@ -1692,6 +1837,11 @@ unsigned int bpf_object__kversion(struct bpf_object *obj)  	return obj ? obj->kern_version : 0;  } +int bpf_object__btf_fd(const struct bpf_object *obj) +{ +	return obj->btf ? btf__fd(obj->btf) : -1; +} +  int bpf_object__set_priv(struct bpf_object *obj, void *priv,  			 bpf_object_clear_priv_t clear_priv)  { @@ -1845,11 +1995,12 @@ BPF_PROG_TYPE_FNS(kprobe, BPF_PROG_TYPE_KPROBE);  BPF_PROG_TYPE_FNS(sched_cls, BPF_PROG_TYPE_SCHED_CLS);  BPF_PROG_TYPE_FNS(sched_act, BPF_PROG_TYPE_SCHED_ACT);  BPF_PROG_TYPE_FNS(tracepoint, BPF_PROG_TYPE_TRACEPOINT); +BPF_PROG_TYPE_FNS(raw_tracepoint, BPF_PROG_TYPE_RAW_TRACEPOINT);  BPF_PROG_TYPE_FNS(xdp, BPF_PROG_TYPE_XDP);  BPF_PROG_TYPE_FNS(perf_event, BPF_PROG_TYPE_PERF_EVENT); -static void bpf_program__set_expected_attach_type(struct bpf_program *prog, -						 enum bpf_attach_type type) +void bpf_program__set_expected_attach_type(struct bpf_program *prog, +					   enum bpf_attach_type type)  {  	prog->expected_attach_type = type;  } @@ -1859,6 +2010,9 @@ static void bpf_program__set_expected_attach_type(struct bpf_program *prog,  #define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0) +#define BPF_S_PROG_SEC(string, ptype) \ +	BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK, ptype) +  #define BPF_SA_PROG_SEC(string, ptype) \  	BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, ptype) @@ -1874,6 +2028,7 @@ static const struct {  	BPF_PROG_SEC("classifier",	BPF_PROG_TYPE_SCHED_CLS),  	BPF_PROG_SEC("action",		BPF_PROG_TYPE_SCHED_ACT),  	BPF_PROG_SEC("tracepoint/",	BPF_PROG_TYPE_TRACEPOINT), +	BPF_PROG_SEC("raw_tracepoint/",	BPF_PROG_TYPE_RAW_TRACEPOINT),  	BPF_PROG_SEC("xdp",		BPF_PROG_TYPE_XDP),  	BPF_PROG_SEC("perf_event",	BPF_PROG_TYPE_PERF_EVENT),  	BPF_PROG_SEC("cgroup/skb",	BPF_PROG_TYPE_CGROUP_SKB), @@ -1889,10 +2044,15 @@ static const struct {  	BPF_SA_PROG_SEC("cgroup/bind6",	BPF_CGROUP_INET6_BIND),  	BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT),  	BPF_SA_PROG_SEC("cgroup/connect6", BPF_CGROUP_INET6_CONNECT), +	BPF_SA_PROG_SEC("cgroup/sendmsg4", BPF_CGROUP_UDP4_SENDMSG), +	BPF_SA_PROG_SEC("cgroup/sendmsg6", BPF_CGROUP_UDP6_SENDMSG), +	BPF_S_PROG_SEC("cgroup/post_bind4", BPF_CGROUP_INET4_POST_BIND), +	BPF_S_PROG_SEC("cgroup/post_bind6", BPF_CGROUP_INET6_POST_BIND),  };  #undef BPF_PROG_SEC  #undef BPF_PROG_SEC_FULL +#undef BPF_S_PROG_SEC  #undef BPF_SA_PROG_SEC  static int bpf_program__identify_section(struct bpf_program *prog) @@ -1929,6 +2089,16 @@ const char *bpf_map__name(struct bpf_map *map)  	return map ? map->name : NULL;  } +uint32_t bpf_map__btf_key_type_id(const struct bpf_map *map) +{ +	return map ? map->btf_key_type_id : 0; +} + +uint32_t bpf_map__btf_value_type_id(const struct bpf_map *map) +{ +	return map ? map->btf_value_type_id : 0; +} +  int bpf_map__set_priv(struct bpf_map *map, void *priv,  		     bpf_map_clear_priv_t clear_priv)  { @@ -2028,14 +2198,18 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,  	enum bpf_attach_type expected_attach_type;  	enum bpf_prog_type prog_type;  	struct bpf_object *obj; +	struct bpf_map *map;  	int section_idx;  	int err;  	if (!attr)  		return -EINVAL; +	if (!attr->file) +		return -EINVAL; -	obj = bpf_object__open(attr->file); -	if (IS_ERR(obj)) +	obj = __bpf_object__open(attr->file, NULL, 0, +				 bpf_prog_type__needs_kver(attr->prog_type)); +	if (IS_ERR_OR_NULL(obj))  		return -ENOENT;  	bpf_object__for_each_program(prog, obj) { @@ -2044,6 +2218,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,  		 * section name.  		 */  		prog_type = attr->prog_type; +		prog->prog_ifindex = attr->ifindex;  		expected_attach_type = attr->expected_attach_type;  		if (prog_type == BPF_PROG_TYPE_UNSPEC) {  			section_idx = bpf_program__identify_section(prog); @@ -2064,6 +2239,10 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,  			first_prog = prog;  	} +	bpf_map__for_each(map, obj) { +		map->map_ifindex = attr->ifindex; +	} +  	if (!first_prog) {  		pr_warning("object file doesn't contain bpf program\n");  		bpf_object__close(obj); @@ -2080,3 +2259,63 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,  	*prog_fd = bpf_program__fd(first_prog);  	return 0;  } + +enum bpf_perf_event_ret +bpf_perf_event_read_simple(void *mem, unsigned long size, +			   unsigned long page_size, void **buf, size_t *buf_len, +			   bpf_perf_event_print_t fn, void *priv) +{ +	volatile struct perf_event_mmap_page *header = mem; +	__u64 data_tail = header->data_tail; +	__u64 data_head = header->data_head; +	void *base, *begin, *end; +	int ret; + +	asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */ +	if (data_head == data_tail) +		return LIBBPF_PERF_EVENT_CONT; + +	base = ((char *)header) + page_size; + +	begin = base + data_tail % size; +	end = base + data_head % size; + +	while (begin != end) { +		struct perf_event_header *ehdr; + +		ehdr = begin; +		if (begin + ehdr->size > base + size) { +			long len = base + size - begin; + +			if (*buf_len < ehdr->size) { +				free(*buf); +				*buf = malloc(ehdr->size); +				if (!*buf) { +					ret = LIBBPF_PERF_EVENT_ERROR; +					break; +				} +				*buf_len = ehdr->size; +			} + +			memcpy(*buf, begin, len); +			memcpy(*buf + len, base, ehdr->size - len); +			ehdr = (void *)*buf; +			begin = base + ehdr->size - len; +		} else if (begin + ehdr->size == base + size) { +			begin = base; +		} else { +			begin += ehdr->size; +		} + +		ret = fn(ehdr, priv); +		if (ret != LIBBPF_PERF_EVENT_CONT) +			break; + +		data_tail += ehdr->size; +	} + +	__sync_synchronize(); /* smp_mb() */ +	header->data_tail = data_tail; + +	return ret; +} diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index a3a62a583f27..09976531aa74 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -52,8 +52,8 @@ enum libbpf_errno {  int libbpf_strerror(int err, char *buf, size_t size);  /* - * In include/linux/compiler-gcc.h, __printf is defined. However - * it should be better if libbpf.h doesn't depend on Linux header file. + * __printf is defined in include/linux/compiler-gcc.h. However, + * it would be better if libbpf.h didn't depend on Linux header files.   * So instead of __printf, here we use gcc attribute directly.   */  typedef int (*libbpf_print_fn_t)(const char *, ...) @@ -78,6 +78,7 @@ int bpf_object__load(struct bpf_object *obj);  int bpf_object__unload(struct bpf_object *obj);  const char *bpf_object__name(struct bpf_object *obj);  unsigned int bpf_object__kversion(struct bpf_object *obj); +int bpf_object__btf_fd(const struct bpf_object *obj);  struct bpf_object *bpf_object__next(struct bpf_object *prev);  #define bpf_object__for_each_safe(pos, tmp)			\ @@ -91,7 +92,7 @@ int bpf_object__set_priv(struct bpf_object *obj, void *priv,  			 bpf_object_clear_priv_t clear_priv);  void *bpf_object__priv(struct bpf_object *prog); -/* Accessors of bpf_program. */ +/* Accessors of bpf_program */  struct bpf_program;  struct bpf_program *bpf_program__next(struct bpf_program *prog,  				      struct bpf_object *obj); @@ -120,28 +121,28 @@ struct bpf_insn;  /*   * Libbpf allows callers to adjust BPF programs before being loaded - * into kernel. One program in an object file can be transform into - * multiple variants to be attached to different code. + * into kernel. One program in an object file can be transformed into + * multiple variants to be attached to different hooks.   *   * bpf_program_prep_t, bpf_program__set_prep and bpf_program__nth_fd - * are APIs for this propose. + * form an API for this purpose.   *   * - bpf_program_prep_t: - *   It defines 'preprocessor', which is a caller defined function + *   Defines a 'preprocessor', which is a caller defined function   *   passed to libbpf through bpf_program__set_prep(), and will be   *   called before program is loaded. The processor should adjust - *   the program one time for each instances according to the number + *   the program one time for each instance according to the instance id   *   passed to it.   *   * - bpf_program__set_prep: - *   Attachs a preprocessor to a BPF program. The number of instances - *   whould be created is also passed through this function. + *   Attaches a preprocessor to a BPF program. The number of instances + *   that should be created is also passed through this function.   *   * - bpf_program__nth_fd: - *   After the program is loaded, get resuling fds from bpf program for - *   each instances. + *   After the program is loaded, get resulting FD of a given instance + *   of the BPF program.   * - * If bpf_program__set_prep() is not used, the program whould be loaded + * If bpf_program__set_prep() is not used, the program would be loaded   * without adjustment during bpf_object__load(). The program has only   * one instance. In this case bpf_program__fd(prog) is equal to   * bpf_program__nth_fd(prog, 0). @@ -155,7 +156,7 @@ struct bpf_prog_prep_result {  	struct bpf_insn *new_insn_ptr;  	int new_insn_cnt; -	/* If not NULL, result fd is set to it */ +	/* If not NULL, result FD is written to it. */  	int *pfd;  }; @@ -168,8 +169,8 @@ struct bpf_prog_prep_result {   *  - res:	Output parameter, result of transformation.   *   * Return value: - *  - Zero: pre-processing success. - *  - Non-zero: pre-processing, stop loading. + *  - Zero:	pre-processing success. + *  - Non-zero:	pre-processing error, stop loading.   */  typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,  				  struct bpf_insn *insns, int insns_cnt, @@ -181,19 +182,23 @@ int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,  int bpf_program__nth_fd(struct bpf_program *prog, int n);  /* - * Adjust type of bpf program. Default is kprobe. + * Adjust type of BPF program. Default is kprobe.   */  int bpf_program__set_socket_filter(struct bpf_program *prog);  int bpf_program__set_tracepoint(struct bpf_program *prog); +int bpf_program__set_raw_tracepoint(struct bpf_program *prog);  int bpf_program__set_kprobe(struct bpf_program *prog);  int bpf_program__set_sched_cls(struct bpf_program *prog);  int bpf_program__set_sched_act(struct bpf_program *prog);  int bpf_program__set_xdp(struct bpf_program *prog);  int bpf_program__set_perf_event(struct bpf_program *prog);  void bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type); +void bpf_program__set_expected_attach_type(struct bpf_program *prog, +					   enum bpf_attach_type type);  bool bpf_program__is_socket_filter(struct bpf_program *prog);  bool bpf_program__is_tracepoint(struct bpf_program *prog); +bool bpf_program__is_raw_tracepoint(struct bpf_program *prog);  bool bpf_program__is_kprobe(struct bpf_program *prog);  bool bpf_program__is_sched_cls(struct bpf_program *prog);  bool bpf_program__is_sched_act(struct bpf_program *prog); @@ -201,10 +206,10 @@ bool bpf_program__is_xdp(struct bpf_program *prog);  bool bpf_program__is_perf_event(struct bpf_program *prog);  /* - * We don't need __attribute__((packed)) now since it is - * unnecessary for 'bpf_map_def' because they are all aligned. - * In addition, using it will trigger -Wpacked warning message, - * and will be treated as an error due to -Werror. + * No need for __attribute__((packed)), all members of 'bpf_map_def' + * are all aligned.  In addition, using __attribute__((packed)) + * would trigger a -Wpacked warning message, and lead to an error + * if -Werror is set.   */  struct bpf_map_def {  	unsigned int type; @@ -215,8 +220,8 @@ struct bpf_map_def {  };  /* - * There is another 'struct bpf_map' in include/linux/map.h. However, - * it is not a uapi header so no need to consider name clash. + * The 'struct bpf_map' in include/linux/bpf.h is internal to the kernel, + * so no need to worry about a name clash.   */  struct bpf_map;  struct bpf_map * @@ -224,7 +229,7 @@ bpf_object__find_map_by_name(struct bpf_object *obj, const char *name);  /*   * Get bpf_map through the offset of corresponding struct bpf_map_def - * in the bpf object file. + * in the BPF object file.   */  struct bpf_map *  bpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset); @@ -239,6 +244,8 @@ bpf_map__next(struct bpf_map *map, struct bpf_object *obj);  int bpf_map__fd(struct bpf_map *map);  const struct bpf_map_def *bpf_map__def(struct bpf_map *map);  const char *bpf_map__name(struct bpf_map *map); +uint32_t bpf_map__btf_key_type_id(const struct bpf_map *map); +uint32_t bpf_map__btf_value_type_id(const struct bpf_map *map);  typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);  int bpf_map__set_priv(struct bpf_map *map, void *priv, @@ -252,6 +259,7 @@ struct bpf_prog_load_attr {  	const char *file;  	enum bpf_prog_type prog_type;  	enum bpf_attach_type expected_attach_type; +	int ifindex;  };  int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, @@ -260,4 +268,17 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,  		  struct bpf_object **pobj, int *prog_fd);  int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); + +enum bpf_perf_event_ret { +	LIBBPF_PERF_EVENT_DONE	= 0, +	LIBBPF_PERF_EVENT_ERROR	= -1, +	LIBBPF_PERF_EVENT_CONT	= -2, +}; + +typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(void *event, +							  void *priv); +int bpf_perf_event_read_simple(void *mem, unsigned long size, +			       unsigned long page_size, +			       void **buf, size_t *buf_len, +			       bpf_perf_event_print_t fn, void *priv);  #endif |