RACK: Fix re-transmitting the segment twice when entering recovery.

TestRACKWithDuplicateACK is flaky as the reorder window can expire before
receiving three duplicate ACKs which will result in sending the first
unacknowledged segment twice: when reorder timer expired and again after
receiving the third duplicate ACK.

This CL will fix this behavior and will not resend the segment again if it was
already re-transmittted when reorder timer expired.

Update the TestRACKWithDuplicateACK to test that the first segment is
considered as lost and is re-transmitted.

PiperOrigin-RevId: 356855168
This commit is contained in:
Nayana Bidari
2021-02-10 16:38:55 -08:00
committed by gVisor bot
parent 97a36d1696
commit ff04d019e3
2 changed files with 8 additions and 5 deletions
+3 -2
View File
@@ -1041,6 +1041,7 @@ func (s *sender) enterRecovery() {
// the 3 duplicate ACKs and are now not in flight.
s.sndCwnd = s.sndSsthresh + 3
s.sackedOut = 0
s.dupAckCount = 0
s.fr.first = s.sndUna
s.fr.last = s.sndNxt - 1
s.fr.maxCwnd = s.sndCwnd + s.outstanding
@@ -1174,7 +1175,6 @@ func (s *sender) detectLoss(seg *segment) (fastRetransmit bool) {
}
s.cc.HandleLossDetected()
s.enterRecovery()
s.dupAckCount = 0
return true
}
@@ -1521,10 +1521,11 @@ func (s *sender) handleRcvdSegment(rcvdSeg *segment) {
// the lost segments.
s.cc.HandleLossDetected()
s.enterRecovery()
fastRetransmit = true
}
if s.fr.active {
s.rc.DoRecovery(nil, true)
s.rc.DoRecovery(nil, fastRetransmit)
}
}
+5 -3
View File
@@ -617,17 +617,19 @@ func TestRACKWithDuplicateACK(t *testing.T) {
const numPackets = 4
data := sendAndReceive(t, c, numPackets)
// Send three duplicate ACKs to trigger fast recovery.
// Send three duplicate ACKs to trigger fast recovery. The first
// segment is considered as lost and will be retransmitted after
// receiving the duplicate ACKs.
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
start := c.IRS.Add(1 + seqnum.Size(maxPayload))
end := start.Add(seqnum.Size(maxPayload))
for i := 0; i < 3; i++ {
c.SendAckWithSACK(seq, maxPayload, []header.SACKBlock{{start, end}})
c.SendAckWithSACK(seq, 0, []header.SACKBlock{{start, end}})
end = end.Add(seqnum.Size(maxPayload))
}
// Receive the retransmitted packet.
c.ReceiveAndCheckPacketWithOptions(data, maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 0, maxPayload, tsOptionSize)
metricPollFn := func() error {
tcpStats := c.Stack().Stats().TCP