aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2007-11-11 00:24:19 -0500
committerDavid S. Miller <davem@davemloft.net>2007-11-11 00:24:19 -0500
commitfbd52eb2bd17bd3468974aa2fdce140f0cd32fc7 (patch)
treeca3b4363dba852caee16f388d48ff4ffe2cc2341 /net/ipv4
parente49aa5d456802c6bec59b29d1d7cbd8e9cc71709 (diff)
[TCP]: Split SACK FRTO flag clearing (fixes FRTO corner case bug)
In case we run out of mem when fragmenting, the clearing of FLAG_ONLY_ORIG_SACKED might get missed which then feeds FRTO with false information. Move clearing outside skb processing loop so that it will get executed even if the skb loop terminates prematurely due to out-of-mem. Besides, now the core of the loop truly deals with a single skb only, which also enables creation a more self-contained of tcp_sacktag_one later on. In addition, small reorganization of if branches was made. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/tcp_input.c35
1 files changed, 17 insertions, 18 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 84bcdc94dfa9..20c9440ab85e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1444,12 +1444,17 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
1444 tp->retransmit_skb_hint = NULL; 1444 tp->retransmit_skb_hint = NULL;
1445 } 1445 }
1446 } else { 1446 } else {
1447 /* New sack for not retransmitted frame, 1447 if (!(sacked & TCPCB_RETRANS)) {
1448 * which was in hole. It is reordering. 1448 /* New sack for not retransmitted frame,
1449 */ 1449 * which was in hole. It is reordering.
1450 if (!(sacked & TCPCB_RETRANS) && 1450 */
1451 fack_count < prior_fackets) 1451 if (fack_count < prior_fackets)
1452 reord = min(fack_count, reord); 1452 reord = min(fack_count, reord);
1453
1454 /* SACK enhanced F-RTO (RFC4138; Appendix B) */
1455 if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark))
1456 flag |= FLAG_ONLY_ORIG_SACKED;
1457 }
1453 1458
1454 if (sacked & TCPCB_LOST) { 1459 if (sacked & TCPCB_LOST) {
1455 TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; 1460 TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
@@ -1458,18 +1463,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
1458 /* clear lost hint */ 1463 /* clear lost hint */
1459 tp->retransmit_skb_hint = NULL; 1464 tp->retransmit_skb_hint = NULL;
1460 } 1465 }
1461 /* SACK enhanced F-RTO detection.
1462 * Set flag if and only if non-rexmitted
1463 * segments below frto_highmark are
1464 * SACKed (RFC4138; Appendix B).
1465 * Clearing correct due to in-order walk
1466 */
1467 if (after(end_seq, tp->frto_highmark)) {
1468 flag &= ~FLAG_ONLY_ORIG_SACKED;
1469 } else {
1470 if (!(sacked & TCPCB_RETRANS))
1471 flag |= FLAG_ONLY_ORIG_SACKED;
1472 }
1473 } 1466 }
1474 1467
1475 TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED; 1468 TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
@@ -1503,6 +1496,12 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
1503 tp->retransmit_skb_hint = NULL; 1496 tp->retransmit_skb_hint = NULL;
1504 } 1497 }
1505 } 1498 }
1499
1500 /* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct
1501 * due to in-order walk
1502 */
1503 if (after(end_seq, tp->frto_highmark))
1504 flag &= ~FLAG_ONLY_ORIG_SACKED;
1506 } 1505 }
1507 1506
1508 if (tp->retrans_out && 1507 if (tp->retrans_out &&