fix: BBR scale window for datagram size

https://github.com/apernet/hysteria/commit/61c75a260f935a6c5adf2f3ce0441f117c65fcbb
This commit is contained in:
wwqgtxx
2026-04-14 11:17:27 +08:00
parent 4ee2251c37
commit f0ad835df1
+41 -46
View File
@@ -27,16 +27,13 @@ const (
invalidPacketNumber = -1
initialCongestionWindowPackets = 32
minCongestionWindowPackets = 4
// Constants based on TCP defaults.
// The minimum CWND to ensure delayed acks don't reduce bandwidth measurements.
// Does not inflate the pacing rate.
defaultMinimumCongestionWindow = 4 * congestion.ByteCount(congestion.InitialPacketSize)
// The gain used for the STARTUP, equal to 2/ln(2).
defaultHighGain = 2.885
// The newly derived gain for STARTUP, equal to 4 * ln(2)
derivedHighGain = 2.773
// The newly derived CWND gain for STARTUP, 2.
derivedHighCWNDGain = 2.0
)
@@ -63,7 +60,6 @@ const (
// Flag.
defaultStartupFullLossCount = 8
quicBbr2DefaultLossThreshold = 0.02
maxBbrBurstPackets = 10
)
type bbrMode int
@@ -267,7 +263,7 @@ func newBbrSender(
congestionWindow: initialCongestionWindow,
initialCongestionWindow: initialCongestionWindow,
maxCongestionWindow: initialMaxCongestionWindow,
minCongestionWindow: defaultMinimumCongestionWindow,
minCongestionWindow: minCongestionWindowForMaxDatagramSize(initialMaxDatagramSize),
highGain: defaultHighGain,
highCwndGain: defaultHighGain,
drainGain: 1.0 / defaultHighGain,
@@ -285,19 +281,37 @@ func newBbrSender(
}
b.pacer = NewPacer(b.bandwidthForPacer)
/*
if b.tracer != nil {
b.lastState = logging.CongestionStateStartup
b.tracer.UpdatedCongestionState(logging.CongestionStateStartup)
}
*/
b.enterStartupMode()
b.setHighCwndGain(derivedHighCWNDGain)
return b
}
func minCongestionWindowForMaxDatagramSize(maxDatagramSize congestion.ByteCount) congestion.ByteCount {
return minCongestionWindowPackets * maxDatagramSize
}
func scaleByteWindowForDatagramSize(window, oldMaxDatagramSize, newMaxDatagramSize congestion.ByteCount) congestion.ByteCount {
if oldMaxDatagramSize == newMaxDatagramSize {
return window
}
return congestion.ByteCount(uint64(window) * uint64(newMaxDatagramSize) / uint64(oldMaxDatagramSize))
}
func (b *bbrSender) rescalePacketSizedWindows(maxDatagramSize congestion.ByteCount) {
oldMaxDatagramSize := b.maxDatagramSize
b.maxDatagramSize = maxDatagramSize
b.initialCongestionWindow = scaleByteWindowForDatagramSize(b.initialCongestionWindow, oldMaxDatagramSize, maxDatagramSize)
b.maxCongestionWindow = scaleByteWindowForDatagramSize(b.maxCongestionWindow, oldMaxDatagramSize, maxDatagramSize)
b.minCongestionWindow = minCongestionWindowForMaxDatagramSize(maxDatagramSize)
b.cwndToCalculateMinPacingRate = scaleByteWindowForDatagramSize(b.cwndToCalculateMinPacingRate, oldMaxDatagramSize, maxDatagramSize)
b.maxCongestionWindowWithNetworkParametersAdjusted = scaleByteWindowForDatagramSize(
b.maxCongestionWindowWithNetworkParametersAdjusted,
oldMaxDatagramSize,
maxDatagramSize,
)
}
func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) {
b.rttStats = provider
}
@@ -330,8 +344,6 @@ func (b *bbrSender) OnPacketSent(
}
b.sampler.OnPacketSent(sentTime, packetNumber, bytes, bytesInFlight, isRetransmittable)
b.maybeAppLimited(bytesInFlight)
}
// CanSend implements the SendAlgorithm interface.
@@ -364,11 +376,18 @@ func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) {
if s < b.maxDatagramSize {
panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", b.maxDatagramSize, s))
}
cwndIsMinCwnd := b.congestionWindow == b.minCongestionWindow
b.maxDatagramSize = s
if cwndIsMinCwnd {
oldMinCongestionWindow := b.minCongestionWindow
oldInitialCongestionWindow := b.initialCongestionWindow
b.rescalePacketSizedWindows(s)
switch b.congestionWindow {
case oldMinCongestionWindow:
b.congestionWindow = b.minCongestionWindow
case oldInitialCongestionWindow:
b.congestionWindow = b.initialCongestionWindow
default:
b.congestionWindow = Min(b.maxCongestionWindow, Max(b.congestionWindow, b.minCongestionWindow))
}
b.recoveryWindow = Min(b.maxCongestionWindow, Max(b.recoveryWindow, b.minCongestionWindow))
b.pacer.SetMaxDatagramSize(s)
}
@@ -411,6 +430,8 @@ func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, even
// packet in lost_packets.
var lastPacketSendState sendTimeState
b.maybeAppLimited(priorInFlight)
// Update bytesInFlight
b.bytesInFlight = priorInFlight
for _, p := range ackedPackets {
@@ -508,22 +529,6 @@ func (b *bbrSender) PacingRate() Bandwidth {
return b.pacingRate
}
func (b *bbrSender) hasGoodBandwidthEstimateForResumption() bool {
return b.hasNonAppLimitedSample()
}
func (b *bbrSender) hasNonAppLimitedSample() bool {
return b.hasNoAppLimitedSample
}
// Sets the pacing gain used in STARTUP. Must be greater than 1.
func (b *bbrSender) setHighGain(highGain float64) {
b.highGain = highGain
if b.mode == bbrModeStartup {
b.pacingGain = highGain
}
}
// Sets the CWND gain used in STARTUP. Must be greater than 1.
func (b *bbrSender) setHighCwndGain(highCwndGain float64) {
b.highCwndGain = highCwndGain
@@ -532,11 +537,6 @@ func (b *bbrSender) setHighCwndGain(highCwndGain float64) {
}
}
// Sets the gain used in DRAIN. Must be less than 1.
func (b *bbrSender) setDrainGain(drainGain float64) {
b.drainGain = drainGain
}
// Get the current bandwidth estimate. Note that Bandwidth is in bits per second.
func (b *bbrSender) bandwidthEstimate() Bandwidth {
return b.maxBandwidth.GetBest()
@@ -697,12 +697,7 @@ func (b *bbrSender) checkIfFullBandwidthReached(lastPacketSendState *sendTimeSta
}
func (b *bbrSender) maybeAppLimited(bytesInFlight congestion.ByteCount) {
congestionWindow := b.GetCongestionWindow()
if bytesInFlight >= congestionWindow {
return
}
availableBytes := congestionWindow - bytesInFlight
if availableBytes > maxBbrBurstPackets*b.maxDatagramSize {
if bytesInFlight < b.getTargetCongestionWindow(1) {
b.sampler.OnAppLimited()
}
}
@@ -729,7 +724,7 @@ func (b *bbrSender) maybeEnterOrExitProbeRtt(now monotime.Time, isRoundStart, mi
b.pacingGain = 1.0
// Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight|
// is at the target small value.
b.exitProbeRttAt = monotime.Time(0)
b.exitProbeRttAt = 0
}
if b.mode == bbrModeProbeRtt {