]> git.baikalelectronics.ru Git - kernel.git/commit
tcp: fix false undo corner cases
authorYuchung Cheng <ycheng@google.com>
Wed, 2 Jul 2014 19:07:16 +0000 (12:07 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 8 Jul 2014 04:40:48 +0000 (21:40 -0700)
commitfa97cf1cd1bf5b87a900fd5d7260af660c6fddb5
tree0cef9beb502c504b884cccc127e34a50974d0f07
parentc15c223e1be723d03ce59c32e1252b074ebe3309
tcp: fix false undo corner cases

The undo code assumes that, upon entering loss recovery, TCP
1) always retransmit something
2) the retransmission never fails locally (e.g., qdisc drop)

so undo_marker is set in tcp_enter_recovery() and undo_retrans is
incremented only when tcp_retransmit_skb() is successful.

When the assumption is broken because TCP's cwnd is too small to
retransmit or the retransmit fails locally. The next (DUP)ACK
would incorrectly revert the cwnd and the congestion state in
tcp_try_undo_dsack() or tcp_may_undo(). Subsequent (DUP)ACKs
may enter the recovery state. The sender repeatedly enter and
(incorrectly) exit recovery states if the retransmits continue to
fail locally while receiving (DUP)ACKs.

The fix is to initialize undo_retrans to -1 and start counting on
the first retransmission. Always increment undo_retrans even if the
retransmissions fail locally because they couldn't cause DSACKs to
undo the cwnd reduction.

Signed-off-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c