A Discrete-Event Network Simulator
API
tcp-rto-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Natale Patriciello <natale.patriciello@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 
19 #include "tcp-error-model.h"
20 #include "tcp-general-test.h"
21 
22 #include "ns3/log.h"
23 #include "ns3/node.h"
24 #include "ns3/rtt-estimator.h"
25 #include "ns3/simple-channel.h"
26 
27 NS_LOG_COMPONENT_DEFINE("TcpRtoTest");
28 
29 using namespace ns3;
30 
43 class TcpRtoTest : public TcpGeneralTest
44 {
45  public:
51  TcpRtoTest(const TypeId& congControl, const std::string& msg);
52 
53  protected:
54  Ptr<TcpSocketMsgBase> CreateSenderSocket(Ptr<Node> node) override;
55  void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
56  void RcvAck(const Ptr<const TcpSocketState> tcb, const TcpHeader& h, SocketWho who) override;
57  void ProcessedAck(const Ptr<const TcpSocketState> tcb,
58  const TcpHeader& h,
59  SocketWho who) override;
60  void FinalChecks() override;
61  void ConfigureProperties() override;
62  void ConfigureEnvironment() override;
63 
64  private:
67 };
68 
69 TcpRtoTest::TcpRtoTest(const TypeId& congControl, const std::string& desc)
70  : TcpGeneralTest(desc),
71  m_afterRTOExpired(false),
72  m_segmentReceived(false)
73 {
74  m_congControlTypeId = congControl;
75 }
76 
77 void
79 {
80  TcpGeneralTest::ConfigureEnvironment();
81  SetAppPktCount(100);
82 }
83 
84 void
86 {
87  TcpGeneralTest::ConfigureProperties();
89 }
90 
93 {
94  // Get a really low RTO, and let them fire as soon as possible since
95  // we are interested only in what happen after it expires
96  Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket(node);
97  socket->SetAttribute("MinRto", TimeValue(Seconds(0.5)));
98 
99  return socket;
100 }
101 
102 void
104 {
105  // In this test, the RTO fires for the first segment (and no more).
106  // This function is called after the management of the RTO expiration,
107  // and because of this we must check all the involved variables.
108  NS_TEST_ASSERT_MSG_EQ(m_afterRTOExpired, false, "Second RTO expired");
109  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
110  TcpSocketState::CA_LOSS,
111  "Ack state machine not in LOSS state after a loss");
112 
113  m_afterRTOExpired = true;
114 }
115 
116 void
118 {
119  // Called after the first ack is received (the lost segment has been
120  // successfully retransmitted. We must check on the sender that variables
121  // are in the same state as they where after AfterRTOExpired if it is the first
122  // ACK after the loss; in every other case, all must be OPEN and the counter
123  // set to 0.
124 
125  if (m_afterRTOExpired && who == SENDER)
126  {
127  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
128  TcpSocketState::CA_LOSS,
129  "Ack state machine not in LOSS state after a loss");
130  }
131  else
132  {
133  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
134  TcpSocketState::CA_OPEN,
135  "Ack state machine not in OPEN state after recovering "
136  "from loss");
137  }
138 }
139 
140 void
142 {
143  // Called after the ACK processing. Every time we should be in OPEN state,
144  // without any packet lost or marked as retransmitted, in both the sockets
145 
146  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
147  TcpSocketState::CA_OPEN,
148  "Ack state machine not in OPEN state after recovering "
149  "from loss");
150 
151  if (who == SENDER)
152  {
153  m_afterRTOExpired = false;
154  m_segmentReceived = true;
155  }
156 }
157 
158 void
160 {
161  // At least one time we should process an ACK; otherwise, the segment
162  // has not been retransmitted, and this is bad
163 
164  NS_TEST_ASSERT_MSG_EQ(m_segmentReceived, true, "Retransmission has not been done");
165 }
166 
177 {
178  public:
186  TcpSsThreshRtoTest(const TypeId& congControl,
187  uint32_t seqToDrop,
188  Time minRto,
189  const std::string& msg);
190 
191  protected:
194  void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override;
195  void SsThreshTrace(uint32_t oldValue, uint32_t newValue) override;
196  void BeforeRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
197  void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
198 
199  void ConfigureEnvironment() override;
200 
207  void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
208 
209  private:
210  uint32_t m_bytesInFlight;
211  uint32_t
213  uint32_t m_ssThreshSocket;
214  uint32_t m_seqToDrop;
216 };
217 
219  uint32_t seqToDrop,
220  Time minRto,
221  const std::string& desc)
222  : TcpGeneralTest(desc),
223  m_seqToDrop(seqToDrop),
224  m_minRtoTime(minRto)
225 {
226  m_congControlTypeId = congControl;
227 }
228 
229 void
231 {
232  TcpGeneralTest::ConfigureEnvironment();
233  SetAppPktCount(100);
236 }
237 
240 {
241  Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket(node);
242  socket->SetAttribute("MinRto", TimeValue(m_minRtoTime));
243  NS_LOG_DEBUG("TcpSsThreshRtoTest create sender socket");
244 
245  return socket;
246 }
247 
250 {
251  NS_LOG_DEBUG("TcpSsThreshRtoTest create errorModel");
252 
253  Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel>();
254 
255  for (uint32_t i = 0; i < 3; ++i)
256  {
258  }
259 
261 
262  return errorModel;
263 }
264 
265 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 
310  NS_TEST_ASSERT_MSG_EQ(ssThresh, m_ssThreshSocket, "Slow Start Threshold is incorrect");
311 }
312 
321 {
322  public:
328  TcpTimeRtoTest(const TypeId& congControl, const std::string& msg);
329 
330  protected:
333  void ErrorClose(SocketWho who) override;
334  void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
335  void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
336  void FinalChecks() override;
337 
338  void ConfigureEnvironment() override;
339 
346  void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
347 
348  private:
351  bool m_closed;
352 };
353 
354 TcpTimeRtoTest::TcpTimeRtoTest(const TypeId& congControl, const std::string& desc)
355  : TcpGeneralTest(desc),
356  m_senderSentSegments(0),
357  m_closed(false)
358 {
359  m_congControlTypeId = congControl;
360 }
361 
362 void
364 {
365  TcpGeneralTest::ConfigureEnvironment();
366  SetAppPktCount(100);
367 }
368 
371 {
372  Ptr<TcpSocketMsgBase> s = TcpGeneralTest::CreateSenderSocket(node);
373  s->SetAttribute("DataRetries", UintegerValue(6));
374 
375  return s;
376 }
377 
380 {
381  Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel>();
382 
383  // Drop packet for 7 times. At the 7th, the connection should be dropped.
384  for (uint32_t i = 0; i < 7; ++i)
385  {
386  errorModel->AddSeqToKill(SequenceNumber32(1));
387  }
388 
390 
391  return errorModel;
392 }
393 
394 void
396 {
397  NS_LOG_FUNCTION(this << p << h << who);
398 
399  if (who == SENDER)
400  {
402  NS_LOG_INFO("Measured RTO:" << GetRto(SENDER).GetSeconds());
403 
404  if (h.GetFlags() & TcpHeader::SYN)
405  {
407  1,
408  "Number of segments sent is different than 1");
409 
410  Time s_rto = GetRto(SENDER);
411  NS_TEST_ASSERT_MSG_EQ(s_rto,
413  "SYN packet sent without respecting "
414  "ConnTimeout attribute");
415  }
416  else
417  {
418  NS_LOG_INFO("TX: " << h << m_senderSentSegments);
419 
421  1,
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 
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 
449  Seconds(0.01),
450  "RTO value differs from calculation");
451  }
452  else if (m_senderSentSegments == 3)
453  { // First data packet. RTO should be the same as before
454 
457  Seconds(0.01),
458  "RTO value has changed unexpectedly");
459  }
460  }
461  }
462  else if (who == RECEIVER)
463  {
464  }
465 }
466 
467 void
469 {
470  m_closed = true;
471 }
472 
473 void
475 {
476  NS_TEST_ASSERT_MSG_EQ(who, SENDER, "RTO in Receiver. That's unexpected");
477 
478  Time actualRto = GetRto(SENDER);
479 
480  if (actualRto < Seconds(60))
481  {
482  NS_TEST_ASSERT_MSG_EQ_TOL(actualRto,
484  Seconds(0.01),
485  "RTO has not doubled after an expiration");
487  }
488  else
489  {
490  NS_TEST_ASSERT_MSG_EQ(actualRto, Seconds(60), "RTO goes beyond 60 second limit");
491  }
492 }
493 
494 void
496 {
497  NS_LOG_INFO("DROPPED! " << tcpH);
498 }
499 
500 void
502 {
504  true,
505  "Socket has not been closed after retrying data retransmissions");
506 }
507 
514 {
515  public:
517  : TestSuite("tcp-rto-test", UNIT)
518  {
519  std::list<TypeId> types = {
520  TcpNewReno::GetTypeId(),
521  };
522 
523  for (const auto& t : types)
524  {
525  AddTestCase(new TcpRtoTest(t, t.GetName() + " RTO retransmit testing"),
526  TestCase::QUICK);
527 
528  constexpr uint32_t seqToDrop = 25001;
529 
530  // With RTO of 0.5 seconds, BytesInFlight winds down to zero before RTO
532  seqToDrop,
533  Seconds(0.5),
534  t.GetName() + " RTO ssthresh testing, set to 2*MSL"),
535  TestCase::QUICK);
536 
537  // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
539  t,
540  seqToDrop,
541  Seconds(0.005),
542  t.GetName() + " RTO ssthresh testing, set to half of BytesInFlight"),
543  TestCase::QUICK);
544 
545  AddTestCase(new TcpTimeRtoTest(t, t.GetName() + " RTO timing testing"),
546  TestCase::QUICK);
547  }
548  }
549 };
550 
#define max(a, b)
Definition: 80211b.c:42
#define Max(a, b)
Testing the moments after an RTO expiration.
Definition: tcp-rto-test.cc:44
void ProcessedAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who) override
TcpRtoTest(const TypeId &congControl, const std::string &msg)
Constructor.
Definition: tcp-rto-test.cc:69
bool m_segmentReceived
True if segments have been received.
Definition: tcp-rto-test.cc:66
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
Definition: tcp-rto-test.cc:92
void ConfigureProperties() override
Change the configuration of the socket properties.
Definition: tcp-rto-test.cc:85
bool m_afterRTOExpired
True if RTO is expired.
Definition: tcp-rto-test.cc:65
void FinalChecks() override
Performs the (eventual) final checks through test asserts.
void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
void RcvAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who) override
void ConfigureEnvironment() override
Change the configuration of the environment.
Definition: tcp-rto-test.cc:78
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.
void ConfigureEnvironment() override
Change the configuration of the environment.
Time m_minRtoTime
the minimum RTO time
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
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.
Ptr< ErrorModel > CreateReceiverErrorModel() override
Create and return the error model to install in the receiver node.
void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
void BeforeRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
void SsThreshTrace(uint32_t oldValue, uint32_t newValue) override
Testing the timing of RTO.
uint32_t m_senderSentSegments
Number of segments sent.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Called when a packet has been dropped.
Ptr< ErrorModel > CreateReceiverErrorModel() override
Create and return the error model to install in the receiver node.
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
void FinalChecks() override
Performs the (eventual) final checks through test asserts.
Time m_previousRTO
Previous RTO.
void ErrorClose(SocketWho who) override
bool m_closed
True if the connection is closed.
void ConfigureEnvironment() override
Change the configuration of the environment.
TcpTimeRtoTest(const TypeId &congControl, const std::string &msg)
Constructor.
void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet transmitted down to IP layer.
void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
Packet header for IPv4.
Definition: ipv4-header.h:34
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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:47
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:118
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:148
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:301
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
a unique identifier for an interface.
Definition: type-id.h:59
Hold an unsigned integer type.
Definition: uinteger.h:45
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
#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:144
#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:337
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
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.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704
static TcpRtoTestSuite g_TcpRtoTestSuite
Static variable for test initialization.