quinn_proto/connection/
paths.rs1use std::{cmp, time::Duration, time::Instant};
2use scionnet::SocketAddr;
3
4use super::{mtud::MtuDiscovery, pacing::Pacer};
5use crate::{config::MtuDiscoveryConfig, congestion, packet::SpaceId, TIMER_GRANULARITY};
6
7pub(super) struct PathData {
9 pub(super) remote: SocketAddr,
10 pub(super) rtt: RttEstimator,
11 pub(super) sending_ecn: bool,
13 pub(super) congestion: Box<dyn congestion::Controller>,
15 pub(super) pacing: Pacer,
17 pub(super) challenge: Option<u64>,
18 pub(super) challenge_pending: bool,
19 pub(super) validated: bool,
24 pub(super) total_sent: u64,
26 pub(super) total_recvd: u64,
28 pub(super) mtud: MtuDiscovery,
30 pub(super) first_packet_after_rtt_sample: Option<(SpaceId, u64)>,
34}
35
36impl PathData {
37 pub(super) fn new(
38 remote: SocketAddr,
39 initial_rtt: Duration,
40 congestion: Box<dyn congestion::Controller>,
41 initial_mtu: u16,
42 min_mtu: u16,
43 peer_max_udp_payload_size: Option<u16>,
44 mtud_config: Option<MtuDiscoveryConfig>,
45 now: Instant,
46 validated: bool,
47 ) -> Self {
48 Self {
49 remote,
50 rtt: RttEstimator::new(initial_rtt),
51 sending_ecn: true,
52 pacing: Pacer::new(initial_rtt, congestion.initial_window(), initial_mtu, now),
53 congestion,
54 challenge: None,
55 challenge_pending: false,
56 validated,
57 total_sent: 0,
58 total_recvd: 0,
59 mtud: mtud_config.map_or(MtuDiscovery::disabled(initial_mtu, min_mtu), |config| {
60 MtuDiscovery::new(initial_mtu, min_mtu, peer_max_udp_payload_size, config)
61 }),
62 first_packet_after_rtt_sample: None,
63 }
64 }
65
66 pub(super) fn from_previous(remote: SocketAddr, prev: &Self, now: Instant) -> Self {
67 let congestion = prev.congestion.clone_box();
68 let smoothed_rtt = prev.rtt.get();
69 Self {
70 remote,
71 rtt: prev.rtt,
72 pacing: Pacer::new(smoothed_rtt, congestion.window(), prev.current_mtu(), now),
73 sending_ecn: true,
74 congestion,
75 challenge: None,
76 challenge_pending: false,
77 validated: false,
78 total_sent: 0,
79 total_recvd: 0,
80 mtud: prev.mtud.clone(),
81 first_packet_after_rtt_sample: prev.first_packet_after_rtt_sample,
82 }
83 }
84
85 pub(super) fn anti_amplification_blocked(&self, bytes_to_send: u64) -> bool {
88 !self.validated && self.total_recvd * 3 < self.total_sent + bytes_to_send
89 }
90
91 pub(super) fn current_mtu(&self) -> u16 {
93 self.mtud.current_mtu()
94 }
95}
96
97#[derive(Copy, Clone)]
99pub struct RttEstimator {
100 latest: Duration,
102 smoothed: Option<Duration>,
104 var: Duration,
106 min: Duration,
108}
109
110impl RttEstimator {
111 fn new(initial_rtt: Duration) -> Self {
112 Self {
113 latest: initial_rtt,
114 smoothed: None,
115 var: initial_rtt / 2,
116 min: initial_rtt,
117 }
118 }
119
120 pub fn get(&self) -> Duration {
122 self.smoothed.unwrap_or(self.latest)
123 }
124
125 pub fn conservative(&self) -> Duration {
130 self.get().max(self.latest)
131 }
132
133 pub fn min(&self) -> Duration {
135 self.min
136 }
137
138 pub(crate) fn pto_base(&self) -> Duration {
140 self.get() + cmp::max(4 * self.var, TIMER_GRANULARITY)
141 }
142
143 pub(crate) fn update(&mut self, ack_delay: Duration, rtt: Duration) {
144 self.latest = rtt;
145 self.min = cmp::min(self.min, self.latest);
147 if let Some(smoothed) = self.smoothed {
149 let adjusted_rtt = if self.min + ack_delay <= self.latest {
150 self.latest - ack_delay
151 } else {
152 self.latest
153 };
154 let var_sample = if smoothed > adjusted_rtt {
155 smoothed - adjusted_rtt
156 } else {
157 adjusted_rtt - smoothed
158 };
159 self.var = (3 * self.var + var_sample) / 4;
160 self.smoothed = Some((7 * smoothed + adjusted_rtt) / 8);
161 } else {
162 self.smoothed = Some(self.latest);
163 self.var = self.latest / 2;
164 self.min = self.latest;
165 }
166 }
167}