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_TEST_ASSERT_MSG_EQ (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 
Test the fast retransmission.
virtual void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet received from IP layer.
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)
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
uint32_t m_seqToKill
Sequence number to drop.
SequenceNumber32 m_sndNextExpSeq
Sender next expected sequence number.
virtual Ptr< ErrorModel > CreateReceiverErrorModel()
Create and return the error model to install in the receiver node.
virtual void RcvAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who)
virtual void FinalChecks()
Performs the (eventual) final checks through test asserts.
bool m_pktDropped
The packet has been dropped.
virtual void CongStateTrace(const TcpSocketState::TcpCongState_t oldValue, const TcpSocketState::TcpCongState_t newValue)
SequenceNumber32 m_previousAck
Previous ACK received.
Ptr< TcpSeqErrorModel > m_errorModel
Error model.
uint32_t m_countRetr
Retry counter.
TcpFastRetrTest(TypeId congControl, uint32_t seqToKill, const std::string &msg)
Constructor.
SequenceNumber32 m_rcvNextExpAck
Receiver next expected sequence number.
bool m_pktWasDropped
The packet was dropped (according to the receiver).
virtual Ptr< ErrorModel > CreateSenderErrorModel()
Create and return the error model to install in the sender node.
uint32_t m_bytesRcvButNotAcked
Number of bytes received but not acked.
virtual void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet transmitted down to IP layer.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Check if the packet being dropped is the right one.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
virtual void ConfigureProperties()
Change the configuration of the socket properties.
uint32_t m_dupAckReceived
DipACk received.
Testsuite for the fast retransmission.
Packet header for IPv4.
Definition: ipv4-header.h:34
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:856
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
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.
uint32_t GetDelAckCount(SocketWho who)
Get the number of delayed ack (if present)
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.
uint32_t GetReTxThreshold(SocketWho who)
Get the retransmission threshold.
uint32_t GetDupAckCount(SocketWho who)
Get the number of dupack received.
uint32_t GetSegSize(SocketWho who)
Get the segment size of the node specified.
TypeId m_congControlTypeId
Congestion control.
void SetInitialSsThresh(SocketWho who, uint32_t initialSsThresh)
Forcefully set the initial ssthresh.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:45
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:143
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:173
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:149
void AddSeqToKill(const SequenceNumber32 &seq)
Add the sequence number to the list of segments to be killed.
TcpCongState_t
Definition of the Congestion state machine.
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1197
AttributeValue implementation for Time.
Definition: nstime.h:1308
a unique identifier for an interface.
Definition: type-id.h:59
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#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:281
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:141
#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:862
static TcpSocketState::TcpCongState_t GetCongStateFrom(Ptr< const TcpSocketState > tcb)
Convenience function to retrieve the ACK state from a TCB.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:1648
static TcpFastRetrTestSuite g_TcpFastRetrTestSuite
Static variable for test initialization.