[TCP]: TCP_DEFER_ACCEPT updates - process as established
Change TCP_DEFER_ACCEPT implementation so that it transitions a connection to ESTABLISHED after handshake is complete instead of leaving it in SYN-RECV until some data arrvies. Place connection in accept queue when first data packet arrives from slow path. Benefits: - established connection is now reset if it never makes it to the accept queue - diagnostic state of established matches with the packet traces showing completed handshake - TCP_DEFER_ACCEPT timeouts are expressed in seconds and can now be enforced with reasonable accuracy instead of rounding up to next exponential back-off of syn-ack retry. Signed-off-by: Patrick McManus <mcmanus@ducksong.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
e4c7884028
commit
ec3c0982a2
@@ -4451,6 +4451,49 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th)
|
||||
}
|
||||
}
|
||||
|
||||
static int tcp_defer_accept_check(struct sock *sk)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
|
||||
if (tp->defer_tcp_accept.request) {
|
||||
int queued_data = tp->rcv_nxt - tp->copied_seq;
|
||||
int hasfin = !skb_queue_empty(&sk->sk_receive_queue) ?
|
||||
tcp_hdr((struct sk_buff *)
|
||||
sk->sk_receive_queue.prev)->fin : 0;
|
||||
|
||||
if (queued_data && hasfin)
|
||||
queued_data--;
|
||||
|
||||
if (queued_data &&
|
||||
tp->defer_tcp_accept.listen_sk->sk_state == TCP_LISTEN) {
|
||||
if (sock_flag(sk, SOCK_KEEPOPEN)) {
|
||||
inet_csk_reset_keepalive_timer(sk,
|
||||
keepalive_time_when(tp));
|
||||
} else {
|
||||
inet_csk_delete_keepalive_timer(sk);
|
||||
}
|
||||
|
||||
inet_csk_reqsk_queue_add(
|
||||
tp->defer_tcp_accept.listen_sk,
|
||||
tp->defer_tcp_accept.request,
|
||||
sk);
|
||||
|
||||
tp->defer_tcp_accept.listen_sk->sk_data_ready(
|
||||
tp->defer_tcp_accept.listen_sk, 0);
|
||||
|
||||
sock_put(tp->defer_tcp_accept.listen_sk);
|
||||
sock_put(sk);
|
||||
tp->defer_tcp_accept.listen_sk = NULL;
|
||||
tp->defer_tcp_accept.request = NULL;
|
||||
} else if (hasfin ||
|
||||
tp->defer_tcp_accept.listen_sk->sk_state != TCP_LISTEN) {
|
||||
tcp_reset(sk);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
@@ -4811,6 +4854,9 @@ step5:
|
||||
|
||||
tcp_data_snd_check(sk);
|
||||
tcp_ack_snd_check(sk);
|
||||
|
||||
if (tcp_defer_accept_check(sk))
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
csum_error:
|
||||
|
Reference in New Issue
Block a user