diff options
author | gVisor bot <gvisor-bot@google.com> | 2020-11-13 22:02:57 +0000 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-11-13 22:02:57 +0000 |
commit | b21b9a28dc155efe04e9aa8e72dfc052f6579e7f (patch) | |
tree | 14ea1708aae4854c7f8c15c8ad04f9fa02813bd8 | |
parent | 4e9636928b2b9e596c9430c13d586afad9058fd2 (diff) | |
parent | 839dd97008bacf526c05afa542e67c94f8b399ea (diff) |
Merge release-20201030.0-92-g839dd9700 (automated)
-rw-r--r-- | pkg/tcpip/stack/stack.go | 1 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/endpoint.go | 1 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/rack.go | 11 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/snd.go | 64 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/tcp_state_autogen.go | 10 |
5 files changed, 71 insertions, 16 deletions
diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index ca9f41af4..e0025e0a9 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -82,6 +82,7 @@ type TCPRACKState struct { FACK seqnum.Value RTT time.Duration Reord bool + DSACKSeen bool } // TCPEndpointID is the unique 4 tuple that identifies a given endpoint. diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 194d3a8a4..e78138415 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -3051,6 +3051,7 @@ func (e *endpoint) completeState() stack.TCPEndpointState { FACK: rc.fack, RTT: rc.rtt, Reord: rc.reorderSeen, + DSACKSeen: rc.dsackSeen, } return s } diff --git a/pkg/tcpip/transport/tcp/rack.go b/pkg/tcpip/transport/tcp/rack.go index d312b1b8b..e0a50a919 100644 --- a/pkg/tcpip/transport/tcp/rack.go +++ b/pkg/tcpip/transport/tcp/rack.go @@ -29,12 +29,12 @@ import ( // // +stateify savable type rackControl struct { + // dsackSeen indicates if the connection has seen a DSACK. + dsackSeen bool + // endSequence is the ending TCP sequence number of rackControl.seg. endSequence seqnum.Value - // dsack indicates if the connection has seen a DSACK. - dsack bool - // fack is the highest selectively or cumulatively acknowledged // sequence. fack seqnum.Value @@ -122,3 +122,8 @@ func (rc *rackControl) detectReorder(seg *segment) { rc.reorderSeen = true } } + +// setDSACKSeen updates rack control if duplicate SACK is seen by the connection. +func (rc *rackControl) setDSACKSeen() { + rc.dsackSeen = true +} diff --git a/pkg/tcpip/transport/tcp/snd.go b/pkg/tcpip/transport/tcp/snd.go index c42d7159a..201cf9aa9 100644 --- a/pkg/tcpip/transport/tcp/snd.go +++ b/pkg/tcpip/transport/tcp/snd.go @@ -1182,25 +1182,29 @@ func (s *sender) detectLoss(seg *segment) (fastRetransmit bool) { // See: https://tools.ietf.org/html/draft-ietf-tcpm-rack-08#section-7.2 // steps 2 and 3. func (s *sender) walkSACK(rcvdSeg *segment) { - if len(rcvdSeg.parsedOptions.SACKBlocks) == 0 { + // Look for DSACK block. + idx := 0 + n := len(rcvdSeg.parsedOptions.SACKBlocks) + if s.checkDSACK(rcvdSeg) { + s.rc.setDSACKSeen() + idx = 1 + n-- + } + + if n == 0 { return } // Sort the SACK blocks. The first block is the most recent unacked // block. The following blocks can be in arbitrary order. - sackBlocks := make([]header.SACKBlock, len(rcvdSeg.parsedOptions.SACKBlocks)) - copy(sackBlocks, rcvdSeg.parsedOptions.SACKBlocks) + sackBlocks := make([]header.SACKBlock, n) + copy(sackBlocks, rcvdSeg.parsedOptions.SACKBlocks[idx:]) sort.Slice(sackBlocks, func(i, j int) bool { return sackBlocks[j].Start.LessThan(sackBlocks[i].Start) }) seg := s.writeList.Front() for _, sb := range sackBlocks { - // This check excludes DSACK blocks. - if sb.Start.LessThanEq(rcvdSeg.ackNumber) || sb.Start.LessThanEq(s.sndUna) || s.sndNxt.LessThan(sb.End) { - continue - } - for seg != nil && seg.sequenceNumber.LessThan(sb.End) && seg.xmitCount != 0 { if sb.Start.LessThanEq(seg.sequenceNumber) && !seg.acked { s.rc.update(seg, rcvdSeg, s.ep.tsOffset) @@ -1212,6 +1216,50 @@ func (s *sender) walkSACK(rcvdSeg *segment) { } } +// checkDSACK checks if a DSACK is reported and updates it in RACK. +func (s *sender) checkDSACK(rcvdSeg *segment) bool { + n := len(rcvdSeg.parsedOptions.SACKBlocks) + if n == 0 { + return false + } + + sb := rcvdSeg.parsedOptions.SACKBlocks[0] + // Check if SACK block is invalid. + if sb.End.LessThan(sb.Start) { + return false + } + + // See: https://tools.ietf.org/html/rfc2883#section-5 DSACK is sent in + // at most one SACK block. DSACK is detected in the below two cases: + // * If the SACK sequence space is less than this cumulative ACK, it is + // an indication that the segment identified by the SACK block has + // been received more than once by the receiver. + // * If the sequence space in the first SACK block is greater than the + // cumulative ACK, then the sender next compares the sequence space + // in the first SACK block with the sequence space in the second SACK + // block, if there is one. This comparison can determine if the first + // SACK block is reporting duplicate data that lies above the + // cumulative ACK. + if sb.Start.LessThan(rcvdSeg.ackNumber) { + return true + } + + if n > 1 { + sb1 := rcvdSeg.parsedOptions.SACKBlocks[1] + if sb1.End.LessThan(sb1.Start) { + return false + } + + // If the first SACK block is fully covered by second SACK + // block, then the first block is a DSACK block. + if sb.End.LessThanEq(sb1.End) && sb1.Start.LessThanEq(sb.Start) { + return true + } + } + + return false +} + // handleRcvdSegment is called when a segment is received; it is responsible for // updating the send-related state. func (s *sender) handleRcvdSegment(rcvdSeg *segment) { diff --git a/pkg/tcpip/transport/tcp/tcp_state_autogen.go b/pkg/tcpip/transport/tcp/tcp_state_autogen.go index 89b07f5e8..d97d86241 100644 --- a/pkg/tcpip/transport/tcp/tcp_state_autogen.go +++ b/pkg/tcpip/transport/tcp/tcp_state_autogen.go @@ -408,8 +408,8 @@ func (rc *rackControl) StateTypeName() string { func (rc *rackControl) StateFields() []string { return []string{ + "dsackSeen", "endSequence", - "dsack", "fack", "minRTT", "rtt", @@ -424,8 +424,8 @@ func (rc *rackControl) StateSave(stateSinkObject state.Sink) { rc.beforeSave() var xmitTimeValue unixTime = rc.saveXmitTime() stateSinkObject.SaveValue(6, xmitTimeValue) - stateSinkObject.Save(0, &rc.endSequence) - stateSinkObject.Save(1, &rc.dsack) + stateSinkObject.Save(0, &rc.dsackSeen) + stateSinkObject.Save(1, &rc.endSequence) stateSinkObject.Save(2, &rc.fack) stateSinkObject.Save(3, &rc.minRTT) stateSinkObject.Save(4, &rc.rtt) @@ -435,8 +435,8 @@ func (rc *rackControl) StateSave(stateSinkObject state.Sink) { func (rc *rackControl) afterLoad() {} func (rc *rackControl) StateLoad(stateSourceObject state.Source) { - stateSourceObject.Load(0, &rc.endSequence) - stateSourceObject.Load(1, &rc.dsack) + stateSourceObject.Load(0, &rc.dsackSeen) + stateSourceObject.Load(1, &rc.endSequence) stateSourceObject.Load(2, &rc.fack) stateSourceObject.Load(3, &rc.minRTT) stateSourceObject.Load(4, &rc.rtt) |