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 "ns3/rtt-estimator.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:
191  TcpSsThreshRtoTest (TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &msg);
192 
193 protected:
194 
197  virtual void BytesInFlightTrace (uint32_t oldValue, uint32_t newValue);
198  virtual void SsThreshTrace (uint32_t oldValue, uint32_t newValue);
199  virtual void BeforeRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
200  virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
201 
202  virtual void ConfigureEnvironment ();
203 
210  void PktDropped (const Ipv4Header &ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
211 
212 private:
213  uint32_t m_bytesInFlight;
215  uint32_t m_ssThreshSocket;
216  uint32_t m_seqToDrop;
218 };
219 
220 TcpSsThreshRtoTest::TcpSsThreshRtoTest (TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &desc)
221  : TcpGeneralTest (desc),
222  m_seqToDrop (seqToDrop),
223  m_minRtoTime (minRto)
224 {
225  m_congControlTypeId = congControl;
226 }
227 
228 void
230 {
231  TcpGeneralTest::ConfigureEnvironment ();
232  SetAppPktCount (100);
235 }
236 
239 {
240  Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket (node);
241  socket->SetAttribute ("MinRto", TimeValue (m_minRtoTime));
242  NS_LOG_DEBUG("TcpSsThreshRtoTest create sender socket");
243 
244  return socket;
245 }
246 
249 {
250  NS_LOG_DEBUG("TcpSsThreshRtoTest create errorModel");
251 
252  Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel> ();
253 
254  for (uint32_t i = 0; i<3; ++i)
255  {
256  errorModel->AddSeqToKill (SequenceNumber32 (m_seqToDrop));
257  }
258 
260 
261  return errorModel;
262 }
263 
264 void
267 {
268  NS_LOG_DEBUG ("DROPPED! " << tcpH);
269 }
270 
271 void
272 TcpSsThreshRtoTest::BytesInFlightTrace (uint32_t oldValue, uint32_t newValue)
273 {
274  NS_LOG_DEBUG ("Socket BytesInFlight=" << newValue);
275  m_bytesInFlight = newValue;
276 }
277 
278 void
279 TcpSsThreshRtoTest::SsThreshTrace (uint32_t oldValue, uint32_t newValue)
280 {
281  NS_LOG_DEBUG ("Socket ssThresh=" << newValue);
282  m_ssThreshSocket = newValue;
283 }
284 
285 void
287 {
288  NS_LOG_DEBUG ("Before RTO for connection " << who);
289 
290  // Get the bytesInFlight value before the expiration of the RTO
291 
292  if (who == SENDER)
293  {
295  NS_LOG_DEBUG("BytesInFlight before RTO Expired " << m_bytesInFlight);
296  }
297 }
298 
299 void
301 {
302  NS_LOG_DEBUG ("After RTO for " << who);
303  Ptr<TcpSocketMsgBase> senderSocket = GetSenderSocket();
304 
305  // compute the ssThresh according to RFC 5681, using the
306  uint32_t ssThresh = std::max(m_bytesInFlightBeforeRto/2, 2*tcb->m_segmentSize);
307 
308  NS_LOG_DEBUG ("ssThresh " << ssThresh << " m_ssThreshSocket " << m_ssThreshSocket);
309 
311  "Slow Start Threshold is incorrect");
312 }
313 
314 
324 {
325 public:
331  TcpTimeRtoTest (TypeId &congControl, const std::string &msg);
332 
333 protected:
336  virtual void ErrorClose (SocketWho who);
337  virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
338  virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
339  virtual void FinalChecks ();
340 
341  virtual void ConfigureEnvironment ();
342 
349  void PktDropped (const Ipv4Header &ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
350 
351 private:
354  bool m_closed;
355 };
356 
357 
358 TcpTimeRtoTest::TcpTimeRtoTest (TypeId &congControl, const std::string &desc)
359  : TcpGeneralTest (desc),
360  m_senderSentSegments (0),
361  m_closed (false)
362 {
363  m_congControlTypeId = congControl;
364 }
365 
366 void
368 {
369  TcpGeneralTest::ConfigureEnvironment ();
370  SetAppPktCount (100);
371 }
372 
373 
376 {
377  Ptr<TcpSocketMsgBase> s = TcpGeneralTest::CreateSenderSocket (node);
378  s->SetAttribute ("DataRetries", UintegerValue (6));
379 
380  return s;
381 }
382 
385 {
386  Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel> ();
387 
388  // Drop packet for 7 times. At the 7th, the connection should be dropped.
389  for (uint32_t i = 0; i<7; ++i)
390  {
391  errorModel->AddSeqToKill (SequenceNumber32 (1));
392  }
393 
395 
396  return errorModel;
397 }
398 
399 void
401 {
402  NS_LOG_FUNCTION (this << p << h << who);
403 
404  if (who == SENDER)
405  {
407  NS_LOG_INFO ("Measured RTO:" << GetRto (SENDER).GetSeconds ());
408 
409  if (h.GetFlags () & TcpHeader::SYN)
410  {
412 
413  Time s_rto = GetRto (SENDER);
415  "SYN packet sent without respecting "
416  "ConnTimeout attribute");
417  }
418  else
419  {
420  NS_LOG_INFO ("TX: " << h << m_senderSentSegments);
421 
423  "First packet has been correctly sent");
424 
425  // Remember, from RFC:
426  // m_rto = Max (m_rtt->GetEstimate () +
427  // Max (m_clockGranularity, m_rtt->GetVariation ()*4), m_minRto);
428 
429  if (m_senderSentSegments == 2)
430  { // ACK of SYN-ACK, rto set for the first time, since now we have
431  // an estimation of RTT
432 
433  Ptr<RttEstimator> rttEstimator = GetRttEstimator (SENDER);
434  Time clockGranularity = GetClockGranularity (SENDER);
435  m_previousRTO = rttEstimator->GetEstimate ();
436 
437  if (clockGranularity > rttEstimator->GetVariation ()*4)
438  {
439  m_previousRTO += clockGranularity;
440  }
441  else
442  {
443  m_previousRTO += rttEstimator->GetVariation ()*4;
444  }
445 
447 
449  "RTO value differs from calculation");
450  }
451  else if (m_senderSentSegments == 3)
452  { // First data packet. RTO should be the same as before
453 
455  "RTO value has changed unexpectedly");
456 
457  }
458  }
459  }
460  else if (who == RECEIVER)
461  {
462 
463  }
464 }
465 
466 void
468 {
469  m_closed = true;
470 }
471 
472 void
474 {
475  NS_TEST_ASSERT_MSG_EQ (who, SENDER, "RTO in Receiver. That's unexpected");
476 
477  Time actualRto = GetRto (SENDER);
478 
479  if (actualRto < Seconds (60))
480  {
482  "RTO has not doubled after an expiration");
484  }
485  else
486  {
487  NS_TEST_ASSERT_MSG_EQ (actualRto, Seconds (60),
488  "RTO goes beyond 60 second limit");
489  }
490 }
491 
492 void
495 {
496  NS_LOG_INFO ("DROPPED! " << tcpH);
497 }
498 
499 void
501 {
503  "Socket has not been closed after retrying data retransmissions");
504 }
505 
506 
514 {
515 public:
516  TcpRtoTestSuite () : TestSuite ("tcp-rto-test", UNIT)
517  {
518  std::list<TypeId> types;
519  types.insert (types.begin (), TcpNewReno::GetTypeId ());
520  types.insert (types.begin (), TcpWestwood::GetTypeId ());
521 
522  for (std::list<TypeId>::iterator it = types.begin (); it != types.end (); ++it)
523  {
524  AddTestCase (new TcpRtoTest ((*it), (*it).GetName () + " RTO retransmit testing"), TestCase::QUICK);
525  uint32_t seqToDrop = 25001;
526  Time minRto = Seconds (0.5);
527  // With RTO of 0.5 seconds, BytesInFlight winds down to zero before RTO
528  AddTestCase (new TcpSsThreshRtoTest ((*it), seqToDrop, minRto, (*it).GetName () + " RTO ssthresh testing, set to 2*MSL"), TestCase::QUICK);
529  // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
530  minRto = Seconds (0.005);
531  AddTestCase (new TcpSsThreshRtoTest ((*it), seqToDrop, minRto, (*it).GetName () + " RTO ssthresh testing, set to half of BytesInFlight"), TestCase::QUICK);
532  AddTestCase (new TcpTimeRtoTest ((*it), (*it).GetName () + " RTO timing testing"), TestCase::QUICK);
533  }
534  }
535 };
536 
538 
539 
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:103
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 environment.
uint32_t m_seqToDrop
the sequence number to drop
TcpSsThreshRtoTest(TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &msg)
Constructor.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
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:1343
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:205
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
Time GetEstimate(void) const
gets the RTT estimate.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
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:281
Time GetMinRto(SocketWho who)
Get the minimum RTO attribute.
static TcpRtoTestSuite g_TcpRtoTestSuite
Static variable for test initialization.
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:43
virtual void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue)
Bytes in flight changes.
AttributeValue implementation for Time.
Definition: nstime.h:1353
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
#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:166
bool m_segmentReceived
True if segments have been received.
Definition: tcp-rto-test.cc:69
#define Max(a, b)
virtual void FinalChecks()
Performs the (eventual) final checks through test asserts.
void SetInitialSsThresh(SocketWho who, uint32_t initialSsThresh)
Forcefully set the initial ssthresh.
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:378
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.
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.
Time GetVariation(void) const
Note that this is not a formal statistical variance; it has the the same units as the estimate...
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: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.
SocketWho
Used as parameter of methods, specifies on what node the caller is interested (e.g.
General infrastructure for TCP testing.
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:173
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:273
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1289
virtual void SsThreshTrace(uint32_t oldValue, uint32_t newValue)
Slow start threshold changes.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1305
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:143
Time GetConnTimeout(SocketWho who)
Get the retransmission time for the SYN segments.
This test suite implements a Unit Test.
Definition: test.h:1353
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
Definition: tcp-rto-test.cc:95
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
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.
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:1642
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.