A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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{
120}
121
122void
124{
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);
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{
292 SetMTU(1500);
293}
294
295void
297{
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", Type::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::Duration::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::Duration::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::Duration::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::Duration::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::Duration::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::Duration::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::Duration::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::Duration::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.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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.
virtual void ConfigureProperties()
Change the configuration of the socket properties.
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.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
void DoTeardown() override
Teardown the TCP test.
void SetSegmentSize(SocketWho who, uint32_t segmentSize)
Forcefully set the segment size.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:47
static TypeId GetTypeId()
Get the type ID.
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
static constexpr auto UNIT
Definition: test.h:1286
a unique identifier for an interface.
Definition: type-id.h:59
std::string GetName() const
Get the name.
Definition: type-id.cc:992
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:145
#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:751
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
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.