Skip to content

Commit ae8b42c

Browse files
committed
Merge branch 'tcp-fastopen-ipv6'
Yuchung Cheng says: ==================== tcp: IPv6 support for fastopen server This patch series add IPv6 support for fastopen server. To minimize code duplication in IPv4 and IPv6, the current v4 only code is refactored and common code is moved into net/ipv4/tcp_fastopen.c. Also the current code uses a different function from tcp_v4_send_synack() to send the first SYN-ACK in fastopen. The new code eliminates this separate function by refactoring the child-socket and syn-ack creation code. After these refactoring in the first four patches, we can easily add the fastopen code in IPv6 by changing corresponding IPv6 functions. Note Fast Open client already supports IPv6. This patch is for the server-side (passive open) IPv6 support only. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 4b9734e + 3a19ce0 commit ae8b42c

File tree

7 files changed

+323
-309
lines changed

7 files changed

+323
-309
lines changed

include/linux/tcp.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,6 @@ static inline bool tcp_passive_fastopen(const struct sock *sk)
366366
tcp_sk(sk)->fastopen_rsk != NULL);
367367
}
368368

369-
static inline bool fastopen_cookie_present(struct tcp_fastopen_cookie *foc)
370-
{
371-
return foc->len != -1;
372-
}
373-
374369
extern void tcp_sock_destruct(struct sock *sk);
375370

376371
static inline int fastopen_init_queue(struct sock *sk, int backlog)

include/net/tcp.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,6 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
220220
#define TFO_SERVER_ENABLE 2
221221
#define TFO_CLIENT_NO_COOKIE 4 /* Data in SYN w/o cookie option */
222222

223-
/* Process SYN data but skip cookie validation */
224-
#define TFO_SERVER_COOKIE_NOT_CHKED 0x100
225223
/* Accept SYN data w/o any cookie option */
226224
#define TFO_SERVER_COOKIE_NOT_REQD 0x200
227225

@@ -230,10 +228,6 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
230228
*/
231229
#define TFO_SERVER_WO_SOCKOPT1 0x400
232230
#define TFO_SERVER_WO_SOCKOPT2 0x800
233-
/* Always create TFO child sockets on a TFO listener even when
234-
* cookie/data not present. (For testing purpose!)
235-
*/
236-
#define TFO_SERVER_ALWAYS 0x1000
237231

238232
extern struct inet_timewait_death_row tcp_death_row;
239233

@@ -1120,6 +1114,9 @@ static inline void tcp_openreq_init(struct request_sock *req,
11201114
ireq->ir_num = ntohs(tcp_hdr(skb)->dest);
11211115
}
11221116

1117+
extern void tcp_openreq_init_rwin(struct request_sock *req,
1118+
struct sock *sk, struct dst_entry *dst);
1119+
11231120
void tcp_enter_memory_pressure(struct sock *sk);
11241121

11251122
static inline int keepalive_intvl_when(const struct tcp_sock *tp)
@@ -1329,8 +1326,10 @@ void tcp_free_fastopen_req(struct tcp_sock *tp);
13291326

13301327
extern struct tcp_fastopen_context __rcu *tcp_fastopen_ctx;
13311328
int tcp_fastopen_reset_cipher(void *key, unsigned int len);
1332-
void tcp_fastopen_cookie_gen(__be32 src, __be32 dst,
1333-
struct tcp_fastopen_cookie *foc);
1329+
bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
1330+
struct request_sock *req,
1331+
struct tcp_fastopen_cookie *foc,
1332+
struct dst_entry *dst);
13341333
void tcp_fastopen_init_key_once(bool publish);
13351334
#define TCP_FASTOPEN_KEY_LENGTH 16
13361335

net/ipv4/tcp_fastopen.c

