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
47{
48 public:
62 uint32_t packets,
63 uint32_t initialCwnd,
64 uint32_t delayedAck,
65 uint32_t expectedCwnd,
66 TypeId& congControl,
67 const std::string& desc);
68
69 protected:
70 void CWndTrace(uint32_t oldValue, uint32_t newValue) override;
71 void QueueDrop(SocketWho who) override;
72 void PhyDrop(SocketWho who) override;
73
74 void ConfigureEnvironment() override;
75 void ConfigureProperties() override;
76 void DoTeardown() override;
77
78 bool m_initial;
79
80 private:
81 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
82 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
90};
91
94 uint32_t packets,
95 uint32_t initialCwnd,
96 uint32_t delayedAck,
97 uint32_t expectedCwnd,
98 TypeId& typeId,
99 const std::string& desc)
100 : TcpGeneralTest(desc),
101 m_initial(true),
102 m_segmentSize(segmentSize),
103 m_packetSize(packetSize),
104 m_packets(packets),
105 m_initialCwnd(initialCwnd),
106 m_delayedAck(delayedAck),
107 m_lastCwnd(0),
108 m_expectedCwnd(expectedCwnd)
109{
110 m_congControlTypeId = typeId;
111}
112
113void
115{
116 TcpGeneralTest::ConfigureEnvironment();
120}
121
122void
124{
125 TcpGeneralTest::ConfigureProperties();
130}
131
132void
134{
135 NS_FATAL_ERROR("Drop on the queue; cannot validate slow start");
136}
137
138void
140{
141 NS_FATAL_ERROR("Drop on the phy: cannot validate slow start");
142}
143
144void
146{
147 NS_LOG_FUNCTION(this << oldValue << newValue);
148 uint32_t segSize = GetSegSize(TcpGeneralTest::SENDER);
149 uint32_t increase = newValue - oldValue;
150 m_lastCwnd = newValue;
151
152 if (m_initial)
153 {
154 m_initial = false;
155 NS_TEST_ASSERT_MSG_EQ(newValue,
157 "The first update is for ACK of SYN and should initialize cwnd");
158 return;
159 }
160
161 // ACK for first data packet is received to speed up the connection
162 if (oldValue == m_initialCwnd * m_segmentSize)
163 {
164 return;
165 }
166
167 NS_TEST_ASSERT_MSG_EQ(increase, m_delayedAck * segSize, "Increase different than segsize");
168 NS_TEST_ASSERT_MSG_LT_OR_EQ(newValue, GetInitialSsThresh(SENDER), "cWnd increased over ssth");
169
170 NS_LOG_INFO("Incremented cWnd by " << m_delayedAck * segSize << " bytes in Slow Start "
171 << "achieving a value of " << newValue);
172}
173
174void
176{
177 NS_LOG_FUNCTION(this << p << h << who);
178}
179
180void
182{
183 NS_LOG_FUNCTION(this << p << h << who);
184}
185
186void
188{
191 "Congestion window did not evolve as expected");
192 TcpGeneralTest::DoTeardown(); // call up to base class method to finish
193}
194
210{
211 public:
226 uint32_t packets,
227 uint32_t initialCwnd,
228 uint32_t initialSSThresh,
229 uint32_t delayedAck,
230 uint32_t expectedCwnd,
231 TypeId& congControl,
232 const std::string& desc);
233
234 protected:
235 void CWndTrace(uint32_t oldValue, uint32_t newValue) override;
236 void QueueDrop(SocketWho who) override;
237 void PhyDrop(SocketWho who) override;
238
239 void ConfigureEnvironment() override;
240 void ConfigureProperties() override;
241 void DoTeardown() override;
242
243 private:
244 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
245 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
258};
259
262 uint32_t packets,
263 uint32_t initialCwnd,
264 uint32_t initialSSThresh,
265 uint32_t delayedAck,
266 uint32_t expectedCwnd,
267 TypeId& typeId,
268 const std::string& desc)
269 : TcpGeneralTest(desc),
270 m_segmentSize(segmentSize),
271 m_packetSize(packetSize),
272 m_packets(packets),
273 m_initialCwnd(initialCwnd),
274 m_initialSSThresh(initialSSThresh),
275 m_delayedAck(delayedAck),
276 m_lastCwnd(0),
277 m_expectedCwnd(expectedCwnd),
278 m_increment(0),
279 m_initial(true),
280 m_inCongAvoidance(false),
281 m_inSlowStartPhase(true)
282{
283 m_congControlTypeId = typeId;
284}
285
286void
288{
289 TcpGeneralTest::ConfigureEnvironment();
292 SetMTU(1500);
293}
294
295void
297{
298 TcpGeneralTest::ConfigureProperties();
304}
305
306void
308{
309 NS_LOG_FUNCTION(this << oldValue << newValue);
310 m_lastCwnd = newValue;
311 if (m_initial)
312 {
313 m_initial = false;
314 NS_TEST_ASSERT_MSG_EQ(newValue,
316 "The first update is for ACK of SYN and should initialize cwnd");
317 return;
318 }
319
320 if ((newValue >= m_initialSSThresh * m_segmentSize) && !m_inCongAvoidance &&
321 (oldValue != m_initialSSThresh))
322 {
323 m_inCongAvoidance = true;
324 m_inSlowStartPhase = false;
325 return;
326 }
327
329 {
330 return;
331 }
332
333 m_increment = newValue - oldValue;
334
335 NS_TEST_ASSERT_MSG_EQ(m_increment, m_segmentSize, "Increase different than segsize");
336}
337
338void
340{
341 NS_FATAL_ERROR("Drop on the queue; cannot validate congestion avoidance");
342}
343
344void
346{
347 NS_FATAL_ERROR("Drop on the phy: cannot validate congestion avoidance");
348}
349
350void
352{
353 NS_LOG_FUNCTION(this << p << h << who);
354}
355
356void
358{
359 NS_LOG_FUNCTION(this << p << h << who);
360}
361
362void
364{
367 "Congestion window did not evolve as expected");
368 TcpGeneralTest::DoTeardown(); // call up to base class method to finish
369}
370
377{
378 public:
380 : TestSuite("tcp-linux-reno-test", UNIT)
381 {
382 TypeId cong_control_type = TcpLinuxReno::GetTypeId();
383 // Test the behavior of Slow Start phase with small segment size
384 // (524 bytes) and delayed acknowledgement of 1 and 2 segments
385 //
386 // Expected data pattern starting at simulation time 10:
387 // (cwnd = 2 segments) 1 ->
388 // (cwnd = 2 segments) 2 ->
389 // (time 10.01s) <- ACK of 1
390 // cwnd increased to 3 segments; send two more
391 // (cwnd = 3 segments) 3 ->
392 // (cwnd = 3 segments) 4 ->
393 // (time 10.011s) <- ACK of 2
394 // cwnd increased to 4 segments; send two more
395 // (cwnd = 4 segments) 5 ->
396 // (cwnd = 4 segments) 6 ->
397 // (time 10.02s) <- ACK of 3
398 // cwnd increased to 5 segments; send two more but only one more to send
399 // (cwnd = 5 segments) 7+FIN ->
400 // <- ACK of 4
401 // <- ACK of 5
402 // <- ACK of 6
403 // <- ACK of 7
404 // cwnd should be at 9 segments
405 // <- FIN/ACK
407 new TcpLinuxRenoSSTest(524, // segment size
408 524, // socket send size
409 7, // socket sends (i.e. packets)
410 2, // initial cwnd
411 1, // delayed ack count
412 9 * 524, // expected final cWnd
413 cong_control_type,
414 "Slow Start MSS = 524, socket send size = 524, delack = 1 " +
415 cong_control_type.GetName()),
416 TestCase::QUICK);
417
418 // Next, enabling delayed acks should not have an effect on the final
419 // cWnd achieved
421 new TcpLinuxRenoSSTest(524, // segment size
422 524, // socket send size
423 7, // socket sends
424 2, // initial cwnd
425 2, // delayed ack count
426 9 * 524, // expected final cWnd
427 cong_control_type,
428 "Slow Start MSS = 524, socket send size = 524, delack = 2 " +
429 cong_control_type.GetName()),
430 TestCase::QUICK);
431
432 // Test the behavior of Slow Start phase with standard segment size
433 // (1500 bytes) and delayed acknowledgement of 1 and 2 segments
434 //
435 // We still expect m_cWnd to end up at 9 segments
437 new TcpLinuxRenoSSTest(1500, // segment size
438 1500, // socket send size
439 7, // socket sends
440 2, // initial cwnd
441 1, // delayed ack count
442 9 * 1500, // expected final cWnd
443 cong_control_type,
444 "Slow Start MSS = 1500, socket send size = 524, delack = 1 " +
445 cong_control_type.GetName()),
446 TestCase::QUICK);
447
448 // Enable delayed acks; we still expect m_cWnd to end up at 9 segments
450 new TcpLinuxRenoSSTest(1500, // segment size
451 1500, // socket send size
452 7, // socket sends
453 2, // initial cwnd
454 2, // delayed ack count
455 9 * 1500, // expected final cWnd
456 cong_control_type,
457 "Slow Start MSS = 1500, socket send size = 524, delack = 2 " +
458 cong_control_type.GetName()),
459 TestCase::QUICK);
460
461 // Test the behavior of Congestion Avoidance phase with small segment size
462 // (524 bytes) and delayed acknowledgement of 1 and 2. One important thing
463 // to confirm is that delayed ACK behavior does not affect the congestion
464 // window growth and final value because LinuxReno TCP counts segments acked
465 //
466 // Expected data pattern starting at simulation time 10:
467 // (cwnd = 1 segment) 1 ->
468 // (time 11s) <- ACK of 1
469 // (cwnd = 2 slow start) 2 ->
470 // (can send one more ) 3 ->
471 // (time 12s ) <- ACK of 2
472 // at this ACK, snd_cwnd >= ssthresh of 2, so go into CongestionAvoidance
473 // snd_cwnd_count will be increased to 1, but less than current window 2
474 // send one new segment to replace the one that was acked
475 // (cwnd = 2 CA ) 4 ->
476 // (again, time 12s ) <- ACK of 3
477 // at this ACK, snd_cwnd >= ssthresh of 2, so stay in CongestionAvoidance
478 // snd_cwnd_count (m_cWndCnt) will be increased to 2, equal to w
479 // We can increase cWnd to three segments and reset snd_cwnd_count
480 // 5 ->
481 // 6+FIN ->
482 // (time 13s ) <- ACK of 4
483 // increase m_cWndCnt to 1
484 // (time 13s ) <- ACK of 5
485 // increase m_cWndCnt to 2
486 // (time 13s ) <- ACK of 6
487 // increase m_cWndCnt to 3, equal to window, so increase m_cWnd by one seg.
488 // Final value of m_cWnd should be 4 * 524 = 2096
490 524, // segment size
491 524, // socket send size
492 6, // socket sends
493 1, // initial cwnd
494 2 * 524, // initial ssthresh
495 1, // delayed ack count
496 4 * 524, // expected final cWnd
497 cong_control_type,
498 "Congestion Avoidance MSS = 524, socket send size = 524, delack = 1 " +
499 cong_control_type.GetName()),
500 TestCase::QUICK);
501
502 // Repeat with delayed acks enabled: should result in same final cWnd
503 // Expected data pattern starting at simulation time 10:
504 // (cwnd = 1 segment) 1 ->
505 // (time 11s) <- ACK of 1, ns-3 will always ack 1st seg
506 // (cwnd = 2 slow start) 2 ->
507 // (can send one more ) 3 ->
508 // (time 12s ) <- ACK of 3 (combined ack of 2 segments)
509 // at this ACK, snd_cwnd >= ssthresh of 2, so go into CongestionAvoidance
510 // snd_cwnd_count will be increased to 1+1 = current window 2
511 // send one new segment to replace the one that was acked
512 // (cwnd = 3 CA ) 4 ->
513 // (cwnd = 3 CA ) 5 ->
514 // (cwnd = 3 CA ) 6 ->
515 // (time 13s ) <- ACK of 5 (combined ack of 2 segments)
516 // (time 13s ) <- ACK of 6 (ack of 1 segment due to FIN)
517 // increase m_cWndCnt to 3, equal to window, so increase m_cWnd by one seg.
518 // Final value of m_cWnd should be 4 * 524 = 2096
520 524, // segment size
521 524, // socket send size
522 6, // socket sends
523 1, // initial cwnd
524 2, // initial ssthresh
525 2, // delayed ack count
526 4 * 524, // expected final cWnd
527 cong_control_type,
528 "Congestion Avoidance MSS = 524, socket send size = 524, delack = 2 " +
529 cong_control_type.GetName()),
530 TestCase::QUICK);
531
532 // Test the behavior of Congestion Avoidance phase with standard segment size (i.e 1500
533 // bytes) and delayed acknowledgement of 1 and 2 Test the behavior of Congestion Avoidance
534 // phase with standard segment size (1500 bytes) and delayed acknowledgement of 1 and 2.
535 // This should result in the same pattern of segment exchanges as
536 // above.
538 1500, // segment size
539 1500, // socket send size
540 6, // socket sends
541 1, // initial cwnd
542 2, // initial ssthresh
543 1, // delayed ack count
544 4 * 1500, // expected final cWnd
545 cong_control_type,
546 "Congestion Avoidance MSS = 1500, socket send size = 1500, delack = 1 " +
547 cong_control_type.GetName()),
548 TestCase::QUICK);
549
551 1500, // segment size
552 1500, // socket send size
553 6, // socket sends
554 1, // initial cwnd
555 2, // initial ssthresh
556 2, // delayed ack count
557 4 * 1500, // expected final cWnd
558 cong_control_type,
559 "Congestion Avoidance MSS = 1500, socket send size = 1500, delack = 2 " +
560 cong_control_type.GetName()),
561 TestCase::QUICK);
562 }
563};
564
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:59
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:179
#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:1348
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.