diff options
author | Ayush Ranjan <ayushranjan@google.com> | 2021-01-15 15:17:23 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-01-15 15:19:45 -0800 |
commit | f37ace6661dfed8acae7e22ed0eb9ad78bdeab34 (patch) | |
tree | 1b28f48ee5e893c07821d3e5e43547898f92d6ec | |
parent | ec9e263f213c59e93f9c8b8123012b3db2dddc9a (diff) |
[rack] Retransmit the probe segment after the probe timer expires.
This change implements TLP details enumerated in
https://tools.ietf.org/html/draft-ietf-tcpm-rack-08#section-7.5.2.
Fixes #5084
PiperOrigin-RevId: 352093473
-rw-r--r-- | pkg/tcpip/transport/tcp/rack.go | 48 |
1 files changed, 36 insertions, 12 deletions
diff --git a/pkg/tcpip/transport/tcp/rack.go b/pkg/tcpip/transport/tcp/rack.go index 5a4ee70f5..307bacca5 100644 --- a/pkg/tcpip/transport/tcp/rack.go +++ b/pkg/tcpip/transport/tcp/rack.go @@ -197,18 +197,42 @@ func (s *sender) probeTimerExpired() *tcpip.Error { if !s.rc.probeTimer.checkExpiration() { return nil } - // TODO(gvisor.dev/issue/5084): Implement this pseudo algorithm. - // If an unsent segment exists AND - // the receive window allows new data to be sent: - // Transmit the lowest-sequence unsent segment of up to SMSS - // Increment FlightSize by the size of the newly-sent segment - // Else if TLPRxtOut is not set: - // Retransmit the highest-sequence segment sent so far - // TLPRxtOut = true - // TLPHighRxt = SND.NXT - // The cwnd remains unchanged - // If FlightSize != 0: - // Arm RTO timer only. + + var dataSent bool + if s.writeNext != nil && s.writeNext.xmitCount == 0 && s.outstanding < s.sndCwnd { + dataSent = s.maybeSendSegment(s.writeNext, int(s.ep.scoreboard.SMSS()), s.sndUna.Add(s.sndWnd)) + if dataSent { + s.outstanding += s.pCount(s.writeNext, s.maxPayloadSize) + s.writeNext = s.writeNext.Next() + } + } + + if !dataSent && !s.rc.tlpRxtOut { + var highestSeqXmit *segment + for highestSeqXmit = s.writeList.Front(); highestSeqXmit != nil; highestSeqXmit = highestSeqXmit.Next() { + if highestSeqXmit.xmitCount == 0 { + // Nothing in writeList is transmitted, no need to send a probe. + highestSeqXmit = nil + break + } + if highestSeqXmit.Next() == nil || highestSeqXmit.Next().xmitCount == 0 { + // Either everything in writeList has been transmitted or the next + // sequence has not been transmitted. Either way this is the highest + // sequence segment that was transmitted. + break + } + } + + if highestSeqXmit != nil { + dataSent = s.maybeSendSegment(highestSeqXmit, int(s.ep.scoreboard.SMSS()), s.sndUna.Add(s.sndWnd)) + if dataSent { + s.rc.tlpRxtOut = true + s.rc.tlpHighRxt = s.sndNxt + } + } + } + + s.postXmit(dataSent) return nil } |