From 2deda9ea46143e9230148f7c33b9f154d1fa3343 Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Mon, 9 Sep 2024 12:33:07 -0700 Subject: [PATCH] Retransmit SYN immediately after a challenge ACK. Linux always retransmits the SYN immediately when a peer sends a challenge ACK. This makes sense since the peer by issuing a challenge ACK is letting us know of a TIME-WAIT socket on its end. Sending a RST will clear the state and retransmitting the SYN shortly thereafter will complete the connection. There is no reason to wait for a full 1s initial timeout in this case as the original SYN wasn't lost. PiperOrigin-RevId: 672635295 --- pkg/tcpip/transport/tcp/connect.go | 31 ++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/pkg/tcpip/transport/tcp/connect.go b/pkg/tcpip/transport/tcp/connect.go index 7de3fe9e4..4125af98c 100644 --- a/pkg/tcpip/transport/tcp/connect.go +++ b/pkg/tcpip/transport/tcp/connect.go @@ -30,15 +30,22 @@ import ( "gvisor.dev/gvisor/pkg/waiter" ) -// InitialRTO is the initial retransmission timeout. -// https://github.com/torvalds/linux/blob/7c636d4d20f/include/net/tcp.h#L142 -const InitialRTO = time.Second +const ( + // tcpMinTimeout is the minimum timeout for a SYN retransmit. + // This mirrors the TCP_TIMEOUT_MIN variable in Linux. + // See: https://github.com/torvalds/linux/blob/249aca0d3d631660aa3583c6a3559b75b6e971b4/include/net/tcp.h#L143 + tcpMinTimeout = 2 * time.Microsecond -// maxSegmentsPerWake is the maximum number of segments to process in the main -// protocol goroutine per wake-up. Yielding [after this number of segments are -// processed] allows other events to be processed as well (e.g., timeouts, -// resets, etc.). -const maxSegmentsPerWake = 100 + // InitialRTO is the initial retransmission timeout. + // https://github.com/torvalds/linux/blob/7c636d4d20f/include/net/tcp.h#L142 + InitialRTO = time.Second + + // maxSegmentsPerWake is the maximum number of segments to process in the main + // protocol goroutine per wake-up. Yielding [after this number of segments are + // processed] allows other events to be processed as well (e.g., timeouts, + // resets, etc.). + maxSegmentsPerWake = 100 +) type handshakeState int @@ -297,6 +304,9 @@ func (h *handshake) synSentState(s *segment) tcpip.Error { // // and send it. h.ep.sendEmptyRaw(header.TCPFlagRst, s.ackNumber, 0, 0) + // Since this was a challenge ACK reschedule the retransmit timer to fire + // soon so that the SYN is retransmitted quickly. + h.retransmitTimer.reinit(tcpMinTimeout) return nil } @@ -701,6 +711,11 @@ func (bt *backoffTimer) reset() tcpip.Error { return nil } +func (bt *backoffTimer) reinit(timeout time.Duration) { + bt.timeout = timeout + bt.t.Reset(bt.timeout) +} + func (bt *backoffTimer) stop() { bt.t.Stop() }