1use crate::packet;
2use crate::recovery::OnLossDetectionTimeoutOutcome;
3use crate::recovery::INITIAL_TIME_THRESHOLD_OVERHEAD;
4use crate::recovery::TIME_THRESHOLD_OVERHEAD_MULTIPLIER;
5use crate::Error;
6use crate::Result;
7
8use std::collections::VecDeque;
9use std::time::Duration;
10use std::time::Instant;
11
12use smallvec::SmallVec;
13
14#[cfg(feature = "qlog")]
15use qlog::events::EventData;
16
17#[cfg(feature = "qlog")]
18use crate::recovery::QlogMetrics;
19
20use crate::frame;
21
22use crate::recovery::bytes_in_flight::BytesInFlight;
23use crate::recovery::gcongestion::Bandwidth;
24use crate::recovery::rtt::RttStats;
25use crate::recovery::CongestionControlAlgorithm;
26use crate::recovery::HandshakeStatus;
27use crate::recovery::LossDetectionTimer;
28use crate::recovery::OnAckReceivedOutcome;
29use crate::recovery::RangeSet;
30use crate::recovery::RecoveryConfig;
31use crate::recovery::RecoveryOps;
32use crate::recovery::RecoveryStats;
33use crate::recovery::ReleaseDecision;
34use crate::recovery::Sent;
35use crate::recovery::StartupExit;
36use crate::recovery::GRANULARITY;
37use crate::recovery::INITIAL_PACKET_THRESHOLD;
38use crate::recovery::INITIAL_TIME_THRESHOLD;
39use crate::recovery::MAX_OUTSTANDING_NON_ACK_ELICITING;
40use crate::recovery::MAX_PACKET_THRESHOLD;
41use crate::recovery::MAX_PTO_PROBES_COUNT;
42use crate::recovery::PACKET_REORDER_TIME_THRESHOLD;
43
44use super::bbr2::BBRv2;
45use super::pacer::Pacer;
46use super::Acked;
47use super::Lost;
48
49const MAX_WINDOW_PACKETS: usize = 20_000;
51
52#[derive(Debug)]
53struct SentPacket {
54 pkt_num: u64,
55 status: SentStatus,
56}
57
58#[derive(Debug)]
59enum SentStatus {
60 Sent {
61 time_sent: Instant,
62 ack_eliciting: bool,
63 in_flight: bool,
64 has_data: bool,
65 is_pmtud_probe: bool,
66 sent_bytes: usize,
67 frames: SmallVec<[frame::Frame; 1]>,
68 },
69 Acked,
70 Lost,
71}
72
73impl SentStatus {
74 fn ack(&mut self) -> Self {
75 std::mem::replace(self, SentStatus::Acked)
76 }
77
78 fn lose(&mut self) -> Self {
79 if !matches!(self, SentStatus::Acked) {
80 std::mem::replace(self, SentStatus::Lost)
81 } else {
82 SentStatus::Acked
83 }
84 }
85}
86
87#[derive(Default)]
88struct RecoveryEpoch {
89 time_of_last_ack_eliciting_packet: Option<Instant>,
91
92 largest_acked_packet: Option<u64>,
95
96 loss_time: Option<Instant>,
99
100 sent_packets: VecDeque<SentPacket>,
103
104 loss_probes: usize,
105 pkts_in_flight: usize,
106
107 acked_frames: VecDeque<frame::Frame>,
108
109 lost_frames_ack: VecDeque<frame::Frame>,
113 lost_frames_pto: VecDeque<frame::Frame>,
114
115 #[allow(dead_code)]
117 test_largest_sent_pkt_num_on_path: Option<u64>,
118}
119
120struct AckedDetectionResult {
121 acked_bytes: usize,
122 spurious_losses: usize,
123 spurious_pkt_thresh: Option<u64>,
124 has_ack_eliciting: bool,
125}
126
127struct LossDetectionResult {
128 lost_bytes: usize,
129 lost_packets: usize,
130
131 pmtud_lost_bytes: usize,
132 pmtud_lost_packets: SmallVec<[u64; 1]>,
133}
134
135impl RecoveryEpoch {
136 fn discard(&mut self, cc: &mut Pacer) -> usize {
139 let unacked_bytes = self
140 .sent_packets
141 .drain(..)
142 .map(|p| {
143 if let SentPacket {
144 status:
145 SentStatus::Sent {
146 in_flight,
147 sent_bytes,
148 ..
149 },
150 pkt_num,
151 } = p
152 {
153 cc.on_packet_neutered(pkt_num);
154 if in_flight {
155 return sent_bytes;
156 }
157 }
158 0
159 })
160 .sum();
161
162 std::mem::take(&mut self.sent_packets);
163 self.clear_lost_frames();
164 std::mem::take(&mut self.acked_frames);
165 self.time_of_last_ack_eliciting_packet = None;
166 self.loss_time = None;
167 self.loss_probes = 0;
168 self.pkts_in_flight = 0;
169
170 unacked_bytes
171 }
172
173 fn detect_and_remove_acked_packets(
175 &mut self, peer_sent_ack_ranges: &RangeSet, newly_acked: &mut Vec<Acked>,
176 skip_pn: Option<u64>, trace_id: &str,
177 ) -> Result<AckedDetectionResult> {
178 newly_acked.clear();
179
180 let mut acked_bytes = 0;
181 let mut spurious_losses = 0;
182 let mut spurious_pkt_thresh = None;
183 let mut has_ack_eliciting = false;
184
185 let largest_ack_received = peer_sent_ack_ranges.last().unwrap();
186 let largest_acked = self
187 .largest_acked_packet
188 .unwrap_or(0)
189 .max(largest_ack_received);
190
191 for peer_sent_range in peer_sent_ack_ranges.iter() {
192 if skip_pn.is_some_and(|skip_pn| peer_sent_range.contains(&skip_pn)) {
193 return Err(Error::OptimisticAckDetected);
198 }
199
200 let start = if self
203 .sent_packets
204 .front()
205 .filter(|e| e.pkt_num >= peer_sent_range.start)
206 .is_some()
207 {
208 0
210 } else {
211 self.sent_packets
212 .binary_search_by_key(&peer_sent_range.start, |p| p.pkt_num)
213 .unwrap_or_else(|e| e)
214 };
215
216 for SentPacket { pkt_num, status } in
217 self.sent_packets.range_mut(start..)
218 {
219 if *pkt_num < peer_sent_range.end {
220 match status.ack() {
221 SentStatus::Sent {
222 time_sent,
223 in_flight,
224 sent_bytes,
225 frames,
226 ack_eliciting,
227 ..
228 } => {
229 if in_flight {
230 self.pkts_in_flight -= 1;
231 acked_bytes += sent_bytes;
232 }
233 newly_acked.push(Acked {
234 pkt_num: *pkt_num,
235 time_sent,
236 });
237
238 self.acked_frames.extend(frames);
239
240 has_ack_eliciting |= ack_eliciting;
241
242 trace!("{trace_id} packet newly acked {pkt_num}");
243 },
244
245 SentStatus::Acked => {},
246 SentStatus::Lost => {
247 spurious_losses += 1;
249 spurious_pkt_thresh
250 .get_or_insert(largest_acked - *pkt_num + 1);
251 },
252 }
253 } else {
254 break;
255 }
256 }
257 }
258
259 self.drain_acked_and_lost_packets();
260
261 Ok(AckedDetectionResult {
262 acked_bytes,
263 spurious_losses,
264 spurious_pkt_thresh,
265 has_ack_eliciting,
266 })
267 }
268
269 fn detect_and_remove_lost_packets(
270 &mut self, loss_delay: Duration, pkt_thresh: Option<u64>, now: Instant,
271 newly_lost: &mut Vec<Lost>,
272 ) -> LossDetectionResult {
273 newly_lost.clear();
274 let mut lost_bytes = 0;
275 self.loss_time = None;
276
277 let lost_send_time = now.checked_sub(loss_delay).unwrap();
278 let largest_acked = self.largest_acked_packet.unwrap_or(0);
279 let mut pmtud_lost_bytes = 0;
280 let mut pmtud_lost_packets = SmallVec::new();
281
282 for SentPacket { pkt_num, status } in &mut self.sent_packets {
283 if *pkt_num > largest_acked {
284 break;
285 }
286
287 if let SentStatus::Sent { time_sent, .. } = status {
288 let loss_by_time = *time_sent <= lost_send_time;
289 let loss_by_pkt = match pkt_thresh {
290 Some(pkt_thresh) => largest_acked >= *pkt_num + pkt_thresh,
291 None => false,
292 };
293
294 if loss_by_time || loss_by_pkt {
295 if let SentStatus::Sent {
296 in_flight,
297 sent_bytes,
298 frames,
299 is_pmtud_probe,
300 ..
301 } = status.lose()
302 {
303 self.lost_frames_ack.extend(frames);
304
305 if in_flight {
306 self.pkts_in_flight -= 1;
307
308 if is_pmtud_probe {
309 pmtud_lost_bytes += sent_bytes;
310 pmtud_lost_packets.push(*pkt_num);
311 continue;
313 }
314
315 lost_bytes += sent_bytes;
316 }
317
318 newly_lost.push(Lost {
319 packet_number: *pkt_num,
320 bytes_lost: sent_bytes,
321 });
322 }
323 } else {
324 self.loss_time = Some(*time_sent + loss_delay);
325 break;
326 }
327 }
328 }
329
330 LossDetectionResult {
331 lost_bytes,
332 lost_packets: newly_lost.len(),
333
334 pmtud_lost_bytes,
335 pmtud_lost_packets,
336 }
337 }
338
339 fn drain_acked_and_lost_packets(&mut self) {
343 while let Some(SentPacket {
344 status: SentStatus::Acked | SentStatus::Lost,
345 ..
346 }) = self.sent_packets.front()
347 {
348 self.sent_packets.pop_front();
349 }
350 }
351
352 fn least_unacked(&self) -> u64 {
353 for pkt in self.sent_packets.iter() {
354 if let SentPacket {
355 pkt_num,
356 status: SentStatus::Sent { .. },
357 } = pkt
358 {
359 return *pkt_num;
360 }
361 }
362
363 self.largest_acked_packet.unwrap_or(0) + 1
364 }
365
366 fn next_lost_frame(&mut self) -> Option<frame::Frame> {
369 self.lost_frames_ack
370 .pop_front()
371 .or_else(|| self.lost_frames_pto.pop_front())
372 }
373
374 fn has_lost_frames(&self) -> bool {
376 !self.lost_frames_ack.is_empty() || !self.lost_frames_pto.is_empty()
377 }
378
379 #[cfg(test)]
381 fn lost_frames_count(&self) -> usize {
382 self.lost_frames_ack.len() + self.lost_frames_pto.len()
383 }
384
385 fn clear_lost_frames(&mut self) {
387 self.lost_frames_ack.clear();
388 self.lost_frames_pto.clear();
389 }
390}
391
392struct LossThreshold {
393 pkt_thresh: Option<u64>,
394 time_thresh: f64,
395
396 time_thresh_overhead: Option<f64>,
405}
406
407impl LossThreshold {
408 fn new(recovery_config: &RecoveryConfig) -> Self {
409 let time_thresh_overhead =
410 if recovery_config.enable_relaxed_loss_threshold {
411 Some(INITIAL_TIME_THRESHOLD_OVERHEAD)
412 } else {
413 None
414 };
415 LossThreshold {
416 pkt_thresh: Some(INITIAL_PACKET_THRESHOLD),
417 time_thresh: INITIAL_TIME_THRESHOLD,
418 time_thresh_overhead,
419 }
420 }
421
422 fn pkt_thresh(&self) -> Option<u64> {
423 self.pkt_thresh
424 }
425
426 fn time_thresh(&self) -> f64 {
427 self.time_thresh
428 }
429
430 fn on_spurious_loss(&mut self, new_pkt_thresh: u64) {
431 match &mut self.time_thresh_overhead {
432 Some(time_thresh_overhead) => {
433 if self.pkt_thresh.is_some() {
434 self.pkt_thresh = None;
436 } else {
437 *time_thresh_overhead *= TIME_THRESHOLD_OVERHEAD_MULTIPLIER;
440 *time_thresh_overhead = time_thresh_overhead.min(1.0);
441
442 self.time_thresh = 1.0 + *time_thresh_overhead;
443 }
444 },
445 None => {
446 let new_packet_threshold = self
447 .pkt_thresh
448 .expect("packet threshold should always be Some when `enable_relaxed_loss_threshold` is false")
449 .max(new_pkt_thresh.min(MAX_PACKET_THRESHOLD));
450 self.pkt_thresh = Some(new_packet_threshold);
451
452 self.time_thresh = PACKET_REORDER_TIME_THRESHOLD;
453 },
454 }
455 }
456}
457
458pub struct GRecovery {
459 epochs: [RecoveryEpoch; packet::Epoch::count()],
460
461 loss_timer: LossDetectionTimer,
462
463 pto_count: u32,
464
465 rtt_stats: RttStats,
466
467 recovery_stats: RecoveryStats,
468
469 pub lost_count: usize,
470
471 pub lost_spurious_count: usize,
472
473 loss_thresh: LossThreshold,
474
475 bytes_in_flight: BytesInFlight,
476
477 bytes_sent: usize,
478
479 pub bytes_lost: u64,
480
481 max_datagram_size: usize,
482 time_sent_set_to_now: bool,
483
484 #[cfg(feature = "qlog")]
485 qlog_metrics: QlogMetrics,
486
487 #[cfg(feature = "qlog")]
488 qlog_prev_cc_state: &'static str,
489
490 outstanding_non_ack_eliciting: usize,
492
493 newly_acked: Vec<Acked>,
495
496 lost_reuse: Vec<Lost>,
499
500 pacer: Pacer,
501}
502
503impl GRecovery {
504 #[cfg(feature = "qlog")]
505 fn send_rate(&self) -> Bandwidth {
506 self.pacer.send_rate().unwrap_or(Bandwidth::zero())
507 }
508
509 #[cfg(feature = "qlog")]
510 fn ack_rate(&self) -> Bandwidth {
511 self.pacer.ack_rate().unwrap_or(Bandwidth::zero())
512 }
513
514 pub fn new(recovery_config: &RecoveryConfig) -> Option<Self> {
515 let cc = match recovery_config.cc_algorithm {
516 CongestionControlAlgorithm::Bbr2Gcongestion => BBRv2::new(
517 recovery_config.initial_congestion_window_packets,
518 MAX_WINDOW_PACKETS,
519 recovery_config.max_send_udp_payload_size,
520 recovery_config.initial_rtt,
521 recovery_config.custom_bbr_params.as_ref(),
522 ),
523 _ => return None,
524 };
525
526 Some(Self {
527 epochs: Default::default(),
528 rtt_stats: RttStats::new(
529 recovery_config.initial_rtt,
530 recovery_config.max_ack_delay,
531 ),
532 recovery_stats: RecoveryStats::default(),
533 loss_timer: Default::default(),
534 pto_count: 0,
535
536 lost_count: 0,
537 lost_spurious_count: 0,
538
539 loss_thresh: LossThreshold::new(recovery_config),
540 bytes_in_flight: Default::default(),
541 bytes_sent: 0,
542 bytes_lost: 0,
543
544 max_datagram_size: recovery_config.max_send_udp_payload_size,
545 time_sent_set_to_now: cc.time_sent_set_to_now(),
546
547 #[cfg(feature = "qlog")]
548 qlog_metrics: QlogMetrics::default(),
549
550 #[cfg(feature = "qlog")]
551 qlog_prev_cc_state: "",
552
553 outstanding_non_ack_eliciting: 0,
554
555 pacer: Pacer::new(
556 recovery_config.pacing,
557 cc,
558 recovery_config
559 .max_pacing_rate
560 .map(Bandwidth::from_mbits_per_second),
561 ),
562
563 newly_acked: Vec::new(),
564 lost_reuse: Vec::new(),
565 })
566 }
567
568 fn detect_and_remove_lost_packets(
569 &mut self, epoch: packet::Epoch, now: Instant,
570 ) -> (usize, usize) {
571 let loss_delay =
572 self.rtt_stats.loss_delay(self.loss_thresh.time_thresh());
573 let lost = &mut self.lost_reuse;
574
575 let LossDetectionResult {
576 lost_bytes,
577 lost_packets,
578 pmtud_lost_bytes,
579 pmtud_lost_packets,
580 } = self.epochs[epoch].detect_and_remove_lost_packets(
581 loss_delay,
582 self.loss_thresh.pkt_thresh(),
583 now,
584 lost,
585 );
586
587 self.bytes_in_flight
588 .saturating_subtract(lost_bytes + pmtud_lost_bytes, now);
589
590 for pkt in pmtud_lost_packets {
591 self.pacer.on_packet_neutered(pkt);
592 }
593
594 (lost_bytes, lost_packets)
595 }
596
597 fn loss_time_and_space(&self) -> (Option<Instant>, packet::Epoch) {
598 let mut epoch = packet::Epoch::Initial;
599 let mut time = self.epochs[epoch].loss_time;
600
601 for e in [packet::Epoch::Handshake, packet::Epoch::Application] {
603 let new_time = self.epochs[e].loss_time;
604 if time.is_none() || new_time < time {
605 time = new_time;
606 epoch = e;
607 }
608 }
609
610 (time, epoch)
611 }
612
613 fn pto_time_and_space(
614 &self, handshake_status: HandshakeStatus, now: Instant,
615 ) -> (Option<Instant>, packet::Epoch) {
616 let mut duration = self.pto() * 2_u32.saturating_pow(self.pto_count);
617
618 if self.bytes_in_flight.is_zero() {
620 if handshake_status.has_handshake_keys {
621 return (Some(now + duration), packet::Epoch::Handshake);
622 } else {
623 return (Some(now + duration), packet::Epoch::Initial);
624 }
625 }
626
627 let mut pto_timeout = None;
628 let mut pto_space = packet::Epoch::Initial;
629
630 for &e in packet::Epoch::epochs(
632 packet::Epoch::Initial..=packet::Epoch::Application,
633 ) {
634 if self.epochs[e].pkts_in_flight == 0 {
635 continue;
636 }
637
638 if e == packet::Epoch::Application {
639 if !handshake_status.completed {
641 return (pto_timeout, pto_space);
642 }
643
644 duration += self.rtt_stats.max_ack_delay *
646 2_u32.saturating_pow(self.pto_count);
647 }
648
649 let new_time = self.epochs[e]
650 .time_of_last_ack_eliciting_packet
651 .map(|t| t + duration);
652
653 if pto_timeout.is_none() || new_time < pto_timeout {
654 pto_timeout = new_time;
655 pto_space = e;
656 }
657 }
658
659 (pto_timeout, pto_space)
660 }
661
662 fn set_loss_detection_timer(
663 &mut self, handshake_status: HandshakeStatus, now: Instant,
664 ) {
665 if let (Some(earliest_loss_time), _) = self.loss_time_and_space() {
666 self.loss_timer.update(earliest_loss_time);
668 return;
669 }
670
671 if self.bytes_in_flight.is_zero() &&
672 handshake_status.peer_verified_address
673 {
674 self.loss_timer.clear();
675 return;
676 }
677
678 if let (Some(timeout), _) = self.pto_time_and_space(handshake_status, now)
680 {
681 self.loss_timer.update(timeout);
682 } else {
683 self.loss_timer.clear();
684 }
685 }
686}
687
688impl RecoveryOps for GRecovery {
689 fn lost_count(&self) -> usize {
690 self.lost_count
691 }
692
693 fn bytes_lost(&self) -> u64 {
694 self.bytes_lost
695 }
696
697 fn should_elicit_ack(&self, epoch: packet::Epoch) -> bool {
698 self.epochs[epoch].loss_probes > 0 ||
699 self.outstanding_non_ack_eliciting >=
700 MAX_OUTSTANDING_NON_ACK_ELICITING
701 }
702
703 fn next_acked_frame(&mut self, epoch: packet::Epoch) -> Option<frame::Frame> {
704 self.epochs[epoch].acked_frames.pop_front()
705 }
706
707 fn next_lost_frame(&mut self, epoch: packet::Epoch) -> Option<frame::Frame> {
708 self.epochs[epoch].next_lost_frame()
709 }
710
711 fn get_largest_acked_on_epoch(&self, epoch: packet::Epoch) -> Option<u64> {
712 self.epochs[epoch].largest_acked_packet
713 }
714
715 fn has_lost_frames(&self, epoch: packet::Epoch) -> bool {
716 self.epochs[epoch].has_lost_frames()
717 }
718
719 fn loss_probes(&self, epoch: packet::Epoch) -> usize {
720 self.epochs[epoch].loss_probes
721 }
722
723 #[cfg(test)]
724 fn inc_loss_probes(&mut self, epoch: packet::Epoch) {
725 self.epochs[epoch].loss_probes += 1;
726 }
727
728 #[cfg(test)]
729 fn lost_frames_count(&self, epoch: packet::Epoch) -> usize {
730 self.epochs[epoch].lost_frames_count()
731 }
732
733 fn ping_sent(&mut self, epoch: packet::Epoch) {
734 self.epochs[epoch].loss_probes =
735 self.epochs[epoch].loss_probes.saturating_sub(1);
736 }
737
738 fn on_packet_sent(
739 &mut self, pkt: Sent, epoch: packet::Epoch,
740 handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
741 ) {
742 let time_sent = if self.time_sent_set_to_now {
743 now
744 } else {
745 self.get_next_release_time().time(now).unwrap_or(now)
746 };
747
748 let epoch = &mut self.epochs[epoch];
749
750 let ack_eliciting = pkt.ack_eliciting;
751 let in_flight = pkt.in_flight;
752 let is_pmtud_probe = pkt.is_pmtud_probe;
753 let pkt_num = pkt.pkt_num;
754 let sent_bytes = pkt.size;
755
756 if let Some(SentPacket { pkt_num, .. }) = epoch.sent_packets.back() {
757 assert!(*pkt_num < pkt.pkt_num, "Packet numbers must increase");
758 }
759
760 let status = SentStatus::Sent {
761 time_sent,
762 ack_eliciting,
763 in_flight,
764 is_pmtud_probe,
765 has_data: pkt.has_data,
766 sent_bytes,
767 frames: pkt.frames,
768 };
769
770 #[cfg(test)]
771 {
772 epoch.test_largest_sent_pkt_num_on_path = epoch
773 .test_largest_sent_pkt_num_on_path
774 .max(Some(pkt.pkt_num));
775 }
776
777 epoch.sent_packets.push_back(SentPacket { pkt_num, status });
778
779 if ack_eliciting {
780 epoch.time_of_last_ack_eliciting_packet = Some(time_sent);
781 self.outstanding_non_ack_eliciting = 0;
782 } else {
783 self.outstanding_non_ack_eliciting += 1;
784 }
785
786 if in_flight {
787 self.pacer.on_packet_sent(
788 time_sent,
789 self.bytes_in_flight.get(),
790 pkt_num,
791 sent_bytes,
792 pkt.has_data,
793 &self.rtt_stats,
794 );
795
796 self.bytes_in_flight.add(sent_bytes, now);
797 epoch.pkts_in_flight += 1;
798 self.set_loss_detection_timer(handshake_status, time_sent);
799 }
800
801 self.bytes_sent += sent_bytes;
802
803 trace!("{trace_id} {self:?}");
804 }
805
806 fn get_packet_send_time(&self, now: Instant) -> Instant {
807 self.pacer.get_next_release_time().time(now).unwrap_or(now)
808 }
809
810 fn on_ack_received(
812 &mut self, peer_sent_ack_ranges: &RangeSet, ack_delay: u64,
813 epoch: packet::Epoch, handshake_status: HandshakeStatus, now: Instant,
814 skip_pn: Option<u64>, trace_id: &str,
815 ) -> Result<OnAckReceivedOutcome> {
816 let prior_in_flight = self.bytes_in_flight.get();
817
818 let AckedDetectionResult {
819 acked_bytes,
820 spurious_losses,
821 spurious_pkt_thresh,
822 has_ack_eliciting,
823 } = self.epochs[epoch].detect_and_remove_acked_packets(
824 peer_sent_ack_ranges,
825 &mut self.newly_acked,
826 skip_pn,
827 trace_id,
828 )?;
829
830 self.lost_spurious_count += spurious_losses;
831 if let Some(thresh) = spurious_pkt_thresh {
832 self.loss_thresh.on_spurious_loss(thresh);
833 }
834
835 if self.newly_acked.is_empty() {
836 return Ok(OnAckReceivedOutcome {
837 acked_bytes,
838 spurious_losses,
839 ..Default::default()
840 });
841 }
842
843 self.bytes_in_flight.saturating_subtract(acked_bytes, now);
844
845 let largest_newly_acked = self.newly_acked.last().unwrap();
846
847 let largest_acked_pkt_num = self.epochs[epoch]
850 .largest_acked_packet
851 .unwrap_or(0)
852 .max(largest_newly_acked.pkt_num);
853 self.epochs[epoch].largest_acked_packet = Some(largest_acked_pkt_num);
854
855 let update_rtt = largest_newly_acked.pkt_num == largest_acked_pkt_num &&
857 has_ack_eliciting;
858 if update_rtt {
859 let latest_rtt = now - largest_newly_acked.time_sent;
860 self.rtt_stats.update_rtt(
861 latest_rtt,
862 Duration::from_micros(ack_delay),
863 now,
864 handshake_status.completed,
865 );
866 }
867
868 let (lost_bytes, lost_packets) =
869 self.detect_and_remove_lost_packets(epoch, now);
870
871 self.pacer.on_congestion_event(
872 update_rtt,
873 prior_in_flight,
874 self.bytes_in_flight.get(),
875 now,
876 &self.newly_acked,
877 &self.lost_reuse,
878 self.epochs[epoch].least_unacked(),
879 &self.rtt_stats,
880 &mut self.recovery_stats,
881 );
882
883 self.pto_count = 0;
884 self.lost_count += lost_packets;
885
886 self.set_loss_detection_timer(handshake_status, now);
887
888 trace!("{trace_id} {self:?}");
889
890 Ok(OnAckReceivedOutcome {
891 lost_packets,
892 lost_bytes,
893 acked_bytes,
894 spurious_losses,
895 })
896 }
897
898 fn on_loss_detection_timeout(
899 &mut self, handshake_status: HandshakeStatus, now: Instant,
900 trace_id: &str,
901 ) -> OnLossDetectionTimeoutOutcome {
902 let (earliest_loss_time, epoch) = self.loss_time_and_space();
903
904 if earliest_loss_time.is_some() {
905 let prior_in_flight = self.bytes_in_flight.get();
906
907 let (lost_bytes, lost_packets) =
908 self.detect_and_remove_lost_packets(epoch, now);
909
910 self.pacer.on_congestion_event(
911 false,
912 prior_in_flight,
913 self.bytes_in_flight.get(),
914 now,
915 &[],
916 &self.lost_reuse,
917 self.epochs[epoch].least_unacked(),
918 &self.rtt_stats,
919 &mut self.recovery_stats,
920 );
921
922 self.lost_count += lost_packets;
923
924 self.set_loss_detection_timer(handshake_status, now);
925
926 trace!("{trace_id} {self:?}");
927 return OnLossDetectionTimeoutOutcome {
928 lost_packets,
929 lost_bytes,
930 };
931 }
932
933 let epoch = if self.bytes_in_flight.get() > 0 {
934 let (_, e) = self.pto_time_and_space(handshake_status, now);
937
938 e
939 } else {
940 if handshake_status.has_handshake_keys {
944 packet::Epoch::Handshake
945 } else {
946 packet::Epoch::Initial
947 }
948 };
949
950 self.pto_count += 1;
951
952 let epoch = &mut self.epochs[epoch];
953
954 epoch.loss_probes = MAX_PTO_PROBES_COUNT.min(self.pto_count as usize);
955
956 let sent_packets_iter_limit = if !epoch.lost_frames_pto.is_empty() {
957 0
960 } else {
961 usize::MAX
962 };
963
964 let unacked_frames = epoch
968 .sent_packets
969 .iter()
970 .take(sent_packets_iter_limit)
971 .filter_map(|p| {
972 if let SentStatus::Sent {
973 has_data: true,
974 frames,
975 ..
976 } = &p.status
977 {
978 Some(frames)
979 } else {
980 None
981 }
982 })
983 .take(epoch.loss_probes)
984 .flatten()
985 .filter(|f| !matches!(f, frame::Frame::DatagramHeader { .. }));
986
987 epoch.lost_frames_pto.extend(unacked_frames.cloned());
995
996 self.pacer
997 .on_retransmission_timeout(epoch.has_lost_frames());
998
999 self.set_loss_detection_timer(handshake_status, now);
1000
1001 trace!("{trace_id} {self:?}");
1002 OnLossDetectionTimeoutOutcome {
1003 lost_packets: 0,
1004 lost_bytes: 0,
1005 }
1006 }
1007
1008 fn on_pkt_num_space_discarded(
1009 &mut self, epoch: packet::Epoch, handshake_status: HandshakeStatus,
1010 now: Instant,
1011 ) {
1012 let epoch = &mut self.epochs[epoch];
1013 self.bytes_in_flight
1014 .saturating_subtract(epoch.discard(&mut self.pacer), now);
1015 self.set_loss_detection_timer(handshake_status, now);
1016 }
1017
1018 fn on_path_change(
1019 &mut self, epoch: packet::Epoch, now: Instant, _trace_id: &str,
1020 ) -> (usize, usize) {
1021 let (lost_bytes, lost_packets) =
1022 self.detect_and_remove_lost_packets(epoch, now);
1023
1024 (lost_packets, lost_bytes)
1025 }
1026
1027 fn loss_detection_timer(&self) -> Option<Instant> {
1028 self.loss_timer.time
1029 }
1030
1031 fn cwnd(&self) -> usize {
1032 self.pacer.get_congestion_window()
1033 }
1034
1035 fn cwnd_available(&self) -> usize {
1036 if self.epochs.iter().any(|e| e.loss_probes > 0) {
1038 return usize::MAX;
1039 }
1040
1041 self.cwnd().saturating_sub(self.bytes_in_flight.get())
1042 }
1043
1044 fn rtt(&self) -> Duration {
1045 self.rtt_stats.rtt()
1046 }
1047
1048 fn min_rtt(&self) -> Option<Duration> {
1049 self.rtt_stats.min_rtt()
1050 }
1051
1052 fn max_rtt(&self) -> Option<Duration> {
1053 self.rtt_stats.max_rtt()
1054 }
1055
1056 fn rttvar(&self) -> Duration {
1057 self.rtt_stats.rttvar()
1058 }
1059
1060 fn pto(&self) -> Duration {
1061 let r = &self.rtt_stats;
1062 r.rtt() + (r.rttvar() * 4).max(GRANULARITY)
1063 }
1064
1065 fn delivery_rate(&self) -> Bandwidth {
1067 self.pacer.bandwidth_estimate(&self.rtt_stats)
1068 }
1069
1070 fn max_bandwidth(&self) -> Option<Bandwidth> {
1071 Some(self.pacer.max_bandwidth())
1072 }
1073
1074 fn rtt_persistent_jump_count(&self) -> u64 {
1075 self.pacer.rtt_persistent_jump_count()
1076 }
1077
1078 fn startup_exit(&self) -> Option<StartupExit> {
1080 self.recovery_stats.startup_exit
1081 }
1082
1083 fn max_datagram_size(&self) -> usize {
1084 self.max_datagram_size
1085 }
1086
1087 fn pmtud_update_max_datagram_size(&mut self, new_max_datagram_size: usize) {
1088 self.max_datagram_size = new_max_datagram_size;
1089 self.pacer.update_mss(self.max_datagram_size);
1090 }
1091
1092 fn update_max_datagram_size(&mut self, new_max_datagram_size: usize) {
1093 self.pmtud_update_max_datagram_size(
1094 self.max_datagram_size.min(new_max_datagram_size),
1095 )
1096 }
1097
1098 fn on_app_limited(&mut self) {
1100 self.pacer.on_app_limited(self.bytes_in_flight.get())
1101 }
1102
1103 #[cfg(test)]
1104 fn sent_packets_len(&self, epoch: packet::Epoch) -> usize {
1105 self.epochs[epoch].sent_packets.len()
1106 }
1107
1108 #[cfg(test)]
1109 fn in_flight_count(&self, epoch: packet::Epoch) -> usize {
1110 self.epochs[epoch].pkts_in_flight
1111 }
1112
1113 fn bytes_in_flight(&self) -> usize {
1114 self.bytes_in_flight.get()
1115 }
1116
1117 fn bytes_in_flight_duration(&self) -> Duration {
1118 self.bytes_in_flight.get_duration()
1119 }
1120
1121 #[cfg(test)]
1122 fn pacing_rate(&self) -> u64 {
1123 self.pacer
1124 .pacing_rate(self.bytes_in_flight.get(), &self.rtt_stats)
1125 .to_bytes_per_period(Duration::from_secs(1))
1126 }
1127
1128 #[cfg(test)]
1129 fn pto_count(&self) -> u32 {
1130 self.pto_count
1131 }
1132
1133 #[cfg(test)]
1134 fn pkt_thresh(&self) -> Option<u64> {
1135 self.loss_thresh.pkt_thresh()
1136 }
1137
1138 #[cfg(test)]
1139 fn time_thresh(&self) -> f64 {
1140 self.loss_thresh.time_thresh()
1141 }
1142
1143 #[cfg(test)]
1144 fn lost_spurious_count(&self) -> usize {
1145 self.lost_spurious_count
1146 }
1147
1148 #[cfg(test)]
1149 fn detect_lost_packets_for_test(
1150 &mut self, epoch: packet::Epoch, now: Instant,
1151 ) -> (usize, usize) {
1152 let ret = self.detect_and_remove_lost_packets(epoch, now);
1153 self.epochs[epoch].drain_acked_and_lost_packets();
1154 ret
1155 }
1156
1157 #[cfg(test)]
1158 fn largest_sent_pkt_num_on_path(&self, epoch: packet::Epoch) -> Option<u64> {
1159 self.epochs[epoch].test_largest_sent_pkt_num_on_path
1160 }
1161
1162 #[cfg(test)]
1163 fn app_limited(&self) -> bool {
1164 self.pacer.is_app_limited(self.bytes_in_flight.get())
1165 }
1166
1167 fn update_app_limited(&mut self, _v: bool) {
1169 }
1171
1172 fn delivery_rate_update_app_limited(&mut self, _v: bool) {
1174 }
1176
1177 fn update_max_ack_delay(&mut self, max_ack_delay: Duration) {
1178 self.rtt_stats.max_ack_delay = max_ack_delay;
1179 }
1180
1181 fn get_next_release_time(&self) -> ReleaseDecision {
1182 self.pacer.get_next_release_time()
1183 }
1184
1185 fn gcongestion_enabled(&self) -> bool {
1186 true
1187 }
1188
1189 #[cfg(feature = "qlog")]
1190 fn state_str(&self, _now: Instant) -> &'static str {
1191 self.pacer.state_str()
1192 }
1193
1194 #[cfg(feature = "qlog")]
1195 fn get_updated_qlog_event_data(&mut self) -> Option<EventData> {
1196 let qlog_metrics = QlogMetrics {
1197 min_rtt: *self.rtt_stats.min_rtt,
1198 smoothed_rtt: self.rtt(),
1199 latest_rtt: self.rtt_stats.latest_rtt(),
1200 rttvar: self.rtt_stats.rttvar(),
1201 cwnd: self.cwnd() as u64,
1202 bytes_in_flight: self.bytes_in_flight.get() as u64,
1203 ssthresh: self.pacer.ssthresh(),
1204
1205 pacing_rate: Some(
1206 self.pacer
1207 .pacing_rate(self.bytes_in_flight.get(), &self.rtt_stats)
1208 .to_bytes_per_second(),
1209 ),
1210 delivery_rate: Some(self.delivery_rate().to_bytes_per_second()),
1211 send_rate: Some(self.send_rate().to_bytes_per_second()),
1212 ack_rate: Some(self.ack_rate().to_bytes_per_second()),
1213 lost_packets: Some(self.lost_count as u64),
1214 lost_bytes: Some(self.bytes_lost),
1215 pto_count: Some(self.pto_count),
1216 };
1217
1218 self.qlog_metrics.maybe_update(qlog_metrics)
1219 }
1220
1221 #[cfg(feature = "qlog")]
1222 fn get_updated_qlog_cc_state(
1223 &mut self, now: Instant,
1224 ) -> Option<&'static str> {
1225 let cc_state = self.state_str(now);
1226 if cc_state != self.qlog_prev_cc_state {
1227 self.qlog_prev_cc_state = cc_state;
1228 Some(cc_state)
1229 } else {
1230 None
1231 }
1232 }
1233
1234 fn send_quantum(&self) -> usize {
1235 let pacing_rate = self
1236 .pacer
1237 .pacing_rate(self.bytes_in_flight.get(), &self.rtt_stats);
1238
1239 let floor = if pacing_rate < Bandwidth::from_kbits_per_second(1200) {
1240 self.max_datagram_size
1241 } else {
1242 2 * self.max_datagram_size
1243 };
1244
1245 pacing_rate
1246 .to_bytes_per_period(ReleaseDecision::EQUAL_THRESHOLD)
1247 .min(64 * 1024)
1248 .max(floor as u64) as usize
1249 }
1250}
1251
1252impl std::fmt::Debug for GRecovery {
1253 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1254 write!(f, "timer={:?} ", self.loss_detection_timer())?;
1255 write!(f, "rtt_stats={:?} ", self.rtt_stats)?;
1256 write!(f, "bytes_in_flight={} ", self.bytes_in_flight.get())?;
1257 write!(f, "{:?} ", self.pacer)?;
1258 Ok(())
1259 }
1260}
1261
1262#[cfg(test)]
1263mod tests {
1264 use super::*;
1265 use crate::Config;
1266
1267 #[test]
1268 fn loss_threshold() {
1269 let config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1270 let recovery_config = RecoveryConfig::from_config(&config);
1271 assert!(!recovery_config.enable_relaxed_loss_threshold);
1272
1273 let mut loss_thresh = LossThreshold::new(&recovery_config);
1274 assert_eq!(loss_thresh.time_thresh_overhead, None);
1275 assert_eq!(loss_thresh.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1276 assert_eq!(loss_thresh.time_thresh(), INITIAL_TIME_THRESHOLD);
1277
1278 loss_thresh.on_spurious_loss(INITIAL_PACKET_THRESHOLD);
1280 assert_eq!(loss_thresh.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1281 assert_eq!(loss_thresh.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1282
1283 for packet_gap in 0..INITIAL_PACKET_THRESHOLD {
1286 loss_thresh.on_spurious_loss(packet_gap);
1287
1288 assert_eq!(
1290 loss_thresh.pkt_thresh().unwrap(),
1291 INITIAL_PACKET_THRESHOLD
1292 );
1293 assert_eq!(loss_thresh.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1294 }
1295
1296 for packet_gap in INITIAL_PACKET_THRESHOLD + 1..MAX_PACKET_THRESHOLD * 2 {
1300 loss_thresh.on_spurious_loss(packet_gap);
1301
1302 let new_packet_threshold = if packet_gap < MAX_PACKET_THRESHOLD {
1306 packet_gap
1307 } else {
1308 MAX_PACKET_THRESHOLD
1309 };
1310 assert_eq!(loss_thresh.pkt_thresh().unwrap(), new_packet_threshold);
1311 assert_eq!(loss_thresh.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1312 }
1313 assert_eq!(loss_thresh.pkt_thresh().unwrap(), MAX_PACKET_THRESHOLD);
1315 assert_eq!(loss_thresh.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1316
1317 loss_thresh.on_spurious_loss(INITIAL_PACKET_THRESHOLD);
1319 assert_eq!(loss_thresh.pkt_thresh().unwrap(), MAX_PACKET_THRESHOLD);
1320 assert_eq!(loss_thresh.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1321 }
1322
1323 #[test]
1324 fn relaxed_loss_threshold() {
1325 const MAX_TIME_THRESHOLD: f64 = 2.0;
1327
1328 let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1329 config.set_enable_relaxed_loss_threshold(true);
1330 let recovery_config = RecoveryConfig::from_config(&config);
1331 assert!(recovery_config.enable_relaxed_loss_threshold);
1332
1333 let mut loss_thresh = LossThreshold::new(&recovery_config);
1334 assert_eq!(
1335 loss_thresh.time_thresh_overhead,
1336 Some(INITIAL_TIME_THRESHOLD_OVERHEAD)
1337 );
1338 assert_eq!(loss_thresh.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1339 assert_eq!(loss_thresh.time_thresh(), INITIAL_TIME_THRESHOLD);
1340
1341 loss_thresh.on_spurious_loss(INITIAL_PACKET_THRESHOLD);
1343 assert_eq!(loss_thresh.pkt_thresh(), None);
1344 assert_eq!(loss_thresh.time_thresh(), INITIAL_TIME_THRESHOLD);
1345
1346 for subsequent_loss_count in 1..100 {
1348 let new_time_threshold = if subsequent_loss_count <= 3 {
1353 1.0 + INITIAL_TIME_THRESHOLD_OVERHEAD *
1354 2_f64.powi(subsequent_loss_count as i32)
1355 } else {
1356 2.0
1357 };
1358
1359 loss_thresh.on_spurious_loss(subsequent_loss_count);
1360 assert_eq!(loss_thresh.pkt_thresh(), None);
1361 assert_eq!(loss_thresh.time_thresh(), new_time_threshold);
1362 }
1363 assert_eq!(loss_thresh.pkt_thresh(), None);
1365 assert_eq!(loss_thresh.time_thresh(), MAX_TIME_THRESHOLD);
1366 }
1367
1368 #[test]
1369 fn test_high_pto_count_no_panic() {
1370 let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap();
1371 config.set_cc_algorithm(CongestionControlAlgorithm::Bbr2Gcongestion);
1372 let recovery_config = RecoveryConfig::from_config(&config);
1373 let mut r = GRecovery::new(&recovery_config).unwrap();
1374
1375 r.pto_count = 99999;
1376
1377 let handshake_status = HandshakeStatus {
1378 completed: true,
1379 has_handshake_keys: true,
1380 peer_verified_address: true,
1381 };
1382 let now = Instant::now();
1383
1384 let _ = r.pto_time_and_space(handshake_status, now);
1385 }
1386}