The total length of the saved syn packet is currently stored in the first 4 bytes (u32) and the actual packet data is stored after that. A latter patch will also want to store an offset (bpf_hdr_opt_off) to a TCP header option which the bpf program will be interested in parsing. Instead of anonymously storing this offset into the second 4 bytes, this patch creates a struct for the existing saved_syn. It can give a readable name to the stored lengths instead of implicitly using the first few u32(s) to do that. The new TCP bpf header offset (bpf_hdr_opt_off) added in a latter patch is an offset from the tcp header instead of from the network header. It will make the bpf programming side easier. Thus, this patch stores the network header length instead of the total length of the syn header. The total length can be obtained by the "network header len + tcp_hdrlen". The latter patch can then also gets the offset to the TCP bpf header option by "network header len + bpf_hdr_opt_off". Signed-off-by: Martin KaFai Lau <kafai@xxxxxx> --- include/linux/tcp.h | 11 ++++++++++- include/net/request_sock.h | 7 ++++++- net/core/filter.c | 4 ++-- net/ipv4/tcp.c | 9 +++++---- net/ipv4/tcp_input.c | 12 ++++++------ 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 3bdec31ce8f4..9d50132d95e6 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -404,7 +404,7 @@ struct tcp_sock { * socket. Used to retransmit SYNACKs etc. */ struct request_sock __rcu *fastopen_rsk; - u32 *saved_syn; + struct saved_syn *saved_syn; }; enum tsq_enum { @@ -482,6 +482,15 @@ static inline void tcp_saved_syn_free(struct tcp_sock *tp) tp->saved_syn = NULL; } +static inline u32 tcp_saved_syn_len(const struct saved_syn *saved_syn) +{ + const struct tcphdr *th; + + th = (void *)saved_syn->data + saved_syn->network_hdrlen; + + return saved_syn->network_hdrlen + __tcp_hdrlen(th); +} + struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk); static inline u16 tcp_mss_clamp(const struct tcp_sock *tp, u16 mss) diff --git a/include/net/request_sock.h b/include/net/request_sock.h index cf8b33213bbc..d77237ec9fb4 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -41,6 +41,11 @@ struct request_sock_ops { int inet_rtx_syn_ack(const struct sock *parent, struct request_sock *req); +struct saved_syn { + u32 network_hdrlen; + u8 data[]; +}; + /* struct request_sock - mini sock to represent a connection request */ struct request_sock { @@ -60,7 +65,7 @@ struct request_sock { struct timer_list rsk_timer; const struct request_sock_ops *rsk_ops; struct sock *sk; - u32 *saved_syn; + struct saved_syn *saved_syn; u32 secid; u32 peer_secid; }; diff --git a/net/core/filter.c b/net/core/filter.c index c796e141ea8e..19dbcc8448d8 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4522,9 +4522,9 @@ static int _bpf_getsockopt(struct sock *sk, int level, int optname, tp = tcp_sk(sk); if (optlen <= 0 || !tp->saved_syn || - optlen > tp->saved_syn[0]) + optlen > tcp_saved_syn_len(tp->saved_syn)) goto err_clear; - memcpy(optval, tp->saved_syn + 1, optlen); + memcpy(optval, tp->saved_syn->data, optlen); break; default: goto err_clear; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index de36c91d32ea..60093a211f4d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3805,20 +3805,21 @@ static int do_tcp_getsockopt(struct sock *sk, int level, lock_sock(sk); if (tp->saved_syn) { - if (len < tp->saved_syn[0]) { - if (put_user(tp->saved_syn[0], optlen)) { + if (len < tcp_saved_syn_len(tp->saved_syn)) { + if (put_user(tcp_saved_syn_len(tp->saved_syn), + optlen)) { release_sock(sk); return -EFAULT; } release_sock(sk); return -EINVAL; } - len = tp->saved_syn[0]; + len = tcp_saved_syn_len(tp->saved_syn); if (put_user(len, optlen)) { release_sock(sk); return -EFAULT; } - if (copy_to_user(optval, tp->saved_syn + 1, len)) { + if (copy_to_user(optval, tp->saved_syn->data, len)) { release_sock(sk); return -EFAULT; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 12fda8f27b08..eb0e32b2def9 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6557,13 +6557,13 @@ static void tcp_reqsk_record_syn(const struct sock *sk, { if (tcp_sk(sk)->save_syn) { u32 len = skb_network_header_len(skb) + tcp_hdrlen(skb); - u32 *copy; + struct saved_syn *saved_syn; - copy = kmalloc(len + sizeof(u32), GFP_ATOMIC); - if (copy) { - copy[0] = len; - memcpy(©[1], skb_network_header(skb), len); - req->saved_syn = copy; + saved_syn = kmalloc(len + sizeof(*saved_syn), GFP_ATOMIC); + if (saved_syn) { + saved_syn->network_hdrlen = skb_network_header_len(skb); + memcpy(saved_syn->data, skb_network_header(skb), len); + req->saved_syn = saved_syn; } } } -- 2.24.1