1
2
3
4
5
6
7 package quic
8
9 import (
10 "fmt"
11 "testing"
12 "time"
13 )
14
15 func TestLossAntiAmplificationLimit(t *testing.T) {
16 test := newLossTest(t, serverSide, lossTestOpts{})
17 test.datagramReceived(1200)
18 t.Logf("# consume anti-amplification capacity in a mix of packets")
19 test.send(initialSpace, 0, sentPacket{
20 size: 1200,
21 ackEliciting: true,
22 inFlight: true,
23 })
24 test.send(initialSpace, 1, sentPacket{
25 size: 1200,
26 ackEliciting: false,
27 inFlight: false,
28 })
29 test.send(initialSpace, 2, sentPacket{
30 size: 1200,
31 ackEliciting: false,
32 inFlight: true,
33 })
34 t.Logf("# send blocked by anti-amplification limit")
35 test.wantSendLimit(ccBlocked)
36
37 t.Logf("# receiving a datagram unblocks server")
38 test.datagramReceived(100)
39 test.wantSendLimit(ccOK)
40
41 t.Logf("# validating client address removes anti-amplification limit")
42 test.validateClientAddress()
43 test.wantSendLimit(ccOK)
44 }
45
46 func TestLossRTTSampleNotGenerated(t *testing.T) {
47 test := newLossTest(t, clientSide, lossTestOpts{})
48 test.send(initialSpace, 0, 1)
49 test.send(initialSpace, 2, sentPacket{
50 ackEliciting: false,
51 inFlight: false,
52 })
53 test.advance(10 * time.Millisecond)
54 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
55 test.wantAck(initialSpace, 1)
56 test.wantVar("latest_rtt", 10*time.Millisecond)
57 t.Logf("# smoothed_rtt = latest_rtt")
58 test.wantVar("smoothed_rtt", 10*time.Millisecond)
59 t.Logf("# rttvar = latest_rtt / 2")
60 test.wantVar("rttvar", 5*time.Millisecond)
61
62
63
64
65 t.Logf("# acks for older packets do not generate an RTT sample")
66 test.advance(1 * time.Millisecond)
67 test.ack(initialSpace, 1*time.Millisecond, i64range[packetNumber]{0, 2})
68 test.wantAck(initialSpace, 0)
69 test.wantVar("smoothed_rtt", 10*time.Millisecond)
70
71
72
73
74 t.Logf("# acks for non-ack-eliciting packets do not generate an RTT sample")
75 test.advance(1 * time.Millisecond)
76 test.ack(initialSpace, 1*time.Millisecond, i64range[packetNumber]{0, 3})
77 test.wantAck(initialSpace, 2)
78 test.wantVar("smoothed_rtt", 10*time.Millisecond)
79 }
80
81 func TestLossMinRTT(t *testing.T) {
82 test := newLossTest(t, clientSide, lossTestOpts{})
83
84
85
86 t.Logf("# min_rtt set on first sample")
87 test.send(initialSpace, 0)
88 test.advance(10 * time.Millisecond)
89 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
90 test.wantAck(initialSpace, 0)
91 test.wantVar("min_rtt", 10*time.Millisecond)
92
93
94
95 t.Logf("# min_rtt does not increase")
96 test.send(initialSpace, 1)
97 test.advance(20 * time.Millisecond)
98 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 2})
99 test.wantAck(initialSpace, 1)
100 test.wantVar("min_rtt", 10*time.Millisecond)
101
102 t.Logf("# min_rtt decreases")
103 test.send(initialSpace, 2)
104 test.advance(5 * time.Millisecond)
105 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
106 test.wantAck(initialSpace, 2)
107 test.wantVar("min_rtt", 5*time.Millisecond)
108 }
109
110 func TestLossMinRTTAfterCongestion(t *testing.T) {
111
112
113
114 test := newLossTest(t, clientSide, lossTestOpts{
115 maxDatagramSize: 1200,
116 })
117 t.Logf("# establish initial RTT sample")
118 test.send(initialSpace, 0, testSentPacketSize(1200))
119 test.advance(10 * time.Millisecond)
120 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
121 test.wantAck(initialSpace, 0)
122 test.wantVar("min_rtt", 10*time.Millisecond)
123
124 t.Logf("# send two packets spanning persistent congestion duration")
125 test.send(initialSpace, 1, testSentPacketSize(1200))
126 t.Logf("# 2000ms >> persistent congestion duration")
127 test.advance(2000 * time.Millisecond)
128 test.wantPTOExpired()
129 test.send(initialSpace, 2, testSentPacketSize(1200))
130
131 t.Logf("# trigger loss of previous packets")
132 test.advance(10 * time.Millisecond)
133 test.send(initialSpace, 3, testSentPacketSize(1200))
134 test.advance(20 * time.Millisecond)
135 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{3, 4})
136 test.wantAck(initialSpace, 3)
137 test.wantLoss(initialSpace, 1, 2)
138 t.Logf("# persistent congestion detected")
139
140 test.send(initialSpace, 4, testSentPacketSize(1200))
141 test.advance(20 * time.Millisecond)
142 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{4, 5})
143 test.wantAck(initialSpace, 4)
144
145 t.Logf("# min_rtt set from first sample after persistent congestion")
146 test.wantVar("min_rtt", 20*time.Millisecond)
147 }
148
149 func TestLossInitialRTTSample(t *testing.T) {
150 test := newLossTest(t, clientSide, lossTestOpts{})
151 test.setMaxAckDelay(2 * time.Millisecond)
152 t.Logf("# initial smoothed_rtt and rtt values")
153 test.wantVar("smoothed_rtt", 333*time.Millisecond)
154 test.wantVar("rttvar", 333*time.Millisecond/2)
155
156
157 t.Logf("# first RTT sample")
158 test.send(initialSpace, 0)
159 test.advance(10 * time.Millisecond)
160 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
161 test.wantAck(initialSpace, 0)
162 test.wantVar("latest_rtt", 10*time.Millisecond)
163 t.Logf("# smoothed_rtt = latest_rtt")
164 test.wantVar("smoothed_rtt", 10*time.Millisecond)
165 t.Logf("# rttvar = latest_rtt / 2")
166 test.wantVar("rttvar", 5*time.Millisecond)
167 }
168
169 func TestLossSmoothedRTTIgnoresMaxAckDelayBeforeHandshakeConfirmed(t *testing.T) {
170 test := newLossTest(t, clientSide, lossTestOpts{})
171 test.setMaxAckDelay(1 * time.Millisecond)
172 test.send(initialSpace, 0)
173 test.advance(10 * time.Millisecond)
174 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
175 test.wantAck(initialSpace, 0)
176 smoothedRTT := 10 * time.Millisecond
177 rttvar := 5 * time.Millisecond
178
179
180
181
182 t.Logf("# subsequent RTT sample")
183 test.send(handshakeSpace, 0)
184 test.advance(20 * time.Millisecond)
185 test.ack(handshakeSpace, 10*time.Millisecond, i64range[packetNumber]{0, 1})
186 test.wantAck(handshakeSpace, 0)
187 test.wantVar("latest_rtt", 20*time.Millisecond)
188 t.Logf("# ack_delay > max_ack_delay")
189 t.Logf("# handshake not confirmed, so ignore max_ack_delay")
190 t.Logf("# adjusted_rtt = latest_rtt - ackDelay")
191 adjustedRTT := 10 * time.Millisecond
192 t.Logf("# smoothed_rtt = 7/8 * smoothed_rtt + 1/8 * adjusted_rtt")
193 smoothedRTT = (7*smoothedRTT + adjustedRTT) / 8
194 test.wantVar("smoothed_rtt", smoothedRTT)
195 rttvarSample := abs(smoothedRTT - adjustedRTT)
196 t.Logf("# rttvar_sample = abs(smoothed_rtt - adjusted_rtt) = %v", rttvarSample)
197 t.Logf("# rttvar = 3/4 * rttvar + 1/4 * rttvar_sample")
198 rttvar = (3*rttvar + rttvarSample) / 4
199 test.wantVar("rttvar", rttvar)
200 }
201
202 func TestLossSmoothedRTTUsesMaxAckDelayAfterHandshakeConfirmed(t *testing.T) {
203 test := newLossTest(t, clientSide, lossTestOpts{})
204 test.setMaxAckDelay(25 * time.Millisecond)
205 test.send(initialSpace, 0)
206 test.advance(10 * time.Millisecond)
207 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
208 test.wantAck(initialSpace, 0)
209 smoothedRTT := 10 * time.Millisecond
210 rttvar := 5 * time.Millisecond
211
212 test.confirmHandshake()
213
214
215
216
217 t.Logf("# subsequent RTT sample")
218 test.send(handshakeSpace, 0)
219 test.advance(50 * time.Millisecond)
220 test.ack(handshakeSpace, 40*time.Millisecond, i64range[packetNumber]{0, 1})
221 test.wantAck(handshakeSpace, 0)
222 test.wantVar("latest_rtt", 50*time.Millisecond)
223 t.Logf("# ack_delay > max_ack_delay")
224 t.Logf("# handshake confirmed, so adjusted_rtt clamps to max_ack_delay")
225 t.Logf("# adjusted_rtt = max_ack_delay")
226 adjustedRTT := 25 * time.Millisecond
227 rttvarSample := abs(smoothedRTT - adjustedRTT)
228 t.Logf("# rttvar_sample = abs(smoothed_rtt - adjusted_rtt) = %v", rttvarSample)
229 t.Logf("# rttvar = 3/4 * rttvar + 1/4 * rttvar_sample")
230 rttvar = (3*rttvar + rttvarSample) / 4
231 test.wantVar("rttvar", rttvar)
232 t.Logf("# smoothed_rtt = 7/8 * smoothed_rtt + 1/8 * adjusted_rtt")
233 smoothedRTT = (7*smoothedRTT + adjustedRTT) / 8
234 test.wantVar("smoothed_rtt", smoothedRTT)
235 }
236
237 func TestLossAckDelayReducesRTTBelowMinRTT(t *testing.T) {
238 test := newLossTest(t, clientSide, lossTestOpts{})
239 test.send(initialSpace, 0)
240 test.advance(10 * time.Millisecond)
241 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
242 test.wantAck(initialSpace, 0)
243 smoothedRTT := 10 * time.Millisecond
244 rttvar := 5 * time.Millisecond
245
246
247
248
249 t.Logf("# subsequent RTT sample")
250 test.send(handshakeSpace, 0)
251 test.advance(12 * time.Millisecond)
252 test.ack(handshakeSpace, 4*time.Millisecond, i64range[packetNumber]{0, 1})
253 test.wantAck(handshakeSpace, 0)
254 test.wantVar("latest_rtt", 12*time.Millisecond)
255 t.Logf("# latest_rtt - ack_delay < min_rtt, so adjusted_rtt = latest_rtt")
256 adjustedRTT := 12 * time.Millisecond
257 rttvarSample := abs(smoothedRTT - adjustedRTT)
258 t.Logf("# rttvar_sample = abs(smoothed_rtt - adjusted_rtt) = %v", rttvarSample)
259 t.Logf("# rttvar = 3/4 * rttvar + 1/4 * rttvar_sample")
260 rttvar = (3*rttvar + rttvarSample) / 4
261 test.wantVar("rttvar", rttvar)
262 t.Logf("# smoothed_rtt = 7/8 * smoothed_rtt + 1/8 * adjusted_rtt")
263 smoothedRTT = (7*smoothedRTT + adjustedRTT) / 8
264 test.wantVar("smoothed_rtt", smoothedRTT)
265 }
266
267 func TestLossPacketThreshold(t *testing.T) {
268
269
270
271 test := newLossTest(t, clientSide, lossTestOpts{})
272 t.Logf("# acking a packet triggers loss of packets sent kPacketThreshold earlier")
273 test.send(appDataSpace, 0, 1, 2, 3, 4, 5, 6)
274 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{4, 5})
275 test.wantAck(appDataSpace, 4)
276 test.wantLoss(appDataSpace, 0, 1)
277 }
278
279 func TestLossOutOfOrderAcks(t *testing.T) {
280 test := newLossTest(t, clientSide, lossTestOpts{})
281 t.Logf("# out of order acks, no loss")
282 test.send(appDataSpace, 0, 1, 2)
283 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{2, 3})
284 test.wantAck(appDataSpace, 2)
285
286 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
287 test.wantAck(appDataSpace, 1)
288
289 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
290 test.wantAck(appDataSpace, 0)
291 }
292
293 func TestLossSendAndAck(t *testing.T) {
294 test := newLossTest(t, clientSide, lossTestOpts{})
295 test.send(appDataSpace, 0, 1, 2)
296 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
297 test.wantAck(appDataSpace, 0, 1, 2)
298
299
300 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
301 }
302
303 func TestLossAckEveryOtherPacket(t *testing.T) {
304 test := newLossTest(t, clientSide, lossTestOpts{})
305 test.send(appDataSpace, 0, 1, 2, 3, 4, 5, 6)
306 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
307 test.wantAck(appDataSpace, 0)
308
309 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{2, 3})
310 test.wantAck(appDataSpace, 2)
311
312 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{4, 5})
313 test.wantAck(appDataSpace, 4)
314 test.wantLoss(appDataSpace, 1)
315
316 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{6, 7})
317 test.wantAck(appDataSpace, 6)
318 test.wantLoss(appDataSpace, 3)
319 }
320
321 func TestLossMultipleSpaces(t *testing.T) {
322
323
324 test := newLossTest(t, clientSide, lossTestOpts{})
325 t.Logf("# send packets in different spaces")
326 test.send(initialSpace, 0, 1, 2)
327 test.send(handshakeSpace, 0, 1, 2)
328 test.send(appDataSpace, 0, 1, 2)
329
330 t.Logf("# ack one packet in each space")
331 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
332 test.wantAck(initialSpace, 1)
333
334 test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
335 test.wantAck(handshakeSpace, 1)
336
337 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
338 test.wantAck(appDataSpace, 1)
339
340 t.Logf("# send more packets")
341 test.send(initialSpace, 3, 4, 5)
342 test.send(handshakeSpace, 3, 4, 5)
343 test.send(appDataSpace, 3, 4, 5)
344
345 t.Logf("# ack the last packet, triggering loss")
346 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{5, 6})
347 test.wantAck(initialSpace, 5)
348 test.wantLoss(initialSpace, 0, 2)
349
350 test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{5, 6})
351 test.wantAck(handshakeSpace, 5)
352 test.wantLoss(handshakeSpace, 0, 2)
353
354 test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{5, 6})
355 test.wantAck(appDataSpace, 5)
356 test.wantLoss(appDataSpace, 0, 2)
357 }
358
359 func TestLossTimeThresholdFirstPacketLost(t *testing.T) {
360
361
362 test := newLossTest(t, clientSide, lossTestOpts{})
363 t.Logf("# packet 0 lost after time threshold passes")
364 test.send(initialSpace, 0, 1)
365 test.advance(10 * time.Millisecond)
366 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
367 test.wantAck(initialSpace, 1)
368
369 t.Logf("# latest_rtt == smoothed_rtt")
370 test.wantVar("smoothed_rtt", 10*time.Millisecond)
371 test.wantVar("latest_rtt", 10*time.Millisecond)
372 t.Logf("# timeout = 9/8 * max(smoothed_rtt, latest_rtt) - time_since_packet_sent")
373 test.wantTimeout(((10 * time.Millisecond * 9) / 8) - 10*time.Millisecond)
374
375 test.advanceToLossTimer()
376 test.wantLoss(initialSpace, 0)
377 }
378
379 func TestLossTimeThreshold(t *testing.T) {
380
381
382
383 for _, tc := range []struct {
384 name string
385 initialRTT time.Duration
386 latestRTT time.Duration
387 wantTimeout time.Duration
388 }{{
389 name: "rtt increasing",
390 initialRTT: 10 * time.Millisecond,
391 latestRTT: 20 * time.Millisecond,
392 wantTimeout: 20 * time.Millisecond * 9 / 8,
393 }, {
394 name: "rtt decreasing",
395 initialRTT: 10 * time.Millisecond,
396 latestRTT: 5 * time.Millisecond,
397 wantTimeout: ((7*10*time.Millisecond + 5*time.Millisecond) / 8) * 9 / 8,
398 }, {
399 name: "rtt less than timer granularity",
400 initialRTT: 500 * time.Microsecond,
401 latestRTT: 500 * time.Microsecond,
402 wantTimeout: 1 * time.Millisecond,
403 }} {
404 t.Run(tc.name, func(t *testing.T) {
405 test := newLossTest(t, clientSide, lossTestOpts{})
406 t.Logf("# first ack establishes smoothed_rtt")
407 test.send(initialSpace, 0)
408 test.advance(tc.initialRTT)
409 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
410 test.wantAck(initialSpace, 0)
411
412 t.Logf("# ack of packet 2 starts loss timer for packet 1")
413 test.send(initialSpace, 1, 2)
414 test.advance(tc.latestRTT)
415 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{2, 3})
416 test.wantAck(initialSpace, 2)
417
418 t.Logf("# smoothed_rtt = %v", test.c.rtt.smoothedRTT)
419 t.Logf("# latest_rtt = %v", test.c.rtt.latestRTT)
420 t.Logf("# timeout = max(9/8 * max(smoothed_rtt, latest_rtt), 1ms)")
421 t.Logf("# (measured since packet 1 sent)")
422 test.wantTimeout(tc.wantTimeout - tc.latestRTT)
423
424 t.Logf("# advancing to the loss time causes loss of packet 1")
425 test.advanceToLossTimer()
426 test.wantLoss(initialSpace, 1)
427 })
428 }
429 }
430
431 func TestLossPTONotAckEliciting(t *testing.T) {
432
433
434
435 test := newLossTest(t, clientSide, lossTestOpts{})
436 t.Logf("# PTO timer for first packet")
437 test.send(initialSpace, 0)
438 test.wantVar("smoothed_rtt", 333*time.Millisecond)
439 test.wantVar("rttvar", 333*time.Millisecond/2)
440 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
441 test.wantTimeout(999 * time.Millisecond)
442
443 t.Logf("# sending a non-ack-eliciting packet doesn't adjust PTO")
444 test.advance(333 * time.Millisecond)
445 test.send(initialSpace, 1, sentPacket{
446 ackEliciting: false,
447 })
448 test.wantVar("smoothed_rtt", 333*time.Millisecond)
449 test.wantVar("rttvar", 333*time.Millisecond/2)
450 test.wantTimeout(666 * time.Millisecond)
451 }
452
453 func TestLossPTOMaxAckDelay(t *testing.T) {
454
455
456
457 test := newLossTest(t, clientSide, lossTestOpts{})
458 t.Logf("# PTO timer for first packet")
459 test.send(initialSpace, 0)
460 test.wantVar("smoothed_rtt", 333*time.Millisecond)
461 test.wantVar("rttvar", 333*time.Millisecond/2)
462 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
463 test.wantTimeout(999 * time.Millisecond)
464
465 test.advance(10 * time.Millisecond)
466 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
467 test.wantAck(initialSpace, 0)
468
469 t.Logf("# PTO timer for handshake packet")
470 test.send(handshakeSpace, 0)
471 test.wantVar("smoothed_rtt", 10*time.Millisecond)
472 test.wantVar("rttvar", 5*time.Millisecond)
473 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
474 test.wantTimeout(30 * time.Millisecond)
475
476 test.advance(10 * time.Millisecond)
477 test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
478 test.wantAck(handshakeSpace, 0)
479 test.confirmHandshake()
480
481 t.Logf("# PTO timer for appdata packet")
482 test.send(appDataSpace, 0)
483 test.wantVar("smoothed_rtt", 10*time.Millisecond)
484 test.wantVar("rttvar", 3750*time.Microsecond)
485 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms) + max_ack_delay (25ms)")
486 test.wantTimeout(50 * time.Millisecond)
487 }
488
489 func TestLossPTOUnderTimerGranularity(t *testing.T) {
490
491
492 test := newLossTest(t, clientSide, lossTestOpts{})
493 test.send(initialSpace, 0)
494 test.advance(10 * time.Microsecond)
495 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
496 test.wantAck(initialSpace, 0)
497
498 test.send(initialSpace, 1)
499 test.wantVar("smoothed_rtt", 10*time.Microsecond)
500 test.wantVar("rttvar", 5*time.Microsecond)
501 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
502 test.wantTimeout(10*time.Microsecond + 1*time.Millisecond)
503 }
504
505 func TestLossPTOMultipleSpaces(t *testing.T) {
506
507
508
509 test := newLossTest(t, clientSide, lossTestOpts{})
510 t.Logf("# PTO timer for first packet")
511 test.send(initialSpace, 0)
512 test.wantVar("smoothed_rtt", 333*time.Millisecond)
513 test.wantVar("rttvar", 333*time.Millisecond/2)
514 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
515 test.wantTimeout(999 * time.Millisecond)
516
517 t.Logf("# Initial and Handshake packets in flight, first takes precedence")
518 test.advance(333 * time.Millisecond)
519 test.send(handshakeSpace, 0)
520 test.wantTimeout(666 * time.Millisecond)
521
522 t.Logf("# Initial packet acked, Handshake PTO timer armed")
523 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
524 test.wantAck(initialSpace, 0)
525 test.wantTimeout(999 * time.Millisecond)
526
527 t.Logf("# send Initial, earlier Handshake PTO takes precedence")
528 test.advance(333 * time.Millisecond)
529 test.send(initialSpace, 1)
530 test.wantTimeout(666 * time.Millisecond)
531 }
532
533 func TestLossPTOHandshakeConfirmation(t *testing.T) {
534
535
536
537 test := newLossTest(t, clientSide, lossTestOpts{})
538 test.send(initialSpace, 0)
539 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
540 test.wantAck(initialSpace, 0)
541
542 test.send(handshakeSpace, 0)
543 test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
544 test.wantAck(handshakeSpace, 0)
545
546 test.send(appDataSpace, 0)
547 test.wantNoTimeout()
548 }
549
550 func TestLossPTOBackoffDoubles(t *testing.T) {
551
552
553
554 test := newLossTest(t, serverSide, lossTestOpts{})
555 test.datagramReceived(1200)
556 test.send(initialSpace, 0)
557 test.wantVar("smoothed_rtt", 333*time.Millisecond)
558 test.wantVar("rttvar", 333*time.Millisecond/2)
559 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
560 test.wantTimeout(999 * time.Millisecond)
561
562 t.Logf("# wait for PTO timer expiration")
563 test.advanceToLossTimer()
564 test.wantPTOExpired()
565 test.wantNoTimeout()
566
567 t.Logf("# PTO timer doubles")
568 test.send(initialSpace, 1)
569 test.wantTimeout(2 * 999 * time.Millisecond)
570 test.advanceToLossTimer()
571 test.wantPTOExpired()
572 test.wantNoTimeout()
573
574 t.Logf("# PTO timer doubles again")
575 test.send(initialSpace, 2)
576 test.wantTimeout(4 * 999 * time.Millisecond)
577 test.advanceToLossTimer()
578 test.wantPTOExpired()
579 test.wantNoTimeout()
580 }
581
582 func TestLossPTOBackoffResetOnAck(t *testing.T) {
583
584
585 test := newLossTest(t, serverSide, lossTestOpts{})
586 test.datagramReceived(1200)
587
588 t.Logf("# first ack establishes smoothed_rtt = 10ms")
589 test.send(initialSpace, 0)
590 test.advance(10 * time.Millisecond)
591 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
592 test.wantAck(initialSpace, 0)
593 t.Logf("# set rttvar for simplicity")
594 test.setRTTVar(0)
595
596 t.Logf("# send packet 1 and wait for PTO")
597 test.send(initialSpace, 1)
598 test.wantTimeout(11 * time.Millisecond)
599 test.advanceToLossTimer()
600 test.wantPTOExpired()
601 test.wantNoTimeout()
602
603 t.Logf("# send packet 2 & 3, PTO doubles")
604 test.send(initialSpace, 2, 3)
605 test.wantTimeout(22 * time.Millisecond)
606
607 test.advance(10 * time.Millisecond)
608 t.Logf("# check remaining PTO (22ms - 10ms elapsed)")
609 test.wantTimeout(12 * time.Millisecond)
610
611 t.Logf("# ACK to packet 2 resets PTO")
612 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
613 test.wantAck(initialSpace, 1)
614 test.wantAck(initialSpace, 2)
615
616 t.Logf("# check remaining PTO (11ms - 10ms elapsed)")
617 test.wantTimeout(1 * time.Millisecond)
618 }
619
620 func TestLossPTOBackoffNotResetOnClientInitialAck(t *testing.T) {
621
622
623
624 test := newLossTest(t, clientSide, lossTestOpts{})
625
626 t.Logf("# first ack establishes smoothed_rtt = 10ms")
627 test.send(initialSpace, 0)
628 test.advance(10 * time.Millisecond)
629 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
630 test.wantAck(initialSpace, 0)
631 t.Logf("# set rttvar for simplicity")
632 test.setRTTVar(0)
633
634 t.Logf("# send packet 1 and wait for PTO")
635 test.send(initialSpace, 1)
636 test.wantTimeout(11 * time.Millisecond)
637 test.advanceToLossTimer()
638 test.wantPTOExpired()
639 test.wantNoTimeout()
640
641 t.Logf("# send more packets, PTO doubles")
642 test.send(initialSpace, 2, 3)
643 test.send(handshakeSpace, 0)
644 test.wantTimeout(22 * time.Millisecond)
645
646 test.advance(10 * time.Millisecond)
647 t.Logf("# check remaining PTO (22ms - 10ms elapsed)")
648 test.wantTimeout(12 * time.Millisecond)
649
650
651
652
653 t.Logf("# ACK to Initial packet does not reset PTO for client")
654 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
655 test.wantAck(initialSpace, 1)
656 test.wantAck(initialSpace, 2)
657 t.Logf("# check remaining PTO (22ms - 10ms elapsed)")
658 test.wantTimeout(12 * time.Millisecond)
659
660 t.Logf("# ACK to handshake packet does reset PTO")
661 test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
662 test.wantAck(handshakeSpace, 0)
663 t.Logf("# check remaining PTO (12ms - 10ms elapsed)")
664 test.wantTimeout(1 * time.Millisecond)
665 }
666
667 func TestLossPTONotSetWhenLossTimerSet(t *testing.T) {
668
669
670
671 test := newLossTest(t, serverSide, lossTestOpts{})
672 test.datagramReceived(1200)
673 t.Logf("# PTO timer set for first packets sent")
674 test.send(initialSpace, 0, 1)
675 test.wantVar("smoothed_rtt", 333*time.Millisecond)
676 test.wantVar("rttvar", 333*time.Millisecond/2)
677 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
678 test.wantTimeout(999 * time.Millisecond)
679
680 t.Logf("# ack of packet 1 starts loss timer for 0, PTO overidden")
681 test.advance(333 * time.Millisecond)
682 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
683 test.wantAck(initialSpace, 1)
684
685 t.Logf("# latest_rtt == smoothed_rtt")
686 test.wantVar("smoothed_rtt", 333*time.Millisecond)
687 test.wantVar("latest_rtt", 333*time.Millisecond)
688 t.Logf("# timeout = 9/8 * max(smoothed_rtt, latest_rtt) - time_since_packet_sent")
689 test.wantTimeout(((333 * time.Millisecond * 9) / 8) - 333*time.Millisecond)
690 }
691
692 func TestLossDiscardingKeysResetsTimers(t *testing.T) {
693
694
695
696 test := newLossTest(t, clientSide, lossTestOpts{})
697
698 t.Logf("# handshake packet sent 1ms after initial")
699 test.send(initialSpace, 0, 1)
700 test.advance(1 * time.Millisecond)
701 test.send(handshakeSpace, 0, 1)
702 test.advance(9 * time.Millisecond)
703
704 t.Logf("# ack of Initial packet 2 starts loss timer for packet 1")
705 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
706 test.wantAck(initialSpace, 1)
707
708 test.advance(1 * time.Millisecond)
709 t.Logf("# smoothed_rtt = %v", 10*time.Millisecond)
710 t.Logf("# latest_rtt = %v", 10*time.Millisecond)
711 t.Logf("# timeout = max(9/8 * max(smoothed_rtt, latest_rtt), 1ms)")
712 t.Logf("# (measured since Initial packet 1 sent)")
713 test.wantTimeout((10 * time.Millisecond * 9 / 8) - 11*time.Millisecond)
714
715 t.Logf("# ack of Handshake packet 2 starts loss timer for packet 1")
716 test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
717 test.wantAck(handshakeSpace, 1)
718
719 t.Logf("# dropping Initial keys sets timer to Handshake timeout")
720 test.discardKeys(initialSpace)
721 test.wantTimeout((10 * time.Millisecond * 9 / 8) - 10*time.Millisecond)
722 }
723
724 func TestLossNoPTOAtAntiAmplificationLimit(t *testing.T) {
725
726
727
728 test := newLossTest(t, serverSide, lossTestOpts{
729 maxDatagramSize: 1 << 20,
730 })
731 test.datagramReceived(1200)
732 test.send(initialSpace, 0, sentPacket{
733 ackEliciting: true,
734 inFlight: true,
735 size: 1200,
736 })
737 test.wantTimeout(999 * time.Millisecond)
738
739 t.Logf("PTO timer should be disabled when at the anti-amplification limit")
740 test.send(initialSpace, 1, sentPacket{
741 ackEliciting: false,
742 inFlight: true,
743 size: 2 * 1200,
744 })
745 test.wantNoTimeout()
746
747
748
749
750 t.Logf("PTO timer should be reset when datagrams are received")
751 test.datagramReceived(1200)
752 test.wantTimeout(999 * time.Millisecond)
753
754
755
756 test.send(initialSpace, 2, sentPacket{
757 ackEliciting: true,
758 inFlight: true,
759 size: 3 * 1200,
760 })
761 test.wantNoTimeout()
762 t.Logf("resetting expired PTO timer should exeute immediately")
763 test.advance(1000 * time.Millisecond)
764 test.datagramReceived(1200)
765 test.wantPTOExpired()
766 test.wantNoTimeout()
767 }
768
769 func TestLossClientSetsPTOWhenHandshakeUnacked(t *testing.T) {
770
771
772
773
774 test := newLossTest(t, clientSide, lossTestOpts{})
775 test.send(initialSpace, 0)
776
777 test.wantVar("smoothed_rtt", 333*time.Millisecond)
778 test.wantVar("rttvar", 333*time.Millisecond/2)
779 t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
780 test.wantTimeout(999 * time.Millisecond)
781
782 test.advance(333 * time.Millisecond)
783 test.wantTimeout(666 * time.Millisecond)
784 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
785 test.wantAck(initialSpace, 0)
786 t.Logf("# PTO timer set for a client before handshake ack even if no packets in flight")
787 test.wantTimeout(999 * time.Millisecond)
788
789 test.advance(333 * time.Millisecond)
790 test.wantTimeout(666 * time.Millisecond)
791 }
792
793 func TestLossKeysDiscarded(t *testing.T) {
794
795
796
797
798 test := newLossTest(t, clientSide, lossTestOpts{})
799 test.send(initialSpace, 0, testSentPacketSize(1200))
800 test.send(handshakeSpace, 0, testSentPacketSize(600))
801 test.wantVar("bytes_in_flight", 1800)
802
803 test.discardKeys(initialSpace)
804 test.wantVar("bytes_in_flight", 600)
805
806 test.discardKeys(handshakeSpace)
807 test.wantVar("bytes_in_flight", 0)
808 }
809
810 func TestLossInitialCongestionWindow(t *testing.T) {
811
812
813
814
815 test := newLossTest(t, clientSide, lossTestOpts{
816 maxDatagramSize: 1200,
817 })
818 t.Logf("# congestion_window = 10*max_datagram_size (1200)")
819 test.wantVar("congestion_window", 12000)
820
821
822 test = newLossTest(t, clientSide, lossTestOpts{
823 maxDatagramSize: 1500,
824 })
825 t.Logf("# congestion_window limited to 14720 bytes")
826 test.wantVar("congestion_window", 14720)
827
828
829 test = newLossTest(t, clientSide, lossTestOpts{
830 maxDatagramSize: 10000,
831 })
832 t.Logf("# congestion_window limited to 2*max_datagram_size (10000)")
833 test.wantVar("congestion_window", 20000)
834
835 for _, tc := range []struct {
836 maxDatagramSize int
837 wantInitialBurst int
838 }{{
839
840 maxDatagramSize: 1200,
841 wantInitialBurst: 12000,
842 }, {
843
844 maxDatagramSize: 1500,
845 wantInitialBurst: 14720,
846 }, {
847
848 maxDatagramSize: 10000,
849 wantInitialBurst: 20000,
850 }} {
851 t.Run(fmt.Sprintf("max_datagram_size=%v", tc.maxDatagramSize), func(t *testing.T) {
852 test := newLossTest(t, clientSide, lossTestOpts{
853 maxDatagramSize: tc.maxDatagramSize,
854 })
855
856 var num packetNumber
857 window := tc.wantInitialBurst
858 for window >= tc.maxDatagramSize {
859 t.Logf("# %v bytes of initial congestion window remain", window)
860 test.send(initialSpace, num, sentPacket{
861 ackEliciting: true,
862 inFlight: true,
863 size: tc.maxDatagramSize,
864 })
865 window -= tc.maxDatagramSize
866 num++
867 }
868 t.Logf("# congestion window (%v) < max_datagram_size, congestion control blocks send", window)
869 test.wantSendLimit(ccLimited)
870 })
871 }
872 }
873
874 func TestLossBytesInFlight(t *testing.T) {
875 test := newLossTest(t, clientSide, lossTestOpts{
876 maxDatagramSize: 1200,
877 })
878 t.Logf("# sent packets are added to bytes_in_flight")
879 test.wantVar("bytes_in_flight", 0)
880 test.send(initialSpace, 0, testSentPacketSize(1200))
881 test.wantVar("bytes_in_flight", 1200)
882 test.send(initialSpace, 1, testSentPacketSize(800))
883 test.wantVar("bytes_in_flight", 2000)
884
885 t.Logf("# acked packets are removed from bytes_in_flight")
886 test.advance(10 * time.Millisecond)
887 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
888 test.wantAck(initialSpace, 1)
889 test.wantVar("bytes_in_flight", 1200)
890
891 t.Logf("# lost packets are removed from bytes_in_flight")
892 test.advanceToLossTimer()
893 test.wantLoss(initialSpace, 0)
894 test.wantVar("bytes_in_flight", 0)
895 }
896
897 func TestLossCongestionWindowLimit(t *testing.T) {
898
899
900
901 test := newLossTest(t, clientSide, lossTestOpts{
902 maxDatagramSize: 1200,
903 })
904 t.Logf("# consume the initial congestion window")
905 test.send(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, testSentPacketSize(1200))
906 test.wantSendLimit(ccLimited)
907
908 t.Logf("# give the pacer bucket time to refill")
909 test.advance(333 * time.Millisecond)
910
911 t.Logf("# sending limited by congestion window, not the pacer")
912 test.wantVar("congestion_window", 12000)
913 test.wantVar("bytes_in_flight", 12000)
914 test.wantVar("pacer_bucket", 12000)
915 test.wantSendLimit(ccLimited)
916
917 t.Logf("# receiving an ack opens up the congestion window")
918 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
919 test.wantAck(initialSpace, 0)
920 test.wantSendLimit(ccOK)
921 }
922
923 func TestLossCongestionStates(t *testing.T) {
924 test := newLossTest(t, clientSide, lossTestOpts{
925 maxDatagramSize: 1200,
926 })
927 t.Logf("# consume the initial congestion window")
928 test.send(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, testSentPacketSize(1200))
929 test.wantSendLimit(ccLimited)
930 test.wantVar("congestion_window", 12000)
931
932
933
934
935 test.advance(333 * time.Millisecond)
936 t.Logf("# congestion window increases by number of bytes acked (1200)")
937 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
938 test.wantAck(initialSpace, 0)
939 test.wantVar("congestion_window", 13200)
940
941 t.Logf("# congestion window increases by number of bytes acked (2400)")
942 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
943 test.wantAck(initialSpace, 1, 2)
944 test.wantVar("congestion_window", 15600)
945
946
947
948
949
950
951 t.Logf("# loss of a packet triggers entry to a recovery period")
952 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{6, 7})
953 test.wantAck(initialSpace, 6)
954 test.wantLoss(initialSpace, 3)
955
956
957
958
959 t.Logf("# slow_start_threshold = congestion_window / 2")
960 test.wantVar("slow_start_threshold", 7800)
961
962
963
964 test.send(initialSpace, 10, testSentPacketSize(1200))
965
966
967
968
969 t.Logf("# congestion window reduced to slow start threshold")
970 test.wantVar("congestion_window", 7800)
971
972 t.Logf("# acks for packets sent before recovery started do not affect congestion")
973 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 10})
974 test.wantAck(initialSpace, 4, 5, 7, 8, 9)
975 test.wantVar("slow_start_threshold", 7800)
976 test.wantVar("congestion_window", 7800)
977
978
979
980
981 t.Logf("# recovery ends and congestion avoidance begins when packet 10 is acked")
982 test.advance(333 * time.Millisecond)
983 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 11})
984 test.wantAck(initialSpace, 10)
985
986
987
988
989 t.Logf("# after processing acks for one congestion window's worth of data...")
990 test.send(initialSpace, 11, 12, 13, 14, 15, 16, testSentPacketSize(1200))
991 test.advance(333 * time.Millisecond)
992 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 17})
993 test.wantAck(initialSpace, 11, 12, 13, 14, 15, 16)
994 t.Logf("# ...congestion window increases by max_datagram_size")
995 test.wantVar("congestion_window", 9000)
996
997
998
999
1000 test.send(initialSpace, 17, 18, 19, 20, 21, testSentPacketSize(1200))
1001 test.advance(333 * time.Millisecond)
1002 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{18, 21})
1003 test.wantAck(initialSpace, 18, 19, 20)
1004 test.wantLoss(initialSpace, 17)
1005 t.Logf("# slow_start_threshold = congestion_window / 2")
1006 test.wantVar("slow_start_threshold", 4500)
1007 }
1008
1009 func TestLossMinimumCongestionWindow(t *testing.T) {
1010
1011
1012 test := newLossTest(t, clientSide, lossTestOpts{
1013 maxDatagramSize: 1200,
1014 })
1015 test.send(initialSpace, 0, 1, 2, 3, testSentPacketSize(1200))
1016 test.wantVar("congestion_window", 12000)
1017
1018 t.Logf("# enter recovery")
1019 test.advance(333 * time.Millisecond)
1020 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{3, 4})
1021 test.wantAck(initialSpace, 3)
1022 test.wantLoss(initialSpace, 0)
1023 test.wantVar("congestion_window", 6000)
1024
1025 t.Logf("# enter congestion avoidance and return to recovery")
1026 test.send(initialSpace, 4, 5, 6, 7)
1027 test.advance(333 * time.Millisecond)
1028 test.wantLoss(initialSpace, 1, 2)
1029 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{7, 8})
1030 test.wantAck(initialSpace, 7)
1031 test.wantLoss(initialSpace, 4)
1032 test.wantVar("congestion_window", 3000)
1033
1034 t.Logf("# enter congestion avoidance and return to recovery")
1035 test.send(initialSpace, 8, 9, 10, 11)
1036 test.advance(333 * time.Millisecond)
1037 test.wantLoss(initialSpace, 5, 6)
1038 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{11, 12})
1039 test.wantAck(initialSpace, 11)
1040 test.wantLoss(initialSpace, 8)
1041 t.Logf("# congestion window does not fall below 2*max_datagram_size")
1042 test.wantVar("congestion_window", 2400)
1043
1044 t.Logf("# enter congestion avoidance and return to recovery")
1045 test.send(initialSpace, 12, 13, 14, 15)
1046 test.advance(333 * time.Millisecond)
1047 test.wantLoss(initialSpace, 9, 10)
1048 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{15, 16})
1049 test.wantAck(initialSpace, 15)
1050 test.wantLoss(initialSpace, 12)
1051 t.Logf("# congestion window does not fall below 2*max_datagram_size")
1052 test.wantVar("congestion_window", 2400)
1053 }
1054
1055 func TestLossPersistentCongestion(t *testing.T) {
1056
1057
1058
1059 test := newLossTest(t, clientSide, lossTestOpts{
1060 maxDatagramSize: 1200,
1061 })
1062 test.send(initialSpace, 0, testSentPacketSize(1200))
1063 test.c.cc.setUnderutilized(true)
1064
1065 test.advance(10 * time.Millisecond)
1066 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
1067 test.wantAck(initialSpace, 0)
1068
1069 t.Logf("# set rttvar for simplicity")
1070 test.setRTTVar(0)
1071 test.wantVar("smoothed_rtt", 10*time.Millisecond)
1072 t.Logf("# persistent congestion duration = 3*(smoothed_rtt + timerGranularity + max_ack_delay)")
1073 t.Logf("# persistent congestion duration = 108ms")
1074
1075 t.Logf("# sending packets 1-5 over 108ms")
1076 test.send(initialSpace, 1, testSentPacketSize(1200))
1077
1078 test.advance(11 * time.Millisecond)
1079 test.wantPTOExpired()
1080 test.send(initialSpace, 2, testSentPacketSize(1200))
1081
1082 test.advance(22 * time.Millisecond)
1083 test.wantPTOExpired()
1084 test.send(initialSpace, 3, testSentPacketSize(1200))
1085
1086 test.advance(44 * time.Millisecond)
1087 test.wantPTOExpired()
1088 test.send(initialSpace, 4, testSentPacketSize(1200))
1089
1090 test.advance(31 * time.Millisecond)
1091 test.send(initialSpace, 5, testSentPacketSize(1200))
1092 t.Logf("# 108ms between packets 1-5")
1093
1094 test.wantVar("congestion_window", 12000)
1095 t.Logf("# triggering loss of packets 1-5")
1096 test.send(initialSpace, 6, 7, 8, testSentPacketSize(1200))
1097 test.advance(10 * time.Millisecond)
1098 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{8, 9})
1099 test.wantAck(initialSpace, 8)
1100 test.wantLoss(initialSpace, 1, 2, 3, 4, 5)
1101
1102 t.Logf("# lost packets spanning persistent congestion duration")
1103 t.Logf("# congestion_window = 2 * max_datagram_size (minimum)")
1104 test.wantVar("congestion_window", 2400)
1105 }
1106
1107 func TestLossSimplePersistentCongestion(t *testing.T) {
1108
1109
1110 test := newLossTest(t, clientSide, lossTestOpts{
1111 maxDatagramSize: 1200,
1112 })
1113
1114 t.Logf("# establish initial RTT sample")
1115 test.send(initialSpace, 0, testSentPacketSize(1200))
1116 test.advance(10 * time.Millisecond)
1117 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
1118 test.wantAck(initialSpace, 0)
1119
1120 t.Logf("# send two packets spanning persistent congestion duration")
1121 test.send(initialSpace, 1, testSentPacketSize(1200))
1122 t.Logf("# 2000ms >> persistent congestion duration")
1123 test.advance(2000 * time.Millisecond)
1124 test.wantPTOExpired()
1125 test.send(initialSpace, 2, testSentPacketSize(1200))
1126
1127 t.Logf("# trigger loss of previous packets")
1128 test.advance(10 * time.Millisecond)
1129 test.send(initialSpace, 3, testSentPacketSize(1200))
1130 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{3, 4})
1131 test.wantAck(initialSpace, 3)
1132 test.wantLoss(initialSpace, 1, 2)
1133
1134 t.Logf("# persistent congestion detected")
1135 test.wantVar("congestion_window", 2400)
1136 }
1137
1138 func TestLossPersistentCongestionAckElicitingPackets(t *testing.T) {
1139
1140
1141 test := newLossTest(t, clientSide, lossTestOpts{
1142 maxDatagramSize: 1200,
1143 })
1144
1145 t.Logf("# establish initial RTT sample")
1146 test.send(initialSpace, 0, testSentPacketSize(1200))
1147 test.advance(10 * time.Millisecond)
1148 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
1149 test.wantAck(initialSpace, 0)
1150
1151 t.Logf("# send two packets spanning persistent congestion duration")
1152 test.send(initialSpace, 1, testSentPacketSize(1200))
1153 t.Logf("# 2000ms >> persistent congestion duration")
1154 test.advance(2000 * time.Millisecond)
1155 test.wantPTOExpired()
1156 test.send(initialSpace, 2, sentPacket{
1157 inFlight: true,
1158 ackEliciting: false,
1159 size: 1200,
1160 })
1161 test.send(initialSpace, 3, testSentPacketSize(1200))
1162
1163 t.Logf("# trigger loss of previous packets")
1164 test.advance(10 * time.Millisecond)
1165 test.send(initialSpace, 4, testSentPacketSize(1200))
1166 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{3, 5})
1167 test.wantAck(initialSpace, 3)
1168 test.wantAck(initialSpace, 4)
1169 test.wantLoss(initialSpace, 1, 2)
1170
1171 t.Logf("# persistent congestion not detected: packet 2 is not ack-eliciting")
1172 test.wantVar("congestion_window", (12000+1200+1200-1200)/2)
1173 }
1174
1175 func TestLossNoPersistentCongestionWithoutRTTSample(t *testing.T) {
1176
1177
1178
1179 test := newLossTest(t, clientSide, lossTestOpts{
1180 maxDatagramSize: 1200,
1181 })
1182
1183 t.Logf("# packets sent before initial RTT sample")
1184 test.send(initialSpace, 0, testSentPacketSize(1200))
1185 test.advance(2000 * time.Millisecond)
1186 test.wantPTOExpired()
1187 test.send(initialSpace, 1, testSentPacketSize(1200))
1188
1189 test.advance(10 * time.Millisecond)
1190 test.send(initialSpace, 2, testSentPacketSize(1200))
1191
1192 t.Logf("# first ack establishes RTT sample")
1193 test.advance(10 * time.Millisecond)
1194 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{2, 3})
1195 test.wantAck(initialSpace, 2)
1196 test.wantLoss(initialSpace, 0, 1)
1197
1198 t.Logf("# loss of packets before initial RTT sample does not cause persistent congestion")
1199 test.wantVar("congestion_window", 12000/2)
1200 }
1201
1202 func TestLossPacerRefillRate(t *testing.T) {
1203
1204
1205
1206 test := newLossTest(t, clientSide, lossTestOpts{
1207 maxDatagramSize: 1200,
1208 })
1209 t.Logf("# consume the initial congestion window")
1210 test.send(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, testSentPacketSize(1200))
1211 test.wantSendLimit(ccLimited)
1212 test.wantVar("pacer_bucket", 0)
1213 test.wantVar("congestion_window", 12000)
1214
1215 t.Logf("# first RTT sample establishes smoothed_rtt")
1216 rtt := 100 * time.Millisecond
1217 test.advance(rtt)
1218 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 10})
1219 test.wantAck(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
1220 test.wantVar("congestion_window", 24000)
1221 test.wantVar("smoothed_rtt", rtt)
1222
1223 t.Logf("# advance 1 RTT to let the pacer bucket refill completely")
1224 test.advance(100 * time.Millisecond)
1225 t.Logf("# pacer_bucket = initial_congestion_window")
1226 test.wantVar("pacer_bucket", 12000)
1227
1228 t.Logf("# consume capacity from the pacer bucket")
1229 test.send(initialSpace, 10, testSentPacketSize(1200))
1230 test.wantVar("pacer_bucket", 10800)
1231 test.send(initialSpace, 11, testSentPacketSize(600))
1232 test.wantVar("pacer_bucket", 10200)
1233 test.send(initialSpace, 12, testSentPacketSize(600))
1234 test.wantVar("pacer_bucket", 9600)
1235 test.send(initialSpace, 13, 14, 15, 16, testSentPacketSize(1200))
1236 test.wantVar("pacer_bucket", 4800)
1237
1238 t.Logf("# advance 1/10 of an RTT, bucket refills")
1239 test.advance(rtt / 10)
1240 t.Logf("# pacer_bucket += 1.25 * (1/10) * congestion_window")
1241 t.Logf("# += 3000")
1242 test.wantVar("pacer_bucket", 7800)
1243 }
1244
1245 func TestLossPacerNextSendTime(t *testing.T) {
1246 test := newLossTest(t, clientSide, lossTestOpts{
1247 maxDatagramSize: 1200,
1248 })
1249 t.Logf("# consume the initial congestion window")
1250 test.send(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, testSentPacketSize(1200))
1251 test.wantSendLimit(ccLimited)
1252 test.wantVar("pacer_bucket", 0)
1253 test.wantVar("congestion_window", 12000)
1254
1255 t.Logf("# first RTT sample establishes smoothed_rtt")
1256 rtt := 100 * time.Millisecond
1257 test.advance(rtt)
1258 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 10})
1259 test.wantAck(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
1260 test.wantVar("congestion_window", 24000)
1261 test.wantVar("smoothed_rtt", rtt)
1262
1263 t.Logf("# advance 1 RTT to let the pacer bucket refill completely")
1264 test.advance(100 * time.Millisecond)
1265 t.Logf("# pacer_bucket = initial_congestion_window")
1266 test.wantVar("pacer_bucket", 12000)
1267
1268 t.Logf("# consume the refilled pacer bucket")
1269 test.send(initialSpace, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, testSentPacketSize(1200))
1270 test.wantSendLimit(ccPaced)
1271
1272 t.Logf("# refill rate = 1.25 * congestion_window / rtt")
1273 test.wantSendDelay(rtt / 25)
1274
1275 t.Logf("# no capacity available yet")
1276 test.advance(rtt / 50)
1277 test.wantVar("pacer_bucket", -600)
1278 test.wantSendLimit(ccPaced)
1279
1280 t.Logf("# capacity available")
1281 test.advance(rtt / 50)
1282 test.wantVar("pacer_bucket", 0)
1283 test.wantSendLimit(ccOK)
1284 }
1285
1286 func TestLossCongestionWindowUnderutilized(t *testing.T) {
1287
1288
1289
1290
1291 test := newLossTest(t, clientSide, lossTestOpts{
1292 maxDatagramSize: 1200,
1293 })
1294 test.send(initialSpace, 0, testSentPacketSize(1200))
1295 test.setUnderutilized(true)
1296 t.Logf("# underutilized: %v", test.c.cc.underutilized)
1297 test.wantVar("congestion_window", 12000)
1298
1299 test.advance(10 * time.Millisecond)
1300 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
1301 test.wantAck(initialSpace, 0)
1302 t.Logf("# congestion window does not increase, because window is underutilized")
1303 test.wantVar("congestion_window", 12000)
1304
1305 t.Logf("# refill pacer bucket")
1306 test.advance(10 * time.Millisecond)
1307 test.wantVar("pacer_bucket", 12000)
1308
1309 test.send(initialSpace, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, testSentPacketSize(1200))
1310 test.setUnderutilized(false)
1311 test.advance(10 * time.Millisecond)
1312 test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 11})
1313 test.wantAck(initialSpace, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
1314 t.Logf("# congestion window increases")
1315 test.wantVar("congestion_window", 24000)
1316 }
1317
1318 type lossTest struct {
1319 t *testing.T
1320 c lossState
1321 now time.Time
1322 fates map[spaceNum]packetFate
1323 failed bool
1324 }
1325
1326 type lossTestOpts struct {
1327 maxDatagramSize int
1328 }
1329
1330 func newLossTest(t *testing.T, side connSide, opts lossTestOpts) *lossTest {
1331 c := &lossTest{
1332 t: t,
1333 now: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC),
1334 fates: make(map[spaceNum]packetFate),
1335 }
1336 maxDatagramSize := 1200
1337 if opts.maxDatagramSize != 0 {
1338 maxDatagramSize = opts.maxDatagramSize
1339 }
1340 c.c.init(side, maxDatagramSize, c.now)
1341 t.Cleanup(func() {
1342 if !c.failed {
1343 c.checkUnexpectedEvents()
1344 }
1345 })
1346 return c
1347 }
1348
1349 type spaceNum struct {
1350 space numberSpace
1351 num packetNumber
1352 }
1353
1354 func (c *lossTest) checkUnexpectedEvents() {
1355 c.t.Helper()
1356 for sn, fate := range c.fates {
1357 c.t.Errorf("ERROR: unexpected %v: %v %v", fate, sn.space, sn.num)
1358 }
1359 if c.c.ptoExpired {
1360 c.t.Errorf("ERROR: PTO timer unexpectedly expired")
1361 }
1362 }
1363
1364 func (c *lossTest) setSmoothedRTT(d time.Duration) {
1365 c.t.Helper()
1366 c.checkUnexpectedEvents()
1367 c.t.Logf("set smoothed_rtt to %v", d)
1368 c.c.rtt.smoothedRTT = d
1369 }
1370
1371 func (c *lossTest) setRTTVar(d time.Duration) {
1372 c.t.Helper()
1373 c.checkUnexpectedEvents()
1374 c.t.Logf("set rttvar to %v", d)
1375 c.c.rtt.rttvar = d
1376 }
1377
1378 func (c *lossTest) setUnderutilized(v bool) {
1379 c.t.Logf("set congestion window underutilized: %v", v)
1380 c.c.cc.setUnderutilized(v)
1381 }
1382
1383 func (c *lossTest) advance(d time.Duration) {
1384 c.t.Helper()
1385 c.checkUnexpectedEvents()
1386 c.t.Logf("advance time %v", d)
1387 c.now = c.now.Add(d)
1388 c.c.advance(c.now, c.onAckOrLoss)
1389 }
1390
1391 func (c *lossTest) advanceToLossTimer() {
1392 c.t.Helper()
1393 c.checkUnexpectedEvents()
1394 d := c.c.timer.Sub(c.now)
1395 c.t.Logf("advance time %v (up to loss timer)", d)
1396 if d < 0 {
1397 c.t.Fatalf("loss timer is in the past")
1398 }
1399 c.now = c.c.timer
1400 c.c.advance(c.now, c.onAckOrLoss)
1401 }
1402
1403 type testSentPacketSize int
1404
1405 func (c *lossTest) send(spaceID numberSpace, opts ...any) {
1406 c.t.Helper()
1407 c.checkUnexpectedEvents()
1408 var nums []packetNumber
1409 prototype := sentPacket{
1410 ackEliciting: true,
1411 inFlight: true,
1412 }
1413 for _, o := range opts {
1414 switch o := o.(type) {
1415 case sentPacket:
1416 prototype = o
1417 case testSentPacketSize:
1418 prototype.size = int(o)
1419 case int:
1420 nums = append(nums, packetNumber(o))
1421 case packetNumber:
1422 nums = append(nums, o)
1423 case i64range[packetNumber]:
1424 for num := o.start; num < o.end; num++ {
1425 nums = append(nums, num)
1426 }
1427 }
1428 }
1429 c.t.Logf("send %v %v", spaceID, nums)
1430 limit, _ := c.c.sendLimit(c.now)
1431 if prototype.inFlight && limit != ccOK {
1432 c.t.Fatalf("congestion control blocks sending packet")
1433 }
1434 if !prototype.inFlight && limit == ccBlocked {
1435 c.t.Fatalf("congestion control blocks sending packet")
1436 }
1437 for _, num := range nums {
1438 sent := &sentPacket{}
1439 *sent = prototype
1440 sent.num = num
1441 c.c.packetSent(c.now, spaceID, sent)
1442 }
1443 }
1444
1445 func (c *lossTest) datagramReceived(size int) {
1446 c.t.Helper()
1447 c.checkUnexpectedEvents()
1448 c.t.Logf("receive %v-byte datagram", size)
1449 c.c.datagramReceived(c.now, size)
1450 }
1451
1452 func (c *lossTest) ack(spaceID numberSpace, ackDelay time.Duration, rs ...i64range[packetNumber]) {
1453 c.t.Helper()
1454 c.checkUnexpectedEvents()
1455 c.c.receiveAckStart()
1456 var acked rangeset[packetNumber]
1457 for _, r := range rs {
1458 c.t.Logf("ack %v delay=%v [%v,%v)", spaceID, ackDelay, r.start, r.end)
1459 acked.add(r.start, r.end)
1460 }
1461 for i, r := range rs {
1462 c.t.Logf("ack %v delay=%v [%v,%v)", spaceID, ackDelay, r.start, r.end)
1463 c.c.receiveAckRange(c.now, spaceID, i, r.start, r.end, c.onAckOrLoss)
1464 }
1465 c.c.receiveAckEnd(c.now, spaceID, ackDelay, c.onAckOrLoss)
1466 }
1467
1468 func (c *lossTest) onAckOrLoss(space numberSpace, sent *sentPacket, fate packetFate) {
1469 c.t.Logf("%v %v %v", fate, space, sent.num)
1470 if _, ok := c.fates[spaceNum{space, sent.num}]; ok {
1471 c.t.Errorf("ERROR: duplicate %v for %v %v", fate, space, sent.num)
1472 }
1473 c.fates[spaceNum{space, sent.num}] = fate
1474 }
1475
1476 func (c *lossTest) confirmHandshake() {
1477 c.t.Helper()
1478 c.checkUnexpectedEvents()
1479 c.t.Logf("confirm handshake")
1480 c.c.confirmHandshake()
1481 }
1482
1483 func (c *lossTest) validateClientAddress() {
1484 c.t.Helper()
1485 c.checkUnexpectedEvents()
1486 c.t.Logf("validate client address")
1487 c.c.validateClientAddress()
1488 }
1489
1490 func (c *lossTest) discardKeys(spaceID numberSpace) {
1491 c.t.Helper()
1492 c.checkUnexpectedEvents()
1493 c.t.Logf("discard %s keys", spaceID)
1494 c.c.discardKeys(c.now, spaceID)
1495 }
1496
1497 func (c *lossTest) setMaxAckDelay(d time.Duration) {
1498 c.t.Helper()
1499 c.checkUnexpectedEvents()
1500 c.t.Logf("set max_ack_delay = %v", d)
1501 c.c.setMaxAckDelay(d)
1502 }
1503
1504 func (c *lossTest) wantAck(spaceID numberSpace, nums ...packetNumber) {
1505 c.t.Helper()
1506 for _, num := range nums {
1507 if c.fates[spaceNum{spaceID, num}] != packetAcked {
1508 c.t.Fatalf("expected ack for %v %v\n", spaceID, num)
1509 }
1510 delete(c.fates, spaceNum{spaceID, num})
1511 }
1512 }
1513
1514 func (c *lossTest) wantLoss(spaceID numberSpace, nums ...packetNumber) {
1515 c.t.Helper()
1516 for _, num := range nums {
1517 if c.fates[spaceNum{spaceID, num}] != packetLost {
1518 c.t.Fatalf("expected loss of %v %v\n", spaceID, num)
1519 }
1520 delete(c.fates, spaceNum{spaceID, num})
1521 }
1522 }
1523
1524 func (c *lossTest) wantPTOExpired() {
1525 c.t.Helper()
1526 if !c.c.ptoExpired {
1527 c.t.Fatalf("expected PTO timer to expire")
1528 } else {
1529 c.t.Logf("PTO TIMER EXPIRED")
1530 }
1531 c.c.ptoExpired = false
1532 }
1533
1534 func (l ccLimit) String() string {
1535 switch l {
1536 case ccOK:
1537 return "ccOK"
1538 case ccBlocked:
1539 return "ccBlocked"
1540 case ccLimited:
1541 return "ccLimited"
1542 case ccPaced:
1543 return "ccPaced"
1544 }
1545 return "BUG"
1546 }
1547
1548 func (c *lossTest) wantSendLimit(want ccLimit) {
1549 c.t.Helper()
1550 if got, _ := c.c.sendLimit(c.now); got != want {
1551 c.t.Fatalf("congestion control send limit is %v, want %v", got, want)
1552 }
1553 }
1554
1555 func (c *lossTest) wantSendDelay(want time.Duration) {
1556 c.t.Helper()
1557 limit, next := c.c.sendLimit(c.now)
1558 if limit != ccPaced {
1559 c.t.Fatalf("congestion control limit is %v, want %v", limit, ccPaced)
1560 }
1561 got := next.Sub(c.now)
1562 if got != want {
1563 c.t.Fatalf("delay until next send is %v, want %v", got, want)
1564 }
1565 }
1566
1567 func (c *lossTest) wantVar(name string, want any) {
1568 c.t.Helper()
1569 var got any
1570 switch name {
1571 case "latest_rtt":
1572 got = c.c.rtt.latestRTT
1573 case "min_rtt":
1574 got = c.c.rtt.minRTT
1575 case "smoothed_rtt":
1576 got = c.c.rtt.smoothedRTT
1577 case "rttvar":
1578 got = c.c.rtt.rttvar
1579 case "congestion_window":
1580 got = c.c.cc.congestionWindow
1581 case "slow_start_threshold":
1582 got = c.c.cc.slowStartThreshold
1583 case "bytes_in_flight":
1584 got = c.c.cc.bytesInFlight
1585 case "pacer_bucket":
1586 got = c.c.pacer.bucket
1587 default:
1588 c.t.Fatalf("unknown var %q", name)
1589 }
1590 if got != want {
1591 c.t.Fatalf("%v = %v, want %v\n", name, got, want)
1592 } else {
1593 c.t.Logf("%v = %v", name, got)
1594 }
1595 }
1596
1597 func (c *lossTest) wantTimeout(want time.Duration) {
1598 c.t.Helper()
1599 if c.c.timer.IsZero() {
1600 c.t.Fatalf("loss detection timer is not set, want %v", want)
1601 }
1602 got := c.c.timer.Sub(c.now)
1603 if got != want {
1604 c.t.Fatalf("loss detection timer expires in %v, want %v", got, want)
1605 }
1606 c.t.Logf("loss detection timer expires in %v", got)
1607 }
1608
1609 func (c *lossTest) wantNoTimeout() {
1610 c.t.Helper()
1611 if !c.c.timer.IsZero() {
1612 d := c.c.timer.Sub(c.now)
1613 c.t.Fatalf("loss detection timer expires in %v, want not set", d)
1614 }
1615 c.t.Logf("loss detection timer is not set")
1616 }
1617
1618 func (f packetFate) String() string {
1619 switch f {
1620 case packetAcked:
1621 return "ACK"
1622 case packetLost:
1623 return "LOSS"
1624 default:
1625 panic("unknown packetFate")
1626 }
1627 }
1628
View as plain text