diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp_input.c | 37 |
1 files changed, 22 insertions, 15 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a06603912137..d5e0fcc22a3b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1109,27 +1109,34 @@ static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack, | |||
1109 | /* Check for lost retransmit. This superb idea is borrowed from "ratehalving". | 1109 | /* Check for lost retransmit. This superb idea is borrowed from "ratehalving". |
1110 | * Event "C". Later note: FACK people cheated me again 8), we have to account | 1110 | * Event "C". Later note: FACK people cheated me again 8), we have to account |
1111 | * for reordering! Ugly, but should help. | 1111 | * for reordering! Ugly, but should help. |
1112 | * | ||
1113 | * Search retransmitted skbs from write_queue that were sent when snd_nxt was | ||
1114 | * less than what is now known to be received by the other end (derived from | ||
1115 | * SACK blocks by the caller). | ||
1112 | */ | 1116 | */ |
1113 | static int tcp_mark_lost_retrans(struct sock *sk, u32 lost_retrans) | 1117 | static int tcp_mark_lost_retrans(struct sock *sk, u32 received_upto) |
1114 | { | 1118 | { |
1115 | struct tcp_sock *tp = tcp_sk(sk); | 1119 | struct tcp_sock *tp = tcp_sk(sk); |
1116 | struct sk_buff *skb; | 1120 | struct sk_buff *skb; |
1117 | int flag = 0; | 1121 | int flag = 0; |
1122 | int cnt = 0; | ||
1118 | 1123 | ||
1119 | tcp_for_write_queue(skb, sk) { | 1124 | tcp_for_write_queue(skb, sk) { |
1120 | u32 ack_seq = TCP_SKB_CB(skb)->ack_seq; | 1125 | u32 ack_seq = TCP_SKB_CB(skb)->ack_seq; |
1121 | 1126 | ||
1122 | if (skb == tcp_send_head(sk)) | 1127 | if (skb == tcp_send_head(sk)) |
1123 | break; | 1128 | break; |
1124 | if (after(TCP_SKB_CB(skb)->seq, lost_retrans)) | 1129 | if (cnt == tp->retrans_out) |
1125 | break; | 1130 | break; |
1126 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) | 1131 | if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) |
1127 | continue; | 1132 | continue; |
1128 | 1133 | ||
1129 | if ((TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) && | 1134 | if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)) |
1130 | after(lost_retrans, ack_seq) && | 1135 | continue; |
1136 | |||
1137 | if (after(received_upto, ack_seq) && | ||
1131 | (tcp_is_fack(tp) || | 1138 | (tcp_is_fack(tp) || |
1132 | !before(lost_retrans, | 1139 | !before(received_upto, |
1133 | ack_seq + tp->reordering * tp->mss_cache))) { | 1140 | ack_seq + tp->reordering * tp->mss_cache))) { |
1134 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; | 1141 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; |
1135 | tp->retrans_out -= tcp_skb_pcount(skb); | 1142 | tp->retrans_out -= tcp_skb_pcount(skb); |
@@ -1143,6 +1150,8 @@ static int tcp_mark_lost_retrans(struct sock *sk, u32 lost_retrans) | |||
1143 | flag |= FLAG_DATA_SACKED; | 1150 | flag |= FLAG_DATA_SACKED; |
1144 | NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); | 1151 | NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); |
1145 | } | 1152 | } |
1153 | } else { | ||
1154 | cnt += tcp_skb_pcount(skb); | ||
1146 | } | 1155 | } |
1147 | } | 1156 | } |
1148 | return flag; | 1157 | return flag; |
@@ -1225,7 +1234,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1225 | int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; | 1234 | int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; |
1226 | int reord = tp->packets_out; | 1235 | int reord = tp->packets_out; |
1227 | int prior_fackets; | 1236 | int prior_fackets; |
1228 | u32 lost_retrans = 0; | 1237 | u32 highest_sack_end_seq = 0; |
1229 | int flag = 0; | 1238 | int flag = 0; |
1230 | int found_dup_sack = 0; | 1239 | int found_dup_sack = 0; |
1231 | int cached_fack_count; | 1240 | int cached_fack_count; |
@@ -1396,11 +1405,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1396 | continue; | 1405 | continue; |
1397 | } | 1406 | } |
1398 | 1407 | ||
1399 | if ((sacked&TCPCB_SACKED_RETRANS) && | ||
1400 | after(end_seq, TCP_SKB_CB(skb)->ack_seq) && | ||
1401 | (!lost_retrans || after(end_seq, lost_retrans))) | ||
1402 | lost_retrans = end_seq; | ||
1403 | |||
1404 | if (!in_sack) | 1408 | if (!in_sack) |
1405 | continue; | 1409 | continue; |
1406 | 1410 | ||
@@ -1454,9 +1458,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1454 | if (fack_count > tp->fackets_out) | 1458 | if (fack_count > tp->fackets_out) |
1455 | tp->fackets_out = fack_count; | 1459 | tp->fackets_out = fack_count; |
1456 | 1460 | ||
1457 | if (after(TCP_SKB_CB(skb)->seq, | 1461 | if (after(TCP_SKB_CB(skb)->seq, tp->highest_sack)) { |
1458 | tp->highest_sack)) | ||
1459 | tp->highest_sack = TCP_SKB_CB(skb)->seq; | 1462 | tp->highest_sack = TCP_SKB_CB(skb)->seq; |
1463 | highest_sack_end_seq = TCP_SKB_CB(skb)->end_seq; | ||
1464 | } | ||
1460 | } else { | 1465 | } else { |
1461 | if (dup_sack && (sacked&TCPCB_RETRANS)) | 1466 | if (dup_sack && (sacked&TCPCB_RETRANS)) |
1462 | reord = min(fack_count, reord); | 1467 | reord = min(fack_count, reord); |
@@ -1476,8 +1481,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1476 | } | 1481 | } |
1477 | } | 1482 | } |
1478 | 1483 | ||
1479 | if (lost_retrans && icsk->icsk_ca_state == TCP_CA_Recovery) | 1484 | if (tp->retrans_out && highest_sack_end_seq && |
1480 | flag |= tcp_mark_lost_retrans(sk, lost_retrans); | 1485 | after(highest_sack_end_seq, tp->high_seq) && |
1486 | icsk->icsk_ca_state == TCP_CA_Recovery) | ||
1487 | flag |= tcp_mark_lost_retrans(sk, highest_sack_end_seq); | ||
1481 | 1488 | ||
1482 | tcp_verify_left_out(tp); | 1489 | tcp_verify_left_out(tp); |
1483 | 1490 | ||