@@ -170,6 +170,17 @@ const (
170170 // CUBIC congestion control is the default in Windows, Linux, and MacOS, and generally achieves
171171 // better throughput on large, long networks.
172172 congestionControlCubic = "cubic"
173+ // maxRetries is the maximum number of retransmissions that the TCP stack should undertake for
174+ // unacked TCP segments, that is, when we are trying to send TCP data and the other side is
175+ // unresponsive. It does not affect TCP operation while both sides are idle. The retry timeout
176+ // has a minimum of 200ms and maximum of 120s, and grows exponentially when the other side is
177+ // unresponsive. The default maxRetries in gVisor is 15, which means in practice over ten
178+ // minutes of unresponsiveness before we time out. Setting to 5 should time out in 15-30s,
179+ // depending on the latency of the connection. In Coder's system we depend on Wireguard as the
180+ // underlay, which retries handshakes on a 5s timer, so we don't want to shorten the timeout
181+ // less than 15s or so, to give us several chances to re-establish a Wireguard session after
182+ // idling.
183+ maxRetries = 5
173184)
174185
175186// Create creates and populates a new Impl.
@@ -227,6 +238,11 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
227238 if tcpipErr != nil {
228239 return nil , fmt .Errorf ("could not set congestion control: %v" , tcpipErr )
229240 }
241+ retries := tcpip .TCPMaxRetriesOption (maxRetries )
242+ tcpipErr = ipstack .SetTransportProtocolOption (tcp .ProtocolNumber , & retries )
243+ if tcpipErr != nil {
244+ return nil , fmt .Errorf ("could not set max retries: %v" , tcpipErr )
245+ }
230246
231247 linkEP := NewEndpoint (512 , tstun .DefaultMTU (), "" )
232248 if tcpipProblem := ipstack .CreateNIC (nicID , linkEP ); tcpipProblem != nil {
0 commit comments