diff options
author | Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> | 2007-02-22 02:08:34 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:23:11 -0400 |
commit | 7c9a4a5b67926dd186d427bc5b9fce6ccbde154c (patch) | |
tree | 8fe8dd5ab09fda204689dfc98fb03dbf99d58cf3 /net/ipv4/tcp_input.c | |
parent | 94d0ea7786714d78d7cb73144bb850254dd0bb78 (diff) |
[TCP]: Prevent unrelated cwnd adjustment while using FRTO
FRTO controls cwnd when it still processes the ACK input or it
has just reverted back to conventional RTO recovery; the normal
rules apply when FRTO has reverted to standard congestion
control.
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 | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 9dc5754141e9..723cee63791f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2522,7 +2522,7 @@ static void tcp_conservative_spur_to_response(struct tcp_sock *tp) | |||
2522 | * to prove that the RTO is indeed spurious. It transfers the control | 2522 | * to prove that the RTO is indeed spurious. It transfers the control |
2523 | * from F-RTO to the conventional RTO recovery | 2523 | * from F-RTO to the conventional RTO recovery |
2524 | */ | 2524 | */ |
2525 | static void tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | 2525 | static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) |
2526 | { | 2526 | { |
2527 | struct tcp_sock *tp = tcp_sk(sk); | 2527 | struct tcp_sock *tp = tcp_sk(sk); |
2528 | 2528 | ||
@@ -2534,7 +2534,7 @@ static void tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | |||
2534 | 2534 | ||
2535 | if (!before(tp->snd_una, tp->frto_highmark)) { | 2535 | if (!before(tp->snd_una, tp->frto_highmark)) { |
2536 | tcp_enter_frto_loss(sk, tp->frto_counter + 1); | 2536 | tcp_enter_frto_loss(sk, tp->frto_counter + 1); |
2537 | return; | 2537 | return 1; |
2538 | } | 2538 | } |
2539 | 2539 | ||
2540 | /* RFC4138 shortcoming in step 2; should also have case c): ACK isn't | 2540 | /* RFC4138 shortcoming in step 2; should also have case c): ACK isn't |
@@ -2542,20 +2542,22 @@ static void tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag) | |||
2542 | */ | 2542 | */ |
2543 | if ((tp->snd_una == prior_snd_una) && (flag&FLAG_NOT_DUP) && | 2543 | if ((tp->snd_una == prior_snd_una) && (flag&FLAG_NOT_DUP) && |
2544 | !(flag&FLAG_FORWARD_PROGRESS)) | 2544 | !(flag&FLAG_FORWARD_PROGRESS)) |
2545 | return; | 2545 | return 1; |
2546 | 2546 | ||
2547 | if (!(flag&FLAG_DATA_ACKED)) { | 2547 | if (!(flag&FLAG_DATA_ACKED)) { |
2548 | tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 0 : 3)); | 2548 | tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 0 : 3)); |
2549 | return; | 2549 | return 1; |
2550 | } | 2550 | } |
2551 | 2551 | ||
2552 | if (tp->frto_counter == 1) { | 2552 | if (tp->frto_counter == 1) { |
2553 | tp->snd_cwnd = tcp_packets_in_flight(tp) + 2; | 2553 | tp->snd_cwnd = tcp_packets_in_flight(tp) + 2; |
2554 | tp->frto_counter = 2; | 2554 | tp->frto_counter = 2; |
2555 | return 1; | ||
2555 | } else /* frto_counter == 2 */ { | 2556 | } else /* frto_counter == 2 */ { |
2556 | tcp_conservative_spur_to_response(tp); | 2557 | tcp_conservative_spur_to_response(tp); |
2557 | tp->frto_counter = 0; | 2558 | tp->frto_counter = 0; |
2558 | } | 2559 | } |
2560 | return 0; | ||
2559 | } | 2561 | } |
2560 | 2562 | ||
2561 | /* This routine deals with incoming acks, but not outgoing ones. */ | 2563 | /* This routine deals with incoming acks, but not outgoing ones. */ |
@@ -2569,6 +2571,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) | |||
2569 | u32 prior_in_flight; | 2571 | u32 prior_in_flight; |
2570 | s32 seq_rtt; | 2572 | s32 seq_rtt; |
2571 | int prior_packets; | 2573 | int prior_packets; |
2574 | int frto_cwnd = 0; | ||
2572 | 2575 | ||
2573 | /* If the ack is newer than sent or older than previous acks | 2576 | /* If the ack is newer than sent or older than previous acks |
2574 | * then we can probably ignore it. | 2577 | * then we can probably ignore it. |
@@ -2631,15 +2634,16 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) | |||
2631 | flag |= tcp_clean_rtx_queue(sk, &seq_rtt); | 2634 | flag |= tcp_clean_rtx_queue(sk, &seq_rtt); |
2632 | 2635 | ||
2633 | if (tp->frto_counter) | 2636 | if (tp->frto_counter) |
2634 | tcp_process_frto(sk, prior_snd_una, flag); | 2637 | frto_cwnd = tcp_process_frto(sk, prior_snd_una, flag); |
2635 | 2638 | ||
2636 | if (tcp_ack_is_dubious(sk, flag)) { | 2639 | if (tcp_ack_is_dubious(sk, flag)) { |
2637 | /* Advance CWND, if state allows this. */ | 2640 | /* Advance CWND, if state allows this. */ |
2638 | if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(sk, flag)) | 2641 | if ((flag & FLAG_DATA_ACKED) && !frto_cwnd && |
2642 | tcp_may_raise_cwnd(sk, flag)) | ||
2639 | tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 0); | 2643 | tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 0); |
2640 | tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag); | 2644 | tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag); |
2641 | } else { | 2645 | } else { |
2642 | if ((flag & FLAG_DATA_ACKED)) | 2646 | if ((flag & FLAG_DATA_ACKED) && !frto_cwnd) |
2643 | tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1); | 2647 | tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1); |
2644 | } | 2648 | } |
2645 | 2649 | ||