A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tcp-tx-buffer-test.cc
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: GPL-2.0-only
3 *
4 */
5
6#include "ns3/log.h"
7#include "ns3/packet.h"
8#include "ns3/simulator.h"
9#include "ns3/tcp-tx-buffer.h"
10#include "ns3/test.h"
11
12#include <limits>
13
14using namespace ns3;
15
16NS_LOG_COMPONENT_DEFINE("TcpTxBufferTestSuite");
17
18/**
19 * \ingroup internet-test
20 * \ingroup tests
21 *
22 * \brief The TcpTxBuffer Test
23 */
25{
26 public:
27 /** \brief Constructor */
29
30 private:
31 void DoRun() override;
32 void DoTeardown() override;
33
34 /** \brief Test if a segment is really set as lost */
35 void TestIsLost();
36 /** \brief Test the generation of an unsent block */
37 void TestNewBlock();
38 /** \brief Test the generation of a previously sent block */
40 /** \brief Test the generation of the "next" block */
41 void TestNextSeg();
42 /** \brief Test the logic of merging items in GetTransmittedSegment()
43 * which is triggered by CopyFromSequence()*/
45 /**
46 * \brief Callback to provide a value of receiver window
47 * \returns the receiver window size
48 */
49 uint32_t GetRWnd() const;
50};
51
53 : TestCase("TcpTxBuffer Test")
54{
55}
56
57void
59{
61 /*
62 * Cases for new block:
63 * -> is exactly the same as stored
64 * -> starts over the boundary, but ends earlier
65 * -> starts over the boundary, but ends after
66 */
68
69 /*
70 * Cases for transmitted block:
71 * -> is exactly the same as previous
72 * -> starts over the boundary, but ends earlier
73 * -> starts over the boundary, but ends after
74 * -> starts inside a packet, ends right
75 * -> starts inside a packet, ends earlier in the same packet
76 * -> starts inside a packet, ends in another packet
77 */
80
81 /*
82 * Case for transmitted block:
83 * -> transmitted packets are marked differently for m_lost under some scenarios
84 * -> packets could be small than MSS when socket buffer is not a multiple of MSS.
85 * -> during retransmission, the sender tries to send a full segment but it
86 * should stop to merge items when they have different values for m_lost.
87 */
90 this);
91
94}
95
96void
98{
100 txBuf->SetRWndCallback(MakeCallback(&TcpTxBufferTestCase::GetRWnd, this));
101 SequenceNumber32 head(1);
102 txBuf->SetHeadSequence(head);
105 txBuf->SetSegmentSize(1000);
106 txBuf->SetDupAckThresh(3);
107
108 txBuf->Add(Create<Packet>(10000));
109
110 for (uint8_t i = 0; i < 10; ++i)
111 {
112 txBuf->CopyFromSequence(1000, SequenceNumber32((i * 1000) + 1));
113 }
114
115 for (uint8_t i = 0; i < 10; ++i)
116 {
117 NS_TEST_ASSERT_MSG_EQ(txBuf->IsLost(SequenceNumber32((i * 1000) + 1)),
118 false,
119 "Lost is true, but it's not");
120 }
121
122 sack->AddSackBlock(TcpOptionSack::SackBlock(SequenceNumber32(1001), SequenceNumber32(2001)));
123 txBuf->Update(sack->GetSackList());
124
125 for (uint8_t i = 0; i < 10; ++i)
126 {
127 NS_TEST_ASSERT_MSG_EQ(txBuf->IsLost(SequenceNumber32((i * 1000) + 1)),
128 false,
129 "Lost is true, but it's not");
130 }
131
132 sack->AddSackBlock(TcpOptionSack::SackBlock(SequenceNumber32(2001), SequenceNumber32(3001)));
133 txBuf->Update(sack->GetSackList());
134
135 for (uint8_t i = 0; i < 10; ++i)
136 {
137 NS_TEST_ASSERT_MSG_EQ(txBuf->IsLost(SequenceNumber32((i * 1000) + 1)),
138 false,
139 "Lost is true, but it's not");
140 }
141
142 sack->AddSackBlock(TcpOptionSack::SackBlock(SequenceNumber32(3001), SequenceNumber32(4001)));
143 txBuf->Update(sack->GetSackList());
144
145 NS_TEST_ASSERT_MSG_EQ(txBuf->IsLost(SequenceNumber32(1)), true, "Lost is true, but it's not");
146
147 for (uint8_t i = 1; i < 10; ++i)
148 {
149 NS_TEST_ASSERT_MSG_EQ(txBuf->IsLost(SequenceNumber32((i * 1000) + 1)),
150 false,
151 "Lost is true, but it's not");
152 }
153}
154
157{
158 // Assume unlimited receiver window
159 return std::numeric_limits<uint32_t>::max();
160}
161
162void
164{
166 ;
167 txBuf->SetRWndCallback(MakeCallback(&TcpTxBufferTestCase::GetRWnd, this));
168 SequenceNumber32 head(1);
170 SequenceNumber32 retHigh;
171 txBuf->SetSegmentSize(150);
172 txBuf->SetDupAckThresh(3);
173 uint32_t dupThresh = 3;
174 uint32_t segmentSize = 150;
176
177 // At the beginning the values of dupThresh and segmentSize don't matter
178 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
179 false,
180 "NextSeq should not be returned at the beginning");
181
182 txBuf->SetHeadSequence(head);
183 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
184 false,
185 "NextSeq should not be returned with no data");
186
187 // Add a single, 30000-bytes long, packet
188 txBuf->Add(Create<Packet>(30000));
189 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
190 true,
191 "No NextSeq with data at beginning");
193 head.GetValue(),
194 "Different NextSeq than expected at the beginning");
195
196 // Simulate sending 100 packets, 150 bytes long each, from seq 1
197 for (uint32_t i = 0; i < 100; ++i)
198 {
199 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
200 true,
201 "No NextSeq with data while \"transmitting\"");
203 head + (segmentSize * i),
204 "Different NextSeq than expected while \"transmitting\"");
205 txBuf->CopyFromSequence(segmentSize, ret);
206 }
207
208 // Ok, now simulate we lost the first segment [1;151], and that we have
209 // limited transmit. NextSeg should return (up to dupThresh-1) new pieces of data
210 SequenceNumber32 lastRet = ret; // This is like m_highTx
211 for (uint32_t i = 1; i < dupThresh; ++i) // iterate dupThresh-1 times (limited transmit)
212 {
213 SequenceNumber32 begin = head + (segmentSize * i);
214 SequenceNumber32 end = begin + segmentSize;
215 sack->AddSackBlock(TcpOptionSack::SackBlock(begin, end));
216 txBuf->Update(sack->GetSackList());
217
218 // new data expected and sent
219 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
220 true,
221 "No NextSeq with SACK block while \"transmitting\"");
223 lastRet + segmentSize,
224 "Different NextSeq than expected in limited transmit");
225 txBuf->CopyFromSequence(segmentSize, ret);
226 sack->ClearSackList();
227 lastRet = ret;
228 }
229
230 // Limited transmit was ok; now there is the dupThresh-th dupack.
231 // Now we need to retransmit the first block..
232 sack->AddSackBlock(TcpOptionSack::SackBlock(head + (segmentSize * (dupThresh)),
233 head + (segmentSize * (dupThresh)) + segmentSize));
234 txBuf->Update(sack->GetSackList());
235 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
236 true,
237 "No NextSeq with SACK block for Fast Recovery");
238 NS_TEST_ASSERT_MSG_EQ(ret, head, "Different NextSeq than expected for Fast Recovery");
239 txBuf->CopyFromSequence(segmentSize, ret);
240 sack->ClearSackList();
241
242 // Fast Retransmission was ok; now check some additional dupacks.
243 for (uint32_t i = 1; i <= 4; ++i)
244 {
245 sack->AddSackBlock(
246 TcpOptionSack::SackBlock(head + (segmentSize * (dupThresh + i)),
247 head + (segmentSize * (dupThresh + i)) + segmentSize));
248 txBuf->Update(sack->GetSackList());
249 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
250 true,
251 "No NextSeq with SACK block after recv dupacks in FR");
253 lastRet + segmentSize,
254 "Different NextSeq than expected after recv dupacks in FR");
255 txBuf->CopyFromSequence(segmentSize, ret);
256 sack->ClearSackList();
257 lastRet = ret;
258 }
259
260 // Well now we receive a partial ACK, corresponding to the segment we retransmitted.
261 // Unfortunately, the next one is lost as well; but NextSeg should be smart enough
262 // to give us the next segment (head + segmentSize) to retransmit.
263 /* In this particular case, we are checking the fact that we have badly crafted
264 * the SACK blocks. Talking in segment, we transmitted 1,2,3,4,5 ... and then
265 * received dupack for 1. While receiving these, we crafted SACK block in the
266 * way that 2,3,4,... were correctly received. Now, if we receive an ACK for 2,
267 * we clearly crafted the corresponding ACK wrongly. TcpTxBuffer should be able
268 * to "backoff" that flag on its HEAD (segment 2). We still don't know for segment
269 * 3,4 .. so keep them.
270 */
271 head = head + segmentSize;
272 txBuf->DiscardUpTo(head);
273
274 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
275 true,
276 "No NextSeq with SACK block after receiving partial ACK");
278 head,
279 "Different NextSeq than expected after receiving partial ACK ");
280 txBuf->CopyFromSequence(segmentSize, ret);
281
282 // Now, check for one more dupack...
283 sack->AddSackBlock(
284 TcpOptionSack::SackBlock(head + (segmentSize * (dupThresh + 6)),
285 head + (segmentSize * (dupThresh + 6)) + segmentSize));
286 txBuf->Update(sack->GetSackList());
287 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
288 true,
289 "No NextSeq with SACK block after recv dupacks after partial ack");
291 lastRet + segmentSize,
292 "Different NextSeq than expected after recv dupacks after partial ack");
293 txBuf->CopyFromSequence(segmentSize, ret);
294 sack->ClearSackList();
295 head = lastRet = ret + segmentSize;
296
297 // And now ack everything we sent to date!
298 txBuf->DiscardUpTo(head);
299
300 // And continue normally until the end
301 for (uint32_t i = 0; i < 93; ++i)
302 {
303 NS_TEST_ASSERT_MSG_EQ(txBuf->NextSeg(&ret, &retHigh, false),
304 true,
305 "No NextSeq with data while \"transmitting\"");
307 head + (segmentSize * i),
308 "Different NextSeq than expected while \"transmitting\"");
309 txBuf->CopyFromSequence(segmentSize, ret);
310 }
311
312 txBuf->DiscardUpTo(ret + segmentSize);
313 NS_TEST_ASSERT_MSG_EQ(txBuf->Size(), 0, "Data inside the buffer");
314}
315
316void
318{
319 // Manually recreating all the conditions
321 txBuf->SetRWndCallback(MakeCallback(&TcpTxBufferTestCase::GetRWnd, this));
322 txBuf->SetHeadSequence(SequenceNumber32(1));
323 txBuf->SetSegmentSize(100);
324
325 // get a packet which is exactly the same stored
326 Ptr<Packet> p1 = Create<Packet>(100);
327 txBuf->Add(p1);
328
329 NS_TEST_ASSERT_MSG_EQ(txBuf->SizeFromSequence(SequenceNumber32(1)),
330 100,
331 "TxBuf miscalculates size");
332 NS_TEST_ASSERT_MSG_EQ(txBuf->BytesInFlight(),
333 0,
334 "TxBuf miscalculates size of in flight segments");
335
336 Ptr<Packet> ret = txBuf->CopyFromSequence(100, SequenceNumber32(1))->GetPacketCopy();
337 NS_TEST_ASSERT_MSG_EQ(ret->GetSize(), 100, "Returned packet has different size than requested");
338 NS_TEST_ASSERT_MSG_EQ(txBuf->SizeFromSequence(SequenceNumber32(1)),
339 100,
340 "TxBuf miscalculates size");
341 NS_TEST_ASSERT_MSG_EQ(txBuf->BytesInFlight(),
342 100,
343 "TxBuf miscalculates size of in flight segments");
344
345 txBuf->DiscardUpTo(SequenceNumber32(101));
346 NS_TEST_ASSERT_MSG_EQ(txBuf->SizeFromSequence(SequenceNumber32(101)),
347 0,
348 "TxBuf miscalculates size");
349 NS_TEST_ASSERT_MSG_EQ(txBuf->BytesInFlight(),
350 0,
351 "TxBuf miscalculates size of in flight segments");
352
353 // starts over the boundary, but ends earlier
354
355 Ptr<Packet> p2 = Create<Packet>(100);
356 txBuf->Add(p2);
357
358 ret = txBuf->CopyFromSequence(50, SequenceNumber32(101))->GetPacketCopy();
359 NS_TEST_ASSERT_MSG_EQ(ret->GetSize(), 50, "Returned packet has different size than requested");
360 NS_TEST_ASSERT_MSG_EQ(txBuf->SizeFromSequence(SequenceNumber32(151)),
361 50,
362 "TxBuf miscalculates size");
363 NS_TEST_ASSERT_MSG_EQ(txBuf->BytesInFlight(),
364 50,
365 "TxBuf miscalculates size of in flight segments");
366
367 // starts over the boundary, but ends after
368 Ptr<Packet> p3 = Create<Packet>(100);
369 txBuf->Add(p3);
370
371 ret = txBuf->CopyFromSequence(70, SequenceNumber32(151))->GetPacketCopy();
372 NS_TEST_ASSERT_MSG_EQ(ret->GetSize(), 70, "Returned packet has different size than requested");
373 NS_TEST_ASSERT_MSG_EQ(txBuf->SizeFromSequence(SequenceNumber32(221)),
374 80,
375 "TxBuf miscalculates size");
376 NS_TEST_ASSERT_MSG_EQ(txBuf->BytesInFlight(),
377 120,
378 "TxBuf miscalculates size of in flight segments");
379
380 ret = txBuf->CopyFromSequence(3000, SequenceNumber32(221))->GetPacketCopy();
381 NS_TEST_ASSERT_MSG_EQ(ret->GetSize(), 80, "Returned packet has different size than requested");
382 NS_TEST_ASSERT_MSG_EQ(txBuf->SizeFromSequence(SequenceNumber32(301)),
383 0,
384 "TxBuf miscalculates size");
385 NS_TEST_ASSERT_MSG_EQ(txBuf->BytesInFlight(),
386 200,
387 "TxBuf miscalculates size of in flight segments");
388
389 // Clear everything
390 txBuf->DiscardUpTo(SequenceNumber32(381));
391 NS_TEST_ASSERT_MSG_EQ(txBuf->Size(), 0, "Size is different than expected");
392}
393
394void
396{
397 TcpTxBuffer txBuf;
398 SequenceNumber32 head(1);
399 txBuf.SetHeadSequence(head);
400 txBuf.SetSegmentSize(2000);
401
402 txBuf.Add(Create<Packet>(2000));
403 txBuf.CopyFromSequence(1000, SequenceNumber32(1));
404 txBuf.CopyFromSequence(1000, SequenceNumber32(1001));
405 txBuf.MarkHeadAsLost();
406
407 // GetTransmittedSegment() will be called and handle the case that two items
408 // have different m_lost value.
409 txBuf.CopyFromSequence(2000, SequenceNumber32(1));
410}
411
412void
416
417void
421
422/**
423 * \ingroup internet-test
424 *
425 * \brief the TestSuite for the TcpTxBuffer test case
426 */
428{
429 public:
431 : TestSuite("tcp-tx-buffer", Type::UNIT)
432 {
433 AddTestCase(new TcpTxBufferTestCase, TestCase::Duration::QUICK);
434 }
435};
436
437static TcpTxBufferTestSuite g_tcpTxBufferTestSuite; //!< Static variable for test initialization
The TcpTxBuffer Test.
void TestTransmittedBlock()
Test the generation of a previously sent block.
void TestMergeItemsWhenGetTransmittedSegment()
Test the logic of merging items in GetTransmittedSegment() which is triggered by CopyFromSequence()
void DoRun() override
Implementation to actually run this TestCase.
void TestNewBlock()
Test the generation of an unsent block.
uint32_t GetRWnd() const
Callback to provide a value of receiver window.
void TestIsLost()
Test if a segment is really set as lost.
void TestNextSeg()
Test the generation of the "next" block.
TcpTxBufferTestCase()
Constructor.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
the TestSuite for the TcpTxBuffer test case
Smart pointer class similar to boost::intrusive_ptr.
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static void Run()
Run the simulation.
Definition simulator.cc:167
std::pair< SequenceNumber32, SequenceNumber32 > SackBlock
SACK block definition.
Tcp sender buffer.
bool Add(Ptr< Packet > p)
Append a data packet to the end of the buffer.
void SetSegmentSize(uint32_t segmentSize)
Set the segment size.
TcpTxItem * CopyFromSequence(uint32_t numBytes, const SequenceNumber32 &seq)
Copy data from the range [seq, seq+numBytes) into a packet.
void MarkHeadAsLost()
Mark the head of the sent list as lost.
void SetHeadSequence(const SequenceNumber32 &seq)
Set the head sequence of the buffer.
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
static constexpr auto UNIT
Definition test.h:1291
uint32_t segmentSize
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
static TcpTxBufferTestSuite g_tcpTxBufferTestSuite
Static variable for test initialization.