A Discrete-Event Network Simulator
API
tcp-fast-retr-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 #include "tcp-error-model.h"
19 #include "tcp-general-test.h"
20 
21 #include "ns3/log.h"
22 #include "ns3/node.h"
23 #include "ns3/simple-channel.h"
24 #include "ns3/tcp-westwood-plus.h"
25 
26 using namespace ns3;
27 
28 NS_LOG_COMPONENT_DEFINE("TcpFastRetrTest");
29 
41 {
42  public:
49  TcpFastRetrTest(TypeId congControl, uint32_t seqToKill, const std::string& msg);
50 
51  Ptr<ErrorModel> CreateSenderErrorModel() override;
52  Ptr<ErrorModel> CreateReceiverErrorModel() override;
53 
54  Ptr<TcpSocketMsgBase> CreateSenderSocket(Ptr<Node> node) override;
55 
56  protected:
57  void RcvAck(const Ptr<const TcpSocketState> tcb, const TcpHeader& h, SocketWho who) override;
58  void ProcessedAck(const Ptr<const TcpSocketState> tcb,
59  const TcpHeader& h,
60  SocketWho who) override;
61 
62  void CongStateTrace(const TcpSocketState::TcpCongState_t oldValue,
63  const TcpSocketState::TcpCongState_t newValue) override;
64 
65  void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
66  void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
67 
68  void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
69 
76  void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
77  void FinalChecks() override;
78 
79  void ConfigureProperties() override;
80  void ConfigureEnvironment() override;
81 
82  bool m_pktDropped;
84  uint32_t m_seqToKill;
85  uint32_t m_dupAckReceived;
86 
90 
91  uint32_t m_countRetr;
92 
94 
96 };
97 
98 TcpFastRetrTest::TcpFastRetrTest(TypeId typeId, uint32_t seqToKill, const std::string& msg)
99  : TcpGeneralTest(msg),
100  m_pktDropped(false),
101  m_pktWasDropped(false),
102  m_seqToKill(seqToKill),
103  m_dupAckReceived(0),
104  m_sndNextExpSeq(0),
105  m_rcvNextExpAck(1),
106  m_countRetr(0),
107  m_bytesRcvButNotAcked(0)
108 {
109  m_congControlTypeId = typeId;
110 }
111 
112 void
114 {
115  TcpGeneralTest::ConfigureProperties();
117 }
118 
119 void
121 {
122  TcpGeneralTest::ConfigureEnvironment();
123  SetAppPktCount(100);
124 }
125 
128 {
129  return nullptr;
130 }
131 
134 {
135  m_errorModel = CreateObject<TcpSeqErrorModel>();
138 
139  return m_errorModel;
140 }
141 
144 {
145  Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket(node);
146  socket->SetAttribute("MinRto", TimeValue(Seconds(10.0)));
147 
148  return socket;
149 }
150 
151 void
153 {
154  if (who == SENDER)
155  {
156  // Nothing to check
157  NS_LOG_INFO("\tSENDER Rx " << h);
158  }
159  else if (who == RECEIVER)
160  {
161  NS_LOG_INFO("\tRECEIVER Rx " << h);
162 
163  // Receiver has received the missing segment
165  {
166  m_pktDropped = false;
167  if (m_bytesRcvButNotAcked > 0)
168  {
171  }
172  }
173 
174  // Count all the received bytes not acked
175  if (m_pktDropped)
176  {
178  }
179  }
180 }
181 
182 void
184 {
185  if (who == SENDER)
186  {
187  NS_LOG_INFO("\tSENDER Tx " << h << " size=" << p->GetSize());
188 
190  {
191  // Spotted the retransmission!
192  m_countRetr++;
193  NS_TEST_ASSERT_MSG_EQ(m_countRetr, 1, "Segment retransmitted too many times");
194  }
195  else
196  {
197  // No delayed ACK involved here.
198  while (h.GetSequenceNumber() < m_sndNextExpSeq)
199  {
201  }
202 
203  if (h.GetSequenceNumber().GetValue() != 50002)
204  {
206  h.GetSequenceNumber(),
207  "Sequence number expected differs");
208  }
209  }
210 
211  if (m_sndNextExpSeq.GetValue() == 0)
212  {
213  // SYN
215  }
216  else if (m_sndNextExpSeq.GetValue() == 1 && p->GetSize() == 32)
217  {
218  // Pure ACK in three-way handshake, then we expect data
220  }
221  else
222  {
223  // Data segments
225  }
226  }
227  else if (who == RECEIVER)
228  {
229  NS_LOG_INFO("\tRECEIVER Tx, " << h << " size=" << p->GetSize());
230 
231  if (h.GetFlags() == (TcpHeader::SYN | TcpHeader::ACK))
232  {
234  0,
235  "SYN pkt has not 0 as initial sequence number."
236  "Probably, random sqn number has been implemented."
237  "Check this test");
238  }
239  else
240  {
242  1,
243  "ACK pkt has not 1 as sequence number."
244  "Probably, random sqn number has been implemented."
245  "Check this test");
246  }
247 
248  // Accounted for delayed ACK, but not received.
249  while (h.GetAckNumber() < m_rcvNextExpAck)
250  {
252  }
253 
254  if (m_rcvNextExpAck.GetValue() >= 50001)
255  {
256  m_rcvNextExpAck = 50002;
257  }
258 
259  NS_TEST_ASSERT_MSG_EQ(h.GetAckNumber(), m_rcvNextExpAck, "ACKing something not considered");
260 
261  if (m_pktDropped)
262  {
264  }
265  else
266  {
267  switch (m_rcvNextExpAck.GetValue())
268  {
269  case 0:
271  break;
272  case 1:
274  break;
275  case 50002:
276  break;
277  default:
279  }
280  }
281  }
282 }
283 
284 void
286 {
287  NS_LOG_FUNCTION(this << tcb << h << who);
288 
289  if (who == SENDER)
290  {
291  if (h.GetAckNumber().GetValue() < m_seqToKill)
292  {
293  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
294  TcpSocketState::CA_OPEN,
295  "Not in OPEN state to respond to a loss");
297  0,
298  "Dupack different than 0 but no loss detected");
299  }
300  else if (h.GetAckNumber().GetValue() == m_seqToKill)
301  {
302  NS_TEST_ASSERT_MSG_EQ(GetDupAckCount(SENDER), m_dupAckReceived, "Dupack count differs");
303 
305  {
306  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
307  TcpSocketState::CA_OPEN,
308  "Not in OPEN state for processing dupack");
309  }
310  else if (GetDupAckCount(SENDER) > 0 &&
312  {
313  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
314  TcpSocketState::CA_DISORDER,
315  "Not in DISORDER state after receiving dupacks");
316  }
318  {
319  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
320  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(tcb->m_congState.Get(),
328  TcpSocketState::CA_OPEN,
329  "Receiver not in OPEN state");
330  }
331 }
332 
333 void
335  const TcpHeader& h,
336  SocketWho who)
337 {
338  NS_LOG_FUNCTION(this << tcb << h << who);
339 
340  if (who == SENDER)
341  {
342  if (m_previousAck == h.GetAckNumber() && h.GetAckNumber().GetValue() < 50002)
343  {
345 
348  "Count of dupAck differs");
349 
351  {
352  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
353  TcpSocketState::CA_DISORDER,
354  "DupAck less than ReTxThreshold but not "
355  "in DISORDER state");
356  }
357  else
358  {
359  NS_TEST_ASSERT_MSG_GT_OR_EQ(tcb->m_congState.Get(),
360  TcpSocketState::CA_RECOVERY,
361  "DupAck greater than ReTxThreshold but not "
362  "in RECOVERY or LOSS state");
363  m_pktWasDropped = true;
364  }
365  }
366  else if (m_previousAck < h.GetAckNumber())
367  {
368  m_dupAckReceived = 0;
369  }
370 
372  }
373  else if (who == RECEIVER)
374  {
375  NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
376  TcpSocketState::CA_OPEN,
377  "Different state than OPEN in the receiver");
378  }
379 }
380 
381 void
383 {
384  NS_TEST_ASSERT_MSG_EQ(true, false, "RTO isn't expected here");
385 }
386 
387 void
389  const TcpSocketState::TcpCongState_t newValue)
390 {
391  NS_LOG_FUNCTION(this << oldValue << newValue);
392 
393  if (oldValue == TcpSocketState::CA_OPEN && newValue == TcpSocketState::CA_DISORDER)
394  {
395  }
396  else if (oldValue == TcpSocketState::CA_OPEN && newValue == TcpSocketState::CA_RECOVERY &&
398  {
399  NS_TEST_ASSERT_MSG_EQ(true, false, "Invalid OPEN to RECOVERY state change");
400  }
401  else if (oldValue == TcpSocketState::CA_DISORDER && newValue == TcpSocketState::CA_RECOVERY)
402  {
405  "DISORDER to RECOVERY state change but not reached "
406  "the ReTxThreshold");
407  }
408 }
409 
410 void
412 {
413  NS_LOG_FUNCTION(this << ipH << tcpH);
414 
415  m_pktDropped = true;
417 
420  "Packet dropped but sequence number differs");
421 }
422 
423 void
425 {
426  NS_TEST_ASSERT_MSG_EQ(m_pktWasDropped, true, "Packet was not dropped at all");
427  NS_TEST_ASSERT_MSG_EQ(m_countRetr, 1, "Segment was not retransmitted at all");
428  NS_TEST_ASSERT_MSG_EQ(m_rcvNextExpAck.GetValue(), 50002, "Not all data have been transmitted");
429 }
430 
437 {
438  public:
440  : TestSuite("tcp-fast-retr-test", UNIT)
441  {
442  std::list<TypeId> types;
443  types.insert(types.begin(), TcpWestwoodPlus::GetTypeId());
444  types.insert(types.begin(), TcpNewReno::GetTypeId());
445 
446  for (auto it = types.begin(); it != types.end(); ++it)
447  {
448  AddTestCase(new TcpFastRetrTest((*it), 5001, "Fast Retransmit testing"),
449  TestCase::QUICK);
450  }
451  }
452 };
453 
Test the fast retransmission.
void ProcessedAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who) override
void ConfigureEnvironment() override
Change the configuration of the environment.
void CongStateTrace(const TcpSocketState::TcpCongState_t oldValue, const TcpSocketState::TcpCongState_t newValue) override
uint32_t m_seqToKill
Sequence number to drop.
Ptr< ErrorModel > CreateReceiverErrorModel() override
Create and return the error model to install in the receiver node.
SequenceNumber32 m_sndNextExpSeq
Sender next expected sequence number.
void ConfigureProperties() override
Change the configuration of the socket properties.
void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet transmitted down to IP layer.
bool m_pktDropped
The packet has been dropped.
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.
void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
SequenceNumber32 m_rcvNextExpAck
Receiver next expected sequence number.
bool m_pktWasDropped
The packet was dropped (according to the receiver).
uint32_t m_bytesRcvButNotAcked
Number of bytes received but not acked.
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Check if the packet being dropped is the right one.
void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet received from IP layer.
void FinalChecks() override
Performs the (eventual) final checks through test asserts.
uint32_t m_dupAckReceived
DipACk received.
Ptr< ErrorModel > CreateSenderErrorModel() override
Create and return the error model to install in the sender node.
void RcvAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who) override
Testsuite for the fast retransmission.
Packet header for IPv4.
Definition: ipv4-header.h:34
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
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.
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: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
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:124
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:301
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
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:202
#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_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:915
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
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 TcpFastRetrTestSuite g_TcpFastRetrTestSuite
Static variable for test initialization.