aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/tcp_input.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 8fe754be8076..0feb10935be1 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -104,6 +104,7 @@ int sysctl_tcp_abc __read_mostly;
104#define FLAG_ONLY_ORIG_SACKED 0x200 /* SACKs only non-rexmit sent before RTO */ 104#define FLAG_ONLY_ORIG_SACKED 0x200 /* SACKs only non-rexmit sent before RTO */
105#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ 105#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */
106#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained DSACK info */ 106#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained DSACK info */
107#define FLAG_NONHEAD_RETRANS_ACKED 0x1000 /* Non-head rexmitted data was ACKed */
107 108
108#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) 109#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED)
109#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) 110#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
@@ -1594,6 +1595,8 @@ void tcp_enter_frto(struct sock *sk)
1594 tp->undo_retrans = 0; 1595 tp->undo_retrans = 0;
1595 1596
1596 skb = tcp_write_queue_head(sk); 1597 skb = tcp_write_queue_head(sk);
1598 if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
1599 tp->undo_marker = 0;
1597 if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { 1600 if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {
1598 TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; 1601 TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
1599 tp->retrans_out -= tcp_skb_pcount(skb); 1602 tp->retrans_out -= tcp_skb_pcount(skb);
@@ -1643,6 +1646,8 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
1643 /* ...enter this if branch just for the first segment */ 1646 /* ...enter this if branch just for the first segment */
1644 flag |= FLAG_DATA_ACKED; 1647 flag |= FLAG_DATA_ACKED;
1645 } else { 1648 } else {
1649 if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
1650 tp->undo_marker = 0;
1646 TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); 1651 TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
1647 } 1652 }
1648 1653
@@ -1658,7 +1663,6 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
1658 tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments; 1663 tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments;
1659 tp->snd_cwnd_cnt = 0; 1664 tp->snd_cwnd_cnt = 0;
1660 tp->snd_cwnd_stamp = tcp_time_stamp; 1665 tp->snd_cwnd_stamp = tcp_time_stamp;
1661 tp->undo_marker = 0;
1662 tp->frto_counter = 0; 1666 tp->frto_counter = 0;
1663 1667
1664 tp->reordering = min_t(unsigned int, tp->reordering, 1668 tp->reordering = min_t(unsigned int, tp->reordering,
@@ -2584,20 +2588,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p)
2584 end_seq = scb->end_seq; 2588 end_seq = scb->end_seq;
2585 } 2589 }
2586 2590
2587 /* Initial outgoing SYN's get put onto the write_queue
2588 * just like anything else we transmit. It is not
2589 * true data, and if we misinform our callers that
2590 * this ACK acks real data, we will erroneously exit
2591 * connection startup slow start one packet too
2592 * quickly. This is severely frowned upon behavior.
2593 */
2594 if (!(scb->flags & TCPCB_FLAG_SYN)) {
2595 flag |= FLAG_DATA_ACKED;
2596 } else {
2597 flag |= FLAG_SYN_ACKED;
2598 tp->retrans_stamp = 0;
2599 }
2600
2601 /* MTU probing checks */ 2591 /* MTU probing checks */
2602 if (fully_acked && icsk->icsk_mtup.probe_size && 2592 if (fully_acked && icsk->icsk_mtup.probe_size &&
2603 !after(tp->mtu_probe.probe_seq_end, scb->end_seq)) { 2593 !after(tp->mtu_probe.probe_seq_end, scb->end_seq)) {
@@ -2610,6 +2600,9 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p)
2610 tp->retrans_out -= packets_acked; 2600 tp->retrans_out -= packets_acked;
2611 flag |= FLAG_RETRANS_DATA_ACKED; 2601 flag |= FLAG_RETRANS_DATA_ACKED;
2612 seq_rtt = -1; 2602 seq_rtt = -1;
2603 if ((flag & FLAG_DATA_ACKED) ||
2604 (packets_acked > 1))
2605 flag |= FLAG_NONHEAD_RETRANS_ACKED;
2613 } else if (seq_rtt < 0) { 2606 } else if (seq_rtt < 0) {
2614 seq_rtt = now - scb->when; 2607 seq_rtt = now - scb->when;
2615 if (fully_acked) 2608 if (fully_acked)
@@ -2631,6 +2624,20 @@ static int tcp_clean_rtx_queue(struct sock *sk, s32 *seq_rtt_p)
2631 } 2624 }
2632 tp->packets_out -= packets_acked; 2625 tp->packets_out -= packets_acked;
2633 2626
2627 /* Initial outgoing SYN's get put onto the write_queue
2628 * just like anything else we transmit. It is not
2629 * true data, and if we misinform our callers that
2630 * this ACK acks real data, we will erroneously exit
2631 * connection startup slow start one packet too
2632 * quickly. This is severely frowned upon behavior.
2633 */
2634 if (!(scb->flags & TCPCB_FLAG_SYN)) {
2635 flag |= FLAG_DATA_ACKED;
2636 } else {
2637 flag |= FLAG_SYN_ACKED;
2638 tp->retrans_stamp = 0;
2639 }
2640
2634 if (!fully_acked) 2641 if (!fully_acked)
2635 break; 2642 break;
2636 2643
@@ -2852,6 +2859,10 @@ static int tcp_process_frto(struct sock *sk, int flag)
2852 if (flag&FLAG_DATA_ACKED) 2859 if (flag&FLAG_DATA_ACKED)
2853 inet_csk(sk)->icsk_retransmits = 0; 2860 inet_csk(sk)->icsk_retransmits = 0;
2854 2861
2862 if ((flag & FLAG_NONHEAD_RETRANS_ACKED) ||
2863 ((tp->frto_counter >= 2) && (flag & FLAG_RETRANS_DATA_ACKED)))
2864 tp->undo_marker = 0;
2865
2855 if (!before(tp->snd_una, tp->frto_highmark)) { 2866 if (!before(tp->snd_una, tp->frto_highmark)) {
2856 tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag); 2867 tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag);
2857 return 1; 2868 return 1;
@@ -2916,6 +2927,7 @@ static int tcp_process_frto(struct sock *sk, int flag)
2916 break; 2927 break;
2917 } 2928 }
2918 tp->frto_counter = 0; 2929 tp->frto_counter = 0;
2930 tp->undo_marker = 0;
2919 } 2931 }
2920 return 0; 2932 return 0;
2921} 2933}