github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/transport/tcp/reno.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tcp 16 17 // renoState stores the variables related to TCP New Reno congestion 18 // control algorithm. 19 // 20 // +stateify savable 21 type renoState struct { 22 s *sender 23 } 24 25 // newRenoCC initializes the state for the NewReno congestion control algorithm. 26 func newRenoCC(s *sender) *renoState { 27 return &renoState{s: s} 28 } 29 30 // updateSlowStart will update the congestion window as per the slow-start 31 // algorithm used by NewReno. If after adjusting the congestion window 32 // we cross the SSthreshold then it will return the number of packets that 33 // must be consumed in congestion avoidance mode. 34 func (r *renoState) updateSlowStart(packetsAcked int) int { 35 // Don't let the congestion window cross into the congestion 36 // avoidance range. 37 newcwnd := r.s.SndCwnd + packetsAcked 38 if newcwnd >= r.s.Ssthresh { 39 newcwnd = r.s.Ssthresh 40 r.s.SndCAAckCount = 0 41 } 42 43 packetsAcked -= newcwnd - r.s.SndCwnd 44 r.s.SndCwnd = newcwnd 45 return packetsAcked 46 } 47 48 // updateCongestionAvoidance will update congestion window in congestion 49 // avoidance mode as described in RFC5681 section 3.1 50 func (r *renoState) updateCongestionAvoidance(packetsAcked int) { 51 // Consume the packets in congestion avoidance mode. 52 r.s.SndCAAckCount += packetsAcked 53 if r.s.SndCAAckCount >= r.s.SndCwnd { 54 r.s.SndCwnd += r.s.SndCAAckCount / r.s.SndCwnd 55 r.s.SndCAAckCount = r.s.SndCAAckCount % r.s.SndCwnd 56 } 57 } 58 59 // reduceSlowStartThreshold reduces the slow-start threshold per RFC 5681, 60 // page 6, eq. 4. It is called when we detect congestion in the network. 61 func (r *renoState) reduceSlowStartThreshold() { 62 r.s.Ssthresh = r.s.Outstanding / 2 63 if r.s.Ssthresh < 2 { 64 r.s.Ssthresh = 2 65 } 66 67 } 68 69 // Update updates the congestion state based on the number of packets that 70 // were acknowledged. 71 // Update implements congestionControl.Update. 72 func (r *renoState) Update(packetsAcked int) { 73 if r.s.SndCwnd < r.s.Ssthresh { 74 packetsAcked = r.updateSlowStart(packetsAcked) 75 if packetsAcked == 0 { 76 return 77 } 78 } 79 r.updateCongestionAvoidance(packetsAcked) 80 } 81 82 // HandleLossDetected implements congestionControl.HandleLossDetected. 83 func (r *renoState) HandleLossDetected() { 84 // A retransmit was triggered due to nDupAckThreshold or when RACK 85 // detected loss. Reduce our slow start threshold. 86 r.reduceSlowStartThreshold() 87 } 88 89 // HandleRTOExpired implements congestionControl.HandleRTOExpired. 90 func (r *renoState) HandleRTOExpired() { 91 // We lost a packet, so reduce ssthresh. 92 r.reduceSlowStartThreshold() 93 94 // Reduce the congestion window to 1, i.e., enter slow-start. Per 95 // RFC 5681, page 7, we must use 1 regardless of the value of the 96 // initial congestion window. 97 r.s.SndCwnd = 1 98 } 99 100 // PostRecovery implements congestionControl.PostRecovery. 101 func (r *renoState) PostRecovery() { 102 // noop. 103 }