1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4 // option. This file may not be copied, modified, or distributed
5 // except according to those terms.
6
7 use super::super::{ConnectionParameters, ACK_RATIO_SCALE};
8 use super::{
9 ack_bytes, connect_rtt_idle, default_client, default_server, fill_cwnd, increase_cwnd,
10 induce_persistent_congestion, new_client, new_server, send_something, DEFAULT_RTT,
11 };
12 use crate::stream_id::StreamType;
13
14 use std::mem;
15 use std::time::Duration;
16 use test_fixture::{addr_v4, assertions};
17
18 /// With the default RTT here (100ms) and default ratio (4), endpoints won't send
19 /// `ACK_FREQUENCY` as the ACK delay isn't different enough from the default.
20 #[test]
ack_rate_default()21 fn ack_rate_default() {
22 let mut client = default_client();
23 let mut server = default_server();
24 let _ = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
25
26 assert_eq!(client.stats().frame_tx.ack_frequency, 0);
27 assert_eq!(server.stats().frame_tx.ack_frequency, 0);
28 }
29
30 /// When the congestion window increases, the rate doesn't change.
31 #[test]
ack_rate_slow_start()32 fn ack_rate_slow_start() {
33 let mut client = default_client();
34 let mut server = default_server();
35 let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
36
37 // Increase the congestion window a few times.
38 let stream = client.stream_create(StreamType::UniDi).unwrap();
39 let now = increase_cwnd(&mut client, &mut server, stream, now);
40 let now = increase_cwnd(&mut client, &mut server, stream, now);
41 let _ = increase_cwnd(&mut client, &mut server, stream, now);
42
43 // The client should not have sent an ACK_FREQUENCY frame, even
44 // though the value would have updated.
45 assert_eq!(client.stats().frame_tx.ack_frequency, 0);
46 assert_eq!(server.stats().frame_rx.ack_frequency, 0);
47 }
48
49 /// When the congestion window decreases, a frame is sent.
50 #[test]
ack_rate_exit_slow_start()51 fn ack_rate_exit_slow_start() {
52 let mut client = default_client();
53 let mut server = default_server();
54 let now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
55
56 // Increase the congestion window a few times, enough that after a loss,
57 // there are enough packets in the window to increase the packet
58 // count in ACK_FREQUENCY frames.
59 let stream = client.stream_create(StreamType::UniDi).unwrap();
60 let now = increase_cwnd(&mut client, &mut server, stream, now);
61 let now = increase_cwnd(&mut client, &mut server, stream, now);
62
63 // Now fill the congestion window and drop the first packet.
64 let (mut pkts, mut now) = fill_cwnd(&mut client, stream, now);
65 pkts.remove(0);
66
67 // After acknowledging the other packets the client will notice the loss.
68 now += DEFAULT_RTT / 2;
69 let ack = ack_bytes(&mut server, stream, pkts, now);
70
71 // Receiving the ACK will cause the client to reduce its congestion window
72 // and to send ACK_FREQUENCY.
73 now += DEFAULT_RTT / 2;
74 assert_eq!(client.stats().frame_tx.ack_frequency, 0);
75 let af = client.process(Some(ack), now).dgram();
76 assert!(af.is_some());
77 assert_eq!(client.stats().frame_tx.ack_frequency, 1);
78 }
79
80 /// When the congestion window collapses, `ACK_FREQUENCY` is updated.
81 #[test]
ack_rate_persistent_congestion()82 fn ack_rate_persistent_congestion() {
83 // Use a configuration that results in the value being set after exiting
84 // the handshake.
85 const RTT: Duration = Duration::from_millis(3);
86 let mut client = new_client(ConnectionParameters::default().ack_ratio(ACK_RATIO_SCALE));
87 let mut server = default_server();
88 let now = connect_rtt_idle(&mut client, &mut server, RTT);
89
90 // The client should have sent a frame.
91 assert_eq!(client.stats().frame_tx.ack_frequency, 1);
92
93 // Now crash the congestion window.
94 let stream = client.stream_create(StreamType::UniDi).unwrap();
95 let (dgrams, mut now) = fill_cwnd(&mut client, stream, now);
96 now += RTT / 2;
97 mem::drop(ack_bytes(&mut server, stream, dgrams, now));
98
99 let now = induce_persistent_congestion(&mut client, &mut server, stream, now);
100
101 // The client sends a second ACK_FREQUENCY frame with an increased rate.
102 let af = client.process_output(now).dgram();
103 assert!(af.is_some());
104 assert_eq!(client.stats().frame_tx.ack_frequency, 2);
105 }
106
107 /// Validate that the configuration works for the client.
108 #[test]
ack_rate_client_one_rtt()109 fn ack_rate_client_one_rtt() {
110 // This has to be chosen so that the resulting ACK delay is between 1ms and 50ms.
111 // We also have to avoid values between 20..30ms (approximately). The default
112 // maximum ACK delay is 25ms and an ACK_FREQUENCY frame won't be sent when the
113 // change to the maximum ACK delay is too small.
114 const RTT: Duration = Duration::from_millis(3);
115 let mut client = new_client(ConnectionParameters::default().ack_ratio(ACK_RATIO_SCALE));
116 let mut server = default_server();
117 let mut now = connect_rtt_idle(&mut client, &mut server, RTT);
118
119 // A single packet from the client will cause the server to engage its delayed
120 // acknowledgment timer, which should now be equal to RTT.
121 let d = send_something(&mut client, now);
122 now += RTT / 2;
123 let delay = server.process(Some(d), now).callback();
124 assert_eq!(delay, RTT);
125
126 assert_eq!(client.stats().frame_tx.ack_frequency, 1);
127 }
128
129 /// Validate that the configuration works for the server.
130 #[test]
ack_rate_server_half_rtt()131 fn ack_rate_server_half_rtt() {
132 const RTT: Duration = Duration::from_millis(10);
133 let mut client = default_client();
134 let mut server = new_server(ConnectionParameters::default().ack_ratio(ACK_RATIO_SCALE * 2));
135 let mut now = connect_rtt_idle(&mut client, &mut server, RTT);
136
137 let d = send_something(&mut server, now);
138 now += RTT / 2;
139 let delay = client.process(Some(d), now).callback();
140 assert_eq!(delay, RTT / 2);
141
142 assert_eq!(server.stats().frame_tx.ack_frequency, 1);
143 }
144
145 /// ACK delay calculations are path-specific,
146 /// so check that they can be sent on new paths.
147 #[test]
migrate_ack_delay()148 fn migrate_ack_delay() {
149 // Have the client send ACK_FREQUENCY frames at a normal-ish rate.
150 let mut client = new_client(ConnectionParameters::default().ack_ratio(ACK_RATIO_SCALE));
151 let mut server = default_server();
152 let mut now = connect_rtt_idle(&mut client, &mut server, DEFAULT_RTT);
153
154 client
155 .migrate(Some(addr_v4()), Some(addr_v4()), true, now)
156 .unwrap();
157
158 let client1 = send_something(&mut client, now);
159 assertions::assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
160 let client2 = send_something(&mut client, now);
161 assertions::assert_v4_path(&client2, false); // Doesn't. Is dropped.
162 now += DEFAULT_RTT / 2;
163 server.process_input(client1, now);
164
165 let stream = client.stream_create(StreamType::UniDi).unwrap();
166 let now = increase_cwnd(&mut client, &mut server, stream, now);
167 let now = increase_cwnd(&mut client, &mut server, stream, now);
168 let now = increase_cwnd(&mut client, &mut server, stream, now);
169
170 // Now lose a packet and force the client to update
171 let (mut pkts, mut now) = fill_cwnd(&mut client, stream, now);
172 pkts.remove(0);
173 now += DEFAULT_RTT / 2;
174 let ack = ack_bytes(&mut server, stream, pkts, now);
175
176 // After noticing this new loss, the client sends ACK_FREQUENCY.
177 // It has sent a few before (as we dropped `client2`), so ignore those.
178 let ad_before = client.stats().frame_tx.ack_frequency;
179 let af = client.process(Some(ack), now).dgram();
180 assert!(af.is_some());
181 assert_eq!(client.stats().frame_tx.ack_frequency, ad_before + 1);
182 }
183