“960109afb496e9355211a48c22d10b64f22d5c28”上不存在“...fluid/framework/git@gitcode.net:paddlepaddle/Paddle.git”
提交 f91c031e 编写于 作者: D David S. Miller

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

Daniel Borkmann says:

====================
pull-request: bpf-next 2020-07-04

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

We've added 73 non-merge commits during the last 17 day(s) which contain
a total of 106 files changed, 5233 insertions(+), 1283 deletions(-).

The main changes are:

1) bpftool ability to show PIDs of processes having open file descriptors
   for BPF map/program/link/BTF objects, relying on BPF iterator progs
   to extract this info efficiently, from Andrii Nakryiko.

2) Addition of BPF iterator progs for dumping TCP and UDP sockets to
   seq_files, from Yonghong Song.

3) Support access to BPF map fields in struct bpf_map from programs
   through BTF struct access, from Andrey Ignatov.

4) Add a bpf_get_task_stack() helper to be able to dump /proc/*/stack
   via seq_file from BPF iterator progs, from Song Liu.

5) Make SO_KEEPALIVE and related options available to bpf_setsockopt()
   helper, from Dmitry Yakunin.

6) Optimize BPF sk_storage selection of its caching index, from Martin
   KaFai Lau.

7) Removal of redundant synchronize_rcu()s from BPF map destruction which
   has been a historic leftover, from Alexei Starovoitov.

8) Several improvements to test_progs to make it easier to create a shell
   loop that invokes each test individually which is useful for some CIs,
   from Jesper Dangaard Brouer.

9) Fix bpftool prog dump segfault when compiled without skeleton code on
   older clang versions, from John Fastabend.

10) Bunch of cleanups and minor improvements, from various others.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -92,6 +92,10 @@ struct bpf_map_ops { ...@@ -92,6 +92,10 @@ struct bpf_map_ops {
int (*map_mmap)(struct bpf_map *map, struct vm_area_struct *vma); int (*map_mmap)(struct bpf_map *map, struct vm_area_struct *vma);
__poll_t (*map_poll)(struct bpf_map *map, struct file *filp, __poll_t (*map_poll)(struct bpf_map *map, struct file *filp,
struct poll_table_struct *pts); struct poll_table_struct *pts);
/* BTF name and id of struct allocated by map_alloc */
const char * const map_btf_name;
int *map_btf_id;
}; };
struct bpf_map_memory { struct bpf_map_memory {
...@@ -261,6 +265,7 @@ enum bpf_return_type { ...@@ -261,6 +265,7 @@ enum bpf_return_type {
RET_PTR_TO_TCP_SOCK_OR_NULL, /* returns a pointer to a tcp_sock or NULL */ RET_PTR_TO_TCP_SOCK_OR_NULL, /* returns a pointer to a tcp_sock or NULL */
RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */ RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */
RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */ RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */
RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */
}; };
/* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs /* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs
...@@ -283,6 +288,12 @@ struct bpf_func_proto { ...@@ -283,6 +288,12 @@ struct bpf_func_proto {
enum bpf_arg_type arg_type[5]; enum bpf_arg_type arg_type[5];
}; };
int *btf_id; /* BTF ids of arguments */ int *btf_id; /* BTF ids of arguments */
bool (*check_btf_id)(u32 btf_id, u32 arg); /* if the argument btf_id is
* valid. Often used if more
* than one btf id is permitted
* for this argument.
*/
int *ret_btf_id; /* return value btf_id */
}; };
/* bpf_context is intentionally undefined structure. Pointer to bpf_context is /* bpf_context is intentionally undefined structure. Pointer to bpf_context is
...@@ -1109,6 +1120,11 @@ static inline bool bpf_allow_ptr_leaks(void) ...@@ -1109,6 +1120,11 @@ static inline bool bpf_allow_ptr_leaks(void)
return perfmon_capable(); return perfmon_capable();
} }
static inline bool bpf_allow_ptr_to_map_access(void)
{
return perfmon_capable();
}
static inline bool bpf_bypass_spec_v1(void) static inline bool bpf_bypass_spec_v1(void)
{ {
return perfmon_capable(); return perfmon_capable();
...@@ -1515,6 +1531,7 @@ static inline bool bpf_map_is_dev_bound(struct bpf_map *map) ...@@ -1515,6 +1531,7 @@ 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);
void init_btf_sock_ids(struct btf *btf);
#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)
...@@ -1540,6 +1557,9 @@ static inline struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr) ...@@ -1540,6 +1557,9 @@ 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 void init_btf_sock_ids(struct btf *btf)
{
}
#endif /* CONFIG_NET && CONFIG_BPF_SYSCALL */ #endif /* CONFIG_NET && CONFIG_BPF_SYSCALL */
#if defined(CONFIG_BPF_STREAM_PARSER) #if defined(CONFIG_BPF_STREAM_PARSER)
...@@ -1607,6 +1627,7 @@ extern const struct bpf_func_proto bpf_get_current_uid_gid_proto; ...@@ -1607,6 +1627,7 @@ extern const struct bpf_func_proto bpf_get_current_uid_gid_proto;
extern const struct bpf_func_proto bpf_get_current_comm_proto; extern const struct bpf_func_proto bpf_get_current_comm_proto;
extern const struct bpf_func_proto bpf_get_stackid_proto; extern const struct bpf_func_proto bpf_get_stackid_proto;
extern const struct bpf_func_proto bpf_get_stack_proto; extern const struct bpf_func_proto bpf_get_stack_proto;
extern const struct bpf_func_proto bpf_get_task_stack_proto;
extern const struct bpf_func_proto bpf_sock_map_update_proto; extern const struct bpf_func_proto bpf_sock_map_update_proto;
extern const struct bpf_func_proto bpf_sock_hash_update_proto; extern const struct bpf_func_proto bpf_sock_hash_update_proto;
extern const struct bpf_func_proto bpf_get_current_cgroup_id_proto; extern const struct bpf_func_proto bpf_get_current_cgroup_id_proto;
...@@ -1629,6 +1650,11 @@ extern const struct bpf_func_proto bpf_ringbuf_reserve_proto; ...@@ -1629,6 +1650,11 @@ extern const struct bpf_func_proto bpf_ringbuf_reserve_proto;
extern const struct bpf_func_proto bpf_ringbuf_submit_proto; extern const struct bpf_func_proto bpf_ringbuf_submit_proto;
extern const struct bpf_func_proto bpf_ringbuf_discard_proto; extern const struct bpf_func_proto bpf_ringbuf_discard_proto;
extern const struct bpf_func_proto bpf_ringbuf_query_proto; extern const struct bpf_func_proto bpf_ringbuf_query_proto;
extern const struct bpf_func_proto bpf_skc_to_tcp6_sock_proto;
extern const struct bpf_func_proto bpf_skc_to_tcp_sock_proto;
extern const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto;
extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto;
extern const struct bpf_func_proto bpf_skc_to_udp6_sock_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);
......
...@@ -379,6 +379,7 @@ struct bpf_verifier_env { ...@@ -379,6 +379,7 @@ struct bpf_verifier_env {
u32 used_map_cnt; /* number of used maps */ u32 used_map_cnt; /* number of used maps */
u32 id_gen; /* used to generate unique reg IDs */ u32 id_gen; /* used to generate unique reg IDs */
bool allow_ptr_leaks; bool allow_ptr_leaks;
bool allow_ptr_to_map_access;
bool bpf_capable; bool bpf_capable;
bool bypass_spec_v1; bool bypass_spec_v1;
bool bypass_spec_v4; bool bypass_spec_v4;
......
...@@ -1244,6 +1244,8 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, ...@@ -1244,6 +1244,8 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
extern struct perf_callchain_entry *perf_callchain(struct perf_event *event, struct pt_regs *regs); extern struct perf_callchain_entry *perf_callchain(struct perf_event *event, struct pt_regs *regs);
extern int get_callchain_buffers(int max_stack); extern int get_callchain_buffers(int max_stack);
extern void put_callchain_buffers(void); extern void put_callchain_buffers(void);
extern struct perf_callchain_entry *get_callchain_entry(int *rctx);
extern void put_callchain_entry(int rctx);
extern int sysctl_perf_event_max_stack; extern int sysctl_perf_event_max_stack;
extern int sysctl_perf_event_max_contexts_per_stack; extern int sysctl_perf_event_max_contexts_per_stack;
......
...@@ -499,6 +499,7 @@ int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from, int pcount, ...@@ -499,6 +499,7 @@ int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from, int pcount,
void tcp_sock_set_cork(struct sock *sk, bool on); void tcp_sock_set_cork(struct sock *sk, bool on);
int tcp_sock_set_keepcnt(struct sock *sk, int val); int tcp_sock_set_keepcnt(struct sock *sk, int val);
int tcp_sock_set_keepidle_locked(struct sock *sk, int val);
int tcp_sock_set_keepidle(struct sock *sk, int val); int tcp_sock_set_keepidle(struct sock *sk, int val);
int tcp_sock_set_keepintvl(struct sock *sk, int val); int tcp_sock_set_keepintvl(struct sock *sk, int val);
void tcp_sock_set_nodelay(struct sock *sk); void tcp_sock_set_nodelay(struct sock *sk);
......
...@@ -879,6 +879,15 @@ static inline void sock_reset_flag(struct sock *sk, enum sock_flags flag) ...@@ -879,6 +879,15 @@ static inline void sock_reset_flag(struct sock *sk, enum sock_flags flag)
__clear_bit(flag, &sk->sk_flags); __clear_bit(flag, &sk->sk_flags);
} }
static inline void sock_valbool_flag(struct sock *sk, enum sock_flags bit,
int valbool)
{
if (valbool)
sock_set_flag(sk, bit);
else
sock_reset_flag(sk, bit);
}
static inline bool sock_flag(const struct sock *sk, enum sock_flags flag) static inline bool sock_flag(const struct sock *sk, enum sock_flags flag)
{ {
return test_bit(flag, &sk->sk_flags); return test_bit(flag, &sk->sk_flags);
......
...@@ -1945,6 +1945,7 @@ struct tcp_iter_state { ...@@ -1945,6 +1945,7 @@ struct tcp_iter_state {
struct seq_net_private p; struct seq_net_private p;
enum tcp_seq_states state; enum tcp_seq_states state;
struct sock *syn_wait_sk; struct sock *syn_wait_sk;
struct tcp_seq_afinfo *bpf_seq_afinfo;
int bucket, offset, sbucket, num; int bucket, offset, sbucket, num;
loff_t last_pos; loff_t last_pos;
}; };
......
...@@ -447,6 +447,7 @@ struct udp_seq_afinfo { ...@@ -447,6 +447,7 @@ struct udp_seq_afinfo {
struct udp_iter_state { struct udp_iter_state {
struct seq_net_private p; struct seq_net_private p;
int bucket; int bucket;
struct udp_seq_afinfo *bpf_seq_afinfo;
}; };
void *udp_seq_start(struct seq_file *seq, loff_t *pos); void *udp_seq_start(struct seq_file *seq, loff_t *pos);
......
此差异已折叠。
...@@ -386,13 +386,6 @@ static void array_map_free(struct bpf_map *map) ...@@ -386,13 +386,6 @@ static void array_map_free(struct bpf_map *map)
{ {
struct bpf_array *array = container_of(map, struct bpf_array, map); struct bpf_array *array = container_of(map, struct bpf_array, map);
/* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0,
* so the programs (can be more than one that used this map) were
* disconnected from events. Wait for outstanding programs to complete
* and free the array
*/
synchronize_rcu();
if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY) if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
bpf_array_free_percpu(array); bpf_array_free_percpu(array);
...@@ -494,6 +487,7 @@ static int array_map_mmap(struct bpf_map *map, struct vm_area_struct *vma) ...@@ -494,6 +487,7 @@ static int array_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
vma->vm_pgoff + pgoff); vma->vm_pgoff + pgoff);
} }
static int array_map_btf_id;
const struct bpf_map_ops array_map_ops = { const struct bpf_map_ops array_map_ops = {
.map_alloc_check = array_map_alloc_check, .map_alloc_check = array_map_alloc_check,
.map_alloc = array_map_alloc, .map_alloc = array_map_alloc,
...@@ -510,8 +504,11 @@ const struct bpf_map_ops array_map_ops = { ...@@ -510,8 +504,11 @@ const struct bpf_map_ops array_map_ops = {
.map_check_btf = array_map_check_btf, .map_check_btf = array_map_check_btf,
.map_lookup_batch = generic_map_lookup_batch, .map_lookup_batch = generic_map_lookup_batch,
.map_update_batch = generic_map_update_batch, .map_update_batch = generic_map_update_batch,
.map_btf_name = "bpf_array",
.map_btf_id = &array_map_btf_id,
}; };
static int percpu_array_map_btf_id;
const struct bpf_map_ops percpu_array_map_ops = { const struct bpf_map_ops percpu_array_map_ops = {
.map_alloc_check = array_map_alloc_check, .map_alloc_check = array_map_alloc_check,
.map_alloc = array_map_alloc, .map_alloc = array_map_alloc,
...@@ -522,6 +519,8 @@ const struct bpf_map_ops percpu_array_map_ops = { ...@@ -522,6 +519,8 @@ const struct bpf_map_ops percpu_array_map_ops = {
.map_delete_elem = array_map_delete_elem, .map_delete_elem = array_map_delete_elem,
.map_seq_show_elem = percpu_array_map_seq_show_elem, .map_seq_show_elem = percpu_array_map_seq_show_elem,
.map_check_btf = array_map_check_btf, .map_check_btf = array_map_check_btf,
.map_btf_name = "bpf_array",
.map_btf_id = &percpu_array_map_btf_id,
}; };
static int fd_array_map_alloc_check(union bpf_attr *attr) static int fd_array_map_alloc_check(union bpf_attr *attr)
...@@ -540,8 +539,6 @@ static void fd_array_map_free(struct bpf_map *map) ...@@ -540,8 +539,6 @@ static void fd_array_map_free(struct bpf_map *map)
struct bpf_array *array = container_of(map, struct bpf_array, map); struct bpf_array *array = container_of(map, struct bpf_array, map);
int i; int i;
synchronize_rcu();
/* make sure it's empty */ /* make sure it's empty */
for (i = 0; i < array->map.max_entries; i++) for (i = 0; i < array->map.max_entries; i++)
BUG_ON(array->ptrs[i] != NULL); BUG_ON(array->ptrs[i] != NULL);
...@@ -868,6 +865,7 @@ static void prog_array_map_free(struct bpf_map *map) ...@@ -868,6 +865,7 @@ static void prog_array_map_free(struct bpf_map *map)
fd_array_map_free(map); fd_array_map_free(map);
} }
static int prog_array_map_btf_id;
const struct bpf_map_ops prog_array_map_ops = { const struct bpf_map_ops prog_array_map_ops = {
.map_alloc_check = fd_array_map_alloc_check, .map_alloc_check = fd_array_map_alloc_check,
.map_alloc = prog_array_map_alloc, .map_alloc = prog_array_map_alloc,
...@@ -883,6 +881,8 @@ const struct bpf_map_ops prog_array_map_ops = { ...@@ -883,6 +881,8 @@ const struct bpf_map_ops prog_array_map_ops = {
.map_fd_sys_lookup_elem = prog_fd_array_sys_lookup_elem, .map_fd_sys_lookup_elem = prog_fd_array_sys_lookup_elem,
.map_release_uref = prog_array_map_clear, .map_release_uref = prog_array_map_clear,
.map_seq_show_elem = prog_array_map_seq_show_elem, .map_seq_show_elem = prog_array_map_seq_show_elem,
.map_btf_name = "bpf_array",
.map_btf_id = &prog_array_map_btf_id,
}; };
static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file, static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file,
...@@ -961,6 +961,7 @@ static void perf_event_fd_array_release(struct bpf_map *map, ...@@ -961,6 +961,7 @@ static void perf_event_fd_array_release(struct bpf_map *map,
rcu_read_unlock(); rcu_read_unlock();
} }
static int perf_event_array_map_btf_id;
const struct bpf_map_ops perf_event_array_map_ops = { const struct bpf_map_ops perf_event_array_map_ops = {
.map_alloc_check = fd_array_map_alloc_check, .map_alloc_check = fd_array_map_alloc_check,
.map_alloc = array_map_alloc, .map_alloc = array_map_alloc,
...@@ -972,6 +973,8 @@ const struct bpf_map_ops perf_event_array_map_ops = { ...@@ -972,6 +973,8 @@ const struct bpf_map_ops perf_event_array_map_ops = {
.map_fd_put_ptr = perf_event_fd_array_put_ptr, .map_fd_put_ptr = perf_event_fd_array_put_ptr,
.map_release = perf_event_fd_array_release, .map_release = perf_event_fd_array_release,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_array",
.map_btf_id = &perf_event_array_map_btf_id,
}; };
#ifdef CONFIG_CGROUPS #ifdef CONFIG_CGROUPS
...@@ -994,6 +997,7 @@ static void cgroup_fd_array_free(struct bpf_map *map) ...@@ -994,6 +997,7 @@ static void cgroup_fd_array_free(struct bpf_map *map)
fd_array_map_free(map); fd_array_map_free(map);
} }
static int cgroup_array_map_btf_id;
const struct bpf_map_ops cgroup_array_map_ops = { const struct bpf_map_ops cgroup_array_map_ops = {
.map_alloc_check = fd_array_map_alloc_check, .map_alloc_check = fd_array_map_alloc_check,
.map_alloc = array_map_alloc, .map_alloc = array_map_alloc,
...@@ -1004,6 +1008,8 @@ const struct bpf_map_ops cgroup_array_map_ops = { ...@@ -1004,6 +1008,8 @@ const struct bpf_map_ops cgroup_array_map_ops = {
.map_fd_get_ptr = cgroup_fd_array_get_ptr, .map_fd_get_ptr = cgroup_fd_array_get_ptr,
.map_fd_put_ptr = cgroup_fd_array_put_ptr, .map_fd_put_ptr = cgroup_fd_array_put_ptr,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_array",
.map_btf_id = &cgroup_array_map_btf_id,
}; };
#endif #endif
...@@ -1077,6 +1083,7 @@ static u32 array_of_map_gen_lookup(struct bpf_map *map, ...@@ -1077,6 +1083,7 @@ static u32 array_of_map_gen_lookup(struct bpf_map *map,
return insn - insn_buf; return insn - insn_buf;
} }
static int array_of_maps_map_btf_id;
const struct bpf_map_ops array_of_maps_map_ops = { const struct bpf_map_ops array_of_maps_map_ops = {
.map_alloc_check = fd_array_map_alloc_check, .map_alloc_check = fd_array_map_alloc_check,
.map_alloc = array_of_map_alloc, .map_alloc = array_of_map_alloc,
...@@ -1089,4 +1096,6 @@ const struct bpf_map_ops array_of_maps_map_ops = { ...@@ -1089,4 +1096,6 @@ const struct bpf_map_ops array_of_maps_map_ops = {
.map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem, .map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem,
.map_gen_lookup = array_of_map_gen_lookup, .map_gen_lookup = array_of_map_gen_lookup,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_array",
.map_btf_id = &array_of_maps_map_btf_id,
}; };
...@@ -611,6 +611,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) ...@@ -611,6 +611,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
return map; return map;
} }
static int bpf_struct_ops_map_btf_id;
const struct bpf_map_ops bpf_struct_ops_map_ops = { const struct bpf_map_ops bpf_struct_ops_map_ops = {
.map_alloc_check = bpf_struct_ops_map_alloc_check, .map_alloc_check = bpf_struct_ops_map_alloc_check,
.map_alloc = bpf_struct_ops_map_alloc, .map_alloc = bpf_struct_ops_map_alloc,
...@@ -620,6 +621,8 @@ const struct bpf_map_ops bpf_struct_ops_map_ops = { ...@@ -620,6 +621,8 @@ const struct bpf_map_ops bpf_struct_ops_map_ops = {
.map_delete_elem = bpf_struct_ops_map_delete_elem, .map_delete_elem = bpf_struct_ops_map_delete_elem,
.map_update_elem = bpf_struct_ops_map_update_elem, .map_update_elem = bpf_struct_ops_map_update_elem,
.map_seq_show_elem = bpf_struct_ops_map_seq_show_elem, .map_seq_show_elem = bpf_struct_ops_map_seq_show_elem,
.map_btf_name = "bpf_struct_ops_map",
.map_btf_id = &bpf_struct_ops_map_btf_id,
}; };
/* "const void *" because some subsystem is /* "const void *" because some subsystem is
......
...@@ -3571,6 +3571,41 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, struct btf *btf, ...@@ -3571,6 +3571,41 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, struct btf *btf,
return ctx_type; return ctx_type;
} }
static const struct bpf_map_ops * const btf_vmlinux_map_ops[] = {
#define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
#define BPF_LINK_TYPE(_id, _name)
#define BPF_MAP_TYPE(_id, _ops) \
[_id] = &_ops,
#include <linux/bpf_types.h>
#undef BPF_PROG_TYPE
#undef BPF_LINK_TYPE
#undef BPF_MAP_TYPE
};
static int btf_vmlinux_map_ids_init(const struct btf *btf,
struct bpf_verifier_log *log)
{
const struct bpf_map_ops *ops;
int i, btf_id;
for (i = 0; i < ARRAY_SIZE(btf_vmlinux_map_ops); ++i) {
ops = btf_vmlinux_map_ops[i];
if (!ops || (!ops->map_btf_name && !ops->map_btf_id))
continue;
if (!ops->map_btf_name || !ops->map_btf_id) {
bpf_log(log, "map type %d is misconfigured\n", i);
return -EINVAL;
}
btf_id = btf_find_by_name_kind(btf, ops->map_btf_name,
BTF_KIND_STRUCT);
if (btf_id < 0)
return btf_id;
*ops->map_btf_id = btf_id;
}
return 0;
}
static int btf_translate_to_vmlinux(struct bpf_verifier_log *log, static int btf_translate_to_vmlinux(struct bpf_verifier_log *log,
struct btf *btf, struct btf *btf,
const struct btf_type *t, const struct btf_type *t,
...@@ -3591,7 +3626,7 @@ struct btf *btf_parse_vmlinux(void) ...@@ -3591,7 +3626,7 @@ struct btf *btf_parse_vmlinux(void)
struct btf_verifier_env *env = NULL; struct btf_verifier_env *env = NULL;
struct bpf_verifier_log *log; struct bpf_verifier_log *log;
struct btf *btf = NULL; struct btf *btf = NULL;
int err, i; int err, btf_id;
env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN); env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN);
if (!env) if (!env)
...@@ -3625,26 +3660,21 @@ struct btf *btf_parse_vmlinux(void) ...@@ -3625,26 +3660,21 @@ struct btf *btf_parse_vmlinux(void)
goto errout; goto errout;
/* find struct bpf_ctx_convert for type checking later */ /* find struct bpf_ctx_convert for type checking later */
for (i = 1; i <= btf->nr_types; i++) { btf_id = btf_find_by_name_kind(btf, "bpf_ctx_convert", BTF_KIND_STRUCT);
const struct btf_type *t; if (btf_id < 0) {
const char *tname; err = btf_id;
t = btf_type_by_id(btf, i);
if (!__btf_type_is_struct(t))
continue;
tname = __btf_name_by_offset(btf, t->name_off);
if (!strcmp(tname, "bpf_ctx_convert")) {
/* btf_parse_vmlinux() runs under bpf_verifier_lock */
bpf_ctx_convert.t = t;
break;
}
}
if (i > btf->nr_types) {
err = -ENOENT;
goto errout; goto errout;
} }
/* btf_parse_vmlinux() runs under bpf_verifier_lock */
bpf_ctx_convert.t = btf_type_by_id(btf, btf_id);
/* find bpf map structs for map_ptr access checking */
err = btf_vmlinux_map_ids_init(btf, log);
if (err < 0)
goto errout;
bpf_struct_ops_init(btf, log); bpf_struct_ops_init(btf, log);
init_btf_sock_ids(btf);
btf_verifier_env_free(env); btf_verifier_env_free(env);
refcount_set(&btf->refcnt, 1); refcount_set(&btf->refcnt, 1);
......
...@@ -543,6 +543,7 @@ static int cpu_map_get_next_key(struct bpf_map *map, void *key, void *next_key) ...@@ -543,6 +543,7 @@ static int cpu_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
return 0; return 0;
} }
static int cpu_map_btf_id;
const struct bpf_map_ops cpu_map_ops = { const struct bpf_map_ops cpu_map_ops = {
.map_alloc = cpu_map_alloc, .map_alloc = cpu_map_alloc,
.map_free = cpu_map_free, .map_free = cpu_map_free,
...@@ -551,6 +552,8 @@ const struct bpf_map_ops cpu_map_ops = { ...@@ -551,6 +552,8 @@ const struct bpf_map_ops cpu_map_ops = {
.map_lookup_elem = cpu_map_lookup_elem, .map_lookup_elem = cpu_map_lookup_elem,
.map_get_next_key = cpu_map_get_next_key, .map_get_next_key = cpu_map_get_next_key,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_cpu_map",
.map_btf_id = &cpu_map_btf_id,
}; };
static int bq_flush_to_queue(struct xdp_bulk_queue *bq) static int bq_flush_to_queue(struct xdp_bulk_queue *bq)
......
...@@ -749,6 +749,7 @@ static int dev_map_hash_update_elem(struct bpf_map *map, void *key, void *value, ...@@ -749,6 +749,7 @@ static int dev_map_hash_update_elem(struct bpf_map *map, void *key, void *value,
map, key, value, map_flags); map, key, value, map_flags);
} }
static int dev_map_btf_id;
const struct bpf_map_ops dev_map_ops = { const struct bpf_map_ops dev_map_ops = {
.map_alloc = dev_map_alloc, .map_alloc = dev_map_alloc,
.map_free = dev_map_free, .map_free = dev_map_free,
...@@ -757,8 +758,11 @@ const struct bpf_map_ops dev_map_ops = { ...@@ -757,8 +758,11 @@ const struct bpf_map_ops dev_map_ops = {
.map_update_elem = dev_map_update_elem, .map_update_elem = dev_map_update_elem,
.map_delete_elem = dev_map_delete_elem, .map_delete_elem = dev_map_delete_elem,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_dtab",
.map_btf_id = &dev_map_btf_id,
}; };
static int dev_map_hash_map_btf_id;
const struct bpf_map_ops dev_map_hash_ops = { const struct bpf_map_ops dev_map_hash_ops = {
.map_alloc = dev_map_alloc, .map_alloc = dev_map_alloc,
.map_free = dev_map_free, .map_free = dev_map_free,
...@@ -767,6 +771,8 @@ const struct bpf_map_ops dev_map_hash_ops = { ...@@ -767,6 +771,8 @@ const struct bpf_map_ops dev_map_hash_ops = {
.map_update_elem = dev_map_hash_update_elem, .map_update_elem = dev_map_hash_update_elem,
.map_delete_elem = dev_map_hash_delete_elem, .map_delete_elem = dev_map_hash_delete_elem,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_dtab",
.map_btf_id = &dev_map_hash_map_btf_id,
}; };
static void dev_map_hash_remove_netdev(struct bpf_dtab *dtab, static void dev_map_hash_remove_netdev(struct bpf_dtab *dtab,
......
...@@ -1290,12 +1290,10 @@ static void htab_map_free(struct bpf_map *map) ...@@ -1290,12 +1290,10 @@ static void htab_map_free(struct bpf_map *map)
{ {
struct bpf_htab *htab = container_of(map, struct bpf_htab, map); struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
/* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0, /* bpf_free_used_maps() or close(map_fd) will trigger this map_free callback.
* so the programs (can be more than one that used this map) were * bpf_free_used_maps() is called after bpf prog is no longer executing.
* disconnected from events. Wait for outstanding critical sections in * There is no need to synchronize_rcu() here to protect map elements.
* these programs to complete
*/ */
synchronize_rcu();
/* some of free_htab_elem() callbacks for elements of this map may /* some of free_htab_elem() callbacks for elements of this map may
* not have executed. Wait for them. * not have executed. Wait for them.
...@@ -1614,6 +1612,7 @@ htab_lru_map_lookup_and_delete_batch(struct bpf_map *map, ...@@ -1614,6 +1612,7 @@ htab_lru_map_lookup_and_delete_batch(struct bpf_map *map,
true, false); true, false);
} }
static int htab_map_btf_id;
const struct bpf_map_ops htab_map_ops = { const struct bpf_map_ops htab_map_ops = {
.map_alloc_check = htab_map_alloc_check, .map_alloc_check = htab_map_alloc_check,
.map_alloc = htab_map_alloc, .map_alloc = htab_map_alloc,
...@@ -1625,8 +1624,11 @@ const struct bpf_map_ops htab_map_ops = { ...@@ -1625,8 +1624,11 @@ const struct bpf_map_ops htab_map_ops = {
.map_gen_lookup = htab_map_gen_lookup, .map_gen_lookup = htab_map_gen_lookup,
.map_seq_show_elem = htab_map_seq_show_elem, .map_seq_show_elem = htab_map_seq_show_elem,
BATCH_OPS(htab), BATCH_OPS(htab),
.map_btf_name = "bpf_htab",
.map_btf_id = &htab_map_btf_id,
}; };
static int htab_lru_map_btf_id;
const struct bpf_map_ops htab_lru_map_ops = { const struct bpf_map_ops htab_lru_map_ops = {
.map_alloc_check = htab_map_alloc_check, .map_alloc_check = htab_map_alloc_check,
.map_alloc = htab_map_alloc, .map_alloc = htab_map_alloc,
...@@ -1639,6 +1641,8 @@ const struct bpf_map_ops htab_lru_map_ops = { ...@@ -1639,6 +1641,8 @@ const struct bpf_map_ops htab_lru_map_ops = {
.map_gen_lookup = htab_lru_map_gen_lookup, .map_gen_lookup = htab_lru_map_gen_lookup,
.map_seq_show_elem = htab_map_seq_show_elem, .map_seq_show_elem = htab_map_seq_show_elem,
BATCH_OPS(htab_lru), BATCH_OPS(htab_lru),
.map_btf_name = "bpf_htab",
.map_btf_id = &htab_lru_map_btf_id,
}; };
/* Called from eBPF program */ /* Called from eBPF program */
...@@ -1743,6 +1747,7 @@ static void htab_percpu_map_seq_show_elem(struct bpf_map *map, void *key, ...@@ -1743,6 +1747,7 @@ static void htab_percpu_map_seq_show_elem(struct bpf_map *map, void *key,
rcu_read_unlock(); rcu_read_unlock();
} }
static int htab_percpu_map_btf_id;
const struct bpf_map_ops htab_percpu_map_ops = { const struct bpf_map_ops htab_percpu_map_ops = {
.map_alloc_check = htab_map_alloc_check, .map_alloc_check = htab_map_alloc_check,
.map_alloc = htab_map_alloc, .map_alloc = htab_map_alloc,
...@@ -1753,8 +1758,11 @@ const struct bpf_map_ops htab_percpu_map_ops = { ...@@ -1753,8 +1758,11 @@ const struct bpf_map_ops htab_percpu_map_ops = {
.map_delete_elem = htab_map_delete_elem, .map_delete_elem = htab_map_delete_elem,
.map_seq_show_elem = htab_percpu_map_seq_show_elem, .map_seq_show_elem = htab_percpu_map_seq_show_elem,
BATCH_OPS(htab_percpu), BATCH_OPS(htab_percpu),
.map_btf_name = "bpf_htab",
.map_btf_id = &htab_percpu_map_btf_id,
}; };
static int htab_lru_percpu_map_btf_id;
const struct bpf_map_ops htab_lru_percpu_map_ops = { const struct bpf_map_ops htab_lru_percpu_map_ops = {
.map_alloc_check = htab_map_alloc_check, .map_alloc_check = htab_map_alloc_check,
.map_alloc = htab_map_alloc, .map_alloc = htab_map_alloc,
...@@ -1765,6 +1773,8 @@ const struct bpf_map_ops htab_lru_percpu_map_ops = { ...@@ -1765,6 +1773,8 @@ const struct bpf_map_ops htab_lru_percpu_map_ops = {
.map_delete_elem = htab_lru_map_delete_elem, .map_delete_elem = htab_lru_map_delete_elem,
.map_seq_show_elem = htab_percpu_map_seq_show_elem, .map_seq_show_elem = htab_percpu_map_seq_show_elem,
BATCH_OPS(htab_lru_percpu), BATCH_OPS(htab_lru_percpu),
.map_btf_name = "bpf_htab",
.map_btf_id = &htab_lru_percpu_map_btf_id,
}; };
static int fd_htab_map_alloc_check(union bpf_attr *attr) static int fd_htab_map_alloc_check(union bpf_attr *attr)
...@@ -1887,6 +1897,7 @@ static void htab_of_map_free(struct bpf_map *map) ...@@ -1887,6 +1897,7 @@ static void htab_of_map_free(struct bpf_map *map)
fd_htab_map_free(map); fd_htab_map_free(map);
} }
static int htab_of_maps_map_btf_id;
const struct bpf_map_ops htab_of_maps_map_ops = { const struct bpf_map_ops htab_of_maps_map_ops = {
.map_alloc_check = fd_htab_map_alloc_check, .map_alloc_check = fd_htab_map_alloc_check,
.map_alloc = htab_of_map_alloc, .map_alloc = htab_of_map_alloc,
...@@ -1899,4 +1910,6 @@ const struct bpf_map_ops htab_of_maps_map_ops = { ...@@ -1899,4 +1910,6 @@ const struct bpf_map_ops htab_of_maps_map_ops = {
.map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem, .map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem,
.map_gen_lookup = htab_of_map_gen_lookup, .map_gen_lookup = htab_of_map_gen_lookup,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_htab",
.map_btf_id = &htab_of_maps_map_btf_id,
}; };
...@@ -409,6 +409,7 @@ static void cgroup_storage_seq_show_elem(struct bpf_map *map, void *_key, ...@@ -409,6 +409,7 @@ static void cgroup_storage_seq_show_elem(struct bpf_map *map, void *_key,
rcu_read_unlock(); rcu_read_unlock();
} }
static int cgroup_storage_map_btf_id;
const struct bpf_map_ops cgroup_storage_map_ops = { const struct bpf_map_ops cgroup_storage_map_ops = {
.map_alloc = cgroup_storage_map_alloc, .map_alloc = cgroup_storage_map_alloc,
.map_free = cgroup_storage_map_free, .map_free = cgroup_storage_map_free,
...@@ -418,6 +419,8 @@ const struct bpf_map_ops cgroup_storage_map_ops = { ...@@ -418,6 +419,8 @@ const struct bpf_map_ops cgroup_storage_map_ops = {
.map_delete_elem = cgroup_storage_delete_elem, .map_delete_elem = cgroup_storage_delete_elem,
.map_check_btf = cgroup_storage_check_btf, .map_check_btf = cgroup_storage_check_btf,
.map_seq_show_elem = cgroup_storage_seq_show_elem, .map_seq_show_elem = cgroup_storage_seq_show_elem,
.map_btf_name = "bpf_cgroup_storage_map",
.map_btf_id = &cgroup_storage_map_btf_id,
}; };
int bpf_cgroup_storage_assign(struct bpf_prog_aux *aux, struct bpf_map *_map) int bpf_cgroup_storage_assign(struct bpf_prog_aux *aux, struct bpf_map *_map)
......
...@@ -589,11 +589,6 @@ static void trie_free(struct bpf_map *map) ...@@ -589,11 +589,6 @@ static void trie_free(struct bpf_map *map)
struct lpm_trie_node __rcu **slot; struct lpm_trie_node __rcu **slot;
struct lpm_trie_node *node; struct lpm_trie_node *node;
/* Wait for outstanding programs to complete
* update/lookup/delete/get_next_key and free the trie.
*/
synchronize_rcu();
/* Always start at the root and walk down to a node that has no /* Always start at the root and walk down to a node that has no
* children. Then free that node, nullify its reference in the parent * children. Then free that node, nullify its reference in the parent
* and start over. * and start over.
...@@ -735,6 +730,7 @@ static int trie_check_btf(const struct bpf_map *map, ...@@ -735,6 +730,7 @@ static int trie_check_btf(const struct bpf_map *map,
-EINVAL : 0; -EINVAL : 0;
} }
static int trie_map_btf_id;
const struct bpf_map_ops trie_map_ops = { const struct bpf_map_ops trie_map_ops = {
.map_alloc = trie_alloc, .map_alloc = trie_alloc,
.map_free = trie_free, .map_free = trie_free,
...@@ -743,4 +739,6 @@ const struct bpf_map_ops trie_map_ops = { ...@@ -743,4 +739,6 @@ const struct bpf_map_ops trie_map_ops = {
.map_update_elem = trie_update_elem, .map_update_elem = trie_update_elem,
.map_delete_elem = trie_delete_elem, .map_delete_elem = trie_delete_elem,
.map_check_btf = trie_check_btf, .map_check_btf = trie_check_btf,
.map_btf_name = "lpm_trie",
.map_btf_id = &trie_map_btf_id,
}; };
...@@ -101,13 +101,6 @@ static void queue_stack_map_free(struct bpf_map *map) ...@@ -101,13 +101,6 @@ static void queue_stack_map_free(struct bpf_map *map)
{ {
struct bpf_queue_stack *qs = bpf_queue_stack(map); struct bpf_queue_stack *qs = bpf_queue_stack(map);
/* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0,
* so the programs (can be more than one that used this map) were
* disconnected from events. Wait for outstanding critical sections in
* these programs to complete
*/
synchronize_rcu();
bpf_map_area_free(qs); bpf_map_area_free(qs);
} }
...@@ -262,6 +255,7 @@ static int queue_stack_map_get_next_key(struct bpf_map *map, void *key, ...@@ -262,6 +255,7 @@ static int queue_stack_map_get_next_key(struct bpf_map *map, void *key,
return -EINVAL; return -EINVAL;
} }
static int queue_map_btf_id;
const struct bpf_map_ops queue_map_ops = { const struct bpf_map_ops queue_map_ops = {
.map_alloc_check = queue_stack_map_alloc_check, .map_alloc_check = queue_stack_map_alloc_check,
.map_alloc = queue_stack_map_alloc, .map_alloc = queue_stack_map_alloc,
...@@ -273,8 +267,11 @@ const struct bpf_map_ops queue_map_ops = { ...@@ -273,8 +267,11 @@ const struct bpf_map_ops queue_map_ops = {
.map_pop_elem = queue_map_pop_elem, .map_pop_elem = queue_map_pop_elem,
.map_peek_elem = queue_map_peek_elem, .map_peek_elem = queue_map_peek_elem,
.map_get_next_key = queue_stack_map_get_next_key, .map_get_next_key = queue_stack_map_get_next_key,
.map_btf_name = "bpf_queue_stack",
.map_btf_id = &queue_map_btf_id,
}; };
static int stack_map_btf_id;
const struct bpf_map_ops stack_map_ops = { const struct bpf_map_ops stack_map_ops = {
.map_alloc_check = queue_stack_map_alloc_check, .map_alloc_check = queue_stack_map_alloc_check,
.map_alloc = queue_stack_map_alloc, .map_alloc = queue_stack_map_alloc,
...@@ -286,4 +283,6 @@ const struct bpf_map_ops stack_map_ops = { ...@@ -286,4 +283,6 @@ const struct bpf_map_ops stack_map_ops = {
.map_pop_elem = stack_map_pop_elem, .map_pop_elem = stack_map_pop_elem,
.map_peek_elem = stack_map_peek_elem, .map_peek_elem = stack_map_peek_elem,
.map_get_next_key = queue_stack_map_get_next_key, .map_get_next_key = queue_stack_map_get_next_key,
.map_btf_name = "bpf_queue_stack",
.map_btf_id = &stack_map_btf_id,
}; };
...@@ -96,8 +96,6 @@ static void reuseport_array_free(struct bpf_map *map) ...@@ -96,8 +96,6 @@ static void reuseport_array_free(struct bpf_map *map)
struct sock *sk; struct sock *sk;
u32 i; u32 i;
synchronize_rcu();
/* /*
* ops->map_*_elem() will not be able to access this * ops->map_*_elem() will not be able to access this
* array now. Hence, this function only races with * array now. Hence, this function only races with
...@@ -345,6 +343,7 @@ static int reuseport_array_get_next_key(struct bpf_map *map, void *key, ...@@ -345,6 +343,7 @@ static int reuseport_array_get_next_key(struct bpf_map *map, void *key,
return 0; return 0;
} }
static int reuseport_array_map_btf_id;
const struct bpf_map_ops reuseport_array_ops = { const struct bpf_map_ops reuseport_array_ops = {
.map_alloc_check = reuseport_array_alloc_check, .map_alloc_check = reuseport_array_alloc_check,
.map_alloc = reuseport_array_alloc, .map_alloc = reuseport_array_alloc,
...@@ -352,4 +351,6 @@ const struct bpf_map_ops reuseport_array_ops = { ...@@ -352,4 +351,6 @@ const struct bpf_map_ops reuseport_array_ops = {
.map_lookup_elem = reuseport_array_lookup_elem, .map_lookup_elem = reuseport_array_lookup_elem,
.map_get_next_key = reuseport_array_get_next_key, .map_get_next_key = reuseport_array_get_next_key,
.map_delete_elem = reuseport_array_delete_elem, .map_delete_elem = reuseport_array_delete_elem,
.map_btf_name = "reuseport_array",
.map_btf_id = &reuseport_array_map_btf_id,
}; };
...@@ -215,13 +215,6 @@ static void ringbuf_map_free(struct bpf_map *map) ...@@ -215,13 +215,6 @@ static void ringbuf_map_free(struct bpf_map *map)
{ {
struct bpf_ringbuf_map *rb_map; struct bpf_ringbuf_map *rb_map;
/* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0,
* so the programs (can be more than one that used this map) were
* disconnected from events. Wait for outstanding critical sections in
* these programs to complete
*/
synchronize_rcu();
rb_map = container_of(map, struct bpf_ringbuf_map, map); rb_map = container_of(map, struct bpf_ringbuf_map, map);
bpf_ringbuf_free(rb_map->rb); bpf_ringbuf_free(rb_map->rb);
kfree(rb_map); kfree(rb_map);
...@@ -294,6 +287,7 @@ static __poll_t ringbuf_map_poll(struct bpf_map *map, struct file *filp, ...@@ -294,6 +287,7 @@ static __poll_t ringbuf_map_poll(struct bpf_map *map, struct file *filp,
return 0; return 0;
} }
static int ringbuf_map_btf_id;
const struct bpf_map_ops ringbuf_map_ops = { const struct bpf_map_ops ringbuf_map_ops = {
.map_alloc = ringbuf_map_alloc, .map_alloc = ringbuf_map_alloc,
.map_free = ringbuf_map_free, .map_free = ringbuf_map_free,
...@@ -303,6 +297,8 @@ const struct bpf_map_ops ringbuf_map_ops = { ...@@ -303,6 +297,8 @@ const struct bpf_map_ops ringbuf_map_ops = {
.map_update_elem = ringbuf_map_update_elem, .map_update_elem = ringbuf_map_update_elem,
.map_delete_elem = ringbuf_map_delete_elem, .map_delete_elem = ringbuf_map_delete_elem,
.map_get_next_key = ringbuf_map_get_next_key, .map_get_next_key = ringbuf_map_get_next_key,
.map_btf_name = "bpf_ringbuf_map",
.map_btf_id = &ringbuf_map_btf_id,
}; };
/* Given pointer to ring buffer record metadata and struct bpf_ringbuf itself, /* Given pointer to ring buffer record metadata and struct bpf_ringbuf itself,
......
...@@ -348,6 +348,44 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, ...@@ -348,6 +348,44 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
} }
} }
static struct perf_callchain_entry *
get_callchain_entry_for_task(struct task_struct *task, u32 init_nr)
{
#ifdef CONFIG_STACKTRACE
struct perf_callchain_entry *entry;
int rctx;
entry = get_callchain_entry(&rctx);
if (!entry)
return NULL;
entry->nr = init_nr +
stack_trace_save_tsk(task, (unsigned long *)(entry->ip + init_nr),
sysctl_perf_event_max_stack - init_nr, 0);
/* stack_trace_save_tsk() works on unsigned long array, while
* perf_callchain_entry uses u64 array. For 32-bit systems, it is
* necessary to fix this mismatch.
*/
if (__BITS_PER_LONG != 64) {
unsigned long *from = (unsigned long *) entry->ip;
u64 *to = entry->ip;
int i;
/* copy data from the end to avoid using extra buffer */
for (i = entry->nr - 1; i >= (int)init_nr; i--)
to[i] = (u64)(from[i]);
}
put_callchain_entry(rctx);
return entry;
#else /* CONFIG_STACKTRACE */
return NULL;
#endif
}
BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map, BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
u64, flags) u64, flags)
{ {
...@@ -448,8 +486,8 @@ const struct bpf_func_proto bpf_get_stackid_proto = { ...@@ -448,8 +486,8 @@ const struct bpf_func_proto bpf_get_stackid_proto = {
.arg3_type = ARG_ANYTHING, .arg3_type = ARG_ANYTHING,
}; };
BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size, static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
u64, flags) void *buf, u32 size, u64 flags)
{ {
u32 init_nr, trace_nr, copy_len, elem_size, num_elem; u32 init_nr, trace_nr, copy_len, elem_size, num_elem;
bool user_build_id = flags & BPF_F_USER_BUILD_ID; bool user_build_id = flags & BPF_F_USER_BUILD_ID;
...@@ -471,13 +509,22 @@ BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size, ...@@ -471,13 +509,22 @@ BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size,
if (unlikely(size % elem_size)) if (unlikely(size % elem_size))
goto clear; goto clear;
/* cannot get valid user stack for task without user_mode regs */
if (task && user && !user_mode(regs))
goto err_fault;
num_elem = size / elem_size; num_elem = size / elem_size;
if (sysctl_perf_event_max_stack < num_elem) if (sysctl_perf_event_max_stack < num_elem)
init_nr = 0; init_nr = 0;
else else
init_nr = sysctl_perf_event_max_stack - num_elem; init_nr = sysctl_perf_event_max_stack - num_elem;
trace = get_perf_callchain(regs, init_nr, kernel, user,
sysctl_perf_event_max_stack, false, false); if (kernel && task)
trace = get_callchain_entry_for_task(task, init_nr);
else
trace = get_perf_callchain(regs, init_nr, kernel, user,
sysctl_perf_event_max_stack,
false, false);
if (unlikely(!trace)) if (unlikely(!trace))
goto err_fault; goto err_fault;
...@@ -505,6 +552,12 @@ BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size, ...@@ -505,6 +552,12 @@ BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size,
return err; return err;
} }
BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size,
u64, flags)
{
return __bpf_get_stack(regs, NULL, buf, size, flags);
}
const struct bpf_func_proto bpf_get_stack_proto = { const struct bpf_func_proto bpf_get_stack_proto = {
.func = bpf_get_stack, .func = bpf_get_stack,
.gpl_only = true, .gpl_only = true,
...@@ -515,6 +568,26 @@ const struct bpf_func_proto bpf_get_stack_proto = { ...@@ -515,6 +568,26 @@ const struct bpf_func_proto bpf_get_stack_proto = {
.arg4_type = ARG_ANYTHING, .arg4_type = ARG_ANYTHING,
}; };
BPF_CALL_4(bpf_get_task_stack, struct task_struct *, task, void *, buf,
u32, size, u64, flags)
{
struct pt_regs *regs = task_pt_regs(task);
return __bpf_get_stack(regs, task, buf, size, flags);
}
static int bpf_get_task_stack_btf_ids[5];
const struct bpf_func_proto bpf_get_task_stack_proto = {
.func = bpf_get_task_stack,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_CONST_SIZE_OR_ZERO,
.arg4_type = ARG_ANYTHING,
.btf_id = bpf_get_task_stack_btf_ids,
};
/* Called from eBPF program */ /* Called from eBPF program */
static void *stack_map_lookup_elem(struct bpf_map *map, void *key) static void *stack_map_lookup_elem(struct bpf_map *map, void *key)
{ {
...@@ -604,15 +677,13 @@ static void stack_map_free(struct bpf_map *map) ...@@ -604,15 +677,13 @@ static void stack_map_free(struct bpf_map *map)
{ {
struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map); struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
/* wait for bpf programs to complete before freeing stack map */
synchronize_rcu();
bpf_map_area_free(smap->elems); bpf_map_area_free(smap->elems);
pcpu_freelist_destroy(&smap->freelist); pcpu_freelist_destroy(&smap->freelist);
bpf_map_area_free(smap); bpf_map_area_free(smap);
put_callchain_buffers(); put_callchain_buffers();
} }
static int stack_trace_map_btf_id;
const struct bpf_map_ops stack_trace_map_ops = { const struct bpf_map_ops stack_trace_map_ops = {
.map_alloc = stack_map_alloc, .map_alloc = stack_map_alloc,
.map_free = stack_map_free, .map_free = stack_map_free,
...@@ -621,6 +692,8 @@ const struct bpf_map_ops stack_trace_map_ops = { ...@@ -621,6 +692,8 @@ const struct bpf_map_ops stack_trace_map_ops = {
.map_update_elem = stack_map_update_elem, .map_update_elem = stack_map_update_elem,
.map_delete_elem = stack_map_delete_elem, .map_delete_elem = stack_map_delete_elem,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_stack_map",
.map_btf_id = &stack_trace_map_btf_id,
}; };
static int __init stack_map_init(void) static int __init stack_map_init(void)
......
...@@ -1351,6 +1351,19 @@ static void mark_reg_not_init(struct bpf_verifier_env *env, ...@@ -1351,6 +1351,19 @@ static void mark_reg_not_init(struct bpf_verifier_env *env,
__mark_reg_not_init(env, regs + regno); __mark_reg_not_init(env, regs + regno);
} }
static void mark_btf_ld_reg(struct bpf_verifier_env *env,
struct bpf_reg_state *regs, u32 regno,
enum bpf_reg_type reg_type, u32 btf_id)
{
if (reg_type == SCALAR_VALUE) {
mark_reg_unknown(env, regs, regno);
return;
}
mark_reg_known_zero(env, regs, regno);
regs[regno].type = PTR_TO_BTF_ID;
regs[regno].btf_id = btf_id;
}
#define DEF_NOT_SUBREG (0) #define DEF_NOT_SUBREG (0)
static void init_reg_state(struct bpf_verifier_env *env, static void init_reg_state(struct bpf_verifier_env *env,
struct bpf_func_state *state) struct bpf_func_state *state)
...@@ -3182,19 +3195,68 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, ...@@ -3182,19 +3195,68 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (atype == BPF_READ && value_regno >= 0) { if (atype == BPF_READ && value_regno >= 0)
if (ret == SCALAR_VALUE) { mark_btf_ld_reg(env, regs, value_regno, ret, btf_id);
mark_reg_unknown(env, regs, value_regno);
return 0; return 0;
} }
mark_reg_known_zero(env, regs, value_regno);
regs[value_regno].type = PTR_TO_BTF_ID; static int check_ptr_to_map_access(struct bpf_verifier_env *env,
regs[value_regno].btf_id = btf_id; struct bpf_reg_state *regs,
int regno, int off, int size,
enum bpf_access_type atype,
int value_regno)
{
struct bpf_reg_state *reg = regs + regno;
struct bpf_map *map = reg->map_ptr;
const struct btf_type *t;
const char *tname;
u32 btf_id;
int ret;
if (!btf_vmlinux) {
verbose(env, "map_ptr access not supported without CONFIG_DEBUG_INFO_BTF\n");
return -ENOTSUPP;
} }
if (!map->ops->map_btf_id || !*map->ops->map_btf_id) {
verbose(env, "map_ptr access not supported for map type %d\n",
map->map_type);
return -ENOTSUPP;
}
t = btf_type_by_id(btf_vmlinux, *map->ops->map_btf_id);
tname = btf_name_by_offset(btf_vmlinux, t->name_off);
if (!env->allow_ptr_to_map_access) {
verbose(env,
"%s access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN\n",
tname);
return -EPERM;
}
if (off < 0) {
verbose(env, "R%d is %s invalid negative access: off=%d\n",
regno, tname, off);
return -EACCES;
}
if (atype != BPF_READ) {
verbose(env, "only read from %s is supported\n", tname);
return -EACCES;
}
ret = btf_struct_access(&env->log, t, off, size, atype, &btf_id);
if (ret < 0)
return ret;
if (value_regno >= 0)
mark_btf_ld_reg(env, regs, value_regno, ret, btf_id);
return 0; return 0;
} }
/* check whether memory at (regno + off) is accessible for t = (read | write) /* check whether memory at (regno + off) is accessible for t = (read | write)
* if t==write, value_regno is a register which value is stored into memory * if t==write, value_regno is a register which value is stored into memory
* if t==read, value_regno is a register which will receive the value from memory * if t==read, value_regno is a register which will receive the value from memory
...@@ -3363,6 +3425,9 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn ...@@ -3363,6 +3425,9 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
} else if (reg->type == PTR_TO_BTF_ID) { } else if (reg->type == PTR_TO_BTF_ID) {
err = check_ptr_to_btf_access(env, regs, regno, off, size, t, err = check_ptr_to_btf_access(env, regs, regno, off, size, t,
value_regno); value_regno);
} else if (reg->type == CONST_PTR_TO_MAP) {
err = check_ptr_to_map_access(env, regs, regno, off, size, t,
value_regno);
} else { } else {
verbose(env, "R%d invalid mem access '%s'\n", regno, verbose(env, "R%d invalid mem access '%s'\n", regno,
reg_type_str[reg->type]); reg_type_str[reg->type]);
...@@ -3735,12 +3800,14 @@ static int int_ptr_type_to_size(enum bpf_arg_type type) ...@@ -3735,12 +3800,14 @@ static int int_ptr_type_to_size(enum bpf_arg_type type)
return -EINVAL; return -EINVAL;
} }
static int check_func_arg(struct bpf_verifier_env *env, u32 regno, static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
enum bpf_arg_type arg_type, struct bpf_call_arg_meta *meta,
struct bpf_call_arg_meta *meta) const struct bpf_func_proto *fn)
{ {
u32 regno = BPF_REG_1 + arg;
struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno]; struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
enum bpf_reg_type expected_type, type = reg->type; enum bpf_reg_type expected_type, type = reg->type;
enum bpf_arg_type arg_type = fn->arg_type[arg];
int err = 0; int err = 0;
if (arg_type == ARG_DONTCARE) if (arg_type == ARG_DONTCARE)
...@@ -3820,9 +3887,16 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, ...@@ -3820,9 +3887,16 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
expected_type = PTR_TO_BTF_ID; expected_type = PTR_TO_BTF_ID;
if (type != expected_type) if (type != expected_type)
goto err_type; goto err_type;
if (reg->btf_id != meta->btf_id) { if (!fn->check_btf_id) {
verbose(env, "Helper has type %s got %s in R%d\n", if (reg->btf_id != meta->btf_id) {
kernel_type_name(meta->btf_id), verbose(env, "Helper has type %s got %s in R%d\n",
kernel_type_name(meta->btf_id),
kernel_type_name(reg->btf_id), regno);
return -EACCES;
}
} else if (!fn->check_btf_id(reg->btf_id, arg)) {
verbose(env, "Helper does not support %s in R%d\n",
kernel_type_name(reg->btf_id), regno); kernel_type_name(reg->btf_id), regno);
return -EACCES; return -EACCES;
...@@ -4644,10 +4718,12 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn ...@@ -4644,10 +4718,12 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
meta.func_id = func_id; meta.func_id = func_id;
/* check args */ /* check args */
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
err = btf_resolve_helper_id(&env->log, fn, i); if (!fn->check_btf_id) {
if (err > 0) err = btf_resolve_helper_id(&env->log, fn, i);
meta.btf_id = err; if (err > 0)
err = check_func_arg(env, BPF_REG_1 + i, fn->arg_type[i], &meta); meta.btf_id = err;
}
err = check_func_arg(env, i, &meta, fn);
if (err) if (err)
return err; return err;
} }
...@@ -4750,6 +4826,18 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn ...@@ -4750,6 +4826,18 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL;
regs[BPF_REG_0].id = ++env->id_gen; regs[BPF_REG_0].id = ++env->id_gen;
regs[BPF_REG_0].mem_size = meta.mem_size; regs[BPF_REG_0].mem_size = meta.mem_size;
} else if (fn->ret_type == RET_PTR_TO_BTF_ID_OR_NULL) {
int ret_btf_id;
mark_reg_known_zero(env, regs, BPF_REG_0);
regs[BPF_REG_0].type = PTR_TO_BTF_ID_OR_NULL;
ret_btf_id = *fn->ret_btf_id;
if (ret_btf_id == 0) {
verbose(env, "invalid return type %d of func %s#%d\n",
fn->ret_type, func_id_name(func_id), func_id);
return -EINVAL;
}
regs[BPF_REG_0].btf_id = ret_btf_id;
} else { } else {
verbose(env, "unknown return type %d of func %s#%d\n", verbose(env, "unknown return type %d of func %s#%d\n",
fn->ret_type, func_id_name(func_id), func_id); fn->ret_type, func_id_name(func_id), func_id);
...@@ -4776,7 +4864,9 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn ...@@ -4776,7 +4864,9 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
if (err) if (err)
return err; return err;
if (func_id == BPF_FUNC_get_stack && !env->prog->has_callchain_buf) { if ((func_id == BPF_FUNC_get_stack ||
func_id == BPF_FUNC_get_task_stack) &&
!env->prog->has_callchain_buf) {
const char *err_str; const char *err_str;
#ifdef CONFIG_PERF_EVENTS #ifdef CONFIG_PERF_EVENTS
...@@ -5031,6 +5121,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, ...@@ -5031,6 +5121,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
if (BPF_CLASS(insn->code) != BPF_ALU64) { if (BPF_CLASS(insn->code) != BPF_ALU64) {
/* 32-bit ALU ops on pointers produce (meaningless) scalars */ /* 32-bit ALU ops on pointers produce (meaningless) scalars */
if (opcode == BPF_SUB && env->allow_ptr_leaks) {
__mark_reg_unknown(env, dst_reg);
return 0;
}
verbose(env, verbose(env,
"R%d 32-bit pointer arithmetic prohibited\n", "R%d 32-bit pointer arithmetic prohibited\n",
dst); dst);
...@@ -10946,6 +11041,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, ...@@ -10946,6 +11041,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
env->strict_alignment = false; env->strict_alignment = false;
env->allow_ptr_leaks = bpf_allow_ptr_leaks(); env->allow_ptr_leaks = bpf_allow_ptr_leaks();
env->allow_ptr_to_map_access = bpf_allow_ptr_to_map_access();
env->bypass_spec_v1 = bpf_bypass_spec_v1(); env->bypass_spec_v1 = bpf_bypass_spec_v1();
env->bypass_spec_v4 = bpf_bypass_spec_v4(); env->bypass_spec_v4 = bpf_bypass_spec_v4();
env->bpf_capable = bpf_capable(); env->bpf_capable = bpf_capable();
......
...@@ -149,7 +149,7 @@ void put_callchain_buffers(void) ...@@ -149,7 +149,7 @@ void put_callchain_buffers(void)
} }
} }
static struct perf_callchain_entry *get_callchain_entry(int *rctx) struct perf_callchain_entry *get_callchain_entry(int *rctx)
{ {
int cpu; int cpu;
struct callchain_cpus_entries *entries; struct callchain_cpus_entries *entries;
...@@ -159,8 +159,10 @@ static struct perf_callchain_entry *get_callchain_entry(int *rctx) ...@@ -159,8 +159,10 @@ static struct perf_callchain_entry *get_callchain_entry(int *rctx)
return NULL; return NULL;
entries = rcu_dereference(callchain_cpus_entries); entries = rcu_dereference(callchain_cpus_entries);
if (!entries) if (!entries) {
put_recursion_context(this_cpu_ptr(callchain_recursion), *rctx);
return NULL; return NULL;
}
cpu = smp_processor_id(); cpu = smp_processor_id();
...@@ -168,7 +170,7 @@ static struct perf_callchain_entry *get_callchain_entry(int *rctx) ...@@ -168,7 +170,7 @@ static struct perf_callchain_entry *get_callchain_entry(int *rctx)
(*rctx * perf_callchain_entry__sizeof())); (*rctx * perf_callchain_entry__sizeof()));
} }
static void void
put_callchain_entry(int rctx) put_callchain_entry(int rctx)
{ {
put_recursion_context(this_cpu_ptr(callchain_recursion), rctx); put_recursion_context(this_cpu_ptr(callchain_recursion), rctx);
...@@ -183,11 +185,8 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, ...@@ -183,11 +185,8 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
int rctx; int rctx;
entry = get_callchain_entry(&rctx); entry = get_callchain_entry(&rctx);
if (rctx == -1)
return NULL;
if (!entry) if (!entry)
goto exit_put; return NULL;
ctx.entry = entry; ctx.entry = entry;
ctx.max_stack = max_stack; ctx.max_stack = max_stack;
......
...@@ -376,7 +376,7 @@ static void bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype, ...@@ -376,7 +376,7 @@ static void bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype,
/* /*
* Only limited trace_printk() conversion specifiers allowed: * Only limited trace_printk() conversion specifiers allowed:
* %d %i %u %x %ld %li %lu %lx %lld %lli %llu %llx %p %pks %pus %s * %d %i %u %x %ld %li %lu %lx %lld %lli %llu %llx %p %pB %pks %pus %s
*/ */
BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1,
u64, arg2, u64, arg3) u64, arg2, u64, arg3)
...@@ -420,6 +420,11 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, ...@@ -420,6 +420,11 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1,
goto fmt_str; goto fmt_str;
} }
if (fmt[i + 1] == 'B') {
i++;
goto fmt_next;
}
/* disallow any further format extensions */ /* disallow any further format extensions */
if (fmt[i + 1] != 0 && if (fmt[i + 1] != 0 &&
!isspace(fmt[i + 1]) && !isspace(fmt[i + 1]) &&
...@@ -636,7 +641,8 @@ BPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size, ...@@ -636,7 +641,8 @@ BPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size,
if (fmt[i] == 'p') { if (fmt[i] == 'p') {
if (fmt[i + 1] == 0 || if (fmt[i + 1] == 0 ||
fmt[i + 1] == 'K' || fmt[i + 1] == 'K' ||
fmt[i + 1] == 'x') { fmt[i + 1] == 'x' ||
fmt[i + 1] == 'B') {
/* just kernel pointers */ /* just kernel pointers */
params[fmt_cnt] = args[fmt_cnt]; params[fmt_cnt] = args[fmt_cnt];
fmt_cnt++; fmt_cnt++;
...@@ -681,7 +687,8 @@ BPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size, ...@@ -681,7 +687,8 @@ BPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size,
} }
if (fmt[i] != 'i' && fmt[i] != 'd' && if (fmt[i] != 'i' && fmt[i] != 'd' &&
fmt[i] != 'u' && fmt[i] != 'x') { fmt[i] != 'u' && fmt[i] != 'x' &&
fmt[i] != 'X') {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
...@@ -1134,6 +1141,10 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) ...@@ -1134,6 +1141,10 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_ringbuf_discard_proto; return &bpf_ringbuf_discard_proto;
case BPF_FUNC_ringbuf_query: case BPF_FUNC_ringbuf_query:
return &bpf_ringbuf_query_proto; return &bpf_ringbuf_query_proto;
case BPF_FUNC_jiffies64:
return &bpf_jiffies64_proto;
case BPF_FUNC_get_task_stack:
return &bpf_get_task_stack_proto;
default: default:
return NULL; return NULL;
} }
...@@ -1512,6 +1523,16 @@ tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) ...@@ -1512,6 +1523,16 @@ tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_skb_output_proto; return &bpf_skb_output_proto;
case BPF_FUNC_xdp_output: case BPF_FUNC_xdp_output:
return &bpf_xdp_output_proto; return &bpf_xdp_output_proto;
case BPF_FUNC_skc_to_tcp6_sock:
return &bpf_skc_to_tcp6_sock_proto;
case BPF_FUNC_skc_to_tcp_sock:
return &bpf_skc_to_tcp_sock_proto;
case BPF_FUNC_skc_to_tcp_timewait_sock:
return &bpf_skc_to_tcp_timewait_sock_proto;
case BPF_FUNC_skc_to_tcp_request_sock:
return &bpf_skc_to_tcp_request_sock_proto;
case BPF_FUNC_skc_to_udp6_sock:
return &bpf_skc_to_udp6_sock_proto;
#endif #endif
case BPF_FUNC_seq_printf: case BPF_FUNC_seq_printf:
return prog->expected_attach_type == BPF_TRACE_ITER ? return prog->expected_attach_type == BPF_TRACE_ITER ?
......
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
#include <uapi/linux/sock_diag.h> #include <uapi/linux/sock_diag.h>
#include <uapi/linux/btf.h> #include <uapi/linux/btf.h>
static atomic_t cache_idx;
#define SK_STORAGE_CREATE_FLAG_MASK \ #define SK_STORAGE_CREATE_FLAG_MASK \
(BPF_F_NO_PREALLOC | BPF_F_CLONE) (BPF_F_NO_PREALLOC | BPF_F_CLONE)
...@@ -81,6 +79,9 @@ struct bpf_sk_storage_elem { ...@@ -81,6 +79,9 @@ struct bpf_sk_storage_elem {
#define SDATA(_SELEM) (&(_SELEM)->sdata) #define SDATA(_SELEM) (&(_SELEM)->sdata)
#define BPF_SK_STORAGE_CACHE_SIZE 16 #define BPF_SK_STORAGE_CACHE_SIZE 16
static DEFINE_SPINLOCK(cache_idx_lock);
static u64 cache_idx_usage_counts[BPF_SK_STORAGE_CACHE_SIZE];
struct bpf_sk_storage { struct bpf_sk_storage {
struct bpf_sk_storage_data __rcu *cache[BPF_SK_STORAGE_CACHE_SIZE]; struct bpf_sk_storage_data __rcu *cache[BPF_SK_STORAGE_CACHE_SIZE];
struct hlist_head list; /* List of bpf_sk_storage_elem */ struct hlist_head list; /* List of bpf_sk_storage_elem */
...@@ -512,6 +513,37 @@ static int sk_storage_delete(struct sock *sk, struct bpf_map *map) ...@@ -512,6 +513,37 @@ static int sk_storage_delete(struct sock *sk, struct bpf_map *map)
return 0; return 0;
} }
static u16 cache_idx_get(void)
{
u64 min_usage = U64_MAX;
u16 i, res = 0;
spin_lock(&cache_idx_lock);
for (i = 0; i < BPF_SK_STORAGE_CACHE_SIZE; i++) {
if (cache_idx_usage_counts[i] < min_usage) {
min_usage = cache_idx_usage_counts[i];
res = i;
/* Found a free cache_idx */
if (!min_usage)
break;
}
}
cache_idx_usage_counts[res]++;
spin_unlock(&cache_idx_lock);
return res;
}
static void cache_idx_free(u16 idx)
{
spin_lock(&cache_idx_lock);
cache_idx_usage_counts[idx]--;
spin_unlock(&cache_idx_lock);
}
/* Called by __sk_destruct() & bpf_sk_storage_clone() */ /* Called by __sk_destruct() & bpf_sk_storage_clone() */
void bpf_sk_storage_free(struct sock *sk) void bpf_sk_storage_free(struct sock *sk)
{ {
...@@ -560,6 +592,8 @@ static void bpf_sk_storage_map_free(struct bpf_map *map) ...@@ -560,6 +592,8 @@ static void bpf_sk_storage_map_free(struct bpf_map *map)
smap = (struct bpf_sk_storage_map *)map; smap = (struct bpf_sk_storage_map *)map;
cache_idx_free(smap->cache_idx);
/* Note that this map might be concurrently cloned from /* Note that this map might be concurrently cloned from
* bpf_sk_storage_clone. Wait for any existing bpf_sk_storage_clone * bpf_sk_storage_clone. Wait for any existing bpf_sk_storage_clone
* RCU read section to finish before proceeding. New RCU * RCU read section to finish before proceeding. New RCU
...@@ -673,8 +707,7 @@ static struct bpf_map *bpf_sk_storage_map_alloc(union bpf_attr *attr) ...@@ -673,8 +707,7 @@ static struct bpf_map *bpf_sk_storage_map_alloc(union bpf_attr *attr)
} }
smap->elem_size = sizeof(struct bpf_sk_storage_elem) + attr->value_size; smap->elem_size = sizeof(struct bpf_sk_storage_elem) + attr->value_size;
smap->cache_idx = (unsigned int)atomic_inc_return(&cache_idx) % smap->cache_idx = cache_idx_get();
BPF_SK_STORAGE_CACHE_SIZE;
return &smap->map; return &smap->map;
} }
...@@ -886,6 +919,7 @@ BPF_CALL_2(bpf_sk_storage_delete, struct bpf_map *, map, struct sock *, sk) ...@@ -886,6 +919,7 @@ BPF_CALL_2(bpf_sk_storage_delete, struct bpf_map *, map, struct sock *, sk)
return -ENOENT; return -ENOENT;
} }
static int sk_storage_map_btf_id;
const struct bpf_map_ops sk_storage_map_ops = { const struct bpf_map_ops sk_storage_map_ops = {
.map_alloc_check = bpf_sk_storage_map_alloc_check, .map_alloc_check = bpf_sk_storage_map_alloc_check,
.map_alloc = bpf_sk_storage_map_alloc, .map_alloc = bpf_sk_storage_map_alloc,
...@@ -895,6 +929,8 @@ const struct bpf_map_ops sk_storage_map_ops = { ...@@ -895,6 +929,8 @@ const struct bpf_map_ops sk_storage_map_ops = {
.map_update_elem = bpf_fd_sk_storage_update_elem, .map_update_elem = bpf_fd_sk_storage_update_elem,
.map_delete_elem = bpf_fd_sk_storage_delete_elem, .map_delete_elem = bpf_fd_sk_storage_delete_elem,
.map_check_btf = bpf_sk_storage_map_check_btf, .map_check_btf = bpf_sk_storage_map_check_btf,
.map_btf_name = "bpf_sk_storage_map",
.map_btf_id = &sk_storage_map_btf_id,
}; };
const struct bpf_func_proto bpf_sk_storage_get_proto = { const struct bpf_func_proto bpf_sk_storage_get_proto = {
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <linux/seccomp.h> #include <linux/seccomp.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/btf.h>
#include <net/sch_generic.h> #include <net/sch_generic.h>
#include <net/cls_cgroup.h> #include <net/cls_cgroup.h>
#include <net/dst_metadata.h> #include <net/dst_metadata.h>
...@@ -73,6 +74,7 @@ ...@@ -73,6 +74,7 @@
#include <net/lwtunnel.h> #include <net/lwtunnel.h>
#include <net/ipv6_stubs.h> #include <net/ipv6_stubs.h>
#include <net/bpf_sk_storage.h> #include <net/bpf_sk_storage.h>
#include <net/transp_v6.h>
/** /**
* sk_filter_trim_cap - run a packet through a socket filter * sk_filter_trim_cap - run a packet through a socket filter
...@@ -4289,10 +4291,10 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, ...@@ -4289,10 +4291,10 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
char *optval, int optlen, u32 flags) char *optval, int optlen, u32 flags)
{ {
char devname[IFNAMSIZ]; char devname[IFNAMSIZ];
int val, valbool;
struct net *net; struct net *net;
int ifindex; int ifindex;
int ret = 0; int ret = 0;
int val;
if (!sk_fullsock(sk)) if (!sk_fullsock(sk))
return -EINVAL; return -EINVAL;
...@@ -4303,6 +4305,7 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, ...@@ -4303,6 +4305,7 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
if (optlen != sizeof(int) && optname != SO_BINDTODEVICE) if (optlen != sizeof(int) && optname != SO_BINDTODEVICE)
return -EINVAL; return -EINVAL;
val = *((int *)optval); val = *((int *)optval);
valbool = val ? 1 : 0;
/* Only some socketops are supported */ /* Only some socketops are supported */
switch (optname) { switch (optname) {
...@@ -4361,6 +4364,11 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, ...@@ -4361,6 +4364,11 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
} }
ret = sock_bindtoindex(sk, ifindex, false); ret = sock_bindtoindex(sk, ifindex, false);
break; break;
case SO_KEEPALIVE:
if (sk->sk_prot->keepalive)
sk->sk_prot->keepalive(sk, valbool);
sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
...@@ -4421,6 +4429,7 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, ...@@ -4421,6 +4429,7 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
ret = tcp_set_congestion_control(sk, name, false, ret = tcp_set_congestion_control(sk, name, false,
reinit, true); reinit, true);
} else { } else {
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
if (optlen != sizeof(int)) if (optlen != sizeof(int))
...@@ -4449,6 +4458,33 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, ...@@ -4449,6 +4458,33 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
else else
tp->save_syn = val; tp->save_syn = val;
break; break;
case TCP_KEEPIDLE:
ret = tcp_sock_set_keepidle_locked(sk, val);
break;
case TCP_KEEPINTVL:
if (val < 1 || val > MAX_TCP_KEEPINTVL)
ret = -EINVAL;
else
tp->keepalive_intvl = val * HZ;
break;
case TCP_KEEPCNT:
if (val < 1 || val > MAX_TCP_KEEPCNT)
ret = -EINVAL;
else
tp->keepalive_probes = val;
break;
case TCP_SYNCNT:
if (val < 1 || val > MAX_TCP_SYNCNT)
ret = -EINVAL;
else
icsk->icsk_syn_retries = val;
break;
case TCP_USER_TIMEOUT:
if (val < 0)
ret = -EINVAL;
else
icsk->icsk_user_timeout = val;
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
...@@ -9191,3 +9227,171 @@ void bpf_prog_change_xdp(struct bpf_prog *prev_prog, struct bpf_prog *prog) ...@@ -9191,3 +9227,171 @@ void bpf_prog_change_xdp(struct bpf_prog *prev_prog, struct bpf_prog *prog)
{ {
bpf_dispatcher_change_prog(BPF_DISPATCHER_PTR(xdp), prev_prog, prog); bpf_dispatcher_change_prog(BPF_DISPATCHER_PTR(xdp), prev_prog, prog);
} }
/* Define a list of socket types which can be the argument for
* skc_to_*_sock() helpers. All these sockets should have
* sock_common as the first argument in its memory layout.
*/
#define BTF_SOCK_TYPE_xxx \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET, "inet_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_CONN, "inet_connection_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_REQ, "inet_request_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_INET_TW, "inet_timewait_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_REQ, "request_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_SOCK, "sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_SOCK_COMMON, "sock_common") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP, "tcp_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_REQ, "tcp_request_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_TW, "tcp_timewait_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP6, "tcp6_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP, "udp_sock") \
BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP6, "udp6_sock")
enum {
#define BTF_SOCK_TYPE(name, str) name,
BTF_SOCK_TYPE_xxx
#undef BTF_SOCK_TYPE
MAX_BTF_SOCK_TYPE,
};
static int btf_sock_ids[MAX_BTF_SOCK_TYPE];
#ifdef CONFIG_BPF_SYSCALL
static const char *bpf_sock_types[] = {
#define BTF_SOCK_TYPE(name, str) str,
BTF_SOCK_TYPE_xxx
#undef BTF_SOCK_TYPE
};
void init_btf_sock_ids(struct btf *btf)
{
int i, btf_id;
for (i = 0; i < MAX_BTF_SOCK_TYPE; i++) {
btf_id = btf_find_by_name_kind(btf, bpf_sock_types[i],
BTF_KIND_STRUCT);
if (btf_id > 0)
btf_sock_ids[i] = btf_id;
}
}
#endif
static bool check_arg_btf_id(u32 btf_id, u32 arg)
{
int i;
/* only one argument, no need to check arg */
for (i = 0; i < MAX_BTF_SOCK_TYPE; i++)
if (btf_sock_ids[i] == btf_id)
return true;
return false;
}
BPF_CALL_1(bpf_skc_to_tcp6_sock, struct sock *, sk)
{
/* tcp6_sock type is not generated in dwarf and hence btf,
* trigger an explicit type generation here.
*/
BTF_TYPE_EMIT(struct tcp6_sock);
if (sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP &&
sk->sk_family == AF_INET6)
return (unsigned long)sk;
return (unsigned long)NULL;
}
const struct bpf_func_proto bpf_skc_to_tcp6_sock_proto = {
.func = bpf_skc_to_tcp6_sock,
.gpl_only = false,
.ret_type = RET_PTR_TO_BTF_ID_OR_NULL,
.arg1_type = ARG_PTR_TO_BTF_ID,
.check_btf_id = check_arg_btf_id,
.ret_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_TCP6],
};
BPF_CALL_1(bpf_skc_to_tcp_sock, struct sock *, sk)
{
if (sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP)
return (unsigned long)sk;
return (unsigned long)NULL;
}
const struct bpf_func_proto bpf_skc_to_tcp_sock_proto = {
.func = bpf_skc_to_tcp_sock,
.gpl_only = false,
.ret_type = RET_PTR_TO_BTF_ID_OR_NULL,
.arg1_type = ARG_PTR_TO_BTF_ID,
.check_btf_id = check_arg_btf_id,
.ret_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_TCP],
};
BPF_CALL_1(bpf_skc_to_tcp_timewait_sock, struct sock *, sk)
{
#ifdef CONFIG_INET
if (sk->sk_prot == &tcp_prot && sk->sk_state == TCP_TIME_WAIT)
return (unsigned long)sk;
#endif
#if IS_BUILTIN(CONFIG_IPV6)
if (sk->sk_prot == &tcpv6_prot && sk->sk_state == TCP_TIME_WAIT)
return (unsigned long)sk;
#endif
return (unsigned long)NULL;
}
const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto = {
.func = bpf_skc_to_tcp_timewait_sock,
.gpl_only = false,
.ret_type = RET_PTR_TO_BTF_ID_OR_NULL,
.arg1_type = ARG_PTR_TO_BTF_ID,
.check_btf_id = check_arg_btf_id,
.ret_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_TCP_TW],
};
BPF_CALL_1(bpf_skc_to_tcp_request_sock, struct sock *, sk)
{
#ifdef CONFIG_INET
if (sk->sk_prot == &tcp_prot && sk->sk_state == TCP_NEW_SYN_RECV)
return (unsigned long)sk;
#endif
#if IS_BUILTIN(CONFIG_IPV6)
if (sk->sk_prot == &tcpv6_prot && sk->sk_state == TCP_NEW_SYN_RECV)
return (unsigned long)sk;
#endif
return (unsigned long)NULL;
}
const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto = {
.func = bpf_skc_to_tcp_request_sock,
.gpl_only = false,
.ret_type = RET_PTR_TO_BTF_ID_OR_NULL,
.arg1_type = ARG_PTR_TO_BTF_ID,
.check_btf_id = check_arg_btf_id,
.ret_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_TCP_REQ],
};
BPF_CALL_1(bpf_skc_to_udp6_sock, struct sock *, sk)
{
/* udp6_sock type is not generated in dwarf and hence btf,
* trigger an explicit type generation here.
*/
BTF_TYPE_EMIT(struct udp6_sock);
if (sk_fullsock(sk) && sk->sk_protocol == IPPROTO_UDP &&
sk->sk_type == SOCK_DGRAM && sk->sk_family == AF_INET6)
return (unsigned long)sk;
return (unsigned long)NULL;
}
const struct bpf_func_proto bpf_skc_to_udp6_sock_proto = {
.func = bpf_skc_to_udp6_sock,
.gpl_only = false,
.ret_type = RET_PTR_TO_BTF_ID_OR_NULL,
.arg1_type = ARG_PTR_TO_BTF_ID,
.check_btf_id = check_arg_btf_id,
.ret_btf_id = &btf_sock_ids[BTF_SOCK_TYPE_UDP6],
};
...@@ -695,15 +695,6 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval, ...@@ -695,15 +695,6 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval,
return ret; return ret;
} }
static inline void sock_valbool_flag(struct sock *sk, enum sock_flags bit,
int valbool)
{
if (valbool)
sock_set_flag(sk, bit);
else
sock_reset_flag(sk, bit);
}
bool sk_mc_loop(struct sock *sk) bool sk_mc_loop(struct sock *sk)
{ {
if (dev_recursion_level()) if (dev_recursion_level())
......
...@@ -643,6 +643,7 @@ const struct bpf_func_proto bpf_msg_redirect_map_proto = { ...@@ -643,6 +643,7 @@ const struct bpf_func_proto bpf_msg_redirect_map_proto = {
.arg4_type = ARG_ANYTHING, .arg4_type = ARG_ANYTHING,
}; };
static int sock_map_btf_id;
const struct bpf_map_ops sock_map_ops = { const struct bpf_map_ops sock_map_ops = {
.map_alloc = sock_map_alloc, .map_alloc = sock_map_alloc,
.map_free = sock_map_free, .map_free = sock_map_free,
...@@ -653,9 +654,11 @@ const struct bpf_map_ops sock_map_ops = { ...@@ -653,9 +654,11 @@ const struct bpf_map_ops sock_map_ops = {
.map_lookup_elem = sock_map_lookup, .map_lookup_elem = sock_map_lookup,
.map_release_uref = sock_map_release_progs, .map_release_uref = sock_map_release_progs,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_stab",
.map_btf_id = &sock_map_btf_id,
}; };
struct bpf_htab_elem { struct bpf_shtab_elem {
struct rcu_head rcu; struct rcu_head rcu;
u32 hash; u32 hash;
struct sock *sk; struct sock *sk;
...@@ -663,14 +666,14 @@ struct bpf_htab_elem { ...@@ -663,14 +666,14 @@ struct bpf_htab_elem {
u8 key[]; u8 key[];
}; };
struct bpf_htab_bucket { struct bpf_shtab_bucket {
struct hlist_head head; struct hlist_head head;
raw_spinlock_t lock; raw_spinlock_t lock;
}; };
struct bpf_htab { struct bpf_shtab {
struct bpf_map map; struct bpf_map map;
struct bpf_htab_bucket *buckets; struct bpf_shtab_bucket *buckets;
u32 buckets_num; u32 buckets_num;
u32 elem_size; u32 elem_size;
struct sk_psock_progs progs; struct sk_psock_progs progs;
...@@ -682,17 +685,17 @@ static inline u32 sock_hash_bucket_hash(const void *key, u32 len) ...@@ -682,17 +685,17 @@ static inline u32 sock_hash_bucket_hash(const void *key, u32 len)
return jhash(key, len, 0); return jhash(key, len, 0);
} }
static struct bpf_htab_bucket *sock_hash_select_bucket(struct bpf_htab *htab, static struct bpf_shtab_bucket *sock_hash_select_bucket(struct bpf_shtab *htab,
u32 hash) u32 hash)
{ {
return &htab->buckets[hash & (htab->buckets_num - 1)]; return &htab->buckets[hash & (htab->buckets_num - 1)];
} }
static struct bpf_htab_elem * static struct bpf_shtab_elem *
sock_hash_lookup_elem_raw(struct hlist_head *head, u32 hash, void *key, sock_hash_lookup_elem_raw(struct hlist_head *head, u32 hash, void *key,
u32 key_size) u32 key_size)
{ {
struct bpf_htab_elem *elem; struct bpf_shtab_elem *elem;
hlist_for_each_entry_rcu(elem, head, node) { hlist_for_each_entry_rcu(elem, head, node) {
if (elem->hash == hash && if (elem->hash == hash &&
...@@ -705,10 +708,10 @@ sock_hash_lookup_elem_raw(struct hlist_head *head, u32 hash, void *key, ...@@ -705,10 +708,10 @@ sock_hash_lookup_elem_raw(struct hlist_head *head, u32 hash, void *key,
static struct sock *__sock_hash_lookup_elem(struct bpf_map *map, void *key) static struct sock *__sock_hash_lookup_elem(struct bpf_map *map, void *key)
{ {
struct bpf_htab *htab = container_of(map, struct bpf_htab, map); struct bpf_shtab *htab = container_of(map, struct bpf_shtab, map);
u32 key_size = map->key_size, hash; u32 key_size = map->key_size, hash;
struct bpf_htab_bucket *bucket; struct bpf_shtab_bucket *bucket;
struct bpf_htab_elem *elem; struct bpf_shtab_elem *elem;
WARN_ON_ONCE(!rcu_read_lock_held()); WARN_ON_ONCE(!rcu_read_lock_held());
...@@ -719,8 +722,8 @@ static struct sock *__sock_hash_lookup_elem(struct bpf_map *map, void *key) ...@@ -719,8 +722,8 @@ static struct sock *__sock_hash_lookup_elem(struct bpf_map *map, void *key)
return elem ? elem->sk : NULL; return elem ? elem->sk : NULL;
} }
static void sock_hash_free_elem(struct bpf_htab *htab, static void sock_hash_free_elem(struct bpf_shtab *htab,
struct bpf_htab_elem *elem) struct bpf_shtab_elem *elem)
{ {
atomic_dec(&htab->count); atomic_dec(&htab->count);
kfree_rcu(elem, rcu); kfree_rcu(elem, rcu);
...@@ -729,9 +732,9 @@ static void sock_hash_free_elem(struct bpf_htab *htab, ...@@ -729,9 +732,9 @@ static void sock_hash_free_elem(struct bpf_htab *htab,
static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk, static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk,
void *link_raw) void *link_raw)
{ {
struct bpf_htab *htab = container_of(map, struct bpf_htab, map); struct bpf_shtab *htab = container_of(map, struct bpf_shtab, map);
struct bpf_htab_elem *elem_probe, *elem = link_raw; struct bpf_shtab_elem *elem_probe, *elem = link_raw;
struct bpf_htab_bucket *bucket; struct bpf_shtab_bucket *bucket;
WARN_ON_ONCE(!rcu_read_lock_held()); WARN_ON_ONCE(!rcu_read_lock_held());
bucket = sock_hash_select_bucket(htab, elem->hash); bucket = sock_hash_select_bucket(htab, elem->hash);
...@@ -753,10 +756,10 @@ static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk, ...@@ -753,10 +756,10 @@ static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk,
static int sock_hash_delete_elem(struct bpf_map *map, void *key) static int sock_hash_delete_elem(struct bpf_map *map, void *key)
{ {
struct bpf_htab *htab = container_of(map, struct bpf_htab, map); struct bpf_shtab *htab = container_of(map, struct bpf_shtab, map);
u32 hash, key_size = map->key_size; u32 hash, key_size = map->key_size;
struct bpf_htab_bucket *bucket; struct bpf_shtab_bucket *bucket;
struct bpf_htab_elem *elem; struct bpf_shtab_elem *elem;
int ret = -ENOENT; int ret = -ENOENT;
hash = sock_hash_bucket_hash(key, key_size); hash = sock_hash_bucket_hash(key, key_size);
...@@ -774,12 +777,12 @@ static int sock_hash_delete_elem(struct bpf_map *map, void *key) ...@@ -774,12 +777,12 @@ static int sock_hash_delete_elem(struct bpf_map *map, void *key)
return ret; return ret;
} }
static struct bpf_htab_elem *sock_hash_alloc_elem(struct bpf_htab *htab, static struct bpf_shtab_elem *sock_hash_alloc_elem(struct bpf_shtab *htab,
void *key, u32 key_size, void *key, u32 key_size,
u32 hash, struct sock *sk, u32 hash, struct sock *sk,
struct bpf_htab_elem *old) struct bpf_shtab_elem *old)
{ {
struct bpf_htab_elem *new; struct bpf_shtab_elem *new;
if (atomic_inc_return(&htab->count) > htab->map.max_entries) { if (atomic_inc_return(&htab->count) > htab->map.max_entries) {
if (!old) { if (!old) {
...@@ -803,10 +806,10 @@ static struct bpf_htab_elem *sock_hash_alloc_elem(struct bpf_htab *htab, ...@@ -803,10 +806,10 @@ static struct bpf_htab_elem *sock_hash_alloc_elem(struct bpf_htab *htab,
static int sock_hash_update_common(struct bpf_map *map, void *key, static int sock_hash_update_common(struct bpf_map *map, void *key,
struct sock *sk, u64 flags) struct sock *sk, u64 flags)
{ {
struct bpf_htab *htab = container_of(map, struct bpf_htab, map); struct bpf_shtab *htab = container_of(map, struct bpf_shtab, map);
u32 key_size = map->key_size, hash; u32 key_size = map->key_size, hash;
struct bpf_htab_elem *elem, *elem_new; struct bpf_shtab_elem *elem, *elem_new;
struct bpf_htab_bucket *bucket; struct bpf_shtab_bucket *bucket;
struct sk_psock_link *link; struct sk_psock_link *link;
struct sk_psock *psock; struct sk_psock *psock;
int ret; int ret;
...@@ -916,8 +919,8 @@ static int sock_hash_update_elem(struct bpf_map *map, void *key, ...@@ -916,8 +919,8 @@ static int sock_hash_update_elem(struct bpf_map *map, void *key,
static int sock_hash_get_next_key(struct bpf_map *map, void *key, static int sock_hash_get_next_key(struct bpf_map *map, void *key,
void *key_next) void *key_next)
{ {
struct bpf_htab *htab = container_of(map, struct bpf_htab, map); struct bpf_shtab *htab = container_of(map, struct bpf_shtab, map);
struct bpf_htab_elem *elem, *elem_next; struct bpf_shtab_elem *elem, *elem_next;
u32 hash, key_size = map->key_size; u32 hash, key_size = map->key_size;
struct hlist_head *head; struct hlist_head *head;
int i = 0; int i = 0;
...@@ -931,7 +934,7 @@ static int sock_hash_get_next_key(struct bpf_map *map, void *key, ...@@ -931,7 +934,7 @@ static int sock_hash_get_next_key(struct bpf_map *map, void *key,
goto find_first_elem; goto find_first_elem;
elem_next = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(&elem->node)), elem_next = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(&elem->node)),
struct bpf_htab_elem, node); struct bpf_shtab_elem, node);
if (elem_next) { if (elem_next) {
memcpy(key_next, elem_next->key, key_size); memcpy(key_next, elem_next->key, key_size);
return 0; return 0;
...@@ -943,7 +946,7 @@ static int sock_hash_get_next_key(struct bpf_map *map, void *key, ...@@ -943,7 +946,7 @@ static int sock_hash_get_next_key(struct bpf_map *map, void *key,
for (; i < htab->buckets_num; i++) { for (; i < htab->buckets_num; i++) {
head = &sock_hash_select_bucket(htab, i)->head; head = &sock_hash_select_bucket(htab, i)->head;
elem_next = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(head)), elem_next = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(head)),
struct bpf_htab_elem, node); struct bpf_shtab_elem, node);
if (elem_next) { if (elem_next) {
memcpy(key_next, elem_next->key, key_size); memcpy(key_next, elem_next->key, key_size);
return 0; return 0;
...@@ -955,7 +958,7 @@ static int sock_hash_get_next_key(struct bpf_map *map, void *key, ...@@ -955,7 +958,7 @@ static int sock_hash_get_next_key(struct bpf_map *map, void *key,
static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) static struct bpf_map *sock_hash_alloc(union bpf_attr *attr)
{ {
struct bpf_htab *htab; struct bpf_shtab *htab;
int i, err; int i, err;
u64 cost; u64 cost;
...@@ -977,15 +980,15 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) ...@@ -977,15 +980,15 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr)
bpf_map_init_from_attr(&htab->map, attr); bpf_map_init_from_attr(&htab->map, attr);
htab->buckets_num = roundup_pow_of_two(htab->map.max_entries); htab->buckets_num = roundup_pow_of_two(htab->map.max_entries);
htab->elem_size = sizeof(struct bpf_htab_elem) + htab->elem_size = sizeof(struct bpf_shtab_elem) +
round_up(htab->map.key_size, 8); round_up(htab->map.key_size, 8);
if (htab->buckets_num == 0 || if (htab->buckets_num == 0 ||
htab->buckets_num > U32_MAX / sizeof(struct bpf_htab_bucket)) { htab->buckets_num > U32_MAX / sizeof(struct bpf_shtab_bucket)) {
err = -EINVAL; err = -EINVAL;
goto free_htab; goto free_htab;
} }
cost = (u64) htab->buckets_num * sizeof(struct bpf_htab_bucket) + cost = (u64) htab->buckets_num * sizeof(struct bpf_shtab_bucket) +
(u64) htab->elem_size * htab->map.max_entries; (u64) htab->elem_size * htab->map.max_entries;
if (cost >= U32_MAX - PAGE_SIZE) { if (cost >= U32_MAX - PAGE_SIZE) {
err = -EINVAL; err = -EINVAL;
...@@ -996,7 +999,7 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) ...@@ -996,7 +999,7 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr)
goto free_htab; goto free_htab;
htab->buckets = bpf_map_area_alloc(htab->buckets_num * htab->buckets = bpf_map_area_alloc(htab->buckets_num *
sizeof(struct bpf_htab_bucket), sizeof(struct bpf_shtab_bucket),
htab->map.numa_node); htab->map.numa_node);
if (!htab->buckets) { if (!htab->buckets) {
bpf_map_charge_finish(&htab->map.memory); bpf_map_charge_finish(&htab->map.memory);
...@@ -1017,10 +1020,10 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) ...@@ -1017,10 +1020,10 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr)
static void sock_hash_free(struct bpf_map *map) static void sock_hash_free(struct bpf_map *map)
{ {
struct bpf_htab *htab = container_of(map, struct bpf_htab, map); struct bpf_shtab *htab = container_of(map, struct bpf_shtab, map);
struct bpf_htab_bucket *bucket; struct bpf_shtab_bucket *bucket;
struct hlist_head unlink_list; struct hlist_head unlink_list;
struct bpf_htab_elem *elem; struct bpf_shtab_elem *elem;
struct hlist_node *node; struct hlist_node *node;
int i; int i;
...@@ -1096,7 +1099,7 @@ static void *sock_hash_lookup(struct bpf_map *map, void *key) ...@@ -1096,7 +1099,7 @@ static void *sock_hash_lookup(struct bpf_map *map, void *key)
static void sock_hash_release_progs(struct bpf_map *map) static void sock_hash_release_progs(struct bpf_map *map)
{ {
psock_progs_drop(&container_of(map, struct bpf_htab, map)->progs); psock_progs_drop(&container_of(map, struct bpf_shtab, map)->progs);
} }
BPF_CALL_4(bpf_sock_hash_update, struct bpf_sock_ops_kern *, sops, BPF_CALL_4(bpf_sock_hash_update, struct bpf_sock_ops_kern *, sops,
...@@ -1176,6 +1179,7 @@ const struct bpf_func_proto bpf_msg_redirect_hash_proto = { ...@@ -1176,6 +1179,7 @@ const struct bpf_func_proto bpf_msg_redirect_hash_proto = {
.arg4_type = ARG_ANYTHING, .arg4_type = ARG_ANYTHING,
}; };
static int sock_hash_map_btf_id;
const struct bpf_map_ops sock_hash_ops = { const struct bpf_map_ops sock_hash_ops = {
.map_alloc = sock_hash_alloc, .map_alloc = sock_hash_alloc,
.map_free = sock_hash_free, .map_free = sock_hash_free,
...@@ -1186,6 +1190,8 @@ const struct bpf_map_ops sock_hash_ops = { ...@@ -1186,6 +1190,8 @@ const struct bpf_map_ops sock_hash_ops = {
.map_lookup_elem_sys_only = sock_hash_lookup_sys, .map_lookup_elem_sys_only = sock_hash_lookup_sys,
.map_release_uref = sock_hash_release_progs, .map_release_uref = sock_hash_release_progs,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "bpf_shtab",
.map_btf_id = &sock_hash_map_btf_id,
}; };
static struct sk_psock_progs *sock_map_progs(struct bpf_map *map) static struct sk_psock_progs *sock_map_progs(struct bpf_map *map)
...@@ -1194,7 +1200,7 @@ static struct sk_psock_progs *sock_map_progs(struct bpf_map *map) ...@@ -1194,7 +1200,7 @@ static struct sk_psock_progs *sock_map_progs(struct bpf_map *map)
case BPF_MAP_TYPE_SOCKMAP: case BPF_MAP_TYPE_SOCKMAP:
return &container_of(map, struct bpf_stab, map)->progs; return &container_of(map, struct bpf_stab, map)->progs;
case BPF_MAP_TYPE_SOCKHASH: case BPF_MAP_TYPE_SOCKHASH:
return &container_of(map, struct bpf_htab, map)->progs; return &container_of(map, struct bpf_shtab, map)->progs;
default: default:
break; break;
} }
......
...@@ -2957,7 +2957,7 @@ void tcp_sock_set_user_timeout(struct sock *sk, u32 val) ...@@ -2957,7 +2957,7 @@ void tcp_sock_set_user_timeout(struct sock *sk, u32 val)
} }
EXPORT_SYMBOL(tcp_sock_set_user_timeout); EXPORT_SYMBOL(tcp_sock_set_user_timeout);
static int __tcp_sock_set_keepidle(struct sock *sk, int val) int tcp_sock_set_keepidle_locked(struct sock *sk, int val)
{ {
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
...@@ -2984,7 +2984,7 @@ int tcp_sock_set_keepidle(struct sock *sk, int val) ...@@ -2984,7 +2984,7 @@ int tcp_sock_set_keepidle(struct sock *sk, int val)
int err; int err;
lock_sock(sk); lock_sock(sk);
err = __tcp_sock_set_keepidle(sk, val); err = tcp_sock_set_keepidle_locked(sk, val);
release_sock(sk); release_sock(sk);
return err; return err;
} }
...@@ -3183,7 +3183,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, ...@@ -3183,7 +3183,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
break; break;
case TCP_KEEPIDLE: case TCP_KEEPIDLE:
err = __tcp_sock_set_keepidle(sk, val); err = tcp_sock_set_keepidle_locked(sk, val);
break; break;
case TCP_KEEPINTVL: case TCP_KEEPINTVL:
if (val < 1 || val > MAX_TCP_KEEPINTVL) if (val < 1 || val > MAX_TCP_KEEPINTVL)
......
...@@ -2211,13 +2211,18 @@ EXPORT_SYMBOL(tcp_v4_destroy_sock); ...@@ -2211,13 +2211,18 @@ EXPORT_SYMBOL(tcp_v4_destroy_sock);
*/ */
static void *listening_get_next(struct seq_file *seq, void *cur) static void *listening_get_next(struct seq_file *seq, void *cur)
{ {
struct tcp_seq_afinfo *afinfo = PDE_DATA(file_inode(seq->file)); struct tcp_seq_afinfo *afinfo;
struct tcp_iter_state *st = seq->private; struct tcp_iter_state *st = seq->private;
struct net *net = seq_file_net(seq); struct net *net = seq_file_net(seq);
struct inet_listen_hashbucket *ilb; struct inet_listen_hashbucket *ilb;
struct hlist_nulls_node *node; struct hlist_nulls_node *node;
struct sock *sk = cur; struct sock *sk = cur;
if (st->bpf_seq_afinfo)
afinfo = st->bpf_seq_afinfo;
else
afinfo = PDE_DATA(file_inode(seq->file));
if (!sk) { if (!sk) {
get_head: get_head:
ilb = &tcp_hashinfo.listening_hash[st->bucket]; ilb = &tcp_hashinfo.listening_hash[st->bucket];
...@@ -2235,7 +2240,8 @@ static void *listening_get_next(struct seq_file *seq, void *cur) ...@@ -2235,7 +2240,8 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
sk_nulls_for_each_from(sk, node) { sk_nulls_for_each_from(sk, node) {
if (!net_eq(sock_net(sk), net)) if (!net_eq(sock_net(sk), net))
continue; continue;
if (sk->sk_family == afinfo->family) if (afinfo->family == AF_UNSPEC ||
sk->sk_family == afinfo->family)
return sk; return sk;
} }
spin_unlock(&ilb->lock); spin_unlock(&ilb->lock);
...@@ -2272,11 +2278,16 @@ static inline bool empty_bucket(const struct tcp_iter_state *st) ...@@ -2272,11 +2278,16 @@ static inline bool empty_bucket(const struct tcp_iter_state *st)
*/ */
static void *established_get_first(struct seq_file *seq) static void *established_get_first(struct seq_file *seq)
{ {
struct tcp_seq_afinfo *afinfo = PDE_DATA(file_inode(seq->file)); struct tcp_seq_afinfo *afinfo;
struct tcp_iter_state *st = seq->private; struct tcp_iter_state *st = seq->private;
struct net *net = seq_file_net(seq); struct net *net = seq_file_net(seq);
void *rc = NULL; void *rc = NULL;
if (st->bpf_seq_afinfo)
afinfo = st->bpf_seq_afinfo;
else
afinfo = PDE_DATA(file_inode(seq->file));
st->offset = 0; st->offset = 0;
for (; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) { for (; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) {
struct sock *sk; struct sock *sk;
...@@ -2289,7 +2300,8 @@ static void *established_get_first(struct seq_file *seq) ...@@ -2289,7 +2300,8 @@ static void *established_get_first(struct seq_file *seq)
spin_lock_bh(lock); spin_lock_bh(lock);
sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
if (sk->sk_family != afinfo->family || if ((afinfo->family != AF_UNSPEC &&
sk->sk_family != afinfo->family) ||
!net_eq(sock_net(sk), net)) { !net_eq(sock_net(sk), net)) {
continue; continue;
} }
...@@ -2304,19 +2316,25 @@ static void *established_get_first(struct seq_file *seq) ...@@ -2304,19 +2316,25 @@ static void *established_get_first(struct seq_file *seq)
static void *established_get_next(struct seq_file *seq, void *cur) static void *established_get_next(struct seq_file *seq, void *cur)
{ {
struct tcp_seq_afinfo *afinfo = PDE_DATA(file_inode(seq->file)); struct tcp_seq_afinfo *afinfo;
struct sock *sk = cur; struct sock *sk = cur;
struct hlist_nulls_node *node; struct hlist_nulls_node *node;
struct tcp_iter_state *st = seq->private; struct tcp_iter_state *st = seq->private;
struct net *net = seq_file_net(seq); struct net *net = seq_file_net(seq);
if (st->bpf_seq_afinfo)
afinfo = st->bpf_seq_afinfo;
else
afinfo = PDE_DATA(file_inode(seq->file));
++st->num; ++st->num;
++st->offset; ++st->offset;
sk = sk_nulls_next(sk); sk = sk_nulls_next(sk);
sk_nulls_for_each_from(sk, node) { sk_nulls_for_each_from(sk, node) {
if (sk->sk_family == afinfo->family && if ((afinfo->family == AF_UNSPEC ||
sk->sk_family == afinfo->family) &&
net_eq(sock_net(sk), net)) net_eq(sock_net(sk), net))
return sk; return sk;
} }
...@@ -2595,6 +2613,74 @@ static int tcp4_seq_show(struct seq_file *seq, void *v) ...@@ -2595,6 +2613,74 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
return 0; return 0;
} }
#ifdef CONFIG_BPF_SYSCALL
struct bpf_iter__tcp {
__bpf_md_ptr(struct bpf_iter_meta *, meta);
__bpf_md_ptr(struct sock_common *, sk_common);
uid_t uid __aligned(8);
};
static int tcp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
struct sock_common *sk_common, uid_t uid)
{
struct bpf_iter__tcp ctx;
meta->seq_num--; /* skip SEQ_START_TOKEN */
ctx.meta = meta;
ctx.sk_common = sk_common;
ctx.uid = uid;
return bpf_iter_run_prog(prog, &ctx);
}
static int bpf_iter_tcp_seq_show(struct seq_file *seq, void *v)
{
struct bpf_iter_meta meta;
struct bpf_prog *prog;
struct sock *sk = v;
uid_t uid;
if (v == SEQ_START_TOKEN)
return 0;
if (sk->sk_state == TCP_TIME_WAIT) {
uid = 0;
} else if (sk->sk_state == TCP_NEW_SYN_RECV) {
const struct request_sock *req = v;
uid = from_kuid_munged(seq_user_ns(seq),
sock_i_uid(req->rsk_listener));
} else {
uid = from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk));
}
meta.seq = seq;
prog = bpf_iter_get_info(&meta, false);
return tcp_prog_seq_show(prog, &meta, v, uid);
}
static void bpf_iter_tcp_seq_stop(struct seq_file *seq, void *v)
{
struct bpf_iter_meta meta;
struct bpf_prog *prog;
if (!v) {
meta.seq = seq;
prog = bpf_iter_get_info(&meta, true);
if (prog)
(void)tcp_prog_seq_show(prog, &meta, v, 0);
}
tcp_seq_stop(seq, v);
}
static const struct seq_operations bpf_iter_tcp_seq_ops = {
.show = bpf_iter_tcp_seq_show,
.start = tcp_seq_start,
.next = tcp_seq_next,
.stop = bpf_iter_tcp_seq_stop,
};
#endif
static const struct seq_operations tcp4_seq_ops = { static const struct seq_operations tcp4_seq_ops = {
.show = tcp4_seq_show, .show = tcp4_seq_show,
.start = tcp_seq_start, .start = tcp_seq_start,
...@@ -2826,8 +2912,63 @@ static struct pernet_operations __net_initdata tcp_sk_ops = { ...@@ -2826,8 +2912,63 @@ static struct pernet_operations __net_initdata tcp_sk_ops = {
.exit_batch = tcp_sk_exit_batch, .exit_batch = tcp_sk_exit_batch,
}; };
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
DEFINE_BPF_ITER_FUNC(tcp, struct bpf_iter_meta *meta,
struct sock_common *sk_common, uid_t uid)
static int bpf_iter_init_tcp(void *priv_data)
{
struct tcp_iter_state *st = priv_data;
struct tcp_seq_afinfo *afinfo;
int ret;
afinfo = kmalloc(sizeof(*afinfo), GFP_USER | __GFP_NOWARN);
if (!afinfo)
return -ENOMEM;
afinfo->family = AF_UNSPEC;
st->bpf_seq_afinfo = afinfo;
ret = bpf_iter_init_seq_net(priv_data);
if (ret)
kfree(afinfo);
return ret;
}
static void bpf_iter_fini_tcp(void *priv_data)
{
struct tcp_iter_state *st = priv_data;
kfree(st->bpf_seq_afinfo);
bpf_iter_fini_seq_net(priv_data);
}
static const struct bpf_iter_reg tcp_reg_info = {
.target = "tcp",
.seq_ops = &bpf_iter_tcp_seq_ops,
.init_seq_private = bpf_iter_init_tcp,
.fini_seq_private = bpf_iter_fini_tcp,
.seq_priv_size = sizeof(struct tcp_iter_state),
.ctx_arg_info_size = 1,
.ctx_arg_info = {
{ offsetof(struct bpf_iter__tcp, sk_common),
PTR_TO_BTF_ID_OR_NULL },
},
};
static void __init bpf_iter_register(void)
{
if (bpf_iter_reg_target(&tcp_reg_info))
pr_warn("Warning: could not register bpf iterator tcp\n");
}
#endif
void __init tcp_v4_init(void) void __init tcp_v4_init(void)
{ {
if (register_pernet_subsys(&tcp_sk_ops)) if (register_pernet_subsys(&tcp_sk_ops))
panic("Failed to create the TCP control socket.\n"); panic("Failed to create the TCP control socket.\n");
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
bpf_iter_register();
#endif
} }
...@@ -2826,10 +2826,15 @@ EXPORT_SYMBOL(udp_prot); ...@@ -2826,10 +2826,15 @@ EXPORT_SYMBOL(udp_prot);
static struct sock *udp_get_first(struct seq_file *seq, int start) static struct sock *udp_get_first(struct seq_file *seq, int start)
{ {
struct sock *sk; struct sock *sk;
struct udp_seq_afinfo *afinfo = PDE_DATA(file_inode(seq->file)); struct udp_seq_afinfo *afinfo;
struct udp_iter_state *state = seq->private; struct udp_iter_state *state = seq->private;
struct net *net = seq_file_net(seq); struct net *net = seq_file_net(seq);
if (state->bpf_seq_afinfo)
afinfo = state->bpf_seq_afinfo;
else
afinfo = PDE_DATA(file_inode(seq->file));
for (state->bucket = start; state->bucket <= afinfo->udp_table->mask; for (state->bucket = start; state->bucket <= afinfo->udp_table->mask;
++state->bucket) { ++state->bucket) {
struct udp_hslot *hslot = &afinfo->udp_table->hash[state->bucket]; struct udp_hslot *hslot = &afinfo->udp_table->hash[state->bucket];
...@@ -2841,7 +2846,8 @@ static struct sock *udp_get_first(struct seq_file *seq, int start) ...@@ -2841,7 +2846,8 @@ static struct sock *udp_get_first(struct seq_file *seq, int start)
sk_for_each(sk, &hslot->head) { sk_for_each(sk, &hslot->head) {
if (!net_eq(sock_net(sk), net)) if (!net_eq(sock_net(sk), net))
continue; continue;
if (sk->sk_family == afinfo->family) if (afinfo->family == AF_UNSPEC ||
sk->sk_family == afinfo->family)
goto found; goto found;
} }
spin_unlock_bh(&hslot->lock); spin_unlock_bh(&hslot->lock);
...@@ -2853,13 +2859,20 @@ static struct sock *udp_get_first(struct seq_file *seq, int start) ...@@ -2853,13 +2859,20 @@ static struct sock *udp_get_first(struct seq_file *seq, int start)
static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
{ {
struct udp_seq_afinfo *afinfo = PDE_DATA(file_inode(seq->file)); struct udp_seq_afinfo *afinfo;
struct udp_iter_state *state = seq->private; struct udp_iter_state *state = seq->private;
struct net *net = seq_file_net(seq); struct net *net = seq_file_net(seq);
if (state->bpf_seq_afinfo)
afinfo = state->bpf_seq_afinfo;
else
afinfo = PDE_DATA(file_inode(seq->file));
do { do {
sk = sk_next(sk); sk = sk_next(sk);
} while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != afinfo->family)); } while (sk && (!net_eq(sock_net(sk), net) ||
(afinfo->family != AF_UNSPEC &&
sk->sk_family != afinfo->family)));
if (!sk) { if (!sk) {
if (state->bucket <= afinfo->udp_table->mask) if (state->bucket <= afinfo->udp_table->mask)
...@@ -2904,9 +2917,14 @@ EXPORT_SYMBOL(udp_seq_next); ...@@ -2904,9 +2917,14 @@ EXPORT_SYMBOL(udp_seq_next);
void udp_seq_stop(struct seq_file *seq, void *v) void udp_seq_stop(struct seq_file *seq, void *v)
{ {
struct udp_seq_afinfo *afinfo = PDE_DATA(file_inode(seq->file)); struct udp_seq_afinfo *afinfo;
struct udp_iter_state *state = seq->private; struct udp_iter_state *state = seq->private;
if (state->bpf_seq_afinfo)
afinfo = state->bpf_seq_afinfo;
else
afinfo = PDE_DATA(file_inode(seq->file));
if (state->bucket <= afinfo->udp_table->mask) if (state->bucket <= afinfo->udp_table->mask)
spin_unlock_bh(&afinfo->udp_table->hash[state->bucket].lock); spin_unlock_bh(&afinfo->udp_table->hash[state->bucket].lock);
} }
...@@ -2950,6 +2968,67 @@ int udp4_seq_show(struct seq_file *seq, void *v) ...@@ -2950,6 +2968,67 @@ int udp4_seq_show(struct seq_file *seq, void *v)
return 0; return 0;
} }
#ifdef CONFIG_BPF_SYSCALL
struct bpf_iter__udp {
__bpf_md_ptr(struct bpf_iter_meta *, meta);
__bpf_md_ptr(struct udp_sock *, udp_sk);
uid_t uid __aligned(8);
int bucket __aligned(8);
};
static int udp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
struct udp_sock *udp_sk, uid_t uid, int bucket)
{
struct bpf_iter__udp ctx;
meta->seq_num--; /* skip SEQ_START_TOKEN */
ctx.meta = meta;
ctx.udp_sk = udp_sk;
ctx.uid = uid;
ctx.bucket = bucket;
return bpf_iter_run_prog(prog, &ctx);
}
static int bpf_iter_udp_seq_show(struct seq_file *seq, void *v)
{
struct udp_iter_state *state = seq->private;
struct bpf_iter_meta meta;
struct bpf_prog *prog;
struct sock *sk = v;
uid_t uid;
if (v == SEQ_START_TOKEN)
return 0;
uid = from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk));
meta.seq = seq;
prog = bpf_iter_get_info(&meta, false);
return udp_prog_seq_show(prog, &meta, v, uid, state->bucket);
}
static void bpf_iter_udp_seq_stop(struct seq_file *seq, void *v)
{
struct bpf_iter_meta meta;
struct bpf_prog *prog;
if (!v) {
meta.seq = seq;
prog = bpf_iter_get_info(&meta, true);
if (prog)
(void)udp_prog_seq_show(prog, &meta, v, 0, 0);
}
udp_seq_stop(seq, v);
}
static const struct seq_operations bpf_iter_udp_seq_ops = {
.start = udp_seq_start,
.next = udp_seq_next,
.stop = bpf_iter_udp_seq_stop,
.show = bpf_iter_udp_seq_show,
};
#endif
const struct seq_operations udp_seq_ops = { const struct seq_operations udp_seq_ops = {
.start = udp_seq_start, .start = udp_seq_start,
.next = udp_seq_next, .next = udp_seq_next,
...@@ -3067,6 +3146,57 @@ static struct pernet_operations __net_initdata udp_sysctl_ops = { ...@@ -3067,6 +3146,57 @@ static struct pernet_operations __net_initdata udp_sysctl_ops = {
.init = udp_sysctl_init, .init = udp_sysctl_init,
}; };
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
DEFINE_BPF_ITER_FUNC(udp, struct bpf_iter_meta *meta,
struct udp_sock *udp_sk, uid_t uid, int bucket)
static int bpf_iter_init_udp(void *priv_data)
{
struct udp_iter_state *st = priv_data;
struct udp_seq_afinfo *afinfo;
int ret;
afinfo = kmalloc(sizeof(*afinfo), GFP_USER | __GFP_NOWARN);
if (!afinfo)
return -ENOMEM;
afinfo->family = AF_UNSPEC;
afinfo->udp_table = &udp_table;
st->bpf_seq_afinfo = afinfo;
ret = bpf_iter_init_seq_net(priv_data);
if (ret)
kfree(afinfo);
return ret;
}
static void bpf_iter_fini_udp(void *priv_data)
{
struct udp_iter_state *st = priv_data;
kfree(st->bpf_seq_afinfo);
bpf_iter_fini_seq_net(priv_data);
}
static const struct bpf_iter_reg udp_reg_info = {
.target = "udp",
.seq_ops = &bpf_iter_udp_seq_ops,
.init_seq_private = bpf_iter_init_udp,
.fini_seq_private = bpf_iter_fini_udp,
.seq_priv_size = sizeof(struct udp_iter_state),
.ctx_arg_info_size = 1,
.ctx_arg_info = {
{ offsetof(struct bpf_iter__udp, udp_sk),
PTR_TO_BTF_ID_OR_NULL },
},
};
static void __init bpf_iter_register(void)
{
if (bpf_iter_reg_target(&udp_reg_info))
pr_warn("Warning: could not register bpf iterator udp\n");
}
#endif
void __init udp_init(void) void __init udp_init(void)
{ {
unsigned long limit; unsigned long limit;
...@@ -3092,4 +3222,8 @@ void __init udp_init(void) ...@@ -3092,4 +3222,8 @@ void __init udp_init(void)
if (register_pernet_subsys(&udp_sysctl_ops)) if (register_pernet_subsys(&udp_sysctl_ops))
panic("UDP: failed to init sysctl parameters.\n"); panic("UDP: failed to init sysctl parameters.\n");
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
bpf_iter_register();
#endif
} }
...@@ -254,6 +254,7 @@ void xsk_map_try_sock_delete(struct xsk_map *map, struct xdp_sock *xs, ...@@ -254,6 +254,7 @@ void xsk_map_try_sock_delete(struct xsk_map *map, struct xdp_sock *xs,
spin_unlock_bh(&map->lock); spin_unlock_bh(&map->lock);
} }
static int xsk_map_btf_id;
const struct bpf_map_ops xsk_map_ops = { const struct bpf_map_ops xsk_map_ops = {
.map_alloc = xsk_map_alloc, .map_alloc = xsk_map_alloc,
.map_free = xsk_map_free, .map_free = xsk_map_free,
...@@ -264,4 +265,6 @@ const struct bpf_map_ops xsk_map_ops = { ...@@ -264,4 +265,6 @@ const struct bpf_map_ops xsk_map_ops = {
.map_update_elem = xsk_map_update_elem, .map_update_elem = xsk_map_update_elem,
.map_delete_elem = xsk_map_delete_elem, .map_delete_elem = xsk_map_delete_elem,
.map_check_btf = map_check_no_btf, .map_check_btf = map_check_no_btf,
.map_btf_name = "xsk_map",
.map_btf_id = &xsk_map_btf_id,
}; };
...@@ -421,6 +421,12 @@ class PrinterHelpers(Printer): ...@@ -421,6 +421,12 @@ class PrinterHelpers(Printer):
'struct sockaddr', 'struct sockaddr',
'struct tcphdr', 'struct tcphdr',
'struct seq_file', 'struct seq_file',
'struct tcp6_sock',
'struct tcp_sock',
'struct tcp_timewait_sock',
'struct tcp_request_sock',
'struct udp6_sock',
'struct task_struct',
'struct __sk_buff', 'struct __sk_buff',
'struct sk_msg_md', 'struct sk_msg_md',
...@@ -458,6 +464,12 @@ class PrinterHelpers(Printer): ...@@ -458,6 +464,12 @@ class PrinterHelpers(Printer):
'struct sockaddr', 'struct sockaddr',
'struct tcphdr', 'struct tcphdr',
'struct seq_file', 'struct seq_file',
'struct tcp6_sock',
'struct tcp_sock',
'struct tcp_timewait_sock',
'struct tcp_request_sock',
'struct udp6_sock',
'struct task_struct',
} }
mapped_types = { mapped_types = {
'u8': '__u8', 'u8': '__u8',
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
*.d *.d
/_bpftool /bpftool-bootstrap
/bpftool /bpftool
bpftool*.8 bpftool*.8
bpf-helpers.* bpf-helpers.*
FEATURE-DUMP.bpftool FEATURE-DUMP.bpftool
feature feature
libbpf libbpf
profiler.skel.h /*.skel.h
/vmlinux.h
...@@ -36,6 +36,11 @@ DESCRIPTION ...@@ -36,6 +36,11 @@ DESCRIPTION
otherwise list all BTF objects currently loaded on the otherwise list all BTF objects currently loaded on the
system. system.
Since Linux 5.8 bpftool is able to discover information about
processes that hold open file descriptors (FDs) against BTF
objects. On such kernels bpftool will automatically emit this
information as well.
**bpftool btf dump** *BTF_SRC* **bpftool btf dump** *BTF_SRC*
Dump BTF entries from a given *BTF_SRC*. Dump BTF entries from a given *BTF_SRC*.
......
...@@ -37,6 +37,11 @@ DESCRIPTION ...@@ -37,6 +37,11 @@ DESCRIPTION
zero or more named attributes, some of which depend on type zero or more named attributes, some of which depend on type
of link. of link.
Since Linux 5.8 bpftool is able to discover information about
processes that hold open file descriptors (FDs) against BPF
links. On such kernels bpftool will automatically emit this
information as well.
**bpftool link pin** *LINK* *FILE* **bpftool link pin** *LINK* *FILE*
Pin link *LINK* as *FILE*. Pin link *LINK* as *FILE*.
...@@ -82,6 +87,7 @@ EXAMPLES ...@@ -82,6 +87,7 @@ EXAMPLES
10: cgroup prog 25 10: cgroup prog 25
cgroup_id 614 attach_type egress cgroup_id 614 attach_type egress
pids test_progs(223)
**# bpftool --json --pretty link show** **# bpftool --json --pretty link show**
...@@ -91,7 +97,12 @@ EXAMPLES ...@@ -91,7 +97,12 @@ EXAMPLES
"type": "cgroup", "type": "cgroup",
"prog_id": 25, "prog_id": 25,
"cgroup_id": 614, "cgroup_id": 614,
"attach_type": "egress" "attach_type": "egress",
"pids": [{
"pid": 223,
"comm": "test_progs"
}
]
} }
] ]
......
...@@ -62,6 +62,11 @@ DESCRIPTION ...@@ -62,6 +62,11 @@ DESCRIPTION
Output will start with map ID followed by map type and Output will start with map ID followed by map type and
zero or more named attributes (depending on kernel version). zero or more named attributes (depending on kernel version).
Since Linux 5.8 bpftool is able to discover information about
processes that hold open file descriptors (FDs) against BPF
maps. On such kernels bpftool will automatically emit this
information as well.
**bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*] **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*]
Create a new map with given parameters and pin it to *bpffs* Create a new map with given parameters and pin it to *bpffs*
as *FILE*. as *FILE*.
...@@ -180,7 +185,8 @@ EXAMPLES ...@@ -180,7 +185,8 @@ EXAMPLES
:: ::
10: hash name some_map flags 0x0 10: hash name some_map flags 0x0
key 4B value 8B max_entries 2048 memlock 167936B key 4B value 8B max_entries 2048 memlock 167936B
pids systemd(1)
The following three commands are equivalent: The following three commands are equivalent:
......
...@@ -75,6 +75,11 @@ DESCRIPTION ...@@ -75,6 +75,11 @@ DESCRIPTION
program run. Activation or deactivation of the feature is program run. Activation or deactivation of the feature is
performed via the **kernel.bpf_stats_enabled** sysctl knob. performed via the **kernel.bpf_stats_enabled** sysctl knob.
Since Linux 5.8 bpftool is able to discover information about
processes that hold open file descriptors (FDs) against BPF
programs. On such kernels bpftool will automatically emit this
information as well.
**bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** | **linum** }] **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** | **linum** }]
Dump eBPF instructions of the programs from the kernel. By Dump eBPF instructions of the programs from the kernel. By
default, eBPF will be disassembled and printed to standard default, eBPF will be disassembled and printed to standard
...@@ -243,6 +248,7 @@ EXAMPLES ...@@ -243,6 +248,7 @@ EXAMPLES
10: xdp name some_prog tag 005a3d2123620c8b gpl run_time_ns 81632 run_cnt 10 10: xdp name some_prog tag 005a3d2123620c8b gpl run_time_ns 81632 run_cnt 10
loaded_at 2017-09-29T20:11:00+0000 uid 0 loaded_at 2017-09-29T20:11:00+0000 uid 0
xlated 528B jited 370B memlock 4096B map_ids 10 xlated 528B jited 370B memlock 4096B map_ids 10
pids systemd(1)
**# bpftool --json --pretty prog show** **# bpftool --json --pretty prog show**
...@@ -262,6 +268,11 @@ EXAMPLES ...@@ -262,6 +268,11 @@ EXAMPLES
"bytes_jited": 370, "bytes_jited": 370,
"bytes_memlock": 4096, "bytes_memlock": 4096,
"map_ids": [10 "map_ids": [10
],
"pids": [{
"pid": 1,
"comm": "systemd"
}
] ]
} }
] ]
......
...@@ -40,8 +40,9 @@ bash_compdir ?= /usr/share/bash-completion/completions ...@@ -40,8 +40,9 @@ bash_compdir ?= /usr/share/bash-completion/completions
CFLAGS += -O2 CFLAGS += -O2
CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
CFLAGS += $(filter-out -Wswitch-enum,$(EXTRA_WARNINGS)) CFLAGS += $(filter-out -Wswitch-enum -Wnested-externs,$(EXTRA_WARNINGS))
CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \ CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \
-I$(if $(OUTPUT),$(OUTPUT),.) \
-I$(srctree)/kernel/bpf/ \ -I$(srctree)/kernel/bpf/ \
-I$(srctree)/tools/include \ -I$(srctree)/tools/include \
-I$(srctree)/tools/include/uapi \ -I$(srctree)/tools/include/uapi \
...@@ -61,9 +62,9 @@ CLANG ?= clang ...@@ -61,9 +62,9 @@ CLANG ?= clang
FEATURE_USER = .bpftool FEATURE_USER = .bpftool
FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \ FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \
clang-bpf-global-var clang-bpf-co-re
FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \ FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \
clang-bpf-global-var clang-bpf-co-re
check_feat := 1 check_feat := 1
NON_CHECK_FEAT_TARGETS := clean uninstall doc doc-clean doc-install doc-uninstall NON_CHECK_FEAT_TARGETS := clean uninstall doc doc-clean doc-install doc-uninstall
...@@ -116,40 +117,60 @@ CFLAGS += -DHAVE_LIBBFD_SUPPORT ...@@ -116,40 +117,60 @@ CFLAGS += -DHAVE_LIBBFD_SUPPORT
SRCS += $(BFD_SRCS) SRCS += $(BFD_SRCS)
endif endif
BPFTOOL_BOOTSTRAP := $(if $(OUTPUT),$(OUTPUT)bpftool-bootstrap,./bpftool-bootstrap)
BOOTSTRAP_OBJS = $(addprefix $(OUTPUT),main.o common.o json_writer.o gen.o btf.o)
OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o
_OBJS = $(filter-out $(OUTPUT)prog.o,$(OBJS)) $(OUTPUT)_prog.o
ifeq ($(feature-clang-bpf-global-var),1) VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
__OBJS = $(OBJS) $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
else ../../../vmlinux \
__OBJS = $(_OBJS) /sys/kernel/btf/vmlinux \
endif /boot/vmlinux-$(shell uname -r)
VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
$(OUTPUT)_prog.o: prog.c ifneq ($(VMLINUX_BTF)$(VMLINUX_H),)
$(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -DBPFTOOL_WITHOUT_SKELETONS -o $@ $< ifeq ($(feature-clang-bpf-co-re),1)
$(OUTPUT)_bpftool: $(_OBJS) $(LIBBPF) BUILD_BPF_SKELS := 1
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(_OBJS) $(LIBS)
skeleton/profiler.bpf.o: skeleton/profiler.bpf.c $(LIBBPF) $(OUTPUT)vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL_BOOTSTRAP)
ifeq ($(VMLINUX_H),)
$(QUIET_GEN)$(BPFTOOL_BOOTSTRAP) btf dump file $< format c > $@
else
$(Q)cp "$(VMLINUX_H)" $@
endif
$(OUTPUT)%.bpf.o: skeleton/%.bpf.c $(OUTPUT)vmlinux.h $(LIBBPF)
$(QUIET_CLANG)$(CLANG) \ $(QUIET_CLANG)$(CLANG) \
-I$(if $(OUTPUT),$(OUTPUT),.) \
-I$(srctree)/tools/include/uapi/ \ -I$(srctree)/tools/include/uapi/ \
-I$(LIBBPF_PATH) -I$(srctree)/tools/lib \ -I$(LIBBPF_PATH) \
-I$(srctree)/tools/lib \
-g -O2 -target bpf -c $< -o $@ -g -O2 -target bpf -c $< -o $@
profiler.skel.h: $(OUTPUT)_bpftool skeleton/profiler.bpf.o $(OUTPUT)%.skel.h: $(OUTPUT)%.bpf.o $(BPFTOOL_BOOTSTRAP)
$(QUIET_GEN)$(OUTPUT)./_bpftool gen skeleton skeleton/profiler.bpf.o > $@ $(QUIET_GEN)$(BPFTOOL_BOOTSTRAP) gen skeleton $< > $@
$(OUTPUT)prog.o: prog.c profiler.skel.h $(OUTPUT)prog.o: $(OUTPUT)profiler.skel.h
$(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $<
$(OUTPUT)pids.o: $(OUTPUT)pid_iter.skel.h
endif
endif
CFLAGS += $(if $(BUILD_BPF_SKELS),,-DBPFTOOL_WITHOUT_SKELETONS)
$(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c $(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c
$(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $< $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $<
$(OUTPUT)feature.o: | zdep $(OUTPUT)feature.o: | zdep
$(OUTPUT)bpftool: $(__OBJS) $(LIBBPF) $(BPFTOOL_BOOTSTRAP): $(BOOTSTRAP_OBJS) $(LIBBPF)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(__OBJS) $(LIBS) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BOOTSTRAP_OBJS) $(LIBS)
$(OUTPUT)bpftool: $(OBJS) $(LIBBPF)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
$(OUTPUT)%.o: %.c $(OUTPUT)%.o: %.c
$(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $< $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $<
...@@ -157,7 +178,7 @@ $(OUTPUT)%.o: %.c ...@@ -157,7 +178,7 @@ $(OUTPUT)%.o: %.c
clean: $(LIBBPF)-clean clean: $(LIBBPF)-clean
$(call QUIET_CLEAN, bpftool) $(call QUIET_CLEAN, bpftool)
$(Q)$(RM) -- $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d $(Q)$(RM) -- $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d
$(Q)$(RM) -- $(OUTPUT)_bpftool profiler.skel.h skeleton/profiler.bpf.o $(Q)$(RM) -- $(BPFTOOL_BOOTSTRAP) $(OUTPUT)*.skel.h $(OUTPUT)vmlinux.h
$(Q)$(RM) -r -- $(OUTPUT)libbpf/ $(Q)$(RM) -r -- $(OUTPUT)libbpf/
$(call QUIET_CLEAN, core-gen) $(call QUIET_CLEAN, core-gen)
$(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpftool $(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpftool
...@@ -192,6 +213,7 @@ FORCE: ...@@ -192,6 +213,7 @@ FORCE:
zdep: zdep:
@if [ "$(feature-zlib)" != "1" ]; then echo "No zlib found"; exit 1 ; fi @if [ "$(feature-zlib)" != "1" ]; then echo "No zlib found"; exit 1 ; fi
.SECONDARY:
.PHONY: all FORCE clean install uninstall zdep .PHONY: all FORCE clean install uninstall zdep
.PHONY: doc doc-clean doc-install doc-uninstall .PHONY: doc doc-clean doc-install doc-uninstall
.DEFAULT_GOAL := all .DEFAULT_GOAL := all
...@@ -809,6 +809,7 @@ show_btf_plain(struct bpf_btf_info *info, int fd, ...@@ -809,6 +809,7 @@ show_btf_plain(struct bpf_btf_info *info, int fd,
printf("%s%u", n++ == 0 ? " map_ids " : ",", printf("%s%u", n++ == 0 ? " map_ids " : ",",
obj->obj_id); obj->obj_id);
} }
emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
printf("\n"); printf("\n");
} }
...@@ -841,6 +842,9 @@ show_btf_json(struct bpf_btf_info *info, int fd, ...@@ -841,6 +842,9 @@ show_btf_json(struct bpf_btf_info *info, int fd,
jsonw_uint(json_wtr, obj->obj_id); jsonw_uint(json_wtr, obj->obj_id);
} }
jsonw_end_array(json_wtr); /* map_ids */ jsonw_end_array(json_wtr); /* map_ids */
emit_obj_refs_json(&refs_table, info->id, json_wtr); /* pids */
jsonw_end_object(json_wtr); /* btf object */ jsonw_end_object(json_wtr); /* btf object */
} }
...@@ -893,6 +897,7 @@ static int do_show(int argc, char **argv) ...@@ -893,6 +897,7 @@ static int do_show(int argc, char **argv)
close(fd); close(fd);
return err; return err;
} }
build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
if (fd >= 0) { if (fd >= 0) {
err = show_btf(fd, &btf_prog_table, &btf_map_table); err = show_btf(fd, &btf_prog_table, &btf_map_table);
...@@ -939,6 +944,7 @@ static int do_show(int argc, char **argv) ...@@ -939,6 +944,7 @@ static int do_show(int argc, char **argv)
exit_free: exit_free:
delete_btf_table(&btf_prog_table); delete_btf_table(&btf_prog_table);
delete_btf_table(&btf_map_table); delete_btf_table(&btf_map_table);
delete_obj_refs_table(&refs_table);
return err; return err;
} }
......
...@@ -29,6 +29,42 @@ ...@@ -29,6 +29,42 @@
#define BPF_FS_MAGIC 0xcafe4a11 #define BPF_FS_MAGIC 0xcafe4a11
#endif #endif
const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE] = {
[BPF_CGROUP_INET_INGRESS] = "ingress",
[BPF_CGROUP_INET_EGRESS] = "egress",
[BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
[BPF_CGROUP_SOCK_OPS] = "sock_ops",
[BPF_CGROUP_DEVICE] = "device",
[BPF_CGROUP_INET4_BIND] = "bind4",
[BPF_CGROUP_INET6_BIND] = "bind6",
[BPF_CGROUP_INET4_CONNECT] = "connect4",
[BPF_CGROUP_INET6_CONNECT] = "connect6",
[BPF_CGROUP_INET4_POST_BIND] = "post_bind4",
[BPF_CGROUP_INET6_POST_BIND] = "post_bind6",
[BPF_CGROUP_INET4_GETPEERNAME] = "getpeername4",
[BPF_CGROUP_INET6_GETPEERNAME] = "getpeername6",
[BPF_CGROUP_INET4_GETSOCKNAME] = "getsockname4",
[BPF_CGROUP_INET6_GETSOCKNAME] = "getsockname6",
[BPF_CGROUP_UDP4_SENDMSG] = "sendmsg4",
[BPF_CGROUP_UDP6_SENDMSG] = "sendmsg6",
[BPF_CGROUP_SYSCTL] = "sysctl",
[BPF_CGROUP_UDP4_RECVMSG] = "recvmsg4",
[BPF_CGROUP_UDP6_RECVMSG] = "recvmsg6",
[BPF_CGROUP_GETSOCKOPT] = "getsockopt",
[BPF_CGROUP_SETSOCKOPT] = "setsockopt",
[BPF_SK_SKB_STREAM_PARSER] = "sk_skb_stream_parser",
[BPF_SK_SKB_STREAM_VERDICT] = "sk_skb_stream_verdict",
[BPF_SK_MSG_VERDICT] = "sk_msg_verdict",
[BPF_LIRC_MODE2] = "lirc_mode2",
[BPF_FLOW_DISSECTOR] = "flow_dissector",
[BPF_TRACE_RAW_TP] = "raw_tp",
[BPF_TRACE_FENTRY] = "fentry",
[BPF_TRACE_FEXIT] = "fexit",
[BPF_MODIFY_RETURN] = "mod_ret",
[BPF_LSM_MAC] = "lsm_mac",
};
void p_err(const char *fmt, ...) void p_err(const char *fmt, ...)
{ {
va_list ap; va_list ap;
...@@ -581,3 +617,311 @@ print_all_levels(__maybe_unused enum libbpf_print_level level, ...@@ -581,3 +617,311 @@ print_all_levels(__maybe_unused enum libbpf_print_level level,
{ {
return vfprintf(stderr, format, args); return vfprintf(stderr, format, args);
} }
static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
{
unsigned int id = 0;
int fd, nb_fds = 0;
void *tmp;
int err;
while (true) {
struct bpf_prog_info info = {};
__u32 len = sizeof(info);
err = bpf_prog_get_next_id(id, &id);
if (err) {
if (errno != ENOENT) {
p_err("%s", strerror(errno));
goto err_close_fds;
}
return nb_fds;
}
fd = bpf_prog_get_fd_by_id(id);
if (fd < 0) {
p_err("can't get prog by id (%u): %s",
id, strerror(errno));
goto err_close_fds;
}
err = bpf_obj_get_info_by_fd(fd, &info, &len);
if (err) {
p_err("can't get prog info (%u): %s",
id, strerror(errno));
goto err_close_fd;
}
if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
(!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
close(fd);
continue;
}
if (nb_fds > 0) {
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
if (!tmp) {
p_err("failed to realloc");
goto err_close_fd;
}
*fds = tmp;
}
(*fds)[nb_fds++] = fd;
}
err_close_fd:
close(fd);
err_close_fds:
while (--nb_fds >= 0)
close((*fds)[nb_fds]);
return -1;
}
int prog_parse_fds(int *argc, char ***argv, int **fds)
{
if (is_prefix(**argv, "id")) {
unsigned int id;
char *endptr;
NEXT_ARGP();
id = strtoul(**argv, &endptr, 0);
if (*endptr) {
p_err("can't parse %s as ID", **argv);
return -1;
}
NEXT_ARGP();
(*fds)[0] = bpf_prog_get_fd_by_id(id);
if ((*fds)[0] < 0) {
p_err("get by id (%u): %s", id, strerror(errno));
return -1;
}
return 1;
} else if (is_prefix(**argv, "tag")) {
unsigned char tag[BPF_TAG_SIZE];
NEXT_ARGP();
if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
!= BPF_TAG_SIZE) {
p_err("can't parse tag");
return -1;
}
NEXT_ARGP();
return prog_fd_by_nametag(tag, fds, true);
} else if (is_prefix(**argv, "name")) {
char *name;
NEXT_ARGP();
name = **argv;
if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
p_err("can't parse name");
return -1;
}
NEXT_ARGP();
return prog_fd_by_nametag(name, fds, false);
} else if (is_prefix(**argv, "pinned")) {
char *path;
NEXT_ARGP();
path = **argv;
NEXT_ARGP();
(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
if ((*fds)[0] < 0)
return -1;
return 1;
}
p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
return -1;
}
int prog_parse_fd(int *argc, char ***argv)
{
int *fds = NULL;
int nb_fds, fd;
fds = malloc(sizeof(int));
if (!fds) {
p_err("mem alloc failed");
return -1;
}
nb_fds = prog_parse_fds(argc, argv, &fds);
if (nb_fds != 1) {
if (nb_fds > 1) {
p_err("several programs match this handle");
while (nb_fds--)
close(fds[nb_fds]);
}
fd = -1;
goto exit_free;
}
fd = fds[0];
exit_free:
free(fds);
return fd;
}
static int map_fd_by_name(char *name, int **fds)
{
unsigned int id = 0;
int fd, nb_fds = 0;
void *tmp;
int err;
while (true) {
struct bpf_map_info info = {};
__u32 len = sizeof(info);
err = bpf_map_get_next_id(id, &id);
if (err) {
if (errno != ENOENT) {
p_err("%s", strerror(errno));
goto err_close_fds;
}
return nb_fds;
}
fd = bpf_map_get_fd_by_id(id);
if (fd < 0) {
p_err("can't get map by id (%u): %s",
id, strerror(errno));
goto err_close_fds;
}
err = bpf_obj_get_info_by_fd(fd, &info, &len);
if (err) {
p_err("can't get map info (%u): %s",
id, strerror(errno));
goto err_close_fd;
}
if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
close(fd);
continue;
}
if (nb_fds > 0) {
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
if (!tmp) {
p_err("failed to realloc");
goto err_close_fd;
}
*fds = tmp;
}
(*fds)[nb_fds++] = fd;
}
err_close_fd:
close(fd);
err_close_fds:
while (--nb_fds >= 0)
close((*fds)[nb_fds]);
return -1;
}
int map_parse_fds(int *argc, char ***argv, int **fds)
{
if (is_prefix(**argv, "id")) {
unsigned int id;
char *endptr;
NEXT_ARGP();
id = strtoul(**argv, &endptr, 0);
if (*endptr) {
p_err("can't parse %s as ID", **argv);
return -1;
}
NEXT_ARGP();
(*fds)[0] = bpf_map_get_fd_by_id(id);
if ((*fds)[0] < 0) {
p_err("get map by id (%u): %s", id, strerror(errno));
return -1;
}
return 1;
} else if (is_prefix(**argv, "name")) {
char *name;
NEXT_ARGP();
name = **argv;
if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
p_err("can't parse name");
return -1;
}
NEXT_ARGP();
return map_fd_by_name(name, fds);
} else if (is_prefix(**argv, "pinned")) {
char *path;
NEXT_ARGP();
path = **argv;
NEXT_ARGP();
(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
if ((*fds)[0] < 0)
return -1;
return 1;
}
p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
return -1;
}
int map_parse_fd(int *argc, char ***argv)
{
int *fds = NULL;
int nb_fds, fd;
fds = malloc(sizeof(int));
if (!fds) {
p_err("mem alloc failed");
return -1;
}
nb_fds = map_parse_fds(argc, argv, &fds);
if (nb_fds != 1) {
if (nb_fds > 1) {
p_err("several maps match this handle");
while (nb_fds--)
close(fds[nb_fds]);
}
fd = -1;
goto exit_free;
}
fd = fds[0];
exit_free:
free(fds);
return fd;
}
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
{
int err;
int fd;
fd = map_parse_fd(argc, argv);
if (fd < 0)
return -1;
err = bpf_obj_get_info_by_fd(fd, info, info_len);
if (err) {
p_err("can't get map info: %s", strerror(errno));
close(fd);
return err;
}
return fd;
}
...@@ -695,7 +695,7 @@ section_program_types(bool *supported_types, const char *define_prefix, ...@@ -695,7 +695,7 @@ section_program_types(bool *supported_types, const char *define_prefix,
"/*** eBPF program types ***/", "/*** eBPF program types ***/",
define_prefix); define_prefix);
for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) for (i = BPF_PROG_TYPE_UNSPEC + 1; i < prog_type_name_size; i++)
probe_prog_type(i, supported_types, define_prefix, ifindex); probe_prog_type(i, supported_types, define_prefix, ifindex);
print_end_section(); print_end_section();
...@@ -741,7 +741,7 @@ section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex) ...@@ -741,7 +741,7 @@ section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex)
" %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n", " %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n",
define_prefix, define_prefix, define_prefix, define_prefix, define_prefix, define_prefix,
define_prefix); define_prefix);
for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) for (i = BPF_PROG_TYPE_UNSPEC + 1; i < prog_type_name_size; i++)
probe_helpers_for_progtype(i, supported_types[i], define_prefix, probe_helpers_for_progtype(i, supported_types[i], define_prefix,
ifindex); ifindex);
......
...@@ -108,7 +108,7 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) ...@@ -108,7 +108,7 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
if (err) if (err)
return err; return err;
if (prog_info.type < ARRAY_SIZE(prog_type_name)) if (prog_info.type < prog_type_name_size)
jsonw_string_field(json_wtr, "prog_type", jsonw_string_field(json_wtr, "prog_type",
prog_type_name[prog_info.type]); prog_type_name[prog_info.type]);
else else
...@@ -143,6 +143,9 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) ...@@ -143,6 +143,9 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
} }
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
} }
emit_obj_refs_json(&refs_table, info->id, json_wtr);
jsonw_end_object(json_wtr); jsonw_end_object(json_wtr);
return 0; return 0;
...@@ -184,7 +187,7 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) ...@@ -184,7 +187,7 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
if (err) if (err)
return err; return err;
if (prog_info.type < ARRAY_SIZE(prog_type_name)) if (prog_info.type < prog_type_name_size)
printf("\n\tprog_type %s ", printf("\n\tprog_type %s ",
prog_type_name[prog_info.type]); prog_type_name[prog_info.type]);
else else
...@@ -212,6 +215,7 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) ...@@ -212,6 +215,7 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
printf("\n\tpinned %s", obj->path); printf("\n\tpinned %s", obj->path);
} }
} }
emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
printf("\n"); printf("\n");
...@@ -257,6 +261,7 @@ static int do_show(int argc, char **argv) ...@@ -257,6 +261,7 @@ static int do_show(int argc, char **argv)
if (show_pinned) if (show_pinned)
build_pinned_obj_table(&link_table, BPF_OBJ_LINK); build_pinned_obj_table(&link_table, BPF_OBJ_LINK);
build_obj_refs_table(&refs_table, BPF_OBJ_LINK);
if (argc == 2) { if (argc == 2) {
fd = link_parse_fd(&argc, &argv); fd = link_parse_fd(&argc, &argv);
...@@ -296,6 +301,8 @@ static int do_show(int argc, char **argv) ...@@ -296,6 +301,8 @@ static int do_show(int argc, char **argv)
if (json_output) if (json_output)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
delete_obj_refs_table(&refs_table);
return errno == ENOENT ? 0 : -1; return errno == ENOENT ? 0 : -1;
} }
......
...@@ -31,6 +31,7 @@ bool relaxed_maps; ...@@ -31,6 +31,7 @@ bool relaxed_maps;
struct pinned_obj_table prog_table; struct pinned_obj_table prog_table;
struct pinned_obj_table map_table; struct pinned_obj_table map_table;
struct pinned_obj_table link_table; struct pinned_obj_table link_table;
struct obj_refs_table refs_table;
static void __noreturn clean_and_exit(int i) static void __noreturn clean_and_exit(int i)
{ {
...@@ -92,9 +93,16 @@ int cmd_select(const struct cmd *cmds, int argc, char **argv, ...@@ -92,9 +93,16 @@ int cmd_select(const struct cmd *cmds, int argc, char **argv,
if (argc < 1 && cmds[0].func) if (argc < 1 && cmds[0].func)
return cmds[0].func(argc, argv); return cmds[0].func(argc, argv);
for (i = 0; cmds[i].func; i++) for (i = 0; cmds[i].cmd; i++) {
if (is_prefix(*argv, cmds[i].cmd)) if (is_prefix(*argv, cmds[i].cmd)) {
if (!cmds[i].func) {
p_err("command '%s' is not supported in bootstrap mode",
cmds[i].cmd);
return -1;
}
return cmds[i].func(argc - 1, argv + 1); return cmds[i].func(argc - 1, argv + 1);
}
}
help(argc - 1, argv + 1); help(argc - 1, argv + 1);
......
...@@ -56,82 +56,21 @@ ...@@ -56,82 +56,21 @@
#define HELP_SPEC_LINK \ #define HELP_SPEC_LINK \
"LINK := { id LINK_ID | pinned FILE }" "LINK := { id LINK_ID | pinned FILE }"
static const char * const prog_type_name[] = { extern const char * const prog_type_name[];
[BPF_PROG_TYPE_UNSPEC] = "unspec", extern const size_t prog_type_name_size;
[BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter",
[BPF_PROG_TYPE_KPROBE] = "kprobe",
[BPF_PROG_TYPE_SCHED_CLS] = "sched_cls",
[BPF_PROG_TYPE_SCHED_ACT] = "sched_act",
[BPF_PROG_TYPE_TRACEPOINT] = "tracepoint",
[BPF_PROG_TYPE_XDP] = "xdp",
[BPF_PROG_TYPE_PERF_EVENT] = "perf_event",
[BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb",
[BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock",
[BPF_PROG_TYPE_LWT_IN] = "lwt_in",
[BPF_PROG_TYPE_LWT_OUT] = "lwt_out",
[BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit",
[BPF_PROG_TYPE_SOCK_OPS] = "sock_ops",
[BPF_PROG_TYPE_SK_SKB] = "sk_skb",
[BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device",
[BPF_PROG_TYPE_SK_MSG] = "sk_msg",
[BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint",
[BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr",
[BPF_PROG_TYPE_LWT_SEG6LOCAL] = "lwt_seg6local",
[BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2",
[BPF_PROG_TYPE_SK_REUSEPORT] = "sk_reuseport",
[BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector",
[BPF_PROG_TYPE_CGROUP_SYSCTL] = "cgroup_sysctl",
[BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable",
[BPF_PROG_TYPE_CGROUP_SOCKOPT] = "cgroup_sockopt",
[BPF_PROG_TYPE_TRACING] = "tracing",
[BPF_PROG_TYPE_STRUCT_OPS] = "struct_ops",
[BPF_PROG_TYPE_EXT] = "ext",
};
static const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE] = { extern const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE];
[BPF_CGROUP_INET_INGRESS] = "ingress",
[BPF_CGROUP_INET_EGRESS] = "egress",
[BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
[BPF_CGROUP_SOCK_OPS] = "sock_ops",
[BPF_CGROUP_DEVICE] = "device",
[BPF_CGROUP_INET4_BIND] = "bind4",
[BPF_CGROUP_INET6_BIND] = "bind6",
[BPF_CGROUP_INET4_CONNECT] = "connect4",
[BPF_CGROUP_INET6_CONNECT] = "connect6",
[BPF_CGROUP_INET4_POST_BIND] = "post_bind4",
[BPF_CGROUP_INET6_POST_BIND] = "post_bind6",
[BPF_CGROUP_INET4_GETPEERNAME] = "getpeername4",
[BPF_CGROUP_INET6_GETPEERNAME] = "getpeername6",
[BPF_CGROUP_INET4_GETSOCKNAME] = "getsockname4",
[BPF_CGROUP_INET6_GETSOCKNAME] = "getsockname6",
[BPF_CGROUP_UDP4_SENDMSG] = "sendmsg4",
[BPF_CGROUP_UDP6_SENDMSG] = "sendmsg6",
[BPF_CGROUP_SYSCTL] = "sysctl",
[BPF_CGROUP_UDP4_RECVMSG] = "recvmsg4",
[BPF_CGROUP_UDP6_RECVMSG] = "recvmsg6",
[BPF_CGROUP_GETSOCKOPT] = "getsockopt",
[BPF_CGROUP_SETSOCKOPT] = "setsockopt",
[BPF_SK_SKB_STREAM_PARSER] = "sk_skb_stream_parser",
[BPF_SK_SKB_STREAM_VERDICT] = "sk_skb_stream_verdict",
[BPF_SK_MSG_VERDICT] = "sk_msg_verdict",
[BPF_LIRC_MODE2] = "lirc_mode2",
[BPF_FLOW_DISSECTOR] = "flow_dissector",
[BPF_TRACE_RAW_TP] = "raw_tp",
[BPF_TRACE_FENTRY] = "fentry",
[BPF_TRACE_FEXIT] = "fexit",
[BPF_MODIFY_RETURN] = "mod_ret",
[BPF_LSM_MAC] = "lsm_mac",
};
extern const char * const map_type_name[]; extern const char * const map_type_name[];
extern const size_t map_type_name_size; extern const size_t map_type_name_size;
/* keep in sync with the definition in skeleton/pid_iter.bpf.c */
enum bpf_obj_type { enum bpf_obj_type {
BPF_OBJ_UNKNOWN, BPF_OBJ_UNKNOWN,
BPF_OBJ_PROG, BPF_OBJ_PROG,
BPF_OBJ_MAP, BPF_OBJ_MAP,
BPF_OBJ_LINK, BPF_OBJ_LINK,
BPF_OBJ_BTF,
}; };
extern const char *bin_name; extern const char *bin_name;
...@@ -139,12 +78,14 @@ extern const char *bin_name; ...@@ -139,12 +78,14 @@ extern const char *bin_name;
extern json_writer_t *json_wtr; extern json_writer_t *json_wtr;
extern bool json_output; extern bool json_output;
extern bool show_pinned; extern bool show_pinned;
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 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;
extern struct pinned_obj_table link_table; extern struct pinned_obj_table link_table;
extern struct obj_refs_table refs_table;
void __printf(1, 2) p_err(const char *fmt, ...); void __printf(1, 2) p_err(const char *fmt, ...);
void __printf(1, 2) p_info(const char *fmt, ...); void __printf(1, 2) p_info(const char *fmt, ...);
...@@ -168,12 +109,35 @@ struct pinned_obj { ...@@ -168,12 +109,35 @@ struct pinned_obj {
struct hlist_node hash; struct hlist_node hash;
}; };
struct obj_refs_table {
DECLARE_HASHTABLE(table, 16);
};
struct obj_ref {
int pid;
char comm[16];
};
struct obj_refs {
struct hlist_node node;
__u32 id;
int ref_cnt;
struct obj_ref *refs;
};
struct btf; struct btf;
struct bpf_line_info; struct bpf_line_info;
int build_pinned_obj_table(struct pinned_obj_table *table, int build_pinned_obj_table(struct pinned_obj_table *table,
enum bpf_obj_type type); enum bpf_obj_type type);
void delete_pinned_obj_table(struct pinned_obj_table *tab); void delete_pinned_obj_table(struct pinned_obj_table *tab);
__weak int build_obj_refs_table(struct obj_refs_table *table,
enum bpf_obj_type type);
__weak void delete_obj_refs_table(struct obj_refs_table *table);
__weak void emit_obj_refs_json(struct obj_refs_table *table, __u32 id,
json_writer_t *json_wtr);
__weak void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id,
const char *prefix);
void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode); void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);
void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode); void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);
...@@ -194,23 +158,28 @@ int mount_bpffs_for_pin(const char *name); ...@@ -194,23 +158,28 @@ int mount_bpffs_for_pin(const char *name);
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***)); int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***));
int do_pin_fd(int fd, const char *name); int do_pin_fd(int fd, const char *name);
int do_prog(int argc, char **arg); /* commands available in bootstrap mode */
int do_map(int argc, char **arg);
int do_link(int argc, char **arg);
int do_event_pipe(int argc, char **argv);
int do_cgroup(int argc, char **arg);
int do_perf(int argc, char **arg);
int do_net(int argc, char **arg);
int do_tracelog(int argc, char **arg);
int do_feature(int argc, char **argv);
int do_btf(int argc, char **argv);
int do_gen(int argc, char **argv); int do_gen(int argc, char **argv);
int do_struct_ops(int argc, char **argv); int do_btf(int argc, char **argv);
int do_iter(int argc, char **argv);
/* non-bootstrap only commands */
int do_prog(int argc, char **arg) __weak;
int do_map(int argc, char **arg) __weak;
int do_link(int argc, char **arg) __weak;
int do_event_pipe(int argc, char **argv) __weak;
int do_cgroup(int argc, char **arg) __weak;
int do_perf(int argc, char **arg) __weak;
int do_net(int argc, char **arg) __weak;
int do_tracelog(int argc, char **arg) __weak;
int do_feature(int argc, char **argv) __weak;
int do_struct_ops(int argc, char **argv) __weak;
int do_iter(int argc, char **argv) __weak;
int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what); int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);
int prog_parse_fd(int *argc, char ***argv); int prog_parse_fd(int *argc, char ***argv);
int prog_parse_fds(int *argc, char ***argv, int **fds);
int map_parse_fd(int *argc, char ***argv); int map_parse_fd(int *argc, char ***argv);
int map_parse_fds(int *argc, char ***argv, int **fds);
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
struct bpf_prog_linfo; struct bpf_prog_linfo;
......
...@@ -93,162 +93,6 @@ static void *alloc_value(struct bpf_map_info *info) ...@@ -93,162 +93,6 @@ static void *alloc_value(struct bpf_map_info *info)
return malloc(info->value_size); return malloc(info->value_size);
} }
static int map_fd_by_name(char *name, int **fds)
{
unsigned int id = 0;
int fd, nb_fds = 0;
void *tmp;
int err;
while (true) {
struct bpf_map_info info = {};
__u32 len = sizeof(info);
err = bpf_map_get_next_id(id, &id);
if (err) {
if (errno != ENOENT) {
p_err("%s", strerror(errno));
goto err_close_fds;
}
return nb_fds;
}
fd = bpf_map_get_fd_by_id(id);
if (fd < 0) {
p_err("can't get map by id (%u): %s",
id, strerror(errno));
goto err_close_fds;
}
err = bpf_obj_get_info_by_fd(fd, &info, &len);
if (err) {
p_err("can't get map info (%u): %s",
id, strerror(errno));
goto err_close_fd;
}
if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
close(fd);
continue;
}
if (nb_fds > 0) {
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
if (!tmp) {
p_err("failed to realloc");
goto err_close_fd;
}
*fds = tmp;
}
(*fds)[nb_fds++] = fd;
}
err_close_fd:
close(fd);
err_close_fds:
while (--nb_fds >= 0)
close((*fds)[nb_fds]);
return -1;
}
static int map_parse_fds(int *argc, char ***argv, int **fds)
{
if (is_prefix(**argv, "id")) {
unsigned int id;
char *endptr;
NEXT_ARGP();
id = strtoul(**argv, &endptr, 0);
if (*endptr) {
p_err("can't parse %s as ID", **argv);
return -1;
}
NEXT_ARGP();
(*fds)[0] = bpf_map_get_fd_by_id(id);
if ((*fds)[0] < 0) {
p_err("get map by id (%u): %s", id, strerror(errno));
return -1;
}
return 1;
} else if (is_prefix(**argv, "name")) {
char *name;
NEXT_ARGP();
name = **argv;
if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
p_err("can't parse name");
return -1;
}
NEXT_ARGP();
return map_fd_by_name(name, fds);
} else if (is_prefix(**argv, "pinned")) {
char *path;
NEXT_ARGP();
path = **argv;
NEXT_ARGP();
(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
if ((*fds)[0] < 0)
return -1;
return 1;
}
p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
return -1;
}
int map_parse_fd(int *argc, char ***argv)
{
int *fds = NULL;
int nb_fds, fd;
fds = malloc(sizeof(int));
if (!fds) {
p_err("mem alloc failed");
return -1;
}
nb_fds = map_parse_fds(argc, argv, &fds);
if (nb_fds != 1) {
if (nb_fds > 1) {
p_err("several maps match this handle");
while (nb_fds--)
close(fds[nb_fds]);
}
fd = -1;
goto exit_free;
}
fd = fds[0];
exit_free:
free(fds);
return fd;
}
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
{
int err;
int fd;
fd = map_parse_fd(argc, argv);
if (fd < 0)
return -1;
err = bpf_obj_get_info_by_fd(fd, info, info_len);
if (err) {
p_err("can't get map info: %s", strerror(errno));
close(fd);
return err;
}
return fd;
}
static int do_dump_btf(const struct btf_dumper *d, static int do_dump_btf(const struct btf_dumper *d,
struct bpf_map_info *map_info, void *key, struct bpf_map_info *map_info, void *key,
void *value) void *value)
...@@ -629,7 +473,7 @@ static int show_map_close_json(int fd, struct bpf_map_info *info) ...@@ -629,7 +473,7 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
if (owner_prog_type) { if (owner_prog_type) {
unsigned int prog_type = atoi(owner_prog_type); unsigned int prog_type = atoi(owner_prog_type);
if (prog_type < ARRAY_SIZE(prog_type_name)) if (prog_type < prog_type_name_size)
jsonw_string_field(json_wtr, "owner_prog_type", jsonw_string_field(json_wtr, "owner_prog_type",
prog_type_name[prog_type]); prog_type_name[prog_type]);
else else
...@@ -666,6 +510,8 @@ static int show_map_close_json(int fd, struct bpf_map_info *info) ...@@ -666,6 +510,8 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
} }
emit_obj_refs_json(&refs_table, info->id, json_wtr);
jsonw_end_object(json_wtr); jsonw_end_object(json_wtr);
return 0; return 0;
...@@ -712,7 +558,7 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info) ...@@ -712,7 +558,7 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
if (owner_prog_type) { if (owner_prog_type) {
unsigned int prog_type = atoi(owner_prog_type); unsigned int prog_type = atoi(owner_prog_type);
if (prog_type < ARRAY_SIZE(prog_type_name)) if (prog_type < prog_type_name_size)
printf("owner_prog_type %s ", printf("owner_prog_type %s ",
prog_type_name[prog_type]); prog_type_name[prog_type]);
else else
...@@ -753,6 +599,8 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info) ...@@ -753,6 +599,8 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
if (frozen) if (frozen)
printf("%sfrozen", info->btf_id ? " " : ""); printf("%sfrozen", info->btf_id ? " " : "");
emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
printf("\n"); printf("\n");
return 0; return 0;
} }
...@@ -811,6 +659,7 @@ static int do_show(int argc, char **argv) ...@@ -811,6 +659,7 @@ static int do_show(int argc, char **argv)
if (show_pinned) if (show_pinned)
build_pinned_obj_table(&map_table, BPF_OBJ_MAP); build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
if (argc == 2) if (argc == 2)
return do_show_subset(argc, argv); return do_show_subset(argc, argv);
...@@ -854,6 +703,8 @@ static int do_show(int argc, char **argv) ...@@ -854,6 +703,8 @@ static int do_show(int argc, char **argv)
if (json_output) if (json_output)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
delete_obj_refs_table(&refs_table);
return errno == ENOENT ? 0 : -1; return errno == ENOENT ? 0 : -1;
} }
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (C) 2020 Facebook */
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <bpf/bpf.h>
#include "main.h"
#include "skeleton/pid_iter.h"
#ifdef BPFTOOL_WITHOUT_SKELETONS
int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
{
p_err("bpftool built without PID iterator support");
return -ENOTSUP;
}
void delete_obj_refs_table(struct obj_refs_table *table) {}
void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id, const char *prefix) {}
#else /* BPFTOOL_WITHOUT_SKELETONS */
#include "pid_iter.skel.h"
static void add_ref(struct obj_refs_table *table, struct pid_iter_entry *e)
{
struct obj_refs *refs;
struct obj_ref *ref;
void *tmp;
int i;
hash_for_each_possible(table->table, refs, node, e->id) {
if (refs->id != e->id)
continue;
for (i = 0; i < refs->ref_cnt; i++) {
if (refs->refs[i].pid == e->pid)
return;
}
tmp = realloc(refs->refs, (refs->ref_cnt + 1) * sizeof(*ref));
if (!tmp) {
p_err("failed to re-alloc memory for ID %u, PID %d, COMM %s...",
e->id, e->pid, e->comm);
return;
}
refs->refs = tmp;
ref = &refs->refs[refs->ref_cnt];
ref->pid = e->pid;
memcpy(ref->comm, e->comm, sizeof(ref->comm));
refs->ref_cnt++;
return;
}
/* new ref */
refs = calloc(1, sizeof(*refs));
if (!refs) {
p_err("failed to alloc memory for ID %u, PID %d, COMM %s...",
e->id, e->pid, e->comm);
return;
}
refs->id = e->id;
refs->refs = malloc(sizeof(*refs->refs));
if (!refs->refs) {
free(refs);
p_err("failed to alloc memory for ID %u, PID %d, COMM %s...",
e->id, e->pid, e->comm);
return;
}
ref = &refs->refs[0];
ref->pid = e->pid;
memcpy(ref->comm, e->comm, sizeof(ref->comm));
refs->ref_cnt = 1;
hash_add(table->table, &refs->node, e->id);
}
static int __printf(2, 0)
libbpf_print_none(__maybe_unused enum libbpf_print_level level,
__maybe_unused const char *format,
__maybe_unused va_list args)
{
return 0;
}
int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
{
char buf[4096];
struct pid_iter_bpf *skel;
struct pid_iter_entry *e;
int err, ret, fd = -1, i;
libbpf_print_fn_t default_print;
hash_init(table->table);
set_max_rlimit();
skel = pid_iter_bpf__open();
if (!skel) {
p_err("failed to open PID iterator skeleton");
return -1;
}
skel->rodata->obj_type = type;
/* we don't want output polluted with libbpf errors if bpf_iter is not
* supported
*/
default_print = libbpf_set_print(libbpf_print_none);
err = pid_iter_bpf__load(skel);
libbpf_set_print(default_print);
if (err) {
/* too bad, kernel doesn't support BPF iterators yet */
err = 0;
goto out;
}
err = pid_iter_bpf__attach(skel);
if (err) {
/* if we loaded above successfully, attach has to succeed */
p_err("failed to attach PID iterator: %d", err);
goto out;
}
fd = bpf_iter_create(bpf_link__fd(skel->links.iter));
if (fd < 0) {
err = -errno;
p_err("failed to create PID iterator session: %d", err);
goto out;
}
while (true) {
ret = read(fd, buf, sizeof(buf));
if (ret < 0) {
err = -errno;
p_err("failed to read PID iterator output: %d", err);
goto out;
}
if (ret == 0)
break;
if (ret % sizeof(*e)) {
err = -EINVAL;
p_err("invalid PID iterator output format");
goto out;
}
ret /= sizeof(*e);
e = (void *)buf;
for (i = 0; i < ret; i++, e++) {
add_ref(table, e);
}
}
err = 0;
out:
if (fd >= 0)
close(fd);
pid_iter_bpf__destroy(skel);
return err;
}
void delete_obj_refs_table(struct obj_refs_table *table)
{
struct obj_refs *refs;
struct hlist_node *tmp;
unsigned int bkt;
hash_for_each_safe(table->table, bkt, tmp, refs, node) {
hash_del(&refs->node);
free(refs->refs);
free(refs);
}
}
void emit_obj_refs_json(struct obj_refs_table *table, __u32 id,
json_writer_t *json_writer)
{
struct obj_refs *refs;
struct obj_ref *ref;
int i;
if (hash_empty(table->table))
return;
hash_for_each_possible(table->table, refs, node, id) {
if (refs->id != id)
continue;
if (refs->ref_cnt == 0)
break;
jsonw_name(json_writer, "pids");
jsonw_start_array(json_writer);
for (i = 0; i < refs->ref_cnt; i++) {
ref = &refs->refs[i];
jsonw_start_object(json_writer);
jsonw_int_field(json_writer, "pid", ref->pid);
jsonw_string_field(json_writer, "comm", ref->comm);
jsonw_end_object(json_writer);
}
jsonw_end_array(json_writer);
break;
}
}
void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id, const char *prefix)
{
struct obj_refs *refs;
struct obj_ref *ref;
int i;
if (hash_empty(table->table))
return;
hash_for_each_possible(table->table, refs, node, id) {
if (refs->id != id)
continue;
if (refs->ref_cnt == 0)
break;
printf("%s", prefix);
for (i = 0; i < refs->ref_cnt; i++) {
ref = &refs->refs[i];
printf("%s%s(%d)", i == 0 ? "" : ", ", ref->comm, ref->pid);
}
break;
}
}
#endif
...@@ -29,6 +29,40 @@ ...@@ -29,6 +29,40 @@
#include "main.h" #include "main.h"
#include "xlated_dumper.h" #include "xlated_dumper.h"
const char * const prog_type_name[] = {
[BPF_PROG_TYPE_UNSPEC] = "unspec",
[BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter",
[BPF_PROG_TYPE_KPROBE] = "kprobe",
[BPF_PROG_TYPE_SCHED_CLS] = "sched_cls",
[BPF_PROG_TYPE_SCHED_ACT] = "sched_act",
[BPF_PROG_TYPE_TRACEPOINT] = "tracepoint",
[BPF_PROG_TYPE_XDP] = "xdp",
[BPF_PROG_TYPE_PERF_EVENT] = "perf_event",
[BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb",
[BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock",
[BPF_PROG_TYPE_LWT_IN] = "lwt_in",
[BPF_PROG_TYPE_LWT_OUT] = "lwt_out",
[BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit",
[BPF_PROG_TYPE_SOCK_OPS] = "sock_ops",
[BPF_PROG_TYPE_SK_SKB] = "sk_skb",
[BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device",
[BPF_PROG_TYPE_SK_MSG] = "sk_msg",
[BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint",
[BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr",
[BPF_PROG_TYPE_LWT_SEG6LOCAL] = "lwt_seg6local",
[BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2",
[BPF_PROG_TYPE_SK_REUSEPORT] = "sk_reuseport",
[BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector",
[BPF_PROG_TYPE_CGROUP_SYSCTL] = "cgroup_sysctl",
[BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable",
[BPF_PROG_TYPE_CGROUP_SOCKOPT] = "cgroup_sockopt",
[BPF_PROG_TYPE_TRACING] = "tracing",
[BPF_PROG_TYPE_STRUCT_OPS] = "struct_ops",
[BPF_PROG_TYPE_EXT] = "ext",
};
const size_t prog_type_name_size = ARRAY_SIZE(prog_type_name);
enum dump_mode { enum dump_mode {
DUMP_JITED, DUMP_JITED,
DUMP_XLATED, DUMP_XLATED,
...@@ -86,158 +120,6 @@ static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) ...@@ -86,158 +120,6 @@ static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
strftime(buf, size, "%FT%T%z", &load_tm); strftime(buf, size, "%FT%T%z", &load_tm);
} }
static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
{
unsigned int id = 0;
int fd, nb_fds = 0;
void *tmp;
int err;
while (true) {
struct bpf_prog_info info = {};
__u32 len = sizeof(info);
err = bpf_prog_get_next_id(id, &id);
if (err) {
if (errno != ENOENT) {
p_err("%s", strerror(errno));
goto err_close_fds;
}
return nb_fds;
}
fd = bpf_prog_get_fd_by_id(id);
if (fd < 0) {
p_err("can't get prog by id (%u): %s",
id, strerror(errno));
goto err_close_fds;
}
err = bpf_obj_get_info_by_fd(fd, &info, &len);
if (err) {
p_err("can't get prog info (%u): %s",
id, strerror(errno));
goto err_close_fd;
}
if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
(!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
close(fd);
continue;
}
if (nb_fds > 0) {
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
if (!tmp) {
p_err("failed to realloc");
goto err_close_fd;
}
*fds = tmp;
}
(*fds)[nb_fds++] = fd;
}
err_close_fd:
close(fd);
err_close_fds:
while (--nb_fds >= 0)
close((*fds)[nb_fds]);
return -1;
}
static int prog_parse_fds(int *argc, char ***argv, int **fds)
{
if (is_prefix(**argv, "id")) {
unsigned int id;
char *endptr;
NEXT_ARGP();
id = strtoul(**argv, &endptr, 0);
if (*endptr) {
p_err("can't parse %s as ID", **argv);
return -1;
}
NEXT_ARGP();
(*fds)[0] = bpf_prog_get_fd_by_id(id);
if ((*fds)[0] < 0) {
p_err("get by id (%u): %s", id, strerror(errno));
return -1;
}
return 1;
} else if (is_prefix(**argv, "tag")) {
unsigned char tag[BPF_TAG_SIZE];
NEXT_ARGP();
if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
!= BPF_TAG_SIZE) {
p_err("can't parse tag");
return -1;
}
NEXT_ARGP();
return prog_fd_by_nametag(tag, fds, true);
} else if (is_prefix(**argv, "name")) {
char *name;
NEXT_ARGP();
name = **argv;
if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
p_err("can't parse name");
return -1;
}
NEXT_ARGP();
return prog_fd_by_nametag(name, fds, false);
} else if (is_prefix(**argv, "pinned")) {
char *path;
NEXT_ARGP();
path = **argv;
NEXT_ARGP();
(*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
if ((*fds)[0] < 0)
return -1;
return 1;
}
p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
return -1;
}
int prog_parse_fd(int *argc, char ***argv)
{
int *fds = NULL;
int nb_fds, fd;
fds = malloc(sizeof(int));
if (!fds) {
p_err("mem alloc failed");
return -1;
}
nb_fds = prog_parse_fds(argc, argv, &fds);
if (nb_fds != 1) {
if (nb_fds > 1) {
p_err("several programs match this handle");
while (nb_fds--)
close(fds[nb_fds]);
}
fd = -1;
goto exit_free;
}
fd = fds[0];
exit_free:
free(fds);
return fd;
}
static void show_prog_maps(int fd, __u32 num_maps) static void show_prog_maps(int fd, __u32 num_maps)
{ {
struct bpf_prog_info info = {}; struct bpf_prog_info info = {};
...@@ -342,6 +224,8 @@ static void print_prog_json(struct bpf_prog_info *info, int fd) ...@@ -342,6 +224,8 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
} }
emit_obj_refs_json(&refs_table, info->id, json_wtr);
jsonw_end_object(json_wtr); jsonw_end_object(json_wtr);
} }
...@@ -408,6 +292,8 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd) ...@@ -408,6 +292,8 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
if (info->btf_id) if (info->btf_id)
printf("\n\tbtf_id %d", info->btf_id); printf("\n\tbtf_id %d", info->btf_id);
emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
printf("\n"); printf("\n");
} }
...@@ -473,6 +359,7 @@ static int do_show(int argc, char **argv) ...@@ -473,6 +359,7 @@ static int do_show(int argc, char **argv)
if (show_pinned) if (show_pinned)
build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
build_obj_refs_table(&refs_table, BPF_OBJ_PROG);
if (argc == 2) if (argc == 2)
return do_show_subset(argc, argv); return do_show_subset(argc, argv);
...@@ -514,6 +401,8 @@ static int do_show(int argc, char **argv) ...@@ -514,6 +401,8 @@ static int do_show(int argc, char **argv)
if (json_output) if (json_output)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
delete_obj_refs_table(&refs_table);
return err; return err;
} }
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (c) 2020 Facebook */
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>
#include "pid_iter.h"
/* keep in sync with the definition in main.h */
enum bpf_obj_type {
BPF_OBJ_UNKNOWN,
BPF_OBJ_PROG,
BPF_OBJ_MAP,
BPF_OBJ_LINK,
BPF_OBJ_BTF,
};
extern const void bpf_link_fops __ksym;
extern const void bpf_map_fops __ksym;
extern const void bpf_prog_fops __ksym;
extern const void btf_fops __ksym;
const volatile enum bpf_obj_type obj_type = BPF_OBJ_UNKNOWN;
static __always_inline __u32 get_obj_id(void *ent, enum bpf_obj_type type)
{
switch (type) {
case BPF_OBJ_PROG:
return BPF_CORE_READ((struct bpf_prog *)ent, aux, id);
case BPF_OBJ_MAP:
return BPF_CORE_READ((struct bpf_map *)ent, id);
case BPF_OBJ_BTF:
return BPF_CORE_READ((struct btf *)ent, id);
case BPF_OBJ_LINK:
return BPF_CORE_READ((struct bpf_link *)ent, id);
default:
return 0;
}
}
SEC("iter/task_file")
int iter(struct bpf_iter__task_file *ctx)
{
struct file *file = ctx->file;
struct task_struct *task = ctx->task;
struct pid_iter_entry e;
const void *fops;
if (!file || !task)
return 0;
switch (obj_type) {
case BPF_OBJ_PROG:
fops = &bpf_prog_fops;
break;
case BPF_OBJ_MAP:
fops = &bpf_map_fops;
break;
case BPF_OBJ_BTF:
fops = &btf_fops;
break;
case BPF_OBJ_LINK:
fops = &bpf_link_fops;
break;
default:
return 0;
}
if (file->f_op != fops)
return 0;
e.pid = task->tgid;
e.id = get_obj_id(file->private_data, obj_type);
bpf_probe_read(&e.comm, sizeof(e.comm), task->group_leader->comm);
bpf_seq_write(ctx->meta->seq, &e, sizeof(e));
return 0;
}
char LICENSE[] SEC("license") = "Dual BSD/GPL";
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/* Copyright (c) 2020 Facebook */
#ifndef __PID_ITER_H
#define __PID_ITER_H
struct pid_iter_entry {
__u32 id;
int pid;
char comm[16];
};
#endif
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
// Copyright (c) 2020 Facebook // Copyright (c) 2020 Facebook
#include "profiler.h" #include <vmlinux.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h> #include <bpf/bpf_tracing.h>
...@@ -116,4 +115,4 @@ int BPF_PROG(fexit_XXX) ...@@ -116,4 +115,4 @@ int BPF_PROG(fexit_XXX)
return 0; return 0;
} }
char LICENSE[] SEC("license") = "GPL"; char LICENSE[] SEC("license") = "Dual BSD/GPL";
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __PROFILER_H
#define __PROFILER_H
/* useful typedefs from vmlinux.h */
typedef signed char __s8;
typedef unsigned char __u8;
typedef short int __s16;
typedef short unsigned int __u16;
typedef int __s32;
typedef unsigned int __u32;
typedef long long int __s64;
typedef long long unsigned int __u64;
typedef __s8 s8;
typedef __u8 u8;
typedef __s16 s16;
typedef __u16 u16;
typedef __s32 s32;
typedef __u32 u32;
typedef __s64 s64;
typedef __u64 u64;
enum {
false = 0,
true = 1,
};
#ifdef __CHECKER__
#define __bitwise__ __attribute__((bitwise))
#else
#define __bitwise__
#endif
typedef __u16 __bitwise__ __le16;
typedef __u16 __bitwise__ __be16;
typedef __u32 __bitwise__ __le32;
typedef __u32 __bitwise__ __be32;
typedef __u64 __bitwise__ __le64;
typedef __u64 __bitwise__ __be64;
typedef __u16 __bitwise__ __sum16;
typedef __u32 __bitwise__ __wsum;
#endif /* __PROFILER_H */
...@@ -68,7 +68,7 @@ FILES= \ ...@@ -68,7 +68,7 @@ FILES= \
test-llvm-version.bin \ test-llvm-version.bin \
test-libaio.bin \ test-libaio.bin \
test-libzstd.bin \ test-libzstd.bin \
test-clang-bpf-global-var.bin \ test-clang-bpf-co-re.bin \
test-file-handle.bin \ test-file-handle.bin \
test-libpfm4.bin test-libpfm4.bin
...@@ -325,7 +325,7 @@ $(OUTPUT)test-libaio.bin: ...@@ -325,7 +325,7 @@ $(OUTPUT)test-libaio.bin:
$(OUTPUT)test-libzstd.bin: $(OUTPUT)test-libzstd.bin:
$(BUILD) -lzstd $(BUILD) -lzstd
$(OUTPUT)test-clang-bpf-global-var.bin: $(OUTPUT)test-clang-bpf-co-re.bin:
$(CLANG) -S -g -target bpf -o - $(patsubst %.bin,%.c,$(@F)) | \ $(CLANG) -S -g -target bpf -o - $(patsubst %.bin,%.c,$(@F)) | \
grep BTF_KIND_VAR grep BTF_KIND_VAR
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020 Facebook // Copyright (c) 2020 Facebook
volatile int global_value_for_test = 1; struct test {
int a;
int b;
} __attribute__((preserve_access_index));
volatile struct test global_value_for_test = {};
此差异已折叠。
...@@ -217,7 +217,7 @@ enum bpf_field_info_kind { ...@@ -217,7 +217,7 @@ enum bpf_field_info_kind {
*/ */
#define BPF_CORE_READ_INTO(dst, src, a, ...) \ #define BPF_CORE_READ_INTO(dst, src, a, ...) \
({ \ ({ \
___core_read(bpf_core_read, dst, src, a, ##__VA_ARGS__) \ ___core_read(bpf_core_read, dst, (src), a, ##__VA_ARGS__) \
}) })
/* /*
...@@ -227,7 +227,7 @@ enum bpf_field_info_kind { ...@@ -227,7 +227,7 @@ enum bpf_field_info_kind {
*/ */
#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) \ #define BPF_CORE_READ_STR_INTO(dst, src, a, ...) \
({ \ ({ \
___core_read(bpf_core_read_str, dst, src, a, ##__VA_ARGS__) \ ___core_read(bpf_core_read_str, dst, (src), a, ##__VA_ARGS__)\
}) })
/* /*
...@@ -254,8 +254,8 @@ enum bpf_field_info_kind { ...@@ -254,8 +254,8 @@ enum bpf_field_info_kind {
*/ */
#define BPF_CORE_READ(src, a, ...) \ #define BPF_CORE_READ(src, a, ...) \
({ \ ({ \
___type(src, a, ##__VA_ARGS__) __r; \ ___type((src), a, ##__VA_ARGS__) __r; \
BPF_CORE_READ_INTO(&__r, src, a, ##__VA_ARGS__); \ BPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \
__r; \ __r; \
}) })
......
...@@ -2,8 +2,35 @@ ...@@ -2,8 +2,35 @@
#ifndef __BPF_ENDIAN__ #ifndef __BPF_ENDIAN__
#define __BPF_ENDIAN__ #define __BPF_ENDIAN__
#include <linux/stddef.h> /*
#include <linux/swab.h> * Isolate byte #n and put it into byte #m, for __u##b type.
* E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:
* 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx
* 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000
* 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn
* 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000
*/
#define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8))
#define ___bpf_swab16(x) ((__u16)( \
___bpf_mvb(x, 16, 0, 1) | \
___bpf_mvb(x, 16, 1, 0)))
#define ___bpf_swab32(x) ((__u32)( \
___bpf_mvb(x, 32, 0, 3) | \
___bpf_mvb(x, 32, 1, 2) | \
___bpf_mvb(x, 32, 2, 1) | \
___bpf_mvb(x, 32, 3, 0)))
#define ___bpf_swab64(x) ((__u64)( \
___bpf_mvb(x, 64, 0, 7) | \
___bpf_mvb(x, 64, 1, 6) | \
___bpf_mvb(x, 64, 2, 5) | \
___bpf_mvb(x, 64, 3, 4) | \
___bpf_mvb(x, 64, 4, 3) | \
___bpf_mvb(x, 64, 5, 2) | \
___bpf_mvb(x, 64, 6, 1) | \
___bpf_mvb(x, 64, 7, 0)))
/* LLVM's BPF target selects the endianness of the CPU /* LLVM's BPF target selects the endianness of the CPU
* it compiles on, or the user specifies (bpfel/bpfeb), * it compiles on, or the user specifies (bpfel/bpfeb),
...@@ -23,16 +50,16 @@ ...@@ -23,16 +50,16 @@
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define __bpf_ntohs(x) __builtin_bswap16(x) # define __bpf_ntohs(x) __builtin_bswap16(x)
# define __bpf_htons(x) __builtin_bswap16(x) # define __bpf_htons(x) __builtin_bswap16(x)
# define __bpf_constant_ntohs(x) ___constant_swab16(x) # define __bpf_constant_ntohs(x) ___bpf_swab16(x)
# define __bpf_constant_htons(x) ___constant_swab16(x) # define __bpf_constant_htons(x) ___bpf_swab16(x)
# define __bpf_ntohl(x) __builtin_bswap32(x) # define __bpf_ntohl(x) __builtin_bswap32(x)
# define __bpf_htonl(x) __builtin_bswap32(x) # define __bpf_htonl(x) __builtin_bswap32(x)
# define __bpf_constant_ntohl(x) ___constant_swab32(x) # define __bpf_constant_ntohl(x) ___bpf_swab32(x)
# define __bpf_constant_htonl(x) ___constant_swab32(x) # define __bpf_constant_htonl(x) ___bpf_swab32(x)
# define __bpf_be64_to_cpu(x) __builtin_bswap64(x) # define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
# define __bpf_cpu_to_be64(x) __builtin_bswap64(x) # define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
# define __bpf_constant_be64_to_cpu(x) ___constant_swab64(x) # define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x)
# define __bpf_constant_cpu_to_be64(x) ___constant_swab64(x) # define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define __bpf_ntohs(x) (x) # define __bpf_ntohs(x) (x)
# define __bpf_htons(x) (x) # define __bpf_htons(x) (x)
......
...@@ -75,5 +75,6 @@ enum libbpf_tristate { ...@@ -75,5 +75,6 @@ enum libbpf_tristate {
}; };
#define __kconfig __attribute__((section(".kconfig"))) #define __kconfig __attribute__((section(".kconfig")))
#define __ksym __attribute__((section(".ksyms")))
#endif #endif
...@@ -168,6 +168,11 @@ static inline bool btf_kflag(const struct btf_type *t) ...@@ -168,6 +168,11 @@ static inline bool btf_kflag(const struct btf_type *t)
return BTF_INFO_KFLAG(t->info); return BTF_INFO_KFLAG(t->info);
} }
static inline bool btf_is_void(const struct btf_type *t)
{
return btf_kind(t) == BTF_KIND_UNKN;
}
static inline bool btf_is_int(const struct btf_type *t) static inline bool btf_is_int(const struct btf_type *t)
{ {
return btf_kind(t) == BTF_KIND_INT; return btf_kind(t) == BTF_KIND_INT;
......
此差异已折叠。
...@@ -200,6 +200,8 @@ LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog, ...@@ -200,6 +200,8 @@ LIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog,
LIBBPF_API const char *bpf_program__name(const struct bpf_program *prog); LIBBPF_API const char *bpf_program__name(const struct bpf_program *prog);
LIBBPF_API const char *bpf_program__title(const struct bpf_program *prog, LIBBPF_API const char *bpf_program__title(const struct bpf_program *prog,
bool needs_copy); bool needs_copy);
LIBBPF_API bool bpf_program__autoload(const struct bpf_program *prog);
LIBBPF_API int bpf_program__set_autoload(struct bpf_program *prog, bool autoload);
/* returns program size in bytes */ /* returns program size in bytes */
LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog); LIBBPF_API size_t bpf_program__size(const struct bpf_program *prog);
...@@ -418,11 +420,38 @@ bpf_map__next(const struct bpf_map *map, const struct bpf_object *obj); ...@@ -418,11 +420,38 @@ bpf_map__next(const struct bpf_map *map, const struct bpf_object *obj);
LIBBPF_API struct bpf_map * LIBBPF_API struct bpf_map *
bpf_map__prev(const struct bpf_map *map, const struct bpf_object *obj); bpf_map__prev(const struct bpf_map *map, const struct bpf_object *obj);
/* get/set map FD */
LIBBPF_API int bpf_map__fd(const struct bpf_map *map); LIBBPF_API int bpf_map__fd(const struct bpf_map *map);
LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd);
/* get map definition */
LIBBPF_API const struct bpf_map_def *bpf_map__def(const struct bpf_map *map); LIBBPF_API const struct bpf_map_def *bpf_map__def(const struct bpf_map *map);
/* get map name */
LIBBPF_API const char *bpf_map__name(const struct bpf_map *map); LIBBPF_API const char *bpf_map__name(const struct bpf_map *map);
/* get/set map type */
LIBBPF_API enum bpf_map_type bpf_map__type(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_type(struct bpf_map *map, enum bpf_map_type type);
/* get/set map size (max_entries) */
LIBBPF_API __u32 bpf_map__max_entries(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_max_entries(struct bpf_map *map, __u32 max_entries);
LIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries);
/* get/set map flags */
LIBBPF_API __u32 bpf_map__map_flags(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_map_flags(struct bpf_map *map, __u32 flags);
/* get/set map NUMA node */
LIBBPF_API __u32 bpf_map__numa_node(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_numa_node(struct bpf_map *map, __u32 numa_node);
/* get/set map key size */
LIBBPF_API __u32 bpf_map__key_size(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_key_size(struct bpf_map *map, __u32 size);
/* get/set map value size */
LIBBPF_API __u32 bpf_map__value_size(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_value_size(struct bpf_map *map, __u32 size);
/* get map key/value BTF type IDs */
LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map); LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map);
LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map); LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);
/* get/set map if_index */
LIBBPF_API __u32 bpf_map__ifindex(const struct bpf_map *map);
LIBBPF_API int bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv, LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
...@@ -430,11 +459,8 @@ LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv, ...@@ -430,11 +459,8 @@ 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 int bpf_map__reuse_fd(struct bpf_map *map, int fd);
LIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries);
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 void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
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);
LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map); LIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);
LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map); LIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);
......
...@@ -270,3 +270,22 @@ LIBBPF_0.0.9 { ...@@ -270,3 +270,22 @@ LIBBPF_0.0.9 {
ring_buffer__new; ring_buffer__new;
ring_buffer__poll; ring_buffer__poll;
} LIBBPF_0.0.8; } LIBBPF_0.0.8;
LIBBPF_0.1.0 {
global:
bpf_map__ifindex;
bpf_map__key_size;
bpf_map__map_flags;
bpf_map__max_entries;
bpf_map__numa_node;
bpf_map__set_key_size;
bpf_map__set_map_flags;
bpf_map__set_max_entries;
bpf_map__set_numa_node;
bpf_map__set_type;
bpf_map__set_value_size;
bpf_map__type;
bpf_map__value_size;
bpf_program__autoload;
bpf_program__set_autoload;
} LIBBPF_0.0.9;
...@@ -134,12 +134,12 @@ $(OUTPUT)/test_stub.o: test_stub.c $(BPFOBJ) ...@@ -134,12 +134,12 @@ $(OUTPUT)/test_stub.o: test_stub.c $(BPFOBJ)
$(call msg,CC,,$@) $(call msg,CC,,$@)
$(CC) -c $(CFLAGS) -o $@ $< $(CC) -c $(CFLAGS) -o $@ $<
VMLINUX_BTF_PATHS := $(if $(O),$(O)/vmlinux) \ VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
$(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \ $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
../../../../vmlinux \ ../../../../vmlinux \
/sys/kernel/btf/vmlinux \ /sys/kernel/btf/vmlinux \
/boot/vmlinux-$(shell uname -r) /boot/vmlinux-$(shell uname -r)
VMLINUX_BTF := $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS)))) VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
$(OUTPUT)/runqslower: $(BPFOBJ) $(OUTPUT)/runqslower: $(BPFOBJ)
$(Q)$(MAKE) $(submake_extras) -C $(TOOLSDIR)/bpf/runqslower \ $(Q)$(MAKE) $(submake_extras) -C $(TOOLSDIR)/bpf/runqslower \
...@@ -182,8 +182,13 @@ $(BUILD_DIR)/libbpf $(BUILD_DIR)/bpftool $(INCLUDE_DIR): ...@@ -182,8 +182,13 @@ $(BUILD_DIR)/libbpf $(BUILD_DIR)/bpftool $(INCLUDE_DIR):
mkdir -p $@ mkdir -p $@
$(INCLUDE_DIR)/vmlinux.h: $(VMLINUX_BTF) | $(BPFTOOL) $(INCLUDE_DIR) $(INCLUDE_DIR)/vmlinux.h: $(VMLINUX_BTF) | $(BPFTOOL) $(INCLUDE_DIR)
ifeq ($(VMLINUX_H),)
$(call msg,GEN,,$@) $(call msg,GEN,,$@)
$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@ $(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@
else
$(call msg,CP,,$@)
cp "$(VMLINUX_H)" $@
endif
# Get Clang's default includes on this system, as opposed to those seen by # Get Clang's default includes on this system, as opposed to those seen by
# '-target bpf'. This fixes "missing" files on some architectures/distros, # '-target bpf'. This fixes "missing" files on some architectures/distros,
......
...@@ -33,10 +33,9 @@ struct ipv6_packet { ...@@ -33,10 +33,9 @@ struct ipv6_packet {
} __packed; } __packed;
extern struct ipv6_packet pkt_v6; extern struct ipv6_packet pkt_v6;
int start_server(int family, int type); int start_server(int family, int type, const char *addr, __u16 port,
int start_server_with_port(int family, int type, __u16 port); int timeout_ms);
int connect_to_fd(int family, int type, int server_fd); int connect_to_fd(int server_fd, int timeout_ms);
int connect_fd_to_fd(int client_fd, int server_fd); int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms);
int connect_wait(int client_fd);
#endif #endif
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */
#include <test_progs.h>
#include <time.h>
#include "test_autoload.skel.h"
void test_autoload(void)
{
int duration = 0, err;
struct test_autoload* skel;
skel = test_autoload__open_and_load();
/* prog3 should be broken */
if (CHECK(skel, "skel_open_and_load", "unexpected success\n"))
goto cleanup;
skel = test_autoload__open();
if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
goto cleanup;
/* don't load prog3 */
bpf_program__set_autoload(skel->progs.prog3, false);
err = test_autoload__load(skel);
if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
goto cleanup;
err = test_autoload__attach(skel);
if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
goto cleanup;
usleep(1);
CHECK(!skel->bss->prog1_called, "prog1", "not called\n");
CHECK(!skel->bss->prog2_called, "prog2", "not called\n");
CHECK(skel->bss->prog3_called, "prog3", "called?!\n");
cleanup:
test_autoload__destroy(skel);
}
...@@ -13,7 +13,7 @@ static void run_lookup_test(__u16 *g_serv_port, int out_sk) ...@@ -13,7 +13,7 @@ static void run_lookup_test(__u16 *g_serv_port, int out_sk)
socklen_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(addr);
__u32 duration = 0; __u32 duration = 0;
serv_sk = start_server(AF_INET6, SOCK_STREAM); serv_sk = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
if (CHECK(serv_sk < 0, "start_server", "failed to start server\n")) if (CHECK(serv_sk < 0, "start_server", "failed to start server\n"))
return; return;
...@@ -24,17 +24,13 @@ static void run_lookup_test(__u16 *g_serv_port, int out_sk) ...@@ -24,17 +24,13 @@ static void run_lookup_test(__u16 *g_serv_port, int out_sk)
*g_serv_port = addr.sin6_port; *g_serv_port = addr.sin6_port;
/* Client outside of test cgroup should fail to connect by timeout. */ /* Client outside of test cgroup should fail to connect by timeout. */
err = connect_fd_to_fd(out_sk, serv_sk); err = connect_fd_to_fd(out_sk, serv_sk, 1000);
if (CHECK(!err || errno != EINPROGRESS, "connect_fd_to_fd", if (CHECK(!err || errno != EINPROGRESS, "connect_fd_to_fd",
"unexpected result err %d errno %d\n", err, errno)) "unexpected result err %d errno %d\n", err, errno))
goto cleanup; goto cleanup;
err = connect_wait(out_sk);
if (CHECK(err, "connect_wait", "unexpected result %d\n", err))
goto cleanup;
/* Client inside test cgroup should connect just fine. */ /* Client inside test cgroup should connect just fine. */
in_sk = connect_to_fd(AF_INET6, SOCK_STREAM, serv_sk); in_sk = connect_to_fd(serv_sk, 0);
if (CHECK(in_sk < 0, "connect_to_fd", "errno %d\n", errno)) if (CHECK(in_sk < 0, "connect_to_fd", "errno %d\n", errno))
goto cleanup; goto cleanup;
...@@ -85,7 +81,7 @@ void test_cgroup_skb_sk_lookup(void) ...@@ -85,7 +81,7 @@ void test_cgroup_skb_sk_lookup(void)
* differs from that of testing cgroup. Moving selftests process to * differs from that of testing cgroup. Moving selftests process to
* testing cgroup won't change cgroup id of an already created socket. * testing cgroup won't change cgroup id of an already created socket.
*/ */
out_sk = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0); out_sk = socket(AF_INET6, SOCK_STREAM, 0);
if (CHECK_FAIL(out_sk < 0)) if (CHECK_FAIL(out_sk < 0))
return; return;
......
...@@ -114,7 +114,7 @@ static int run_test(int cgroup_fd, int server_fd, int family, int type) ...@@ -114,7 +114,7 @@ static int run_test(int cgroup_fd, int server_fd, int family, int type)
goto close_bpf_object; goto close_bpf_object;
} }
fd = connect_to_fd(family, type, server_fd); fd = connect_to_fd(server_fd, 0);
if (fd < 0) { if (fd < 0) {
err = -1; err = -1;
goto close_bpf_object; goto close_bpf_object;
...@@ -137,25 +137,25 @@ void test_connect_force_port(void) ...@@ -137,25 +137,25 @@ void test_connect_force_port(void)
if (CHECK_FAIL(cgroup_fd < 0)) if (CHECK_FAIL(cgroup_fd < 0))
return; return;
server_fd = start_server_with_port(AF_INET, SOCK_STREAM, 60123); server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 60123, 0);
if (CHECK_FAIL(server_fd < 0)) if (CHECK_FAIL(server_fd < 0))
goto close_cgroup_fd; goto close_cgroup_fd;
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_STREAM)); CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_STREAM));
close(server_fd); close(server_fd);
server_fd = start_server_with_port(AF_INET6, SOCK_STREAM, 60124); server_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 60124, 0);
if (CHECK_FAIL(server_fd < 0)) if (CHECK_FAIL(server_fd < 0))
goto close_cgroup_fd; goto close_cgroup_fd;
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_STREAM)); CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_STREAM));
close(server_fd); close(server_fd);
server_fd = start_server_with_port(AF_INET, SOCK_DGRAM, 60123); server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 60123, 0);
if (CHECK_FAIL(server_fd < 0)) if (CHECK_FAIL(server_fd < 0))
goto close_cgroup_fd; goto close_cgroup_fd;
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_DGRAM)); CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_DGRAM));
close(server_fd); close(server_fd);
server_fd = start_server_with_port(AF_INET6, SOCK_DGRAM, 60124); server_fd = start_server(AF_INET6, SOCK_DGRAM, NULL, 60124, 0);
if (CHECK_FAIL(server_fd < 0)) if (CHECK_FAIL(server_fd < 0))
goto close_cgroup_fd; goto close_cgroup_fd;
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_DGRAM)); CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_DGRAM));
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册