Skip to content

Commit 3a19ce0

Browse files
Longinus00davem330
authored andcommitted
tcp: IPv6 support for fastopen server
After all the preparatory works, supporting IPv6 in Fast Open is now easy. We pretty much just mirror v4 code. The only difference is how we generate the Fast Open cookie for IPv6 sockets. Since Fast Open cookie is 128 bits and we use AES 128, we use CBC-MAC to encrypt both the source and destination IPv6 addresses since the cookie is a MAC tag. Signed-off-by: Daniel Lee <[email protected]> Signed-off-by: Yuchung Cheng <[email protected]> Signed-off-by: Jerry Chu <[email protected]> Acked-by: Neal Cardwell <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0a672f7 commit 3a19ce0

File tree

2 files changed

+71
-26
lines changed

2 files changed

+71
-26
lines changed

net/ipv4/tcp_fastopen.c

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,27 +72,58 @@ error: kfree(ctx);
7272
return err;
7373
}
7474

75-
/* Computes the fastopen cookie for the IP path.
76-
* The path is a 128 bits long (pad with zeros for IPv4).
77-
*
78-
* The caller must check foc->len to determine if a valid cookie
79-
* has been generated successfully.
80-
*/
81-
void tcp_fastopen_cookie_gen(__be32 src, __be32 dst,
82-
struct tcp_fastopen_cookie *foc)
75+
static bool __tcp_fastopen_cookie_gen(const void *path,
76+
struct tcp_fastopen_cookie *foc)
8377
{
84-
__be32 path[4] = { src, dst, 0, 0 };
8578
struct tcp_fastopen_context *ctx;
79+
bool ok = false;
8680

8781
tcp_fastopen_init_key_once(true);
8882

8983
rcu_read_lock();
9084
ctx = rcu_dereference(tcp_fastopen_ctx);
9185
if (ctx) {
92-
crypto_cipher_encrypt_one(ctx->tfm, foc->val, (__u8 *)path);
86+
crypto_cipher_encrypt_one(ctx->tfm, foc->val, path);
9387
foc->len = TCP_FASTOPEN_COOKIE_SIZE;
88+
ok = true;
9489
}
9590
rcu_read_unlock();
91+
return ok;
92+
}
93+
94+
/* Generate the fastopen cookie by doing aes128 encryption on both
95+
* the source and destination addresses. Pad 0s for IPv4 or IPv4-mapped-IPv6
96+
* addresses. For the longer IPv6 addresses use CBC-MAC.
97+
*
98+
* XXX (TFO) - refactor when TCP_FASTOPEN_COOKIE_SIZE != AES_BLOCK_SIZE.
99+
*/
100+
static bool tcp_fastopen_cookie_gen(struct request_sock *req,
101+
struct sk_buff *syn,
102+
struct tcp_fastopen_cookie *foc)
103+
{
104+
if (req->rsk_ops->family == AF_INET) {
105+
const struct iphdr *iph = ip_hdr(syn);
106+
107+
__be32 path[4] = { iph->saddr, iph->daddr, 0, 0 };
108+
return __tcp_fastopen_cookie_gen(path, foc);
109+
}
110+
111+
#if IS_ENABLED(CONFIG_IPV6)
112+
if (req->rsk_ops->family == AF_INET6) {
113+
const struct ipv6hdr *ip6h = ipv6_hdr(syn);
114+
struct tcp_fastopen_cookie tmp;
115+
116+
if (__tcp_fastopen_cookie_gen(&ip6h->saddr, &tmp)) {
117+
struct in6_addr *buf = (struct in6_addr *) tmp.val;
118+
int i = 4;
119+
120+
for (i = 0; i < 4; i++)
121+
buf->s6_addr32[i] ^= ip6h->daddr.s6_addr32[i];
122+
return __tcp_fastopen_cookie_gen(buf, foc);
123+
}
124+
}
125+
#endif
126+
return false;
96127
}
97128

