9d3237b590
[ Upstream commit 686dc2db2a0fdc1d34b424ec2c0a735becd8d62b ]
Fix a bug reported and analyzed by Nagaraj Arankal, where the handling
of a spurious non-SACK RTO could cause a connection to fail to clear
retrans_stamp, causing a later RTO to very prematurely time out the
connection with ETIMEDOUT.
Here is the buggy scenario, expanding upon Nagaraj Arankal's excellent
report:
(*1) Send one data packet on a non-SACK connection
(*2) Because no ACK packet is received, the packet is retransmitted
and we enter CA_Loss; but this retransmission is spurious.
(*3) The ACK for the original data is received. The transmitted packet
is acknowledged. The TCP timestamp is before the retrans_stamp,
so tcp_may_undo() returns true, and tcp_try_undo_loss() returns
true without changing state to Open (because tcp_is_sack() is
false), and tcp_process_loss() returns without calling
tcp_try_undo_recovery(). Normally after undoing a CA_Loss
episode, tcp_fastretrans_alert() would see that the connection
has returned to CA_Open and fall through and call
tcp_try_to_open(), which would set retrans_stamp to 0. However,
for non-SACK connections we hold the connection in CA_Loss, so do
not fall through to call tcp_try_to_open() and do not set
retrans_stamp to 0. So retrans_stamp is (erroneously) still
non-zero.
At this point the first "retransmission event" has passed and
been recovered from. Any future retransmission is a completely
new "event". However, retrans_stamp is erroneously still
set. (And we are still in CA_Loss, which is correct.)
(*4) After 16 minutes (to correspond with tcp_retries2=15), a new data
packet is sent. Note: No data is transmitted between (*3) and
(*4) and we disabled keep alives.
The socket's timeout SHOULD be calculated from this point in
time, but instead it's calculated from the prior "event" 16
minutes ago (step (*2)).
(*5) Because no ACK packet is received, the packet is retransmitted.
(*6) At the time of the 2nd retransmission, the socket returns
ETIMEDOUT, prematurely, because retrans_stamp is (erroneously)
too far in the past (set at the time of (*2)).
This commit fixes this bug by ensuring that we reuse in
tcp_try_undo_loss() the same careful logic for non-SACK connections
that we have in tcp_try_undo_recovery(). To avoid duplicating logic,
we factor out that logic into a new
tcp_is_non_sack_preventing_reopen() helper and call that helper from
both undo functions.
Fixes:
|
||
---|---|---|
.. | ||
bpfilter | ||
netfilter | ||
af_inet.c | ||
ah4.c | ||
arp.c | ||
cipso_ipv4.c | ||
datagram.c | ||
devinet.c | ||
esp4_offload.c | ||
esp4.c | ||
fib_frontend.c | ||
fib_lookup.h | ||
fib_notifier.c | ||
fib_rules.c | ||
fib_semantics.c | ||
fib_trie.c | ||
fou.c | ||
gre_demux.c | ||
gre_offload.c | ||
icmp.c | ||
igmp.c | ||
inet_connection_sock.c | ||
inet_diag.c | ||
inet_fragment.c | ||
inet_hashtables.c | ||
inet_timewait_sock.c | ||
inetpeer.c | ||
ip_forward.c | ||
ip_fragment.c | ||
ip_gre.c | ||
ip_input.c | ||
ip_options.c | ||
ip_output.c | ||
ip_sockglue.c | ||
ip_tunnel_core.c | ||
ip_tunnel.c | ||
ip_vti.c | ||
ipcomp.c | ||
ipconfig.c | ||
ipip.c | ||
ipmr_base.c | ||
ipmr.c | ||
Kconfig | ||
Makefile | ||
metrics.c | ||
netfilter.c | ||
netlink.c | ||
nexthop.c | ||
ping.c | ||
proc.c | ||
protocol.c | ||
raw_diag.c | ||
raw.c | ||
route.c | ||
syncookies.c | ||
sysctl_net_ipv4.c | ||
tcp_bbr.c | ||
tcp_bic.c | ||
tcp_bpf.c | ||
tcp_cdg.c | ||
tcp_cong.c | ||
tcp_cubic.c | ||
tcp_dctcp.c | ||
tcp_dctcp.h | ||
tcp_diag.c | ||
tcp_fastopen.c | ||
tcp_highspeed.c | ||
tcp_htcp.c | ||
tcp_hybla.c | ||
tcp_illinois.c | ||
tcp_input.c | ||
tcp_ipv4.c | ||
tcp_lp.c | ||
tcp_metrics.c | ||
tcp_minisocks.c | ||
tcp_nv.c | ||
tcp_offload.c | ||
tcp_output.c | ||
tcp_rate.c | ||
tcp_recovery.c | ||
tcp_scalable.c | ||
tcp_timer.c | ||
tcp_ulp.c | ||
tcp_vegas.c | ||
tcp_vegas.h | ||
tcp_veno.c | ||
tcp_westwood.c | ||
tcp_yeah.c | ||
tcp.c | ||
tunnel4.c | ||
udp_diag.c | ||
udp_impl.h | ||
udp_offload.c | ||
udp_tunnel.c | ||
udp.c | ||
udplite.c | ||
xfrm4_input.c | ||
xfrm4_output.c | ||
xfrm4_policy.c | ||
xfrm4_protocol.c | ||
xfrm4_state.c | ||
xfrm4_tunnel.c |