Lines changed: 209 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,25 +72,224 @@ 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;
127+
}
128+
129+
static bool tcp_fastopen_create_child(struct sock *sk,
130+
struct sk_buff *skb,
131+
struct dst_entry *dst,
132+
struct request_sock *req)
133+
{
134+
struct tcp_sock *tp = tcp_sk(sk);
135+
struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
136+
struct sock *child;
137+
138+
req->num_retrans = 0;
139+
req->num_timeout = 0;
140+
req->sk = NULL;
141+
142+
child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
143+
if (child == NULL)
144+
return false;
145+
146+
spin_lock(&queue->fastopenq->lock);
147+
queue->fastopenq->qlen++;
148+
spin_unlock(&queue->fastopenq->lock);
149+
150+
/* Initialize the child socket. Have to fix some values to take
151+
* into account the child is a Fast Open socket and is created
152+
* only out of the bits carried in the SYN packet.
153+
*/
154+
tp = tcp_sk(child);
155+
156+
tp->fastopen_rsk = req;
157+
/* Do a hold on the listner sk so that if the listener is being
158+
* closed, the child that has been accepted can live on and still
159+
* access listen_lock.
160+
*/
161+
sock_hold(sk);
162+
tcp_rsk(req)->listener = sk;
163+
164+
/* RFC1323: The window in SYN & SYN/ACK segments is never
165+
* scaled. So correct it appropriately.
166+
*/
167+
tp->snd_wnd = ntohs(tcp_hdr(skb)->window);
168+
169+
/* Activate the retrans timer so that SYNACK can be retransmitted.
170+
* The request socket is not added to the SYN table of the parent
171+
* because it's been added to the accept queue directly.
172+
*/
173+
inet_csk_reset_xmit_timer(child, ICSK_TIME_RETRANS,
174+
TCP_TIMEOUT_INIT, TCP_RTO_MAX);
175+
176+
/* Add the child socket directly into the accept queue */
177+
inet_csk_reqsk_queue_add(sk, req, child);
178+
179+
/* Now finish processing the fastopen child socket. */
180+
inet_csk(child)->icsk_af_ops->rebuild_header(child);
181+
tcp_init_congestion_control(child);
182+
tcp_mtup_init(child);
183+
tcp_init_metrics(child);
184+
tcp_init_buffer_space(child);
185+
186+
/* Queue the data carried in the SYN packet. We need to first
187+
* bump skb's refcnt because the caller will attempt to free it.
188+
*
189+
* XXX (TFO) - we honor a zero-payload TFO request for now,
190+
* (any reason not to?) but no need to queue the skb since
191+
* there is no data. How about SYN+FIN?
192+
*/
193+
if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1) {
194+
skb = skb_get(skb);
195+
skb_dst_drop(skb);
196+
__skb_pull(skb, tcp_hdr(skb)->doff * 4);
197+
skb_set_owner_r(skb, child);
198+
__skb_queue_tail(&child->sk_receive_queue, skb);
199+
tp->syn_data_acked = 1;
200+
}
201+
tcp_rsk(req)->rcv_nxt = tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
202+
sk->sk_data_ready(sk);
203+
bh_unlock_sock(child);
204+
sock_put(child);
205+
WARN_ON(req->sk == NULL);
206+
return true;
207+
}
208+
EXPORT_SYMBOL(tcp_fastopen_create_child);
209+
210+
static bool tcp_fastopen_queue_check(struct sock *sk)
211+
{
212+
struct fastopen_queue *fastopenq;
213+
214+
/* Make sure the listener has enabled fastopen, and we don't
215+
* exceed the max # of pending TFO requests allowed before trying
216+
* to validating the cookie in order to avoid burning CPU cycles
217+
* unnecessarily.
218+
*
219+
* XXX (TFO) - The implication of checking the max_qlen before
220+
* processing a cookie request is that clients can't differentiate
221+
* between qlen overflow causing Fast Open to be disabled
222+
* temporarily vs a server not supporting Fast Open at all.
223+
*/
224+
fastopenq = inet_csk(sk)->icsk_accept_queue.fastopenq;
225+
if (fastopenq == NULL || fastopenq->max_qlen == 0)
226+
return false;
227+
228+
if (fastopenq->qlen >= fastopenq->max_qlen) {
229+
struct request_sock *req1;
230+
spin_lock(&fastopenq->lock);
231+
req1 = fastopenq->rskq_rst_head;
232+
if ((req1 == NULL) || time_after(req1->expires, jiffies)) {
233+
spin_unlock(&fastopenq->lock);
234+
NET_INC_STATS_BH(sock_net(sk),
235+
LINUX_MIB_TCPFASTOPENLISTENOVERFLOW);
236+
return false;
237+
}
238+
fastopenq->rskq_rst_head = req1->dl_next;
239+
fastopenq->qlen--;
240+
spin_unlock(&fastopenq->lock);
241+
reqsk_free(req1);
242+
}
243+
return true;
244+
}
245+
246+
/* Returns true if we should perform Fast Open on the SYN. The cookie (foc)
247+
* may be updated and return the client in the SYN-ACK later. E.g., Fast Open
248+
* cookie request (foc->len == 0).
249+
*/
250+
bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
251+
struct request_sock *req,
252+
struct tcp_fastopen_cookie *foc,
253+
struct dst_entry *dst)
254+
{
255+
struct tcp_fastopen_cookie valid_foc = { .len = -1 };
256+
bool syn_data = TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1;
257+
258+
if (!((sysctl_tcp_fastopen & TFO_SERVER_ENABLE) &&
259+
(syn_data || foc->len >= 0) &&
260+
tcp_fastopen_queue_check(sk))) {
261+
foc->len = -1;
262+
return false;
263+
}
264+
265+
if (syn_data && (sysctl_tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD))
266+
goto fastopen;
267+
268+
if (tcp_fastopen_cookie_gen(req, skb, &valid_foc) &&
269+
foc->len == TCP_FASTOPEN_COOKIE_SIZE &&
270+
foc->len == valid_foc.len &&
271+
!memcmp(foc->val, valid_foc.val, foc->len)) {
272+
/* Cookie is valid. Create a (full) child socket to accept
273+
* the data in SYN before returning a SYN-ACK to ack the
274+
* data. If we fail to create the socket, fall back and
275+
* ack the ISN only but includes the same cookie.
276+
*
277+
* Note: Data-less SYN with valid cookie is allowed to send
278+
* data in SYN_RECV state.
279+
*/
280+
fastopen:
281+
if (tcp_fastopen_create_child(sk, skb, dst, req)) {
282+
foc->len = -1;
283+
NET_INC_STATS_BH(sock_net(sk),
284+
LINUX_MIB_TCPFASTOPENPASSIVE);
285+
return true;
286+
}
287+
}
288+
289+
NET_INC_STATS_BH(sock_net(sk), foc->len ?
290+
LINUX_MIB_TCPFASTOPENPASSIVEFAIL :
291+
LINUX_MIB_TCPFASTOPENCOOKIEREQD);
292+
*foc = valid_foc;
293+
return false;
96294
}
295+
EXPORT_SYMBOL(tcp_try_fastopen);

0 commit comments

Comments
 (0)