github.com/kelleygo/clashcore@v1.0.2/transport/tuic/congestion/bbr_sender.go (about)

     1  package congestion
     2  
     3  // src from https://quiche.googlesource.com/quiche.git/+/66dea072431f94095dfc3dd2743cb94ef365f7ef/quic/core/congestion_control/bbr_sender.cc
     4  
     5  import (
     6  	"fmt"
     7  	"math"
     8  	"net"
     9  	"time"
    10  
    11  	"github.com/metacubex/quic-go/congestion"
    12  	"github.com/zhangyunhao116/fastrand"
    13  )
    14  
    15  const (
    16  	// InitialMaxDatagramSize is the default maximum packet size used in QUIC for congestion window computations in bytes.
    17  	InitialMaxDatagramSize        = 1252
    18  	InitialPacketSizeIPv4         = 1252
    19  	InitialPacketSizeIPv6         = 1232
    20  	InitialCongestionWindow       = 32
    21  	DefaultBBRMaxCongestionWindow = 10000
    22  )
    23  
    24  func GetInitialPacketSize(addr net.Addr) congestion.ByteCount {
    25  	maxSize := congestion.ByteCount(1200)
    26  	// If this is not a UDP address, we don't know anything about the MTU.
    27  	// Use the minimum size of an Initial packet as the max packet size.
    28  	if udpAddr, ok := addr.(*net.UDPAddr); ok {
    29  		if udpAddr.IP.To4() != nil {
    30  			maxSize = InitialPacketSizeIPv4
    31  		} else {
    32  			maxSize = InitialPacketSizeIPv6
    33  		}
    34  	}
    35  	return congestion.ByteCount(maxSize)
    36  }
    37  
    38  var (
    39  
    40  	// Default initial rtt used before any samples are received.
    41  	InitialRtt = 100 * time.Millisecond
    42  
    43  	// The gain used for the STARTUP, equal to  4*ln(2).
    44  	DefaultHighGain = 2.77
    45  
    46  	// The gain used in STARTUP after loss has been detected.
    47  	// 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth
    48  	// in measured bandwidth.
    49  	StartupAfterLossGain = 1.5
    50  
    51  	// The cycle of gains used during the PROBE_BW stage.
    52  	PacingGain = []float64{1.25, 0.75, 1, 1, 1, 1, 1, 1}
    53  
    54  	// The length of the gain cycle.
    55  	GainCycleLength = len(PacingGain)
    56  
    57  	// The size of the bandwidth filter window, in round-trips.
    58  	BandwidthWindowSize = GainCycleLength + 2
    59  
    60  	// The time after which the current min_rtt value expires.
    61  	MinRttExpiry = 10 * time.Second
    62  
    63  	// The minimum time the connection can spend in PROBE_RTT mode.
    64  	ProbeRttTime = time.Millisecond * 200
    65  
    66  	// If the bandwidth does not increase by the factor of |kStartupGrowthTarget|
    67  	// within |kRoundTripsWithoutGrowthBeforeExitingStartup| rounds, the connection
    68  	// will exit the STARTUP mode.
    69  	StartupGrowthTarget                         = 1.25
    70  	RoundTripsWithoutGrowthBeforeExitingStartup = int64(3)
    71  
    72  	// Coefficient of target congestion window to use when basing PROBE_RTT on BDP.
    73  	ModerateProbeRttMultiplier = 0.75
    74  
    75  	// Coefficient to determine if a new RTT is sufficiently similar to min_rtt that
    76  	// we don't need to enter PROBE_RTT.
    77  	SimilarMinRttThreshold = 1.125
    78  
    79  	// Congestion window gain for QUIC BBR during PROBE_BW phase.
    80  	DefaultCongestionWindowGainConst = 2.0
    81  )
    82  
    83  type bbrMode int
    84  
    85  const (
    86  	// Startup phase of the connection.
    87  	STARTUP = iota
    88  	// After achieving the highest possible bandwidth during the startup, lower
    89  	// the pacing rate in order to drain the queue.
    90  	DRAIN
    91  	// Cruising mode.
    92  	PROBE_BW
    93  	// Temporarily slow down sending in order to empty the buffer and measure
    94  	// the real minimum RTT.
    95  	PROBE_RTT
    96  )
    97  
    98  type bbrRecoveryState int
    99  
   100  const (
   101  	// Do not limit.
   102  	NOT_IN_RECOVERY = iota
   103  
   104  	// Allow an extra outstanding byte for each byte acknowledged.
   105  	CONSERVATION
   106  
   107  	// Allow two extra outstanding bytes for each byte acknowledged (slow
   108  	// start).
   109  	GROWTH
   110  )
   111  
   112  type bbrSender struct {
   113  	mode          bbrMode
   114  	clock         Clock
   115  	rttStats      congestion.RTTStatsProvider
   116  	bytesInFlight congestion.ByteCount
   117  	// return total bytes of unacked packets.
   118  	//GetBytesInFlight func() congestion.ByteCount
   119  	// Bandwidth sampler provides BBR with the bandwidth measurements at
   120  	// individual points.
   121  	sampler *BandwidthSampler
   122  	// The number of the round trips that have occurred during the connection.
   123  	roundTripCount int64
   124  	// The packet number of the most recently sent packet.
   125  	lastSendPacket congestion.PacketNumber
   126  	// Acknowledgement of any packet after |current_round_trip_end_| will cause
   127  	// the round trip counter to advance.
   128  	currentRoundTripEnd congestion.PacketNumber
   129  	// The filter that tracks the maximum bandwidth over the multiple recent
   130  	// round-trips.
   131  	maxBandwidth *WindowedFilter
   132  	// Tracks the maximum number of bytes acked faster than the sending rate.
   133  	maxAckHeight *WindowedFilter
   134  	// The time this aggregation started and the number of bytes acked during it.
   135  	aggregationEpochStartTime time.Time
   136  	aggregationEpochBytes     congestion.ByteCount
   137  	// Minimum RTT estimate.  Automatically expires within 10 seconds (and
   138  	// triggers PROBE_RTT mode) if no new value is sampled during that period.
   139  	minRtt time.Duration
   140  	// The time at which the current value of |min_rtt_| was assigned.
   141  	minRttTimestamp time.Time
   142  	// The maximum allowed number of bytes in flight.
   143  	congestionWindow congestion.ByteCount
   144  	// The initial value of the |congestion_window_|.
   145  	initialCongestionWindow congestion.ByteCount
   146  	// The largest value the |congestion_window_| can achieve.
   147  	initialMaxCongestionWindow congestion.ByteCount
   148  	// The smallest value the |congestion_window_| can achieve.
   149  	//minCongestionWindow congestion.ByteCount
   150  	// The pacing gain applied during the STARTUP phase.
   151  	highGain float64
   152  	// The CWND gain applied during the STARTUP phase.
   153  	highCwndGain float64
   154  	// The pacing gain applied during the DRAIN phase.
   155  	drainGain float64
   156  	// The current pacing rate of the connection.
   157  	pacingRate Bandwidth
   158  	// The gain currently applied to the pacing rate.
   159  	pacingGain float64
   160  	// The gain currently applied to the congestion window.
   161  	congestionWindowGain float64
   162  	// The gain used for the congestion window during PROBE_BW.  Latched from
   163  	// quic_bbr_cwnd_gain flag.
   164  	congestionWindowGainConst float64
   165  	// The number of RTTs to stay in STARTUP mode.  Defaults to 3.
   166  	numStartupRtts int64
   167  	// If true, exit startup if 1RTT has passed with no bandwidth increase and
   168  	// the connection is in recovery.
   169  	exitStartupOnLoss bool
   170  	// Number of round-trips in PROBE_BW mode, used for determining the current
   171  	// pacing gain cycle.
   172  	cycleCurrentOffset int
   173  	// The time at which the last pacing gain cycle was started.
   174  	lastCycleStart time.Time
   175  	// Indicates whether the connection has reached the full bandwidth mode.
   176  	isAtFullBandwidth bool
   177  	// Number of rounds during which there was no significant bandwidth increase.
   178  	roundsWithoutBandwidthGain int64
   179  	// The bandwidth compared to which the increase is measured.
   180  	bandwidthAtLastRound Bandwidth
   181  	// Set to true upon exiting quiescence.
   182  	exitingQuiescence bool
   183  	// Time at which PROBE_RTT has to be exited.  Setting it to zero indicates
   184  	// that the time is yet unknown as the number of packets in flight has not
   185  	// reached the required value.
   186  	exitProbeRttAt time.Time
   187  	// Indicates whether a round-trip has passed since PROBE_RTT became active.
   188  	probeRttRoundPassed bool
   189  	// Indicates whether the most recent bandwidth sample was marked as
   190  	// app-limited.
   191  	lastSampleIsAppLimited bool
   192  	// Indicates whether any non app-limited samples have been recorded.
   193  	hasNoAppLimitedSample bool
   194  	// Indicates app-limited calls should be ignored as long as there's
   195  	// enough data inflight to see more bandwidth when necessary.
   196  	flexibleAppLimited bool
   197  	// Current state of recovery.
   198  	recoveryState bbrRecoveryState
   199  	// Receiving acknowledgement of a packet after |end_recovery_at_| will cause
   200  	// BBR to exit the recovery mode.  A value above zero indicates at least one
   201  	// loss has been detected, so it must not be set back to zero.
   202  	endRecoveryAt congestion.PacketNumber
   203  	// A window used to limit the number of bytes in flight during loss recovery.
   204  	recoveryWindow congestion.ByteCount
   205  	// If true, consider all samples in recovery app-limited.
   206  	isAppLimitedRecovery bool
   207  	// When true, pace at 1.5x and disable packet conservation in STARTUP.
   208  	slowerStartup bool
   209  	// When true, disables packet conservation in STARTUP.
   210  	rateBasedStartup bool
   211  	// When non-zero, decreases the rate in STARTUP by the total number of bytes
   212  	// lost in STARTUP divided by CWND.
   213  	startupRateReductionMultiplier int64
   214  	// Sum of bytes lost in STARTUP.
   215  	startupBytesLost congestion.ByteCount
   216  	// When true, add the most recent ack aggregation measurement during STARTUP.
   217  	enableAckAggregationDuringStartup bool
   218  	// When true, expire the windowed ack aggregation values in STARTUP when
   219  	// bandwidth increases more than 25%.
   220  	expireAckAggregationInStartup bool
   221  	// If true, will not exit low gain mode until bytes_in_flight drops below BDP
   222  	// or it's time for high gain mode.
   223  	drainToTarget bool
   224  	// If true, use a CWND of 0.75*BDP during probe_rtt instead of 4 packets.
   225  	probeRttBasedOnBdp bool
   226  	// If true, skip probe_rtt and update the timestamp of the existing min_rtt to
   227  	// now if min_rtt over the last cycle is within 12.5% of the current min_rtt.
   228  	// Even if the min_rtt is 12.5% too low, the 25% gain cycling and 2x CWND gain
   229  	// should overcome an overly small min_rtt.
   230  	probeRttSkippedIfSimilarRtt bool
   231  	// If true, disable PROBE_RTT entirely as long as the connection was recently
   232  	// app limited.
   233  	probeRttDisabledIfAppLimited bool
   234  	appLimitedSinceLastProbeRtt  bool
   235  	minRttSinceLastProbeRtt      time.Duration
   236  	// Latched value of --quic_always_get_bw_sample_when_acked.
   237  	alwaysGetBwSampleWhenAcked bool
   238  
   239  	pacer *pacer
   240  
   241  	maxDatagramSize congestion.ByteCount
   242  }
   243  
   244  func NewBBRSender(
   245  	clock Clock,
   246  	initialMaxDatagramSize,
   247  	initialCongestionWindow,
   248  	initialMaxCongestionWindow congestion.ByteCount,
   249  ) *bbrSender {
   250  	b := &bbrSender{
   251  		mode:                      STARTUP,
   252  		clock:                     clock,
   253  		sampler:                   NewBandwidthSampler(),
   254  		maxBandwidth:              NewWindowedFilter(int64(BandwidthWindowSize), MaxFilter),
   255  		maxAckHeight:              NewWindowedFilter(int64(BandwidthWindowSize), MaxFilter),
   256  		congestionWindow:          initialCongestionWindow,
   257  		initialCongestionWindow:   initialCongestionWindow,
   258  		highGain:                  DefaultHighGain,
   259  		highCwndGain:              DefaultHighGain,
   260  		drainGain:                 1.0 / DefaultHighGain,
   261  		pacingGain:                1.0,
   262  		congestionWindowGain:      1.0,
   263  		congestionWindowGainConst: DefaultCongestionWindowGainConst,
   264  		numStartupRtts:            RoundTripsWithoutGrowthBeforeExitingStartup,
   265  		recoveryState:             NOT_IN_RECOVERY,
   266  		recoveryWindow:            initialMaxCongestionWindow,
   267  		minRttSinceLastProbeRtt:   InfiniteRTT,
   268  		maxDatagramSize:           initialMaxDatagramSize,
   269  	}
   270  	b.pacer = newPacer(b.BandwidthEstimate)
   271  	return b
   272  }
   273  
   274  func (b *bbrSender) maxCongestionWindow() congestion.ByteCount {
   275  	return b.maxDatagramSize * DefaultBBRMaxCongestionWindow
   276  }
   277  
   278  func (b *bbrSender) minCongestionWindow() congestion.ByteCount {
   279  	return b.maxDatagramSize * b.initialCongestionWindow
   280  }
   281  
   282  func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) {
   283  	b.rttStats = provider
   284  }
   285  
   286  func (b *bbrSender) GetBytesInFlight() congestion.ByteCount {
   287  	return b.bytesInFlight
   288  }
   289  
   290  // TimeUntilSend returns when the next packet should be sent.
   291  func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time {
   292  	b.bytesInFlight = bytesInFlight
   293  	return b.pacer.TimeUntilSend()
   294  }
   295  
   296  func (b *bbrSender) HasPacingBudget(now time.Time) bool {
   297  	return b.pacer.Budget(now) >= b.maxDatagramSize
   298  }
   299  
   300  func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) {
   301  	if s < b.maxDatagramSize {
   302  		panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", b.maxDatagramSize, s))
   303  	}
   304  	cwndIsMinCwnd := b.congestionWindow == b.minCongestionWindow()
   305  	b.maxDatagramSize = s
   306  	if cwndIsMinCwnd {
   307  		b.congestionWindow = b.minCongestionWindow()
   308  	}
   309  	b.pacer.SetMaxDatagramSize(s)
   310  }
   311  
   312  func (b *bbrSender) OnPacketSent(sentTime time.Time, bytesInFlight congestion.ByteCount, packetNumber congestion.PacketNumber, bytes congestion.ByteCount, isRetransmittable bool) {
   313  	b.pacer.SentPacket(sentTime, bytes)
   314  	b.lastSendPacket = packetNumber
   315  
   316  	b.bytesInFlight = bytesInFlight
   317  	if bytesInFlight == 0 && b.sampler.isAppLimited {
   318  		b.exitingQuiescence = true
   319  	}
   320  
   321  	if b.aggregationEpochStartTime.IsZero() {
   322  		b.aggregationEpochStartTime = sentTime
   323  	}
   324  
   325  	b.sampler.OnPacketSent(sentTime, packetNumber, bytes, bytesInFlight, isRetransmittable)
   326  }
   327  
   328  func (b *bbrSender) CanSend(bytesInFlight congestion.ByteCount) bool {
   329  	b.bytesInFlight = bytesInFlight
   330  	return bytesInFlight < b.GetCongestionWindow()
   331  }
   332  
   333  func (b *bbrSender) GetCongestionWindow() congestion.ByteCount {
   334  	if b.mode == PROBE_RTT {
   335  		return b.ProbeRttCongestionWindow()
   336  	}
   337  
   338  	if b.InRecovery() && !(b.rateBasedStartup && b.mode == STARTUP) {
   339  		return minByteCount(b.congestionWindow, b.recoveryWindow)
   340  	}
   341  
   342  	return b.congestionWindow
   343  }
   344  
   345  func (b *bbrSender) MaybeExitSlowStart() {
   346  
   347  }
   348  
   349  func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, eventTime time.Time) {
   350  	// Stub
   351  }
   352  
   353  func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) {
   354  	// Stub
   355  }
   356  
   357  func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) {
   358  	totalBytesAckedBefore := b.sampler.totalBytesAcked
   359  	isRoundStart, minRttExpired := false, false
   360  
   361  	if lostPackets != nil {
   362  		b.DiscardLostPackets(lostPackets)
   363  	}
   364  
   365  	// Input the new data into the BBR model of the connection.
   366  	var excessAcked congestion.ByteCount
   367  	if len(ackedPackets) > 0 {
   368  		lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber
   369  		isRoundStart = b.UpdateRoundTripCounter(lastAckedPacket)
   370  		minRttExpired = b.UpdateBandwidthAndMinRtt(eventTime, ackedPackets)
   371  		b.UpdateRecoveryState(len(lostPackets) > 0, isRoundStart)
   372  		bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore
   373  		excessAcked = b.UpdateAckAggregationBytes(eventTime, bytesAcked)
   374  	}
   375  
   376  	// Handle logic specific to PROBE_BW mode.
   377  	if b.mode == PROBE_BW {
   378  		b.UpdateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) > 0)
   379  	}
   380  
   381  	// Handle logic specific to STARTUP and DRAIN modes.
   382  	if isRoundStart && !b.isAtFullBandwidth {
   383  		b.CheckIfFullBandwidthReached()
   384  	}
   385  	b.MaybeExitStartupOrDrain(eventTime)
   386  
   387  	// Handle logic specific to PROBE_RTT.
   388  	b.MaybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired)
   389  
   390  	// Calculate number of packets acked and lost.
   391  	bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore
   392  	bytesLost := congestion.ByteCount(0)
   393  	for _, packet := range lostPackets {
   394  		bytesLost += packet.BytesLost
   395  	}
   396  
   397  	// After the model is updated, recalculate the pacing rate and congestion
   398  	// window.
   399  	b.CalculatePacingRate()
   400  	b.CalculateCongestionWindow(bytesAcked, excessAcked)
   401  	b.CalculateRecoveryWindow(bytesAcked, bytesLost)
   402  }
   403  
   404  //func (b *bbrSender) SetNumEmulatedConnections(n int) {
   405  //
   406  //}
   407  
   408  func (b *bbrSender) OnRetransmissionTimeout(packetsRetransmitted bool) {
   409  
   410  }
   411  
   412  //func (b *bbrSender) OnConnectionMigration() {
   413  //
   414  //}
   415  
   416  //// Experiments
   417  //func (b *bbrSender) SetSlowStartLargeReduction(enabled bool) {
   418  //
   419  //}
   420  
   421  //func (b *bbrSender) BandwidthEstimate() Bandwidth {
   422  //	return Bandwidth(b.maxBandwidth.GetBest())
   423  //}
   424  
   425  // BandwidthEstimate returns the current bandwidth estimate
   426  func (b *bbrSender) BandwidthEstimate() Bandwidth {
   427  	if b.rttStats == nil {
   428  		return infBandwidth
   429  	}
   430  	srtt := b.rttStats.SmoothedRTT()
   431  	if srtt == 0 {
   432  		// If we haven't measured an rtt, the bandwidth estimate is unknown.
   433  		return infBandwidth
   434  	}
   435  	return BandwidthFromDelta(b.GetCongestionWindow(), srtt)
   436  }
   437  
   438  //func (b *bbrSender) HybridSlowStart() *HybridSlowStart {
   439  //	return nil
   440  //}
   441  
   442  //func (b *bbrSender) SlowstartThreshold() congestion.ByteCount {
   443  //	return 0
   444  //}
   445  
   446  //func (b *bbrSender) RenoBeta() float32 {
   447  //	return 0.0
   448  //}
   449  
   450  func (b *bbrSender) InRecovery() bool {
   451  	return b.recoveryState != NOT_IN_RECOVERY
   452  }
   453  
   454  func (b *bbrSender) InSlowStart() bool {
   455  	return b.mode == STARTUP
   456  }
   457  
   458  //func (b *bbrSender) ShouldSendProbingPacket() bool {
   459  //	if b.pacingGain <= 1 {
   460  //		return false
   461  //	}
   462  //	// TODO(b/77975811): If the pipe is highly under-utilized, consider not
   463  //	// sending a probing transmission, because the extra bandwidth is not needed.
   464  //	// If flexible_app_limited is enabled, check if the pipe is sufficiently full.
   465  //	if b.flexibleAppLimited {
   466  //		return !b.IsPipeSufficientlyFull()
   467  //	} else {
   468  //		return true
   469  //	}
   470  //}
   471  
   472  //func (b *bbrSender) IsPipeSufficientlyFull() bool {
   473  //	// See if we need more bytes in flight to see more bandwidth.
   474  //	if b.mode == STARTUP {
   475  //		// STARTUP exits if it doesn't observe a 25% bandwidth increase, so the CWND
   476  //		// must be more than 25% above the target.
   477  //		return b.GetBytesInFlight() >= b.GetTargetCongestionWindow(1.5)
   478  //	}
   479  //	if b.pacingGain > 1 {
   480  //		// Super-unity PROBE_BW doesn't exit until 1.25 * BDP is achieved.
   481  //		return b.GetBytesInFlight() >= b.GetTargetCongestionWindow(b.pacingGain)
   482  //	}
   483  //	// If bytes_in_flight are above the target congestion window, it should be
   484  //	// possible to observe the same or more bandwidth if it's available.
   485  //	return b.GetBytesInFlight() >= b.GetTargetCongestionWindow(1.1)
   486  //}
   487  
   488  //func (b *bbrSender) SetFromConfig() {
   489  //	// TODO: not impl.
   490  //}
   491  
   492  func (b *bbrSender) UpdateRoundTripCounter(lastAckedPacket congestion.PacketNumber) bool {
   493  	if b.currentRoundTripEnd == 0 || lastAckedPacket > b.currentRoundTripEnd {
   494  		b.currentRoundTripEnd = lastAckedPacket
   495  		b.roundTripCount++
   496  		// if b.rttStats != nil && b.InSlowStart() {
   497  		// TODO: ++stats_->slowstart_num_rtts;
   498  		// }
   499  		return true
   500  	}
   501  	return false
   502  }
   503  
   504  func (b *bbrSender) UpdateBandwidthAndMinRtt(now time.Time, ackedPackets []congestion.AckedPacketInfo) bool {
   505  	sampleMinRtt := InfiniteRTT
   506  
   507  	for _, packet := range ackedPackets {
   508  		if !b.alwaysGetBwSampleWhenAcked && packet.BytesAcked == 0 {
   509  			// Skip acked packets with 0 in flight bytes when updating bandwidth.
   510  			return false
   511  		}
   512  		bandwidthSample := b.sampler.OnPacketAcked(now, packet.PacketNumber)
   513  		if b.alwaysGetBwSampleWhenAcked && !bandwidthSample.stateAtSend.isValid {
   514  			// From the sampler's perspective, the packet has never been sent, or the
   515  			// packet has been acked or marked as lost previously.
   516  			return false
   517  		}
   518  		b.lastSampleIsAppLimited = bandwidthSample.stateAtSend.isAppLimited
   519  		//     has_non_app_limited_sample_ |=
   520  		//        !bandwidth_sample.state_at_send.is_app_limited;
   521  		if !bandwidthSample.stateAtSend.isAppLimited {
   522  			b.hasNoAppLimitedSample = true
   523  		}
   524  		if bandwidthSample.rtt > 0 {
   525  			sampleMinRtt = minRtt(sampleMinRtt, bandwidthSample.rtt)
   526  		}
   527  		if !bandwidthSample.stateAtSend.isAppLimited || bandwidthSample.bandwidth > b.BandwidthEstimate() {
   528  			b.maxBandwidth.Update(int64(bandwidthSample.bandwidth), b.roundTripCount)
   529  		}
   530  	}
   531  
   532  	// If none of the RTT samples are valid, return immediately.
   533  	if sampleMinRtt == InfiniteRTT {
   534  		return false
   535  	}
   536  
   537  	b.minRttSinceLastProbeRtt = minRtt(b.minRttSinceLastProbeRtt, sampleMinRtt)
   538  	// Do not expire min_rtt if none was ever available.
   539  	minRttExpired := b.minRtt > 0 && (now.After(b.minRttTimestamp.Add(MinRttExpiry)))
   540  	if minRttExpired || sampleMinRtt < b.minRtt || b.minRtt == 0 {
   541  		if minRttExpired && b.ShouldExtendMinRttExpiry() {
   542  			minRttExpired = false
   543  		} else {
   544  			b.minRtt = sampleMinRtt
   545  		}
   546  		b.minRttTimestamp = now
   547  		// Reset since_last_probe_rtt fields.
   548  		b.minRttSinceLastProbeRtt = InfiniteRTT
   549  		b.appLimitedSinceLastProbeRtt = false
   550  	}
   551  
   552  	return minRttExpired
   553  }
   554  
   555  func (b *bbrSender) ShouldExtendMinRttExpiry() bool {
   556  	if b.probeRttDisabledIfAppLimited && b.appLimitedSinceLastProbeRtt {
   557  		// Extend the current min_rtt if we've been app limited recently.
   558  		return true
   559  	}
   560  
   561  	minRttIncreasedSinceLastProbe := b.minRttSinceLastProbeRtt > time.Duration(float64(b.minRtt)*SimilarMinRttThreshold)
   562  	if b.probeRttSkippedIfSimilarRtt && b.appLimitedSinceLastProbeRtt && !minRttIncreasedSinceLastProbe {
   563  		// Extend the current min_rtt if we've been app limited recently and an rtt
   564  		// has been measured in that time that's less than 12.5% more than the
   565  		// current min_rtt.
   566  		return true
   567  	}
   568  
   569  	return false
   570  }
   571  
   572  func (b *bbrSender) DiscardLostPackets(lostPackets []congestion.LostPacketInfo) {
   573  	for _, packet := range lostPackets {
   574  		b.sampler.OnCongestionEvent(packet.PacketNumber)
   575  		if b.mode == STARTUP {
   576  			// if b.rttStats != nil {
   577  			// TODO: slow start.
   578  			// }
   579  			if b.startupRateReductionMultiplier != 0 {
   580  				b.startupBytesLost += packet.BytesLost
   581  			}
   582  		}
   583  	}
   584  }
   585  
   586  func (b *bbrSender) UpdateRecoveryState(hasLosses, isRoundStart bool) {
   587  	// Exit recovery when there are no losses for a round.
   588  	if !hasLosses {
   589  		b.endRecoveryAt = b.lastSendPacket
   590  	}
   591  	switch b.recoveryState {
   592  	case NOT_IN_RECOVERY:
   593  		// Enter conservation on the first loss.
   594  		if hasLosses {
   595  			b.recoveryState = CONSERVATION
   596  			// This will cause the |recovery_window_| to be set to the correct
   597  			// value in CalculateRecoveryWindow().
   598  			b.recoveryWindow = 0
   599  			// Since the conservation phase is meant to be lasting for a whole
   600  			// round, extend the current round as if it were started right now.
   601  			b.currentRoundTripEnd = b.lastSendPacket
   602  			if false && b.lastSampleIsAppLimited {
   603  				b.isAppLimitedRecovery = true
   604  			}
   605  		}
   606  	case CONSERVATION:
   607  		if isRoundStart {
   608  			b.recoveryState = GROWTH
   609  		}
   610  		fallthrough
   611  	case GROWTH:
   612  		// Exit recovery if appropriate.
   613  		if !hasLosses && b.lastSendPacket > b.endRecoveryAt {
   614  			b.recoveryState = NOT_IN_RECOVERY
   615  			b.isAppLimitedRecovery = false
   616  		}
   617  	}
   618  
   619  	if b.recoveryState != NOT_IN_RECOVERY && b.isAppLimitedRecovery {
   620  		b.sampler.OnAppLimited()
   621  	}
   622  }
   623  
   624  func (b *bbrSender) UpdateAckAggregationBytes(ackTime time.Time, ackedBytes congestion.ByteCount) congestion.ByteCount {
   625  	// Compute how many bytes are expected to be delivered, assuming max bandwidth
   626  	// is correct.
   627  	expectedAckedBytes := congestion.ByteCount(b.maxBandwidth.GetBest()) *
   628  		congestion.ByteCount((ackTime.Sub(b.aggregationEpochStartTime)))
   629  	// Reset the current aggregation epoch as soon as the ack arrival rate is less
   630  	// than or equal to the max bandwidth.
   631  	if b.aggregationEpochBytes <= expectedAckedBytes {
   632  		// Reset to start measuring a new aggregation epoch.
   633  		b.aggregationEpochBytes = ackedBytes
   634  		b.aggregationEpochStartTime = ackTime
   635  		return 0
   636  	}
   637  	// Compute how many extra bytes were delivered vs max bandwidth.
   638  	// Include the bytes most recently acknowledged to account for stretch acks.
   639  	b.aggregationEpochBytes += ackedBytes
   640  	b.maxAckHeight.Update(int64(b.aggregationEpochBytes-expectedAckedBytes), b.roundTripCount)
   641  	return b.aggregationEpochBytes - expectedAckedBytes
   642  }
   643  
   644  func (b *bbrSender) UpdateGainCyclePhase(now time.Time, priorInFlight congestion.ByteCount, hasLosses bool) {
   645  	bytesInFlight := b.GetBytesInFlight()
   646  	// In most cases, the cycle is advanced after an RTT passes.
   647  	shouldAdvanceGainCycling := now.Sub(b.lastCycleStart) > b.GetMinRtt()
   648  
   649  	// If the pacing gain is above 1.0, the connection is trying to probe the
   650  	// bandwidth by increasing the number of bytes in flight to at least
   651  	// pacing_gain * BDP.  Make sure that it actually reaches the target, as long
   652  	// as there are no losses suggesting that the buffers are not able to hold
   653  	// that much.
   654  	if b.pacingGain > 1.0 && !hasLosses && priorInFlight < b.GetTargetCongestionWindow(b.pacingGain) {
   655  		shouldAdvanceGainCycling = false
   656  	}
   657  	// If pacing gain is below 1.0, the connection is trying to drain the extra
   658  	// queue which could have been incurred by probing prior to it.  If the number
   659  	// of bytes in flight falls down to the estimated BDP value earlier, conclude
   660  	// that the queue has been successfully drained and exit this cycle early.
   661  	if b.pacingGain < 1.0 && bytesInFlight <= b.GetTargetCongestionWindow(1.0) {
   662  		shouldAdvanceGainCycling = true
   663  	}
   664  
   665  	if shouldAdvanceGainCycling {
   666  		b.cycleCurrentOffset = (b.cycleCurrentOffset + 1) % GainCycleLength
   667  		b.lastCycleStart = now
   668  		// Stay in low gain mode until the target BDP is hit.
   669  		// Low gain mode will be exited immediately when the target BDP is achieved.
   670  		if b.drainToTarget && b.pacingGain < 1.0 && PacingGain[b.cycleCurrentOffset] == 1.0 &&
   671  			bytesInFlight > b.GetTargetCongestionWindow(1.0) {
   672  			return
   673  		}
   674  		b.pacingGain = PacingGain[b.cycleCurrentOffset]
   675  	}
   676  }
   677  
   678  func (b *bbrSender) GetTargetCongestionWindow(gain float64) congestion.ByteCount {
   679  	bdp := congestion.ByteCount(b.GetMinRtt()) * congestion.ByteCount(b.BandwidthEstimate())
   680  	congestionWindow := congestion.ByteCount(gain * float64(bdp))
   681  
   682  	// BDP estimate will be zero if no bandwidth samples are available yet.
   683  	if congestionWindow == 0 {
   684  		congestionWindow = congestion.ByteCount(gain * float64(b.initialCongestionWindow))
   685  	}
   686  
   687  	return maxByteCount(congestionWindow, b.minCongestionWindow())
   688  }
   689  
   690  func (b *bbrSender) CheckIfFullBandwidthReached() {
   691  	if b.lastSampleIsAppLimited {
   692  		return
   693  	}
   694  
   695  	target := Bandwidth(float64(b.bandwidthAtLastRound) * StartupGrowthTarget)
   696  	if b.BandwidthEstimate() >= target {
   697  		b.bandwidthAtLastRound = b.BandwidthEstimate()
   698  		b.roundsWithoutBandwidthGain = 0
   699  		if b.expireAckAggregationInStartup {
   700  			// Expire old excess delivery measurements now that bandwidth increased.
   701  			b.maxAckHeight.Reset(0, b.roundTripCount)
   702  		}
   703  		return
   704  	}
   705  	b.roundsWithoutBandwidthGain++
   706  	if b.roundsWithoutBandwidthGain >= b.numStartupRtts || (b.exitStartupOnLoss && b.InRecovery()) {
   707  		b.isAtFullBandwidth = true
   708  	}
   709  }
   710  
   711  func (b *bbrSender) MaybeExitStartupOrDrain(now time.Time) {
   712  	if b.mode == STARTUP && b.isAtFullBandwidth {
   713  		b.OnExitStartup(now)
   714  		b.mode = DRAIN
   715  		b.pacingGain = b.drainGain
   716  		b.congestionWindowGain = b.highCwndGain
   717  	}
   718  	if b.mode == DRAIN && b.GetBytesInFlight() <= b.GetTargetCongestionWindow(1) {
   719  		b.EnterProbeBandwidthMode(now)
   720  	}
   721  }
   722  
   723  func (b *bbrSender) EnterProbeBandwidthMode(now time.Time) {
   724  	b.mode = PROBE_BW
   725  	b.congestionWindowGain = b.congestionWindowGainConst
   726  
   727  	// Pick a random offset for the gain cycle out of {0, 2..7} range. 1 is
   728  	// excluded because in that case increased gain and decreased gain would not
   729  	// follow each other.
   730  	b.cycleCurrentOffset = fastrand.Int() % (GainCycleLength - 1)
   731  	if b.cycleCurrentOffset >= 1 {
   732  		b.cycleCurrentOffset += 1
   733  	}
   734  
   735  	b.lastCycleStart = now
   736  	b.pacingGain = PacingGain[b.cycleCurrentOffset]
   737  }
   738  
   739  func (b *bbrSender) MaybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRttExpired bool) {
   740  	if minRttExpired && !b.exitingQuiescence && b.mode != PROBE_RTT {
   741  		if b.InSlowStart() {
   742  			b.OnExitStartup(now)
   743  		}
   744  		b.mode = PROBE_RTT
   745  		b.pacingGain = 1.0
   746  		// Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight|
   747  		// is at the target small value.
   748  		b.exitProbeRttAt = time.Time{}
   749  	}
   750  
   751  	if b.mode == PROBE_RTT {
   752  		b.sampler.OnAppLimited()
   753  		if b.exitProbeRttAt.IsZero() {
   754  			// If the window has reached the appropriate size, schedule exiting
   755  			// PROBE_RTT.  The CWND during PROBE_RTT is kMinimumCongestionWindow, but
   756  			// we allow an extra packet since QUIC checks CWND before sending a
   757  			// packet.
   758  			if b.GetBytesInFlight() < b.ProbeRttCongestionWindow()+b.maxDatagramSize {
   759  				b.exitProbeRttAt = now.Add(ProbeRttTime)
   760  				b.probeRttRoundPassed = false
   761  			}
   762  		} else {
   763  			if isRoundStart {
   764  				b.probeRttRoundPassed = true
   765  			}
   766  			if !now.Before(b.exitProbeRttAt) && b.probeRttRoundPassed {
   767  				b.minRttTimestamp = now
   768  				if !b.isAtFullBandwidth {
   769  					b.EnterStartupMode(now)
   770  				} else {
   771  					b.EnterProbeBandwidthMode(now)
   772  				}
   773  			}
   774  		}
   775  	}
   776  	b.exitingQuiescence = false
   777  }
   778  
   779  func (b *bbrSender) ProbeRttCongestionWindow() congestion.ByteCount {
   780  	if b.probeRttBasedOnBdp {
   781  		return b.GetTargetCongestionWindow(ModerateProbeRttMultiplier)
   782  	} else {
   783  		return b.minCongestionWindow()
   784  	}
   785  }
   786  
   787  func (b *bbrSender) EnterStartupMode(now time.Time) {
   788  	// if b.rttStats != nil {
   789  	// TODO: slow start.
   790  	// }
   791  	b.mode = STARTUP
   792  	b.pacingGain = b.highGain
   793  	b.congestionWindowGain = b.highCwndGain
   794  }
   795  
   796  func (b *bbrSender) OnExitStartup(now time.Time) {
   797  	if b.rttStats == nil {
   798  		return
   799  	}
   800  	// TODO: slow start.
   801  }
   802  
   803  func (b *bbrSender) CalculatePacingRate() {
   804  	if b.BandwidthEstimate() == 0 {
   805  		return
   806  	}
   807  
   808  	targetRate := Bandwidth(b.pacingGain * float64(b.BandwidthEstimate()))
   809  	if b.isAtFullBandwidth {
   810  		b.pacingRate = targetRate
   811  		return
   812  	}
   813  
   814  	// Pace at the rate of initial_window / RTT as soon as RTT measurements are
   815  	// available.
   816  	if b.pacingRate == 0 && b.rttStats.MinRTT() > 0 {
   817  		b.pacingRate = BandwidthFromDelta(b.initialCongestionWindow, b.rttStats.MinRTT())
   818  		return
   819  	}
   820  	// Slow the pacing rate in STARTUP once loss has ever been detected.
   821  	hasEverDetectedLoss := b.endRecoveryAt > 0
   822  	if b.slowerStartup && hasEverDetectedLoss && b.hasNoAppLimitedSample {
   823  		b.pacingRate = Bandwidth(StartupAfterLossGain * float64(b.BandwidthEstimate()))
   824  		return
   825  	}
   826  
   827  	// Slow the pacing rate in STARTUP by the bytes_lost / CWND.
   828  	if b.startupRateReductionMultiplier != 0 && hasEverDetectedLoss && b.hasNoAppLimitedSample {
   829  		b.pacingRate = Bandwidth((1.0 - (float64(b.startupBytesLost) * float64(b.startupRateReductionMultiplier) / float64(b.congestionWindow))) * float64(targetRate))
   830  		// Ensure the pacing rate doesn't drop below the startup growth target times
   831  		// the bandwidth estimate.
   832  		b.pacingRate = maxBandwidth(b.pacingRate, Bandwidth(StartupGrowthTarget*float64(b.BandwidthEstimate())))
   833  		return
   834  	}
   835  
   836  	// Do not decrease the pacing rate during startup.
   837  	b.pacingRate = maxBandwidth(b.pacingRate, targetRate)
   838  }
   839  
   840  func (b *bbrSender) CalculateCongestionWindow(ackedBytes, excessAcked congestion.ByteCount) {
   841  	if b.mode == PROBE_RTT {
   842  		return
   843  	}
   844  
   845  	targetWindow := b.GetTargetCongestionWindow(b.congestionWindowGain)
   846  	if b.isAtFullBandwidth {
   847  		// Add the max recently measured ack aggregation to CWND.
   848  		targetWindow += congestion.ByteCount(b.maxAckHeight.GetBest())
   849  	} else if b.enableAckAggregationDuringStartup {
   850  		// Add the most recent excess acked.  Because CWND never decreases in
   851  		// STARTUP, this will automatically create a very localized max filter.
   852  		targetWindow += excessAcked
   853  	}
   854  
   855  	// Instead of immediately setting the target CWND as the new one, BBR grows
   856  	// the CWND towards |target_window| by only increasing it |bytes_acked| at a
   857  	// time.
   858  	addBytesAcked := true || !b.InRecovery()
   859  	if b.isAtFullBandwidth {
   860  		b.congestionWindow = minByteCount(targetWindow, b.congestionWindow+ackedBytes)
   861  	} else if addBytesAcked && (b.congestionWindow < targetWindow || b.sampler.totalBytesAcked < b.initialCongestionWindow) {
   862  		// If the connection is not yet out of startup phase, do not decrease the
   863  		// window.
   864  		b.congestionWindow += ackedBytes
   865  	}
   866  
   867  	// Enforce the limits on the congestion window.
   868  	b.congestionWindow = maxByteCount(b.congestionWindow, b.minCongestionWindow())
   869  	b.congestionWindow = minByteCount(b.congestionWindow, b.maxCongestionWindow())
   870  }
   871  
   872  func (b *bbrSender) CalculateRecoveryWindow(ackedBytes, lostBytes congestion.ByteCount) {
   873  	if b.rateBasedStartup && b.mode == STARTUP {
   874  		return
   875  	}
   876  
   877  	if b.recoveryState == NOT_IN_RECOVERY {
   878  		return
   879  	}
   880  
   881  	// Set up the initial recovery window.
   882  	if b.recoveryWindow == 0 {
   883  		b.recoveryWindow = maxByteCount(b.GetBytesInFlight()+ackedBytes, b.minCongestionWindow())
   884  		return
   885  	}
   886  
   887  	// Remove losses from the recovery window, while accounting for a potential
   888  	// integer underflow.
   889  	if b.recoveryWindow >= lostBytes {
   890  		b.recoveryWindow -= lostBytes
   891  	} else {
   892  		b.recoveryWindow = congestion.ByteCount(b.maxDatagramSize)
   893  	}
   894  	// In CONSERVATION mode, just subtracting losses is sufficient.  In GROWTH,
   895  	// release additional |bytes_acked| to achieve a slow-start-like behavior.
   896  	if b.recoveryState == GROWTH {
   897  		b.recoveryWindow += ackedBytes
   898  	}
   899  	// Sanity checks.  Ensure that we always allow to send at least an MSS or
   900  	// |bytes_acked| in response, whichever is larger.
   901  	b.recoveryWindow = maxByteCount(b.recoveryWindow, b.GetBytesInFlight()+ackedBytes)
   902  	b.recoveryWindow = maxByteCount(b.recoveryWindow, b.minCongestionWindow())
   903  }
   904  
   905  var _ congestion.CongestionControl = (*bbrSender)(nil)
   906  
   907  func (b *bbrSender) GetMinRtt() time.Duration {
   908  	if b.minRtt > 0 {
   909  		return b.minRtt
   910  	} else {
   911  		return InitialRtt
   912  	}
   913  }
   914  
   915  func minRtt(a, b time.Duration) time.Duration {
   916  	if a < b {
   917  		return a
   918  	} else {
   919  		return b
   920  	}
   921  }
   922  
   923  func minBandwidth(a, b Bandwidth) Bandwidth {
   924  	if a < b {
   925  		return a
   926  	} else {
   927  		return b
   928  	}
   929  }
   930  
   931  func maxBandwidth(a, b Bandwidth) Bandwidth {
   932  	if a > b {
   933  		return a
   934  	} else {
   935  		return b
   936  	}
   937  }
   938  
   939  func maxByteCount(a, b congestion.ByteCount) congestion.ByteCount {
   940  	if a > b {
   941  		return a
   942  	} else {
   943  		return b
   944  	}
   945  }
   946  
   947  func minByteCount(a, b congestion.ByteCount) congestion.ByteCount {
   948  	if a < b {
   949  		return a
   950  	} else {
   951  		return b
   952  	}
   953  }
   954  
   955  var (
   956  	InfiniteRTT = time.Duration(math.MaxInt64)
   957  )