A Discrete-Event Network Simulator
API
tcp-linux-reno-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 Apoorva Bhargava <apoorvabhargava13@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
18#include "tcp-general-test.h"
19
20#include "ns3/config.h"
21#include "ns3/log.h"
22#include "ns3/node.h"
23#include "ns3/simple-channel.h"
24#include "ns3/tcp-header.h"
25#include "ns3/tcp-linux-reno.h"
26#include "ns3/test.h"
27
28using namespace ns3;
29
30NS_LOG_COMPONENT_DEFINE("TcpLinuxRenoTest");
31
48{
49 public:
63 uint32_t packets,
64 uint32_t initialCwnd,
65 uint32_t delayedAck,
66 uint32_t expectedCwnd,
67 TypeId& congControl,
68 const std::string& desc);
69
70 protected:
71 void CWndTrace(uint32_t oldValue, uint32_t newValue) override;
72 void QueueDrop(SocketWho who) override;
73 void PhyDrop(SocketWho who) override;
74
75 void ConfigureEnvironment() override;
76 void ConfigureProperties() override;
77 void DoTeardown() override;
78
79 bool m_initial;
80
81 private:
82 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
83 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
91};
92
95 uint32_t packets,
96 uint32_t initialCwnd,
97 uint32_t delayedAck,
98 uint32_t expectedCwnd,
99 TypeId& typeId,
100 const std::string& desc)
101 : TcpGeneralTest(desc),
102 m_initial(true),
103 m_segmentSize(segmentSize),
104 m_packetSize(packetSize),
105 m_packets(packets),
106 m_initialCwnd(initialCwnd),
107 m_delayedAck(delayedAck),
108 m_lastCwnd(0),
109 m_expectedCwnd(expectedCwnd)
110{
111 m_congControlTypeId = typeId;
112}
113
114void
116{
117 TcpGeneralTest::ConfigureEnvironment();
121}
122
123void
125{
126 TcpGeneralTest::ConfigureProperties();
131}
132
133void
135{
136 NS_FATAL_ERROR("Drop on the queue; cannot validate slow start");
137}
138
139void
141{
142 NS_FATAL_ERROR("Drop on the phy: cannot validate slow start");
143}
144
145void
147{
148 NS_LOG_FUNCTION(this << oldValue << newValue);
149 uint32_t segSize = GetSegSize(TcpGeneralTest::SENDER);
150 uint32_t increase = newValue - oldValue;
151 m_lastCwnd = newValue;
152
153 if (m_initial)
154 {
155 m_initial = false;
156 NS_TEST_ASSERT_MSG_EQ(newValue,
158 "The first update is for ACK of SYN and should initialize cwnd");
159 return;
160 }
161
162 // ACK for first data packet is received to speed up the connection
163 if (oldValue == m_initialCwnd * m_segmentSize)
164 {
165 return;
166 }
167
168 NS_TEST_ASSERT_MSG_EQ(increase, m_delayedAck * segSize, "Increase different than segsize");
169 NS_TEST_ASSERT_MSG_LT_OR_EQ(newValue, GetInitialSsThresh(SENDER), "cWnd increased over ssth");
170
171 NS_LOG_INFO("Incremented cWnd by " << m_delayedAck * segSize << " bytes in Slow Start "
172 << "achieving a value of " << newValue);
173}
174
175void
177{
178 NS_LOG_FUNCTION(this << p << h << who);
179}
180
181void
183{
184 NS_LOG_FUNCTION(this << p << h << who);
185}
186
187void
189{
192 "Congestion window did not evolve as expected");
193 TcpGeneralTest::DoTeardown(); // call up to base class method to finish
194}
195
212{
213 public:
228 uint32_t packets,
229 uint32_t initialCwnd,
230 uint32_t initialSSThresh,
231 uint32_t delayedAck,
232 uint32_t expectedCwnd,
233 TypeId& congControl,
234 const std::string& desc);
235
236 protected:
237 void CWndTrace(uint32_t oldValue, uint32_t newValue) override;
238 void QueueDrop(SocketWho who) override;
239 void PhyDrop(SocketWho who) override;
240
241 void ConfigureEnvironment() override;
242 void ConfigureProperties() override;
243 void DoTeardown() override;
244
245 private:
246 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
247 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
260};
261
264 uint32_t packets,
265 uint32_t initialCwnd,
266 uint32_t initialSSThresh,
267 uint32_t delayedAck,
268 uint32_t expectedCwnd,
269 TypeId& typeId,
270 const std::string& desc)
271 : TcpGeneralTest(desc),
272 m_segmentSize(segmentSize),
273 m_packetSize(packetSize),
274 m_packets(packets),
275 m_initialCwnd(initialCwnd),
276 m_initialSSThresh(initialSSThresh),
277 m_delayedAck(delayedAck),
278 m_lastCwnd(0),
279 m_expectedCwnd(expectedCwnd),
280 m_increment(0),
281 m_initial(true),
282 m_inCongAvoidance(false),
283 m_inSlowStartPhase(true)
284{
285 m_congControlTypeId = typeId;
286}
287
288void
290{
291 TcpGeneralTest::ConfigureEnvironment();
294 SetMTU(1500);
295}
296
297void
299{
300 TcpGeneralTest::ConfigureProperties();
306}
307
308void
310{
311 NS_LOG_FUNCTION(this << oldValue << newValue);
312 m_lastCwnd = newValue;
313 if (m_initial)
314 {
315 m_initial = false;
316 NS_TEST_ASSERT_MSG_EQ(newValue,
318 "The first update is for ACK of SYN and should initialize cwnd");
319 return;
320 }
321
322 if ((newValue >= m_initialSSThresh * m_segmentSize) && !m_inCongAvoidance &&
323 (oldValue != m_initialSSThresh))
324 {
325 m_inCongAvoidance = true;
326 m_inSlowStartPhase = false;
327 return;
328 }
329
331 {
332 return;
333 }
334
335 m_increment = newValue - oldValue;
336
337 NS_TEST_ASSERT_MSG_EQ(m_increment, m_segmentSize, "Increase different than segsize");
338}
339
340void
342{
343 NS_FATAL_ERROR("Drop on the queue; cannot validate congestion avoidance");
344}
345
346void
348{
349 NS_FATAL_ERROR("Drop on the phy: cannot validate congestion avoidance");
350}
351
352void
354{
355 NS_LOG_FUNCTION(this << p << h << who);
356}
357
358void
360{
361 NS_LOG_FUNCTION(this << p << h << who);
362}
363
364void
366{
369 "Congestion window did not evolve as expected");
370 TcpGeneralTest::DoTeardown(); // call up to base class method to finish
371}
372
380{
381 public:
383 : TestSuite("tcp-linux-reno-test", UNIT)
384 {
385 TypeId cong_control_type = TcpLinuxReno::GetTypeId();
386 // Test the behavior of Slow Start phase with small segment size
387 // (524 bytes) and delayed acknowledgement of 1 and 2 segments
388 //
389 // Expected data pattern starting at simulation time 10:
390 // (cwnd = 2 segments) 1 ->
391 // (cwnd = 2 segments) 2 ->
392 // (time 10.01s) <- ACK of 1
393 // cwnd increased to 3 segments; send two more
394 // (cwnd = 3 segments) 3 ->
395 // (cwnd = 3 segments) 4 ->
396 // (time 10.011s) <- ACK of 2
397 // cwnd increased to 4 segments; send two more
398 // (cwnd = 4 segments) 5 ->
399 // (cwnd = 4 segments) 6 ->
400 // (time 10.02s) <- ACK of 3
401 // cwnd increased to 5 segments; send two more but only one more to send
402 // (cwnd = 5 segments) 7+FIN ->
403 // <- ACK of 4
404 // <- ACK of 5
405 // <- ACK of 6
406 // <- ACK of 7
407 // cwnd should be at 9 segments
408 // <- FIN/ACK
410 new TcpLinuxRenoSSTest(524, // segment size
411 524, // socket send size
412 7, // socket sends (i.e. packets)
413 2, // initial cwnd
414 1, // delayed ack count
415 9 * 524, // expected final cWnd
416 cong_control_type,
417 "Slow Start MSS = 524, socket send size = 524, delack = 1 " +
418 cong_control_type.GetName()),
419 TestCase::QUICK);
420
421 // Next, enabling delayed acks should not have an effect on the final
422 // cWnd achieved
424 new TcpLinuxRenoSSTest(524, // segment size
425 524, // socket send size
426 7, // socket sends
427 2, // initial cwnd
428 2, // delayed ack count
429 9 * 524, // expected final cWnd
430 cong_control_type,
431 "Slow Start MSS = 524, socket send size = 524, delack = 2 " +
432 cong_control_type.GetName()),
433 TestCase::QUICK);
434
435 // Test the behavior of Slow Start phase with standard segment size
436 // (1500 bytes) and delayed acknowledgement of 1 and 2 segments
437 //
438 // We still expect m_cWnd to end up at 9 segments
440 new TcpLinuxRenoSSTest(1500, // segment size
441 1500, // socket send size
442 7, // socket sends
443 2, // initial cwnd
444 1, // delayed ack count
445 9 * 1500, // expected final cWnd
446 cong_control_type,
447 "Slow Start MSS = 1500, socket send size = 524, delack = 1 " +
448 cong_control_type.GetName()),
449 TestCase::QUICK);
450
451 // Enable delayed acks; we still expect m_cWnd to end up at 9 segments
453 new TcpLinuxRenoSSTest(1500, // segment size
454 1500, // socket send size
455 7, // socket sends
456 2, // initial cwnd
457 2, // delayed ack count
458 9 * 1500, // expected final cWnd
459 cong_control_type,
460 "Slow Start MSS = 1500, socket send size = 524, delack = 2 " +
461 cong_control_type.GetName()),
462 TestCase::QUICK);
463
464 // Test the behavior of Congestion Avoidance phase with small segment size
465 // (524 bytes) and delayed acknowledgement of 1 and 2. One important thing
466 // to confirm is that delayed ACK behavior does not affect the congestion
467 // window growth and final value because LinuxReno TCP counts segments acked
468 //
469 // Expected data pattern starting at simulation time 10:
470 // (cwnd = 1 segment) 1 ->
471 // (time 11s) <- ACK of 1
472 // (cwnd = 2 slow start) 2 ->
473 // (can send one more ) 3 ->
474 // (time 12s ) <- ACK of 2
475 // at this ACK, snd_cwnd >= ssthresh of 2, so go into CongestionAvoidance
476 // snd_cwnd_count will be increased to 1, but less than current window 2
477 // send one new segment to replace the one that was acked
478 // (cwnd = 2 CA ) 4 ->
479 // (again, time 12s ) <- ACK of 3
480 // at this ACK, snd_cwnd >= ssthresh of 2, so stay in CongestionAvoidance
481 // snd_cwnd_count (m_cWndCnt) will be increased to 2, equal to w
482 // We can increase cWnd to three segments and reset snd_cwnd_count
483 // 5 ->
484 // 6+FIN ->
485 // (time 13s ) <- ACK of 4
486 // increase m_cWndCnt to 1
487 // (time 13s ) <- ACK of 5
488 // increase m_cWndCnt to 2
489 // (time 13s ) <- ACK of 6
490 // increase m_cWndCnt to 3, equal to window, so increase m_cWnd by one seg.
491 // Final value of m_cWnd should be 4 * 524 = 2096
493 524, // segment size
494 524, // socket send size
495 6, // socket sends
496 1, // initial cwnd
497 2 * 524, // initial ssthresh
498 1, // delayed ack count
499 4 * 524, // expected final cWnd
500 cong_control_type,
501 "Congestion Avoidance MSS = 524, socket send size = 524, delack = 1 " +
502 cong_control_type.GetName()),
503 TestCase::QUICK);
504
505 // Repeat with delayed acks enabled: should result in same final cWnd
506 // Expected data pattern starting at simulation time 10:
507 // (cwnd = 1 segment) 1 ->
508 // (time 11s) <- ACK of 1, ns-3 will always ack 1st seg
509 // (cwnd = 2 slow start) 2 ->
510 // (can send one more ) 3 ->
511 // (time 12s ) <- ACK of 3 (combined ack of 2 segments)
512 // at this ACK, snd_cwnd >= ssthresh of 2, so go into CongestionAvoidance
513 // snd_cwnd_count will be increased to 1+1 = current window 2
514 // send one new segment to replace the one that was acked
515 // (cwnd = 3 CA ) 4 ->
516 // (cwnd = 3 CA ) 5 ->
517 // (cwnd = 3 CA ) 6 ->
518 // (time 13s ) <- ACK of 5 (combined ack of 2 segments)
519 // (time 13s ) <- ACK of 6 (ack of 1 segment due to FIN)
520 // increase m_cWndCnt to 3, equal to window, so increase m_cWnd by one seg.
521 // Final value of m_cWnd should be 4 * 524 = 2096
523 524, // segment size
524 524, // socket send size
525 6, // socket sends
526 1, // initial cwnd
527 2, // initial ssthresh
528 2, // delayed ack count
529 4 * 524, // expected final cWnd
530 cong_control_type,
531 "Congestion Avoidance MSS = 524, socket send size = 524, delack = 2 " +
532 cong_control_type.GetName()),
533 TestCase::QUICK);
534
535 // Test the behavior of Congestion Avoidance phase with standard segment size (i.e 1500
536 // bytes) and delayed acknowledgement of 1 and 2 Test the behavior of Congestion Avoidance
537 // phase with standard segment size (1500 bytes) and delayed acknowledgement of 1 and 2.
538 // This should result in the same pattern of segment exchanges as
539 // above.
541 1500, // segment size
542 1500, // socket send size
543 6, // socket sends
544 1, // initial cwnd
545 2, // initial ssthresh
546 1, // delayed ack count
547 4 * 1500, // expected final cWnd
548 cong_control_type,
549 "Congestion Avoidance MSS = 1500, socket send size = 1500, delack = 1 " +
550 cong_control_type.GetName()),
551 TestCase::QUICK);
552
554 1500, // segment size
555 1500, // socket send size
556 6, // socket sends
557 1, // initial cwnd
558 2, // initial ssthresh
559 2, // delayed ack count
560 4 * 1500, // expected final cWnd
561 cong_control_type,
562 "Congestion Avoidance MSS = 1500, socket send size = 1500, delack = 2 " +
563 cong_control_type.GetName()),
564 TestCase::QUICK);
565 }
566};
567
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.
void DoTeardown() override
Teardown the TCP test.
void CWndTrace(uint32_t oldValue, uint32_t newValue) override
Tracks the congestion window changes.
void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet received from IP layer.
void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet transmitted down to IP layer.
uint32_t m_packets
Number of packets to send to the socket.
uint32_t m_expectedCwnd
Expected final cWnd value.
void PhyDrop(SocketWho who) override
Link drop.
uint32_t m_lastCwnd
Last cWnd value reported.
uint32_t m_increment
Congestion window increment.
void ConfigureProperties() override
Change the configuration of the socket properties.
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.
void ConfigureEnvironment() override
Change the configuration of the environment.
uint32_t m_initialCwnd
Initial congestion window (segments)
void QueueDrop(SocketWho who) override
Drop on the queue.
This unit test checks that the slow start and congestion avoidance behavior matches Linux behavior as...
bool m_initial
First cycle flag.
void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet transmitted down to IP layer.
uint32_t m_lastCwnd
Last cWnd value reported.
void DoTeardown() override
Teardown the TCP test.
uint32_t m_initialCwnd
Initial congestion window.
uint32_t m_delayedAck
Delayed Acknowledgement.
void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet received from IP layer.
void ConfigureProperties() override
Change the configuration of the socket properties.
void ConfigureEnvironment() override
Change the configuration of the environment.
void CWndTrace(uint32_t oldValue, uint32_t newValue) override
Tracks the congestion window changes.
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.
void QueueDrop(SocketWho who) override
Drop on the queue.
uint32_t m_expectedCwnd
Expected final cWnd value.
uint32_t m_packets
Packet counter.
uint32_t m_segmentSize
Segment size.
void PhyDrop(SocketWho who) override
Link drop.
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:46
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
a unique identifier for an interface.
Definition: type-id.h:60
std::string GetName() const
Get the name.
Definition: type-id.cc:995
uint32_t segmentSize
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:160
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#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:275
#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:144
#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:750
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
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
Packet size generated at the AP.