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