diff options
author | Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> | 2007-11-11 00:24:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-11-11 00:24:19 -0500 |
commit | fbd52eb2bd17bd3468974aa2fdce140f0cd32fc7 (patch) | |
tree | ca3b4363dba852caee16f388d48ff4ffe2cc2341 /net/ipv4 | |
parent | e49aa5d456802c6bec59b29d1d7cbd8e9cc71709 (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.c | 35 |
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 && |