1 // Copyright (C) 2022, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright notice,
9 //       this list of conditions and the following disclaimer.
10 //
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 //! BBR Congestion Control
28 //!
29 //! This implementation is based on the following draft:
30 //! <https://tools.ietf.org/html/draft-cardwell-iccrg-bbr-congestion-control-00>
31 
32 use crate::minmax::Minmax;
33 use crate::packet;
34 use crate::recovery::*;
35 
36 use std::time::Duration;
37 use std::time::Instant;
38 
39 pub static BBR: CongestionControlOps = CongestionControlOps {
40     on_init,
41     reset,
42     on_packet_sent,
43     on_packets_acked,
44     congestion_event,
45     collapse_cwnd,
46     checkpoint,
47     rollback,
48     has_custom_pacing,
49     debug_fmt,
50 };
51 
52 /// A constant specifying the length of the BBR.BtlBw max filter window for
53 /// BBR.BtlBwFilter, BtlBwFilterLen is 10 packet-timed round trips.
54 const BTLBW_FILTER_LEN: Duration = Duration::from_secs(10);
55 
56 /// A constant specifying the minimum time interval between ProbeRTT states: 10
57 /// secs.
58 const PROBE_RTT_INTERVAL: Duration = Duration::from_secs(10);
59 
60 /// A constant specifying the length of the RTProp min filter window.
61 const RTPROP_FILTER_LEN: Duration = PROBE_RTT_INTERVAL;
62 
63 /// A constant specifying the minimum gain value that will allow the sending
64 /// rate to double each round (2/ln(2) ~= 2.89), used in Startup mode for both
65 /// BBR.pacing_gain and BBR.cwnd_gain.
66 const BBR_HIGH_GAIN: f64 = 2.89;
67 
68 /// The minimal cwnd value BBR tries to target using: 4 packets, or 4 * SMSS
69 const BBR_MIN_PIPE_CWND_PKTS: usize = 4;
70 
71 /// The number of phases in the BBR ProbeBW gain cycle: 8.
72 const BBR_GAIN_CYCLE_LEN: usize = 8;
73 
74 /// A constant specifying the minimum duration for which ProbeRTT state holds
75 /// inflight to BBRMinPipeCwnd or fewer packets: 200 ms.
76 const PROBE_RTT_DURATION: Duration = Duration::from_millis(200);
77 
78 /// Pacing Gain Cycle.
79 const PACING_GAIN_CYCLE: [f64; BBR_GAIN_CYCLE_LEN] =
80     [5.0 / 4.0, 3.0 / 4.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
81 
82 /// A constant to check BBR.BtlBW is still growing.
83 const BTLBW_GROWTH_TARGET: f64 = 1.25;
84 
85 /// BBR Internal State Machine.
86 #[derive(Debug, PartialEq, Eq)]
87 enum BBRStateMachine {
88     Startup,
89     Drain,
90     ProbeBW,
91     ProbeRTT,
92 }
93 
94 /// BBR Specific State Variables.
95 pub struct State {
96     // The current state of a BBR flow in the BBR state machine.
97     state: BBRStateMachine,
98 
99     // The current pacing rate for a BBR flow, which controls inter-packet
100     // spacing.
101     pacing_rate: u64,
102 
103     // BBR's estimated bottleneck bandwidth available to the transport flow,
104     // estimated from the maximum delivery rate sample in a sliding window.
105     btlbw: u64,
106 
107     // The max filter used to estimate BBR.BtlBw.
108     btlbwfilter: Minmax<u64>,
109 
110     // BBR's estimated two-way round-trip propagation delay of the path,
111     // estimated from the windowed minimum recent round-trip delay sample.
112     rtprop: Duration,
113 
114     // The wall clock time at which the current BBR.RTProp sample was obtained.
115     rtprop_stamp: Instant,
116 
117     // A boolean recording whether the BBR.RTprop has expired and is due for a
118     // refresh with an application idle period or a transition into ProbeRTT
119     // state.
120     rtprop_expired: bool,
121 
122     // The dynamic gain factor used to scale BBR.BtlBw to produce
123     // BBR.pacing_rate.
124     pacing_gain: f64,
125 
126     // The dynamic gain factor used to scale the estimated BDP to produce a
127     // congestion window (cwnd).
128     cwnd_gain: f64,
129 
130     // A boolean that records whether BBR estimates that it has ever fully
131     // utilized its available bandwidth ("filled the pipe").
132     filled_pipe: bool,
133 
134     // Count of packet-timed round trips elapsed so far.
135     round_count: u64,
136 
137     // A boolean that BBR sets to true once per packet-timed round trip,
138     // on ACKs that advance BBR.round_count.
139     round_start: bool,
140 
141     // packet.delivered value denoting the end of a packet-timed round trip.
142     next_round_delivered: usize,
143 
144     // Timestamp when ProbeRTT state ends.
145     probe_rtt_done_stamp: Option<Instant>,
146 
147     // Checking if a roundtrip in ProbeRTT state ends.
148     probe_rtt_round_done: bool,
149 
150     // Checking if in the packet conservation mode during recovery.
151     packet_conservation: bool,
152 
153     // Saved cwnd before loss recovery.
154     prior_cwnd: usize,
155 
156     // Checking if restarting from idle.
157     idle_restart: bool,
158 
159     // Baseline level delivery rate for full pipe estimator.
160     full_bw: u64,
161 
162     // The number of round for full pipe estimator without much growth.
163     full_bw_count: usize,
164 
165     // Last time cycle_index is updated.
166     cycle_stamp: Instant,
167 
168     // Current index of pacing_gain_cycle[].
169     cycle_index: usize,
170 
171     // The upper bound on the volume of data BBR allows in flight.
172     target_cwnd: usize,
173 
174     // Whether in the recovery episode.
175     in_recovery: bool,
176 
177     // Start time of the connection.
178     start_time: Instant,
179 
180     // Newly marked lost data size in bytes.
181     newly_lost_bytes: usize,
182 
183     // Newly acked data size in bytes.
184     newly_acked_bytes: usize,
185 
186     // bytes_in_flight before processing this ACK.
187     prior_bytes_in_flight: usize,
188 }
189 
190 impl State {
new() -> Self191     pub fn new() -> Self {
192         let now = Instant::now();
193 
194         State {
195             state: BBRStateMachine::Startup,
196 
197             pacing_rate: 0,
198 
199             btlbw: 0,
200 
201             btlbwfilter: Minmax::new(0),
202 
203             rtprop: Duration::ZERO,
204 
205             rtprop_stamp: now,
206 
207             rtprop_expired: false,
208 
209             pacing_gain: 0.0,
210 
211             cwnd_gain: 0.0,
212 
213             filled_pipe: false,
214 
215             round_count: 0,
216 
217             round_start: false,
218 
219             next_round_delivered: 0,
220 
221             probe_rtt_done_stamp: None,
222 
223             probe_rtt_round_done: false,
224 
225             packet_conservation: false,
226 
227             prior_cwnd: 0,
228 
229             idle_restart: false,
230 
231             full_bw: 0,
232 
233             full_bw_count: 0,
234 
235             cycle_stamp: now,
236 
237             cycle_index: 0,
238 
239             target_cwnd: 0,
240 
241             in_recovery: false,
242 
243             start_time: now,
244 
245             newly_lost_bytes: 0,
246 
247             newly_acked_bytes: 0,
248 
249             prior_bytes_in_flight: 0,
250         }
251     }
252 }
253 
254 // When entering the recovery episode.
bbr_enter_recovery(r: &mut Recovery, now: Instant)255 fn bbr_enter_recovery(r: &mut Recovery, now: Instant) {
256     r.bbr_state.prior_cwnd = per_ack::bbr_save_cwnd(r);
257 
258     r.congestion_window = r.bytes_in_flight +
259         r.bbr_state.newly_acked_bytes.max(r.max_datagram_size);
260     r.congestion_recovery_start_time = Some(now);
261 
262     r.bbr_state.packet_conservation = true;
263     r.bbr_state.in_recovery = true;
264 
265     // Start round now.
266     r.bbr_state.next_round_delivered = r.delivery_rate.delivered();
267 }
268 
269 // When exiting the recovery episode.
bbr_exit_recovery(r: &mut Recovery)270 fn bbr_exit_recovery(r: &mut Recovery) {
271     r.congestion_recovery_start_time = None;
272 
273     r.bbr_state.packet_conservation = false;
274     r.bbr_state.in_recovery = false;
275 
276     per_ack::bbr_restore_cwnd(r);
277 }
278 
279 // Congestion Control Hooks.
280 //
on_init(r: &mut Recovery)281 fn on_init(r: &mut Recovery) {
282     init::bbr_init(r);
283 }
284 
reset(r: &mut Recovery)285 fn reset(r: &mut Recovery) {
286     r.bbr_state = State::new();
287 
288     init::bbr_init(r);
289 }
290 
on_packet_sent(r: &mut Recovery, sent_bytes: usize, _now: Instant)291 fn on_packet_sent(r: &mut Recovery, sent_bytes: usize, _now: Instant) {
292     r.bytes_in_flight += sent_bytes;
293 
294     per_transmit::bbr_on_transmit(r);
295 }
296 
on_packets_acked( r: &mut Recovery, packets: &[Acked], _epoch: packet::Epoch, now: Instant, )297 fn on_packets_acked(
298     r: &mut Recovery, packets: &[Acked], _epoch: packet::Epoch, now: Instant,
299 ) {
300     r.bbr_state.newly_acked_bytes = packets.iter().fold(0, |acked_bytes, p| {
301         r.bbr_state.prior_bytes_in_flight = r.bytes_in_flight;
302 
303         per_ack::bbr_update_model_and_state(r, p, now);
304 
305         r.bytes_in_flight = r.bytes_in_flight.saturating_sub(p.size);
306 
307         acked_bytes + p.size
308     });
309 
310     if let Some(pkt) = packets.last() {
311         if !r.in_congestion_recovery(pkt.time_sent) {
312             // Upon exiting loss recovery.
313             bbr_exit_recovery(r);
314         }
315     }
316 
317     per_ack::bbr_update_control_parameters(r, now);
318 
319     r.bbr_state.newly_lost_bytes = 0;
320 }
321 
congestion_event( r: &mut Recovery, lost_bytes: usize, time_sent: Instant, _epoch: packet::Epoch, now: Instant, )322 fn congestion_event(
323     r: &mut Recovery, lost_bytes: usize, time_sent: Instant,
324     _epoch: packet::Epoch, now: Instant,
325 ) {
326     r.bbr_state.newly_lost_bytes = lost_bytes;
327 
328     // Upon entering Fast Recovery.
329     if !r.in_congestion_recovery(time_sent) {
330         // Upon entering Fast Recovery.
331         bbr_enter_recovery(r, now);
332     }
333 }
334 
collapse_cwnd(r: &mut Recovery)335 fn collapse_cwnd(r: &mut Recovery) {
336     r.bbr_state.prior_cwnd = per_ack::bbr_save_cwnd(r);
337 
338     reno::collapse_cwnd(r);
339 }
340 
checkpoint(_r: &mut Recovery)341 fn checkpoint(_r: &mut Recovery) {}
342 
rollback(_r: &mut Recovery) -> bool343 fn rollback(_r: &mut Recovery) -> bool {
344     false
345 }
346 
has_custom_pacing() -> bool347 fn has_custom_pacing() -> bool {
348     true
349 }
350 
debug_fmt(r: &Recovery, f: &mut std::fmt::Formatter) -> std::fmt::Result351 fn debug_fmt(r: &Recovery, f: &mut std::fmt::Formatter) -> std::fmt::Result {
352     let bbr = &r.bbr_state;
353 
354     write!(
355          f,
356          "bbr={{ state={:?} btlbw={} rtprop={:?} pacing_rate={} pacing_gain={} cwnd_gain={} target_cwnd={} send_quantum={} filled_pipe={} round_count={} }}",
357          bbr.state, bbr.btlbw, bbr.rtprop, bbr.pacing_rate, bbr.pacing_gain, bbr.cwnd_gain, bbr.target_cwnd, r.send_quantum(), bbr.filled_pipe, bbr.round_count
358     )
359 }
360 
361 #[cfg(test)]
362 mod tests {
363     use super::*;
364 
365     use crate::recovery;
366 
367     use smallvec::smallvec;
368 
369     #[test]
bbr_init()370     fn bbr_init() {
371         let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
372         cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::BBR);
373 
374         let mut r = Recovery::new(&cfg);
375 
376         // on_init() is called in Connection::new(), so it need to be
377         // called manually here.
378         r.on_init();
379 
380         assert_eq!(r.cwnd(), r.max_datagram_size * INITIAL_WINDOW_PACKETS);
381         assert_eq!(r.bytes_in_flight, 0);
382 
383         assert_eq!(r.bbr_state.state, BBRStateMachine::Startup);
384     }
385 
386     #[test]
bbr_send()387     fn bbr_send() {
388         let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
389         cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::BBR);
390 
391         let mut r = Recovery::new(&cfg);
392         let now = Instant::now();
393 
394         r.on_init();
395         r.on_packet_sent_cc(1000, now);
396 
397         assert_eq!(r.bytes_in_flight, 1000);
398     }
399 
400     #[test]
bbr_startup()401     fn bbr_startup() {
402         let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
403         cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::BBR);
404 
405         let mut r = Recovery::new(&cfg);
406         let now = Instant::now();
407         let mss = r.max_datagram_size;
408 
409         r.on_init();
410 
411         // Send 5 packets.
412         for pn in 0..5 {
413             let pkt = Sent {
414                 pkt_num: pn,
415                 frames: smallvec![],
416                 time_sent: now,
417                 time_acked: None,
418                 time_lost: None,
419                 size: mss,
420                 ack_eliciting: true,
421                 in_flight: true,
422                 delivered: 0,
423                 delivered_time: now,
424                 first_sent_time: now,
425                 is_app_limited: false,
426                 has_data: false,
427             };
428 
429             r.on_packet_sent(
430                 pkt,
431                 packet::Epoch::Application,
432                 HandshakeStatus::default(),
433                 now,
434                 "",
435             );
436         }
437 
438         let rtt = Duration::from_millis(50);
439         let now = now + rtt;
440         let cwnd_prev = r.cwnd();
441 
442         let mut acked = ranges::RangeSet::default();
443         acked.insert(0..5);
444 
445         assert_eq!(
446             r.on_ack_received(
447                 &acked,
448                 25,
449                 packet::Epoch::Application,
450                 HandshakeStatus::default(),
451                 now,
452                 "",
453             ),
454             Ok((0, 0)),
455         );
456 
457         assert_eq!(r.bbr_state.state, BBRStateMachine::Startup);
458         assert_eq!(r.cwnd(), cwnd_prev + mss * 5);
459         assert_eq!(r.bytes_in_flight, 0);
460         assert_eq!(
461             r.delivery_rate(),
462             ((mss * 5) as f64 / rtt.as_secs_f64()) as u64
463         );
464         assert_eq!(r.bbr_state.btlbw, r.delivery_rate());
465     }
466 
467     #[test]
bbr_congestion_event()468     fn bbr_congestion_event() {
469         let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
470         cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::BBR);
471 
472         let mut r = Recovery::new(&cfg);
473         let now = Instant::now();
474         let mss = r.max_datagram_size;
475 
476         r.on_init();
477 
478         // Send 5 packets.
479         for pn in 0..5 {
480             let pkt = Sent {
481                 pkt_num: pn,
482                 frames: smallvec![],
483                 time_sent: now,
484                 time_acked: None,
485                 time_lost: None,
486                 size: mss,
487                 ack_eliciting: true,
488                 in_flight: true,
489                 delivered: 0,
490                 delivered_time: now,
491                 first_sent_time: now,
492                 is_app_limited: false,
493                 has_data: false,
494             };
495 
496             r.on_packet_sent(
497                 pkt,
498                 packet::Epoch::Application,
499                 HandshakeStatus::default(),
500                 now,
501                 "",
502             );
503         }
504 
505         let rtt = Duration::from_millis(50);
506         let now = now + rtt;
507 
508         // Make a packet loss to trigger a congestion event.
509         let mut acked = ranges::RangeSet::default();
510         acked.insert(4..5);
511 
512         // 2 acked, 2 x MSS lost.
513         assert_eq!(
514             r.on_ack_received(
515                 &acked,
516                 25,
517                 packet::Epoch::Application,
518                 HandshakeStatus::default(),
519                 now,
520                 "",
521             ),
522             Ok((2, 2400)),
523         );
524 
525         // Sent: 0, 1, 2, 3, 4, Acked 4.
526         assert_eq!(r.cwnd(), mss * 4);
527         // Stil in flight: 2, 3.
528         assert_eq!(r.bytes_in_flight, mss * 2);
529     }
530 
531     #[test]
bbr_drain()532     fn bbr_drain() {
533         let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
534         cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::BBR);
535 
536         let mut r = Recovery::new(&cfg);
537         let now = Instant::now();
538         let mss = r.max_datagram_size;
539 
540         r.on_init();
541 
542         let mut pn = 0;
543 
544         // Stop right before filled_pipe=true.
545         for _ in 0..3 {
546             let pkt = Sent {
547                 pkt_num: pn,
548                 frames: smallvec![],
549                 time_sent: now,
550                 time_acked: None,
551                 time_lost: None,
552                 size: mss,
553                 ack_eliciting: true,
554                 in_flight: true,
555                 delivered: r.delivery_rate.delivered(),
556                 delivered_time: now,
557                 first_sent_time: now,
558                 is_app_limited: false,
559                 has_data: false,
560             };
561 
562             r.on_packet_sent(
563                 pkt,
564                 packet::Epoch::Application,
565                 HandshakeStatus::default(),
566                 now,
567                 "",
568             );
569 
570             pn += 1;
571 
572             let rtt = Duration::from_millis(50);
573 
574             let now = now + rtt;
575 
576             let mut acked = ranges::RangeSet::default();
577             acked.insert(0..pn);
578 
579             assert_eq!(
580                 r.on_ack_received(
581                     &acked,
582                     25,
583                     packet::Epoch::Application,
584                     HandshakeStatus::default(),
585                     now,
586                     "",
587                 ),
588                 Ok((0, 0)),
589             );
590         }
591 
592         // Stop at right before filled_pipe=true.
593         for _ in 0..5 {
594             let pkt = Sent {
595                 pkt_num: pn,
596                 frames: smallvec![],
597                 time_sent: now,
598                 time_acked: None,
599                 time_lost: None,
600                 size: mss,
601                 ack_eliciting: true,
602                 in_flight: true,
603                 delivered: r.delivery_rate.delivered(),
604                 delivered_time: now,
605                 first_sent_time: now,
606                 is_app_limited: false,
607                 has_data: false,
608             };
609 
610             r.on_packet_sent(
611                 pkt,
612                 packet::Epoch::Application,
613                 HandshakeStatus::default(),
614                 now,
615                 "",
616             );
617 
618             pn += 1;
619         }
620 
621         let rtt = Duration::from_millis(50);
622         let now = now + rtt;
623 
624         let mut acked = ranges::RangeSet::default();
625 
626         // We sent 5 packets, but ack only one, to stay
627         // in Drain state.
628         acked.insert(0..pn - 4);
629 
630         assert_eq!(
631             r.on_ack_received(
632                 &acked,
633                 25,
634                 packet::Epoch::Application,
635                 HandshakeStatus::default(),
636                 now,
637                 "",
638             ),
639             Ok((0, 0)),
640         );
641 
642         // Now we are in Drain state.
643         assert_eq!(r.bbr_state.filled_pipe, true);
644         assert_eq!(r.bbr_state.state, BBRStateMachine::Drain);
645         assert!(r.bbr_state.pacing_gain < 1.0);
646     }
647 
648     #[test]
bbr_probe_bw()649     fn bbr_probe_bw() {
650         let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
651         cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::BBR);
652 
653         let mut r = Recovery::new(&cfg);
654         let now = Instant::now();
655         let mss = r.max_datagram_size;
656 
657         r.on_init();
658 
659         let mut pn = 0;
660 
661         // At 4th roundtrip, filled_pipe=true and switch to Drain,
662         // but move to ProbeBW immediately because bytes_in_flight is
663         // smaller than BBRInFlight(1).
664         for _ in 0..4 {
665             let pkt = Sent {
666                 pkt_num: pn,
667                 frames: smallvec![],
668                 time_sent: now,
669                 time_acked: None,
670                 time_lost: None,
671                 size: mss,
672                 ack_eliciting: true,
673                 in_flight: true,
674                 delivered: r.delivery_rate.delivered(),
675                 delivered_time: now,
676                 first_sent_time: now,
677                 is_app_limited: false,
678                 has_data: false,
679             };
680 
681             r.on_packet_sent(
682                 pkt,
683                 packet::Epoch::Application,
684                 HandshakeStatus::default(),
685                 now,
686                 "",
687             );
688 
689             pn += 1;
690 
691             let rtt = Duration::from_millis(50);
692             let now = now + rtt;
693 
694             let mut acked = ranges::RangeSet::default();
695             acked.insert(0..pn);
696 
697             assert_eq!(
698                 r.on_ack_received(
699                     &acked,
700                     25,
701                     packet::Epoch::Application,
702                     HandshakeStatus::default(),
703                     now,
704                     "",
705                 ),
706                 Ok((0, 0)),
707             );
708         }
709 
710         // Now we are in ProbeBW state.
711         assert_eq!(r.bbr_state.filled_pipe, true);
712         assert_eq!(r.bbr_state.state, BBRStateMachine::ProbeBW);
713 
714         // In the first ProbeBW cycle, pacing_gain should be >= 1.0.
715         assert!(r.bbr_state.pacing_gain >= 1.0);
716     }
717 
718     #[test]
bbr_probe_rtt()719     fn bbr_probe_rtt() {
720         let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
721         cfg.set_cc_algorithm(recovery::CongestionControlAlgorithm::BBR);
722 
723         let mut r = Recovery::new(&cfg);
724         let now = Instant::now();
725         let mss = r.max_datagram_size;
726 
727         r.on_init();
728 
729         let mut pn = 0;
730 
731         // At 4th roundtrip, filled_pipe=true and switch to Drain,
732         // but move to ProbeBW immediately because bytes_in_flight is
733         // smaller than BBRInFlight(1).
734         for _ in 0..4 {
735             let pkt = Sent {
736                 pkt_num: pn,
737                 frames: smallvec![],
738                 time_sent: now,
739                 time_acked: None,
740                 time_lost: None,
741                 size: mss,
742                 ack_eliciting: true,
743                 in_flight: true,
744                 delivered: r.delivery_rate.delivered(),
745                 delivered_time: now,
746                 first_sent_time: now,
747                 is_app_limited: false,
748                 has_data: false,
749             };
750 
751             r.on_packet_sent(
752                 pkt,
753                 packet::Epoch::Application,
754                 HandshakeStatus::default(),
755                 now,
756                 "",
757             );
758 
759             pn += 1;
760 
761             let rtt = Duration::from_millis(50);
762             let now = now + rtt;
763 
764             let mut acked = ranges::RangeSet::default();
765             acked.insert(0..pn);
766 
767             assert_eq!(
768                 r.on_ack_received(
769                     &acked,
770                     25,
771                     packet::Epoch::Application,
772                     HandshakeStatus::default(),
773                     now,
774                     "",
775                 ),
776                 Ok((0, 0)),
777             );
778         }
779 
780         // Now we are in ProbeBW state.
781         assert_eq!(r.bbr_state.state, BBRStateMachine::ProbeBW);
782 
783         // After RTPROP_FILTER_LEN (10s), switch to ProbeRTT.
784         let now = now + RTPROP_FILTER_LEN;
785 
786         let pkt = Sent {
787             pkt_num: pn,
788             frames: smallvec![],
789             time_sent: now,
790             time_acked: None,
791             time_lost: None,
792             size: mss,
793             ack_eliciting: true,
794             in_flight: true,
795             delivered: r.delivery_rate.delivered(),
796             delivered_time: now,
797             first_sent_time: now,
798             is_app_limited: false,
799             has_data: false,
800         };
801 
802         r.on_packet_sent(
803             pkt,
804             packet::Epoch::Application,
805             HandshakeStatus::default(),
806             now,
807             "",
808         );
809 
810         pn += 1;
811 
812         // Don't update rtprop by giving larger rtt than before.
813         // If rtprop is updated, rtprop expiry check is reset.
814         let rtt = Duration::from_millis(100);
815         let now = now + rtt;
816 
817         let mut acked = ranges::RangeSet::default();
818         acked.insert(0..pn);
819 
820         assert_eq!(
821             r.on_ack_received(
822                 &acked,
823                 25,
824                 packet::Epoch::Application,
825                 HandshakeStatus::default(),
826                 now,
827                 "",
828             ),
829             Ok((0, 0)),
830         );
831 
832         assert_eq!(r.bbr_state.state, BBRStateMachine::ProbeRTT);
833         assert_eq!(r.bbr_state.pacing_gain, 1.0);
834     }
835 }
836 
837 mod init;
838 mod pacing;
839 mod per_ack;
840 mod per_transmit;
841