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/tcp-westwood.h"
23 #include "ns3/simple-channel.h"
24 #include "tcp-general-test.h"
25 #include "tcp-error-model.h"
26 
27 NS_LOG_COMPONENT_DEFINE ("TcpRtoTest");
28 
29 using namespace ns3;
30 
44 class TcpRtoTest : public TcpGeneralTest
45 {
46 public:
52  TcpRtoTest (TypeId &congControl, const std::string &msg);
53 
54 protected:
55 
56  virtual Ptr<TcpSocketMsgBase> CreateSenderSocket (Ptr<Node> node);
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 
66 private:
69 };
70 
71 TcpRtoTest::TcpRtoTest (TypeId &congControl, const std::string &desc)
72  : TcpGeneralTest (desc),
73  m_afterRTOExpired (false),
74  m_segmentReceived (false)
75 {
76  m_congControlTypeId = congControl;
77 }
78 
79 void
81 {
82  TcpGeneralTest::ConfigureEnvironment ();
83  SetAppPktCount (100);
84 }
85 
86 void
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 
104 void
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 
118 void
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 
141 void
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 
159 void
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 {
182 public:
190  TcpSsThreshRtoTest (TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &msg);
191 
192 protected:
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 
211 private:
212  uint32_t m_bytesInFlight;
214  uint32_t m_ssThreshSocket;
215  uint32_t m_seqToDrop;
217 };
218 
219 TcpSsThreshRtoTest::TcpSsThreshRtoTest (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 
227 void
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  {
255  errorModel->AddSeqToKill (SequenceNumber32 (m_seqToDrop));
256  }
257 
259 
260  return errorModel;
261 }
262 
263 void
266 {
267  NS_LOG_DEBUG ("DROPPED! " << tcpH);
268 }
269 
270 void
271 TcpSsThreshRtoTest::BytesInFlightTrace (uint32_t oldValue, uint32_t newValue)
272 {
273  NS_LOG_DEBUG ("Socket BytesInFlight=" << newValue);
274  m_bytesInFlight = newValue;
275 }
276 
277 void
278 TcpSsThreshRtoTest::SsThreshTrace (uint32_t oldValue, uint32_t newValue)
279 {
280  NS_LOG_DEBUG ("Socket ssThresh=" << newValue);
281  m_ssThreshSocket = newValue;
282 }
283 
284 void
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 
298 void
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 {
324 public:
330  TcpTimeRtoTest (TypeId &congControl, const std::string &msg);
331 
332 protected:
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 
350 private:
353  bool m_closed;
354 };
355 
356 
357 TcpTimeRtoTest::TcpTimeRtoTest (TypeId &congControl, const std::string &desc)
358  : TcpGeneralTest (desc),
359  m_senderSentSegments (0),
360  m_closed (false)
361 {
362  m_congControlTypeId = congControl;
363 }
364 
365 void
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 
398 void
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  {
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 has been 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 
432  Ptr<RttEstimator> rttEstimator = GetRttEstimator (SENDER);
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 }
464 
465 void
467 {
468  m_closed = true;
469 }
470 
471 void
473 {
474  NS_TEST_ASSERT_MSG_EQ (who, SENDER, "RTO in Receiver. That's unexpected");
475 
476  Time actualRto = GetRto (SENDER);
477 
478  if (actualRto < Seconds (60))
479  {
481  "RTO has not doubled after an expiration");
483  }
484  else
485  {
486  NS_TEST_ASSERT_MSG_EQ (actualRto, Seconds (60),
487  "RTO goes beyond 60 second limit");
488  }
489 }
490 
491 void
494 {
495  NS_LOG_INFO ("DROPPED! " << tcpH);
496 }
497 
498 void
500 {
502  "Socket has not been closed after retrying data retransmissions");
503 }
504 
505 
513 {
514 public:
515  TcpRtoTestSuite () : TestSuite ("tcp-rto-test", UNIT)
516  {
517  std::list<TypeId> types;
518  types.insert (types.begin (), TcpNewReno::GetTypeId ());
519  types.insert (types.begin (), TcpWestwood::GetTypeId ());
520 
521  for (std::list<TypeId>::iterator it = types.begin (); it != types.end (); ++it)
522  {
523  AddTestCase (new TcpRtoTest ((*it), (*it).GetName () + " RTO retransmit testing"), TestCase::QUICK);
524  uint32_t seqToDrop = 25001;
525  Time minRto = Seconds (0.5);
526  // With RTO of 0.5 seconds, BytesInFlight winds down to zero before RTO
527  AddTestCase (new TcpSsThreshRtoTest ((*it), seqToDrop, minRto, (*it).GetName () + " RTO ssthresh testing, set to 2*MSL"), TestCase::QUICK);
528  // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
529  minRto = Seconds (0.005);
530  AddTestCase (new TcpSsThreshRtoTest ((*it), seqToDrop, minRto, (*it).GetName () + " RTO ssthresh testing, set to half of BytesInFlight"), TestCase::QUICK);
531  AddTestCase (new TcpTimeRtoTest ((*it), (*it).GetName () + " RTO timing testing"), TestCase::QUICK);
532  }
533  }
534 };
535 
537 
538 
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.
uint32_t m_seqToDrop
the sequence number to drop
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:1015
virtual void ConfigureEnvironment()
Change the configuration of the evironment.
Definition: tcp-rto-test.cc:80
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:87
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:1069
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:68
#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
the ssThresh as computed by the socket
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.
Time m_minRtoTime
the minimum RTO time
Testing the moments after an RTO expiration.
Definition: tcp-rto-test.cc:44
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:67
#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:1007
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:1023
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:94
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:71
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.