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

     1  package congestion
     2  
     3  // src from https://github.com/google/quiche/blob/e7872fc9e12bb1d46a118949c3d4da36de58aa44/quiche/quic/core/congestion_control/bbr_sender.cc
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"time"
     9  
    10  	"github.com/metacubex/quic-go/congestion"
    11  
    12  	"github.com/zhangyunhao116/fastrand"
    13  )
    14  
    15  // BbrSender implements BBR congestion control algorithm.  BBR aims to estimate
    16  // the current available Bottleneck Bandwidth and RTT (hence the name), and
    17  // regulates the pacing rate and the size of the congestion window based on
    18  // those signals.
    19  //
    20  // BBR relies on pacing in order to function properly.  Do not use BBR when
    21  // pacing is disabled.
    22  //
    23  
    24  const (
    25  	minBps = 65536 // 64 kbps
    26  
    27  	invalidPacketNumber            = -1
    28  	initialCongestionWindowPackets = 32
    29  
    30  	// Constants based on TCP defaults.
    31  	// The minimum CWND to ensure delayed acks don't reduce bandwidth measurements.
    32  	// Does not inflate the pacing rate.
    33  	defaultMinimumCongestionWindow = 4 * congestion.ByteCount(congestion.InitialPacketSizeIPv4)
    34  
    35  	// The gain used for the STARTUP, equal to 2/ln(2).
    36  	defaultHighGain = 2.885
    37  	// The newly derived gain for STARTUP, equal to 4 * ln(2)
    38  	derivedHighGain = 2.773
    39  	// The newly derived CWND gain for STARTUP, 2.
    40  	derivedHighCWNDGain = 2.0
    41  )
    42  
    43  // The cycle of gains used during the PROBE_BW stage.
    44  var pacingGain = [...]float64{1.25, 0.75, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}
    45  
    46  const (
    47  	// The length of the gain cycle.
    48  	gainCycleLength = len(pacingGain)
    49  	// The size of the bandwidth filter window, in round-trips.
    50  	bandwidthWindowSize = gainCycleLength + 2
    51  
    52  	// The time after which the current min_rtt value expires.
    53  	minRttExpiry = 10 * time.Second
    54  	// The minimum time the connection can spend in PROBE_RTT mode.
    55  	probeRttTime = 200 * time.Millisecond
    56  	// If the bandwidth does not increase by the factor of |kStartupGrowthTarget|
    57  	// within |kRoundTripsWithoutGrowthBeforeExitingStartup| rounds, the connection
    58  	// will exit the STARTUP mode.
    59  	startupGrowthTarget                         = 1.25
    60  	roundTripsWithoutGrowthBeforeExitingStartup = int64(3)
    61  
    62  	// Flag.
    63  	defaultStartupFullLossCount  = 8
    64  	quicBbr2DefaultLossThreshold = 0.02
    65  	maxBbrBurstPackets           = 3
    66  )
    67  
    68  type bbrMode int
    69  
    70  const (
    71  	// Startup phase of the connection.
    72  	bbrModeStartup = iota
    73  	// After achieving the highest possible bandwidth during the startup, lower
    74  	// the pacing rate in order to drain the queue.
    75  	bbrModeDrain
    76  	// Cruising mode.
    77  	bbrModeProbeBw
    78  	// Temporarily slow down sending in order to empty the buffer and measure
    79  	// the real minimum RTT.
    80  	bbrModeProbeRtt
    81  )
    82  
    83  // Indicates how the congestion control limits the amount of bytes in flight.
    84  type bbrRecoveryState int
    85  
    86  const (
    87  	// Do not limit.
    88  	bbrRecoveryStateNotInRecovery = iota
    89  	// Allow an extra outstanding byte for each byte acknowledged.
    90  	bbrRecoveryStateConservation
    91  	// Allow two extra outstanding bytes for each byte acknowledged (slow
    92  	// start).
    93  	bbrRecoveryStateGrowth
    94  )
    95  
    96  type bbrSender struct {
    97  	rttStats congestion.RTTStatsProvider
    98  	clock    Clock
    99  	pacer    *Pacer
   100  
   101  	mode bbrMode
   102  
   103  	// Bandwidth sampler provides BBR with the bandwidth measurements at
   104  	// individual points.
   105  	sampler *bandwidthSampler
   106  
   107  	// The number of the round trips that have occurred during the connection.
   108  	roundTripCount roundTripCount
   109  
   110  	// The packet number of the most recently sent packet.
   111  	lastSentPacket congestion.PacketNumber
   112  	// Acknowledgement of any packet after |current_round_trip_end_| will cause
   113  	// the round trip counter to advance.
   114  	currentRoundTripEnd congestion.PacketNumber
   115  
   116  	// Number of congestion events with some losses, in the current round.
   117  	numLossEventsInRound uint64
   118  
   119  	// Number of total bytes lost in the current round.
   120  	bytesLostInRound congestion.ByteCount
   121  
   122  	// The filter that tracks the maximum bandwidth over the multiple recent
   123  	// round-trips.
   124  	maxBandwidth *WindowedFilter[Bandwidth, roundTripCount]
   125  
   126  	// Minimum RTT estimate.  Automatically expires within 10 seconds (and
   127  	// triggers PROBE_RTT mode) if no new value is sampled during that period.
   128  	minRtt time.Duration
   129  	// The time at which the current value of |min_rtt_| was assigned.
   130  	minRttTimestamp time.Time
   131  
   132  	// The maximum allowed number of bytes in flight.
   133  	congestionWindow congestion.ByteCount
   134  
   135  	// The initial value of the |congestion_window_|.
   136  	initialCongestionWindow congestion.ByteCount
   137  
   138  	// The largest value the |congestion_window_| can achieve.
   139  	maxCongestionWindow congestion.ByteCount
   140  
   141  	// The smallest value the |congestion_window_| can achieve.
   142  	minCongestionWindow congestion.ByteCount
   143  
   144  	// The pacing gain applied during the STARTUP phase.
   145  	highGain float64
   146  
   147  	// The CWND gain applied during the STARTUP phase.
   148  	highCwndGain float64
   149  
   150  	// The pacing gain applied during the DRAIN phase.
   151  	drainGain float64
   152  
   153  	// The current pacing rate of the connection.
   154  	pacingRate Bandwidth
   155  
   156  	// The gain currently applied to the pacing rate.
   157  	pacingGain float64
   158  	// The gain currently applied to the congestion window.
   159  	congestionWindowGain float64
   160  
   161  	// The gain used for the congestion window during PROBE_BW.  Latched from
   162  	// quic_bbr_cwnd_gain flag.
   163  	congestionWindowGainConstant float64
   164  	// The number of RTTs to stay in STARTUP mode.  Defaults to 3.
   165  	numStartupRtts int64
   166  
   167  	// Number of round-trips in PROBE_BW mode, used for determining the current
   168  	// pacing gain cycle.
   169  	cycleCurrentOffset int
   170  	// The time at which the last pacing gain cycle was started.
   171  	lastCycleStart time.Time
   172  
   173  	// Indicates whether the connection has reached the full bandwidth mode.
   174  	isAtFullBandwidth bool
   175  	// Number of rounds during which there was no significant bandwidth increase.
   176  	roundsWithoutBandwidthGain int64
   177  	// The bandwidth compared to which the increase is measured.
   178  	bandwidthAtLastRound Bandwidth
   179  
   180  	// Set to true upon exiting quiescence.
   181  	exitingQuiescence bool
   182  
   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  
   190  	// Indicates whether the most recent bandwidth sample was marked as
   191  	// app-limited.
   192  	lastSampleIsAppLimited bool
   193  	// Indicates whether any non app-limited samples have been recorded.
   194  	hasNoAppLimitedSample bool
   195  
   196  	// Current state of recovery.
   197  	recoveryState bbrRecoveryState
   198  	// Receiving acknowledgement of a packet after |end_recovery_at_| will cause
   199  	// BBR to exit the recovery mode.  A value above zero indicates at least one
   200  	// loss has been detected, so it must not be set back to zero.
   201  	endRecoveryAt congestion.PacketNumber
   202  	// A window used to limit the number of bytes in flight during loss recovery.
   203  	recoveryWindow congestion.ByteCount
   204  	// If true, consider all samples in recovery app-limited.
   205  	isAppLimitedRecovery bool // not used
   206  
   207  	// When true, pace at 1.5x and disable packet conservation in STARTUP.
   208  	slowerStartup bool // not used
   209  	// When true, disables packet conservation in STARTUP.
   210  	rateBasedStartup bool // not used
   211  
   212  	// When true, add the most recent ack aggregation measurement during STARTUP.
   213  	enableAckAggregationDuringStartup bool
   214  	// When true, expire the windowed ack aggregation values in STARTUP when
   215  	// bandwidth increases more than 25%.
   216  	expireAckAggregationInStartup bool
   217  
   218  	// If true, will not exit low gain mode until bytes_in_flight drops below BDP
   219  	// or it's time for high gain mode.
   220  	drainToTarget bool
   221  
   222  	// If true, slow down pacing rate in STARTUP when overshooting is detected.
   223  	detectOvershooting bool
   224  	// Bytes lost while detect_overshooting_ is true.
   225  	bytesLostWhileDetectingOvershooting congestion.ByteCount
   226  	// Slow down pacing rate if
   227  	// bytes_lost_while_detecting_overshooting_ *
   228  	// bytes_lost_multiplier_while_detecting_overshooting_ > IW.
   229  	bytesLostMultiplierWhileDetectingOvershooting uint8
   230  	// When overshooting is detected, do not drop pacing_rate_ below this value /
   231  	// min_rtt.
   232  	cwndToCalculateMinPacingRate congestion.ByteCount
   233  
   234  	// Max congestion window when adjusting network parameters.
   235  	maxCongestionWindowWithNetworkParametersAdjusted congestion.ByteCount // not used
   236  
   237  	// Params.
   238  	maxDatagramSize congestion.ByteCount
   239  	// Recorded on packet sent. equivalent |unacked_packets_->bytes_in_flight()|
   240  	bytesInFlight congestion.ByteCount
   241  }
   242  
   243  var _ congestion.CongestionControl = &bbrSender{}
   244  
   245  func NewBbrSender(
   246  	clock Clock,
   247  	initialMaxDatagramSize congestion.ByteCount,
   248  	initialCongestionWindowPackets congestion.ByteCount,
   249  ) *bbrSender {
   250  	return newBbrSender(
   251  		clock,
   252  		initialMaxDatagramSize,
   253  		initialCongestionWindowPackets*initialMaxDatagramSize,
   254  		congestion.MaxCongestionWindowPackets*initialMaxDatagramSize,
   255  	)
   256  }
   257  
   258  func newBbrSender(
   259  	clock Clock,
   260  	initialMaxDatagramSize,
   261  	initialCongestionWindow,
   262  	initialMaxCongestionWindow congestion.ByteCount,
   263  ) *bbrSender {
   264  	b := &bbrSender{
   265  		clock:                        clock,
   266  		mode:                         bbrModeStartup,
   267  		sampler:                      newBandwidthSampler(roundTripCount(bandwidthWindowSize)),
   268  		lastSentPacket:               invalidPacketNumber,
   269  		currentRoundTripEnd:          invalidPacketNumber,
   270  		maxBandwidth:                 NewWindowedFilter(roundTripCount(bandwidthWindowSize), MaxFilter[Bandwidth]),
   271  		congestionWindow:             initialCongestionWindow,
   272  		initialCongestionWindow:      initialCongestionWindow,
   273  		maxCongestionWindow:          initialMaxCongestionWindow,
   274  		minCongestionWindow:          defaultMinimumCongestionWindow,
   275  		highGain:                     defaultHighGain,
   276  		highCwndGain:                 defaultHighGain,
   277  		drainGain:                    1.0 / defaultHighGain,
   278  		pacingGain:                   1.0,
   279  		congestionWindowGain:         1.0,
   280  		congestionWindowGainConstant: 2.0,
   281  		numStartupRtts:               roundTripsWithoutGrowthBeforeExitingStartup,
   282  		recoveryState:                bbrRecoveryStateNotInRecovery,
   283  		endRecoveryAt:                invalidPacketNumber,
   284  		recoveryWindow:               initialMaxCongestionWindow,
   285  		bytesLostMultiplierWhileDetectingOvershooting:    2,
   286  		cwndToCalculateMinPacingRate:                     initialCongestionWindow,
   287  		maxCongestionWindowWithNetworkParametersAdjusted: initialMaxCongestionWindow,
   288  		maxDatagramSize: initialMaxDatagramSize,
   289  	}
   290  	b.pacer = NewPacer(b.bandwidthForPacer)
   291  
   292  	/*
   293  		if b.tracer != nil {
   294  			b.lastState = logging.CongestionStateStartup
   295  			b.tracer.UpdatedCongestionState(logging.CongestionStateStartup)
   296  		}
   297  	*/
   298  
   299  	b.enterStartupMode(b.clock.Now())
   300  	b.setHighCwndGain(derivedHighCWNDGain)
   301  
   302  	return b
   303  }
   304  
   305  func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) {
   306  	b.rttStats = provider
   307  }
   308  
   309  // TimeUntilSend implements the SendAlgorithm interface.
   310  func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time {
   311  	return b.pacer.TimeUntilSend()
   312  }
   313  
   314  // HasPacingBudget implements the SendAlgorithm interface.
   315  func (b *bbrSender) HasPacingBudget(now time.Time) bool {
   316  	return b.pacer.Budget(now) >= b.maxDatagramSize
   317  }
   318  
   319  // OnPacketSent implements the SendAlgorithm interface.
   320  func (b *bbrSender) OnPacketSent(
   321  	sentTime time.Time,
   322  	bytesInFlight congestion.ByteCount,
   323  	packetNumber congestion.PacketNumber,
   324  	bytes congestion.ByteCount,
   325  	isRetransmittable bool,
   326  ) {
   327  	b.pacer.SentPacket(sentTime, bytes)
   328  
   329  	b.lastSentPacket = packetNumber
   330  	b.bytesInFlight = bytesInFlight
   331  
   332  	if bytesInFlight == 0 {
   333  		b.exitingQuiescence = true
   334  	}
   335  
   336  	b.sampler.OnPacketSent(sentTime, packetNumber, bytes, bytesInFlight, isRetransmittable)
   337  }
   338  
   339  // CanSend implements the SendAlgorithm interface.
   340  func (b *bbrSender) CanSend(bytesInFlight congestion.ByteCount) bool {
   341  	return bytesInFlight < b.GetCongestionWindow()
   342  }
   343  
   344  // MaybeExitSlowStart implements the SendAlgorithm interface.
   345  func (b *bbrSender) MaybeExitSlowStart() {
   346  	// Do nothing
   347  }
   348  
   349  // OnPacketAcked implements the SendAlgorithm interface.
   350  func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes, priorInFlight congestion.ByteCount, eventTime time.Time) {
   351  	// Do nothing.
   352  }
   353  
   354  // OnPacketLost implements the SendAlgorithm interface.
   355  func (b *bbrSender) OnPacketLost(number congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) {
   356  	// Do nothing.
   357  }
   358  
   359  // OnRetransmissionTimeout implements the SendAlgorithm interface.
   360  func (b *bbrSender) OnRetransmissionTimeout(packetsRetransmitted bool) {
   361  	// Do nothing.
   362  }
   363  
   364  // SetMaxDatagramSize implements the SendAlgorithm interface.
   365  func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) {
   366  	if s < b.maxDatagramSize {
   367  		panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", b.maxDatagramSize, s))
   368  	}
   369  	cwndIsMinCwnd := b.congestionWindow == b.minCongestionWindow
   370  	b.maxDatagramSize = s
   371  	if cwndIsMinCwnd {
   372  		b.congestionWindow = b.minCongestionWindow
   373  	}
   374  	b.pacer.SetMaxDatagramSize(s)
   375  }
   376  
   377  // InSlowStart implements the SendAlgorithmWithDebugInfos interface.
   378  func (b *bbrSender) InSlowStart() bool {
   379  	return b.mode == bbrModeStartup
   380  }
   381  
   382  // InRecovery implements the SendAlgorithmWithDebugInfos interface.
   383  func (b *bbrSender) InRecovery() bool {
   384  	return b.recoveryState != bbrRecoveryStateNotInRecovery
   385  }
   386  
   387  // GetCongestionWindow implements the SendAlgorithmWithDebugInfos interface.
   388  func (b *bbrSender) GetCongestionWindow() congestion.ByteCount {
   389  	if b.mode == bbrModeProbeRtt {
   390  		return b.probeRttCongestionWindow()
   391  	}
   392  
   393  	if b.InRecovery() {
   394  		return Min(b.congestionWindow, b.recoveryWindow)
   395  	}
   396  
   397  	return b.congestionWindow
   398  }
   399  
   400  func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) {
   401  	// Do nothing.
   402  }
   403  
   404  func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) {
   405  	totalBytesAckedBefore := b.sampler.TotalBytesAcked()
   406  	totalBytesLostBefore := b.sampler.TotalBytesLost()
   407  
   408  	var isRoundStart, minRttExpired bool
   409  	var excessAcked, bytesLost congestion.ByteCount
   410  
   411  	// The send state of the largest packet in acked_packets, unless it is
   412  	// empty. If acked_packets is empty, it's the send state of the largest
   413  	// packet in lost_packets.
   414  	var lastPacketSendState sendTimeState
   415  
   416  	b.maybeApplimited(priorInFlight)
   417  
   418  	// Update bytesInFlight
   419  	b.bytesInFlight = priorInFlight
   420  	for _, p := range ackedPackets {
   421  		b.bytesInFlight -= p.BytesAcked
   422  	}
   423  	for _, p := range lostPackets {
   424  		b.bytesInFlight -= p.BytesLost
   425  	}
   426  
   427  	if len(ackedPackets) != 0 {
   428  		lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber
   429  		isRoundStart = b.updateRoundTripCounter(lastAckedPacket)
   430  		b.updateRecoveryState(lastAckedPacket, len(lostPackets) != 0, isRoundStart)
   431  	}
   432  
   433  	sample := b.sampler.OnCongestionEvent(eventTime,
   434  		ackedPackets, lostPackets, b.maxBandwidth.GetBest(), infBandwidth, b.roundTripCount)
   435  	if sample.lastPacketSendState.isValid {
   436  		b.lastSampleIsAppLimited = sample.lastPacketSendState.isAppLimited
   437  		b.hasNoAppLimitedSample = b.hasNoAppLimitedSample || !b.lastSampleIsAppLimited
   438  	}
   439  	// Avoid updating |max_bandwidth_| if a) this is a loss-only event, or b) all
   440  	// packets in |acked_packets| did not generate valid samples. (e.g. ack of
   441  	// ack-only packets). In both cases, sampler_.total_bytes_acked() will not
   442  	// change.
   443  	if totalBytesAckedBefore != b.sampler.TotalBytesAcked() {
   444  		if !sample.sampleIsAppLimited || sample.sampleMaxBandwidth > b.maxBandwidth.GetBest() {
   445  			b.maxBandwidth.Update(sample.sampleMaxBandwidth, b.roundTripCount)
   446  		}
   447  	}
   448  
   449  	if sample.sampleRtt != infRTT {
   450  		minRttExpired = b.maybeUpdateMinRtt(eventTime, sample.sampleRtt)
   451  	}
   452  	bytesLost = b.sampler.TotalBytesLost() - totalBytesLostBefore
   453  
   454  	excessAcked = sample.extraAcked
   455  	lastPacketSendState = sample.lastPacketSendState
   456  
   457  	if len(lostPackets) != 0 {
   458  		b.numLossEventsInRound++
   459  		b.bytesLostInRound += bytesLost
   460  	}
   461  
   462  	// Handle logic specific to PROBE_BW mode.
   463  	if b.mode == bbrModeProbeBw {
   464  		b.updateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) != 0)
   465  	}
   466  
   467  	// Handle logic specific to STARTUP and DRAIN modes.
   468  	if isRoundStart && !b.isAtFullBandwidth {
   469  		b.checkIfFullBandwidthReached(&lastPacketSendState)
   470  	}
   471  
   472  	b.maybeExitStartupOrDrain(eventTime)
   473  
   474  	// Handle logic specific to PROBE_RTT.
   475  	b.maybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired)
   476  
   477  	// Calculate number of packets acked and lost.
   478  	bytesAcked := b.sampler.TotalBytesAcked() - totalBytesAckedBefore
   479  
   480  	// After the model is updated, recalculate the pacing rate and congestion
   481  	// window.
   482  	b.calculatePacingRate(bytesLost)
   483  	b.calculateCongestionWindow(bytesAcked, excessAcked)
   484  	b.calculateRecoveryWindow(bytesAcked, bytesLost)
   485  
   486  	// Cleanup internal state.
   487  	// This is where we clean up obsolete (acked or lost) packets from the bandwidth sampler.
   488  	// The "least unacked" should actually be FirstOutstanding, but since we are not passing
   489  	// that through OnCongestionEventEx, we will only do an estimate using acked/lost packets
   490  	// for now. Because of fast retransmission, they should differ by no more than 2 packets.
   491  	// (this is controlled by packetThreshold in quic-go's sentPacketHandler)
   492  	var leastUnacked congestion.PacketNumber
   493  	if len(ackedPackets) != 0 {
   494  		leastUnacked = ackedPackets[len(ackedPackets)-1].PacketNumber - 2
   495  	} else {
   496  		leastUnacked = lostPackets[len(lostPackets)-1].PacketNumber + 1
   497  	}
   498  	b.sampler.RemoveObsoletePackets(leastUnacked)
   499  
   500  	if isRoundStart {
   501  		b.numLossEventsInRound = 0
   502  		b.bytesLostInRound = 0
   503  	}
   504  }
   505  
   506  func (b *bbrSender) PacingRate() Bandwidth {
   507  	if b.pacingRate == 0 {
   508  		return Bandwidth(b.highGain * float64(
   509  			BandwidthFromDelta(b.initialCongestionWindow, b.getMinRtt())))
   510  	}
   511  
   512  	return b.pacingRate
   513  }
   514  
   515  func (b *bbrSender) hasGoodBandwidthEstimateForResumption() bool {
   516  	return b.hasNonAppLimitedSample()
   517  }
   518  
   519  func (b *bbrSender) hasNonAppLimitedSample() bool {
   520  	return b.hasNoAppLimitedSample
   521  }
   522  
   523  // Sets the pacing gain used in STARTUP.  Must be greater than 1.
   524  func (b *bbrSender) setHighGain(highGain float64) {
   525  	b.highGain = highGain
   526  	if b.mode == bbrModeStartup {
   527  		b.pacingGain = highGain
   528  	}
   529  }
   530  
   531  // Sets the CWND gain used in STARTUP.  Must be greater than 1.
   532  func (b *bbrSender) setHighCwndGain(highCwndGain float64) {
   533  	b.highCwndGain = highCwndGain
   534  	if b.mode == bbrModeStartup {
   535  		b.congestionWindowGain = highCwndGain
   536  	}
   537  }
   538  
   539  // Sets the gain used in DRAIN.  Must be less than 1.
   540  func (b *bbrSender) setDrainGain(drainGain float64) {
   541  	b.drainGain = drainGain
   542  }
   543  
   544  // What's the current estimated bandwidth in bytes per second.
   545  func (b *bbrSender) bandwidthEstimate() Bandwidth {
   546  	return b.maxBandwidth.GetBest()
   547  }
   548  
   549  func (b *bbrSender) bandwidthForPacer() congestion.ByteCount {
   550  	bps := congestion.ByteCount(float64(b.bandwidthEstimate()) * b.congestionWindowGain / float64(BytesPerSecond))
   551  	if bps < minBps {
   552  		// We need to make sure that the bandwidth value for pacer is never zero,
   553  		// otherwise it will go into an edge case where HasPacingBudget = false
   554  		// but TimeUntilSend is before, causing the quic-go send loop to go crazy and get stuck.
   555  		return minBps
   556  	}
   557  	return bps
   558  }
   559  
   560  // Returns the current estimate of the RTT of the connection.  Outside of the
   561  // edge cases, this is minimum RTT.
   562  func (b *bbrSender) getMinRtt() time.Duration {
   563  	if b.minRtt != 0 {
   564  		return b.minRtt
   565  	}
   566  	// min_rtt could be available if the handshake packet gets neutered then
   567  	// gets acknowledged. This could only happen for QUIC crypto where we do not
   568  	// drop keys.
   569  	minRtt := b.rttStats.MinRTT()
   570  	if minRtt == 0 {
   571  		return 100 * time.Millisecond
   572  	} else {
   573  		return minRtt
   574  	}
   575  }
   576  
   577  // Computes the target congestion window using the specified gain.
   578  func (b *bbrSender) getTargetCongestionWindow(gain float64) congestion.ByteCount {
   579  	bdp := bdpFromRttAndBandwidth(b.getMinRtt(), b.bandwidthEstimate())
   580  	congestionWindow := congestion.ByteCount(gain * float64(bdp))
   581  
   582  	// BDP estimate will be zero if no bandwidth samples are available yet.
   583  	if congestionWindow == 0 {
   584  		congestionWindow = congestion.ByteCount(gain * float64(b.initialCongestionWindow))
   585  	}
   586  
   587  	return Max(congestionWindow, b.minCongestionWindow)
   588  }
   589  
   590  // The target congestion window during PROBE_RTT.
   591  func (b *bbrSender) probeRttCongestionWindow() congestion.ByteCount {
   592  	return b.minCongestionWindow
   593  }
   594  
   595  func (b *bbrSender) maybeUpdateMinRtt(now time.Time, sampleMinRtt time.Duration) bool {
   596  	// Do not expire min_rtt if none was ever available.
   597  	minRttExpired := b.minRtt != 0 && now.After(b.minRttTimestamp.Add(minRttExpiry))
   598  	if minRttExpired || sampleMinRtt < b.minRtt || b.minRtt == 0 {
   599  		b.minRtt = sampleMinRtt
   600  		b.minRttTimestamp = now
   601  	}
   602  
   603  	return minRttExpired
   604  }
   605  
   606  // Enters the STARTUP mode.
   607  func (b *bbrSender) enterStartupMode(now time.Time) {
   608  	b.mode = bbrModeStartup
   609  	// b.maybeTraceStateChange(logging.CongestionStateStartup)
   610  	b.pacingGain = b.highGain
   611  	b.congestionWindowGain = b.highCwndGain
   612  }
   613  
   614  // Enters the PROBE_BW mode.
   615  func (b *bbrSender) enterProbeBandwidthMode(now time.Time) {
   616  	b.mode = bbrModeProbeBw
   617  	// b.maybeTraceStateChange(logging.CongestionStateProbeBw)
   618  	b.congestionWindowGain = b.congestionWindowGainConstant
   619  
   620  	// Pick a random offset for the gain cycle out of {0, 2..7} range. 1 is
   621  	// excluded because in that case increased gain and decreased gain would not
   622  	// follow each other.
   623  	b.cycleCurrentOffset = int(fastrand.Int31n(congestion.PacketsPerConnectionID)) % (gainCycleLength - 1)
   624  	if b.cycleCurrentOffset >= 1 {
   625  		b.cycleCurrentOffset += 1
   626  	}
   627  
   628  	b.lastCycleStart = now
   629  	b.pacingGain = pacingGain[b.cycleCurrentOffset]
   630  }
   631  
   632  // Updates the round-trip counter if a round-trip has passed.  Returns true if
   633  // the counter has been advanced.
   634  func (b *bbrSender) updateRoundTripCounter(lastAckedPacket congestion.PacketNumber) bool {
   635  	if b.currentRoundTripEnd == invalidPacketNumber || lastAckedPacket > b.currentRoundTripEnd {
   636  		b.roundTripCount++
   637  		b.currentRoundTripEnd = b.lastSentPacket
   638  		return true
   639  	}
   640  	return false
   641  }
   642  
   643  // Updates the current gain used in PROBE_BW mode.
   644  func (b *bbrSender) updateGainCyclePhase(now time.Time, priorInFlight congestion.ByteCount, hasLosses bool) {
   645  	// In most cases, the cycle is advanced after an RTT passes.
   646  	shouldAdvanceGainCycling := now.After(b.lastCycleStart.Add(b.getMinRtt()))
   647  	// If the pacing gain is above 1.0, the connection is trying to probe the
   648  	// bandwidth by increasing the number of bytes in flight to at least
   649  	// pacing_gain * BDP.  Make sure that it actually reaches the target, as long
   650  	// as there are no losses suggesting that the buffers are not able to hold
   651  	// that much.
   652  	if b.pacingGain > 1.0 && !hasLosses && priorInFlight < b.getTargetCongestionWindow(b.pacingGain) {
   653  		shouldAdvanceGainCycling = false
   654  	}
   655  
   656  	// If pacing gain is below 1.0, the connection is trying to drain the extra
   657  	// queue which could have been incurred by probing prior to it.  If the number
   658  	// of bytes in flight falls down to the estimated BDP value earlier, conclude
   659  	// that the queue has been successfully drained and exit this cycle early.
   660  	if b.pacingGain < 1.0 && b.bytesInFlight <= b.getTargetCongestionWindow(1) {
   661  		shouldAdvanceGainCycling = true
   662  	}
   663  
   664  	if shouldAdvanceGainCycling {
   665  		b.cycleCurrentOffset = (b.cycleCurrentOffset + 1) % gainCycleLength
   666  		b.lastCycleStart = now
   667  		// Stay in low gain mode until the target BDP is hit.
   668  		// Low gain mode will be exited immediately when the target BDP is achieved.
   669  		if b.drainToTarget && b.pacingGain < 1 &&
   670  			pacingGain[b.cycleCurrentOffset] == 1 &&
   671  			b.bytesInFlight > b.getTargetCongestionWindow(1) {
   672  			return
   673  		}
   674  		b.pacingGain = pacingGain[b.cycleCurrentOffset]
   675  	}
   676  }
   677  
   678  // Tracks for how many round-trips the bandwidth has not increased
   679  // significantly.
   680  func (b *bbrSender) checkIfFullBandwidthReached(lastPacketSendState *sendTimeState) {
   681  	if b.lastSampleIsAppLimited {
   682  		return
   683  	}
   684  
   685  	target := Bandwidth(float64(b.bandwidthAtLastRound) * startupGrowthTarget)
   686  	if b.bandwidthEstimate() >= target {
   687  		b.bandwidthAtLastRound = b.bandwidthEstimate()
   688  		b.roundsWithoutBandwidthGain = 0
   689  		if b.expireAckAggregationInStartup {
   690  			// Expire old excess delivery measurements now that bandwidth increased.
   691  			b.sampler.ResetMaxAckHeightTracker(0, b.roundTripCount)
   692  		}
   693  		return
   694  	}
   695  
   696  	b.roundsWithoutBandwidthGain++
   697  	if b.roundsWithoutBandwidthGain >= b.numStartupRtts ||
   698  		b.shouldExitStartupDueToLoss(lastPacketSendState) {
   699  		b.isAtFullBandwidth = true
   700  	}
   701  }
   702  
   703  func (b *bbrSender) maybeApplimited(bytesInFlight congestion.ByteCount) {
   704  	congestionWindow := b.GetCongestionWindow()
   705  	if bytesInFlight >= congestionWindow {
   706  		return
   707  	}
   708  	availableBytes := congestionWindow - bytesInFlight
   709  	drainLimited := b.mode == bbrModeDrain && bytesInFlight > congestionWindow/2
   710  	if !drainLimited || availableBytes > maxBbrBurstPackets*b.maxDatagramSize {
   711  		b.sampler.OnAppLimited()
   712  	}
   713  }
   714  
   715  // Transitions from STARTUP to DRAIN and from DRAIN to PROBE_BW if
   716  // appropriate.
   717  func (b *bbrSender) maybeExitStartupOrDrain(now time.Time) {
   718  	if b.mode == bbrModeStartup && b.isAtFullBandwidth {
   719  		b.mode = bbrModeDrain
   720  		// b.maybeTraceStateChange(logging.CongestionStateDrain)
   721  		b.pacingGain = b.drainGain
   722  		b.congestionWindowGain = b.highCwndGain
   723  	}
   724  	if b.mode == bbrModeDrain && b.bytesInFlight <= b.getTargetCongestionWindow(1) {
   725  		b.enterProbeBandwidthMode(now)
   726  	}
   727  }
   728  
   729  // Decides whether to enter or exit PROBE_RTT.
   730  func (b *bbrSender) maybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRttExpired bool) {
   731  	if minRttExpired && !b.exitingQuiescence && b.mode != bbrModeProbeRtt {
   732  		b.mode = bbrModeProbeRtt
   733  		// b.maybeTraceStateChange(logging.CongestionStateProbRtt)
   734  		b.pacingGain = 1.0
   735  		// Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight|
   736  		// is at the target small value.
   737  		b.exitProbeRttAt = time.Time{}
   738  	}
   739  
   740  	if b.mode == bbrModeProbeRtt {
   741  		b.sampler.OnAppLimited()
   742  		// b.maybeTraceStateChange(logging.CongestionStateApplicationLimited)
   743  
   744  		if b.exitProbeRttAt.IsZero() {
   745  			// If the window has reached the appropriate size, schedule exiting
   746  			// PROBE_RTT.  The CWND during PROBE_RTT is kMinimumCongestionWindow, but
   747  			// we allow an extra packet since QUIC checks CWND before sending a
   748  			// packet.
   749  			if b.bytesInFlight < b.probeRttCongestionWindow()+congestion.MaxPacketBufferSize {
   750  				b.exitProbeRttAt = now.Add(probeRttTime)
   751  				b.probeRttRoundPassed = false
   752  			}
   753  		} else {
   754  			if isRoundStart {
   755  				b.probeRttRoundPassed = true
   756  			}
   757  			if now.Sub(b.exitProbeRttAt) >= 0 && b.probeRttRoundPassed {
   758  				b.minRttTimestamp = now
   759  				if !b.isAtFullBandwidth {
   760  					b.enterStartupMode(now)
   761  				} else {
   762  					b.enterProbeBandwidthMode(now)
   763  				}
   764  			}
   765  		}
   766  	}
   767  
   768  	b.exitingQuiescence = false
   769  }
   770  
   771  // Determines whether BBR needs to enter, exit or advance state of the
   772  // recovery.
   773  func (b *bbrSender) updateRecoveryState(lastAckedPacket congestion.PacketNumber, hasLosses, isRoundStart bool) {
   774  	// Disable recovery in startup, if loss-based exit is enabled.
   775  	if !b.isAtFullBandwidth {
   776  		return
   777  	}
   778  
   779  	// Exit recovery when there are no losses for a round.
   780  	if hasLosses {
   781  		b.endRecoveryAt = b.lastSentPacket
   782  	}
   783  
   784  	switch b.recoveryState {
   785  	case bbrRecoveryStateNotInRecovery:
   786  		if hasLosses {
   787  			b.recoveryState = bbrRecoveryStateConservation
   788  			// This will cause the |recovery_window_| to be set to the correct
   789  			// value in CalculateRecoveryWindow().
   790  			b.recoveryWindow = 0
   791  			// Since the conservation phase is meant to be lasting for a whole
   792  			// round, extend the current round as if it were started right now.
   793  			b.currentRoundTripEnd = b.lastSentPacket
   794  		}
   795  	case bbrRecoveryStateConservation:
   796  		if isRoundStart {
   797  			b.recoveryState = bbrRecoveryStateGrowth
   798  		}
   799  		fallthrough
   800  	case bbrRecoveryStateGrowth:
   801  		// Exit recovery if appropriate.
   802  		if !hasLosses && lastAckedPacket > b.endRecoveryAt {
   803  			b.recoveryState = bbrRecoveryStateNotInRecovery
   804  		}
   805  	}
   806  }
   807  
   808  // Determines the appropriate pacing rate for the connection.
   809  func (b *bbrSender) calculatePacingRate(bytesLost congestion.ByteCount) {
   810  	if b.bandwidthEstimate() == 0 {
   811  		return
   812  	}
   813  
   814  	targetRate := Bandwidth(b.pacingGain * float64(b.bandwidthEstimate()))
   815  	if b.isAtFullBandwidth {
   816  		b.pacingRate = targetRate
   817  		return
   818  	}
   819  
   820  	// Pace at the rate of initial_window / RTT as soon as RTT measurements are
   821  	// available.
   822  	if b.pacingRate == 0 && b.rttStats.MinRTT() != 0 {
   823  		b.pacingRate = BandwidthFromDelta(b.initialCongestionWindow, b.rttStats.MinRTT())
   824  		return
   825  	}
   826  
   827  	if b.detectOvershooting {
   828  		b.bytesLostWhileDetectingOvershooting += bytesLost
   829  		// Check for overshooting with network parameters adjusted when pacing rate
   830  		// > target_rate and loss has been detected.
   831  		if b.pacingRate > targetRate && b.bytesLostWhileDetectingOvershooting > 0 {
   832  			if b.hasNoAppLimitedSample ||
   833  				b.bytesLostWhileDetectingOvershooting*congestion.ByteCount(b.bytesLostMultiplierWhileDetectingOvershooting) > b.initialCongestionWindow {
   834  				// We are fairly sure overshoot happens if 1) there is at least one
   835  				// non app-limited bw sample or 2) half of IW gets lost. Slow pacing
   836  				// rate.
   837  				b.pacingRate = Max(targetRate, BandwidthFromDelta(b.cwndToCalculateMinPacingRate, b.rttStats.MinRTT()))
   838  				b.bytesLostWhileDetectingOvershooting = 0
   839  				b.detectOvershooting = false
   840  			}
   841  		}
   842  	}
   843  
   844  	// Do not decrease the pacing rate during startup.
   845  	b.pacingRate = Max(b.pacingRate, targetRate)
   846  }
   847  
   848  // Determines the appropriate congestion window for the connection.
   849  func (b *bbrSender) calculateCongestionWindow(bytesAcked, excessAcked congestion.ByteCount) {
   850  	if b.mode == bbrModeProbeRtt {
   851  		return
   852  	}
   853  
   854  	targetWindow := b.getTargetCongestionWindow(b.congestionWindowGain)
   855  	if b.isAtFullBandwidth {
   856  		// Add the max recently measured ack aggregation to CWND.
   857  		targetWindow += b.sampler.MaxAckHeight()
   858  	} else if b.enableAckAggregationDuringStartup {
   859  		// Add the most recent excess acked.  Because CWND never decreases in
   860  		// STARTUP, this will automatically create a very localized max filter.
   861  		targetWindow += excessAcked
   862  	}
   863  
   864  	// Instead of immediately setting the target CWND as the new one, BBR grows
   865  	// the CWND towards |target_window| by only increasing it |bytes_acked| at a
   866  	// time.
   867  	if b.isAtFullBandwidth {
   868  		b.congestionWindow = Min(targetWindow, b.congestionWindow+bytesAcked)
   869  	} else if b.congestionWindow < targetWindow ||
   870  		b.sampler.TotalBytesAcked() < b.initialCongestionWindow {
   871  		// If the connection is not yet out of startup phase, do not decrease the
   872  		// window.
   873  		b.congestionWindow += bytesAcked
   874  	}
   875  
   876  	// Enforce the limits on the congestion window.
   877  	b.congestionWindow = Max(b.congestionWindow, b.minCongestionWindow)
   878  	b.congestionWindow = Min(b.congestionWindow, b.maxCongestionWindow)
   879  }
   880  
   881  // Determines the appropriate window that constrains the in-flight during recovery.
   882  func (b *bbrSender) calculateRecoveryWindow(bytesAcked, bytesLost congestion.ByteCount) {
   883  	if b.recoveryState == bbrRecoveryStateNotInRecovery {
   884  		return
   885  	}
   886  
   887  	// Set up the initial recovery window.
   888  	if b.recoveryWindow == 0 {
   889  		b.recoveryWindow = b.bytesInFlight + bytesAcked
   890  		b.recoveryWindow = Max(b.minCongestionWindow, b.recoveryWindow)
   891  		return
   892  	}
   893  
   894  	// Remove losses from the recovery window, while accounting for a potential
   895  	// integer underflow.
   896  	if b.recoveryWindow >= bytesLost {
   897  		b.recoveryWindow = b.recoveryWindow - bytesLost
   898  	} else {
   899  		b.recoveryWindow = b.maxDatagramSize
   900  	}
   901  
   902  	// In CONSERVATION mode, just subtracting losses is sufficient.  In GROWTH,
   903  	// release additional |bytes_acked| to achieve a slow-start-like behavior.
   904  	if b.recoveryState == bbrRecoveryStateGrowth {
   905  		b.recoveryWindow += bytesAcked
   906  	}
   907  
   908  	// Always allow sending at least |bytes_acked| in response.
   909  	b.recoveryWindow = Max(b.recoveryWindow, b.bytesInFlight+bytesAcked)
   910  	b.recoveryWindow = Max(b.minCongestionWindow, b.recoveryWindow)
   911  }
   912  
   913  // Return whether we should exit STARTUP due to excessive loss.
   914  func (b *bbrSender) shouldExitStartupDueToLoss(lastPacketSendState *sendTimeState) bool {
   915  	if b.numLossEventsInRound < defaultStartupFullLossCount || !lastPacketSendState.isValid {
   916  		return false
   917  	}
   918  
   919  	inflightAtSend := lastPacketSendState.bytesInFlight
   920  
   921  	if inflightAtSend > 0 && b.bytesLostInRound > 0 {
   922  		if b.bytesLostInRound > congestion.ByteCount(float64(inflightAtSend)*quicBbr2DefaultLossThreshold) {
   923  			return true
   924  		}
   925  		return false
   926  	}
   927  	return false
   928  }
   929  
   930  func bdpFromRttAndBandwidth(rtt time.Duration, bandwidth Bandwidth) congestion.ByteCount {
   931  	return congestion.ByteCount(rtt) * congestion.ByteCount(bandwidth) / congestion.ByteCount(BytesPerSecond) / congestion.ByteCount(time.Second)
   932  }
   933  
   934  func GetInitialPacketSize(addr net.Addr) congestion.ByteCount {
   935  	// If this is not a UDP address, we don't know anything about the MTU.
   936  	// Use the minimum size of an Initial packet as the max packet size.
   937  	if udpAddr, ok := addr.(*net.UDPAddr); ok {
   938  		if udpAddr.IP.To4() != nil {
   939  			return congestion.InitialPacketSizeIPv4
   940  		} else {
   941  			return congestion.InitialPacketSizeIPv6
   942  		}
   943  	} else {
   944  		return congestion.MinInitialPacketSize
   945  	}
   946  }