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 * 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
26using namespace ns3;
27
28NS_LOG_COMPONENT_DEFINE("TcpFastRetrTest");
29
41{
42 public:
49 TcpFastRetrTest(TypeId congControl, uint32_t seqToKill, const std::string& msg);
50
53
55
56 protected:
57 void RcvAck(const Ptr<const TcpSocketState> tcb, const TcpHeader& h, SocketWho who) override;
59 const TcpHeader& h,
60 SocketWho who) override;
61
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
86
90
92
94
96};
97
98TcpFastRetrTest::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
112void
114{
117}
118
119void
121{
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{
146 socket->SetAttribute("MinRto", TimeValue(Seconds(10.0)));
147
148 return socket;
149}
150
151void
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
182void
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.
199 {
201 }
202
203 if (h.GetSequenceNumber().GetValue() != 50002)
204 {
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
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
284void
286{
287 NS_LOG_FUNCTION(this << tcb << h << who);
288
289 if (who == SENDER)
290 {
292 {
293 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
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 {
303
305 {
306 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
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(),
315 "Not in DISORDER state after receiving dupacks");
316 }
318 {
319 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
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(),
329 "Receiver not in OPEN state");
330 }
331}
332
333void
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(),
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(),
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 {
369 }
370
372 }
373 else if (who == RECEIVER)
374 {
375 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
377 "Different state than OPEN in the receiver");
378 }
379}
380
381void
383{
384 NS_TEST_ASSERT_MSG_EQ(true, false, "RTO isn't expected here");
385}
386
387void
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
410void
412{
413 NS_LOG_FUNCTION(this << ipH << tcpH);
414
415 m_pktDropped = true;
417
420 "Packet dropped but sequence number differs");
421}
422
423void
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", Type::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::Duration::QUICK);
450 }
451 }
452};
453
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
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.
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: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
static TypeId GetTypeId()
Get the type ID.
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.
@ 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:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
static constexpr auto UNIT
Definition: test.h:1286
AttributeValue implementation for Time.
Definition: nstime.h:1413
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:145
#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:916
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.