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
This commit is contained in:
gVisor bot
2024-09-09 12:37:29 -07:00
parent 7cf7cffd4f
commit 2deda9ea46
+23 -8
View File
@@ -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 {
// <SEQ=SEG.ACK><CTL=RST>
// 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()
}