98129
static bool tcp_fastopen_create_child(struct sock *sk,
@@ -234,10 +265,8 @@ bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
234265
if (syn_data && (sysctl_tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD))
235266
goto fastopen;
236267

237-
tcp_fastopen_cookie_gen(ip_hdr(skb)->saddr,
238-
ip_hdr(skb)->daddr, &valid_foc);
239-
240-
if (foc->len == TCP_FASTOPEN_COOKIE_SIZE &&
268+
if (tcp_fastopen_cookie_gen(req, skb, &valid_foc) &&
269+
foc->len == TCP_FASTOPEN_COOKIE_SIZE &&
241270
foc->len == valid_foc.len &&
242271
!memcmp(foc->val, valid_foc.val, foc->len)) {
243272
/* Cookie is valid. Create a (full) child socket to accept

net/ipv6/tcp_ipv6.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
472472
static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
473473
struct flowi6 *fl6,
474474
struct request_sock *req,
475-
u16 queue_mapping)
475+
u16 queue_mapping,
476+
struct tcp_fastopen_cookie *foc)
476477
{
477478
struct inet_request_sock *ireq = inet_rsk(req);
478479
struct ipv6_pinfo *np = inet6_sk(sk);
@@ -483,7 +484,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
483484
if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL)
484485
goto done;
485486

486-
skb = tcp_make_synack(sk, dst, req, NULL);
487+
skb = tcp_make_synack(sk, dst, req, foc);
487488

488489
if (skb) {
489490
__tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr,
@@ -507,7 +508,7 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req)
507508
struct flowi6 fl6;
508509
int res;
509510

510-
res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0);
511+
res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0, NULL);
511512
if (!res) {
512513
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
513514
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
@@ -926,7 +927,12 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
926927
static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
927928
struct request_sock *req)
928929
{
929-
tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1,
930+
/* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
931+
* sk->sk_state == TCP_SYN_RECV -> for Fast Open.
932+
*/
933+
tcp_v6_send_ack(skb, (sk->sk_state == TCP_LISTEN) ?
934+
tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
935+
tcp_rsk(req)->rcv_nxt,
930936
req->rcv_wnd, tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if,
931937
tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
932938
0, 0);
@@ -978,8 +984,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
978984
struct tcp_sock *tp = tcp_sk(sk);
979985
__u32 isn = TCP_SKB_CB(skb)->when;
980986
struct dst_entry *dst = NULL;
987+
struct tcp_fastopen_cookie foc = { .len = -1 };
988+
bool want_cookie = false, fastopen;
981989
struct flowi6 fl6;
982-
bool want_cookie = false;
990+
int err;
983991

984992
if (skb->protocol == htons(ETH_P_IP))
985993
return tcp_v4_conn_request(sk, skb);
@@ -1010,7 +1018,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
10101018
tcp_clear_options(&tmp_opt);
10111019
tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
10121020
tmp_opt.user_mss = tp->rx_opt.user_mss;
1013-
tcp_parse_options(skb, &tmp_opt, 0, NULL);
1021+
tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc);
10141022

10151023
if (want_cookie && !tmp_opt.saw_tstamp)
10161024
tcp_clear_options(&tmp_opt);
@@ -1083,19 +1091,27 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
10831091
isn = tcp_v6_init_sequence(skb);
10841092
}
10851093
have_isn:
1086-
tcp_rsk(req)->snt_isn = isn;
10871094

10881095
if (security_inet_conn_request(sk, skb, req))
10891096
goto drop_and_release;
10901097

1091-
if (tcp_v6_send_synack(sk, dst, &fl6, req,
1092-
skb_get_queue_mapping(skb)) ||
1093-
want_cookie)
1098+
if (!dst && (dst = inet6_csk_route_req(sk, &fl6, req)) == NULL)
10941099
goto drop_and_free;
10951100

1101+
tcp_rsk(req)->snt_isn = isn;
10961102
tcp_rsk(req)->snt_synack = tcp_time_stamp;
1097-
tcp_rsk(req)->listener = NULL;
1098-
inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1103+
tcp_openreq_init_rwin(req, sk, dst);
1104+
fastopen = !want_cookie &&
1105+
tcp_try_fastopen(sk, skb, req, &foc, dst);
1106+
err = tcp_v6_send_synack(sk, dst, &fl6, req,
1107+
skb_get_queue_mapping(skb), &foc);
1108+
if (!fastopen) {
1109+
if (err || want_cookie)
1110+
goto drop_and_free;
1111+
1112+
tcp_rsk(req)->listener = NULL;
1113+
inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1114+
}
10991115
return 0;
11001116

11011117
drop_and_release:

0 commit comments

Comments
 (0)