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