1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 */
8
9 #include <quic/congestion_control/NewReno.h>
10
11 #include <folly/portability/GTest.h>
12 #include <quic/common/test/TestUtils.h>
13 #include <quic/fizz/server/handshake/FizzServerQuicHandshakeContext.h>
14
15 using namespace testing;
16
17 namespace quic {
18 namespace test {
19
20 class NewRenoTest : public Test {};
21
createLossEvent(std::vector<std::pair<PacketNum,size_t>> lostPackets)22 CongestionController::LossEvent createLossEvent(
23 std::vector<std::pair<PacketNum, size_t>> lostPackets) {
24 CongestionController::LossEvent loss;
25 auto connId = getTestConnectionId();
26 for (auto packetData : lostPackets) {
27 RegularQuicWritePacket packet(
28 ShortHeader(ProtectionType::KeyPhaseZero, connId, packetData.first));
29 loss.addLostPacket(OutstandingPacket(
30 std::move(packet),
31 Clock::now(),
32 10,
33 0,
34 false,
35 10,
36 0,
37 0,
38 0,
39 LossState(),
40 0));
41 loss.lostBytes = packetData.second;
42 }
43 loss.lostPackets = lostPackets.size();
44 return loss;
45 }
46
createAckEvent(PacketNum largestAcked,uint64_t ackedSize,TimePoint packetSentTime)47 CongestionController::AckEvent createAckEvent(
48 PacketNum largestAcked,
49 uint64_t ackedSize,
50 TimePoint packetSentTime) {
51 RegularQuicWritePacket packet(ShortHeader(
52 ProtectionType::KeyPhaseZero, getTestConnectionId(), largestAcked));
53 CongestionController::AckEvent ack;
54 ack.largestAckedPacket = largestAcked;
55 ack.ackTime = Clock::now();
56 ack.ackedBytes = ackedSize;
57 ack.ackedPackets.push_back(
58 makeAckPacketFromOutstandingPacket(OutstandingPacket(
59 std::move(packet),
60 packetSentTime,
61 ackedSize,
62 0,
63 false,
64 ackedSize,
65 0,
66 0,
67 0,
68 LossState(),
69 0)));
70 return ack;
71 }
72
createPacket(PacketNum packetNum,uint32_t size,TimePoint sendTime,uint64_t inflight=0)73 OutstandingPacket createPacket(
74 PacketNum packetNum,
75 uint32_t size,
76 TimePoint sendTime,
77 uint64_t inflight = 0) {
78 auto connId = getTestConnectionId();
79 RegularQuicWritePacket packet(
80 ShortHeader(ProtectionType::KeyPhaseZero, connId, packetNum));
81 return OutstandingPacket(
82 std::move(packet),
83 sendTime,
84 size,
85 0,
86 false,
87 size,
88 0,
89 inflight,
90 0,
91 LossState(),
92 0);
93 }
94
TEST_F(NewRenoTest,TestLoss)95 TEST_F(NewRenoTest, TestLoss) {
96 QuicServerConnectionState conn(
97 FizzServerQuicHandshakeContext::Builder().build());
98 NewReno reno(conn);
99 EXPECT_TRUE(reno.inSlowStart());
100
101 // Simulate largest sent.
102 conn.lossState.largestSent = 5;
103 PacketNum loss1 = 5;
104 // Lose packet less than previous one now.
105 PacketNum loss2 = 3;
106 // Lose packet greater than previous loss.
107 PacketNum loss3 = 11;
108 reno.onPacketSent(createPacket(loss2, 10, Clock::now()));
109 reno.onPacketSent(createPacket(loss1, 11, Clock::now()));
110 reno.onPacketSent(createPacket(loss3, 20, Clock::now()));
111 EXPECT_EQ(reno.getBytesInFlight(), 41);
112 auto originalWritableBytes = reno.getWritableBytes();
113
114 reno.onPacketAckOrLoss(
115 folly::none, createLossEvent({std::make_pair(loss1, 11)}));
116 EXPECT_EQ(reno.getBytesInFlight(), 30);
117
118 EXPECT_FALSE(reno.inSlowStart());
119 auto newWritableBytes1 = reno.getWritableBytes();
120 EXPECT_LE(newWritableBytes1, originalWritableBytes + 11);
121
122 reno.onPacketAckOrLoss(
123 folly::none, createLossEvent({std::make_pair(loss2, 10)}));
124 auto newWritableBytes2 = reno.getWritableBytes();
125 EXPECT_LE(newWritableBytes2, newWritableBytes1 + 10);
126 EXPECT_EQ(reno.getBytesInFlight(), 20);
127
128 reno.onPacketAckOrLoss(
129 folly::none, createLossEvent({std::make_pair(loss3, 20)}));
130 auto newWritableBytes3 = reno.getWritableBytes();
131 EXPECT_LE(newWritableBytes3, newWritableBytes2 + 20);
132 EXPECT_EQ(reno.getBytesInFlight(), 0);
133 }
134
TEST_F(NewRenoTest,SendMoreThanWritable)135 TEST_F(NewRenoTest, SendMoreThanWritable) {
136 QuicServerConnectionState conn(
137 FizzServerQuicHandshakeContext::Builder().build());
138 NewReno reno(conn);
139 EXPECT_TRUE(reno.inSlowStart());
140
141 PacketNum loss = 10;
142 auto originalWritableBytes = reno.getWritableBytes();
143 reno.onPacketSent(
144 createPacket(loss, originalWritableBytes + 20, Clock::now()));
145 EXPECT_EQ(reno.getBytesInFlight(), originalWritableBytes + 20);
146 EXPECT_EQ(reno.getWritableBytes(), 0);
147 reno.onPacketAckOrLoss(
148 folly::none,
149 createLossEvent({std::make_pair(loss, originalWritableBytes + 20)}));
150 EXPECT_LT(reno.getWritableBytes(), originalWritableBytes);
151 }
152
TEST_F(NewRenoTest,TestSlowStartAck)153 TEST_F(NewRenoTest, TestSlowStartAck) {
154 QuicServerConnectionState conn(
155 FizzServerQuicHandshakeContext::Builder().build());
156 NewReno reno(conn);
157 EXPECT_TRUE(reno.inSlowStart());
158
159 auto originalWritableBytes = reno.getWritableBytes();
160 PacketNum ackPacketNum1 = 10;
161 uint64_t ackedSize = 10;
162
163 auto packet = createPacket(ackPacketNum1, ackedSize, Clock::now());
164 reno.onPacketSent(packet);
165 EXPECT_EQ(reno.getBytesInFlight(), ackedSize);
166 reno.onPacketAckOrLoss(
167 createAckEvent(ackPacketNum1, ackedSize, packet.metadata.time),
168 folly::none);
169 EXPECT_TRUE(reno.inSlowStart());
170 auto newWritableBytes = reno.getWritableBytes();
171
172 EXPECT_EQ(newWritableBytes, originalWritableBytes + ackedSize);
173 }
174
TEST_F(NewRenoTest,TestSteadyStateAck)175 TEST_F(NewRenoTest, TestSteadyStateAck) {
176 QuicServerConnectionState conn(
177 FizzServerQuicHandshakeContext::Builder().build());
178 NewReno reno(conn);
179 EXPECT_TRUE(reno.inSlowStart());
180
181 conn.lossState.largestSent = 5;
182 auto originalWritableBytes = reno.getWritableBytes();
183 PacketNum loss1 = 4;
184 reno.onPacketSent(createPacket(loss1, 10, Clock::now()));
185 reno.onPacketAckOrLoss(
186 folly::none, createLossEvent({std::make_pair(loss1, 10)}));
187 EXPECT_FALSE(reno.inSlowStart());
188 auto newWritableBytes1 = reno.getWritableBytes();
189 EXPECT_LT(newWritableBytes1, originalWritableBytes);
190
191 PacketNum ackPacketNum1 = 4;
192 uint64_t ackedSize = 10;
193 auto packet1 = createPacket(
194 ackPacketNum1, ackedSize, Clock::now() - std::chrono::milliseconds(10));
195 reno.onPacketSent(packet1);
196 reno.onPacketAckOrLoss(
197 createAckEvent(ackPacketNum1, ackedSize, packet1.metadata.time),
198 folly::none);
199 EXPECT_FALSE(reno.inSlowStart());
200
201 auto newWritableBytes2 = reno.getWritableBytes();
202 EXPECT_EQ(newWritableBytes2, newWritableBytes1);
203
204 PacketNum ackPacketNum2 = 6;
205 auto packet2 = createPacket(ackPacketNum2, ackedSize, Clock::now());
206 reno.onPacketSent(packet2);
207 reno.onPacketAckOrLoss(
208 createAckEvent(ackPacketNum2, ackedSize, packet2.metadata.time),
209 folly::none);
210 EXPECT_FALSE(reno.inSlowStart());
211
212 auto newWritableBytes3 = reno.getWritableBytes();
213 EXPECT_EQ(
214 newWritableBytes3,
215 newWritableBytes2 +
216 ((kDefaultUDPSendPacketLen * ackedSize) / newWritableBytes2));
217 }
218
TEST_F(NewRenoTest,TestWritableBytes)219 TEST_F(NewRenoTest, TestWritableBytes) {
220 QuicServerConnectionState conn(
221 FizzServerQuicHandshakeContext::Builder().build());
222 NewReno reno(conn);
223 EXPECT_TRUE(reno.inSlowStart());
224
225 conn.lossState.largestSent = 5;
226 PacketNum ackPacketNum = 6;
227 uint64_t writableBytes = reno.getWritableBytes();
228 reno.onPacketSent(
229 createPacket(ackPacketNum, writableBytes - 10, Clock::now()));
230 EXPECT_EQ(reno.getWritableBytes(), 10);
231 reno.onPacketSent(createPacket(ackPacketNum, 20, Clock::now()));
232 EXPECT_EQ(reno.getWritableBytes(), 0);
233 }
234
TEST_F(NewRenoTest,PersistentCongestion)235 TEST_F(NewRenoTest, PersistentCongestion) {
236 QuicServerConnectionState conn(
237 FizzServerQuicHandshakeContext::Builder().build());
238 NewReno reno(conn);
239 EXPECT_TRUE(reno.inSlowStart());
240
241 conn.lossState.largestSent = 5;
242 PacketNum ackPacketNum = 6;
243 uint32_t ackedSize = 10;
244 auto pkt = createPacket(ackPacketNum, ackedSize, Clock::now());
245 reno.onPacketSent(pkt);
246 CongestionController::LossEvent loss;
247 loss.persistentCongestion = true;
248 loss.addLostPacket(pkt);
249 reno.onPacketAckOrLoss(folly::none, loss);
250 EXPECT_EQ(
251 reno.getWritableBytes(),
252 conn.transportSettings.minCwndInMss * conn.udpSendPacketLen);
253 EXPECT_TRUE(reno.inSlowStart());
254 }
255
TEST_F(NewRenoTest,RemoveBytesWithoutLossOrAck)256 TEST_F(NewRenoTest, RemoveBytesWithoutLossOrAck) {
257 QuicServerConnectionState conn(
258 FizzServerQuicHandshakeContext::Builder().build());
259 NewReno reno(conn);
260 EXPECT_TRUE(reno.inSlowStart());
261
262 auto originalWritableBytes = reno.getWritableBytes();
263 conn.lossState.largestSent = 5;
264 PacketNum ackPacketNum = 6;
265 uint32_t ackedSize = 10;
266 reno.onPacketSent(createPacket(ackPacketNum, ackedSize, Clock::now()));
267 reno.onRemoveBytesFromInflight(2);
268 EXPECT_EQ(reno.getWritableBytes(), originalWritableBytes - ackedSize + 2);
269 }
270 } // namespace test
271 } // namespace quic
272