A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7#include "tcp-error-model.h"
8#include "tcp-general-test.h"
9
10#include "ns3/log.h"
11#include "ns3/node.h"
12#include "ns3/simple-channel.h"
13#include "ns3/tcp-westwood-plus.h"
14
15using namespace ns3;
16
17NS_LOG_COMPONENT_DEFINE("TcpFastRetrTest");
18
19/**
20 * \ingroup internet-test
21 *
22 * \brief Test the fast retransmission
23 *
24 * Checking what is happening is not so easy, so there are a lot of variables
25 * which helps to keep track on what is happening.
26 * The idea is following sequence and ack numbers which are exchanged,
27 * testing if they are the same as the implementation transmits.
28 */
30{
31 public:
32 /**
33 * \brief Constructor
34 * \param congControl Type of congestion control.
35 * \param seqToKill Sequence number of the packet to drop.
36 * \param msg Test message.
37 */
38 TcpFastRetrTest(TypeId congControl, uint32_t seqToKill, const std::string& msg);
39
42
44
45 protected:
46 void RcvAck(const Ptr<const TcpSocketState> tcb, const TcpHeader& h, SocketWho who) override;
48 const TcpHeader& h,
49 SocketWho who) override;
50
52 const TcpSocketState::TcpCongState_t newValue) override;
53
54 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
55 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
56
57 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
58
59 /**
60 * \brief Check if the packet being dropped is the right one.
61 * \param ipH IPv4 header.
62 * \param tcpH TCP header.
63 * \param p The packet.
64 */
65 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
66 void FinalChecks() override;
67
68 void ConfigureProperties() override;
69 void ConfigureEnvironment() override;
70
71 bool m_pktDropped; //!< The packet has been dropped.
72 bool m_pktWasDropped; //!< The packet was dropped (according to the receiver).
73 uint32_t m_seqToKill; //!< Sequence number to drop.
74 uint32_t m_dupAckReceived; //!< DipACk received.
75
76 SequenceNumber32 m_previousAck; //!< Previous ACK received.
77 SequenceNumber32 m_sndNextExpSeq; //!< Sender next expected sequence number.
78 SequenceNumber32 m_rcvNextExpAck; //!< Receiver next expected sequence number.
79
80 uint32_t m_countRetr; //!< Retry counter.
81
82 uint32_t m_bytesRcvButNotAcked; //!< Number of bytes received but not acked.
83
85};
86
87TcpFastRetrTest::TcpFastRetrTest(TypeId typeId, uint32_t seqToKill, const std::string& msg)
88 : TcpGeneralTest(msg),
89 m_pktDropped(false),
90 m_pktWasDropped(false),
91 m_seqToKill(seqToKill),
92 m_dupAckReceived(0),
93 m_sndNextExpSeq(0),
94 m_rcvNextExpAck(1),
95 m_countRetr(0),
96 m_bytesRcvButNotAcked(0)
97{
98 m_congControlTypeId = typeId;
99}
100
101void
107
108void
114
117{
118 return nullptr;
119}
120
130
133{
135 socket->SetAttribute("MinRto", TimeValue(Seconds(10.0)));
136
137 return socket;
138}
139
140void
142{
143 if (who == SENDER)
144 {
145 // Nothing to check
146 NS_LOG_INFO("\tSENDER Rx " << h);
147 }
148 else if (who == RECEIVER)
149 {
150 NS_LOG_INFO("\tRECEIVER Rx " << h);
151
152 // Receiver has received the missing segment
154 {
155 m_pktDropped = false;
156 if (m_bytesRcvButNotAcked > 0)
157 {
160 }
161 }
162
163 // Count all the received bytes not acked
164 if (m_pktDropped)
165 {
167 }
168 }
169}
170
171void
173{
174 if (who == SENDER)
175 {
176 NS_LOG_INFO("\tSENDER Tx " << h << " size=" << p->GetSize());
177
179 {
180 // Spotted the retransmission!
181 m_countRetr++;
182 NS_TEST_ASSERT_MSG_EQ(m_countRetr, 1, "Segment retransmitted too many times");
183 }
184 else
185 {
186 // No delayed ACK involved here.
188 {
190 }
191
192 if (h.GetSequenceNumber().GetValue() != 50002)
193 {
196 "Sequence number expected differs");
197 }
198 }
199
200 // SYN or Pure ACK in three-way handshake, then we expect data
201 if ((m_sndNextExpSeq.GetValue() == 0) ||
202 (m_sndNextExpSeq.GetValue() == 1 && p->GetSize() == 32))
203 {
205 }
206 else
207 {
208 // Data segments
210 }
211 }
212 else if (who == RECEIVER)
213 {
214 NS_LOG_INFO("\tRECEIVER Tx, " << h << " size=" << p->GetSize());
215
217 {
219 0,
220 "SYN pkt has not 0 as initial sequence number."
221 "Probably, random sqn number has been implemented."
222 "Check this test");
223 }
224 else
225 {
227 1,
228 "ACK pkt has not 1 as sequence number."
229 "Probably, random sqn number has been implemented."
230 "Check this test");
231 }
232
233 // Accounted for delayed ACK, but not received.
234 while (h.GetAckNumber() < m_rcvNextExpAck)
235 {
237 }
238
239 if (m_rcvNextExpAck.GetValue() >= 50001)
240 {
241 m_rcvNextExpAck = 50002;
242 }
243
244 NS_TEST_ASSERT_MSG_EQ(h.GetAckNumber(), m_rcvNextExpAck, "ACKing something not considered");
245
246 if (m_pktDropped)
247 {
249 }
250 else
251 {
252 switch (m_rcvNextExpAck.GetValue())
253 {
254 case 0:
256 break;
257 case 1:
259 break;
260 case 50002:
261 break;
262 default:
264 }
265 }
266 }
267}
268
269void
271{
272 NS_LOG_FUNCTION(this << tcb << h << who);
273
274 if (who == SENDER)
275 {
277 {
278 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
280 "Not in OPEN state to respond to a loss");
282 0,
283 "Dupack different than 0 but no loss detected");
284 }
285 else if (h.GetAckNumber().GetValue() == m_seqToKill)
286 {
288
290 {
291 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
293 "Not in OPEN state for processing dupack");
294 }
295 else if (GetDupAckCount(SENDER) > 0 &&
297 {
298 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
300 "Not in DISORDER state after receiving dupacks");
301 }
303 {
304 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
306 "Not in RECOVERY state after reaching retxthresh");
307 }
308 }
309 }
310 else if (who == RECEIVER)
311 {
312 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
314 "Receiver not in OPEN state");
315 }
316}
317
318void
320 const TcpHeader& h,
321 SocketWho who)
322{
323 NS_LOG_FUNCTION(this << tcb << h << who);
324
325 if (who == SENDER)
326 {
327 if (m_previousAck == h.GetAckNumber() && h.GetAckNumber().GetValue() < 50002)
328 {
330
333 "Count of dupAck differs");
334
336 {
337 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
339 "DupAck less than ReTxThreshold but not "
340 "in DISORDER state");
341 }
342 else
343 {
344 NS_TEST_ASSERT_MSG_GT_OR_EQ(tcb->m_congState.Get(),
346 "DupAck greater than ReTxThreshold but not "
347 "in RECOVERY or LOSS state");
348 m_pktWasDropped = true;
349 }
350 }
351 else if (m_previousAck < h.GetAckNumber())
352 {
354 }
355
357 }
358 else if (who == RECEIVER)
359 {
360 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
362 "Different state than OPEN in the receiver");
363 }
364}
365
366void
368{
369 NS_TEST_ASSERT_MSG_EQ(true, false, "RTO isn't expected here");
370}
371
372void
374 const TcpSocketState::TcpCongState_t newValue)
375{
376 NS_LOG_FUNCTION(this << oldValue << newValue);
377
378 if (oldValue == TcpSocketState::CA_OPEN && newValue == TcpSocketState::CA_DISORDER)
379 {
380 }
381 else if (oldValue == TcpSocketState::CA_OPEN && newValue == TcpSocketState::CA_RECOVERY &&
383 {
384 NS_TEST_ASSERT_MSG_EQ(true, false, "Invalid OPEN to RECOVERY state change");
385 }
386 else if (oldValue == TcpSocketState::CA_DISORDER && newValue == TcpSocketState::CA_RECOVERY)
387 {
390 "DISORDER to RECOVERY state change but not reached "
391 "the ReTxThreshold");
392 }
393}
394
395void
397{
398 NS_LOG_FUNCTION(this << ipH << tcpH);
399
400 m_pktDropped = true;
402
405 "Packet dropped but sequence number differs");
406}
407
408void
410{
411 NS_TEST_ASSERT_MSG_EQ(m_pktWasDropped, true, "Packet was not dropped at all");
412 NS_TEST_ASSERT_MSG_EQ(m_countRetr, 1, "Segment was not retransmitted at all");
413 NS_TEST_ASSERT_MSG_EQ(m_rcvNextExpAck.GetValue(), 50002, "Not all data have been transmitted");
414}
415
416/**
417 * \ingroup internet-test
418 *
419 * \brief Testsuite for the fast retransmission
420 */
422{
423 public:
425 : TestSuite("tcp-fast-retr-test", Type::UNIT)
426 {
427 std::list<TypeId> types;
428 types.insert(types.begin(), TcpWestwoodPlus::GetTypeId());
429 types.insert(types.begin(), TcpNewReno::GetTypeId());
430
431 for (auto it = types.begin(); it != types.end(); ++it)
432 {
433 AddTestCase(new TcpFastRetrTest((*it), 5001, "Fast Retransmit testing"),
434 TestCase::Duration::QUICK);
435 }
436 }
437};
438
439static TcpFastRetrTestSuite g_TcpFastRetrTestSuite; //!< Static variable for test initialization
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:23
Smart pointer class similar to boost::intrusive_ptr.
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
General infrastructure for TCP testing.
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
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.
virtual void ConfigureProperties()
Change the configuration of the socket properties.
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.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
Header for the Transmission Control Protocol.
Definition tcp-header.h:36
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
uint8_t GetFlags() const
Get the flags.
SequenceNumber32 GetAckNumber() const
Get the ACK number.
static TypeId GetTypeId()
Get the type ID.
TcpCongState_t
Definition of the Congestion state machine.
@ CA_RECOVERY
CWND was reduced, we are fast-retransmitting.
@ CA_DISORDER
In all the respects it is "Open", but requires a bit more attention.
@ CA_OPEN
Normal state, no dubious events.
static TypeId GetTypeId()
Get the type ID.
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
static constexpr auto UNIT
Definition test.h:1291
a unique identifier for an interface.
Definition type-id.h:48
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#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:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
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:134
#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:905
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
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:684
static TcpFastRetrTestSuite g_TcpFastRetrTestSuite
Static variable for test initialization.