Commit 7b16509b authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next

Alexei Starovoitov says:

====================
pull-request: bpf-next 2021-05-19

The following pull-request contains BPF updates for your *net-next* tree.

We've added 43 non-merge commits during the last 11 day(s) which contain
a total of 74 files changed, 3717 insertions(+), 578 deletions(-).

The main changes are:

1) syscall program type, fd array, and light skeleton, from Alexei.

2) Stop emitting static variables in skeleton, from Andrii.

3) Low level tc-bpf api, from Kumar.

4) Reduce verifier kmalloc/kfree churn, from Lorenz.
====================
parents 9287aa2b 3a2daa72
...@@ -178,9 +178,6 @@ static bool is_addsub_imm(u32 imm) ...@@ -178,9 +178,6 @@ static bool is_addsub_imm(u32 imm)
return !(imm & ~0xfff) || !(imm & ~0xfff000); return !(imm & ~0xfff) || !(imm & ~0xfff000);
} }
/* Stack must be multiples of 16B */
#define STACK_ALIGN(sz) (((sz) + 15) & ~15)
/* Tail call offset to jump into */ /* Tail call offset to jump into */
#if IS_ENABLED(CONFIG_ARM64_BTI_KERNEL) #if IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)
#define PROLOGUE_OFFSET 8 #define PROLOGUE_OFFSET 8
...@@ -255,7 +252,8 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf) ...@@ -255,7 +252,8 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
emit(A64_BTI_J, ctx); emit(A64_BTI_J, ctx);
} }
ctx->stack_size = STACK_ALIGN(prog->aux->stack_depth); /* Stack must be multiples of 16B */
ctx->stack_size = round_up(prog->aux->stack_depth, 16);
/* Set up function call stack */ /* Set up function call stack */
emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx); emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
...@@ -487,17 +485,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, ...@@ -487,17 +485,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
break; break;
case BPF_ALU | BPF_DIV | BPF_X: case BPF_ALU | BPF_DIV | BPF_X:
case BPF_ALU64 | BPF_DIV | BPF_X: case BPF_ALU64 | BPF_DIV | BPF_X:
emit(A64_UDIV(is64, dst, dst, src), ctx);
break;
case BPF_ALU | BPF_MOD | BPF_X: case BPF_ALU | BPF_MOD | BPF_X:
case BPF_ALU64 | BPF_MOD | BPF_X: case BPF_ALU64 | BPF_MOD | BPF_X:
switch (BPF_OP(code)) { emit(A64_UDIV(is64, tmp, dst, src), ctx);
case BPF_DIV: emit(A64_MSUB(is64, dst, dst, tmp, src), ctx);
emit(A64_UDIV(is64, dst, dst, src), ctx);
break;
case BPF_MOD:
emit(A64_UDIV(is64, tmp, dst, src), ctx);
emit(A64_MSUB(is64, dst, dst, tmp, src), ctx);
break;
}
break; break;
case BPF_ALU | BPF_LSH | BPF_X: case BPF_ALU | BPF_LSH | BPF_X:
case BPF_ALU64 | BPF_LSH | BPF_X: case BPF_ALU64 | BPF_LSH | BPF_X:
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/sched/mm.h> #include <linux/sched/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/percpu-refcount.h> #include <linux/percpu-refcount.h>
#include <linux/bpfptr.h>
struct bpf_verifier_env; struct bpf_verifier_env;
struct bpf_verifier_log; struct bpf_verifier_log;
...@@ -1428,7 +1429,7 @@ struct bpf_iter__bpf_map_elem { ...@@ -1428,7 +1429,7 @@ struct bpf_iter__bpf_map_elem {
int bpf_iter_reg_target(const struct bpf_iter_reg *reg_info); int bpf_iter_reg_target(const struct bpf_iter_reg *reg_info);
void bpf_iter_unreg_target(const struct bpf_iter_reg *reg_info); void bpf_iter_unreg_target(const struct bpf_iter_reg *reg_info);
bool bpf_iter_prog_supported(struct bpf_prog *prog); bool bpf_iter_prog_supported(struct bpf_prog *prog);
int bpf_iter_link_attach(const union bpf_attr *attr, struct bpf_prog *prog); int bpf_iter_link_attach(const union bpf_attr *attr, bpfptr_t uattr, struct bpf_prog *prog);
int bpf_iter_new_fd(struct bpf_link *link); int bpf_iter_new_fd(struct bpf_link *link);
bool bpf_link_is_iter(struct bpf_link *link); bool bpf_link_is_iter(struct bpf_link *link);
struct bpf_prog *bpf_iter_get_info(struct bpf_iter_meta *meta, bool in_stop); struct bpf_prog *bpf_iter_get_info(struct bpf_iter_meta *meta, bool in_stop);
...@@ -1459,7 +1460,7 @@ int bpf_fd_htab_map_update_elem(struct bpf_map *map, struct file *map_file, ...@@ -1459,7 +1460,7 @@ int bpf_fd_htab_map_update_elem(struct bpf_map *map, struct file *map_file,
int bpf_fd_htab_map_lookup_elem(struct bpf_map *map, void *key, u32 *value); int bpf_fd_htab_map_lookup_elem(struct bpf_map *map, void *key, u32 *value);
int bpf_get_file_flag(int flags); int bpf_get_file_flag(int flags);
int bpf_check_uarg_tail_zero(void __user *uaddr, size_t expected_size, int bpf_check_uarg_tail_zero(bpfptr_t uaddr, size_t expected_size,
size_t actual_size); size_t actual_size);
/* memcpy that is used with 8-byte aligned pointers, power-of-8 size and /* memcpy that is used with 8-byte aligned pointers, power-of-8 size and
...@@ -1479,8 +1480,7 @@ static inline void bpf_long_memcpy(void *dst, const void *src, u32 size) ...@@ -1479,8 +1480,7 @@ static inline void bpf_long_memcpy(void *dst, const void *src, u32 size)
} }
/* verify correctness of eBPF program */ /* verify correctness of eBPF program */
int bpf_check(struct bpf_prog **fp, union bpf_attr *attr, int bpf_check(struct bpf_prog **fp, union bpf_attr *attr, bpfptr_t uattr);
union bpf_attr __user *uattr);
#ifndef CONFIG_BPF_JIT_ALWAYS_ON #ifndef CONFIG_BPF_JIT_ALWAYS_ON
void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth); void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth);
...@@ -1826,6 +1826,9 @@ static inline bool bpf_map_is_dev_bound(struct bpf_map *map) ...@@ -1826,6 +1826,9 @@ static inline bool bpf_map_is_dev_bound(struct bpf_map *map)
struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr); struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr);
void bpf_map_offload_map_free(struct bpf_map *map); void bpf_map_offload_map_free(struct bpf_map *map);
int bpf_prog_test_run_syscall(struct bpf_prog *prog,
const union bpf_attr *kattr,
union bpf_attr __user *uattr);
#else #else
static inline int bpf_prog_offload_init(struct bpf_prog *prog, static inline int bpf_prog_offload_init(struct bpf_prog *prog,
union bpf_attr *attr) union bpf_attr *attr)
...@@ -1851,6 +1854,13 @@ static inline struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr) ...@@ -1851,6 +1854,13 @@ static inline struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr)
static inline void bpf_map_offload_map_free(struct bpf_map *map) static inline void bpf_map_offload_map_free(struct bpf_map *map)
{ {
} }
static inline int bpf_prog_test_run_syscall(struct bpf_prog *prog,
const union bpf_attr *kattr,
union bpf_attr __user *uattr)
{
return -ENOTSUPP;
}
#endif /* CONFIG_NET && CONFIG_BPF_SYSCALL */ #endif /* CONFIG_NET && CONFIG_BPF_SYSCALL */
#if defined(CONFIG_INET) && defined(CONFIG_BPF_SYSCALL) #if defined(CONFIG_INET) && defined(CONFIG_BPF_SYSCALL)
...@@ -1964,6 +1974,7 @@ extern const struct bpf_func_proto bpf_get_socket_ptr_cookie_proto; ...@@ -1964,6 +1974,7 @@ extern const struct bpf_func_proto bpf_get_socket_ptr_cookie_proto;
extern const struct bpf_func_proto bpf_task_storage_get_proto; extern const struct bpf_func_proto bpf_task_storage_get_proto;
extern const struct bpf_func_proto bpf_task_storage_delete_proto; extern const struct bpf_func_proto bpf_task_storage_delete_proto;
extern const struct bpf_func_proto bpf_for_each_map_elem_proto; extern const struct bpf_func_proto bpf_for_each_map_elem_proto;
extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto;
const struct bpf_func_proto *bpf_tracing_func_proto( const struct bpf_func_proto *bpf_tracing_func_proto(
enum bpf_func_id func_id, const struct bpf_prog *prog); enum bpf_func_id func_id, const struct bpf_prog *prog);
......
...@@ -77,6 +77,8 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm, ...@@ -77,6 +77,8 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm,
void *, void *) void *, void *)
#endif /* CONFIG_BPF_LSM */ #endif /* CONFIG_BPF_LSM */
#endif #endif
BPF_PROG_TYPE(BPF_PROG_TYPE_SYSCALL, bpf_syscall,
void *, void *)
BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops) BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops)
BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_ARRAY, percpu_array_map_ops) BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_ARRAY, percpu_array_map_ops)
......
...@@ -215,6 +215,13 @@ struct bpf_idx_pair { ...@@ -215,6 +215,13 @@ struct bpf_idx_pair {
u32 idx; u32 idx;
}; };
struct bpf_id_pair {
u32 old;
u32 cur;
};
/* Maximum number of register states that can exist at once */
#define BPF_ID_MAP_SIZE (MAX_BPF_REG + MAX_BPF_STACK / BPF_REG_SIZE)
#define MAX_CALL_FRAMES 8 #define MAX_CALL_FRAMES 8
struct bpf_verifier_state { struct bpf_verifier_state {
/* call stack tracking */ /* call stack tracking */
...@@ -418,6 +425,7 @@ struct bpf_verifier_env { ...@@ -418,6 +425,7 @@ struct bpf_verifier_env {
const struct bpf_line_info *prev_linfo; const struct bpf_line_info *prev_linfo;
struct bpf_verifier_log log; struct bpf_verifier_log log;
struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1];
struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE];
struct { struct {
int *insn_state; int *insn_state;
int *insn_stack; int *insn_stack;
...@@ -442,6 +450,7 @@ struct bpf_verifier_env { ...@@ -442,6 +450,7 @@ struct bpf_verifier_env {
u32 peak_states; u32 peak_states;
/* longest register parentage chain walked for liveness marking */ /* longest register parentage chain walked for liveness marking */
u32 longest_mark_read_walk; u32 longest_mark_read_walk;
bpfptr_t fd_array;
}; };
__printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log, __printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log,
......
/* SPDX-License-Identifier: GPL-2.0-only */
/* A pointer that can point to either kernel or userspace memory. */
#ifndef _LINUX_BPFPTR_H
#define _LINUX_BPFPTR_H
#include <linux/sockptr.h>
typedef sockptr_t bpfptr_t;
static inline bool bpfptr_is_kernel(bpfptr_t bpfptr)
{
return bpfptr.is_kernel;
}
static inline bpfptr_t KERNEL_BPFPTR(void *p)
{
return (bpfptr_t) { .kernel = p, .is_kernel = true };
}
static inline bpfptr_t USER_BPFPTR(void __user *p)
{
return (bpfptr_t) { .user = p };
}
static inline bpfptr_t make_bpfptr(u64 addr, bool is_kernel)
{
if (is_kernel)
return KERNEL_BPFPTR((void*) (uintptr_t) addr);
else
return USER_BPFPTR(u64_to_user_ptr(addr));
}
static inline bool bpfptr_is_null(bpfptr_t bpfptr)
{
if (bpfptr_is_kernel(bpfptr))
return !bpfptr.kernel;
return !bpfptr.user;
}
static inline void bpfptr_add(bpfptr_t *bpfptr, size_t val)
{
if (bpfptr_is_kernel(*bpfptr))
bpfptr->kernel += val;
else
bpfptr->user += val;
}
static inline int copy_from_bpfptr_offset(void *dst, bpfptr_t src,
size_t offset, size_t size)
{
return copy_from_sockptr_offset(dst, (sockptr_t) src, offset, size);
}
static inline int copy_from_bpfptr(void *dst, bpfptr_t src, size_t size)
{
return copy_from_bpfptr_offset(dst, src, 0, size);
}
static inline int copy_to_bpfptr_offset(bpfptr_t dst, size_t offset,
const void *src, size_t size)
{
return copy_to_sockptr_offset((sockptr_t) dst, offset, src, size);
}
static inline void *memdup_bpfptr(bpfptr_t src, size_t len)
{
return memdup_sockptr((sockptr_t) src, len);
}
static inline long strncpy_from_bpfptr(char *dst, bpfptr_t src, size_t count)
{
return strncpy_from_sockptr(dst, (sockptr_t) src, count);
}
#endif /* _LINUX_BPFPTR_H */
...@@ -21,7 +21,7 @@ extern const struct file_operations btf_fops; ...@@ -21,7 +21,7 @@ extern const struct file_operations btf_fops;
void btf_get(struct btf *btf); void btf_get(struct btf *btf);
void btf_put(struct btf *btf); void btf_put(struct btf *btf);
int btf_new_fd(const union bpf_attr *attr); int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr);
struct btf *btf_get_by_fd(int fd); struct btf *btf_get_by_fd(int fd);
int btf_get_info_by_fd(const struct btf *btf, int btf_get_info_by_fd(const struct btf *btf,
const union bpf_attr *attr, const union bpf_attr *attr,
......
...@@ -126,8 +126,7 @@ int sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from, ...@@ -126,8 +126,7 @@ int sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from,
struct sk_msg *msg, u32 bytes); struct sk_msg *msg, u32 bytes);
int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from,
struct sk_msg *msg, u32 bytes); struct sk_msg *msg, u32 bytes);
int sk_msg_wait_data(struct sock *sk, struct sk_psock *psock, int flags, int sk_msg_wait_data(struct sock *sk, struct sk_psock *psock, long timeo);
long timeo, int *err);
int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg, int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
int len, int flags); int len, int flags);
......
...@@ -837,6 +837,7 @@ enum bpf_cmd { ...@@ -837,6 +837,7 @@ enum bpf_cmd {
BPF_PROG_ATTACH, BPF_PROG_ATTACH,
BPF_PROG_DETACH, BPF_PROG_DETACH,
BPF_PROG_TEST_RUN, BPF_PROG_TEST_RUN,
BPF_PROG_RUN = BPF_PROG_TEST_RUN,
BPF_PROG_GET_NEXT_ID, BPF_PROG_GET_NEXT_ID,
BPF_MAP_GET_NEXT_ID, BPF_MAP_GET_NEXT_ID,
BPF_PROG_GET_FD_BY_ID, BPF_PROG_GET_FD_BY_ID,
...@@ -937,6 +938,7 @@ enum bpf_prog_type { ...@@ -937,6 +938,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_EXT, BPF_PROG_TYPE_EXT,
BPF_PROG_TYPE_LSM, BPF_PROG_TYPE_LSM,
BPF_PROG_TYPE_SK_LOOKUP, BPF_PROG_TYPE_SK_LOOKUP,
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
}; };
enum bpf_attach_type { enum bpf_attach_type {
...@@ -1097,8 +1099,8 @@ enum bpf_link_type { ...@@ -1097,8 +1099,8 @@ enum bpf_link_type {
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have /* When BPF ldimm64's insn[0].src_reg != 0 then this can have
* the following extensions: * the following extensions:
* *
* insn[0].src_reg: BPF_PSEUDO_MAP_FD * insn[0].src_reg: BPF_PSEUDO_MAP_[FD|IDX]
* insn[0].imm: map fd * insn[0].imm: map fd or fd_idx
* insn[1].imm: 0 * insn[1].imm: 0
* insn[0].off: 0 * insn[0].off: 0
* insn[1].off: 0 * insn[1].off: 0
...@@ -1106,15 +1108,19 @@ enum bpf_link_type { ...@@ -1106,15 +1108,19 @@ enum bpf_link_type {
* verifier type: CONST_PTR_TO_MAP * verifier type: CONST_PTR_TO_MAP
*/ */
#define BPF_PSEUDO_MAP_FD 1 #define BPF_PSEUDO_MAP_FD 1
/* insn[0].src_reg: BPF_PSEUDO_MAP_VALUE #define BPF_PSEUDO_MAP_IDX 5
* insn[0].imm: map fd
/* insn[0].src_reg: BPF_PSEUDO_MAP_[IDX_]VALUE
* insn[0].imm: map fd or fd_idx
* insn[1].imm: offset into value * insn[1].imm: offset into value
* insn[0].off: 0 * insn[0].off: 0
* insn[1].off: 0 * insn[1].off: 0
* ldimm64 rewrite: address of map[0]+offset * ldimm64 rewrite: address of map[0]+offset
* verifier type: PTR_TO_MAP_VALUE * verifier type: PTR_TO_MAP_VALUE
*/ */
#define BPF_PSEUDO_MAP_VALUE 2 #define BPF_PSEUDO_MAP_VALUE 2
#define BPF_PSEUDO_MAP_IDX_VALUE 6
/* insn[0].src_reg: BPF_PSEUDO_BTF_ID /* insn[0].src_reg: BPF_PSEUDO_BTF_ID
* insn[0].imm: kernel btd id of VAR * insn[0].imm: kernel btd id of VAR
* insn[1].imm: 0 * insn[1].imm: 0
...@@ -1314,6 +1320,8 @@ union bpf_attr { ...@@ -1314,6 +1320,8 @@ union bpf_attr {
/* or valid module BTF object fd or 0 to attach to vmlinux */ /* or valid module BTF object fd or 0 to attach to vmlinux */
__u32 attach_btf_obj_fd; __u32 attach_btf_obj_fd;
}; };
__u32 :32; /* pad */
__aligned_u64 fd_array; /* array of FDs */
}; };
struct { /* anonymous struct used by BPF_OBJ_* commands */ struct { /* anonymous struct used by BPF_OBJ_* commands */
...@@ -4735,6 +4743,24 @@ union bpf_attr { ...@@ -4735,6 +4743,24 @@ union bpf_attr {
* be zero-terminated except when **str_size** is 0. * be zero-terminated except when **str_size** is 0.
* *
* Or **-EBUSY** if the per-CPU memory copy buffer is busy. * Or **-EBUSY** if the per-CPU memory copy buffer is busy.
*
* long bpf_sys_bpf(u32 cmd, void *attr, u32 attr_size)
* Description
* Execute bpf syscall with given arguments.
* Return
* A syscall result.
*
* long bpf_btf_find_by_name_kind(char *name, int name_sz, u32 kind, int flags)
* Description
* Find BTF type with given name and kind in vmlinux BTF or in module's BTFs.
* Return
* Returns btf_id and btf_obj_fd in lower and upper 32 bits.
*
* long bpf_sys_close(u32 fd)
* Description
* Execute close syscall for given FD.
* Return
* A syscall result.
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -4903,6 +4929,9 @@ union bpf_attr { ...@@ -4903,6 +4929,9 @@ union bpf_attr {
FN(check_mtu), \ FN(check_mtu), \
FN(for_each_map_elem), \ FN(for_each_map_elem), \
FN(snprintf), \ FN(snprintf), \
FN(sys_bpf), \
FN(btf_find_by_name_kind), \
FN(sys_close), \
/* */ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
......
...@@ -473,15 +473,16 @@ bool bpf_link_is_iter(struct bpf_link *link) ...@@ -473,15 +473,16 @@ bool bpf_link_is_iter(struct bpf_link *link)
return link->ops == &bpf_iter_link_lops; return link->ops == &bpf_iter_link_lops;
} }
int bpf_iter_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) int bpf_iter_link_attach(const union bpf_attr *attr, bpfptr_t uattr,
struct bpf_prog *prog)
{ {
union bpf_iter_link_info __user *ulinfo;
struct bpf_link_primer link_primer; struct bpf_link_primer link_primer;
struct bpf_iter_target_info *tinfo; struct bpf_iter_target_info *tinfo;
union bpf_iter_link_info linfo; union bpf_iter_link_info linfo;
struct bpf_iter_link *link; struct bpf_iter_link *link;
u32 prog_btf_id, linfo_len; u32 prog_btf_id, linfo_len;
bool existed = false; bool existed = false;
bpfptr_t ulinfo;
int err; int err;
if (attr->link_create.target_fd || attr->link_create.flags) if (attr->link_create.target_fd || attr->link_create.flags)
...@@ -489,18 +490,18 @@ int bpf_iter_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) ...@@ -489,18 +490,18 @@ int bpf_iter_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
memset(&linfo, 0, sizeof(union bpf_iter_link_info)); memset(&linfo, 0, sizeof(union bpf_iter_link_info));
ulinfo = u64_to_user_ptr(attr->link_create.iter_info); ulinfo = make_bpfptr(attr->link_create.iter_info, uattr.is_kernel);
linfo_len = attr->link_create.iter_info_len; linfo_len = attr->link_create.iter_info_len;
if (!ulinfo ^ !linfo_len) if (bpfptr_is_null(ulinfo) ^ !linfo_len)
return -EINVAL; return -EINVAL;
if (ulinfo) { if (!bpfptr_is_null(ulinfo)) {
err = bpf_check_uarg_tail_zero(ulinfo, sizeof(linfo), err = bpf_check_uarg_tail_zero(ulinfo, sizeof(linfo),
linfo_len); linfo_len);
if (err) if (err)
return err; return err;
linfo_len = min_t(u32, linfo_len, sizeof(linfo)); linfo_len = min_t(u32, linfo_len, sizeof(linfo));
if (copy_from_user(&linfo, ulinfo, linfo_len)) if (copy_from_bpfptr(&linfo, ulinfo, linfo_len))
return -EFAULT; return -EFAULT;
} }
......
...@@ -4257,7 +4257,7 @@ static int btf_parse_hdr(struct btf_verifier_env *env) ...@@ -4257,7 +4257,7 @@ static int btf_parse_hdr(struct btf_verifier_env *env)
return 0; return 0;
} }
static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size, static struct btf *btf_parse(bpfptr_t btf_data, u32 btf_data_size,
u32 log_level, char __user *log_ubuf, u32 log_size) u32 log_level, char __user *log_ubuf, u32 log_size)
{ {
struct btf_verifier_env *env = NULL; struct btf_verifier_env *env = NULL;
...@@ -4306,7 +4306,7 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size, ...@@ -4306,7 +4306,7 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
btf->data = data; btf->data = data;
btf->data_size = btf_data_size; btf->data_size = btf_data_size;
if (copy_from_user(data, btf_data, btf_data_size)) { if (copy_from_bpfptr(data, btf_data, btf_data_size)) {
err = -EFAULT; err = -EFAULT;
goto errout; goto errout;
} }
...@@ -5780,12 +5780,12 @@ static int __btf_new_fd(struct btf *btf) ...@@ -5780,12 +5780,12 @@ static int __btf_new_fd(struct btf *btf)
return anon_inode_getfd("btf", &btf_fops, btf, O_RDONLY | O_CLOEXEC); return anon_inode_getfd("btf", &btf_fops, btf, O_RDONLY | O_CLOEXEC);
} }
int btf_new_fd(const union bpf_attr *attr) int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr)
{ {
struct btf *btf; struct btf *btf;
int ret; int ret;
btf = btf_parse(u64_to_user_ptr(attr->btf), btf = btf_parse(make_bpfptr(attr->btf, uattr.is_kernel),
attr->btf_size, attr->btf_log_level, attr->btf_size, attr->btf_log_level,
u64_to_user_ptr(attr->btf_log_buf), u64_to_user_ptr(attr->btf_log_buf),
attr->btf_log_size); attr->btf_log_size);
...@@ -6085,3 +6085,65 @@ struct module *btf_try_get_module(const struct btf *btf) ...@@ -6085,3 +6085,65 @@ struct module *btf_try_get_module(const struct btf *btf)
return res; return res;
} }
BPF_CALL_4(bpf_btf_find_by_name_kind, char *, name, int, name_sz, u32, kind, int, flags)
{
struct btf *btf;
long ret;
if (flags)
return -EINVAL;
if (name_sz <= 1 || name[name_sz - 1])
return -EINVAL;
btf = bpf_get_btf_vmlinux();
if (IS_ERR(btf))
return PTR_ERR(btf);
ret = btf_find_by_name_kind(btf, name, kind);
/* ret is never zero, since btf_find_by_name_kind returns
* positive btf_id or negative error.
*/
if (ret < 0) {
struct btf *mod_btf;
int id;
/* If name is not found in vmlinux's BTF then search in module's BTFs */
spin_lock_bh(&btf_idr_lock);
idr_for_each_entry(&btf_idr, mod_btf, id) {
if (!btf_is_module(mod_btf))
continue;
/* linear search could be slow hence unlock/lock
* the IDR to avoiding holding it for too long
*/
btf_get(mod_btf);
spin_unlock_bh(&btf_idr_lock);
ret = btf_find_by_name_kind(mod_btf, name, kind);
if (ret > 0) {
int btf_obj_fd;
btf_obj_fd = __btf_new_fd(mod_btf);
if (btf_obj_fd < 0) {
btf_put(mod_btf);
return btf_obj_fd;
}
return ret | (((u64)btf_obj_fd) << 32);
}
spin_lock_bh(&btf_idr_lock);
btf_put(mod_btf);
}
spin_unlock_bh(&btf_idr_lock);
}
return ret;
}
const struct bpf_func_proto bpf_btf_find_by_name_kind_proto = {
.func = bpf_btf_find_by_name_kind,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_MEM,
.arg2_type = ARG_CONST_SIZE,
.arg3_type = ARG_ANYTHING,
.arg4_type = ARG_ANYTHING,
};
This diff is collapsed.
This diff is collapsed.
...@@ -409,7 +409,7 @@ static void *bpf_ctx_init(const union bpf_attr *kattr, u32 max_size) ...@@ -409,7 +409,7 @@ static void *bpf_ctx_init(const union bpf_attr *kattr, u32 max_size)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (data_in) { if (data_in) {
err = bpf_check_uarg_tail_zero(data_in, max_size, size); err = bpf_check_uarg_tail_zero(USER_BPFPTR(data_in), max_size, size);
if (err) { if (err) {
kfree(data); kfree(data);
return ERR_PTR(err); return ERR_PTR(err);
...@@ -918,3 +918,46 @@ int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kat ...@@ -918,3 +918,46 @@ int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kat
kfree(user_ctx); kfree(user_ctx);
return ret; return ret;
} }
int bpf_prog_test_run_syscall(struct bpf_prog *prog,
const union bpf_attr *kattr,
union bpf_attr __user *uattr)
{
void __user *ctx_in = u64_to_user_ptr(kattr->test.ctx_in);
__u32 ctx_size_in = kattr->test.ctx_size_in;
void *ctx = NULL;
u32 retval;
int err = 0;
/* doesn't support data_in/out, ctx_out, duration, or repeat or flags */
if (kattr->test.data_in || kattr->test.data_out ||
kattr->test.ctx_out || kattr->test.duration ||
kattr->test.repeat || kattr->test.flags)
return -EINVAL;
if (ctx_size_in < prog->aux->max_ctx_offset ||
ctx_size_in > U16_MAX)
return -EINVAL;
if (ctx_size_in) {
ctx = kzalloc(ctx_size_in, GFP_USER);
if (!ctx)
return -ENOMEM;
if (copy_from_user(ctx, ctx_in, ctx_size_in)) {
err = -EFAULT;
goto out;
}
}
retval = bpf_prog_run_pin_on_cpu(prog, ctx);
if (copy_to_user(&uattr->test.retval, &retval, sizeof(u32))) {
err = -EFAULT;
goto out;
}
if (ctx_size_in)
if (copy_to_user(ctx_in, ctx, ctx_size_in))
err = -EFAULT;
out:
kfree(ctx);
return err;
}
...@@ -3235,7 +3235,7 @@ static int bpf_skb_net_hdr_pop(struct sk_buff *skb, u32 off, u32 len) ...@@ -3235,7 +3235,7 @@ static int bpf_skb_net_hdr_pop(struct sk_buff *skb, u32 off, u32 len)
return ret; return ret;
} }
static int bpf_skb_proto_4_to_6(struct sk_buff *skb) static int bpf_skb_proto_4_to_6(struct sk_buff *skb, u64 flags)
{ {
const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr); const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
u32 off = skb_mac_header_len(skb); u32 off = skb_mac_header_len(skb);
...@@ -3264,7 +3264,9 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb) ...@@ -3264,7 +3264,9 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
} }
/* Due to IPv6 header, MSS needs to be downgraded. */ /* Due to IPv6 header, MSS needs to be downgraded. */
skb_decrease_gso_size(shinfo, len_diff); if (!(flags & BPF_F_ADJ_ROOM_FIXED_GSO))
skb_decrease_gso_size(shinfo, len_diff);
/* Header must be checked, and gso_segs recomputed. */ /* Header must be checked, and gso_segs recomputed. */
shinfo->gso_type |= SKB_GSO_DODGY; shinfo->gso_type |= SKB_GSO_DODGY;
shinfo->gso_segs = 0; shinfo->gso_segs = 0;
...@@ -3276,7 +3278,7 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb) ...@@ -3276,7 +3278,7 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
return 0; return 0;
} }
static int bpf_skb_proto_6_to_4(struct sk_buff *skb) static int bpf_skb_proto_6_to_4(struct sk_buff *skb, u64 flags)
{ {
const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr); const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
u32 off = skb_mac_header_len(skb); u32 off = skb_mac_header_len(skb);
...@@ -3305,7 +3307,9 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb) ...@@ -3305,7 +3307,9 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
} }
/* Due to IPv4 header, MSS can be upgraded. */ /* Due to IPv4 header, MSS can be upgraded. */
skb_increase_gso_size(shinfo, len_diff); if (!(flags & BPF_F_ADJ_ROOM_FIXED_GSO))
skb_increase_gso_size(shinfo, len_diff);
/* Header must be checked, and gso_segs recomputed. */ /* Header must be checked, and gso_segs recomputed. */
shinfo->gso_type |= SKB_GSO_DODGY; shinfo->gso_type |= SKB_GSO_DODGY;
shinfo->gso_segs = 0; shinfo->gso_segs = 0;
...@@ -3317,17 +3321,17 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb) ...@@ -3317,17 +3321,17 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
return 0; return 0;
} }
static int bpf_skb_proto_xlat(struct sk_buff *skb, __be16 to_proto) static int bpf_skb_proto_xlat(struct sk_buff *skb, __be16 to_proto, u64 flags)
{ {
__be16 from_proto = skb->protocol; __be16 from_proto = skb->protocol;
if (from_proto == htons(ETH_P_IP) && if (from_proto == htons(ETH_P_IP) &&
to_proto == htons(ETH_P_IPV6)) to_proto == htons(ETH_P_IPV6))
return bpf_skb_proto_4_to_6(skb); return bpf_skb_proto_4_to_6(skb, flags);
if (from_proto == htons(ETH_P_IPV6) && if (from_proto == htons(ETH_P_IPV6) &&
to_proto == htons(ETH_P_IP)) to_proto == htons(ETH_P_IP))
return bpf_skb_proto_6_to_4(skb); return bpf_skb_proto_6_to_4(skb, flags);
return -ENOTSUPP; return -ENOTSUPP;
} }
...@@ -3337,7 +3341,7 @@ BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto, ...@@ -3337,7 +3341,7 @@ BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto,
{ {
int ret; int ret;
if (unlikely(flags)) if (unlikely(flags & ~(BPF_F_ADJ_ROOM_FIXED_GSO)))
return -EINVAL; return -EINVAL;
/* General idea is that this helper does the basic groundwork /* General idea is that this helper does the basic groundwork
...@@ -3357,7 +3361,7 @@ BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto, ...@@ -3357,7 +3361,7 @@ BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto,
* that. For offloads, we mark packet as dodgy, so that headers * that. For offloads, we mark packet as dodgy, so that headers
* need to be verified first. * need to be verified first.
*/ */
ret = bpf_skb_proto_xlat(skb, proto); ret = bpf_skb_proto_xlat(skb, proto, flags);
bpf_compute_data_pointers(skb); bpf_compute_data_pointers(skb);
return ret; return ret;
} }
......
...@@ -399,8 +399,7 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, ...@@ -399,8 +399,7 @@ int sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from,
} }
EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter); EXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter);
int sk_msg_wait_data(struct sock *sk, struct sk_psock *psock, int flags, int sk_msg_wait_data(struct sock *sk, struct sk_psock *psock, long timeo)
long timeo, int *err)
{ {
DEFINE_WAIT_FUNC(wait, woken_wake_function); DEFINE_WAIT_FUNC(wait, woken_wake_function);
int ret = 0; int ret = 0;
......
...@@ -184,11 +184,11 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -184,11 +184,11 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
msg_bytes_ready: msg_bytes_ready:
copied = sk_msg_recvmsg(sk, psock, msg, len, flags); copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
if (!copied) { if (!copied) {
int data, err = 0;
long timeo; long timeo;
int data;
timeo = sock_rcvtimeo(sk, nonblock); timeo = sock_rcvtimeo(sk, nonblock);
data = sk_msg_wait_data(sk, psock, flags, timeo, &err); data = sk_msg_wait_data(sk, psock, timeo);
if (data) { if (data) {
if (!sk_psock_queue_empty(psock)) if (!sk_psock_queue_empty(psock))
goto msg_bytes_ready; goto msg_bytes_ready;
...@@ -196,14 +196,9 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -196,14 +196,9 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
sk_psock_put(sk, psock); sk_psock_put(sk, psock);
return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
} }
if (err) {
ret = err;
goto out;
}
copied = -EAGAIN; copied = -EAGAIN;
} }
ret = copied; ret = copied;
out:
release_sock(sk); release_sock(sk);
sk_psock_put(sk, psock); sk_psock_put(sk, psock);
return ret; return ret;
......
...@@ -43,21 +43,17 @@ static int udp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -43,21 +43,17 @@ static int udp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
msg_bytes_ready: msg_bytes_ready:
copied = sk_msg_recvmsg(sk, psock, msg, len, flags); copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
if (!copied) { if (!copied) {
int data, err = 0;
long timeo; long timeo;
int data;
timeo = sock_rcvtimeo(sk, nonblock); timeo = sock_rcvtimeo(sk, nonblock);
data = sk_msg_wait_data(sk, psock, flags, timeo, &err); data = sk_msg_wait_data(sk, psock, timeo);
if (data) { if (data) {
if (!sk_psock_queue_empty(psock)) if (!sk_psock_queue_empty(psock))
goto msg_bytes_ready; goto msg_bytes_ready;
ret = sk_udp_recvmsg(sk, msg, len, nonblock, flags, addr_len); ret = sk_udp_recvmsg(sk, msg, len, nonblock, flags, addr_len);
goto out; goto out;
} }
if (err) {
ret = err;
goto out;
}
copied = -EAGAIN; copied = -EAGAIN;
} }
ret = copied; ret = copied;
......
...@@ -396,7 +396,7 @@ int main(int argc, char **argv) ...@@ -396,7 +396,7 @@ int main(int argc, char **argv)
* on different systems with different compilers. The right way is * on different systems with different compilers. The right way is
* to parse the ELF file. We took a shortcut here. * to parse the ELF file. We took a shortcut here.
*/ */
uprobe_file_offset = (__u64)main - (__u64)&__executable_start; uprobe_file_offset = (unsigned long)main - (unsigned long)&__executable_start;
CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0], CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0],
uprobe_file_offset, 0x0, false, uprobe_file_offset, 0x0, false,
BPF_FD_TYPE_UPROBE, BPF_FD_TYPE_UPROBE,
......
...@@ -136,7 +136,7 @@ endif ...@@ -136,7 +136,7 @@ endif
BPFTOOL_BOOTSTRAP := $(BOOTSTRAP_OUTPUT)bpftool BPFTOOL_BOOTSTRAP := $(BOOTSTRAP_OUTPUT)bpftool
BOOTSTRAP_OBJS = $(addprefix $(BOOTSTRAP_OUTPUT),main.o common.o json_writer.o gen.o btf.o) BOOTSTRAP_OBJS = $(addprefix $(BOOTSTRAP_OUTPUT),main.o common.o json_writer.o gen.o btf.o xlated_dumper.o btf_dumper.o) $(OUTPUT)disasm.o
OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o
VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \ VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
......
This diff is collapsed.
...@@ -29,6 +29,7 @@ bool show_pinned; ...@@ -29,6 +29,7 @@ bool show_pinned;
bool block_mount; bool block_mount;
bool verifier_logs; bool verifier_logs;
bool relaxed_maps; bool relaxed_maps;
bool use_loader;
struct btf *base_btf; struct btf *base_btf;
struct pinned_obj_table prog_table; struct pinned_obj_table prog_table;
struct pinned_obj_table map_table; struct pinned_obj_table map_table;
...@@ -392,6 +393,7 @@ int main(int argc, char **argv) ...@@ -392,6 +393,7 @@ int main(int argc, char **argv)
{ "mapcompat", no_argument, NULL, 'm' }, { "mapcompat", no_argument, NULL, 'm' },
{ "nomount", no_argument, NULL, 'n' }, { "nomount", no_argument, NULL, 'n' },
{ "debug", no_argument, NULL, 'd' }, { "debug", no_argument, NULL, 'd' },
{ "use-loader", no_argument, NULL, 'L' },
{ "base-btf", required_argument, NULL, 'B' }, { "base-btf", required_argument, NULL, 'B' },
{ 0 } { 0 }
}; };
...@@ -409,7 +411,7 @@ int main(int argc, char **argv) ...@@ -409,7 +411,7 @@ int main(int argc, char **argv)
hash_init(link_table.table); hash_init(link_table.table);
opterr = 0; opterr = 0;
while ((opt = getopt_long(argc, argv, "VhpjfmndB:", while ((opt = getopt_long(argc, argv, "VhpjfLmndB:",
options, NULL)) >= 0) { options, NULL)) >= 0) {
switch (opt) { switch (opt) {
case 'V': case 'V':
...@@ -452,6 +454,9 @@ int main(int argc, char **argv) ...@@ -452,6 +454,9 @@ int main(int argc, char **argv)
return -1; return -1;
} }
break; break;
case 'L':
use_loader = true;
break;
default: default:
p_err("unrecognized option '%s'", argv[optind - 1]); p_err("unrecognized option '%s'", argv[optind - 1]);
if (json_output) if (json_output)
......
...@@ -90,6 +90,7 @@ extern bool show_pids; ...@@ -90,6 +90,7 @@ extern bool show_pids;
extern bool block_mount; extern bool block_mount;
extern bool verifier_logs; extern bool verifier_logs;
extern bool relaxed_maps; extern bool relaxed_maps;
extern bool use_loader;
extern struct btf *base_btf; extern struct btf *base_btf;
extern struct pinned_obj_table prog_table; extern struct pinned_obj_table prog_table;
extern struct pinned_obj_table map_table; extern struct pinned_obj_table map_table;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <dirent.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
...@@ -24,6 +25,8 @@ ...@@ -24,6 +25,8 @@
#include <bpf/bpf.h> #include <bpf/bpf.h>
#include <bpf/btf.h> #include <bpf/btf.h>
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include <bpf/bpf_gen_internal.h>
#include <bpf/skel_internal.h>
#include "cfg.h" #include "cfg.h"
#include "main.h" #include "main.h"
...@@ -1499,7 +1502,7 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) ...@@ -1499,7 +1502,7 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
set_max_rlimit(); set_max_rlimit();
obj = bpf_object__open_file(file, &open_opts); obj = bpf_object__open_file(file, &open_opts);
if (IS_ERR_OR_NULL(obj)) { if (libbpf_get_error(obj)) {
p_err("failed to open object file"); p_err("failed to open object file");
goto err_free_reuse_maps; goto err_free_reuse_maps;
} }
...@@ -1645,8 +1648,110 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) ...@@ -1645,8 +1648,110 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
return -1; return -1;
} }
static int count_open_fds(void)
{
DIR *dp = opendir("/proc/self/fd");
struct dirent *de;
int cnt = -3;
if (!dp)
return -1;
while ((de = readdir(dp)))
cnt++;
closedir(dp);
return cnt;
}
static int try_loader(struct gen_loader_opts *gen)
{
struct bpf_load_and_run_opts opts = {};
struct bpf_loader_ctx *ctx;
int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc),
sizeof(struct bpf_prog_desc));
int log_buf_sz = (1u << 24) - 1;
int err, fds_before, fd_delta;
char *log_buf;
ctx = alloca(ctx_sz);
memset(ctx, 0, ctx_sz);
ctx->sz = ctx_sz;
ctx->log_level = 1;
ctx->log_size = log_buf_sz;
log_buf = malloc(log_buf_sz);
if (!log_buf)
return -ENOMEM;
ctx->log_buf = (long) log_buf;
opts.ctx = ctx;
opts.data = gen->data;
opts.data_sz = gen->data_sz;
opts.insns = gen->insns;
opts.insns_sz = gen->insns_sz;
fds_before = count_open_fds();
err = bpf_load_and_run(&opts);
fd_delta = count_open_fds() - fds_before;
if (err < 0) {
fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf);
if (fd_delta)
fprintf(stderr, "loader prog leaked %d FDs\n",
fd_delta);
}
free(log_buf);
return err;
}
static int do_loader(int argc, char **argv)
{
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts);
DECLARE_LIBBPF_OPTS(gen_loader_opts, gen);
struct bpf_object_load_attr load_attr = {};
struct bpf_object *obj;
const char *file;
int err = 0;
if (!REQ_ARGS(1))
return -1;
file = GET_ARG();
obj = bpf_object__open_file(file, &open_opts);
if (libbpf_get_error(obj)) {
p_err("failed to open object file");
goto err_close_obj;
}
err = bpf_object__gen_loader(obj, &gen);
if (err)
goto err_close_obj;
load_attr.obj = obj;
if (verifier_logs)
/* log_level1 + log_level2 + stats, but not stable UAPI */
load_attr.log_level = 1 + 2 + 4;
err = bpf_object__load_xattr(&load_attr);
if (err) {
p_err("failed to load object file");
goto err_close_obj;
}
if (verifier_logs) {
struct dump_data dd = {};
kernel_syms_load(&dd);
dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false);
kernel_syms_destroy(&dd);
}
err = try_loader(&gen);
err_close_obj:
bpf_object__close(obj);
return err;
}
static int do_load(int argc, char **argv) static int do_load(int argc, char **argv)
{ {
if (use_loader)
return do_loader(argc, argv);
return load_with_options(argc, argv, true); return load_with_options(argc, argv, true);
} }
......
...@@ -196,6 +196,9 @@ static const char *print_imm(void *private_data, ...@@ -196,6 +196,9 @@ static const char *print_imm(void *private_data,
else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE) else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE)
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"map[id:%u][0]+%u", insn->imm, (insn + 1)->imm); "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm);
else if (insn->src_reg == BPF_PSEUDO_MAP_IDX_VALUE)
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"map[idx:%u]+%u", insn->imm, (insn + 1)->imm);
else if (insn->src_reg == BPF_PSEUDO_FUNC) else if (insn->src_reg == BPF_PSEUDO_FUNC)
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"subprog[%+d]", insn->imm); "subprog[%+d]", insn->imm);
......
...@@ -837,6 +837,7 @@ enum bpf_cmd { ...@@ -837,6 +837,7 @@ enum bpf_cmd {
BPF_PROG_ATTACH, BPF_PROG_ATTACH,
BPF_PROG_DETACH, BPF_PROG_DETACH,
BPF_PROG_TEST_RUN, BPF_PROG_TEST_RUN,
BPF_PROG_RUN = BPF_PROG_TEST_RUN,
BPF_PROG_GET_NEXT_ID, BPF_PROG_GET_NEXT_ID,
BPF_MAP_GET_NEXT_ID, BPF_MAP_GET_NEXT_ID,
BPF_PROG_GET_FD_BY_ID, BPF_PROG_GET_FD_BY_ID,
...@@ -937,6 +938,7 @@ enum bpf_prog_type { ...@@ -937,6 +938,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_EXT, BPF_PROG_TYPE_EXT,
BPF_PROG_TYPE_LSM, BPF_PROG_TYPE_LSM,
BPF_PROG_TYPE_SK_LOOKUP, BPF_PROG_TYPE_SK_LOOKUP,
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
}; };
enum bpf_attach_type { enum bpf_attach_type {
...@@ -1097,8 +1099,8 @@ enum bpf_link_type { ...@@ -1097,8 +1099,8 @@ enum bpf_link_type {
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have /* When BPF ldimm64's insn[0].src_reg != 0 then this can have
* the following extensions: * the following extensions:
* *
* insn[0].src_reg: BPF_PSEUDO_MAP_FD * insn[0].src_reg: BPF_PSEUDO_MAP_[FD|IDX]
* insn[0].imm: map fd * insn[0].imm: map fd or fd_idx
* insn[1].imm: 0 * insn[1].imm: 0
* insn[0].off: 0 * insn[0].off: 0
* insn[1].off: 0 * insn[1].off: 0
...@@ -1106,15 +1108,19 @@ enum bpf_link_type { ...@@ -1106,15 +1108,19 @@ enum bpf_link_type {
* verifier type: CONST_PTR_TO_MAP * verifier type: CONST_PTR_TO_MAP
*/ */
#define BPF_PSEUDO_MAP_FD 1 #define BPF_PSEUDO_MAP_FD 1
/* insn[0].src_reg: BPF_PSEUDO_MAP_VALUE #define BPF_PSEUDO_MAP_IDX 5
* insn[0].imm: map fd
/* insn[0].src_reg: BPF_PSEUDO_MAP_[IDX_]VALUE
* insn[0].imm: map fd or fd_idx
* insn[1].imm: offset into value * insn[1].imm: offset into value
* insn[0].off: 0 * insn[0].off: 0
* insn[1].off: 0 * insn[1].off: 0
* ldimm64 rewrite: address of map[0]+offset * ldimm64 rewrite: address of map[0]+offset
* verifier type: PTR_TO_MAP_VALUE * verifier type: PTR_TO_MAP_VALUE
*/ */
#define BPF_PSEUDO_MAP_VALUE 2 #define BPF_PSEUDO_MAP_VALUE 2
#define BPF_PSEUDO_MAP_IDX_VALUE 6
/* insn[0].src_reg: BPF_PSEUDO_BTF_ID /* insn[0].src_reg: BPF_PSEUDO_BTF_ID
* insn[0].imm: kernel btd id of VAR * insn[0].imm: kernel btd id of VAR
* insn[1].imm: 0 * insn[1].imm: 0
...@@ -1314,6 +1320,8 @@ union bpf_attr { ...@@ -1314,6 +1320,8 @@ union bpf_attr {
/* or valid module BTF object fd or 0 to attach to vmlinux */ /* or valid module BTF object fd or 0 to attach to vmlinux */
__u32 attach_btf_obj_fd; __u32 attach_btf_obj_fd;
}; };
__u32 :32; /* pad */
__aligned_u64 fd_array; /* array of FDs */
}; };
struct { /* anonymous struct used by BPF_OBJ_* commands */ struct { /* anonymous struct used by BPF_OBJ_* commands */
...@@ -4735,6 +4743,24 @@ union bpf_attr { ...@@ -4735,6 +4743,24 @@ union bpf_attr {
* be zero-terminated except when **str_size** is 0. * be zero-terminated except when **str_size** is 0.
* *
* Or **-EBUSY** if the per-CPU memory copy buffer is busy. * Or **-EBUSY** if the per-CPU memory copy buffer is busy.
*
* long bpf_sys_bpf(u32 cmd, void *attr, u32 attr_size)
* Description
* Execute bpf syscall with given arguments.
* Return
* A syscall result.
*
* long bpf_btf_find_by_name_kind(char *name, int name_sz, u32 kind, int flags)
* Description
* Find BTF type with given name and kind in vmlinux BTF or in module's BTFs.
* Return
* Returns btf_id and btf_obj_fd in lower and upper 32 bits.
*
* long bpf_sys_close(u32 fd)
* Description
* Execute close syscall for given FD.
* Return
* A syscall result.
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -4903,6 +4929,9 @@ union bpf_attr { ...@@ -4903,6 +4929,9 @@ union bpf_attr {
FN(check_mtu), \ FN(check_mtu), \
FN(for_each_map_elem), \ FN(for_each_map_elem), \
FN(snprintf), \ FN(snprintf), \
FN(sys_bpf), \
FN(btf_find_by_name_kind), \
FN(sys_close), \
/* */ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
......
libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \ libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \
netlink.o bpf_prog_linfo.o libbpf_probes.o xsk.o hashmap.o \ netlink.o bpf_prog_linfo.o libbpf_probes.o xsk.o hashmap.o \
btf_dump.o ringbuf.o strset.o linker.o btf_dump.o ringbuf.o strset.o linker.o gen_loader.o
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
/* Copyright (c) 2021 Facebook */
#ifndef __BPF_GEN_INTERNAL_H
#define __BPF_GEN_INTERNAL_H
struct ksym_relo_desc {
const char *name;
int kind;
int insn_idx;
};
struct bpf_gen {
struct gen_loader_opts *opts;
void *data_start;
void *data_cur;
void *insn_start;
void *insn_cur;
ssize_t cleanup_label;
__u32 nr_progs;
__u32 nr_maps;
int log_level;
int error;
struct ksym_relo_desc *relos;
int relo_cnt;
char attach_target[128];
int attach_kind;
};
void bpf_gen__init(struct bpf_gen *gen, int log_level);
int bpf_gen__finish(struct bpf_gen *gen);
void bpf_gen__free(struct bpf_gen *gen);
void bpf_gen__load_btf(struct bpf_gen *gen, const void *raw_data, __u32 raw_size);
void bpf_gen__map_create(struct bpf_gen *gen, struct bpf_create_map_attr *map_attr, int map_idx);
struct bpf_prog_load_params;
void bpf_gen__prog_load(struct bpf_gen *gen, struct bpf_prog_load_params *load_attr, int prog_idx);
void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *value, __u32 value_size);
void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx);
void bpf_gen__record_attach_target(struct bpf_gen *gen, const char *name, enum bpf_attach_type type);
void bpf_gen__record_extern(struct bpf_gen *gen, const char *name, int kind, int insn_idx);
#endif
This diff is collapsed.
This diff is collapsed.
...@@ -471,6 +471,7 @@ LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv, ...@@ -471,6 +471,7 @@ LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
LIBBPF_API void *bpf_map__priv(const struct bpf_map *map); LIBBPF_API void *bpf_map__priv(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map, LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map,
const void *data, size_t size); const void *data, size_t size);
LIBBPF_API const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize);
LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map); LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);
LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map); LIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path); LIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);
...@@ -498,6 +499,7 @@ LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, ...@@ -498,6 +499,7 @@ LIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type, LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj, int *prog_fd); struct bpf_object **pobj, int *prog_fd);
/* XDP related API */
struct xdp_link_info { struct xdp_link_info {
__u32 prog_id; __u32 prog_id;
__u32 drv_prog_id; __u32 drv_prog_id;
...@@ -520,6 +522,49 @@ LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags); ...@@ -520,6 +522,49 @@ LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
LIBBPF_API int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info, LIBBPF_API int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
size_t info_size, __u32 flags); size_t info_size, __u32 flags);
/* TC related API */
enum bpf_tc_attach_point {
BPF_TC_INGRESS = 1 << 0,
BPF_TC_EGRESS = 1 << 1,
BPF_TC_CUSTOM = 1 << 2,
};
#define BPF_TC_PARENT(a, b) \
((((a) << 16) & 0xFFFF0000U) | ((b) & 0x0000FFFFU))
enum bpf_tc_flags {
BPF_TC_F_REPLACE = 1 << 0,
};
struct bpf_tc_hook {
size_t sz;
int ifindex;
enum bpf_tc_attach_point attach_point;
__u32 parent;
size_t :0;
};
#define bpf_tc_hook__last_field parent
struct bpf_tc_opts {
size_t sz;
int prog_fd;
__u32 flags;
__u32 prog_id;
__u32 handle;
__u32 priority;
size_t :0;
};
#define bpf_tc_opts__last_field priority
LIBBPF_API int bpf_tc_hook_create(struct bpf_tc_hook *hook);
LIBBPF_API int bpf_tc_hook_destroy(struct bpf_tc_hook *hook);
LIBBPF_API int bpf_tc_attach(const struct bpf_tc_hook *hook,
struct bpf_tc_opts *opts);
LIBBPF_API int bpf_tc_detach(const struct bpf_tc_hook *hook,
const struct bpf_tc_opts *opts);
LIBBPF_API int bpf_tc_query(const struct bpf_tc_hook *hook,
struct bpf_tc_opts *opts);
/* Ring buffer APIs */ /* Ring buffer APIs */
struct ring_buffer; struct ring_buffer;
...@@ -756,6 +801,18 @@ LIBBPF_API int bpf_object__attach_skeleton(struct bpf_object_skeleton *s); ...@@ -756,6 +801,18 @@ LIBBPF_API int bpf_object__attach_skeleton(struct bpf_object_skeleton *s);
LIBBPF_API void bpf_object__detach_skeleton(struct bpf_object_skeleton *s); LIBBPF_API void bpf_object__detach_skeleton(struct bpf_object_skeleton *s);
LIBBPF_API void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s); LIBBPF_API void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s);
struct gen_loader_opts {
size_t sz; /* size of this struct, for forward/backward compatiblity */
const char *data;
const char *insns;
__u32 data_sz;
__u32 insns_sz;
};
#define gen_loader_opts__last_field insns_sz
LIBBPF_API int bpf_object__gen_loader(struct bpf_object *obj,
struct gen_loader_opts *opts);
enum libbpf_tristate { enum libbpf_tristate {
TRI_NO = 0, TRI_NO = 0,
TRI_YES = 1, TRI_YES = 1,
...@@ -768,10 +825,18 @@ struct bpf_linker_opts { ...@@ -768,10 +825,18 @@ struct bpf_linker_opts {
}; };
#define bpf_linker_opts__last_field sz #define bpf_linker_opts__last_field sz
struct bpf_linker_file_opts {
/* size of this struct, for forward/backward compatiblity */
size_t sz;
};
#define bpf_linker_file_opts__last_field sz
struct bpf_linker; struct bpf_linker;
LIBBPF_API struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts *opts); LIBBPF_API struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts *opts);
LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker, const char *filename); LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker,
const char *filename,
const struct bpf_linker_file_opts *opts);
LIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker); LIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker);
LIBBPF_API void bpf_linker__free(struct bpf_linker *linker); LIBBPF_API void bpf_linker__free(struct bpf_linker *linker);
......
...@@ -359,6 +359,13 @@ LIBBPF_0.4.0 { ...@@ -359,6 +359,13 @@ LIBBPF_0.4.0 {
bpf_linker__finalize; bpf_linker__finalize;
bpf_linker__free; bpf_linker__free;
bpf_linker__new; bpf_linker__new;
bpf_map__initial_value;
bpf_map__inner_map; bpf_map__inner_map;
bpf_object__gen_loader;
bpf_object__set_kversion; bpf_object__set_kversion;
bpf_tc_attach;
bpf_tc_detach;
bpf_tc_hook_create;
bpf_tc_hook_destroy;
bpf_tc_query;
} LIBBPF_0.3.0; } LIBBPF_0.3.0;
...@@ -258,6 +258,8 @@ int bpf_object__section_size(const struct bpf_object *obj, const char *name, ...@@ -258,6 +258,8 @@ int bpf_object__section_size(const struct bpf_object *obj, const char *name,
int bpf_object__variable_offset(const struct bpf_object *obj, const char *name, int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
__u32 *off); __u32 *off);
struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf); struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf);
void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type,
const char **prefix, int *kind);
struct btf_ext_info { struct btf_ext_info {
/* /*
......
...@@ -158,7 +158,9 @@ struct bpf_linker { ...@@ -158,7 +158,9 @@ struct bpf_linker {
static int init_output_elf(struct bpf_linker *linker, const char *file); static int init_output_elf(struct bpf_linker *linker, const char *file);
static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, struct src_obj *obj); static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
const struct bpf_linker_file_opts *opts,
struct src_obj *obj);
static int linker_sanity_check_elf(struct src_obj *obj); static int linker_sanity_check_elf(struct src_obj *obj);
static int linker_sanity_check_elf_symtab(struct src_obj *obj, struct src_sec *sec); static int linker_sanity_check_elf_symtab(struct src_obj *obj, struct src_sec *sec);
static int linker_sanity_check_elf_relos(struct src_obj *obj, struct src_sec *sec); static int linker_sanity_check_elf_relos(struct src_obj *obj, struct src_sec *sec);
...@@ -435,15 +437,19 @@ static int init_output_elf(struct bpf_linker *linker, const char *file) ...@@ -435,15 +437,19 @@ static int init_output_elf(struct bpf_linker *linker, const char *file)
return 0; return 0;
} }
int bpf_linker__add_file(struct bpf_linker *linker, const char *filename) int bpf_linker__add_file(struct bpf_linker *linker, const char *filename,
const struct bpf_linker_file_opts *opts)
{ {
struct src_obj obj = {}; struct src_obj obj = {};
int err = 0; int err = 0;
if (!OPTS_VALID(opts, bpf_linker_file_opts))
return -EINVAL;
if (!linker->elf) if (!linker->elf)
return -EINVAL; return -EINVAL;
err = err ?: linker_load_obj_file(linker, filename, &obj); err = err ?: linker_load_obj_file(linker, filename, opts, &obj);
err = err ?: linker_append_sec_data(linker, &obj); err = err ?: linker_append_sec_data(linker, &obj);
err = err ?: linker_append_elf_syms(linker, &obj); err = err ?: linker_append_elf_syms(linker, &obj);
err = err ?: linker_append_elf_relos(linker, &obj); err = err ?: linker_append_elf_relos(linker, &obj);
...@@ -529,7 +535,9 @@ static struct src_sec *add_src_sec(struct src_obj *obj, const char *sec_name) ...@@ -529,7 +535,9 @@ static struct src_sec *add_src_sec(struct src_obj *obj, const char *sec_name)
return sec; return sec;
} }
static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, struct src_obj *obj) static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
const struct bpf_linker_file_opts *opts,
struct src_obj *obj)
{ {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
const int host_endianness = ELFDATA2LSB; const int host_endianness = ELFDATA2LSB;
...@@ -1780,7 +1788,7 @@ static void sym_update_visibility(Elf64_Sym *sym, int sym_vis) ...@@ -1780,7 +1788,7 @@ static void sym_update_visibility(Elf64_Sym *sym, int sym_vis)
/* libelf doesn't provide setters for ST_VISIBILITY, /* libelf doesn't provide setters for ST_VISIBILITY,
* but it is stored in the lower 2 bits of st_other * but it is stored in the lower 2 bits of st_other
*/ */
sym->st_other &= 0x03; sym->st_other &= ~0x03;
sym->st_other |= sym_vis; sym->st_other |= sym_vis;
} }
......
This diff is collapsed.
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
#define __LIBBPF_NLATTR_H #define __LIBBPF_NLATTR_H
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <errno.h>
#include <linux/netlink.h> #include <linux/netlink.h>
/* avoid multiple definition of netlink features */ /* avoid multiple definition of netlink features */
#define __LINUX_NETLINK_H #define __LINUX_NETLINK_H
...@@ -103,4 +106,49 @@ int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, ...@@ -103,4 +106,49 @@ int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh); int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh);
static inline struct nlattr *nla_data(struct nlattr *nla)
{
return (struct nlattr *)((char *)nla + NLA_HDRLEN);
}
static inline struct nlattr *nh_tail(struct nlmsghdr *nh)
{
return (struct nlattr *)((char *)nh + NLMSG_ALIGN(nh->nlmsg_len));
}
static inline int nlattr_add(struct nlmsghdr *nh, size_t maxsz, int type,
const void *data, int len)
{
struct nlattr *nla;
if (NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > maxsz)
return -EMSGSIZE;
if (!!data != !!len)
return -EINVAL;
nla = nh_tail(nh);
nla->nla_type = type;
nla->nla_len = NLA_HDRLEN + len;
if (data)
memcpy(nla_data(nla), data, len);
nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len) + NLA_ALIGN(nla->nla_len);
return 0;
}
static inline struct nlattr *nlattr_begin_nested(struct nlmsghdr *nh,
size_t maxsz, int type)
{
struct nlattr *tail;
tail = nh_tail(nh);
if (nlattr_add(nh, maxsz, type | NLA_F_NESTED, NULL, 0))
return NULL;
return tail;
}
static inline void nlattr_end_nested(struct nlmsghdr *nh, struct nlattr *tail)
{
tail->nla_len = (char *)nh_tail(nh) - (char *)tail;
}
#endif /* __LIBBPF_NLATTR_H */ #endif /* __LIBBPF_NLATTR_H */
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
/* Copyright (c) 2021 Facebook */
#ifndef __SKEL_INTERNAL_H
#define __SKEL_INTERNAL_H
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
/* This file is a base header for auto-generated *.lskel.h files.
* Its contents will change and may become part of auto-generation in the future.
*
* The layout of bpf_[map|prog]_desc and bpf_loader_ctx is feature dependent
* and will change from one version of libbpf to another and features
* requested during loader program generation.
*/
struct bpf_map_desc {
union {
/* input for the loader prog */
struct {
__aligned_u64 initial_value;
__u32 max_entries;
};
/* output of the loader prog */
struct {
int map_fd;
};
};
};
struct bpf_prog_desc {
int prog_fd;
};
struct bpf_loader_ctx {
size_t sz;
__u32 log_level;
__u32 log_size;
__u64 log_buf;
};
struct bpf_load_and_run_opts {
struct bpf_loader_ctx *ctx;
const void *data;
const void *insns;
__u32 data_sz;
__u32 insns_sz;
const char *errstr;
};
static inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
unsigned int size)
{
return syscall(__NR_bpf, cmd, attr, size);
}
static inline int skel_closenz(int fd)
{
if (fd > 0)
return close(fd);
return -EINVAL;
}
static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
{
int map_fd = -1, prog_fd = -1, key = 0, err;
union bpf_attr attr;
map_fd = bpf_create_map_name(BPF_MAP_TYPE_ARRAY, "__loader.map", 4,
opts->data_sz, 1, 0);
if (map_fd < 0) {
opts->errstr = "failed to create loader map";
err = -errno;
goto out;
}
err = bpf_map_update_elem(map_fd, &key, opts->data, 0);
if (err < 0) {
opts->errstr = "failed to update loader map";
err = -errno;
goto out;
}
memset(&attr, 0, sizeof(attr));
attr.prog_type = BPF_PROG_TYPE_SYSCALL;
attr.insns = (long) opts->insns;
attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
attr.license = (long) "Dual BSD/GPL";
memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
attr.fd_array = (long) &map_fd;
attr.log_level = opts->ctx->log_level;
attr.log_size = opts->ctx->log_size;
attr.log_buf = opts->ctx->log_buf;
attr.prog_flags = BPF_F_SLEEPABLE;
prog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
if (prog_fd < 0) {
opts->errstr = "failed to load loader prog";
err = -errno;
goto out;
}
memset(&attr, 0, sizeof(attr));
attr.test.prog_fd = prog_fd;
attr.test.ctx_in = (long) opts->ctx;
attr.test.ctx_size_in = opts->ctx->sz;
err = skel_sys_bpf(BPF_PROG_RUN, &attr, sizeof(attr));
if (err < 0 || (int)attr.test.retval < 0) {
opts->errstr = "failed to execute loader prog";
if (err < 0)
err = -errno;
else
err = (int)attr.test.retval;
goto out;
}
err = 0;
out:
if (map_fd >= 0)
close(map_fd);
if (prog_fd >= 0)
close(prog_fd);
return err;
}
#endif
...@@ -30,6 +30,7 @@ test_sysctl ...@@ -30,6 +30,7 @@ test_sysctl
xdping xdping
test_cpp test_cpp
*.skel.h *.skel.h
*.lskel.h
/no_alu32 /no_alu32
/bpf_gcc /bpf_gcc
/tools /tools
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 Facebook */ /* Copyright (c) 2019 Facebook */
#include <test_progs.h> #include <test_progs.h>
#include "fentry_test.skel.h" #include "fentry_test.lskel.h"
#include "fexit_test.skel.h" #include "fexit_test.lskel.h"
void test_fentry_fexit(void) void test_fentry_fexit(void)
{ {
...@@ -26,7 +26,7 @@ void test_fentry_fexit(void) ...@@ -26,7 +26,7 @@ void test_fentry_fexit(void)
if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err))
goto close_prog; goto close_prog;
prog_fd = bpf_program__fd(fexit_skel->progs.test1); prog_fd = fexit_skel->progs.test1.prog_fd;
err = bpf_prog_test_run(prog_fd, 1, NULL, 0, err = bpf_prog_test_run(prog_fd, 1, NULL, 0,
NULL, NULL, &retval, &duration); NULL, NULL, &retval, &duration);
CHECK(err || retval, "ipv6", CHECK(err || retval, "ipv6",
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <test_progs.h> #include <test_progs.h>
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include <bpf/btf.h> #include <bpf/btf.h>
#include "test_ksyms_module.skel.h" #include "test_ksyms_module.lskel.h"
static int duration; static int duration;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment