On Sat, Jun 20, 2020 at 10:55:06PM -0700, Yonghong Song wrote: > Three more helpers are added to cast a sock_common pointer to > an tcp_sock, tcp_timewait_sock or a tcp_request_sock for > tracing programs. > > Signed-off-by: Yonghong Song <yhs@xxxxxx> > --- > include/linux/bpf.h | 3 ++ > include/uapi/linux/bpf.h | 23 ++++++++++++++- > kernel/trace/bpf_trace.c | 6 ++++ > net/core/filter.c | 51 ++++++++++++++++++++++++++++++++++ > scripts/bpf_helpers_doc.py | 6 ++++ > tools/include/uapi/linux/bpf.h | 23 ++++++++++++++- > 6 files changed, 110 insertions(+), 2 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 0c658f78e939..b17e682454e5 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1637,6 +1637,9 @@ 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_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; > > const struct bpf_func_proto *bpf_tracing_func_proto( > enum bpf_func_id func_id, const struct bpf_prog *prog); > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > index 394fcba27b6a..e256417d94c2 100644 > --- a/include/uapi/linux/bpf.h > +++ b/include/uapi/linux/bpf.h > @@ -3258,6 +3258,24 @@ union bpf_attr { > * Dynamically cast a *sk* pointer to a *tcp6_sock* pointer. > * Return > * *sk* if casting is valid, or NULL otherwise. > + * > + * struct tcp_sock *bpf_skc_to_tcp_sock(void *sk) > + * Description > + * Dynamically cast a *sk* pointer to a *tcp_sock* pointer. > + * Return > + * *sk* if casting is valid, or NULL otherwise. > + * > + * struct tcp_timewait_sock *bpf_skc_to_tcp_timewait_sock(void *sk) > + * Description > + * Dynamically cast a *sk* pointer to a *tcp_timewait_sock* pointer. > + * Return > + * *sk* if casting is valid, or NULL otherwise. > + * > + * struct tcp_request_sock *bpf_skc_to_tcp_request_sock(void *sk) > + * Description > + * Dynamically cast a *sk* pointer to a *tcp_request_sock* pointer. > + * Return > + * *sk* if casting is valid, or NULL otherwise. > */ > #define __BPF_FUNC_MAPPER(FN) \ > FN(unspec), \ > @@ -3396,7 +3414,10 @@ union bpf_attr { > FN(ringbuf_discard), \ > FN(ringbuf_query), \ > FN(csum_level), \ > - FN(skc_to_tcp6_sock), > + FN(skc_to_tcp6_sock), \ > + FN(skc_to_tcp_sock), \ > + FN(skc_to_tcp_timewait_sock), \ > + FN(skc_to_tcp_request_sock), > > /* integer value in 'imm' field of BPF_CALL instruction selects which helper > * function eBPF program intends to call > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c > index 478c10d1ec33..de5fbe66e1ca 100644 > --- a/kernel/trace/bpf_trace.c > +++ b/kernel/trace/bpf_trace.c > @@ -1517,6 +1517,12 @@ tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) > 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; > #endif > case BPF_FUNC_seq_printf: > return prog->expected_attach_type == BPF_TRACE_ITER ? > diff --git a/net/core/filter.c b/net/core/filter.c > index 8ca365c5bd10..d26ce3b5e3d5 100644 > --- a/net/core/filter.c > +++ b/net/core/filter.c > @@ -9271,3 +9271,54 @@ const struct bpf_func_proto bpf_skc_to_tcp6_sock_proto = { > .check_btf_id = check_arg_btf_id, > .ret_btf_id = &sock_cast_btf_ids[SOCK_CAST_TCP6_SOCK], > }; > + > +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 = true, s/true/false/ and for other bpf_func_proto below. > + .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 = &sock_cast_btf_ids[SOCK_CAST_TCP_SOCK], > +}; > + > +BPF_CALL_1(bpf_skc_to_tcp_timewait_sock, struct sock *, sk) > +{ > + if (sk->sk_state == TCP_TIME_WAIT) Not sure if checking TCP_TIME_WAIT can guarantee a tcp_timewait_sock. dccp seems to have the same state aliased to DCCP_TIME_WAIT. The same goes for the TCP_NEW_SYN_RECV check. may be checking sk->sk_prot instead? > + return (unsigned long)sk; > + > + 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 = true, > + .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 = &sock_cast_btf_ids[SOCK_CAST_TCP_TW_SOCK], > +}; > + > +BPF_CALL_1(bpf_skc_to_tcp_request_sock, struct sock *, sk) > +{ > + if (sk->sk_state == TCP_NEW_SYN_RECV) > + return (unsigned long)sk; > + > + 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 = true, > + .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 = &sock_cast_btf_ids[SOCK_CAST_TCP_REQ_SOCK], > +};