A Discrete-Event Network Simulator
API
tcp-tx-buffer-test.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation;
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 *
16 */
17
18#include <limits>
19#include "ns3/test.h"
20#include "ns3/tcp-tx-buffer.h"
21#include "ns3/packet.h"
22#include "ns3/simulator.h"
23#include "ns3/log.h"
24
25using namespace ns3;
26
27NS_LOG_COMPONENT_DEFINE ("TcpTxBufferTestSuite");
28
36{
37public:
40
41private:
42 virtual void DoRun (void);
43 virtual void DoTeardown (void);
44
46 void TestIsLost ();
48 void TestNewBlock ();
52 void TestNextSeg ();
60 uint32_t GetRWnd (void) const;
61};
62
64 : TestCase ("TcpTxBuffer Test")
65{
66}
67
68void
70{
71 Simulator::Schedule (Seconds (0.0), &TcpTxBufferTestCase::TestIsLost, this);
72 /*
73 * Cases for new block:
74 * -> is exactly the same as stored
75 * -> starts over the boundary, but ends earlier
76 * -> starts over the boundary, but ends after
77 */
78 Simulator::Schedule (Seconds (0.0), &TcpTxBufferTestCase::TestNewBlock, this);
79
80 /*
81 * Cases for transmitted block:
82 * -> is exactly the same as previous
83 * -> starts over the boundary, but ends earlier
84 * -> starts over the boundary, but ends after
85 * -> starts inside a packet, ends right
86 * -> starts inside a packet, ends earlier in the same packet
87 * -> starts inside a packet, ends in another packet
88 */
89 Simulator::Schedule (Seconds (0.0),
91 Simulator::Schedule (Seconds (0.0),
93
94 /*
95 * Case for transmitted block:
96 * -> transmitted packets are marked differently for m_lost under some scenarios
97 * -> packets could be small than MSS when socket buffer is not a multiple of MSS.
98 * -> during retransmission, the sender tries to send a full segment but it
99 * should stop to merge items when they have different values for m_lost.
100 */
101 Simulator::Schedule (Seconds (0.0),
103
104 Simulator::Run ();
105 Simulator::Destroy ();
106}
107
108void
110{
111 Ptr<TcpTxBuffer> txBuf = CreateObject<TcpTxBuffer> ();
112 txBuf->SetRWndCallback (MakeCallback (&TcpTxBufferTestCase::GetRWnd, this));
113 SequenceNumber32 head (1);
114 txBuf->SetHeadSequence (head);
116 Ptr<TcpOptionSack> sack = CreateObject<TcpOptionSack> ();
117 txBuf->SetSegmentSize (1000);
118 txBuf->SetDupAckThresh (3);
119
120 txBuf->Add(Create<Packet> (10000));
121
122 for (uint8_t i = 0; i <10 ; ++i)
123 txBuf->CopyFromSequence (1000, SequenceNumber32((i*1000)+1));
124
125 for (uint8_t i = 0; i < 10 ; ++i)
126 NS_TEST_ASSERT_MSG_EQ (txBuf->IsLost(SequenceNumber32((i*1000)+1)), false,
127 "Lost is true, but it's not");
128
129 sack->AddSackBlock (TcpOptionSack::SackBlock (SequenceNumber32 (1001), SequenceNumber32 (2001)));
130 txBuf->Update(sack->GetSackList());
131
132 for (uint8_t i = 0; i < 10 ; ++i)
133 NS_TEST_ASSERT_MSG_EQ (txBuf->IsLost(SequenceNumber32((i*1000)+1)), false,
134 "Lost is true, but it's not");
135
136 sack->AddSackBlock (TcpOptionSack::SackBlock (SequenceNumber32 (2001), SequenceNumber32 (3001)));
137 txBuf->Update(sack->GetSackList());
138
139 for (uint8_t i = 0; i < 10 ; ++i)
140 NS_TEST_ASSERT_MSG_EQ (txBuf->IsLost(SequenceNumber32((i*1000)+1)), false,
141 "Lost is true, but it's not");
142
143 sack->AddSackBlock (TcpOptionSack::SackBlock (SequenceNumber32 (3001), SequenceNumber32 (4001)));
144 txBuf->Update(sack->GetSackList());
145
146 NS_TEST_ASSERT_MSG_EQ (txBuf->IsLost(SequenceNumber32(1)), true,
147 "Lost is true, but it's not");
148
149 for (uint8_t i = 1; i < 10 ; ++i)
150 NS_TEST_ASSERT_MSG_EQ (txBuf->IsLost(SequenceNumber32((i*1000)+1)), false,
151 "Lost is true, but it's not");
152
153
154}
155
158{
159 // Assume unlimited receiver window
161}
162
163void
165{
166 Ptr<TcpTxBuffer> txBuf = CreateObject<TcpTxBuffer> ();;
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;
175 Ptr<TcpOptionSack> sack = CreateObject<TcpOptionSack> ();
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), false,
179 "NextSeq should not be returned at the beginning");
180
181 txBuf->SetHeadSequence (head);
182 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), false,
183 "NextSeq should not be returned with no data");
184
185 // Add a single, 30000-bytes long, packet
186 txBuf->Add (Create<Packet> (30000));
187 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), true,
188 "No NextSeq with data at beginning");
189 NS_TEST_ASSERT_MSG_EQ (ret.GetValue (), head.GetValue (),
190 "Different NextSeq than expected at the beginning");
191
192 // Simulate sending 100 packets, 150 bytes long each, from seq 1
193 for (uint32_t i=0; i<100; ++i)
194 {
195 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), true,
196 "No NextSeq with data while \"transmitting\"");
197 NS_TEST_ASSERT_MSG_EQ (ret, head + (segmentSize * i),
198 "Different NextSeq than expected while \"transmitting\"");
199 txBuf->CopyFromSequence (segmentSize, ret);
200 }
201
202 // Ok, now simulate we lost the first segment [1;151], and that we have
203 // limited transmit. NextSeg should return (up to dupThresh-1) new pieces of data
204 SequenceNumber32 lastRet = ret; // This is like m_highTx
205 for (uint32_t i=1; i<dupThresh; ++i) // iterate dupThresh-1 times (limited transmit)
206 {
207 SequenceNumber32 begin = head + (segmentSize * i);
208 SequenceNumber32 end = begin + segmentSize;
209 sack->AddSackBlock (TcpOptionSack::SackBlock (begin, end));
210 txBuf->Update (sack->GetSackList ());
211
212 // new data expected and sent
213 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), true,
214 "No NextSeq with SACK block while \"transmitting\"");
215 NS_TEST_ASSERT_MSG_EQ (ret, lastRet + segmentSize,
216 "Different NextSeq than expected in limited transmit");
217 txBuf->CopyFromSequence (segmentSize, ret);
218 sack->ClearSackList ();
219 lastRet = ret;
220 }
221
222 // Limited transmit was ok; now there is the dupThresh-th dupack.
223 // Now we need to retransmit the first block..
224 sack->AddSackBlock (TcpOptionSack::SackBlock (head + (segmentSize * (dupThresh)),
225 head + (segmentSize * (dupThresh)) + segmentSize));
226 txBuf->Update (sack->GetSackList ());
227 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), true,
228 "No NextSeq with SACK block for Fast Recovery");
229 NS_TEST_ASSERT_MSG_EQ (ret, head,
230 "Different NextSeq than expected for Fast Recovery");
231 txBuf->CopyFromSequence (segmentSize, ret);
232 sack->ClearSackList ();
233
234 // Fast Retransmission was ok; now check some additional dupacks.
235 for (uint32_t i=1; i<=4; ++i)
236 {
237 sack->AddSackBlock (TcpOptionSack::SackBlock (head + (segmentSize * (dupThresh+i)),
238 head + (segmentSize * (dupThresh+i)) + segmentSize));
239 txBuf->Update (sack->GetSackList ());
240 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), true,
241 "No NextSeq with SACK block after recv dupacks in FR");
242 NS_TEST_ASSERT_MSG_EQ (ret, lastRet + segmentSize,
243 "Different NextSeq than expected after recv dupacks in FR");
244 txBuf->CopyFromSequence (segmentSize, ret);
245 sack->ClearSackList ();
246 lastRet = ret;
247 }
248
249 // Well now we receive a partial ACK, corresponding to the segment we retransmitted.
250 // Unfortunately, the next one is lost as well; but NextSeg should be smart enough
251 // to give us the next segment (head + segmentSize) to retransmit.
252 /* In this particular case, we are checking the fact that we have badly crafted
253 * the SACK blocks. Talking in segment, we transmitted 1,2,3,4,5 ... and then
254 * received dupack for 1. While receiving these, we crafted SACK block in the
255 * way that 2,3,4,... were correctly received. Now, if we receive an ACK for 2,
256 * we clearly crafted the corresponding ACK wrongly. TcpTxBuffer should be able
257 * to "backoff" that flag on its HEAD (segment 2). We still don't know for segment
258 * 3,4 .. so keep them.
259 */
260 head = head + segmentSize;
261 txBuf->DiscardUpTo (head);
262
263 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), true,
264 "No NextSeq with SACK block after receiving partial ACK");
265 NS_TEST_ASSERT_MSG_EQ (ret, head,
266 "Different NextSeq than expected after receiving partial ACK ");
267 txBuf->CopyFromSequence (segmentSize, ret);
268
269 // Now, check for one more dupack...
270 sack->AddSackBlock (TcpOptionSack::SackBlock (head + (segmentSize * (dupThresh+6)),
271 head + (segmentSize * (dupThresh+6)) + segmentSize));
272 txBuf->Update (sack->GetSackList ());
273 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), true,
274 "No NextSeq with SACK block after recv dupacks after partial ack");
275 NS_TEST_ASSERT_MSG_EQ (ret, lastRet + segmentSize,
276 "Different NextSeq than expected after recv dupacks after partial ack");
277 txBuf->CopyFromSequence (segmentSize, ret);
278 sack->ClearSackList ();
279 head = lastRet = ret + segmentSize;
280
281 // And now ack everything we sent to date!
282 txBuf->DiscardUpTo (head);
283
284 // And continue normally until the end
285 for (uint32_t i=0; i<93; ++i)
286 {
287 NS_TEST_ASSERT_MSG_EQ (txBuf->NextSeg (&ret, &retHigh, false), true,
288 "No NextSeq with data while \"transmitting\"");
289 NS_TEST_ASSERT_MSG_EQ (ret, head + (segmentSize * i),
290 "Different NextSeq than expected while \"transmitting\"");
291 txBuf->CopyFromSequence (segmentSize, ret);
292 }
293
294 txBuf->DiscardUpTo (ret+segmentSize);
295 NS_TEST_ASSERT_MSG_EQ (txBuf->Size (), 0,
296 "Data inside the buffer");
297}
298
299void
301{
302 // Manually recreating all the conditions
303 Ptr<TcpTxBuffer> txBuf = CreateObject<TcpTxBuffer> ();
304 txBuf->SetRWndCallback (MakeCallback (&TcpTxBufferTestCase::GetRWnd, this));
305 txBuf->SetHeadSequence (SequenceNumber32 (1));
306 txBuf->SetSegmentSize (100);
307
308 // get a packet which is exactly the same stored
309 Ptr<Packet> p1 = Create<Packet> (100);
310 txBuf->Add (p1);
311
312 NS_TEST_ASSERT_MSG_EQ (txBuf->SizeFromSequence (SequenceNumber32 (1)), 100,
313 "TxBuf miscalculates size");
314 NS_TEST_ASSERT_MSG_EQ (txBuf->BytesInFlight (), 0,
315 "TxBuf miscalculates size of in flight segments");
316
317 Ptr<Packet> ret = txBuf->CopyFromSequence (100, SequenceNumber32 (1))->GetPacketCopy ();
318 NS_TEST_ASSERT_MSG_EQ (ret->GetSize (), 100,
319 "Returned packet has different size than requested");
320 NS_TEST_ASSERT_MSG_EQ (txBuf->SizeFromSequence (SequenceNumber32 (1)), 100,
321 "TxBuf miscalculates size");
322 NS_TEST_ASSERT_MSG_EQ (txBuf->BytesInFlight (), 100,
323 "TxBuf miscalculates size of in flight segments");
324
325 txBuf->DiscardUpTo (SequenceNumber32 (101));
326 NS_TEST_ASSERT_MSG_EQ (txBuf->SizeFromSequence (SequenceNumber32 (101)), 0,
327 "TxBuf miscalculates size");
328 NS_TEST_ASSERT_MSG_EQ (txBuf->BytesInFlight (), 0,
329 "TxBuf miscalculates size of in flight segments");
330
331 // starts over the boundary, but ends earlier
332
333 Ptr<Packet> p2 = Create<Packet> (100);
334 txBuf->Add (p2);
335
336 ret = txBuf->CopyFromSequence (50, SequenceNumber32 (101))->GetPacketCopy ();
337 NS_TEST_ASSERT_MSG_EQ (ret->GetSize (), 50,
338 "Returned packet has different size than requested");
339 NS_TEST_ASSERT_MSG_EQ (txBuf->SizeFromSequence (SequenceNumber32 (151)), 50,
340 "TxBuf miscalculates size");
341 NS_TEST_ASSERT_MSG_EQ (txBuf->BytesInFlight (), 50,
342 "TxBuf miscalculates size of in flight segments");
343
344 // starts over the boundary, but ends after
345 Ptr<Packet> p3 = Create<Packet> (100);
346 txBuf->Add (p3);
347
348 ret = txBuf->CopyFromSequence (70, SequenceNumber32 (151))->GetPacketCopy ();
349 NS_TEST_ASSERT_MSG_EQ (ret->GetSize (), 70,
350 "Returned packet has different size than requested");
351 NS_TEST_ASSERT_MSG_EQ (txBuf->SizeFromSequence (SequenceNumber32 (221)), 80,
352 "TxBuf miscalculates size");
353 NS_TEST_ASSERT_MSG_EQ (txBuf->BytesInFlight (), 120,
354 "TxBuf miscalculates size of in flight segments");
355
356 ret = txBuf->CopyFromSequence (3000, SequenceNumber32 (221))->GetPacketCopy ();
357 NS_TEST_ASSERT_MSG_EQ (ret->GetSize (), 80,
358 "Returned packet has different size than requested");
359 NS_TEST_ASSERT_MSG_EQ (txBuf->SizeFromSequence (SequenceNumber32 (301)), 0,
360 "TxBuf miscalculates size");
361 NS_TEST_ASSERT_MSG_EQ (txBuf->BytesInFlight (), 200,
362 "TxBuf miscalculates size of in flight segments");
363
364 // Clear everything
365 txBuf->DiscardUpTo (SequenceNumber32 (381));
366 NS_TEST_ASSERT_MSG_EQ (txBuf->Size (), 0,
367 "Size is different than expected");
368}
369
370void
372{
373 TcpTxBuffer txBuf;
374 SequenceNumber32 head (1);
375 txBuf.SetHeadSequence (head);
376 txBuf.SetSegmentSize (2000);
377
378 txBuf.Add(Create<Packet> (2000));
379 txBuf.CopyFromSequence (1000, SequenceNumber32(1));
380 txBuf.CopyFromSequence (1000, SequenceNumber32(1001));
381 txBuf.MarkHeadAsLost();
382
383 // GetTransmittedSegment() will be called and handle the case that two items
384 // have different m_lost value.
385 txBuf.CopyFromSequence (2000, SequenceNumber32(1));
386}
387
388void
390{
391}
392
393void
395{
396}
397
405{
406public:
408 : TestSuite ("tcp-tx-buffer", UNIT)
409 {
410 AddTestCase (new TcpTxBufferTestCase, TestCase::QUICK);
411 }
412};
413
#define max(a, b)
Definition: 80211b.c:43
The TcpTxBuffer Test.
virtual void DoRun(void)
Implementation to actually run this TestCase.
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 TestNewBlock()
Test the generation of an unsent block.
uint32_t GetRWnd(void) const
Callback to provide a value of receiver window.
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
void TestIsLost()
Test if a segment is really set as lost.
void TestNextSeg()
Test the generation of the "next" block.
TcpTxBufferTestCase()
Constructor.
the TestSuite for the TcpTxBuffer test case
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:856
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
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:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1197
uint32_t segmentSize
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
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:141
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1648
static TcpTxBufferTestSuite g_tcpTxBufferTestSuite
Static variable for test initialization.