Commit 267cf9fa authored by Martin KaFai Lau's avatar Martin KaFai Lau Committed by Alexei Starovoitov

tcp: bpf: Optionally store mac header in TCP_SAVE_SYN

This patch is adapted from Eric's patch in an earlier discussion [1].

The TCP_SAVE_SYN currently only stores the network header and
tcp header.  This patch allows it to optionally store
the mac header also if the setsockopt's optval is 2.

It requires one more bit for the "save_syn" bit field in tcp_sock.
This patch achieves this by moving the syn_smc bit next to the is_mptcp.
The syn_smc is currently used with the TCP experimental option.  Since
syn_smc is only used when CONFIG_SMC is enabled, this patch also puts
the "IS_ENABLED(CONFIG_SMC)" around it like the is_mptcp did
with "IS_ENABLED(CONFIG_MPTCP)".

The mac_hdrlen is also stored in the "struct saved_syn"
to allow a quick offset from the bpf prog if it chooses to start
getting from the network header or the tcp header.

[1]: https://lore.kernel.org/netdev/CANn89iLJNWh6bkH7DNhy_kmcAexuUCccqERqe7z2QsvPhGrYPQ@mail.gmail.com/Suggested-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarMartin KaFai Lau <kafai@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/bpf/20200820190123.2886935-1-kafai@fb.com
parent ad2f8eb0
...@@ -239,14 +239,13 @@ struct tcp_sock { ...@@ -239,14 +239,13 @@ struct tcp_sock {
repair : 1, repair : 1,
frto : 1;/* F-RTO (RFC5682) activated in CA_Loss */ frto : 1;/* F-RTO (RFC5682) activated in CA_Loss */
u8 repair_queue; u8 repair_queue;
u8 syn_data:1, /* SYN includes data */ u8 save_syn:2, /* Save headers of SYN packet */
syn_data:1, /* SYN includes data */
syn_fastopen:1, /* SYN includes Fast Open option */ syn_fastopen:1, /* SYN includes Fast Open option */
syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */ syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */
syn_fastopen_ch:1, /* Active TFO re-enabling probe */ syn_fastopen_ch:1, /* Active TFO re-enabling probe */
syn_data_acked:1,/* data in SYN is acked by SYN-ACK */ syn_data_acked:1,/* data in SYN is acked by SYN-ACK */
save_syn:1, /* Save headers of SYN packet */ is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */
is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */
syn_smc:1; /* SYN includes SMC */
u32 tlp_high_seq; /* snd_nxt at the time of TLP */ u32 tlp_high_seq; /* snd_nxt at the time of TLP */
u32 tcp_tx_delay; /* delay (in usec) added to TX packets */ u32 tcp_tx_delay; /* delay (in usec) added to TX packets */
...@@ -393,6 +392,9 @@ struct tcp_sock { ...@@ -393,6 +392,9 @@ struct tcp_sock {
#if IS_ENABLED(CONFIG_MPTCP) #if IS_ENABLED(CONFIG_MPTCP)
bool is_mptcp; bool is_mptcp;
#endif #endif
#if IS_ENABLED(CONFIG_SMC)
bool syn_smc; /* SYN includes SMC */
#endif
#ifdef CONFIG_TCP_MD5SIG #ifdef CONFIG_TCP_MD5SIG
/* TCP AF-Specific parts; only used by MD5 Signature support so far */ /* TCP AF-Specific parts; only used by MD5 Signature support so far */
...@@ -488,7 +490,8 @@ static inline void tcp_saved_syn_free(struct tcp_sock *tp) ...@@ -488,7 +490,8 @@ static inline void tcp_saved_syn_free(struct tcp_sock *tp)
static inline u32 tcp_saved_syn_len(const struct saved_syn *saved_syn) static inline u32 tcp_saved_syn_len(const struct saved_syn *saved_syn)
{ {
return saved_syn->network_hdrlen + saved_syn->tcp_hdrlen; return saved_syn->mac_hdrlen + saved_syn->network_hdrlen +
saved_syn->tcp_hdrlen;
} }
struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
......
...@@ -42,6 +42,7 @@ struct request_sock_ops { ...@@ -42,6 +42,7 @@ struct request_sock_ops {
int inet_rtx_syn_ack(const struct sock *parent, struct request_sock *req); int inet_rtx_syn_ack(const struct sock *parent, struct request_sock *req);
struct saved_syn { struct saved_syn {
u32 mac_hdrlen;
u32 network_hdrlen; u32 network_hdrlen;
u32 tcp_hdrlen; u32 tcp_hdrlen;
u8 data[]; u8 data[];
......
...@@ -4540,6 +4540,7 @@ enum { ...@@ -4540,6 +4540,7 @@ enum {
*/ */
TCP_BPF_SYN = 1005, /* Copy the TCP header */ TCP_BPF_SYN = 1005, /* Copy the TCP header */
TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */ TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */
TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */
}; };
enum { enum {
......
...@@ -4682,11 +4682,16 @@ static int bpf_sock_ops_get_syn(struct bpf_sock_ops_kern *bpf_sock, ...@@ -4682,11 +4682,16 @@ static int bpf_sock_ops_get_syn(struct bpf_sock_ops_kern *bpf_sock,
if (optname == TCP_BPF_SYN) { if (optname == TCP_BPF_SYN) {
hdr_start = syn_skb->data; hdr_start = syn_skb->data;
ret = tcp_hdrlen(syn_skb); ret = tcp_hdrlen(syn_skb);
} else { } else if (optname == TCP_BPF_SYN_IP) {
/* optname == TCP_BPF_SYN_IP */
hdr_start = skb_network_header(syn_skb); hdr_start = skb_network_header(syn_skb);
ret = skb_network_header_len(syn_skb) + ret = skb_network_header_len(syn_skb) +
tcp_hdrlen(syn_skb); tcp_hdrlen(syn_skb);
} else {
/* optname == TCP_BPF_SYN_MAC */
hdr_start = skb_mac_header(syn_skb);
ret = skb_mac_header_len(syn_skb) +
skb_network_header_len(syn_skb) +
tcp_hdrlen(syn_skb);
} }
} else { } else {
struct sock *sk = bpf_sock->sk; struct sock *sk = bpf_sock->sk;
...@@ -4706,12 +4711,24 @@ static int bpf_sock_ops_get_syn(struct bpf_sock_ops_kern *bpf_sock, ...@@ -4706,12 +4711,24 @@ static int bpf_sock_ops_get_syn(struct bpf_sock_ops_kern *bpf_sock,
if (optname == TCP_BPF_SYN) { if (optname == TCP_BPF_SYN) {
hdr_start = saved_syn->data + hdr_start = saved_syn->data +
saved_syn->mac_hdrlen +
saved_syn->network_hdrlen; saved_syn->network_hdrlen;
ret = saved_syn->tcp_hdrlen; ret = saved_syn->tcp_hdrlen;
} else if (optname == TCP_BPF_SYN_IP) {
hdr_start = saved_syn->data +
saved_syn->mac_hdrlen;
ret = saved_syn->network_hdrlen +
saved_syn->tcp_hdrlen;
} else { } else {
/* optname == TCP_BPF_SYN_IP */ /* optname == TCP_BPF_SYN_MAC */
/* TCP_SAVE_SYN may not have saved the mac hdr */
if (!saved_syn->mac_hdrlen)
return -ENOENT;
hdr_start = saved_syn->data; hdr_start = saved_syn->data;
ret = saved_syn->network_hdrlen + ret = saved_syn->mac_hdrlen +
saved_syn->network_hdrlen +
saved_syn->tcp_hdrlen; saved_syn->tcp_hdrlen;
} }
} }
...@@ -4724,7 +4741,7 @@ BPF_CALL_5(bpf_sock_ops_getsockopt, struct bpf_sock_ops_kern *, bpf_sock, ...@@ -4724,7 +4741,7 @@ BPF_CALL_5(bpf_sock_ops_getsockopt, struct bpf_sock_ops_kern *, bpf_sock,
int, level, int, optname, char *, optval, int, optlen) int, level, int, optname, char *, optval, int, optlen)
{ {
if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP && if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP &&
optname >= TCP_BPF_SYN && optname <= TCP_BPF_SYN_IP) { optname >= TCP_BPF_SYN && optname <= TCP_BPF_SYN_MAC) {
int ret, copy_len = 0; int ret, copy_len = 0;
const u8 *start; const u8 *start;
......
...@@ -3211,7 +3211,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname, ...@@ -3211,7 +3211,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname,
break; break;
case TCP_SAVE_SYN: case TCP_SAVE_SYN:
if (val < 0 || val > 1) /* 0: disable, 1: enable, 2: start from ether_header */
if (val < 0 || val > 2)
err = -EINVAL; err = -EINVAL;
else else
tp->save_syn = val; tp->save_syn = val;
......
...@@ -6676,13 +6676,25 @@ static void tcp_reqsk_record_syn(const struct sock *sk, ...@@ -6676,13 +6676,25 @@ static void tcp_reqsk_record_syn(const struct sock *sk,
if (tcp_sk(sk)->save_syn) { if (tcp_sk(sk)->save_syn) {
u32 len = skb_network_header_len(skb) + tcp_hdrlen(skb); u32 len = skb_network_header_len(skb) + tcp_hdrlen(skb);
struct saved_syn *saved_syn; struct saved_syn *saved_syn;
u32 mac_hdrlen;
void *base;
if (tcp_sk(sk)->save_syn == 2) { /* Save full header. */
base = skb_mac_header(skb);
mac_hdrlen = skb_mac_header_len(skb);
len += mac_hdrlen;
} else {
base = skb_network_header(skb);
mac_hdrlen = 0;
}
saved_syn = kmalloc(struct_size(saved_syn, data, len), saved_syn = kmalloc(struct_size(saved_syn, data, len),
GFP_ATOMIC); GFP_ATOMIC);
if (saved_syn) { if (saved_syn) {
saved_syn->mac_hdrlen = mac_hdrlen;
saved_syn->network_hdrlen = skb_network_header_len(skb); saved_syn->network_hdrlen = skb_network_header_len(skb);
saved_syn->tcp_hdrlen = tcp_hdrlen(skb); saved_syn->tcp_hdrlen = tcp_hdrlen(skb);
memcpy(saved_syn->data, skb_network_header(skb), len); memcpy(saved_syn->data, base, len);
req->saved_syn = saved_syn; req->saved_syn = saved_syn;
} }
} }
......
...@@ -4540,6 +4540,7 @@ enum { ...@@ -4540,6 +4540,7 @@ enum {
*/ */
TCP_BPF_SYN = 1005, /* Copy the TCP header */ TCP_BPF_SYN = 1005, /* Copy the TCP header */
TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */ TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */
TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */
}; };
enum { enum {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment