A Discrete-Event Network Simulator
API
tcp-linux-reno-test.cc
Go to the documentation of this file.
1/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2019 Apoorva Bhargava <apoorvabhargava13@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19#include "ns3/log.h"
20#include "ns3/test.h"
21#include "ns3/simple-channel.h"
22#include "ns3/node.h"
23#include "ns3/config.h"
24#include "ns3/tcp-header.h"
25#include "tcp-general-test.h"
26#include "ns3/tcp-linux-reno.h"
27
28using namespace ns3;
29
30NS_LOG_COMPONENT_DEFINE ("TcpLinuxRenoTest");
31
47class
49{
50public:
63 uint32_t initialCwnd, uint32_t delayedAck,
64 uint32_t expectedCwnd,
65 TypeId& congControl, const std::string &desc);
66
67protected:
68 virtual void CWndTrace (uint32_t oldValue, uint32_t newValue);
69 void QueueDrop (SocketWho who);
70 void PhyDrop (SocketWho who);
71
72 virtual void ConfigureEnvironment ();
73 virtual void ConfigureProperties ();
74 virtual void DoTeardown ();
75
76 bool m_initial;
77
78private:
79 virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
80 virtual void Rx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
88};
89
92 uint32_t packets,
93 uint32_t initialCwnd,
94 uint32_t delayedAck,
95 uint32_t expectedCwnd,
96 TypeId &typeId,
97 const std::string &desc)
98 : TcpGeneralTest (desc),
99 m_initial (true),
100 m_segmentSize (segmentSize),
101 m_packetSize (packetSize),
102 m_packets (packets),
103 m_initialCwnd (initialCwnd),
104 m_delayedAck (delayedAck),
105 m_lastCwnd (0),
106 m_expectedCwnd (expectedCwnd)
107{
108 m_congControlTypeId = typeId;
109}
110
111void
113{
114 TcpGeneralTest::ConfigureEnvironment ();
118}
119
120void
122{
123 TcpGeneralTest::ConfigureProperties ();
128}
129
130void
132{
133 NS_FATAL_ERROR ("Drop on the queue; cannot validate slow start");
134}
135
136void
138{
139 NS_FATAL_ERROR ("Drop on the phy: cannot validate slow start");
140}
141
142void
144{
145 NS_LOG_FUNCTION (this << oldValue << newValue);
146 uint32_t segSize = GetSegSize (TcpGeneralTest::SENDER);
147 uint32_t increase = newValue - oldValue;
148 m_lastCwnd = newValue;
149
150 if (m_initial)
151 {
152 m_initial = false;
153 NS_TEST_ASSERT_MSG_EQ (newValue, m_initialCwnd * m_segmentSize, "The first update is for ACK of SYN and should initialize cwnd");
154 return;
155 }
156
157 // ACK for first data packet is received to speed up the connection
158 if (oldValue == m_initialCwnd * m_segmentSize)
159 {
160 return;
161 }
162
163 NS_TEST_ASSERT_MSG_EQ (increase, m_delayedAck * segSize, "Increase different than segsize");
164 NS_TEST_ASSERT_MSG_LT_OR_EQ (newValue, GetInitialSsThresh (SENDER), "cWnd increased over ssth");
165
166 NS_LOG_INFO ("Incremented cWnd by " << m_delayedAck * segSize << " bytes in Slow Start " <<
167 "achieving a value of " << newValue);
168}
169
170void
172{
173 NS_LOG_FUNCTION (this << p << h << who);
174}
175
176void
178{
179 NS_LOG_FUNCTION (this << p << h << who);
180}
181
182
183void
185{
186 NS_TEST_ASSERT_MSG_EQ (m_lastCwnd, m_expectedCwnd, "Congestion window did not evolve as expected");
187 TcpGeneralTest::DoTeardown (); // call up to base class method to finish
188}
189
205class
207{
208public:
222 uint32_t packets, uint32_t initialCwnd,
223 uint32_t initialSSThresh, uint32_t delayedAck,
224 uint32_t expectedCwnd,
225 TypeId& congControl, const std::string &desc);
226
227protected:
228 virtual void CWndTrace (uint32_t oldValue, uint32_t newValue);
229 virtual void QueueDrop (SocketWho who);
230 virtual void PhyDrop (SocketWho who);
231
232 virtual void ConfigureEnvironment ();
233 virtual void ConfigureProperties ();
234 virtual void DoTeardown ();
235
236private:
237 virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
238 virtual void Rx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
251};
252
253
256 uint32_t packets,
257 uint32_t initialCwnd,
258 uint32_t initialSSThresh,
259 uint32_t delayedAck,
260 uint32_t expectedCwnd,
261 TypeId &typeId,
262 const std::string &desc)
263 : TcpGeneralTest (desc),
264 m_segmentSize (segmentSize),
265 m_packetSize (packetSize),
266 m_packets (packets),
267 m_initialCwnd (initialCwnd),
268 m_initialSSThresh (initialSSThresh),
269 m_delayedAck (delayedAck),
270 m_lastCwnd (0),
271 m_expectedCwnd (expectedCwnd),
272 m_increment (0),
273 m_initial (true),
274 m_inCongAvoidance (false),
275 m_inSlowStartPhase (true)
276{
277 m_congControlTypeId = typeId;
278}
279
280void
282{
283 TcpGeneralTest::ConfigureEnvironment ();
286 SetMTU (1500);
287}
288
290{
291 TcpGeneralTest::ConfigureProperties ();
297}
298
299void
301{
302 NS_LOG_FUNCTION (this << oldValue << newValue);
303 m_lastCwnd = newValue;
304 if (m_initial)
305 {
306 m_initial = false;
307 NS_TEST_ASSERT_MSG_EQ (newValue, m_initialCwnd * m_segmentSize, "The first update is for ACK of SYN and should initialize cwnd");
308 return;
309 }
310
311 if ((newValue >= m_initialSSThresh * m_segmentSize) && !m_inCongAvoidance && (oldValue != m_initialSSThresh))
312 {
313 m_inCongAvoidance = true;
314 m_inSlowStartPhase = false;
315 return;
316 }
317
319 {
320 return;
321 }
322
323 m_increment = newValue - oldValue;
324
325 NS_TEST_ASSERT_MSG_EQ (m_increment, m_segmentSize, "Increase different than segsize");
326}
327
328void
330{
331 NS_FATAL_ERROR ("Drop on the queue; cannot validate congestion avoidance");
332}
333
334void
336{
337 NS_FATAL_ERROR ("Drop on the phy: cannot validate congestion avoidance");
338}
339
340void
342{
343 NS_LOG_FUNCTION (this << p << h << who);
344}
345
346void
348{
349 NS_LOG_FUNCTION (this << p << h << who);
350}
351
352void
354{
355 NS_TEST_ASSERT_MSG_EQ (m_lastCwnd, m_expectedCwnd, "Congestion window did not evolve as expected");
356 TcpGeneralTest::DoTeardown (); // call up to base class method to finish
357}
358
366{
367public:
368 TcpLinuxRenoTestSuite () : TestSuite ("tcp-linux-reno-test", UNIT)
369 {
370 TypeId cong_control_type = TcpLinuxReno::GetTypeId ();
371 // Test the behavior of Slow Start phase with small segment size
372 // (524 bytes) and delayed acknowledgement of 1 and 2 segments
373 //
374 // Expected data pattern starting at simulation time 10:
375 // (cwnd = 2 segments) 1 ->
376 // (cwnd = 2 segments) 2 ->
377 // (time 10.01s) <- ACK of 1
378 // cwnd increased to 3 segments; send two more
379 // (cwnd = 3 segments) 3 ->
380 // (cwnd = 3 segments) 4 ->
381 // (time 10.011s) <- ACK of 2
382 // cwnd increased to 4 segments; send two more
383 // (cwnd = 4 segments) 5 ->
384 // (cwnd = 4 segments) 6 ->
385 // (time 10.02s) <- ACK of 3
386 // cwnd increased to 5 segments; send two more but only one more to send
387 // (cwnd = 5 segments) 7+FIN ->
388 // <- ACK of 4
389 // <- ACK of 5
390 // <- ACK of 6
391 // <- ACK of 7
392 // cwnd should be at 9 segments
393 // <- FIN/ACK
394 AddTestCase (new TcpLinuxRenoSSTest (524, // segment size
395 524, // socket send size
396 7, // socket sends (i.e. packets)
397 2, // initial cwnd
398 1, // delayed ack count
399 9 * 524, // expected final cWnd
400 cong_control_type,
401 "Slow Start MSS = 524, socket send size = 524, delack = 1 " + cong_control_type.GetName ()),
402 TestCase::QUICK);
403
404 // Next, enabling delayed acks should not have an effect on the final
405 // cWnd achieved
406 AddTestCase (new TcpLinuxRenoSSTest (524, // segment size
407 524, // socket send size
408 7, // socket sends
409 2, // initial cwnd
410 2, // delayed ack count
411 9 * 524, // expected final cWnd
412 cong_control_type,
413 "Slow Start MSS = 524, socket send size = 524, delack = 2 " + cong_control_type.GetName ()),
414 TestCase::QUICK);
415
416 // Test the behavior of Slow Start phase with standard segment size
417 // (1500 bytes) and delayed acknowledgement of 1 and 2 segments
418 //
419 // We still expect m_cWnd to end up at 9 segments
420 AddTestCase (new TcpLinuxRenoSSTest (1500, // segment size
421 1500, // socket send size
422 7, // socket sends
423 2, // initial cwnd
424 1, // delayed ack count
425 9 * 1500, // expected final cWnd
426 cong_control_type,
427 "Slow Start MSS = 1500, socket send size = 524, delack = 1 " + cong_control_type.GetName ()),
428 TestCase::QUICK);
429
430 // Enable delayed acks; we still expect m_cWnd to end up at 9 segments
431 AddTestCase (new TcpLinuxRenoSSTest (1500, // segment size
432 1500, // socket send size
433 7, // socket sends
434 2, // initial cwnd
435 2, // delayed ack count
436 9 * 1500, // expected final cWnd
437 cong_control_type,
438 "Slow Start MSS = 1500, socket send size = 524, delack = 2 " + cong_control_type.GetName ()),
439 TestCase::QUICK);
440
441 // Test the behavior of Congestion Avoidance phase with small segment size
442 // (524 bytes) and delayed acknowledgement of 1 and 2. One important thing
443 // to confirm is that delayed ACK behavior does not affect the congestion
444 // window growth and final value because LinuxReno TCP counts segments acked
445 //
446 // Expected data pattern starting at simulation time 10:
447 // (cwnd = 1 segment) 1 ->
448 // (time 11s) <- ACK of 1
449 // (cwnd = 2 slow start) 2 ->
450 // (can send one more ) 3 ->
451 // (time 12s ) <- ACK of 2
452 // at this ACK, snd_cwnd >= ssthresh of 2, so go into CongestionAvoidance
453 // snd_cwnd_count will be increased to 1, but less than current window 2
454 // send one new segment to replace the one that was acked
455 // (cwnd = 2 CA ) 4 ->
456 // (again, time 12s ) <- ACK of 3
457 // at this ACK, snd_cwnd >= ssthresh of 2, so stay in CongestionAvoidance
458 // snd_cwnd_count (m_cWndCnt) will be increased to 2, equal to w
459 // We can increase cWnd to three segments and reset snd_cwnd_count
460 // 5 ->
461 // 6+FIN ->
462 // (time 13s ) <- ACK of 4
463 // increase m_cWndCnt to 1
464 // (time 13s ) <- ACK of 5
465 // increase m_cWndCnt to 2
466 // (time 13s ) <- ACK of 6
467 // increase m_cWndCnt to 3, equal to window, so increase m_cWnd by one seg.
468 // Final value of m_cWnd should be 4 * 524 = 2096
469 AddTestCase (new TcpLinuxRenoCongAvoidTest (524, // segment size
470 524, // socket send size
471 6, // socket sends
472 1, // initial cwnd
473 2 * 524, // initial ssthresh
474 1, // delayed ack count
475 4 * 524, // expected final cWnd
476 cong_control_type,
477 "Congestion Avoidance MSS = 524, socket send size = 524, delack = 1 " + cong_control_type.GetName ()),
478 TestCase::QUICK);
479
480 // Repeat with delayed acks enabled: should result in same final cWnd
481 // Expected data pattern starting at simulation time 10:
482 // (cwnd = 1 segment) 1 ->
483 // (time 11s) <- ACK of 1, ns-3 will always ack 1st seg
484 // (cwnd = 2 slow start) 2 ->
485 // (can send one more ) 3 ->
486 // (time 12s ) <- ACK of 3 (combined ack of 2 segments)
487 // at this ACK, snd_cwnd >= ssthresh of 2, so go into CongestionAvoidance
488 // snd_cwnd_count will be increased to 1+1 = current window 2
489 // send one new segment to replace the one that was acked
490 // (cwnd = 3 CA ) 4 ->
491 // (cwnd = 3 CA ) 5 ->
492 // (cwnd = 3 CA ) 6 ->
493 // (time 13s ) <- ACK of 5 (combined ack of 2 segments)
494 // (time 13s ) <- ACK of 6 (ack of 1 segment due to FIN)
495 // increase m_cWndCnt to 3, equal to window, so increase m_cWnd by one seg.
496 // Final value of m_cWnd should be 4 * 524 = 2096
497 AddTestCase (new TcpLinuxRenoCongAvoidTest (524, // segment size
498 524, // socket send size
499 6, // socket sends
500 1, // initial cwnd
501 2, // initial ssthresh
502 2, // delayed ack count
503 4 * 524, // expected final cWnd
504 cong_control_type,
505 "Congestion Avoidance MSS = 524, socket send size = 524, delack = 2 " + cong_control_type.GetName ()),
506 TestCase::QUICK);
507
508 // Test the behavior of Congestion Avoidance phase with standard segment size (i.e 1500 bytes)
509 // and delayed acknowledgement of 1 and 2
510 // Test the behavior of Congestion Avoidance phase with standard segment
511 // size (1500 bytes) and delayed acknowledgement of 1 and 2.
512 // This should result in the same pattern of segment exchanges as
513 // above.
514 AddTestCase (new TcpLinuxRenoCongAvoidTest (1500, // segment size
515 1500, // socket send size
516 6, // socket sends
517 1, // initial cwnd
518 2, // initial ssthresh
519 1, // delayed ack count
520 4 * 1500, // expected final cWnd
521 cong_control_type,
522 "Congestion Avoidance MSS = 1500, socket send size = 1500, delack = 1 " + cong_control_type.GetName ()),
523 TestCase::QUICK);
524
525 AddTestCase (new TcpLinuxRenoCongAvoidTest (1500, // segment size
526 1500, // socket send size
527 6, // socket sends
528 1, // initial cwnd
529 2, // initial ssthresh
530 2, // delayed ack count
531 4 * 1500, // expected final cWnd
532 cong_control_type,
533 "Congestion Avoidance MSS = 1500, socket send size = 1500, delack = 2 " + cong_control_type.GetName ()),
534 TestCase::QUICK);
535 }
536};
537
This unit test checks that the slow start and congestion avoidance behavior matches Linux behavior as...
bool m_inCongAvoidance
True if in congestion avoidance.
uint32_t m_initialSSThresh
Initial slow start threshold (bytes)
uint32_t m_segmentSize
Segment size.
bool m_inSlowStartPhase
True if in slow start.
uint32_t m_delayedAck
Delayed Acknowledgement.
uint32_t m_packetSize
Size of the packets used in socket writes.
bool m_initial
True on first run.
virtual void PhyDrop(SocketWho who)
Link drop.
virtual void CWndTrace(uint32_t oldValue, uint32_t newValue)
Tracks the congestion window changes.
uint32_t m_packets
Number of packets to send to the socket.
uint32_t m_expectedCwnd
Expected final cWnd value.
virtual void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet received from IP layer.
uint32_t m_lastCwnd
Last cWnd value reported.
virtual void DoTeardown()
Teardown the TCP test.
uint32_t m_increment
Congestion window increment.
TcpLinuxRenoCongAvoidTest(uint32_t segmentSize, uint32_t packetSize, uint32_t packets, uint32_t initialCwnd, uint32_t initialSSThresh, uint32_t delayedAck, uint32_t expectedCwnd, TypeId &congControl, const std::string &desc)
Constructor.
virtual void QueueDrop(SocketWho who)
Drop on the queue.
virtual void ConfigureProperties()
Change the configuration of the socket properties.
virtual void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet transmitted down to IP layer.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
uint32_t m_initialCwnd
Initial congestion window (segments)
This unit test checks that the slow start and congestion avoidance behavior matches Linux behavior as...
bool m_initial
First cycle flag.
uint32_t m_lastCwnd
Last cWnd value reported.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
virtual void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet transmitted down to IP layer.
uint32_t m_initialCwnd
Initial congestion window.
uint32_t m_delayedAck
Delayed Acknowledgement.
virtual void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet received from IP layer.
TcpLinuxRenoSSTest(uint32_t segmentSize, uint32_t packetSize, uint32_t packets, uint32_t initialCwnd, uint32_t delayedAck, uint32_t expectedCwnd, TypeId &congControl, const std::string &desc)
Constructor.
uint32_t m_packetSize
Packet size.
uint32_t m_expectedCwnd
Expected final cWnd value.
uint32_t m_packets
Packet counter.
virtual void CWndTrace(uint32_t oldValue, uint32_t newValue)
Tracks the congestion window changes.
virtual void ConfigureProperties()
Change the configuration of the socket properties.
void QueueDrop(SocketWho who)
Drop on the queue.
void PhyDrop(SocketWho who)
Link drop.
uint32_t m_segmentSize
Segment size.
virtual void DoTeardown()
Teardown the TCP test.
TestSuite for the behavior of Linux Reno.
General infrastructure for TCP testing.
void SetPropagationDelay(Time propDelay)
Propagation delay of the bottleneck link.
void SetAppPktCount(uint32_t pktCount)
Set app packet count.
void SetDelAckMaxCount(SocketWho who, uint32_t count)
Forcefully set the delayed acknowledgement count.
SocketWho
Used as parameter of methods, specifies on what node the caller is interested (e.g.
@ RECEIVER
Receiver node.
void SetAppPktSize(uint32_t pktSize)
Set app packet size.
void SetInitialCwnd(SocketWho who, uint32_t initialCwnd)
Forcefully set the initial cwnd.
uint32_t GetInitialSsThresh(SocketWho who)
Get the initial slow start threshold.
void SetMTU(uint32_t mtu)
MTU of the bottleneck link.
uint32_t GetSegSize(SocketWho who)
Get the segment size of the node specified.
TypeId m_congControlTypeId
Congestion control.
void SetInitialSsThresh(SocketWho who, uint32_t initialSsThresh)
Forcefully set the initial ssthresh.
void SetSegmentSize(SocketWho who, uint32_t segmentSize)
Forcefully set the segment size.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:45
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
a unique identifier for an interface.
Definition: type-id.h:59
std::string GetName(void) const
Get the name.
Definition: type-id.cc:976
uint32_t segmentSize
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
#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
#define NS_TEST_ASSERT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report and abort if not.
Definition: test.h:712
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1252
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static TcpLinuxRenoTestSuite g_tcpLinuxRenoTestSuite
Static variable for test initialization.
static const uint32_t packetSize
Pcket size generated at the AP.