A Discrete-Event Network Simulator
API
tcp-rto-test.cc
Go to the documentation of this file.
1/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2015 Natale Patriciello <natale.patriciello@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
20#include "ns3/node.h"
21#include "ns3/log.h"
22#include "ns3/simple-channel.h"
23#include "ns3/rtt-estimator.h"
24#include "tcp-general-test.h"
25#include "tcp-error-model.h"
26
27NS_LOG_COMPONENT_DEFINE ("TcpRtoTest");
28
29using namespace ns3;
30
45{
46public:
52 TcpRtoTest (const TypeId &congControl, const std::string &msg);
53
54protected:
55
57 virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
58 virtual void RcvAck (const Ptr<const TcpSocketState> tcb,
59 const TcpHeader& h, SocketWho who);
60 virtual void ProcessedAck (const Ptr<const TcpSocketState> tcb,
61 const TcpHeader& h, SocketWho who);
62 virtual void FinalChecks ();
63 virtual void ConfigureProperties ();
64 virtual void ConfigureEnvironment ();
65
66private:
69};
70
71TcpRtoTest::TcpRtoTest (const TypeId &congControl, const std::string &desc)
72 : TcpGeneralTest (desc),
73 m_afterRTOExpired (false),
74 m_segmentReceived (false)
75{
76 m_congControlTypeId = congControl;
77}
78
79void
81{
82 TcpGeneralTest::ConfigureEnvironment ();
83 SetAppPktCount (100);
84}
85
86void
88{
89 TcpGeneralTest::ConfigureProperties ();
91}
92
95{
96 // Get a really low RTO, and let them fire as soon as possible since
97 // we are interested only in what happen after it expires
98 Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket (node);
99 socket->SetAttribute ("MinRto", TimeValue (Seconds (0.5)));
100
101 return socket;
102}
103
104void
106{
107 // In this test, the RTO fires for the first segment (and no more).
108 // This function is called after the management of the RTO expiration,
109 // and because of this we must check all the involved variables.
111 "Second RTO expired");
112 NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_LOSS,
113 "Ack state machine not in LOSS state after a loss");
114
115 m_afterRTOExpired = true;
116}
117
118void
120 SocketWho who)
121{
122 // Called after the first ack is received (the lost segment has been
123 // successfully retransmitted. We must check on the sender that variables
124 // are in the same state as they where after AfterRTOExpired if it is the first
125 // ACK after the loss; in every other case, all must be OPEN and the counter
126 // set to 0.
127
128 if (m_afterRTOExpired && who == SENDER)
129 {
130 NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_LOSS,
131 "Ack state machine not in LOSS state after a loss");
132 }
133 else
134 {
135 NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_OPEN,
136 "Ack state machine not in OPEN state after recovering "
137 "from loss");
138 }
139}
140
141void
143 SocketWho who)
144{
145 // Called after the ACK processing. Every time we should be in OPEN state,
146 // without any packet lost or marked as retransmitted, in both the sockets
147
148 NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_OPEN,
149 "Ack state machine not in OPEN state after recovering "
150 "from loss");
151
152 if (who == SENDER)
153 {
154 m_afterRTOExpired = false;
155 m_segmentReceived = true;
156 }
157}
158
159void
161{
162 // At least one time we should process an ACK; otherwise, the segment
163 // has not been retransmitted, and this is bad
164
166 "Retransmission has not been done");
167}
168
169
181{
182public:
190 TcpSsThreshRtoTest (const TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &msg);
191
192protected:
193
196 virtual void BytesInFlightTrace (uint32_t oldValue, uint32_t newValue);
197 virtual void SsThreshTrace (uint32_t oldValue, uint32_t newValue);
198 virtual void BeforeRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
199 virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
200
201 virtual void ConfigureEnvironment ();
202
209 void PktDropped (const Ipv4Header &ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
210
211private:
217};
218
219TcpSsThreshRtoTest::TcpSsThreshRtoTest (const TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &desc)
220 : TcpGeneralTest (desc),
221 m_seqToDrop (seqToDrop),
222 m_minRtoTime (minRto)
223{
224 m_congControlTypeId = congControl;
225}
226
227void
229{
230 TcpGeneralTest::ConfigureEnvironment ();
231 SetAppPktCount (100);
234}
235
238{
239 Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket (node);
240 socket->SetAttribute ("MinRto", TimeValue (m_minRtoTime));
241 NS_LOG_DEBUG("TcpSsThreshRtoTest create sender socket");
242
243 return socket;
244}
245
248{
249 NS_LOG_DEBUG("TcpSsThreshRtoTest create errorModel");
250
251 Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel> ();
252
253 for (uint32_t i = 0; i < 3; ++i)
254 {
256 }
257
259
260 return errorModel;
261}
262
263void
266{
267 NS_LOG_DEBUG ("DROPPED! " << tcpH);
268}
269
270void
272{
273 NS_LOG_DEBUG ("Socket BytesInFlight=" << newValue);
274 m_bytesInFlight = newValue;
275}
276
277void
279{
280 NS_LOG_DEBUG ("Socket ssThresh=" << newValue);
281 m_ssThreshSocket = newValue;
282}
283
284void
286{
287 NS_LOG_DEBUG ("Before RTO for connection " << who);
288
289 // Get the bytesInFlight value before the expiration of the RTO
290
291 if (who == SENDER)
292 {
294 NS_LOG_DEBUG("BytesInFlight before RTO Expired " << m_bytesInFlight);
295 }
296}
297
298void
300{
301 NS_LOG_DEBUG ("After RTO for " << who);
302 Ptr<TcpSocketMsgBase> senderSocket = GetSenderSocket();
303
304 // compute the ssThresh according to RFC 5681, using the
305 uint32_t ssThresh = std::max (m_bytesInFlightBeforeRto / 2, 2 * tcb->m_segmentSize);
306
307 NS_LOG_DEBUG ("ssThresh " << ssThresh << " m_ssThreshSocket " << m_ssThreshSocket);
308
310 "Slow Start Threshold is incorrect");
311}
312
313
323{
324public:
330 TcpTimeRtoTest (const TypeId &congControl, const std::string &msg);
331
332protected:
335 virtual void ErrorClose (SocketWho who);
336 virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
337 virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
338 virtual void FinalChecks ();
339
340 virtual void ConfigureEnvironment ();
341
348 void PktDropped (const Ipv4Header &ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
349
350private:
353 bool m_closed;
354};
355
356
357TcpTimeRtoTest::TcpTimeRtoTest (const TypeId &congControl, const std::string &desc)
358 : TcpGeneralTest (desc),
359 m_senderSentSegments (0),
360 m_closed (false)
361{
362 m_congControlTypeId = congControl;
363}
364
365void
367{
368 TcpGeneralTest::ConfigureEnvironment ();
369 SetAppPktCount (100);
370}
371
372
375{
376 Ptr<TcpSocketMsgBase> s = TcpGeneralTest::CreateSenderSocket (node);
377 s->SetAttribute ("DataRetries", UintegerValue (6));
378
379 return s;
380}
381
384{
385 Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel> ();
386
387 // Drop packet for 7 times. At the 7th, the connection should be dropped.
388 for (uint32_t i = 0; i < 7; ++i)
389 {
390 errorModel->AddSeqToKill (SequenceNumber32 (1));
391 }
392
394
395 return errorModel;
396}
397
398void
400{
401 NS_LOG_FUNCTION (this << p << h << who);
402
403 if (who == SENDER)
404 {
406 NS_LOG_INFO ("Measured RTO:" << GetRto (SENDER).GetSeconds ());
407
408 if (h.GetFlags () & TcpHeader::SYN)
409 {
410 NS_TEST_ASSERT_MSG_EQ (m_senderSentSegments, 1, "Number of segments sent is different than 1");
411
412 Time s_rto = GetRto (SENDER);
414 "SYN packet sent without respecting "
415 "ConnTimeout attribute");
416 }
417 else
418 {
419 NS_LOG_INFO ("TX: " << h << m_senderSentSegments);
420
422 "First packet was not correctly sent");
423
424 // Remember, from RFC:
425 // m_rto = Max (m_rtt->GetEstimate () +
426 // Max (m_clockGranularity, m_rtt->GetVariation ()*4), m_minRto);
427
428 if (m_senderSentSegments == 2)
429 { // ACK of SYN-ACK, rto set for the first time, since now we have
430 // an estimation of RTT
431
433 Time clockGranularity = GetClockGranularity (SENDER);
434 m_previousRTO = rttEstimator->GetEstimate ();
435
436 if (clockGranularity > rttEstimator->GetVariation () * 4)
437 {
438 m_previousRTO += clockGranularity;
439 }
440 else
441 {
442 m_previousRTO += rttEstimator->GetVariation () * 4;
443 }
444
446
448 "RTO value differs from calculation");
449 }
450 else if (m_senderSentSegments == 3)
451 { // First data packet. RTO should be the same as before
452
454 "RTO value has changed unexpectedly");
455
456 }
457 }
458 }
459 else if (who == RECEIVER)
460 {
461 }
462}
463
464void
466{
467 m_closed = true;
468}
469
470void
472{
473 NS_TEST_ASSERT_MSG_EQ (who, SENDER, "RTO in Receiver. That's unexpected");
474
475 Time actualRto = GetRto (SENDER);
476
477 if (actualRto < Seconds (60))
478 {
480 "RTO has not doubled after an expiration");
482 }
483 else
484 {
485 NS_TEST_ASSERT_MSG_EQ (actualRto, Seconds (60),
486 "RTO goes beyond 60 second limit");
487 }
488}
489
490void
493{
494 NS_LOG_INFO ("DROPPED! " << tcpH);
495}
496
497void
499{
501 "Socket has not been closed after retrying data retransmissions");
502}
503
504
512{
513public:
514 TcpRtoTestSuite () : TestSuite ("tcp-rto-test", UNIT)
515 {
516 std::list<TypeId> types = {
517 TcpNewReno::GetTypeId (),
518 };
519
520 for (const auto &t : types)
521 {
522 AddTestCase (new TcpRtoTest (t, t.GetName () + " RTO retransmit testing"), TestCase::QUICK);
523
524 constexpr uint32_t seqToDrop = 25001;
525
526 // With RTO of 0.5 seconds, BytesInFlight winds down to zero before RTO
528 t, seqToDrop, Seconds (0.5),
529 t.GetName () + " RTO ssthresh testing, set to 2*MSL"),
530 TestCase::QUICK);
531
532 // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
534 t, seqToDrop, Seconds (0.005),
535 t.GetName () + " RTO ssthresh testing, set to half of BytesInFlight"),
536 TestCase::QUICK);
537
538 AddTestCase (new TcpTimeRtoTest (t, t.GetName () + " RTO timing testing"), TestCase::QUICK);
539 }
540 }
541};
542
#define max(a, b)
Definition: 80211b.c:43
#define Max(a, b)
Testing the moments after an RTO expiration.
Definition: tcp-rto-test.cc:45
virtual void ConfigureEnvironment()
Change the configuration of the environment.
Definition: tcp-rto-test.cc:80
TcpRtoTest(const TypeId &congControl, const std::string &msg)
Constructor.
Definition: tcp-rto-test.cc:71
bool m_segmentReceived
True if segments have been received.
Definition: tcp-rto-test.cc:68
bool m_afterRTOExpired
True if RTO is expired.
Definition: tcp-rto-test.cc:67
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
virtual void RcvAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who)
Received ack.
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
Definition: tcp-rto-test.cc:94
virtual void ConfigureProperties()
Change the configuration of the socket properties.
Definition: tcp-rto-test.cc:87
virtual void FinalChecks()
Performs the (eventual) final checks through test asserts.
virtual void ProcessedAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who)
Processed ack.
TCP RTO TestSuite.
Testing the ssthresh behavior after the RTO expires.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Called when a packet has been dropped.
virtual void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue)
Bytes in flight changes.
Time m_minRtoTime
the minimum RTO time
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
virtual void SsThreshTrace(uint32_t oldValue, uint32_t newValue)
Slow start threshold changes.
TcpSsThreshRtoTest(const TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &msg)
Constructor.
uint32_t m_seqToDrop
the sequence number to drop
uint32_t m_ssThreshSocket
the ssThresh as computed by the socket
virtual void ConfigureEnvironment()
Change the configuration of the environment.
virtual void BeforeRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
uint32_t m_bytesInFlight
Store the number of bytes in flight.
uint32_t m_bytesInFlightBeforeRto
Store the number of bytes in flight before the RTO expiration.
virtual Ptr< ErrorModel > CreateReceiverErrorModel()
Create and return the error model to install in the receiver node.
Testing the timing of RTO.
uint32_t m_senderSentSegments
Number of segments sent.
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Called when a packet has been dropped.
virtual void FinalChecks()
Performs the (eventual) final checks through test asserts.
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
Time m_previousRTO
Previous RTO.
bool m_closed
True if the connection is closed.
virtual Ptr< ErrorModel > CreateReceiverErrorModel()
Create and return the error model to install in the receiver node.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
TcpTimeRtoTest(const TypeId &congControl, const std::string &msg)
Constructor.
virtual void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet transmitted down to IP layer.
virtual void ErrorClose(SocketWho who)
Socket closed with an error.
Packet header for IPv4.
Definition: ipv4-header.h:34
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
void SetDropCallback(Callback< void, const Ipv4Header &, const TcpHeader &, Ptr< const Packet > > cb)
Set the drop callback.
General infrastructure for TCP testing.
Ptr< RttEstimator > GetRttEstimator(SocketWho who)
Get the Rtt estimator of the socket.
void SetPropagationDelay(Time propDelay)
Propagation delay of the bottleneck link.
void SetAppPktCount(uint32_t pktCount)
Set app packet count.
SocketWho
Used as parameter of methods, specifies on what node the caller is interested (e.g.
@ RECEIVER
Receiver node.
Time GetMinRto(SocketWho who)
Get the minimum RTO attribute.
Time GetClockGranularity(SocketWho who)
Get the clock granularity attribute.
Time GetRto(SocketWho who)
Get the retransmission time.
Time GetConnTimeout(SocketWho who)
Get the retransmission time for the SYN segments.
void SetAppPktInterval(Time pktInterval)
Interval between app-generated packet.
TypeId m_congControlTypeId
Congestion control.
void SetInitialSsThresh(SocketWho who, uint32_t initialSsThresh)
Forcefully set the initial ssthresh.
Ptr< TcpSocketMsgBase > GetSenderSocket()
Get the pointer to a previously created sender socket.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:45
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:143
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:173
void AddSeqToKill(const SequenceNumber32 &seq)
Add the sequence number to the list of segments to be killed.
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
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
AttributeValue implementation for Time.
Definition: nstime.h:1308
a unique identifier for an interface.
Definition: type-id.h:59
Hold an unsigned integer type.
Definition: uinteger.h:44
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#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_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report and...
Definition: test.h:323
static TcpSocketState::TcpCongState_t GetCongStateFrom(Ptr< const TcpSocketState > tcb)
Convenience function to retrieve the ACK state from a TCB.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1260
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
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.
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 TcpRtoTestSuite g_TcpRtoTestSuite
Static variable for test initialization.