@@ -193,6 +193,7 @@ pub(super) struct BBRv2NetworkModel {
193193 /// The most recent ack rate from the BandwidthSampler.
194194 latest_ack_rate : Option < Bandwidth > ,
195195
196+ /// Detector for persistent RTT jump episodes.
196197 rtt_jump_detector : RttJumpDetector ,
197198}
198199
@@ -242,7 +243,7 @@ impl BBRv2NetworkModel {
242243 latest_send_rate : None ,
243244 latest_ack_rate : None ,
244245
245- rtt_jump_detector : RttJumpDetector :: new ( ) ,
246+ rtt_jump_detector : RttJumpDetector :: new ( params . rtt_jump_detector ) ,
246247 }
247248 }
248249
@@ -369,8 +370,7 @@ impl BBRv2NetworkModel {
369370 if let Some ( rtt_sample) = sample. sample_rtt {
370371 congestion_event. sample_min_rtt = Some ( rtt_sample) ;
371372
372- self . rtt_jump_detector . on_rtt_sample_with_mode (
373- params. rtt_jump_detector ,
373+ self . rtt_jump_detector . on_rtt_sample (
374374 rtt_sample,
375375 event_time,
376376 self . full_bandwidth_reached ,
@@ -930,6 +930,28 @@ mod tests {
930930 assert ! ( model. last_persistent_jump_time( ) . is_some( ) ) ;
931931 }
932932
933+ #[ test]
934+ fn hmm_detector_can_be_enabled ( ) {
935+ let params = & rtt_jump_params ( BbrRttJumpDetector :: Hmm ) ;
936+ let mut model = BBRv2NetworkModel :: new ( params, RTT ) ;
937+ let base = Instant :: now ( ) ;
938+
939+ for pkt in 1 ..9u64 {
940+ ack_with_rtt ( & mut model, params, pkt, base, ms ( pkt * 10 ) , RTT ) ;
941+ }
942+ model. set_full_bandwidth_reached ( ) ;
943+
944+ let mut offset = 200u64 ;
945+ for pkt in 9u64 ..40 {
946+ ack_with_rtt ( & mut model, params, pkt, base, ms ( offset) , RTT_3X ) ;
947+ offset += 100 ;
948+ }
949+
950+ assert_eq ! ( model. rtt_persistent_jump_count( ) , 1 ) ;
951+ assert ! ( model. is_rtt_jump_persistent( ) ) ;
952+ assert ! ( model. last_persistent_jump_time( ) . is_some( ) ) ;
953+ }
954+
933955 #[ test]
934956 fn global_min_detector_sustained_step_becomes_persistent ( ) {
935957 let params = & rtt_jump_params ( BbrRttJumpDetector :: GlobalMin ) ;
@@ -1012,4 +1034,28 @@ mod tests {
10121034 assert_eq ! ( model. rtt_persistent_jump_count( ) , 1 ) ;
10131035 assert ! ( model. is_rtt_jump_persistent( ) ) ;
10141036 }
1037+
1038+ #[ test]
1039+ fn hmm_detector_ignores_startup_rtt_jump_until_full_bandwidth ( ) {
1040+ let params = & rtt_jump_params ( BbrRttJumpDetector :: Hmm ) ;
1041+ let mut model = BBRv2NetworkModel :: new ( params, RTT ) ;
1042+ let base = Instant :: now ( ) ;
1043+
1044+ for pkt in 1 ..9u64 {
1045+ ack_with_rtt ( & mut model, params, pkt, base, ms ( pkt * 10 ) , RTT ) ;
1046+ }
1047+
1048+ for pkt in 9u64 ..20 {
1049+ ack_with_rtt ( & mut model, params, pkt, base, ms ( pkt * 100 ) , RTT_3X ) ;
1050+ }
1051+
1052+ assert_eq ! ( model. rtt_persistent_jump_count( ) , 0 ) ;
1053+ assert ! ( !model. is_rtt_jump_active( ) ) ;
1054+
1055+ model. set_full_bandwidth_reached ( ) ;
1056+ ack_with_rtt ( & mut model, params, 20 , base, ms ( 2100 ) , RTT_3X ) ;
1057+
1058+ assert_eq ! ( model. rtt_persistent_jump_count( ) , 0 ) ;
1059+ assert ! ( !model. is_rtt_jump_persistent( ) ) ;
1060+ }
10151061}
0 commit comments