summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/transport/tcp/snd.go
diff options
context:
space:
mode:
authorgVisor bot <gvisor-bot@google.com>2021-02-12 01:27:06 +0000
committergVisor bot <gvisor-bot@google.com>2021-02-12 01:27:06 +0000
commita5c96a9f604a00d72bc5ee01a8dc651276f463c5 (patch)
tree06e38568372f5ad50cbd88bb59283474ef37675c /pkg/tcpip/transport/tcp/snd.go
parent660aa59a851a15efc127fb55135eeb2bd63a4981 (diff)
parent91cf7b3ca48b9388c9058962ffe798c37e951990 (diff)
Merge release-20210201.0-91-g91cf7b3ca (automated)
Diffstat (limited to 'pkg/tcpip/transport/tcp/snd.go')
-rw-r--r--pkg/tcpip/transport/tcp/snd.go18
1 files changed, 15 insertions, 3 deletions
diff --git a/pkg/tcpip/transport/tcp/snd.go b/pkg/tcpip/transport/tcp/snd.go
index 37f064aaf..7911e6b85 100644
--- a/pkg/tcpip/transport/tcp/snd.go
+++ b/pkg/tcpip/transport/tcp/snd.go
@@ -1131,6 +1131,14 @@ func (s *sender) SetPipe() {
s.outstanding = pipe
}
+// shouldEnterRecovery returns true if the sender should enter fast recovery
+// based on dupAck count and sack scoreboard.
+// See RFC 6675 section 5.
+func (s *sender) shouldEnterRecovery() bool {
+ return s.dupAckCount >= nDupAckThreshold ||
+ (s.ep.sackPermitted && s.ep.tcpRecovery&tcpip.TCPRACKLossDetection == 0 && s.ep.scoreboard.IsLost(s.sndUna))
+}
+
// detectLoss is called when an ack is received and returns whether a loss is
// detected. It manages the state related to duplicate acks and determines if
// a retransmit is needed according to the rules in RFC 6582 (NewReno).
@@ -1155,7 +1163,7 @@ func (s *sender) detectLoss(seg *segment) (fastRetransmit bool) {
// Do not enter fast recovery until we reach nDupAckThreshold or the
// first unacknowledged byte is considered lost as per SACK scoreboard.
- if s.dupAckCount < nDupAckThreshold || (s.ep.sackPermitted && !s.ep.scoreboard.IsLost(s.sndUna)) {
+ if !s.shouldEnterRecovery() {
// RFC 6675 Step 3.
s.fr.highRxt = s.sndUna - 1
// Do run SetPipe() to calculate the outstanding segments.
@@ -1169,7 +1177,11 @@ func (s *sender) detectLoss(seg *segment) (fastRetransmit bool) {
// We only do the check here, the incrementing of last to the highest
// sequence number transmitted till now is done when enterRecovery
// is invoked.
- if !s.fr.last.LessThan(seg.ackNumber) {
+ //
+ // Note that we only enter recovery when at least one more byte of data
+ // beyond s.fr.last (the highest byte that was outstanding when fast
+ // retransmit was last entered) is acked.
+ if !s.fr.last.LessThan(seg.ackNumber - 1) {
s.dupAckCount = 0
return false
}
@@ -1351,7 +1363,7 @@ func (s *sender) handleRcvdSegment(rcvdSeg *segment) {
if s.fr.active {
// Leave fast recovery if it acknowledges all the data covered by
// this fast recovery session.
- if ack.InRange(s.sndUna, s.sndNxt+1) && s.fr.last.LessThan(ack) {
+ if (ack-1).InRange(s.sndUna, s.sndNxt) && s.fr.last.LessThan(ack) {
s.leaveRecovery()
}
} else {