@@ -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
+ reo_wnd_mult : u32 ,
194
+ reo_wnd_persist : [ u8 ; 16 ] ,
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
+ reo_wnd_mult : 0 ,
208
+ reo_wnd_persist : Default :: default ( ) ,
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 . reo_wnd_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 . reo_wnd_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,71 @@ 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
+ println ! ( "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
+
477
+ // inverse of lost_delay = rtt_estimate * (self.reo_wnd_mult + 9) / 8;
478
+ // self.reo_wnd_mult = (lost_delay / rtt_estimate) * 8 - 9
479
+ let new_reo_wnd = min (
480
+ ( max_rtt. as_micros ( ) * 8 / rtt_estimate. as_micros ( ) ) - 9 + 1 ,
481
+ self . reo_wnd_persist . len ( ) as u128 ,
482
+ ) ;
483
+ let new_reo_wnd = usize:: try_from ( new_reo_wnd) . unwrap ( ) ;
484
+ for el in 0 ..new_reo_wnd {
485
+ self . reo_wnd_persist [ el] = 16 ;
486
+ }
487
+ println ! (
488
+ "max_rtt={}, rtt_estimate={} old_barrier={}, new_barrier={}" ,
489
+ max_rtt. as_millis( ) ,
490
+ rtt_estimate. as_millis( ) ,
491
+ ( rtt_estimate * ( self . reo_wnd_mult + 9 ) / 8 ) . as_millis( ) ,
492
+ ( rtt_estimate * ( new_reo_wnd as u32 + 9 ) / 8 ) . as_millis( )
493
+ ) ;
494
+ println ! (
495
+ "detect_reordered_packets old={}, new={}, reo_wnd_persist={:?}" ,
496
+ self . reo_wnd_mult,
497
+ ( max_rtt. as_micros( ) * 8 / rtt_estimate. as_micros( ) ) - 9 + 1 ,
498
+ self . reo_wnd_persist
499
+ ) ;
500
+ self . reo_wnd_mult = max ( self . reo_wnd_mult , u32:: try_from ( new_reo_wnd) . unwrap ( ) ) ;
501
+ }
502
+ }
503
+
504
+ pub fn on_exiting_recovery ( & mut self ) {
505
+ let old = self . reo_wnd_mult ;
506
+ for ( i, el) in self . reo_wnd_persist . iter_mut ( ) . enumerate ( ) {
507
+ if * el == 0 {
508
+ self . reo_wnd_mult = u32:: try_from ( i) . unwrap ( ) ;
509
+ break ;
510
+ }
511
+ * el = el. saturating_sub ( 1 ) ;
512
+ }
513
+ println ! (
514
+ "detect_lost_packets old={}, new={}, reo_wnd_persist={:?}" ,
515
+ old, self . reo_wnd_mult, self . reo_wnd_persist
516
+ ) ;
517
+ }
441
518
}
442
519
443
520
#[ derive( Debug ) ]
@@ -680,6 +757,9 @@ impl LossRecovery {
680
757
return ( Vec :: new ( ) , Vec :: new ( ) ) ;
681
758
}
682
759
760
+ let rtt_estimate = primary_path. borrow ( ) . rtt ( ) . estimated_upper ( ) ;
761
+ space. detect_reordered_packets ( now, & acked_packets, rtt_estimate) ;
762
+
683
763
// Track largest PN acked per space
684
764
let prev_largest_acked = space. largest_acked_sent_time ;
685
765
if Some ( largest_acked) > space. largest_acked {
@@ -704,12 +784,11 @@ impl LossRecovery {
704
784
// We need to ensure that we have sent any PTO probes before they are removed
705
785
// as we rely on the count of in-flight packets to determine whether to send
706
786
// another probe. Removing them too soon would result in not sending on PTO.
707
- let loss_delay = primary_path. borrow ( ) . rtt ( ) . loss_delay ( ) ;
708
787
let cleanup_delay = self . pto_period ( primary_path. borrow ( ) . rtt ( ) , pn_space) ;
709
788
let mut lost = Vec :: new ( ) ;
710
789
self . spaces . get_mut ( pn_space) . unwrap ( ) . detect_lost_packets (
711
790
now,
712
- loss_delay ,
791
+ rtt_estimate ,
713
792
cleanup_delay,
714
793
& mut lost,
715
794
) ;
@@ -725,9 +804,12 @@ impl LossRecovery {
725
804
// This must happen after on_packets_lost. If in recovery, this could
726
805
// take us out, and then lost packets will start a new recovery period
727
806
// when it shouldn't.
728
- primary_path
807
+ if primary_path
729
808
. borrow_mut ( )
730
- . on_packets_acked ( & acked_packets, now) ;
809
+ . on_packets_acked ( & acked_packets, now)
810
+ {
811
+ self . spaces . get_mut ( pn_space) . unwrap ( ) . on_exiting_recovery ( ) ;
812
+ }
731
813
732
814
self . pto_state = None ;
733
815
0 commit comments