Files
quic-go/mtu_discoverer_test.go
Marten Seemann 2557fb98b2 initialize the MTU discoverer when processing the transport parameters (#4514)
On the client side, we always use the configured packet size. This comes
with the risk of failing the handshake if the path doesn't support this
MTU. If the server sends a max_udp_payload_size that's smaller than this
size, we can safely ignore this: Obviously, the server still processed
the (fully padded) Initial packet, despite claiming that it wouldn't do
so.

On the server side, there's no downside to using 1200 bytes until we
received the client's transport parameters:
* If the first packet didn't contain the entire ClientHello, all we can
do is ACK that packet. We don't need a lot of bytes for that.
* If it did, we will have processed the transport parameters and
initialized the MTU discoverer.
2024-05-13 22:50:26 -07:00

120 lines
3.4 KiB
Go

package quic
import (
"math/rand"
"time"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("MTU Discoverer", func() {
const (
rtt = 100 * time.Millisecond
startMTU protocol.ByteCount = 1000
maxMTU protocol.ByteCount = 2000
)
var (
d *mtuFinder
rttStats *utils.RTTStats
now time.Time
discoveredMTU protocol.ByteCount
)
BeforeEach(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.Start()
now = time.Now()
})
It("only allows a probe 5 RTTs after the handshake completes", func() {
Expect(d.ShouldSendProbe(now)).To(BeFalse())
Expect(d.ShouldSendProbe(now.Add(rtt * 9 / 2))).To(BeFalse())
Expect(d.ShouldSendProbe(now.Add(rtt * 5))).To(BeTrue())
})
It("doesn't allow a probe if another probe is still in flight", func() {
ping, _ := d.GetPing()
Expect(d.ShouldSendProbe(now.Add(10 * rtt))).To(BeFalse())
ping.Handler.OnLost(ping.Frame)
Expect(d.ShouldSendProbe(now.Add(10 * rtt))).To(BeTrue())
})
It("tries a lower size when a probe is lost", func() {
ping, size := d.GetPing()
Expect(size).To(Equal(protocol.ByteCount(1500)))
ping.Handler.OnLost(ping.Frame)
_, size = d.GetPing()
Expect(size).To(Equal(protocol.ByteCount(1250)))
})
It("tries a higher size and calls the callback when a probe is acknowledged", func() {
ping, size := d.GetPing()
Expect(size).To(Equal(protocol.ByteCount(1500)))
ping.Handler.OnAcked(ping.Frame)
Expect(discoveredMTU).To(Equal(protocol.ByteCount(1500)))
_, size = d.GetPing()
Expect(size).To(Equal(protocol.ByteCount(1750)))
})
It("stops discovery after getting close enough to the MTU", func() {
var sizes []protocol.ByteCount
t := now.Add(5 * rtt)
for d.ShouldSendProbe(t) {
ping, size := d.GetPing()
ping.Handler.OnAcked(ping.Frame)
sizes = append(sizes, size)
t = t.Add(5 * rtt)
}
Expect(sizes).To(Equal([]protocol.ByteCount{1500, 1750, 1875, 1937, 1968, 1984}))
Expect(d.ShouldSendProbe(t.Add(10 * rtt))).To(BeFalse())
})
It("doesn't do discovery before being started", func() {
d := newMTUDiscoverer(rttStats, startMTU, protocol.MaxByteCount, 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++ {
maxMTU := protocol.ByteCount(rand.Intn(int(3000-startMTU))) + startMTU + 1
currentMTU := startMTU
d := newMTUDiscoverer(rttStats, startMTU, maxMTU, func(s protocol.ByteCount) { currentMTU = s })
d.Start()
now := time.Now()
realMTU := protocol.ByteCount(rand.Intn(int(maxMTU-startMTU))) + startMTU
t := now.Add(mtuProbeDelay * rtt)
var count int
for d.ShouldSendProbe(t) {
if count > 25 {
Fail("too many iterations")
}
count++
ping, size := d.GetPing()
if size <= realMTU {
ping.Handler.OnAcked(ping.Frame)
} else {
ping.Handler.OnLost(ping.Frame)
}
t = t.Add(mtuProbeDelay * rtt)
}
diff := realMTU - currentMTU
Expect(diff).To(BeNumerically(">=", 0))
maxDiff = max(maxDiff, diff)
}
Expect(maxDiff).To(BeEquivalentTo(maxMTUDiff))
})
})