/
mtu_discoverer_test.go
143 lines (129 loc) · 3.82 KB
/
mtu_discoverer_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package quic
import (
"math/rand"
"time"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/logging"
. "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 },
nil,
)
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) {}, nil)
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
var tracedMTU protocol.ByteCount
var tracerDone bool
d := newMTUDiscoverer(
rttStats,
startMTU,
maxMTU,
func(s protocol.ByteCount) { currentMTU = s },
&logging.ConnectionTracer{
UpdatedMTU: func(mtu logging.ByteCount, done bool) {
tracedMTU = mtu
tracerDone = done
},
},
)
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)
if maxMTU > currentMTU+maxMTU {
Expect(tracedMTU).To(Equal(currentMTU))
Expect(tracerDone).To(BeTrue())
}
}
Expect(maxDiff).To(BeEquivalentTo(maxMTUDiff))
})
})