A Discrete-Event Network Simulator
API
tcp-fast-retr-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 "ns3/log.h"
20 #include "ns3/tcp-westwood.h"
21 #include "tcp-general-test.h"
22 #include "ns3/simple-channel.h"
23 #include "ns3/node.h"
24 #include "tcp-error-model.h"
25 
26 using namespace ns3;
27 
28 NS_LOG_COMPONENT_DEFINE ("TcpFastRetrTest");
29 
42 {
43 public:
50  TcpFastRetrTest (TypeId congControl, uint32_t seqToKill, const std::string &msg);
51 
52  virtual Ptr<ErrorModel> CreateSenderErrorModel ();
53  virtual Ptr<ErrorModel> CreateReceiverErrorModel ();
54 
55  virtual Ptr<TcpSocketMsgBase> CreateSenderSocket (Ptr<Node> node);
56 
57 protected:
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 
63  virtual void CongStateTrace (const TcpSocketState::TcpCongState_t oldValue,
64  const TcpSocketState::TcpCongState_t newValue);
65 
66  virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
67  virtual void Rx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who);
68 
69  virtual void AfterRTOExpired (const Ptr<const TcpSocketState> tcb, SocketWho who);
70 
77  void PktDropped (const Ipv4Header &ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
78  virtual void FinalChecks ();
79 
80  virtual void ConfigureProperties ();
81  virtual void ConfigureEnvironment ();
82 
83  bool m_pktDropped;
85  uint32_t m_seqToKill;
86  uint32_t m_dupAckReceived;
87 
91 
92  uint32_t m_countRetr;
93 
95 
97 };
98 
99 TcpFastRetrTest::TcpFastRetrTest (TypeId typeId, uint32_t seqToKill,
100  const std::string &msg)
101  : TcpGeneralTest (msg),
102  m_pktDropped (false),
103  m_pktWasDropped (false),
104  m_seqToKill (seqToKill),
105  m_dupAckReceived (0),
106  m_sndNextExpSeq (0),
107  m_rcvNextExpAck (1),
108  m_countRetr (0),
109  m_bytesRcvButNotAcked (0)
110 {
111  m_congControlTypeId = typeId;
112 }
113 
114 void
116 {
117  TcpGeneralTest::ConfigureProperties ();
119 }
120 
121 void
123 {
124  TcpGeneralTest::ConfigureEnvironment ();
125  SetAppPktCount (100);
126 }
127 
130 {
131  return 0;
132 }
133 
136 {
137  m_errorModel = CreateObject<TcpSeqErrorModel> ();
140 
141  return m_errorModel;
142 }
143 
144 
147 {
148  Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket (node);
149  socket->SetAttribute ("MinRto", TimeValue (Seconds (10.0)));
150 
151  return socket;
152 }
153 
154 void
156 {
157  if (who == SENDER)
158  {
159  // Nothing to check
160  NS_LOG_INFO ("\tSENDER Rx " << h);
161  }
162  else if (who == RECEIVER)
163  {
164  NS_LOG_INFO ("\tRECEIVER Rx " << h);
165 
166  // Receiver has received the missing segment
167  if (h.GetSequenceNumber ().GetValue () == m_seqToKill)
168  {
169  m_pktDropped = false;
170  if (m_bytesRcvButNotAcked > 0)
171  {
174  }
175  }
176 
177  // Count all the received bytes not acked
178  if (m_pktDropped)
179  {
181  }
182  }
183 }
184 
185 void
187 {
188  if (who == SENDER)
189  {
190  NS_LOG_INFO ("\tSENDER Tx " << h << " size=" << p->GetSize ());
191 
193  {
194  // Spotted the retransmission!
195  m_countRetr++;
197  "Segment retransmitted too many times");
198  }
199  else
200  {
201  // No delayed ACK involved here.
202  while (h.GetSequenceNumber () < m_sndNextExpSeq)
203  {
205  }
206 
207  if (h.GetSequenceNumber ().GetValue () != 50002)
208  {
210  "Sequence number expected differs");
211  }
212  }
213 
214  if (m_sndNextExpSeq.GetValue () == 0)
215  {
216  // SYN
218  }
219  else if (m_sndNextExpSeq.GetValue () == 1 && p->GetSize () == 32)
220  {
221  // Pure ACK in three-way handshake, then we expect data
223  }
224  else
225  {
226  // Data segments
228  }
229  }
230  else if (who == RECEIVER)
231  {
232  NS_LOG_INFO ("\tRECEIVER Tx, " << h << " size=" << p->GetSize ());
233 
234  if (h.GetFlags () == (TcpHeader::SYN | TcpHeader::ACK))
235  {
237  "SYN pkt has not 0 as initial sequence number."
238  "Probably, random sqn number has been implemented."
239  "Check this test");
240  }
241  else
242  {
244  "ACK pkt has not 1 as sequence number."
245  "Probably, random sqn number has been implemented."
246  "Check this test");
247  }
248 
249  // Accounted for delayed ACK, but not received.
250  while (h.GetAckNumber () < m_rcvNextExpAck)
251  {
253  }
254 
255  if (m_rcvNextExpAck.GetValue () >= 50001)
256  {
257  m_rcvNextExpAck = 50002;
258  }
259 
261  "ACKing something not considered");
262 
263  if (m_pktDropped)
264  {
266  }
267  else
268  {
269  switch (m_rcvNextExpAck.GetValue ())
270  {
271  case 0:
273  break;
274  case 1:
276  break;
277  case 50002:
278  break;
279  default:
281  }
282  }
283  }
284 }
285 
286 void
288  SocketWho who)
289 {
290  NS_LOG_FUNCTION (this << tcb << h << who);
291 
292  if (who == SENDER)
293  {
294  if (h.GetAckNumber ().GetValue () < m_seqToKill)
295  {
296  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_OPEN,
297  "Not in OPEN state to respond to a loss");
299  "Dupack different than 0 but no loss detected");
300  }
301  else if (h.GetAckNumber ().GetValue () == m_seqToKill)
302  {
304  "Dupack count differs");
305 
306  if (GetDupAckCount (SENDER) == 0 &&
308  {
309  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_OPEN,
310  "Not in OPEN state for processing dupack");
311  }
312  else if (GetDupAckCount (SENDER) > 0 &&
314  {
315  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_DISORDER,
316  "Not in DISORDER state after receiving dupacks");
317  }
319  {
320  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_RECOVERY,
321  "Not in RECOVERY state after reaching retxthresh");
322  }
323  }
324  }
325  else if (who == RECEIVER)
326  {
327  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_OPEN,
328  "Receiver not in OPEN state");
329  }
330 }
331 
332 void
334  SocketWho who)
335 {
336  NS_LOG_FUNCTION (this << tcb << h << who);
337 
338  if (who == SENDER)
339  {
340  if (m_previousAck == h.GetAckNumber () && h.GetAckNumber ().GetValue () < 50002)
341  {
343 
345  "Count of dupAck differs");
346 
348  {
349  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_DISORDER,
350  "DupAck less than ReTxThreshold but not "
351  "in DISORDER state");
352  }
353  else
354  {
355  NS_TEST_ASSERT_MSG_GT_OR_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_RECOVERY,
356  "DupAck greater than ReTxThreshold but not "
357  "in RECOVERY or LOSS state");
358  m_pktWasDropped = true;
359  }
360  }
361  else if (m_previousAck < h.GetAckNumber ())
362  {
363  m_dupAckReceived = 0;
364  }
365 
367  }
368  else if (who == RECEIVER)
369  {
370  NS_TEST_ASSERT_MSG_EQ (GetCongStateFrom (tcb), TcpSocketState::CA_OPEN,
371  "Different state than OPEN in the receiver");
372  }
373 }
374 
375 void
377 {
378  NS_ASSERT_MSG (true == false, "RTO isn't expected here");
379 }
380 
381 void
383  const TcpSocketState::TcpCongState_t newValue)
384 {
385  NS_LOG_FUNCTION (this << oldValue << newValue);
386 
387  if (oldValue == TcpSocketState::CA_OPEN && newValue == TcpSocketState::CA_DISORDER)
388  {
389  }
390  else if (oldValue == TcpSocketState::CA_OPEN
391  && newValue == TcpSocketState::CA_RECOVERY
392  && GetReTxThreshold (SENDER) > 1)
393  {
394  NS_TEST_ASSERT_MSG_EQ (true, false,
395  "Invalid OPEN to RECOVERY state change");
396  }
397  else if (oldValue == TcpSocketState::CA_DISORDER
398  && newValue == TcpSocketState::CA_RECOVERY)
399  {
401  "DISORDER to RECOVERY state change but not reached "
402  "the ReTxThreshold");
403  }
404 }
405 
406 
407 void
409 {
410  NS_LOG_FUNCTION (this << ipH << tcpH);
411 
412  m_pktDropped = true;
414 
416  "Packet dropped but sequence number differs");
417 }
418 
419 void
421 {
423  "Packet was not dropped at all");
425  "Segment was not retransmitted at all");
427  "Not all data have been transmitted");
428 }
429 
430 
438 {
439 public:
440  TcpFastRetrTestSuite () : TestSuite ("tcp-fast-retr-test", UNIT)
441  {
442  std::list<TypeId> types;
443  types.insert (types.begin (), TcpWestwood::GetTypeId ());
444  types.insert (types.begin (), TcpNewReno::GetTypeId ());
445 
446  for (std::list<TypeId>::iterator it = types.begin (); it != types.end (); ++it)
447  {
448  AddTestCase (new TcpFastRetrTest ((*it), 5001, "Fast Retransmit testing"), TestCase::QUICK);
449  }
450  }
451 };
452 
454 
uint32_t GetReTxThreshold(SocketWho who)
Get the retransmission threshold.
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 "...
uint32_t m_bytesRcvButNotAcked
Number of bytes received but not acked.
Test the fast retransmission.
SequenceNumber32 m_previousAck
Previous ACK received.
Testsuite for the fast retransmission.
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:852
NS_ASSERT_MSG(false, "Ipv4AddressGenerator::MaskToIndex(): Impossible")
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
bool m_pktWasDropped
The packet was dropped (according to the receiver).
virtual void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet transmitted down to IP layer.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Check if the packet being dropped is the right one.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:204
uint32_t m_countRetr
Retry counter.
static TcpSocketState::TcpCongState_t GetCongStateFrom(Ptr< const TcpSocketState > tcb)
Convenience function to retrieve the ACK state from a TCB.
TcpFastRetrTest(TypeId congControl, uint32_t seqToKill, const std::string &msg)
Constructor.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:280
uint32_t m_seqToKill
Sequence number to drop.
uint32_t GetDelAckCount(SocketWho who)
Get the number of delayed ack (if present)
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:149
Ptr< TcpSeqErrorModel > m_errorModel
Error model.
virtual void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet received from IP layer.
virtual void CongStateTrace(const TcpSocketState::TcpCongState_t oldValue, const TcpSocketState::TcpCongState_t newValue)
State on Ack state machine changes.
Packet header for IPv4.
Definition: ipv4-header.h:33
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
virtual void ProcessedAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who)
Processed ack.
AttributeValue implementation for Time.
Definition: nstime.h:1124
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
SequenceNumber32 m_sndNextExpSeq
Sender next expected sequence number.
virtual Ptr< ErrorModel > CreateReceiverErrorModel()
Create and return the error model to install in the receiver node.
#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
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
virtual void ConfigureProperties()
Change the configuration of the socket properties.
void SetInitialSsThresh(SocketWho who, uint32_t initialSsThresh)
Forcefully set the initial ssth.
TcpCongState_t
Definition of the Congestion state machine.
virtual void FinalChecks()
Performs the (eventual) final checks through test asserts.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Generic "sequence number" class.
uint32_t GetSegSize(SocketWho who)
Get the segment size of the node specified.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:44
uint32_t GetDupAckCount(SocketWho who)
Get the number of dupack received.
void AddSeqToKill(const SequenceNumber32 &seq)
Add the sequence number to the list of segments to be killed.
void SetAppPktCount(uint32_t pktCount)
Set app packet count.
bool m_pktDropped
The packet has been dropped.
SocketWho
Used as parameter of methods, specifies on what node the caller is interested (e.g.
virtual Ptr< ErrorModel > CreateSenderErrorModel()
Create and return the error model to install in the sender node.
General infrastructure for TCP testing.
uint32_t m_dupAckReceived
DipACk received.
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:173
SequenceNumber32 m_rcvNextExpAck
Receiver next expected sequence number.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1062
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:143
This test suite implements a Unit Test.
Definition: test.h:1351
virtual void RcvAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who)
Received ack.
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
#define NS_TEST_ASSERT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to a limit and report and abort if not...
Definition: test.h:1018
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:185
a unique identifier for an interface.
Definition: type-id.h:58
static TcpFastRetrTestSuite g_TcpFastRetrTestSuite
Static variable for test initialization.
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
TypeId m_congControlTypeId
Congestion control.