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.windowUpdateQueue = newWindowUpdateQueue(s.streamsMap, s.connFlowController, s.framer.QueueControlFrame)
s.datagramQueue = newDatagramQueue(s.scheduleSending, s.logger) 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 s.connState.Version = s.version
} }
@ -805,16 +813,7 @@ func (s *connection) handleHandshakeConfirmed() {
if maxPacketSize == 0 { if maxPacketSize == 0 {
maxPacketSize = protocol.MaxByteCount maxPacketSize = protocol.MaxByteCount
} }
maxPacketSize = utils.Min(maxPacketSize, protocol.MaxPacketBufferSize) s.mtuDiscoverer.Start(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)
},
)
} }
} }

View file

@ -36,6 +36,20 @@ func (m *MockMTUDiscoverer) EXPECT() *MockMTUDiscovererMockRecorder {
return m.recorder 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. // GetPing mocks base method.
func (m *MockMTUDiscoverer) GetPing() (ackhandler.Frame, protocol.ByteCount) { func (m *MockMTUDiscoverer) GetPing() (ackhandler.Frame, protocol.ByteCount) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@ -64,3 +78,15 @@ func (mr *MockMTUDiscovererMockRecorder) ShouldSendProbe(arg0 interface{}) *gomo
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldSendProbe", reflect.TypeOf((*MockMTUDiscoverer)(nil).ShouldSendProbe), arg0) 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 { 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 ShouldSendProbe(now time.Time) bool
CurrentSize() protocol.ByteCount
GetPing() (ping ackhandler.Frame, datagramSize protocol.ByteCount) GetPing() (ping ackhandler.Frame, datagramSize protocol.ByteCount)
} }
@ -34,13 +38,11 @@ type mtuFinder struct {
var _ mtuDiscoverer = &mtuFinder{} 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{ return &mtuFinder{
current: start, current: start,
rttStats: rttStats, rttStats: rttStats,
lastProbeTime: time.Now(), // to make sure the first probe packet is not sent immediately
mtuIncreased: mtuIncreased, mtuIncreased: mtuIncreased,
max: max,
} }
} }
@ -48,7 +50,15 @@ func (f *mtuFinder) done() bool {
return f.max-f.current <= maxMTUDiff+1 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 { func (f *mtuFinder) ShouldSendProbe(now time.Time) bool {
if f.max == 0 || f.lastProbeTime.IsZero() {
return false
}
if f.probeInFlight || f.done() { if f.probeInFlight || f.done() {
return false return false
} }
@ -72,3 +82,7 @@ func (f *mtuFinder) GetPing() (ackhandler.Frame, protocol.ByteCount) {
}, },
}, size }, size
} }
func (f *mtuFinder) CurrentSize() protocol.ByteCount {
return f.current
}

View file

@ -19,7 +19,7 @@ var _ = Describe("MTU Discoverer", func() {
) )
var ( var (
d mtuDiscoverer d *mtuFinder
rttStats *utils.RTTStats rttStats *utils.RTTStats
now time.Time now time.Time
discoveredMTU protocol.ByteCount discoveredMTU protocol.ByteCount
@ -29,9 +29,9 @@ var _ = Describe("MTU Discoverer", func() {
rttStats = &utils.RTTStats{} rttStats = &utils.RTTStats{}
rttStats.SetInitialRTT(rtt) rttStats.SetInitialRTT(rtt)
Expect(rttStats.SmoothedRTT()).To(Equal(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() now = time.Now()
_ = discoveredMTU
}) })
It("only allows a probe 5 RTTs after the handshake completes", func() { 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()) 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() { It("finds the MTU", func() {
const rep = 3000 const rep = 3000
var maxDiff protocol.ByteCount var maxDiff protocol.ByteCount
for i := 0; i < rep; i++ { for i := 0; i < rep; i++ {
max := protocol.ByteCount(rand.Intn(int(3000-startMTU))) + startMTU + 1 max := protocol.ByteCount(rand.Intn(int(3000-startMTU))) + startMTU + 1
currentMTU := startMTU 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() now := time.Now()
realMTU := protocol.ByteCount(rand.Intn(int(max-startMTU))) + startMTU realMTU := protocol.ByteCount(rand.Intn(int(max-startMTU))) + startMTU
t := now.Add(mtuProbeDelay * rtt) t := now.Add(mtuProbeDelay * rtt)