From patchwork Thu Dec 6 18:45:32 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuchung Cheng X-Patchwork-Id: 204300 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 15AB82C00DB for ; Fri, 7 Dec 2012 05:45:50 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1946674Ab2LFSpr (ORCPT ); Thu, 6 Dec 2012 13:45:47 -0500 Received: from mail-yh0-f74.google.com ([209.85.213.74]:50638 "EHLO mail-yh0-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S964860Ab2LFSpq (ORCPT ); Thu, 6 Dec 2012 13:45:46 -0500 Received: by mail-yh0-f74.google.com with SMTP id 10so675637yhl.1 for ; Thu, 06 Dec 2012 10:45:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer; bh=GNJsCsa0JiqdrEnrOCTeMk/Qtl1U7dE8OQEb2A5FsUg=; b=bqILYonAuNpgP89Q57fbncUxa0QqcHgiDAi36B4f9zGLTt5gcUnRAJA4BwqnQ/ViRm zslZBOKjxk3Z7PF9cY778gzzDXl15NZwvDHDszKoPNEI4sSqEEjFDDg8MT2V5/6yCWQD ZeL+WEvaXYhQLg7E3TT6Y53+QA6pR78cWLQqepVPvWHVpR/HKQqRJ716eNtXLIxJFcic nXZXN9N+BXL8dsrYBdV0Zcy8IAlG77onTcWsdzUwJLz91qKPy4FCzqdMKS/tm+VQW92I DlRhAipkKi3qYT+Hdp6txLpifkzphv8BDT0LE6OfkOpZ18wkGrnqeVnpY1B8mOtzjXkE Tywg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:x-gm-message-state; bh=GNJsCsa0JiqdrEnrOCTeMk/Qtl1U7dE8OQEb2A5FsUg=; b=LFoj7lCHH9bGz0gZAf80+ZIVTWrKYxXgE1/g4CDIbNm2fi5EWg/75QESW0PJWkjQ30 c/iUMoLHJ7j/5VB4s8zG9oRq7can1hvFnhfyZ2LywY/AhjIuzwzEscXBKmIg8PctKOfC X9g1iBbdVOBY7mWGXeBePCW2ZNc59DyOKLWfAFCQ0uIKivlW69Hq70iazdsEuLpZpGzq sbBP/k3BAfBvSL8jj5imgTahdTconmTwhrsYAXxybP5lE2jmRZUDNTvlC5QfpDdkvF7Q T969LGmZPTLYvhc4E43D7OYRun8Iu8DcVcSk1v/8f7zyIkIRz09KaE1M7/b1y+ouB285 6B8w== Received: by 10.236.119.82 with SMTP id m58mr1645261yhh.26.1354819543832; Thu, 06 Dec 2012 10:45:43 -0800 (PST) Received: from wpzn4.hot.corp.google.com (216-239-44-65.google.com [216.239.44.65]) by gmr-mx.google.com with ESMTPS id r10si397214ann.1.2012.12.06.10.45.43 (version=TLSv1/SSLv3 cipher=AES128-SHA); Thu, 06 Dec 2012 10:45:43 -0800 (PST) Received: from blast2.mtv.corp.google.com (blast2.mtv.corp.google.com [172.17.132.164]) by wpzn4.hot.corp.google.com (Postfix) with ESMTP id 9C7CE82004A; Thu, 6 Dec 2012 10:45:43 -0800 (PST) Received: by blast2.mtv.corp.google.com (Postfix, from userid 5463) id 41FE2180AD6; Thu, 6 Dec 2012 10:45:43 -0800 (PST) From: Yuchung Cheng To: davem@davemloft.net, ncardwell@google.com, nanditad@google.com, edumazet@google.com Cc: netdev@vger.kernel.org, Yuchung Cheng Subject: [PATCH] tcp: bug fix Fast Open client retransmission Date: Thu, 6 Dec 2012 10:45:32 -0800 Message-Id: <1354819532-15676-1-git-send-email-ycheng@google.com> X-Mailer: git-send-email 1.7.7.3 X-Gm-Message-State: ALoCoQmhlbS3bNSAoKeJRr4+uGm7H1UPq5eKiJBYSWJLerRI/c2DDh9fPJ4auTORo/6kRSNBpAJeQvd2MfTwYS3NmNYu3xFCTZHzS4BNXtETMnXMtx24OoqSSDu9kCLqlHpZOtvUC9waBp21LfrbbSqUmdkMnCjL2RtmM44Yrb9BkfS+J1Vp35VtSeRf4YaV49LTNGdR0mMF Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org If SYN-ACK partially acks SYN-data, the client retransmits the remaining data by tcp_retransmit_skb(). This increments lost recovery state variables like tp->retrans_out in Open state. If loss recovery happens before the retransmission is acked, it triggers the WARN_ON check in tcp_fastretrans_alert(). For example: the client sends SYN-data, gets SYN-ACK acking only ISN, retransmits data, sends another 4 data packets and get 3 dupacks. Since the retransmission is not caused by network drop it should not update the recovery state variables. Further the server may return a smaller MSS than the cached MSS used for SYN-data, so the retranmission needs a loop. Otherwise some data will not be retransmitted until timeout or other loss recovery events. Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell --- include/net/tcp.h | 1 + net/ipv4/tcp_input.c | 6 +++++- net/ipv4/tcp_output.c | 15 ++++++++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 3202bde..aed42c7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -524,6 +524,7 @@ static inline __u32 cookie_v6_init_sequence(struct sock *sk, extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, int nonagle); extern bool tcp_may_send_now(struct sock *sk); +extern int __tcp_retransmit_skb(struct sock *, struct sk_buff *); extern int tcp_retransmit_skb(struct sock *, struct sk_buff *); extern void tcp_retransmit_timer(struct sock *sk); extern void tcp_xmit_retransmit_queue(struct sock *); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index fc67831..a136925 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5652,7 +5652,11 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, tcp_fastopen_cache_set(sk, mss, cookie, syn_drop); if (data) { /* Retransmit unacked data in SYN */ - tcp_retransmit_skb(sk, data); + tcp_for_write_queue_from(data, sk) { + if (data == tcp_send_head(sk) || + __tcp_retransmit_skb(sk, data)) + break; + } tcp_rearm_rto(sk); return true; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 8ac0855..5d45159 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2309,12 +2309,11 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to, * state updates are done by the caller. Returns non-zero if an * error occurred which prevented the send. */ -int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) +int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); unsigned int cur_mss; - int err; /* Inconslusive MTU probe */ if (icsk->icsk_mtup.probe_size) { @@ -2387,11 +2386,17 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) if (unlikely(NET_IP_ALIGN && ((unsigned long)skb->data & 3))) { struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER, GFP_ATOMIC); - err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : - -ENOBUFS; + return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : + -ENOBUFS; } else { - err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); + return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); } +} + +int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_sock *tp = tcp_sk(sk); + int err = __tcp_retransmit_skb(sk, skb); if (err == 0) { /* Update global TCP statistics. */