diff options
author | Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> | 2010-10-13 21:42:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-17 16:46:33 -0400 |
commit | 1fdb936101637c91819efea47e921bb592e07e34 (patch) | |
tree | c713564e117225a2af79479a0ed82d277a54e41d /net/ipv4/tcp_input.c | |
parent | f3e85df845a5da60fc461cf49537435b1d07cf6d (diff) |
tcp: sack lost marking fixes
When only fast rexmit should be done, tcp_mark_head_lost marks
L too far. Also, sacked_upto below 1 is perfectly valid number,
the packets == 0 then needs to be trapped elsewhere.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e4fbdae066d5..ee0df4817498 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2495,7 +2495,7 @@ static void tcp_timeout_skbs(struct sock *sk) | |||
2495 | /* Mark head of queue up as lost. With RFC3517 SACK, the packets is | 2495 | /* Mark head of queue up as lost. With RFC3517 SACK, the packets is |
2496 | * is against sacked "cnt", otherwise it's against facked "cnt" | 2496 | * is against sacked "cnt", otherwise it's against facked "cnt" |
2497 | */ | 2497 | */ |
2498 | static void tcp_mark_head_lost(struct sock *sk, int packets) | 2498 | static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head) |
2499 | { | 2499 | { |
2500 | struct tcp_sock *tp = tcp_sk(sk); | 2500 | struct tcp_sock *tp = tcp_sk(sk); |
2501 | struct sk_buff *skb; | 2501 | struct sk_buff *skb; |
@@ -2503,13 +2503,13 @@ static void tcp_mark_head_lost(struct sock *sk, int packets) | |||
2503 | int err; | 2503 | int err; |
2504 | unsigned int mss; | 2504 | unsigned int mss; |
2505 | 2505 | ||
2506 | if (packets == 0) | ||
2507 | return; | ||
2508 | |||
2509 | WARN_ON(packets > tp->packets_out); | 2506 | WARN_ON(packets > tp->packets_out); |
2510 | if (tp->lost_skb_hint) { | 2507 | if (tp->lost_skb_hint) { |
2511 | skb = tp->lost_skb_hint; | 2508 | skb = tp->lost_skb_hint; |
2512 | cnt = tp->lost_cnt_hint; | 2509 | cnt = tp->lost_cnt_hint; |
2510 | /* Head already handled? */ | ||
2511 | if (mark_head && skb != tcp_write_queue_head(sk)) | ||
2512 | return; | ||
2513 | } else { | 2513 | } else { |
2514 | skb = tcp_write_queue_head(sk); | 2514 | skb = tcp_write_queue_head(sk); |
2515 | cnt = 0; | 2515 | cnt = 0; |
@@ -2544,6 +2544,9 @@ static void tcp_mark_head_lost(struct sock *sk, int packets) | |||
2544 | } | 2544 | } |
2545 | 2545 | ||
2546 | tcp_skb_mark_lost(tp, skb); | 2546 | tcp_skb_mark_lost(tp, skb); |
2547 | |||
2548 | if (mark_head) | ||
2549 | break; | ||
2547 | } | 2550 | } |
2548 | tcp_verify_left_out(tp); | 2551 | tcp_verify_left_out(tp); |
2549 | } | 2552 | } |
@@ -2555,17 +2558,18 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit) | |||
2555 | struct tcp_sock *tp = tcp_sk(sk); | 2558 | struct tcp_sock *tp = tcp_sk(sk); |
2556 | 2559 | ||
2557 | if (tcp_is_reno(tp)) { | 2560 | if (tcp_is_reno(tp)) { |
2558 | tcp_mark_head_lost(sk, 1); | 2561 | tcp_mark_head_lost(sk, 1, 1); |
2559 | } else if (tcp_is_fack(tp)) { | 2562 | } else if (tcp_is_fack(tp)) { |
2560 | int lost = tp->fackets_out - tp->reordering; | 2563 | int lost = tp->fackets_out - tp->reordering; |
2561 | if (lost <= 0) | 2564 | if (lost <= 0) |
2562 | lost = 1; | 2565 | lost = 1; |
2563 | tcp_mark_head_lost(sk, lost); | 2566 | tcp_mark_head_lost(sk, lost, 0); |
2564 | } else { | 2567 | } else { |
2565 | int sacked_upto = tp->sacked_out - tp->reordering; | 2568 | int sacked_upto = tp->sacked_out - tp->reordering; |
2566 | if (sacked_upto < fast_rexmit) | 2569 | if (sacked_upto >= 0) |
2567 | sacked_upto = fast_rexmit; | 2570 | tcp_mark_head_lost(sk, sacked_upto, 0); |
2568 | tcp_mark_head_lost(sk, sacked_upto); | 2571 | else if (fast_rexmit) |
2572 | tcp_mark_head_lost(sk, 1, 1); | ||
2569 | } | 2573 | } |
2570 | 2574 | ||
2571 | tcp_timeout_skbs(sk); | 2575 | tcp_timeout_skbs(sk); |
@@ -2971,7 +2975,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) | |||
2971 | before(tp->snd_una, tp->high_seq) && | 2975 | before(tp->snd_una, tp->high_seq) && |
2972 | icsk->icsk_ca_state != TCP_CA_Open && | 2976 | icsk->icsk_ca_state != TCP_CA_Open && |
2973 | tp->fackets_out > tp->reordering) { | 2977 | tp->fackets_out > tp->reordering) { |
2974 | tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering); | 2978 | tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering, 0); |
2975 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSS); | 2979 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSS); |
2976 | } | 2980 | } |
2977 | 2981 | ||