mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-20 16:29:07 +08:00
bpf: sync with latest bpf-next tree (#5)
sync with latest bpf-next tree. the include/linux/filter.h is created as libbpf.c tries to use various insn define macros. Signed-off-by: Yonghong Song <yhs@fb.com>
This commit is contained in:
24
include/linux/filter.h
Normal file
24
include/linux/filter.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
||||
|
||||
#ifndef __LINUX_FILTER_H
|
||||
#define __LINUX_FILTER_H
|
||||
|
||||
#include <linux/bpf.h>
|
||||
|
||||
#define BPF_MOV64_IMM(DST, IMM) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU64 | BPF_MOV | BPF_K, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = 0, \
|
||||
.off = 0, \
|
||||
.imm = IMM })
|
||||
|
||||
#define BPF_EXIT_INSN() \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_JMP | BPF_EXIT, \
|
||||
.dst_reg = 0, \
|
||||
.src_reg = 0, \
|
||||
.off = 0, \
|
||||
.imm = 0 })
|
||||
|
||||
#endif
|
||||
@@ -103,6 +103,7 @@ enum bpf_cmd {
|
||||
BPF_BTF_LOAD,
|
||||
BPF_BTF_GET_FD_BY_ID,
|
||||
BPF_TASK_FD_QUERY,
|
||||
BPF_MAP_LOOKUP_AND_DELETE_ELEM,
|
||||
};
|
||||
|
||||
enum bpf_map_type {
|
||||
@@ -128,6 +129,8 @@ enum bpf_map_type {
|
||||
BPF_MAP_TYPE_CGROUP_STORAGE,
|
||||
BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
|
||||
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
|
||||
BPF_MAP_TYPE_QUEUE,
|
||||
BPF_MAP_TYPE_STACK,
|
||||
};
|
||||
|
||||
enum bpf_prog_type {
|
||||
@@ -254,9 +257,6 @@ enum bpf_attach_type {
|
||||
/* Specify numa node during map creation */
|
||||
#define BPF_F_NUMA_NODE (1U << 2)
|
||||
|
||||
/* flags for BPF_PROG_QUERY */
|
||||
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
||||
|
||||
#define BPF_OBJ_NAME_LEN 16U
|
||||
|
||||
/* Flags for accessing BPF object */
|
||||
@@ -266,6 +266,12 @@ enum bpf_attach_type {
|
||||
/* Flag for stack_map, store build_id+offset instead of pointer */
|
||||
#define BPF_F_STACK_BUILD_ID (1U << 5)
|
||||
|
||||
/* Zero-initialize hash function seed. This should only be used for testing. */
|
||||
#define BPF_F_ZERO_SEED (1U << 6)
|
||||
|
||||
/* flags for BPF_PROG_QUERY */
|
||||
#define BPF_F_QUERY_EFFECTIVE (1U << 0)
|
||||
|
||||
enum bpf_stack_build_id_status {
|
||||
/* user space need an empty entry to identify end of a trace */
|
||||
BPF_STACK_BUILD_ID_EMPTY = 0,
|
||||
@@ -332,6 +338,10 @@ union bpf_attr {
|
||||
* (context accesses, allowed helpers, etc).
|
||||
*/
|
||||
__u32 expected_attach_type;
|
||||
__u32 prog_btf_fd; /* fd pointing to BTF type data */
|
||||
__u32 func_info_rec_size; /* userspace bpf_func_info size */
|
||||
__aligned_u64 func_info; /* func info */
|
||||
__u32 func_info_cnt; /* number of bpf_func_info records */
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||
@@ -462,6 +472,28 @@ union bpf_attr {
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* int bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags)
|
||||
* Description
|
||||
* Push an element *value* in *map*. *flags* is one of:
|
||||
*
|
||||
* **BPF_EXIST**
|
||||
* If the queue/stack is full, the oldest element is removed to
|
||||
* make room for this.
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* int bpf_map_pop_elem(struct bpf_map *map, void *value)
|
||||
* Description
|
||||
* Pop an element from *map*.
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* int bpf_map_peek_elem(struct bpf_map *map, void *value)
|
||||
* Description
|
||||
* Get an element from *map* without removing it.
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* int bpf_probe_read(void *dst, u32 size, const void *src)
|
||||
* Description
|
||||
* For tracing programs, safely attempt to read *size* bytes from
|
||||
@@ -1433,7 +1465,7 @@ union bpf_attr {
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* int bpf_skb_adjust_room(struct sk_buff *skb, u32 len_diff, u32 mode, u64 flags)
|
||||
* int bpf_skb_adjust_room(struct sk_buff *skb, s32 len_diff, u32 mode, u64 flags)
|
||||
* Description
|
||||
* Grow or shrink the room for data in the packet associated to
|
||||
* *skb* by *len_diff*, and according to the selected *mode*.
|
||||
@@ -2176,6 +2208,8 @@ union bpf_attr {
|
||||
* **CONFIG_NET** configuration option.
|
||||
* Return
|
||||
* Pointer to *struct bpf_sock*, or NULL in case of failure.
|
||||
* For sockets with reuseport option, *struct bpf_sock*
|
||||
* return is from reuse->socks[] using hash of the packet.
|
||||
*
|
||||
* struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags)
|
||||
* Description
|
||||
@@ -2208,6 +2242,8 @@ union bpf_attr {
|
||||
* **CONFIG_NET** configuration option.
|
||||
* Return
|
||||
* Pointer to *struct bpf_sock*, or NULL in case of failure.
|
||||
* For sockets with reuseport option, *struct bpf_sock*
|
||||
* return is from reuse->socks[] using hash of the packet.
|
||||
*
|
||||
* int bpf_sk_release(struct bpf_sock *sk)
|
||||
* Description
|
||||
@@ -2215,6 +2251,23 @@ union bpf_attr {
|
||||
* pointer that was returned from bpf_sk_lookup_xxx\ ().
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags)
|
||||
* Description
|
||||
* For socket policies, insert *len* bytes into msg at offset
|
||||
* *start*.
|
||||
*
|
||||
* If a program of type **BPF_PROG_TYPE_SK_MSG** is run on a
|
||||
* *msg* it may want to insert metadata or options into the msg.
|
||||
* This can later be read and used by any of the lower layer BPF
|
||||
* hooks.
|
||||
*
|
||||
* This helper may fail if under memory pressure (a malloc
|
||||
* fails) in these cases BPF programs will get an appropriate
|
||||
* error and BPF programs will need to handle them.
|
||||
*
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
@@ -2303,7 +2356,11 @@ union bpf_attr {
|
||||
FN(skb_ancestor_cgroup_id), \
|
||||
FN(sk_lookup_tcp), \
|
||||
FN(sk_lookup_udp), \
|
||||
FN(sk_release),
|
||||
FN(sk_release), \
|
||||
FN(map_push_elem), \
|
||||
FN(map_pop_elem), \
|
||||
FN(map_peek_elem), \
|
||||
FN(msg_push_data),
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
* function eBPF program intends to call
|
||||
@@ -2411,6 +2468,7 @@ struct __sk_buff {
|
||||
|
||||
__u32 data_meta;
|
||||
struct bpf_flow_keys *flow_keys;
|
||||
__u64 tstamp;
|
||||
};
|
||||
|
||||
struct bpf_tunnel_key {
|
||||
@@ -2585,6 +2643,10 @@ struct bpf_prog_info {
|
||||
__u32 nr_jited_func_lens;
|
||||
__aligned_u64 jited_ksyms;
|
||||
__aligned_u64 jited_func_lens;
|
||||
__u32 btf_id;
|
||||
__u32 func_info_rec_size;
|
||||
__aligned_u64 func_info;
|
||||
__u32 func_info_cnt;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_map_info {
|
||||
@@ -2896,4 +2958,9 @@ struct bpf_flow_keys {
|
||||
};
|
||||
};
|
||||
|
||||
struct bpf_func_info {
|
||||
__u32 insn_offset;
|
||||
__u32 type_id;
|
||||
};
|
||||
|
||||
#endif /* _UAPI__LINUX_BPF_H__ */
|
||||
|
||||
@@ -40,7 +40,8 @@ struct btf_type {
|
||||
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
||||
* "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST and RESTRICT.
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
* FUNC and FUNC_PROTO.
|
||||
* "type" is a type_id referring to another type.
|
||||
*/
|
||||
union {
|
||||
@@ -64,8 +65,10 @@ struct btf_type {
|
||||
#define BTF_KIND_VOLATILE 9 /* Volatile */
|
||||
#define BTF_KIND_CONST 10 /* Const */
|
||||
#define BTF_KIND_RESTRICT 11 /* Restrict */
|
||||
#define BTF_KIND_MAX 11
|
||||
#define NR_BTF_KINDS 12
|
||||
#define BTF_KIND_FUNC 12 /* Function */
|
||||
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
|
||||
#define BTF_KIND_MAX 13
|
||||
#define NR_BTF_KINDS 14
|
||||
|
||||
/* For some specific BTF_KIND, "struct btf_type" is immediately
|
||||
* followed by extra data.
|
||||
@@ -110,4 +113,13 @@ struct btf_member {
|
||||
__u32 offset; /* offset in bits */
|
||||
};
|
||||
|
||||
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
|
||||
* The exact number of btf_param is stored in the vlen (of the
|
||||
* info in "struct btf_type").
|
||||
*/
|
||||
struct btf_param {
|
||||
__u32 name_off;
|
||||
__u32 type;
|
||||
};
|
||||
|
||||
#endif /* _UAPI__LINUX_BTF_H__ */
|
||||
|
||||
@@ -287,6 +287,7 @@ enum {
|
||||
IFLA_BR_MCAST_STATS_ENABLED,
|
||||
IFLA_BR_MCAST_IGMP_VERSION,
|
||||
IFLA_BR_MCAST_MLD_VERSION,
|
||||
IFLA_BR_VLAN_STATS_PER_PORT,
|
||||
__IFLA_BR_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ enum nlmsgerr_attrs {
|
||||
#define NETLINK_LIST_MEMBERSHIPS 9
|
||||
#define NETLINK_CAP_ACK 10
|
||||
#define NETLINK_EXT_ACK 11
|
||||
#define NETLINK_DUMP_STRICT_CHK 12
|
||||
|
||||
struct nl_pktinfo {
|
||||
__u32 group;
|
||||
|
||||
62
src/bpf.c
62
src/bpf.c
@@ -177,6 +177,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
char *log_buf, size_t log_buf_sz)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
void *finfo = NULL;
|
||||
__u32 name_len;
|
||||
int fd;
|
||||
|
||||
@@ -196,6 +197,10 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
attr.log_level = 0;
|
||||
attr.kern_version = load_attr->kern_version;
|
||||
attr.prog_ifindex = load_attr->prog_ifindex;
|
||||
attr.prog_btf_fd = load_attr->prog_btf_fd;
|
||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||
attr.func_info_cnt = load_attr->func_info_cnt;
|
||||
attr.func_info = ptr_to_u64(load_attr->func_info);
|
||||
memcpy(attr.prog_name, load_attr->name,
|
||||
min(name_len, BPF_OBJ_NAME_LEN - 1));
|
||||
|
||||
@@ -203,12 +208,55 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
if (fd >= 0 || !log_buf || !log_buf_sz)
|
||||
return fd;
|
||||
|
||||
/* After bpf_prog_load, the kernel may modify certain attributes
|
||||
* to give user space a hint how to deal with loading failure.
|
||||
* Check to see whether we can make some changes and load again.
|
||||
*/
|
||||
if (errno == E2BIG && attr.func_info_cnt &&
|
||||
attr.func_info_rec_size < load_attr->func_info_rec_size) {
|
||||
__u32 actual_rec_size = load_attr->func_info_rec_size;
|
||||
__u32 expected_rec_size = attr.func_info_rec_size;
|
||||
__u32 finfo_cnt = load_attr->func_info_cnt;
|
||||
__u64 finfo_len = actual_rec_size * finfo_cnt;
|
||||
const void *orecord;
|
||||
void *nrecord;
|
||||
int i;
|
||||
|
||||
finfo = malloc(finfo_len);
|
||||
if (!finfo)
|
||||
/* further try with log buffer won't help */
|
||||
return fd;
|
||||
|
||||
/* zero out bytes kernel does not understand */
|
||||
orecord = load_attr->func_info;
|
||||
nrecord = finfo;
|
||||
for (i = 0; i < load_attr->func_info_cnt; i++) {
|
||||
memcpy(nrecord, orecord, expected_rec_size);
|
||||
memset(nrecord + expected_rec_size, 0,
|
||||
actual_rec_size - expected_rec_size);
|
||||
orecord += actual_rec_size;
|
||||
nrecord += actual_rec_size;
|
||||
}
|
||||
|
||||
/* try with corrected func info records */
|
||||
attr.func_info = ptr_to_u64(finfo);
|
||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||
|
||||
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||
|
||||
if (fd >= 0 || !log_buf || !log_buf_sz)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Try again with log */
|
||||
attr.log_buf = ptr_to_u64(log_buf);
|
||||
attr.log_size = log_buf_sz;
|
||||
attr.log_level = 1;
|
||||
log_buf[0] = 0;
|
||||
return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||
done:
|
||||
free(finfo);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
||||
@@ -278,6 +326,18 @@ int bpf_map_lookup_elem(int fd, const void *key, void *value)
|
||||
return sys_bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
|
||||
bzero(&attr, sizeof(attr));
|
||||
attr.map_fd = fd;
|
||||
attr.key = ptr_to_u64(key);
|
||||
attr.value = ptr_to_u64(value);
|
||||
|
||||
return sys_bpf(BPF_MAP_LOOKUP_AND_DELETE_ELEM, &attr, sizeof(attr));
|
||||
}
|
||||
|
||||
int bpf_map_delete_elem(int fd, const void *key)
|
||||
{
|
||||
union bpf_attr attr;
|
||||
|
||||
15
src/bpf.h
15
src/bpf.h
@@ -27,6 +27,10 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef LIBBPF_API
|
||||
#define LIBBPF_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
@@ -74,6 +78,10 @@ struct bpf_load_program_attr {
|
||||
const char *license;
|
||||
__u32 kern_version;
|
||||
__u32 prog_ifindex;
|
||||
__u32 prog_btf_fd;
|
||||
__u32 func_info_rec_size;
|
||||
const void *func_info;
|
||||
__u32 func_info_cnt;
|
||||
};
|
||||
|
||||
/* Flags to direct loading requirements */
|
||||
@@ -99,6 +107,8 @@ LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value,
|
||||
__u64 flags);
|
||||
|
||||
LIBBPF_API int bpf_map_lookup_elem(int fd, const void *key, void *value);
|
||||
LIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key,
|
||||
void *value);
|
||||
LIBBPF_API int bpf_map_delete_elem(int fd, const void *key);
|
||||
LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);
|
||||
LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
|
||||
@@ -126,4 +136,9 @@ LIBBPF_API int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf,
|
||||
LIBBPF_API 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __LIBBPF_BPF_H */
|
||||
|
||||
347
src/btf.c
347
src/btf.c
@@ -37,6 +37,23 @@ struct btf {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct btf_ext {
|
||||
void *func_info;
|
||||
__u32 func_info_rec_size;
|
||||
__u32 func_info_len;
|
||||
};
|
||||
|
||||
/* The minimum bpf_func_info checked by the loader */
|
||||
struct bpf_func_info_min {
|
||||
__u32 insn_offset;
|
||||
__u32 type_id;
|
||||
};
|
||||
|
||||
static inline __u64 ptr_to_u64(const void *ptr)
|
||||
{
|
||||
return (__u64) (unsigned long) ptr;
|
||||
}
|
||||
|
||||
static int btf_add_type(struct btf *btf, struct btf_type *t)
|
||||
{
|
||||
if (btf->types_size - btf->nr_types < 2) {
|
||||
@@ -165,6 +182,10 @@ static int btf_parse_type_sec(struct btf *btf, btf_print_fn_t err_log)
|
||||
case BTF_KIND_ENUM:
|
||||
next_type += vlen * sizeof(struct btf_enum);
|
||||
break;
|
||||
case BTF_KIND_FUNC_PROTO:
|
||||
next_type += vlen * sizeof(struct btf_param);
|
||||
break;
|
||||
case BTF_KIND_FUNC:
|
||||
case BTF_KIND_TYPEDEF:
|
||||
case BTF_KIND_PTR:
|
||||
case BTF_KIND_FWD:
|
||||
@@ -393,3 +414,329 @@ const char *btf__name_by_offset(const struct btf *btf, __u32 offset)
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int btf_get_from_id(__u32 id, struct btf **btf)
|
||||
{
|
||||
struct bpf_btf_info btf_info = { 0 };
|
||||
__u32 len = sizeof(btf_info);
|
||||
__u32 last_size;
|
||||
int btf_fd;
|
||||
void *ptr;
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
*btf = NULL;
|
||||
btf_fd = bpf_btf_get_fd_by_id(id);
|
||||
if (btf_fd < 0)
|
||||
return 0;
|
||||
|
||||
/* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so
|
||||
* let's start with a sane default - 4KiB here - and resize it only if
|
||||
* bpf_obj_get_info_by_fd() needs a bigger buffer.
|
||||
*/
|
||||
btf_info.btf_size = 4096;
|
||||
last_size = btf_info.btf_size;
|
||||
ptr = malloc(last_size);
|
||||
if (!ptr) {
|
||||
err = -ENOMEM;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
bzero(ptr, last_size);
|
||||
btf_info.btf = ptr_to_u64(ptr);
|
||||
err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
|
||||
|
||||
if (!err && btf_info.btf_size > last_size) {
|
||||
void *temp_ptr;
|
||||
|
||||
last_size = btf_info.btf_size;
|
||||
temp_ptr = realloc(ptr, last_size);
|
||||
if (!temp_ptr) {
|
||||
err = -ENOMEM;
|
||||
goto exit_free;
|
||||
}
|
||||
ptr = temp_ptr;
|
||||
bzero(ptr, last_size);
|
||||
btf_info.btf = ptr_to_u64(ptr);
|
||||
err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
|
||||
}
|
||||
|
||||
if (err || btf_info.btf_size > last_size) {
|
||||
err = errno;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
*btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL);
|
||||
if (IS_ERR(*btf)) {
|
||||
err = PTR_ERR(*btf);
|
||||
*btf = NULL;
|
||||
}
|
||||
|
||||
exit_free:
|
||||
close(btf_fd);
|
||||
free(ptr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btf_ext_validate_func_info(const void *finfo, __u32 size,
|
||||
btf_print_fn_t err_log)
|
||||
{
|
||||
int sec_hdrlen = sizeof(struct btf_sec_func_info);
|
||||
__u32 size_left, num_records, record_size;
|
||||
const struct btf_sec_func_info *sinfo;
|
||||
__u64 total_record_size;
|
||||
|
||||
/* At least a func_info record size */
|
||||
if (size < sizeof(__u32)) {
|
||||
elog("BTF.ext func_info record size not found");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The record size needs to meet below minimum standard */
|
||||
record_size = *(__u32 *)finfo;
|
||||
if (record_size < sizeof(struct bpf_func_info_min) ||
|
||||
record_size % sizeof(__u32)) {
|
||||
elog("BTF.ext func_info invalid record size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sinfo = finfo + sizeof(__u32);
|
||||
size_left = size - sizeof(__u32);
|
||||
|
||||
/* If no func_info records, return failure now so .BTF.ext
|
||||
* won't be used.
|
||||
*/
|
||||
if (!size_left) {
|
||||
elog("BTF.ext no func info records");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (size_left) {
|
||||
if (size_left < sec_hdrlen) {
|
||||
elog("BTF.ext func_info header not found");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_records = sinfo->num_func_info;
|
||||
if (num_records == 0) {
|
||||
elog("incorrect BTF.ext num_func_info");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
total_record_size = sec_hdrlen +
|
||||
(__u64)num_records * record_size;
|
||||
if (size_left < total_record_size) {
|
||||
elog("incorrect BTF.ext num_func_info");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size_left -= total_record_size;
|
||||
sinfo = (void *)sinfo + total_record_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
|
||||
btf_print_fn_t err_log)
|
||||
{
|
||||
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
||||
__u32 meta_left, last_func_info_pos;
|
||||
void *finfo;
|
||||
|
||||
if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
|
||||
data_size < hdr->hdr_len) {
|
||||
elog("BTF.ext header not found");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdr->magic != BTF_MAGIC) {
|
||||
elog("Invalid BTF.ext magic:%x\n", hdr->magic);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdr->version != BTF_VERSION) {
|
||||
elog("Unsupported BTF.ext version:%u\n", hdr->version);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (hdr->flags) {
|
||||
elog("Unsupported BTF.ext flags:%x\n", hdr->flags);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
meta_left = data_size - hdr->hdr_len;
|
||||
if (!meta_left) {
|
||||
elog("BTF.ext has no data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (meta_left < hdr->func_info_off) {
|
||||
elog("Invalid BTF.ext func_info section offset:%u\n",
|
||||
hdr->func_info_off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdr->func_info_off & 0x03) {
|
||||
elog("BTF.ext func_info section is not aligned to 4 bytes\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
last_func_info_pos = hdr->hdr_len + hdr->func_info_off +
|
||||
hdr->func_info_len;
|
||||
if (last_func_info_pos > data_size) {
|
||||
elog("Invalid BTF.ext func_info section size:%u\n",
|
||||
hdr->func_info_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
finfo = data + hdr->hdr_len + hdr->func_info_off;
|
||||
return btf_ext_validate_func_info(finfo, hdr->func_info_len,
|
||||
err_log);
|
||||
}
|
||||
|
||||
void btf_ext__free(struct btf_ext *btf_ext)
|
||||
{
|
||||
if (!btf_ext)
|
||||
return;
|
||||
|
||||
free(btf_ext->func_info);
|
||||
free(btf_ext);
|
||||
}
|
||||
|
||||
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
|
||||
{
|
||||
const struct btf_ext_header *hdr;
|
||||
struct btf_ext *btf_ext;
|
||||
void *org_fdata, *fdata;
|
||||
__u32 hdrlen, size_u32;
|
||||
int err;
|
||||
|
||||
err = btf_ext_parse_hdr(data, size, err_log);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
btf_ext = calloc(1, sizeof(struct btf_ext));
|
||||
if (!btf_ext)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hdr = (const struct btf_ext_header *)data;
|
||||
hdrlen = hdr->hdr_len;
|
||||
size_u32 = sizeof(__u32);
|
||||
fdata = malloc(hdr->func_info_len - size_u32);
|
||||
if (!fdata) {
|
||||
free(btf_ext);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* remember record size and copy rest of func_info data */
|
||||
org_fdata = data + hdrlen + hdr->func_info_off;
|
||||
btf_ext->func_info_rec_size = *(__u32 *)org_fdata;
|
||||
memcpy(fdata, org_fdata + size_u32, hdr->func_info_len - size_u32);
|
||||
btf_ext->func_info = fdata;
|
||||
btf_ext->func_info_len = hdr->func_info_len - size_u32;
|
||||
|
||||
return btf_ext;
|
||||
}
|
||||
|
||||
int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const char *sec_name, void **func_info,
|
||||
__u32 *func_info_rec_size, __u32 *func_info_len)
|
||||
{
|
||||
__u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
|
||||
__u32 i, record_size, records_len;
|
||||
struct btf_sec_func_info *sinfo;
|
||||
const char *info_sec_name;
|
||||
__s64 remain_len;
|
||||
void *data;
|
||||
|
||||
record_size = btf_ext->func_info_rec_size;
|
||||
sinfo = btf_ext->func_info;
|
||||
remain_len = btf_ext->func_info_len;
|
||||
|
||||
while (remain_len > 0) {
|
||||
records_len = sinfo->num_func_info * record_size;
|
||||
info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
|
||||
if (strcmp(info_sec_name, sec_name)) {
|
||||
remain_len -= sec_hdrlen + records_len;
|
||||
sinfo = (void *)sinfo + sec_hdrlen + records_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
data = malloc(records_len);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(data, sinfo->data, records_len);
|
||||
|
||||
/* adjust the insn_offset, the data in .BTF.ext is
|
||||
* the actual byte offset, and the kernel expects
|
||||
* the offset in term of bpf_insn.
|
||||
*
|
||||
* adjust the insn offset only, the rest data will
|
||||
* be passed to kernel.
|
||||
*/
|
||||
for (i = 0; i < sinfo->num_func_info; i++) {
|
||||
struct bpf_func_info_min *record;
|
||||
|
||||
record = data + i * record_size;
|
||||
record->insn_offset /= sizeof(struct bpf_insn);
|
||||
}
|
||||
|
||||
*func_info = data;
|
||||
*func_info_len = records_len;
|
||||
*func_info_rec_size = record_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const char *sec_name, __u32 insns_cnt,
|
||||
void **func_info, __u32 *func_info_len)
|
||||
{
|
||||
__u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
|
||||
__u32 i, record_size, existing_flen, records_len;
|
||||
struct btf_sec_func_info *sinfo;
|
||||
const char *info_sec_name;
|
||||
__u64 remain_len;
|
||||
void *data;
|
||||
|
||||
record_size = btf_ext->func_info_rec_size;
|
||||
sinfo = btf_ext->func_info;
|
||||
remain_len = btf_ext->func_info_len;
|
||||
while (remain_len > 0) {
|
||||
records_len = sinfo->num_func_info * record_size;
|
||||
info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
|
||||
if (strcmp(info_sec_name, sec_name)) {
|
||||
remain_len -= sec_hdrlen + records_len;
|
||||
sinfo = (void *)sinfo + sec_hdrlen + records_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
existing_flen = *func_info_len;
|
||||
data = realloc(*func_info, existing_flen + records_len);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(data + existing_flen, sinfo->data, records_len);
|
||||
/* adjust insn_offset only, the rest data will be passed
|
||||
* to the kernel.
|
||||
*/
|
||||
for (i = 0; i < sinfo->num_func_info; i++) {
|
||||
struct bpf_func_info_min *record;
|
||||
|
||||
record = data + existing_flen + i * record_size;
|
||||
record->insn_offset =
|
||||
record->insn_offset / sizeof(struct bpf_insn) +
|
||||
insns_cnt;
|
||||
}
|
||||
*func_info = data;
|
||||
*func_info_len = existing_flen + records_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
59
src/btf.h
59
src/btf.h
@@ -6,15 +6,60 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef LIBBPF_API
|
||||
#define LIBBPF_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#define BTF_ELF_SEC ".BTF"
|
||||
#define BTF_EXT_ELF_SEC ".BTF.ext"
|
||||
|
||||
struct btf;
|
||||
struct btf_ext;
|
||||
struct btf_type;
|
||||
|
||||
/*
|
||||
* The .BTF.ext ELF section layout defined as
|
||||
* struct btf_ext_header
|
||||
* func_info subsection
|
||||
*
|
||||
* The func_info subsection layout:
|
||||
* record size for struct bpf_func_info in the func_info subsection
|
||||
* struct btf_sec_func_info for section #1
|
||||
* a list of bpf_func_info records for section #1
|
||||
* where struct bpf_func_info mimics one in include/uapi/linux/bpf.h
|
||||
* but may not be identical
|
||||
* struct btf_sec_func_info for section #2
|
||||
* a list of bpf_func_info records for section #2
|
||||
* ......
|
||||
*
|
||||
* Note that the bpf_func_info record size in .BTF.ext may not
|
||||
* be the same as the one defined in include/uapi/linux/bpf.h.
|
||||
* The loader should ensure that record_size meets minimum
|
||||
* requirement and pass the record as is to the kernel. The
|
||||
* kernel will handle the func_info properly based on its contents.
|
||||
*/
|
||||
struct btf_ext_header {
|
||||
__u16 magic;
|
||||
__u8 version;
|
||||
__u8 flags;
|
||||
__u32 hdr_len;
|
||||
|
||||
/* All offsets are in bytes relative to the end of this header */
|
||||
__u32 func_info_off;
|
||||
__u32 func_info_len;
|
||||
};
|
||||
|
||||
struct btf_sec_func_info {
|
||||
__u32 sec_name_off;
|
||||
__u32 num_func_info;
|
||||
/* Followed by num_func_info number of bpf func_info records */
|
||||
__u8 data[0];
|
||||
};
|
||||
|
||||
typedef int (*btf_print_fn_t)(const char *, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
|
||||
@@ -28,5 +73,19 @@ LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id);
|
||||
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
||||
LIBBPF_API int btf__fd(const struct btf *btf);
|
||||
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
||||
LIBBPF_API int btf_get_from_id(__u32 id, struct btf **btf);
|
||||
|
||||
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
|
||||
void btf_ext__free(struct btf_ext *btf_ext);
|
||||
int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const char *sec_name, void **func_info,
|
||||
__u32 *func_info_rec_size, __u32 *func_info_len);
|
||||
int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
|
||||
const char *sec_name, __u32 insns_cnt, void **func_info,
|
||||
__u32 *func_info_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __LIBBPF_BTF_H */
|
||||
|
||||
637
src/libbpf.c
637
src/libbpf.c
@@ -24,9 +24,11 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/ring_buffer.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
@@ -113,6 +115,11 @@ void libbpf_set_print(libbpf_print_fn_t warn,
|
||||
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
|
||||
#endif
|
||||
|
||||
struct bpf_capabilities {
|
||||
/* v4.14: kernel support for program & map names. */
|
||||
__u32 name:1;
|
||||
};
|
||||
|
||||
/*
|
||||
* bpf_prog should be a better name but it has been used in
|
||||
* linux/filter.h.
|
||||
@@ -123,6 +130,10 @@ struct bpf_program {
|
||||
char *name;
|
||||
int prog_ifindex;
|
||||
char *section_name;
|
||||
/* section_name with / replaced by _; makes recursive pinning
|
||||
* in bpf_object__pin_programs easier
|
||||
*/
|
||||
char *pin_name;
|
||||
struct bpf_insn *insns;
|
||||
size_t insns_cnt, main_prog_cnt;
|
||||
enum bpf_prog_type type;
|
||||
@@ -151,6 +162,12 @@ struct bpf_program {
|
||||
bpf_program_clear_priv_t clear_priv;
|
||||
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
int btf_fd;
|
||||
void *func_info;
|
||||
__u32 func_info_rec_size;
|
||||
__u32 func_info_len;
|
||||
|
||||
struct bpf_capabilities *caps;
|
||||
};
|
||||
|
||||
struct bpf_map {
|
||||
@@ -158,6 +175,7 @@ struct bpf_map {
|
||||
char *name;
|
||||
size_t offset;
|
||||
int map_ifindex;
|
||||
int inner_map_fd;
|
||||
struct bpf_map_def def;
|
||||
__u32 btf_key_type_id;
|
||||
__u32 btf_value_type_id;
|
||||
@@ -207,10 +225,13 @@ struct bpf_object {
|
||||
struct list_head list;
|
||||
|
||||
struct btf *btf;
|
||||
struct btf_ext *btf_ext;
|
||||
|
||||
void *priv;
|
||||
bpf_object_clear_priv_t clear_priv;
|
||||
|
||||
struct bpf_capabilities caps;
|
||||
|
||||
char path[];
|
||||
};
|
||||
#define obj_elf_valid(o) ((o)->efile.elf)
|
||||
@@ -236,6 +257,9 @@ void bpf_program__unload(struct bpf_program *prog)
|
||||
|
||||
prog->instances.nr = -1;
|
||||
zfree(&prog->instances.fds);
|
||||
|
||||
zclose(prog->btf_fd);
|
||||
zfree(&prog->func_info);
|
||||
}
|
||||
|
||||
static void bpf_program__exit(struct bpf_program *prog)
|
||||
@@ -252,6 +276,7 @@ static void bpf_program__exit(struct bpf_program *prog)
|
||||
bpf_program__unload(prog);
|
||||
zfree(&prog->name);
|
||||
zfree(&prog->section_name);
|
||||
zfree(&prog->pin_name);
|
||||
zfree(&prog->insns);
|
||||
zfree(&prog->reloc_desc);
|
||||
|
||||
@@ -260,6 +285,17 @@ static void bpf_program__exit(struct bpf_program *prog)
|
||||
prog->idx = -1;
|
||||
}
|
||||
|
||||
static char *__bpf_program__pin_name(struct bpf_program *prog)
|
||||
{
|
||||
char *name, *p;
|
||||
|
||||
name = p = strdup(prog->section_name);
|
||||
while ((p = strchr(p, '/')))
|
||||
*p = '_';
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_program__init(void *data, size_t size, char *section_name, int idx,
|
||||
struct bpf_program *prog)
|
||||
@@ -278,6 +314,13 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
|
||||
goto errout;
|
||||
}
|
||||
|
||||
prog->pin_name = __bpf_program__pin_name(prog);
|
||||
if (!prog->pin_name) {
|
||||
pr_warning("failed to alloc pin name for prog under section(%d) %s\n",
|
||||
idx, section_name);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
prog->insns = malloc(size);
|
||||
if (!prog->insns) {
|
||||
pr_warning("failed to alloc insns for prog under section %s\n",
|
||||
@@ -290,7 +333,8 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
|
||||
prog->idx = idx;
|
||||
prog->instances.fds = NULL;
|
||||
prog->instances.nr = -1;
|
||||
prog->type = BPF_PROG_TYPE_KPROBE;
|
||||
prog->type = BPF_PROG_TYPE_UNSPEC;
|
||||
prog->btf_fd = -1;
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
@@ -309,6 +353,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
prog.caps = &obj->caps;
|
||||
progs = obj->programs;
|
||||
nr_progs = obj->nr_programs;
|
||||
|
||||
@@ -561,6 +606,14 @@ static int compare_bpf_map(const void *_a, const void *_b)
|
||||
return a->offset - b->offset;
|
||||
}
|
||||
|
||||
static bool bpf_map_type__is_map_in_map(enum bpf_map_type type)
|
||||
{
|
||||
if (type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
|
||||
type == BPF_MAP_TYPE_HASH_OF_MAPS)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__init_maps(struct bpf_object *obj, int flags)
|
||||
{
|
||||
@@ -624,13 +677,15 @@ bpf_object__init_maps(struct bpf_object *obj, int flags)
|
||||
}
|
||||
obj->nr_maps = nr_maps;
|
||||
|
||||
/*
|
||||
* fill all fd with -1 so won't close incorrect
|
||||
* fd (fd=0 is stdin) when failure (zclose won't close
|
||||
* negative fd)).
|
||||
*/
|
||||
for (i = 0; i < nr_maps; i++)
|
||||
for (i = 0; i < nr_maps; i++) {
|
||||
/*
|
||||
* fill all fd with -1 so won't close incorrect
|
||||
* fd (fd=0 is stdin) when failure (zclose won't close
|
||||
* negative fd)).
|
||||
*/
|
||||
obj->maps[i].fd = -1;
|
||||
obj->maps[i].inner_map_fd = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill obj->maps using data in "maps" section.
|
||||
@@ -783,6 +838,15 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
|
||||
BTF_ELF_SEC, PTR_ERR(obj->btf));
|
||||
obj->btf = NULL;
|
||||
}
|
||||
} else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) {
|
||||
obj->btf_ext = btf_ext__new(data->d_buf, data->d_size,
|
||||
__pr_debug);
|
||||
if (IS_ERR(obj->btf_ext)) {
|
||||
pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n",
|
||||
BTF_EXT_ELF_SEC,
|
||||
PTR_ERR(obj->btf_ext));
|
||||
obj->btf_ext = NULL;
|
||||
}
|
||||
} else if (sh.sh_type == SHT_SYMTAB) {
|
||||
if (obj->efile.symbols) {
|
||||
pr_warning("bpf: multiple SYMTAB in %s\n",
|
||||
@@ -1093,6 +1157,52 @@ err_free_new_name:
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__probe_name(struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_load_program_attr attr;
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* make sure basic loading works */
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
|
||||
attr.insns = insns;
|
||||
attr.insns_cnt = ARRAY_SIZE(insns);
|
||||
attr.license = "GPL";
|
||||
|
||||
ret = bpf_load_program_xattr(&attr, NULL, 0);
|
||||
if (ret < 0) {
|
||||
cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
|
||||
pr_warning("Error in %s():%s(%d). Couldn't load basic 'r0 = 0' BPF program.\n",
|
||||
__func__, cp, errno);
|
||||
return -errno;
|
||||
}
|
||||
close(ret);
|
||||
|
||||
/* now try the same program, but with the name */
|
||||
|
||||
attr.name = "test";
|
||||
ret = bpf_load_program_xattr(&attr, NULL, 0);
|
||||
if (ret >= 0) {
|
||||
obj->caps.name = 1;
|
||||
close(ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__probe_caps(struct bpf_object *obj)
|
||||
{
|
||||
return bpf_object__probe_name(obj);
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__create_maps(struct bpf_object *obj)
|
||||
{
|
||||
@@ -1112,7 +1222,8 @@ bpf_object__create_maps(struct bpf_object *obj)
|
||||
continue;
|
||||
}
|
||||
|
||||
create_attr.name = map->name;
|
||||
if (obj->caps.name)
|
||||
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;
|
||||
@@ -1122,6 +1233,9 @@ bpf_object__create_maps(struct bpf_object *obj)
|
||||
create_attr.btf_fd = 0;
|
||||
create_attr.btf_key_type_id = 0;
|
||||
create_attr.btf_value_type_id = 0;
|
||||
if (bpf_map_type__is_map_in_map(def->type) &&
|
||||
map->inner_map_fd >= 0)
|
||||
create_attr.inner_map_fd = map->inner_map_fd;
|
||||
|
||||
if (obj->btf && !bpf_map_find_btf_info(map, obj->btf)) {
|
||||
create_attr.btf_fd = btf__fd(obj->btf);
|
||||
@@ -1166,6 +1280,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
|
||||
struct bpf_insn *insn, *new_insn;
|
||||
struct bpf_program *text;
|
||||
size_t new_cnt;
|
||||
int err;
|
||||
|
||||
if (relo->type != RELO_CALL)
|
||||
return -LIBBPF_ERRNO__RELOC;
|
||||
@@ -1188,6 +1303,20 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
|
||||
pr_warning("oom in prog realloc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (obj->btf && obj->btf_ext) {
|
||||
err = btf_ext__reloc(obj->btf, obj->btf_ext,
|
||||
text->section_name,
|
||||
prog->insns_cnt,
|
||||
&prog->func_info,
|
||||
&prog->func_info_len);
|
||||
if (err) {
|
||||
pr_warning("error in btf_ext__reloc for sec %s\n",
|
||||
text->section_name);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(new_insn + prog->insns_cnt, text->insns,
|
||||
text->insns_cnt * sizeof(*insn));
|
||||
prog->insns = new_insn;
|
||||
@@ -1207,7 +1336,24 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
if (!prog || !prog->reloc_desc)
|
||||
if (!prog)
|
||||
return 0;
|
||||
|
||||
if (obj->btf && obj->btf_ext) {
|
||||
err = btf_ext__reloc_init(obj->btf, obj->btf_ext,
|
||||
prog->section_name,
|
||||
&prog->func_info,
|
||||
&prog->func_info_rec_size,
|
||||
&prog->func_info_len);
|
||||
if (err) {
|
||||
pr_warning("err in btf_ext__reloc_init for sec %s\n",
|
||||
prog->section_name);
|
||||
return err;
|
||||
}
|
||||
prog->btf_fd = btf__fd(obj->btf);
|
||||
}
|
||||
|
||||
if (!prog->reloc_desc)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < prog->nr_reloc; i++) {
|
||||
@@ -1295,9 +1441,9 @@ 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, int prog_ifindex)
|
||||
load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
|
||||
char *license, __u32 kern_version, int *pfd,
|
||||
__u32 func_info_cnt)
|
||||
{
|
||||
struct bpf_load_program_attr load_attr;
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
@@ -1305,14 +1451,19 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,
|
||||
int ret;
|
||||
|
||||
memset(&load_attr, 0, sizeof(struct bpf_load_program_attr));
|
||||
load_attr.prog_type = type;
|
||||
load_attr.expected_attach_type = expected_attach_type;
|
||||
load_attr.name = name;
|
||||
load_attr.prog_type = prog->type;
|
||||
load_attr.expected_attach_type = prog->expected_attach_type;
|
||||
if (prog->caps->name)
|
||||
load_attr.name = prog->name;
|
||||
load_attr.insns = insns;
|
||||
load_attr.insns_cnt = insns_cnt;
|
||||
load_attr.license = license;
|
||||
load_attr.kern_version = kern_version;
|
||||
load_attr.prog_ifindex = prog_ifindex;
|
||||
load_attr.prog_ifindex = prog->prog_ifindex;
|
||||
load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0;
|
||||
load_attr.func_info = prog->func_info;
|
||||
load_attr.func_info_rec_size = prog->func_info_rec_size;
|
||||
load_attr.func_info_cnt = func_info_cnt;
|
||||
|
||||
if (!load_attr.insns || !load_attr.insns_cnt)
|
||||
return -EINVAL;
|
||||
@@ -1370,8 +1521,14 @@ int
|
||||
bpf_program__load(struct bpf_program *prog,
|
||||
char *license, __u32 kern_version)
|
||||
{
|
||||
__u32 func_info_cnt;
|
||||
int err = 0, fd, i;
|
||||
|
||||
if (prog->func_info_len == 0)
|
||||
func_info_cnt = 0;
|
||||
else
|
||||
func_info_cnt = prog->func_info_len / prog->func_info_rec_size;
|
||||
|
||||
if (prog->instances.nr < 0 || !prog->instances.fds) {
|
||||
if (prog->preprocessor) {
|
||||
pr_warning("Internal error: can't load program '%s'\n",
|
||||
@@ -1393,10 +1550,9 @@ 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->expected_attach_type,
|
||||
prog->name, prog->insns, prog->insns_cnt,
|
||||
err = load_program(prog, prog->insns, prog->insns_cnt,
|
||||
license, kern_version, &fd,
|
||||
prog->prog_ifindex);
|
||||
func_info_cnt);
|
||||
if (!err)
|
||||
prog->instances.fds[0] = fd;
|
||||
goto out;
|
||||
@@ -1424,11 +1580,10 @@ bpf_program__load(struct bpf_program *prog,
|
||||
continue;
|
||||
}
|
||||
|
||||
err = load_program(prog->type, prog->expected_attach_type,
|
||||
prog->name, result.new_insn_ptr,
|
||||
err = load_program(prog, result.new_insn_ptr,
|
||||
result.new_insn_cnt,
|
||||
license, kern_version, &fd,
|
||||
prog->prog_ifindex);
|
||||
func_info_cnt);
|
||||
|
||||
if (err) {
|
||||
pr_warning("Loading the %dth instance of program '%s' failed\n",
|
||||
@@ -1494,12 +1649,12 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type)
|
||||
case BPF_PROG_TYPE_LIRC_MODE2:
|
||||
case BPF_PROG_TYPE_SK_REUSEPORT:
|
||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||
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:
|
||||
case BPF_PROG_TYPE_PERF_EVENT:
|
||||
return false;
|
||||
case BPF_PROG_TYPE_KPROBE:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@@ -1626,6 +1781,7 @@ int bpf_object__load(struct bpf_object *obj)
|
||||
|
||||
obj->loaded = true;
|
||||
|
||||
CHECK_ERR(bpf_object__probe_caps(obj), err, out);
|
||||
CHECK_ERR(bpf_object__create_maps(obj), err, out);
|
||||
CHECK_ERR(bpf_object__relocate(obj), err, out);
|
||||
CHECK_ERR(bpf_object__load_progs(obj), err, out);
|
||||
@@ -1698,6 +1854,34 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_program__unpin_instance(struct bpf_program *prog, const char *path,
|
||||
int instance)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (prog == NULL) {
|
||||
pr_warning("invalid program pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (instance < 0 || instance >= prog->instances.nr) {
|
||||
pr_warning("invalid prog instance %d of prog %s (max %d)\n",
|
||||
instance, prog->section_name, prog->instances.nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = unlink(path);
|
||||
if (err != 0)
|
||||
return -errno;
|
||||
pr_debug("unpinned program '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int make_dir(const char *path)
|
||||
{
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
@@ -1732,10 +1916,78 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prog->instances.nr == 1) {
|
||||
/* don't create subdirs when pinning single instance */
|
||||
return bpf_program__pin_instance(prog, path, 0);
|
||||
}
|
||||
|
||||
err = make_dir(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < prog->instances.nr; i++) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%d", path, i);
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin;
|
||||
}
|
||||
|
||||
err = bpf_program__pin_instance(prog, buf, i);
|
||||
if (err)
|
||||
goto err_unpin;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin:
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%d", path, i);
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_program__unpin_instance(prog, buf, i);
|
||||
}
|
||||
|
||||
rmdir(path);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_program__unpin(struct bpf_program *prog, const char *path)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (prog == NULL) {
|
||||
pr_warning("invalid program pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prog->instances.nr <= 0) {
|
||||
pr_warning("no instances of prog %s to pin\n",
|
||||
prog->section_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prog->instances.nr == 1) {
|
||||
/* don't create subdirs when pinning single instance */
|
||||
return bpf_program__unpin_instance(prog, path, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < prog->instances.nr; i++) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
@@ -1746,11 +1998,15 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
|
||||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_program__pin_instance(prog, buf, i);
|
||||
err = bpf_program__unpin_instance(prog, buf, i);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rmdir(path);
|
||||
if (err)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1775,12 +2031,33 @@ int bpf_map__pin(struct bpf_map *map, const char *path)
|
||||
}
|
||||
|
||||
pr_debug("pinned map '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
int bpf_map__unpin(struct bpf_map *map, const char *path)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (map == NULL) {
|
||||
pr_warning("invalid map pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = unlink(path);
|
||||
if (err != 0)
|
||||
return -errno;
|
||||
pr_debug("unpinned map '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin_maps(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
|
||||
@@ -1796,6 +2073,53 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bpf_map__for_each(map, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
bpf_map__name(map));
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin_maps;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin_maps;
|
||||
}
|
||||
|
||||
err = bpf_map__pin(map, buf);
|
||||
if (err)
|
||||
goto err_unpin_maps;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin_maps:
|
||||
while ((map = bpf_map__prev(map, obj))) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
bpf_map__name(map));
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_map__unpin(map, buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_object__unpin_maps(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
bpf_map__for_each(map, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
@@ -1807,23 +2131,90 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_map__pin(map, buf);
|
||||
err = bpf_map__unpin(map, buf);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin_programs(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
if (!obj->loaded) {
|
||||
pr_warning("object not yet loaded; load it first\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = make_dir(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->section_name);
|
||||
prog->pin_name);
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin_programs;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin_programs;
|
||||
}
|
||||
|
||||
err = bpf_program__pin(prog, buf);
|
||||
if (err)
|
||||
goto err_unpin_programs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin_programs:
|
||||
while ((prog = bpf_program__prev(prog, obj))) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->pin_name);
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_program__unpin(prog, buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_object__unpin_programs(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->pin_name);
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_program__pin(prog, buf);
|
||||
err = bpf_program__unpin(prog, buf);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -1831,6 +2222,23 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bpf_object__pin_maps(obj, path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_object__pin_programs(obj, path);
|
||||
if (err) {
|
||||
bpf_object__unpin_maps(obj, path);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bpf_object__close(struct bpf_object *obj)
|
||||
{
|
||||
size_t i;
|
||||
@@ -1844,6 +2252,7 @@ void bpf_object__close(struct bpf_object *obj)
|
||||
bpf_object__elf_finish(obj);
|
||||
bpf_object__unload(obj);
|
||||
btf__free(obj->btf);
|
||||
btf_ext__free(obj->btf_ext);
|
||||
|
||||
for (i = 0; i < obj->nr_maps; i++) {
|
||||
zfree(&obj->maps[i].name);
|
||||
@@ -1917,23 +2326,26 @@ void *bpf_object__priv(struct bpf_object *obj)
|
||||
}
|
||||
|
||||
static struct bpf_program *
|
||||
__bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
|
||||
__bpf_program__iter(struct bpf_program *p, struct bpf_object *obj, bool forward)
|
||||
{
|
||||
size_t idx;
|
||||
size_t nr_programs = obj->nr_programs;
|
||||
ssize_t idx;
|
||||
|
||||
if (!obj->programs)
|
||||
if (!nr_programs)
|
||||
return NULL;
|
||||
/* First handler */
|
||||
if (prev == NULL)
|
||||
return &obj->programs[0];
|
||||
|
||||
if (prev->obj != obj) {
|
||||
if (!p)
|
||||
/* Iter from the beginning */
|
||||
return forward ? &obj->programs[0] :
|
||||
&obj->programs[nr_programs - 1];
|
||||
|
||||
if (p->obj != obj) {
|
||||
pr_warning("error: program handler doesn't match object\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idx = (prev - obj->programs) + 1;
|
||||
if (idx >= obj->nr_programs)
|
||||
idx = (p - obj->programs) + (forward ? 1 : -1);
|
||||
if (idx >= obj->nr_programs || idx < 0)
|
||||
return NULL;
|
||||
return &obj->programs[idx];
|
||||
}
|
||||
@@ -1944,7 +2356,19 @@ bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
|
||||
struct bpf_program *prog = prev;
|
||||
|
||||
do {
|
||||
prog = __bpf_program__next(prog, obj);
|
||||
prog = __bpf_program__iter(prog, obj, true);
|
||||
} while (prog && bpf_program__is_function_storage(prog, obj));
|
||||
|
||||
return prog;
|
||||
}
|
||||
|
||||
struct bpf_program *
|
||||
bpf_program__prev(struct bpf_program *next, struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_program *prog = next;
|
||||
|
||||
do {
|
||||
prog = __bpf_program__iter(prog, obj, false);
|
||||
} while (prog && bpf_program__is_function_storage(prog, obj));
|
||||
|
||||
return prog;
|
||||
@@ -2083,19 +2507,19 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
prog->expected_attach_type = type;
|
||||
}
|
||||
|
||||
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, atype) \
|
||||
{ string, sizeof(string) - 1, ptype, eatype, atype }
|
||||
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, is_attachable, atype) \
|
||||
{ string, sizeof(string) - 1, ptype, eatype, is_attachable, atype }
|
||||
|
||||
/* Programs that can NOT be attached. */
|
||||
#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, -EINVAL)
|
||||
#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, 0, 0)
|
||||
|
||||
/* Programs that can be attached. */
|
||||
#define BPF_APROG_SEC(string, ptype, atype) \
|
||||
BPF_PROG_SEC_IMPL(string, ptype, 0, atype)
|
||||
BPF_PROG_SEC_IMPL(string, ptype, 0, 1, atype)
|
||||
|
||||
/* Programs that must specify expected attach type at load time. */
|
||||
#define BPF_EAPROG_SEC(string, ptype, eatype) \
|
||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, eatype)
|
||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, 1, eatype)
|
||||
|
||||
/* Programs that can be attached but attach type can't be identified by section
|
||||
* name. Kept for backward compatibility.
|
||||
@@ -2107,6 +2531,7 @@ static const struct {
|
||||
size_t len;
|
||||
enum bpf_prog_type prog_type;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
int is_attachable;
|
||||
enum bpf_attach_type attach_type;
|
||||
} section_names[] = {
|
||||
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
|
||||
@@ -2197,7 +2622,7 @@ int libbpf_attach_type_by_name(const char *name,
|
||||
for (i = 0; i < ARRAY_SIZE(section_names); i++) {
|
||||
if (strncmp(name, section_names[i].sec, section_names[i].len))
|
||||
continue;
|
||||
if (section_names[i].attach_type == -EINVAL)
|
||||
if (!section_names[i].is_attachable)
|
||||
return -EINVAL;
|
||||
*attach_type = section_names[i].attach_type;
|
||||
return 0;
|
||||
@@ -2270,10 +2695,24 @@ void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
|
||||
map->map_ifindex = ifindex;
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
||||
int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd)
|
||||
{
|
||||
size_t idx;
|
||||
if (!bpf_map_type__is_map_in_map(map->def.type)) {
|
||||
pr_warning("error: unsupported map type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (map->inner_map_fd != -1) {
|
||||
pr_warning("error: inner_map_fd already specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
map->inner_map_fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bpf_map *
|
||||
__bpf_map__iter(struct bpf_map *m, struct bpf_object *obj, int i)
|
||||
{
|
||||
ssize_t idx;
|
||||
struct bpf_map *s, *e;
|
||||
|
||||
if (!obj || !obj->maps)
|
||||
@@ -2282,21 +2721,39 @@ bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
||||
s = obj->maps;
|
||||
e = obj->maps + obj->nr_maps;
|
||||
|
||||
if (prev == NULL)
|
||||
return s;
|
||||
|
||||
if ((prev < s) || (prev >= e)) {
|
||||
if ((m < s) || (m >= e)) {
|
||||
pr_warning("error in %s: map handler doesn't belong to object\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idx = (prev - obj->maps) + 1;
|
||||
if (idx >= obj->nr_maps)
|
||||
idx = (m - obj->maps) + i;
|
||||
if (idx >= obj->nr_maps || idx < 0)
|
||||
return NULL;
|
||||
return &obj->maps[idx];
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
||||
{
|
||||
if (prev == NULL)
|
||||
return obj->maps;
|
||||
|
||||
return __bpf_map__iter(prev, obj, 1);
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__prev(struct bpf_map *next, struct bpf_object *obj)
|
||||
{
|
||||
if (next == NULL) {
|
||||
if (!obj->nr_maps)
|
||||
return NULL;
|
||||
return obj->maps + obj->nr_maps - 1;
|
||||
}
|
||||
|
||||
return __bpf_map__iter(next, obj, -1);
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_object__find_map_by_name(struct bpf_object *obj, const char *name)
|
||||
{
|
||||
@@ -2414,61 +2871,49 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
||||
}
|
||||
|
||||
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)
|
||||
bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
|
||||
void **copy_mem, size_t *copy_size,
|
||||
bpf_perf_event_print_t fn, void *private_data)
|
||||
{
|
||||
volatile struct perf_event_mmap_page *header = mem;
|
||||
struct perf_event_mmap_page *header = mmap_mem;
|
||||
__u64 data_head = ring_buffer_read_head(header);
|
||||
__u64 data_tail = header->data_tail;
|
||||
__u64 data_head = header->data_head;
|
||||
int ret = LIBBPF_PERF_EVENT_ERROR;
|
||||
void *base, *begin, *end;
|
||||
void *base = ((__u8 *)header) + page_size;
|
||||
int ret = LIBBPF_PERF_EVENT_CONT;
|
||||
struct perf_event_header *ehdr;
|
||||
size_t ehdr_size;
|
||||
|
||||
asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */
|
||||
if (data_head == data_tail)
|
||||
return LIBBPF_PERF_EVENT_CONT;
|
||||
while (data_head != data_tail) {
|
||||
ehdr = base + (data_tail & (mmap_size - 1));
|
||||
ehdr_size = ehdr->size;
|
||||
|
||||
base = ((char *)header) + page_size;
|
||||
if (((void *)ehdr) + ehdr_size > base + mmap_size) {
|
||||
void *copy_start = ehdr;
|
||||
size_t len_first = base + mmap_size - copy_start;
|
||||
size_t len_secnd = ehdr_size - len_first;
|
||||
|
||||
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) {
|
||||
if (*copy_size < ehdr_size) {
|
||||
free(*copy_mem);
|
||||
*copy_mem = malloc(ehdr_size);
|
||||
if (!*copy_mem) {
|
||||
*copy_size = 0;
|
||||
ret = LIBBPF_PERF_EVENT_ERROR;
|
||||
break;
|
||||
}
|
||||
*buf_len = ehdr->size;
|
||||
*copy_size = 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;
|
||||
memcpy(*copy_mem, copy_start, len_first);
|
||||
memcpy(*copy_mem + len_first, base, len_secnd);
|
||||
ehdr = *copy_mem;
|
||||
}
|
||||
|
||||
ret = fn(ehdr, priv);
|
||||
ret = fn(ehdr, private_data);
|
||||
data_tail += ehdr_size;
|
||||
if (ret != LIBBPF_PERF_EVENT_CONT)
|
||||
break;
|
||||
|
||||
data_tail += ehdr->size;
|
||||
}
|
||||
|
||||
__sync_synchronize(); /* smp_mb() */
|
||||
header->data_tail = data_tail;
|
||||
|
||||
ring_buffer_write_tail(header, data_tail);
|
||||
return ret;
|
||||
}
|
||||
|
||||
44
src/libbpf.h
44
src/libbpf.h
@@ -16,6 +16,10 @@
|
||||
#include <sys/types.h> // for size_t
|
||||
#include <linux/bpf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef LIBBPF_API
|
||||
#define LIBBPF_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
@@ -71,6 +75,13 @@ struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr,
|
||||
LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf,
|
||||
size_t obj_buf_sz,
|
||||
const char *name);
|
||||
LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path);
|
||||
LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,
|
||||
const char *path);
|
||||
LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
|
||||
LIBBPF_API void bpf_object__close(struct bpf_object *object);
|
||||
|
||||
@@ -112,6 +123,9 @@ LIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog,
|
||||
(pos) != NULL; \
|
||||
(pos) = bpf_program__next((pos), (obj)))
|
||||
|
||||
LIBBPF_API struct bpf_program *bpf_program__prev(struct bpf_program *prog,
|
||||
struct bpf_object *obj);
|
||||
|
||||
typedef void (*bpf_program_clear_priv_t)(struct bpf_program *,
|
||||
void *);
|
||||
|
||||
@@ -131,7 +145,11 @@ LIBBPF_API int bpf_program__fd(struct bpf_program *prog);
|
||||
LIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog,
|
||||
const char *path,
|
||||
int instance);
|
||||
LIBBPF_API int bpf_program__unpin_instance(struct bpf_program *prog,
|
||||
const char *path,
|
||||
int instance);
|
||||
LIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path);
|
||||
LIBBPF_API int bpf_program__unpin(struct bpf_program *prog, const char *path);
|
||||
LIBBPF_API void bpf_program__unload(struct bpf_program *prog);
|
||||
|
||||
struct bpf_insn;
|
||||
@@ -260,6 +278,9 @@ bpf_map__next(struct bpf_map *map, struct bpf_object *obj);
|
||||
(pos) != NULL; \
|
||||
(pos) = bpf_map__next((pos), (obj)))
|
||||
|
||||
LIBBPF_API struct bpf_map *
|
||||
bpf_map__prev(struct bpf_map *map, struct bpf_object *obj);
|
||||
|
||||
LIBBPF_API int bpf_map__fd(struct bpf_map *map);
|
||||
LIBBPF_API const struct bpf_map_def *bpf_map__def(struct bpf_map *map);
|
||||
LIBBPF_API const char *bpf_map__name(struct bpf_map *map);
|
||||
@@ -274,6 +295,9 @@ LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd);
|
||||
LIBBPF_API bool bpf_map__is_offload_neutral(struct bpf_map *map);
|
||||
LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
|
||||
LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
|
||||
LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
|
||||
|
||||
LIBBPF_API int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd);
|
||||
|
||||
LIBBPF_API long libbpf_get_error(const void *ptr);
|
||||
|
||||
@@ -297,13 +321,14 @@ enum bpf_perf_event_ret {
|
||||
LIBBPF_PERF_EVENT_CONT = -2,
|
||||
};
|
||||
|
||||
typedef enum bpf_perf_event_ret (*bpf_perf_event_print_t)(void *event,
|
||||
void *priv);
|
||||
LIBBPF_API 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);
|
||||
struct perf_event_header;
|
||||
typedef enum bpf_perf_event_ret
|
||||
(*bpf_perf_event_print_t)(struct perf_event_header *hdr,
|
||||
void *private_data);
|
||||
LIBBPF_API enum bpf_perf_event_ret
|
||||
bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
|
||||
void **copy_mem, size_t *copy_size,
|
||||
bpf_perf_event_print_t fn, void *private_data);
|
||||
|
||||
struct nlattr;
|
||||
typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
|
||||
@@ -316,4 +341,9 @@ int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
|
||||
libbpf_dump_nlmsg_t dump_qdisc_nlmsg, void *cookie);
|
||||
int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
|
||||
libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* __LIBBPF_LIBBPF_H */
|
||||
|
||||
Reference in New Issue
Block a user