initialize the MTU discoverer immediately

This commit is contained in:
Marten Seemann 2023-04-17 23:42:58 +02:00
parent 727f9e5654
commit ecaef04695
4 changed files with 67 additions and 20 deletions

View file

@ -523,6 +523,14 @@ func (s *connection) preSetup() {
s.windowUpdateQueue = newWindowUpdateQueue(s.streamsMap, s.connFlowController, s.framer.QueueControlFrame)
s.datagramQueue = newDatagramQueue(s.scheduleSending, s.logger)
s.mtuDiscoverer = newMTUDiscoverer(
s.rttStats,
getMaxPacketSize(s.conn.RemoteAddr()),
func(size protocol.ByteCount) {
s.sentPacketHandler.SetMaxDatagramSize(size)
s.packer.SetMaxPacketSize(size)
},
)
s.connState.Version = s.version
}
@ -805,16 +813,7 @@ func (s *connection) handleHandshakeConfirmed() {
if maxPacketSize == 0 {
maxPacketSize = protocol.MaxByteCount
}
maxPacketSize = utils.Min(maxPacketSize, protocol.MaxPacketBufferSize)
s.mtuDiscoverer = newMTUDiscoverer(
s.rttStats,
getMaxPacketSize(s.conn.RemoteAddr()),
maxPacketSize,
func(size protocol.ByteCount) {
s.sentPacketHandler.SetMaxDatagramSize(size)
s.packer.SetMaxPacketSize(size)
},
)
s.mtuDiscoverer.Start(utils.Min(maxPacketSize, protocol.MaxPacketBufferSize))
}
}

View file

@ -36,6 +36,20 @@ func (m *MockMTUDiscoverer) EXPECT() *MockMTUDiscovererMockRecorder {
return m.recorder
}
// CurrentSize mocks base method.
func (m *MockMTUDiscoverer) CurrentSize() protocol.ByteCount {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CurrentSize")
ret0, _ := ret[0].(protocol.ByteCount)
return ret0
}
// CurrentSize indicates an expected call of CurrentSize.
func (mr *MockMTUDiscovererMockRecorder) CurrentSize() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CurrentSize", reflect.TypeOf((*MockMTUDiscoverer)(nil).CurrentSize))
}
// GetPing mocks base method.
func (m *MockMTUDiscoverer) GetPing() (ackhandler.Frame, protocol.ByteCount) {
m.ctrl.T.Helper()
@ -64,3 +78,15 @@ func (mr *MockMTUDiscovererMockRecorder) ShouldSendProbe(arg0 interface{}) *gomo
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldSendProbe", reflect.TypeOf((*MockMTUDiscoverer)(nil).ShouldSendProbe), arg0)
}
// Start mocks base method.
func (m *MockMTUDiscoverer) Start(arg0 protocol.ByteCount) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Start", arg0)
}
// Start indicates an expected call of Start.
func (mr *MockMTUDiscovererMockRecorder) Start(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockMTUDiscoverer)(nil).Start), arg0)
}

View file

@ -10,7 +10,11 @@ import (
)
type mtuDiscoverer interface {
// Start starts the MTU discovery process.
// It's unnecessary to call ShouldSendProbe before that.
Start(maxPacketSize protocol.ByteCount)
ShouldSendProbe(now time.Time) bool
CurrentSize() protocol.ByteCount
GetPing() (ping ackhandler.Frame, datagramSize protocol.ByteCount)
}
@ -34,13 +38,11 @@ type mtuFinder struct {
var _ mtuDiscoverer = &mtuFinder{}
func newMTUDiscoverer(rttStats *utils.RTTStats, start, max protocol.ByteCount, mtuIncreased func(protocol.ByteCount)) mtuDiscoverer {
func newMTUDiscoverer(rttStats *utils.RTTStats, start protocol.ByteCount, mtuIncreased func(protocol.ByteCount)) *mtuFinder {
return &mtuFinder{
current: start,
rttStats: rttStats,
lastProbeTime: time.Now(), // to make sure the first probe packet is not sent immediately
mtuIncreased: mtuIncreased,
max: max,
current: start,
rttStats: rttStats,
mtuIncreased: mtuIncreased,
}
}
@ -48,7 +50,15 @@ func (f *mtuFinder) done() bool {
return f.max-f.current <= maxMTUDiff+1
}
func (f *mtuFinder) Start(maxPacketSize protocol.ByteCount) {
f.lastProbeTime = time.Now() // makes sure the first probe packet is not sent immediately
f.max = maxPacketSize
}
func (f *mtuFinder) ShouldSendProbe(now time.Time) bool {
if f.max == 0 || f.lastProbeTime.IsZero() {
return false
}
if f.probeInFlight || f.done() {
return false
}
@ -72,3 +82,7 @@ func (f *mtuFinder) GetPing() (ackhandler.Frame, protocol.ByteCount) {
},
}, size
}
func (f *mtuFinder) CurrentSize() protocol.ByteCount {
return f.current
}

View file

@ -19,7 +19,7 @@ var _ = Describe("MTU Discoverer", func() {
)
var (
d mtuDiscoverer
d *mtuFinder
rttStats *utils.RTTStats
now time.Time
discoveredMTU protocol.ByteCount
@ -29,9 +29,9 @@ var _ = Describe("MTU Discoverer", func() {
rttStats = &utils.RTTStats{}
rttStats.SetInitialRTT(rtt)
Expect(rttStats.SmoothedRTT()).To(Equal(rtt))
d = newMTUDiscoverer(rttStats, startMTU, maxMTU, func(s protocol.ByteCount) { discoveredMTU = s })
d = newMTUDiscoverer(rttStats, startMTU, func(s protocol.ByteCount) { discoveredMTU = s })
d.Start(maxMTU)
now = time.Now()
_ = discoveredMTU
})
It("only allows a probe 5 RTTs after the handshake completes", func() {
@ -77,13 +77,21 @@ var _ = Describe("MTU Discoverer", func() {
Expect(d.ShouldSendProbe(t.Add(10 * rtt))).To(BeFalse())
})
It("doesn't do discovery before being started", func() {
d := newMTUDiscoverer(rttStats, startMTU, func(s protocol.ByteCount) {})
for i := 0; i < 5; i++ {
Expect(d.ShouldSendProbe(time.Now())).To(BeFalse())
}
})
It("finds the MTU", func() {
const rep = 3000
var maxDiff protocol.ByteCount
for i := 0; i < rep; i++ {
max := protocol.ByteCount(rand.Intn(int(3000-startMTU))) + startMTU + 1
currentMTU := startMTU
d := newMTUDiscoverer(rttStats, startMTU, max, func(s protocol.ByteCount) { currentMTU = s })
d := newMTUDiscoverer(rttStats, startMTU, func(s protocol.ByteCount) { currentMTU = s })
d.Start(max)
now := time.Now()
realMTU := protocol.ByteCount(rand.Intn(int(max-startMTU))) + startMTU
t := now.Add(mtuProbeDelay * rtt)