gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  import (
    18  	"time"
    19  )
    20  
    21  // renoState stores the variables related to TCP New Reno congestion
    22  // control algorithm.
    23  //
    24  // +stateify savable
    25  type renoState struct {
    26  	s *sender
    27  }
    28  
    29  // newRenoCC initializes the state for the NewReno congestion control algorithm.
    30  func newRenoCC(s *sender) *renoState {
    31  	return &renoState{s: s}
    32  }
    33  
    34  // updateSlowStart will update the congestion window as per the slow-start
    35  // algorithm used by NewReno. If after adjusting the congestion window
    36  // we cross the SSthreshold then it will return the number of packets that
    37  // must be consumed in congestion avoidance mode.
    38  func (r *renoState) updateSlowStart(packetsAcked int) int {
    39  	// Don't let the congestion window cross into the congestion
    40  	// avoidance range.
    41  	newcwnd := r.s.SndCwnd + packetsAcked
    42  	if newcwnd >= r.s.Ssthresh {
    43  		newcwnd = r.s.Ssthresh
    44  		r.s.SndCAAckCount = 0
    45  	}
    46  
    47  	packetsAcked -= newcwnd - r.s.SndCwnd
    48  	r.s.SndCwnd = newcwnd
    49  	return packetsAcked
    50  }
    51  
    52  // updateCongestionAvoidance will update congestion window in congestion
    53  // avoidance mode as described in RFC5681 section 3.1
    54  func (r *renoState) updateCongestionAvoidance(packetsAcked int) {
    55  	// Consume the packets in congestion avoidance mode.
    56  	r.s.SndCAAckCount += packetsAcked
    57  	if r.s.SndCAAckCount >= r.s.SndCwnd {
    58  		r.s.SndCwnd += r.s.SndCAAckCount / r.s.SndCwnd
    59  		r.s.SndCAAckCount = r.s.SndCAAckCount % r.s.SndCwnd
    60  	}
    61  }
    62  
    63  // reduceSlowStartThreshold reduces the slow-start threshold per RFC 5681,
    64  // page 6, eq. 4. It is called when we detect congestion in the network.
    65  func (r *renoState) reduceSlowStartThreshold() {
    66  	r.s.Ssthresh = r.s.Outstanding / 2
    67  	if r.s.Ssthresh < 2 {
    68  		r.s.Ssthresh = 2
    69  	}
    70  
    71  }
    72  
    73  // Update updates the congestion state based on the number of packets that
    74  // were acknowledged.
    75  // Update implements congestionControl.Update.
    76  func (r *renoState) Update(packetsAcked int, _ time.Duration) {
    77  	if r.s.SndCwnd < r.s.Ssthresh {
    78  		packetsAcked = r.updateSlowStart(packetsAcked)
    79  		if packetsAcked == 0 {
    80  			return
    81  		}
    82  	}
    83  	r.updateCongestionAvoidance(packetsAcked)
    84  }
    85  
    86  // HandleLossDetected implements congestionControl.HandleLossDetected.
    87  func (r *renoState) HandleLossDetected() {
    88  	// A retransmit was triggered due to nDupAckThreshold or when RACK
    89  	// detected loss. Reduce our slow start threshold.
    90  	r.reduceSlowStartThreshold()
    91  }
    92  
    93  // HandleRTOExpired implements congestionControl.HandleRTOExpired.
    94  func (r *renoState) HandleRTOExpired() {
    95  	// We lost a packet, so reduce ssthresh.
    96  	r.reduceSlowStartThreshold()
    97  
    98  	// Reduce the congestion window to 1, i.e., enter slow-start. Per
    99  	// RFC 5681, page 7, we must use 1 regardless of the value of the
   100  	// initial congestion window.
   101  	r.s.SndCwnd = 1
   102  }
   103  
   104  // PostRecovery implements congestionControl.PostRecovery.
   105  func (r *renoState) PostRecovery() {
   106  	// noop.
   107  }