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
26using namespace ns3;
27
28NS_LOG_COMPONENT_DEFINE ("TcpFastRetrTest");
29
42{
43public:
50 TcpFastRetrTest (TypeId congControl, uint32_t seqToKill, const std::string &msg);
51
54
56
57protected:
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
87
91
93
95
97};
98
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
114void
116{
117 TcpGeneralTest::ConfigureProperties ();
119}
120
121void
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
154void
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
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
185void
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.
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
286void
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
332void
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 {
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
375void
377{
378 NS_TEST_ASSERT_MSG_EQ (true, false, "RTO isn't expected here");
379}
380
381void
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
407void
409{
410 NS_LOG_FUNCTION (this << ipH << tcpH);
411
412 m_pktDropped = true;
414
416 "Packet dropped but sequence number differs");
417}
418
419void
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{
439public:
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)
Processed ack.
virtual void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who)
Rto has expired.
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)
Received ack.
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)
State on Ack state machine changes.
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.