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 #include "tcp-error-model.h"
20 
21 #include "ns3/node.h"
22 #include "ns3/log.h"
23 #include "ns3/tcp-westwood.h"
24 #include "ns3/simple-channel.h"
25 #include "tcp-general-test.h"
26 #include "tcp-error-model.h"
27 
28 NS_LOG_COMPONENT_DEFINE ("TcpRtoTest");
29 
30 using namespace ns3;
31 
45 class TcpRtoTest : public TcpGeneralTest
46 {
47 public:
53  TcpRtoTest (TypeId &congControl, const std::string &msg);
54 
55 protected:
56 
57  virtual Ptr<TcpSocketMsgBase> CreateSenderSocket (Ptr<Node> node);
58  virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
59  virtual void RcvAck (const Ptr<const TcpSocketState> tcb,
60  const TcpHeader& h, SocketWho who);
61  virtual void ProcessedAck (const Ptr<const TcpSocketState> tcb,
62  const TcpHeader& h, SocketWho who);
63  virtual void FinalChecks ();
64  virtual void ConfigureProperties ();
65  virtual void ConfigureEnvironment ();
66 
67 private:
70 };
71 
72 TcpRtoTest::TcpRtoTest (TypeId &congControl, const std::string &desc)
73  : TcpGeneralTest (desc),
74  m_afterRTOExpired (false),
75  m_segmentReceived (false)
76 {
77  m_congControlTypeId = congControl;
78 }
79 
80 void
82 {
83  TcpGeneralTest::ConfigureEnvironment ();
84  SetAppPktCount (100);
85 }
86 
87 void
89 {
90  TcpGeneralTest::ConfigureProperties ();
92 }
93 
96 {
97  // Get a really low RTO, and let them fire as soon as possible since
98  // we are interested only in what happen after it expires
99  Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket (node);
100  socket->SetAttribute ("MinRto", TimeValue (Seconds (0.5)));
101 
102  return socket;
103 }
104 
105 void
107 {
108  // In this test, the RTO fires for the first segment (and no more).
109  // This function is called after the management of the RTO expiration,
110  // and because of this we must check all the involved variables.
112  "Second RTO expired");
113  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_LOSS,
114  "Ack state machine not in LOSS state after a loss");
115 
116  m_afterRTOExpired = true;
117 }
118 
119 void
121  SocketWho who)
122 {
123  // Called after the first ack is received (the lost segment has been
124  // successfully retransmitted. We must check on the sender that variables
125  // are in the same state as they where after AfterRTOExpired if it is the first
126  // ACK after the loss; in every other case, all must be OPEN and the counter
127  // set to 0.
128 
129  if (m_afterRTOExpired && who == SENDER)
130  {
131  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_LOSS,
132  "Ack state machine not in LOSS state after a loss");
133  }
134  else
135  {
136  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_OPEN,
137  "Ack state machine not in OPEN state after recovering "
138  "from loss");
139  }
140 }
141 
142 void
144  SocketWho who)
145 {
146  // Called after the ACK processing. Every time we should be in OPEN state,
147  // without any packet lost or marked as retransmitted, in both the sockets
148 
149  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_OPEN,
150  "Ack state machine not in OPEN state after recovering "
151  "from loss");
152 
153  if (who == SENDER)
154  {
155  m_afterRTOExpired = false;
156  m_segmentReceived = true;
157  }
158 }
159 
160 void
162 {
163  // At least one time we should process an ACK; otherwise, the segment
164  // has not been retransmitted, and this is bad
165 
167  "Retransmission has not been done");
168 }
169 
170 
182 {
183 public:
189  TcpSsThreshRtoTest (TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &msg);
190 
191 protected:
192 
195  virtual void BytesInFlightTrace (uint32_t oldValue, uint32_t newValue);
196  virtual void SsThreshTrace (uint32_t oldValue, uint32_t newValue);
197  virtual void BeforeRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
198  virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
199 
200  virtual void ConfigureEnvironment ();
201 
208  void PktDropped (const Ipv4Header &ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
209 
210 private:
211  uint32_t m_bytesInFlight;
213  uint32_t m_ssThreshSocket; //<! the ssThresh as computed by the socket
214  uint32_t m_seqToDrop;
216 };
217 
218 TcpSsThreshRtoTest::TcpSsThreshRtoTest (TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &desc)
219  : TcpGeneralTest (desc),
220  m_seqToDrop (seqToDrop),
221  m_minRtoTime (minRto)
222 {
223  m_congControlTypeId = congControl;
224 }
225 
226 void
228 {
229  TcpGeneralTest::ConfigureEnvironment ();
230  SetAppPktCount (100);
233 }
234 
237 {
238  Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket (node);
239  socket->SetAttribute ("MinRto", TimeValue (m_minRtoTime));
240  NS_LOG_DEBUG("TcpSsThreshRtoTest create sender socket");
241 
242  return socket;
243 }
244 
247 {
248  NS_LOG_DEBUG("TcpSsThreshRtoTest create errorModel");
249 
250  Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel> ();
251 
252  for (uint32_t i = 0; i<3; ++i)
253  {
254  errorModel->AddSeqToKill (SequenceNumber32 (m_seqToDrop));
255  }
256 
258 
259  return errorModel;
260 }
261 
262 void
265 {
266  NS_LOG_DEBUG ("DROPPED! " << tcpH);
267 }
268 
269 void
270 TcpSsThreshRtoTest::BytesInFlightTrace (uint32_t oldValue, uint32_t newValue)
271 {
272  NS_LOG_DEBUG ("Socket BytesInFlight=" << newValue);
273  m_bytesInFlight = newValue;
274 }
275 
276 void
277 TcpSsThreshRtoTest::SsThreshTrace (uint32_t oldValue, uint32_t newValue)
278 {
279  NS_LOG_DEBUG ("Socket ssThresh=" << newValue);
280  m_ssThreshSocket = newValue;
281 }
282 
283 void
285 {
286  NS_LOG_DEBUG ("Before RTO for connection " << who);
287 
288  // Get the bytesInFlight value before the expiration of the RTO
289 
290  if (who == SENDER)
291  {
293  NS_LOG_DEBUG("BytesInFlight before RTO Expired " << m_bytesInFlight);
294  }
295 }
296 
297 void
299 {
300  NS_LOG_DEBUG ("After RTO for " << who);
301  Ptr<TcpSocketMsgBase> senderSocket = GetSenderSocket();
302 
303  // compute the ssThresh according to RFC 5681, using the
304  uint32_t ssThresh = std::max(m_bytesInFlightBeforeRto/2, 2*tcb->m_segmentSize);
305 
306  NS_LOG_DEBUG ("ssThresh " << ssThresh << " m_ssThreshSocket " << m_ssThreshSocket);
307 
309  "Slow Start Threshold is incorrect");
310 }
311 
312 
322 {
323 public:
329  TcpTimeRtoTest (TypeId &congControl, const std::string &msg);
330 
331 protected:
334  virtual void ErrorClose (SocketWho who);
335  virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
336  virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
337  virtual void FinalChecks ();
338 
339  virtual void ConfigureEnvironment ();
340 
347  void PktDropped (const Ipv4Header &ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
348 
349 private:
352  bool m_closed;
353 };
354 
355 
356 TcpTimeRtoTest::TcpTimeRtoTest (TypeId &congControl, const std::string &desc)
357  : TcpGeneralTest (desc),
358  m_senderSentSegments (0),
359  m_closed (false)
360 {
361  m_congControlTypeId = congControl;
362 }
363 
364 void
366 {
367  TcpGeneralTest::ConfigureEnvironment ();
368  SetAppPktCount (100);
369 }
370 
371 
374 {
375  Ptr<TcpSocketMsgBase> s = TcpGeneralTest::CreateSenderSocket (node);
376  s->SetAttribute ("DataRetries", UintegerValue (6));
377 
378  return s;
379 }
380 
383 {
384  Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel> ();
385 
386  // Drop packet for 7 times. At the 7th, the connection should be dropped.
387  for (uint32_t i = 0; i<7; ++i)
388  {
389  errorModel->AddSeqToKill (SequenceNumber32 (1));
390  }
391 
393 
394  return errorModel;
395 }
396 
397 void
399 {
400  NS_LOG_FUNCTION (this << p << h << who);
401 
402  if (who == SENDER)
403  {
405  NS_LOG_INFO ("Measured RTO:" << GetRto (SENDER).GetSeconds ());
406 
407  if (h.GetFlags () & TcpHeader::SYN)
408  {
410 
411  Time s_rto = GetRto (SENDER);
413  "SYN packet sent without respecting "
414  "ConnTimeout attribute");
415  }
416  else
417  {
418  NS_LOG_INFO ("TX: " << h << m_senderSentSegments);
419 
421  "First packet has been correctly sent");
422 
423  // Remember, from RFC:
424  // m_rto = Max (m_rtt->GetEstimate () +
425  // Max (m_clockGranularity, m_rtt->GetVariation ()*4), m_minRto);
426 
427  if (m_senderSentSegments == 2)
428  { // ACK of SYN-ACK, rto set for the first time, since now we have
429  // an estimation of RTT
430 
431  Ptr<RttEstimator> rttEstimator = GetRttEstimator (SENDER);
432  Time clockGranularity = GetClockGranularity (SENDER);
433  m_previousRTO = rttEstimator->GetEstimate ();
434 
435  if (clockGranularity > rttEstimator->GetVariation ()*4)
436  {
437  m_previousRTO += clockGranularity;
438  }
439  else
440  {
441  m_previousRTO += rttEstimator->GetVariation ()*4;
442  }
443 
445 
447  "RTO value differs from calculation");
448  }
449  else if (m_senderSentSegments == 3)
450  { // First data packet. RTO should be the same as before
451 
453  "RTO value has changed unexpectedly");
454 
455  }
456  }
457  }
458  else if (who == RECEIVER)
459  {
460 
461  }
462 }
463 
464 void
466 {
467  m_closed = true;
468 }
469 
470 void
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 
490 void
493 {
494  NS_LOG_INFO ("DROPPED! " << tcpH);
495 }
496 
497 void
499 {
501  "Socket has not been closed after retrying data retransmissions");
502 }
503 
504 
512 {
513 public:
514  TcpRtoTestSuite () : TestSuite ("tcp-rto-test", UNIT)
515  {
516  std::list<TypeId> types;
517  types.insert (types.begin (), TcpNewReno::GetTypeId ());
518  types.insert (types.begin (), TcpWestwood::GetTypeId ());
519 
520  for (std::list<TypeId>::iterator it = types.begin (); it != types.end (); ++it)
521  {
522  AddTestCase (new TcpRtoTest ((*it), (*it).GetName () + " RTO retransmit testing"), TestCase::QUICK);
523  uint32_t seqToDrop = 25001;
524  Time minRto = Seconds (0.5);
525  // With RTO of 0.5 seconds, BytesInFlight winds down to zero before RTO
526  AddTestCase (new TcpSsThreshRtoTest ((*it), seqToDrop, minRto, (*it).GetName () + " RTO ssthresh testing, set to 2*MSL"), TestCase::QUICK);
527  // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
528  minRto = Seconds (0.005);
529  AddTestCase (new TcpSsThreshRtoTest ((*it), seqToDrop, minRto, (*it).GetName () + " RTO ssthresh testing, set to half of BytesInFlight"), TestCase::QUICK);
530  AddTestCase (new TcpTimeRtoTest ((*it), (*it).GetName () + " RTO timing testing"), TestCase::QUICK);
531  }
532  }
533 };
534 
536 
537 
virtual Ptr< ErrorModel > CreateReceiverErrorModel()
Create and return the error model to install in the receiver node.
virtual void ErrorClose(SocketWho who)
Socket closed with an error.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
virtual void ConfigureEnvironment()
Change the configuration of the evironment.
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:143
TcpSsThreshRtoTest(TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &msg)
Constructor.
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:173
virtual void ConfigureEnvironment()
Change the configuration of the evironment.
Ptr< TcpSocketMsgBase > GetSenderSocket()
Get the pointer to a previously created sender socket.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Called when a packet has been dropped.
void SetDropCallback(Callback< void, const Ipv4Header &, const TcpHeader &, Ptr< const Packet > > cb)
Set the drop callback.
A suite of tests to run.
Definition: test.h:1342
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1001
virtual void ConfigureEnvironment()
Change the configuration of the evironment.
Definition: tcp-rto-test.cc:81
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Called when a packet has been dropped.
static TcpSocketState::TcpCongState_t GetCongStateFrom(Ptr< const TcpSocketState > tcb)
Convenience function to retrieve the ACK state from a TCB.
uint32_t m_segmentSize
Segment size.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:277
Time GetMinRto(SocketWho who)
Get the minimun RTO attribute.
static TcpRtoTestSuite g_TcpRtoTestSuite
Static variable for test initialization.
This test suite implements a Unit Test.
Definition: test.h:1352
Packet header for IPv4.
Definition: ipv4-header.h:33
virtual void ConfigureProperties()
Change the configuration of the socket properties.
Definition: tcp-rto-test.cc:88
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
#define max(a, b)
Definition: 80211b.c:45
virtual void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue)
Bytes in flight changes.
AttributeValue implementation for Time.
Definition: nstime.h:1055
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
Hold an unsigned integer type.
Definition: uinteger.h:44
SocketWho
Used as parameter of methods, specifies on what node the caller is interested (e.g.
#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:168
bool m_segmentReceived
True if segments have been received.
Definition: tcp-rto-test.cc:69
#define Max(a, b)
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
virtual void FinalChecks()
Performs the (eventual) final checks through test asserts.
void SetInitialSsThresh(SocketWho who, uint32_t initialSsThresh)
Forcefully set the initial ssth.
virtual void FinalChecks()
Performs the (eventual) final checks through test asserts.
#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:380
TCP RTO TestSuite.
Testing the ssthresh behavior after the RTO expires.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time GetClockGranularity(SocketWho who)
Get the clock granularity attribute.
virtual void BeforeRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
Time GetVariation(void) const
Note that this is not a formal statistical variance; it has the the same units as the estimate...
Header for the Transmission Control Protocol.
Definition: tcp-header.h:44
uint32_t m_ssThreshSocket
void AddSeqToKill(const SequenceNumber32 &seq)
Add the sequence number to the list of segments to be killed.
bool m_closed
True if the connection is closed.
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
void SetAppPktCount(uint32_t pktCount)
Set app packet count.
void SetAppPktInterval(Time pktInterval)
Interval between app-generated packet.
TcpTimeRtoTest(TypeId &congControl, const std::string &msg)
Constructor.
Testing the moments after an RTO expiration.
Definition: tcp-rto-test.cc:45
uint32_t m_bytesInFlight
Store the number of bytes in flight.
virtual void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet transmitted down to IP layer.
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
Time m_previousRTO
Previous RTO.
uint32_t m_senderSentSegments
Number of segments sent.
General infrastructure for TCP testing.
bool m_afterRTOExpired
True if RTO is expired.
Definition: tcp-rto-test.cc:68
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:269
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:993
virtual void SsThreshTrace(uint32_t oldValue, uint32_t newValue)
Slow start threshold changes.
Time GetEstimate(void) const
gets the RTT estimate.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1009
Time GetConnTimeout(SocketWho who)
Get the retransmission time for the SYN segments.
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
Definition: tcp-rto-test.cc:95
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:185
Testing the timing of RTO.
uint32_t m_bytesInFlightBeforeRto
Store the number of bytes in flight before the RTO expiration.
TcpRtoTest(TypeId &congControl, const std::string &msg)
Constructor.
Definition: tcp-rto-test.cc:72
Ptr< RttEstimator > GetRttEstimator(SocketWho who)
Get the Rtt estimator of the socket.
a unique identifier for an interface.
Definition: type-id.h:58
virtual void ProcessedAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who)
Processed ack.
virtual void RcvAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who)
Received ack.
void SetPropagationDelay(Time propDelay)
Propagation delay of the bottleneck link.
virtual Ptr< ErrorModel > CreateReceiverErrorModel()
Create and return the error model to install in the receiver node.
TypeId m_congControlTypeId
Congestion control.
Time GetRto(SocketWho who)
Get the retransmission time.