@@ -185,6 +185,13 @@ pub(crate) struct LossRecoverySpace {
185
185
/// This is `None` if there were no out-of-order packets detected.
186
186
/// When set to `Some(T)`, time-based loss detection should be enabled.
187
187
first_ooo_time : Option < Instant > ,
188
+ /// If no reordering has been observed, TODO: just say reo_wnd_mult != 0
189
+ reordering_seen : bool ,
190
+ /// the RTO is RTT * (reo_wnd_mult + 9) / 8
191
+ ///
192
+ /// this is basically the index of the first non-zero entry of `reo_wnd_persist`
193
+ reorder_window_mult : u32 ,
194
+ reorder_window_persist : u32 ,
188
195
}
189
196
190
197
impl LossRecoverySpace {
@@ -197,6 +204,9 @@ impl LossRecoverySpace {
197
204
in_flight_outstanding : 0 ,
198
205
sent_packets : BTreeMap :: default ( ) ,
199
206
first_ooo_time : None ,
207
+ reorder_window_mult : 0 ,
208
+ reorder_window_persist : 0 ,
209
+ reordering_seen : false ,
200
210
}
201
211
}
202
212
@@ -384,18 +394,20 @@ impl LossRecoverySpace {
384
394
pub fn detect_lost_packets (
385
395
& mut self ,
386
396
now : Instant ,
387
- loss_delay : Duration ,
397
+ rtt_estimate : Duration ,
388
398
cleanup_delay : Duration ,
389
399
lost_packets : & mut Vec < SentPacket > ,
390
400
) {
391
401
// Housekeeping.
392
402
self . remove_old_lost ( now, cleanup_delay) ;
393
403
404
+ let loss_delay = rtt_estimate * ( self . reorder_window_mult + 9 ) / 8 ;
394
405
qtrace ! (
395
- "detect lost {}: now={:?} delay={:?}" ,
406
+ "detect lost {}: now={:?} delay={:?}, multiplier={} " ,
396
407
self . space,
397
408
now,
398
409
loss_delay,
410
+ self . reorder_window_mult
399
411
) ;
400
412
self . first_ooo_time = None ;
401
413
@@ -418,7 +430,7 @@ impl LossRecoverySpace {
418
430
packet. time_sent,
419
431
loss_delay
420
432
) ;
421
- } else if largest_acked >= Some ( * pn + PACKET_THRESHOLD ) {
433
+ } else if ! self . reordering_seen && largest_acked >= Some ( * pn + PACKET_THRESHOLD ) {
422
434
qtrace ! (
423
435
"lost={}, is >= {} from largest acked {:?}" ,
424
436
pn,
@@ -438,6 +450,60 @@ impl LossRecoverySpace {
438
450
439
451
lost_packets. extend ( lost_pns. iter ( ) . map ( |pn| self . sent_packets [ pn] . clone ( ) ) ) ;
440
452
}
453
+
454
+ pub fn detect_reordered_packets (
455
+ & mut self ,
456
+ now : Instant ,
457
+ acked_pkts : & [ SentPacket ] ,
458
+ rtt_estimate : Duration ,
459
+ ) {
460
+ // detect packet reordering
461
+ let mut max_rtt = Duration :: default ( ) ;
462
+ if let Some ( largest_ack) = self . largest_acked {
463
+ for pkt in acked_pkts
464
+ . iter ( )
465
+ . filter ( |pkt| pkt. cc_in_flight ( ) && pkt. pn < largest_ack)
466
+ {
467
+ qinfo ! ( "detect_reordered_packets largest_ack={}, pn={}" , largest_ack, pkt. pn) ;
468
+ // reordering event
469
+ self . reordering_seen = true ;
470
+ max_rtt = max ( max_rtt, now. duration_since ( pkt. time_sent ) ) ;
471
+ }
472
+ }
473
+ // update reo_wnd
474
+ if max_rtt > rtt_estimate && !rtt_estimate. is_zero ( ) {
475
+ // calculate reo_wnd necessary to accept the reordering event
476
+ // inverse of
477
+ // lost_delay = rtt_estimate * (self.reo_wnd_mult + 9) / 8;
478
+ // <=> self.reo_wnd_mult = (lost_delay / rtt_estimate) * 8 - 9
479
+ let multiplier = min (
480
+ ( max_rtt. as_micros ( ) * 8 / rtt_estimate. as_micros ( ) ) - 9 + 1 ,
481
+ 8 ,
482
+ ) ;
483
+ let multiplier = u32:: try_from ( multiplier) . unwrap ( ) ;
484
+ qinfo ! (
485
+ "detect_reordered_packets max_rtt={}, rtt_estimate={} old_barrier={}, new_barrier={}" ,
486
+ max_rtt. as_micros( ) ,
487
+ rtt_estimate. as_micros( ) ,
488
+ ( rtt_estimate * ( self . reorder_window_mult + 9 ) / 8 ) . as_micros( ) ,
489
+ ( rtt_estimate * ( multiplier + 9 ) / 8 ) . as_micros( )
490
+ ) ;
491
+ self . reorder_window_mult = max ( self . reorder_window_mult , multiplier) ;
492
+ }
493
+ }
494
+
495
+ pub fn on_exiting_recovery ( & mut self ) {
496
+ if self . reorder_window_persist != 0 {
497
+ self . reorder_window_persist -= 1 ;
498
+ if self . reorder_window_persist == 0 {
499
+ self . reorder_window_mult = 0 ;
500
+ }
501
+ }
502
+ qinfo ! (
503
+ "on_exiting_recovery reorder_window_persist={}, reorder_window_mult={}" ,
504
+ self . reorder_window_persist, self . reorder_window_mult
505
+ ) ;
506
+ }
441
507
}
442
508
443
509
#[ derive( Debug ) ]
@@ -680,6 +746,9 @@ impl LossRecovery {
680
746
return ( Vec :: new ( ) , Vec :: new ( ) ) ;
681
747
}
682
748
749
+ let rtt_estimate = primary_path. borrow ( ) . rtt ( ) . estimated_upper ( ) ;
750
+ space. detect_reordered_packets ( now, & acked_packets, rtt_estimate) ;
751
+
683
752
// Track largest PN acked per space
684
753
let prev_largest_acked = space. largest_acked_sent_time ;
685
754
if Some ( largest_acked) > space. largest_acked {
@@ -704,12 +773,11 @@ impl LossRecovery {
704
773
// We need to ensure that we have sent any PTO probes before they are removed
705
774
// as we rely on the count of in-flight packets to determine whether to send
706
775
// another probe. Removing them too soon would result in not sending on PTO.
707
- let loss_delay = primary_path. borrow ( ) . rtt ( ) . loss_delay ( ) ;
708
776
let cleanup_delay = self . pto_period ( primary_path. borrow ( ) . rtt ( ) , pn_space) ;
709
777
let mut lost = Vec :: new ( ) ;
710
778
self . spaces . get_mut ( pn_space) . unwrap ( ) . detect_lost_packets (
711
779
now,
712
- loss_delay ,
780
+ rtt_estimate ,
713
781
cleanup_delay,
714
782
& mut lost,
715
783
) ;
@@ -725,9 +793,12 @@ impl LossRecovery {
725
793
// This must happen after on_packets_lost. If in recovery, this could
726
794
// take us out, and then lost packets will start a new recovery period
727
795
// when it shouldn't.
728
- primary_path
796
+ if primary_path
729
797
. borrow_mut ( )
730
- . on_packets_acked ( & acked_packets, now) ;
798
+ . on_packets_acked ( & acked_packets, now)
799
+ {
800
+ self . spaces . get_mut ( pn_space) . unwrap ( ) . on_exiting_recovery ( ) ;
801
+ }
731
802
732
803
self . pto_state = None ;
733
804
0 commit comments