A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tcp-rto-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
19#include "tcp-error-model.h"
20#include "tcp-general-test.h"
21
22#include "ns3/log.h"
23#include "ns3/node.h"
24#include "ns3/rtt-estimator.h"
25#include "ns3/simple-channel.h"
26
27NS_LOG_COMPONENT_DEFINE("TcpRtoTest");
28
29using namespace ns3;
30
31/**
32 * \ingroup internet-test
33 *
34 * \brief Testing the moments after an RTO expiration
35 *
36 * The scope of this test is to be sure that, after an RTO expiration,
37 * the TCP implementation set the correct state in the ACK state machine,
38 * and marks the lost segment as lost; then, after the retransmission, the
39 * state is fully recovered. This is the base check, where only one segment
40 * (the first) is lost and retransmitted.
41 *
42 */
44{
45 public:
46 /**
47 * \brief Constructor.
48 * \param congControl Congestion control type.
49 * \param msg Test description.
50 */
51 TcpRtoTest(const TypeId& congControl, const std::string& msg);
52
53 protected:
55 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
56 void RcvAck(const Ptr<const TcpSocketState> tcb, const TcpHeader& h, SocketWho who) override;
58 const TcpHeader& h,
59 SocketWho who) override;
60 void FinalChecks() override;
61 void ConfigureProperties() override;
62 void ConfigureEnvironment() override;
63
64 private:
65 bool m_afterRTOExpired; //!< True if RTO is expired.
66 bool m_segmentReceived; //!< True if segments have been received.
67};
68
69TcpRtoTest::TcpRtoTest(const TypeId& congControl, const std::string& desc)
70 : TcpGeneralTest(desc),
71 m_afterRTOExpired(false),
72 m_segmentReceived(false)
73{
74 m_congControlTypeId = congControl;
75}
76
77void
79{
81 SetAppPktCount(100);
82}
83
84void
86{
89}
90
93{
94 // Get a really low RTO, and let them fire as soon as possible since
95 // we are interested only in what happen after it expires
97 socket->SetAttribute("MinRto", TimeValue(Seconds(0.5)));
98
99 return socket;
100}
101
102void
104{
105 // In this test, the RTO fires for the first segment (and no more).
106 // This function is called after the management of the RTO expiration,
107 // and because of this we must check all the involved variables.
108 NS_TEST_ASSERT_MSG_EQ(m_afterRTOExpired, false, "Second RTO expired");
109 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
111 "Ack state machine not in LOSS state after a loss");
112
113 m_afterRTOExpired = true;
114}
115
116void
118{
119 // Called after the first ack is received (the lost segment has been
120 // successfully retransmitted. We must check on the sender that variables
121 // are in the same state as they where after AfterRTOExpired if it is the first
122 // ACK after the loss; in every other case, all must be OPEN and the counter
123 // set to 0.
124
125 if (m_afterRTOExpired && who == SENDER)
126 {
127 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
129 "Ack state machine not in LOSS state after a loss");
130 }
131 else
132 {
133 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
135 "Ack state machine not in OPEN state after recovering "
136 "from loss");
137 }
138}
139
140void
142{
143 // Called after the ACK processing. Every time we should be in OPEN state,
144 // without any packet lost or marked as retransmitted, in both the sockets
145
146 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
148 "Ack state machine not in OPEN state after recovering "
149 "from loss");
150
151 if (who == SENDER)
152 {
153 m_afterRTOExpired = false;
154 m_segmentReceived = true;
155 }
156}
157
158void
160{
161 // At least one time we should process an ACK; otherwise, the segment
162 // has not been retransmitted, and this is bad
163
164 NS_TEST_ASSERT_MSG_EQ(m_segmentReceived, true, "Retransmission has not been done");
165}
166
167/**
168 * \ingroup internet-test
169 *
170 * \brief Testing the ssthresh behavior after the RTO expires
171 *
172 * The scope of this test is to be sure that, after an RTO expiration,
173 * the TCP implementation sets the correct ssthresh value
174 *
175 */
177{
178 public:
179 /**
180 * \brief Constructor.
181 * \param congControl congestion control type
182 * \param seqToDrop sequence number to drop
183 * \param minRto minimum RTO
184 * \param msg test description
185 */
186 TcpSsThreshRtoTest(const TypeId& congControl,
187 uint32_t seqToDrop,
188 Time minRto,
189 const std::string& msg);
190
191 protected:
194 void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override;
195 void SsThreshTrace(uint32_t oldValue, uint32_t newValue) override;
196 void BeforeRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
197 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
198
199 void ConfigureEnvironment() override;
200
201 /**
202 * \brief Called when a packet has been dropped.
203 * \param ipH IPv4 header.
204 * \param tcpH TCP header.
205 * \param p The packet.
206 */
207 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
208
209 private:
210 uint32_t m_bytesInFlight; //!< Store the number of bytes in flight
212 m_bytesInFlightBeforeRto; //!< Store the number of bytes in flight before the RTO expiration
213 uint32_t m_ssThreshSocket; //!< the ssThresh as computed by the socket
214 uint32_t m_seqToDrop; //!< the sequence number to drop
215 Time m_minRtoTime; //!< the minimum RTO time
216};
217
219 uint32_t seqToDrop,
220 Time minRto,
221 const std::string& desc)
222 : TcpGeneralTest(desc),
223 m_seqToDrop(seqToDrop),
224 m_minRtoTime(minRto)
225{
226 m_congControlTypeId = congControl;
227}
228
229void
231{
233 SetAppPktCount(100);
236}
237
240{
242 socket->SetAttribute("MinRto", TimeValue(m_minRtoTime));
243 NS_LOG_DEBUG("TcpSsThreshRtoTest create sender socket");
244
245 return socket;
246}
247
250{
251 NS_LOG_DEBUG("TcpSsThreshRtoTest create errorModel");
252
253 Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel>();
254
255 for (uint32_t i = 0; i < 3; ++i)
256 {
257 errorModel->AddSeqToKill(SequenceNumber32(m_seqToDrop));
258 }
259
260 errorModel->SetDropCallback(MakeCallback(&TcpSsThreshRtoTest::PktDropped, this));
261
262 return errorModel;
263}
264
265void
267{
268 NS_LOG_DEBUG("DROPPED! " << tcpH);
269}
270
271void
273{
274 NS_LOG_DEBUG("Socket BytesInFlight=" << newValue);
275 m_bytesInFlight = newValue;
276}
277
278void
280{
281 NS_LOG_DEBUG("Socket ssThresh=" << newValue);
282 m_ssThreshSocket = newValue;
283}
284
285void
287{
288 NS_LOG_DEBUG("Before RTO for connection " << who);
289
290 // Get the bytesInFlight value before the expiration of the RTO
291
292 if (who == SENDER)
293 {
295 NS_LOG_DEBUG("BytesInFlight before RTO Expired " << m_bytesInFlight);
296 }
297}
298
299void
301{
302 NS_LOG_DEBUG("After RTO for " << who);
303 Ptr<TcpSocketMsgBase> senderSocket = GetSenderSocket();
304
305 // compute the ssThresh according to RFC 5681, using the
306 uint32_t ssThresh = std::max(m_bytesInFlightBeforeRto / 2, 2 * tcb->m_segmentSize);
307
308 NS_LOG_DEBUG("ssThresh " << ssThresh << " m_ssThreshSocket " << m_ssThreshSocket);
309
310 NS_TEST_ASSERT_MSG_EQ(ssThresh, m_ssThreshSocket, "Slow Start Threshold is incorrect");
311}
312
313/**
314 * \ingroup internet-test
315 *
316 * \brief Testing the timing of RTO
317 *
318 * Checking if RTO is doubled ONLY after a retransmission.
319 */
321{
322 public:
323 /**
324 * \brief Constructor.
325 * \param congControl Congestion control type.
326 * \param msg Test description.
327 */
328 TcpTimeRtoTest(const TypeId& congControl, const std::string& msg);
329
330 protected:
333 void ErrorClose(SocketWho who) override;
334 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
335 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
336 void FinalChecks() override;
337
338 void ConfigureEnvironment() override;
339
340 /**
341 * \brief Called when a packet has been dropped.
342 * \param ipH IPv4 header.
343 * \param tcpH TCP header.
344 * \param p The packet.
345 */
346 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
347
348 private:
349 uint32_t m_senderSentSegments; //!< Number of segments sent.
350 Time m_previousRTO; //!< Previous RTO.
351 bool m_closed; //!< True if the connection is closed.
352};
353
354TcpTimeRtoTest::TcpTimeRtoTest(const TypeId& congControl, const std::string& desc)
355 : TcpGeneralTest(desc),
356 m_senderSentSegments(0),
357 m_closed(false)
358{
359 m_congControlTypeId = congControl;
360}
361
362void
364{
366 SetAppPktCount(100);
367}
368
371{
373 s->SetAttribute("DataRetries", UintegerValue(6));
374
375 return s;
376}
377
380{
381 Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel>();
382
383 // Drop packet for 7 times. At the 7th, the connection should be dropped.
384 for (uint32_t i = 0; i < 7; ++i)
385 {
386 errorModel->AddSeqToKill(SequenceNumber32(1));
387 }
388
389 errorModel->SetDropCallback(MakeCallback(&TcpTimeRtoTest::PktDropped, this));
390
391 return errorModel;
392}
393
394void
396{
397 NS_LOG_FUNCTION(this << p << h << who);
398
399 if (who == SENDER)
400 {
402 NS_LOG_INFO("Measured RTO:" << GetRto(SENDER).GetSeconds());
403
404 if (h.GetFlags() & TcpHeader::SYN)
405 {
407 1,
408 "Number of segments sent is different than 1");
409
410 Time s_rto = GetRto(SENDER);
413 "SYN packet sent without respecting "
414 "ConnTimeout attribute");
415 }
416 else
417 {
418 NS_LOG_INFO("TX: " << h << m_senderSentSegments);
419
421 1,
422 "First packet was not correctly sent");
423
424 // Remember, from RFC:
425 // m_rto = Max (m_rtt->GetEstimate () +
426 // Max (m_clockGranularity, m_rtt->GetVariation ()*4), m_minRto);
427
428 if (m_senderSentSegments == 2)
429 { // ACK of SYN-ACK, rto set for the first time, since now we have
430 // an estimation of RTT
431
433 Time clockGranularity = GetClockGranularity(SENDER);
434 m_previousRTO = rttEstimator->GetEstimate();
435
436 if (clockGranularity > rttEstimator->GetVariation() * 4)
437 {
438 m_previousRTO += clockGranularity;
439 }
440 else
441 {
442 m_previousRTO += rttEstimator->GetVariation() * 4;
443 }
444
446
449 Seconds(0.01),
450 "RTO value differs from calculation");
451 }
452 else if (m_senderSentSegments == 3)
453 { // First data packet. RTO should be the same as before
454
457 Seconds(0.01),
458 "RTO value has changed unexpectedly");
459 }
460 }
461 }
462 else if (who == RECEIVER)
463 {
464 }
465}
466
467void
469{
470 m_closed = true;
471}
472
473void
475{
476 NS_TEST_ASSERT_MSG_EQ(who, SENDER, "RTO in Receiver. That's unexpected");
477
478 Time actualRto = GetRto(SENDER);
479
480 if (actualRto < Seconds(60))
481 {
484 Seconds(0.01),
485 "RTO has not doubled after an expiration");
487 }
488 else
489 {
490 NS_TEST_ASSERT_MSG_EQ(actualRto, Seconds(60), "RTO goes beyond 60 second limit");
491 }
492}
493
494void
496{
497 NS_LOG_INFO("DROPPED! " << tcpH);
498}
499
500void
502{
504 true,
505 "Socket has not been closed after retrying data retransmissions");
506}
507
508/**
509 * \ingroup internet-test
510 *
511 * \brief TCP RTO TestSuite
512 */
514{
515 public:
517 : TestSuite("tcp-rto-test", Type::UNIT)
518 {
519 std::list<TypeId> types = {
521 };
522
523 for (const auto& t : types)
524 {
525 AddTestCase(new TcpRtoTest(t, t.GetName() + " RTO retransmit testing"),
526 TestCase::Duration::QUICK);
527
528 constexpr uint32_t seqToDrop = 25001;
529
530 // With RTO of 0.5 seconds, BytesInFlight winds down to zero before RTO
532 seqToDrop,
533 Seconds(0.5),
534 t.GetName() + " RTO ssthresh testing, set to 2*MSL"),
535 TestCase::Duration::QUICK);
536
537 // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
539 t,
540 seqToDrop,
541 Seconds(0.005),
542 t.GetName() + " RTO ssthresh testing, set to half of BytesInFlight"),
543 TestCase::Duration::QUICK);
544
545 AddTestCase(new TcpTimeRtoTest(t, t.GetName() + " RTO timing testing"),
546 TestCase::Duration::QUICK);
547 }
548 }
549};
550
551static TcpRtoTestSuite g_TcpRtoTestSuite; //!< Static variable for test initialization
#define Max(a, b)
Testing the moments after an RTO expiration.
Definition: tcp-rto-test.cc:44
void ProcessedAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who) override
Processed ack.
TcpRtoTest(const TypeId &congControl, const std::string &msg)
Constructor.
Definition: tcp-rto-test.cc:69
bool m_segmentReceived
True if segments have been received.
Definition: tcp-rto-test.cc:66
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
Definition: tcp-rto-test.cc:92
void ConfigureProperties() override
Change the configuration of the socket properties.
Definition: tcp-rto-test.cc:85
bool m_afterRTOExpired
True if RTO is expired.
Definition: tcp-rto-test.cc:65
void FinalChecks() override
Performs the (eventual) final checks through test asserts.
void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
Rto has expired.
void RcvAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who) override
Received ack.
void ConfigureEnvironment() override
Change the configuration of the environment.
Definition: tcp-rto-test.cc:78
TCP RTO TestSuite.
Testing the ssthresh behavior after the RTO expires.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Called when a packet has been dropped.
void ConfigureEnvironment() override
Change the configuration of the environment.
Time m_minRtoTime
the minimum RTO time
TcpSsThreshRtoTest(const TypeId &congControl, uint32_t seqToDrop, Time minRto, const std::string &msg)
Constructor.
uint32_t m_seqToDrop
the sequence number to drop
uint32_t m_ssThreshSocket
the ssThresh as computed by the socket
uint32_t m_bytesInFlight
Store the number of bytes in flight.
uint32_t m_bytesInFlightBeforeRto
Store the number of bytes in flight before the RTO expiration.
Ptr< ErrorModel > CreateReceiverErrorModel() override
Create and return the error model to install in the receiver node.
void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override
Bytes in flight changes.
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
void BeforeRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
Rto has expired.
void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
Rto has expired.
void SsThreshTrace(uint32_t oldValue, uint32_t newValue) override
Slow start threshold changes.
Testing the timing of RTO.
uint32_t m_senderSentSegments
Number of segments sent.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Called when a packet has been dropped.
Ptr< ErrorModel > CreateReceiverErrorModel() override
Create and return the error model to install in the receiver node.
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
void FinalChecks() override
Performs the (eventual) final checks through test asserts.
Time m_previousRTO
Previous RTO.
void ErrorClose(SocketWho who) override
Socket closed with an error.
bool m_closed
True if the connection is closed.
void ConfigureEnvironment() override
Change the configuration of the environment.
TcpTimeRtoTest(const TypeId &congControl, const std::string &msg)
Constructor.
void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet transmitted down to IP layer.
void AfterRTOExpired(const Ptr< const TcpSocketState > tcb, SocketWho who) override
Rto has expired.
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.
General infrastructure for TCP testing.
Ptr< RttEstimator > GetRttEstimator(SocketWho who)
Get the Rtt estimator of the socket.
virtual Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node)
Create and install the socket to install on the sender.
void SetPropagationDelay(Time propDelay)
Propagation delay of the bottleneck link.
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.
Time GetMinRto(SocketWho who)
Get the minimum RTO attribute.
virtual void ConfigureProperties()
Change the configuration of the socket properties.
Time GetClockGranularity(SocketWho who)
Get the clock granularity attribute.
Time GetRto(SocketWho who)
Get the retransmission time.
Time GetConnTimeout(SocketWho who)
Get the retransmission time for the SYN segments.
void SetAppPktInterval(Time pktInterval)
Interval between app-generated packet.
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.
Ptr< TcpSocketMsgBase > GetSenderSocket()
Get the pointer to a previously created sender socket.
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
static TypeId GetTypeId()
Get the type ID.
@ CA_LOSS
CWND was reduced due to RTO timeout or SACK reneging.
@ CA_OPEN
Normal state, no dubious events.
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
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
AttributeValue implementation for Time.
Definition: nstime.h:1406
a unique identifier for an interface.
Definition: type-id.h:59
Hold an unsigned integer type.
Definition: uinteger.h:45
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report and...
Definition: test.h:338
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1343
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
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:706
static TcpRtoTestSuite g_TcpRtoTestSuite
Static variable for test initialization.