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.h"
25
26using namespace ns3;
27
28NS_LOG_COMPONENT_DEFINE("TcpFastRetrTest");
29
42{
43 public:
50 TcpFastRetrTest(TypeId congControl, uint32_t seqToKill, const std::string& msg);
51
54
56
57 protected:
58 void RcvAck(const Ptr<const TcpSocketState> tcb, const TcpHeader& h, SocketWho who) override;
60 const TcpHeader& h,
61 SocketWho who) override;
62
64 const TcpSocketState::TcpCongState_t newValue) override;
65
66 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
67 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
68
69 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
70
77 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
78 void FinalChecks() override;
79
80 void ConfigureProperties() override;
81 void ConfigureEnvironment() override;
82
87
91
93
95
97};
98
99TcpFastRetrTest::TcpFastRetrTest(TypeId typeId, uint32_t seqToKill, const std::string& msg)
100 : TcpGeneralTest(msg),
101 m_pktDropped(false),
102 m_pktWasDropped(false),
103 m_seqToKill(seqToKill),
104 m_dupAckReceived(0),
105 m_sndNextExpSeq(0),
106 m_rcvNextExpAck(1),
107 m_countRetr(0),
108 m_bytesRcvButNotAcked(0)
109{
110 m_congControlTypeId = typeId;
111}
112
113void
115{
116 TcpGeneralTest::ConfigureProperties();
118}
119
120void
122{
123 TcpGeneralTest::ConfigureEnvironment();
124 SetAppPktCount(100);
125}
126
129{
130 return nullptr;
131}
132
135{
136 m_errorModel = CreateObject<TcpSeqErrorModel>();
139
140 return m_errorModel;
141}
142
145{
146 Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket(node);
147 socket->SetAttribute("MinRto", TimeValue(Seconds(10.0)));
148
149 return socket;
150}
151
152void
154{
155 if (who == SENDER)
156 {
157 // Nothing to check
158 NS_LOG_INFO("\tSENDER Rx " << h);
159 }
160 else if (who == RECEIVER)
161 {
162 NS_LOG_INFO("\tRECEIVER Rx " << h);
163
164 // Receiver has received the missing segment
166 {
167 m_pktDropped = false;
168 if (m_bytesRcvButNotAcked > 0)
169 {
172 }
173 }
174
175 // Count all the received bytes not acked
176 if (m_pktDropped)
177 {
179 }
180 }
181}
182
183void
185{
186 if (who == SENDER)
187 {
188 NS_LOG_INFO("\tSENDER Tx " << h << " size=" << p->GetSize());
189
191 {
192 // Spotted the retransmission!
193 m_countRetr++;
194 NS_TEST_ASSERT_MSG_EQ(m_countRetr, 1, "Segment retransmitted too many times");
195 }
196 else
197 {
198 // No delayed ACK involved here.
200 {
202 }
203
204 if (h.GetSequenceNumber().GetValue() != 50002)
205 {
208 "Sequence number expected differs");
209 }
210 }
211
212 if (m_sndNextExpSeq.GetValue() == 0)
213 {
214 // SYN
216 }
217 else if (m_sndNextExpSeq.GetValue() == 1 && p->GetSize() == 32)
218 {
219 // Pure ACK in three-way handshake, then we expect data
221 }
222 else
223 {
224 // Data segments
226 }
227 }
228 else if (who == RECEIVER)
229 {
230 NS_LOG_INFO("\tRECEIVER Tx, " << h << " size=" << p->GetSize());
231
232 if (h.GetFlags() == (TcpHeader::SYN | TcpHeader::ACK))
233 {
235 0,
236 "SYN pkt has not 0 as initial sequence number."
237 "Probably, random sqn number has been implemented."
238 "Check this test");
239 }
240 else
241 {
243 1,
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
260 NS_TEST_ASSERT_MSG_EQ(h.GetAckNumber(), m_rcvNextExpAck, "ACKing something not considered");
261
262 if (m_pktDropped)
263 {
265 }
266 else
267 {
268 switch (m_rcvNextExpAck.GetValue())
269 {
270 case 0:
272 break;
273 case 1:
275 break;
276 case 50002:
277 break;
278 default:
280 }
281 }
282 }
283}
284
285void
287{
288 NS_LOG_FUNCTION(this << tcb << h << who);
289
290 if (who == SENDER)
291 {
293 {
295 TcpSocketState::CA_OPEN,
296 "Not in OPEN state to respond to a loss");
298 0,
299 "Dupack different than 0 but no loss detected");
300 }
301 else if (h.GetAckNumber().GetValue() == m_seqToKill)
302 {
304
306 {
308 TcpSocketState::CA_OPEN,
309 "Not in OPEN state for processing dupack");
310 }
311 else if (GetDupAckCount(SENDER) > 0 &&
313 {
315 TcpSocketState::CA_DISORDER,
316 "Not in DISORDER state after receiving dupacks");
317 }
319 {
321 TcpSocketState::CA_RECOVERY,
322 "Not in RECOVERY state after reaching retxthresh");
323 }
324 }
325 }
326 else if (who == RECEIVER)
327 {
329 TcpSocketState::CA_OPEN,
330 "Receiver not in OPEN state");
331 }
332}
333
334void
336 const TcpHeader& h,
337 SocketWho who)
338{
339 NS_LOG_FUNCTION(this << tcb << h << who);
340
341 if (who == SENDER)
342 {
343 if (m_previousAck == h.GetAckNumber() && h.GetAckNumber().GetValue() < 50002)
344 {
346
349 "Count of dupAck differs");
350
352 {
354 TcpSocketState::CA_DISORDER,
355 "DupAck less than ReTxThreshold but not "
356 "in DISORDER state");
357 }
358 else
359 {
361 TcpSocketState::CA_RECOVERY,
362 "DupAck greater than ReTxThreshold but not "
363 "in RECOVERY or LOSS state");
364 m_pktWasDropped = true;
365 }
366 }
367 else if (m_previousAck < h.GetAckNumber())
368 {
370 }
371
373 }
374 else if (who == RECEIVER)
375 {
377 TcpSocketState::CA_OPEN,
378 "Different state than OPEN in the receiver");
379 }
380}
381
382void
384{
385 NS_TEST_ASSERT_MSG_EQ(true, false, "RTO isn't expected here");
386}
387
388void
390 const TcpSocketState::TcpCongState_t newValue)
391{
392 NS_LOG_FUNCTION(this << oldValue << newValue);
393
394 if (oldValue == TcpSocketState::CA_OPEN && newValue == TcpSocketState::CA_DISORDER)
395 {
396 }
397 else if (oldValue == TcpSocketState::CA_OPEN && newValue == TcpSocketState::CA_RECOVERY &&
399 {
400 NS_TEST_ASSERT_MSG_EQ(true, false, "Invalid OPEN to RECOVERY state change");
401 }
402 else if (oldValue == TcpSocketState::CA_DISORDER && newValue == TcpSocketState::CA_RECOVERY)
403 {
406 "DISORDER to RECOVERY state change but not reached "
407 "the ReTxThreshold");
408 }
409}
410
411void
413{
414 NS_LOG_FUNCTION(this << ipH << tcpH);
415
416 m_pktDropped = true;
418
421 "Packet dropped but sequence number differs");
422}
423
424void
426{
427 NS_TEST_ASSERT_MSG_EQ(m_pktWasDropped, true, "Packet was not dropped at all");
428 NS_TEST_ASSERT_MSG_EQ(m_countRetr, 1, "Segment was not retransmitted at all");
429 NS_TEST_ASSERT_MSG_EQ(m_rcvNextExpAck.GetValue(), 50002, "Not all data have been transmitted");
430}
431
439{
440 public:
442 : TestSuite("tcp-fast-retr-test", UNIT)
443 {
444 std::list<TypeId> types;
445 types.insert(types.begin(), TcpWestwood::GetTypeId());
446 types.insert(types.begin(), TcpNewReno::GetTypeId());
447
448 for (std::list<TypeId>::iterator it = types.begin(); it != types.end(); ++it)
449 {
450 AddTestCase(new TcpFastRetrTest((*it), 5001, "Fast Retransmit testing"),
451 TestCase::QUICK);
452 }
453 }
454};
455
Test the fast retransmission.
void ProcessedAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who) override
Processed ack.
void ConfigureEnvironment() override
Change the configuration of the environment.
void CongStateTrace(const TcpSocketState::TcpCongState_t oldValue, const TcpSocketState::TcpCongState_t newValue) override
State on Ack state machine changes.
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
Rto has expired.
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
Received ack.
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:863
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
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:46
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:137
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:167
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:143
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:305
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
AttributeValue implementation for Time.
Definition: nstime.h:1425
a unique identifier for an interface.
Definition: type-id.h:60
#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
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: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:691
static TcpFastRetrTestSuite g_TcpFastRetrTestSuite
Static variable for test initialization.