A Discrete-Event Network Simulator
API
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
45{
46 public:
52 TcpRtoTest(const TypeId& congControl, const std::string& msg);
53
54 protected:
56 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
57 void RcvAck(const Ptr<const TcpSocketState> tcb, const TcpHeader& h, SocketWho who) override;
59 const TcpHeader& h,
60 SocketWho who) override;
61 void FinalChecks() override;
62 void ConfigureProperties() override;
63 void ConfigureEnvironment() override;
64
65 private:
68};
69
70TcpRtoTest::TcpRtoTest(const TypeId& congControl, const std::string& desc)
71 : TcpGeneralTest(desc),
72 m_afterRTOExpired(false),
73 m_segmentReceived(false)
74{
75 m_congControlTypeId = congControl;
76}
77
78void
80{
81 TcpGeneralTest::ConfigureEnvironment();
82 SetAppPktCount(100);
83}
84
85void
87{
88 TcpGeneralTest::ConfigureProperties();
90}
91
94{
95 // Get a really low RTO, and let them fire as soon as possible since
96 // we are interested only in what happen after it expires
97 Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket(node);
98 socket->SetAttribute("MinRto", TimeValue(Seconds(0.5)));
99
100 return socket;
101}
102
103void
105{
106 // In this test, the RTO fires for the first segment (and no more).
107 // This function is called after the management of the RTO expiration,
108 // and because of this we must check all the involved variables.
109 NS_TEST_ASSERT_MSG_EQ(m_afterRTOExpired, false, "Second RTO expired");
111 TcpSocketState::CA_LOSS,
112 "Ack state machine not in LOSS state after a loss");
113
114 m_afterRTOExpired = true;
115}
116
117void
119{
120 // Called after the first ack is received (the lost segment has been
121 // successfully retransmitted. We must check on the sender that variables
122 // are in the same state as they where after AfterRTOExpired if it is the first
123 // ACK after the loss; in every other case, all must be OPEN and the counter
124 // set to 0.
125
126 if (m_afterRTOExpired && who == SENDER)
127 {
129 TcpSocketState::CA_LOSS,
130 "Ack state machine not in LOSS state after a loss");
131 }
132 else
133 {
135 TcpSocketState::CA_OPEN,
136 "Ack state machine not in OPEN state after recovering "
137 "from loss");
138 }
139}
140
141void
143{
144 // Called after the ACK processing. Every time we should be in OPEN state,
145 // without any packet lost or marked as retransmitted, in both the sockets
146
148 TcpSocketState::CA_OPEN,
149 "Ack state machine not in OPEN state after recovering "
150 "from loss");
151
152 if (who == SENDER)
153 {
154 m_afterRTOExpired = false;
155 m_segmentReceived = true;
156 }
157}
158
159void
161{
162 // At least one time we should process an ACK; otherwise, the segment
163 // has not been retransmitted, and this is bad
164
165 NS_TEST_ASSERT_MSG_EQ(m_segmentReceived, true, "Retransmission has not been done");
166}
167
179{
180 public:
188 TcpSsThreshRtoTest(const TypeId& congControl,
189 uint32_t seqToDrop,
190 Time minRto,
191 const std::string& msg);
192
193 protected:
196 void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override;
197 void SsThreshTrace(uint32_t oldValue, uint32_t newValue) override;
198 void BeforeRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
199 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
200
201 void ConfigureEnvironment() override;
202
209 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
210
211 private:
218};
219
221 uint32_t seqToDrop,
222 Time minRto,
223 const std::string& desc)
224 : TcpGeneralTest(desc),
225 m_seqToDrop(seqToDrop),
226 m_minRtoTime(minRto)
227{
228 m_congControlTypeId = congControl;
229}
230
231void
233{
234 TcpGeneralTest::ConfigureEnvironment();
235 SetAppPktCount(100);
238}
239
242{
243 Ptr<TcpSocketMsgBase> socket = TcpGeneralTest::CreateSenderSocket(node);
244 socket->SetAttribute("MinRto", TimeValue(m_minRtoTime));
245 NS_LOG_DEBUG("TcpSsThreshRtoTest create sender socket");
246
247 return socket;
248}
249
252{
253 NS_LOG_DEBUG("TcpSsThreshRtoTest create errorModel");
254
255 Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel>();
256
257 for (uint32_t i = 0; i < 3; ++i)
258 {
260 }
261
263
264 return errorModel;
265}
266
267void
269{
270 NS_LOG_DEBUG("DROPPED! " << tcpH);
271}
272
273void
275{
276 NS_LOG_DEBUG("Socket BytesInFlight=" << newValue);
277 m_bytesInFlight = newValue;
278}
279
280void
282{
283 NS_LOG_DEBUG("Socket ssThresh=" << newValue);
284 m_ssThreshSocket = newValue;
285}
286
287void
289{
290 NS_LOG_DEBUG("Before RTO for connection " << who);
291
292 // Get the bytesInFlight value before the expiration of the RTO
293
294 if (who == SENDER)
295 {
297 NS_LOG_DEBUG("BytesInFlight before RTO Expired " << m_bytesInFlight);
298 }
299}
300
301void
303{
304 NS_LOG_DEBUG("After RTO for " << who);
305 Ptr<TcpSocketMsgBase> senderSocket = GetSenderSocket();
306
307 // compute the ssThresh according to RFC 5681, using the
308 uint32_t ssThresh = std::max(m_bytesInFlightBeforeRto / 2, 2 * tcb->m_segmentSize);
309
310 NS_LOG_DEBUG("ssThresh " << ssThresh << " m_ssThreshSocket " << m_ssThreshSocket);
311
312 NS_TEST_ASSERT_MSG_EQ(ssThresh, m_ssThreshSocket, "Slow Start Threshold is incorrect");
313}
314
324{
325 public:
331 TcpTimeRtoTest(const TypeId& congControl, const std::string& msg);
332
333 protected:
336 void ErrorClose(SocketWho who) override;
337 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
338 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
339 void FinalChecks() override;
340
341 void ConfigureEnvironment() override;
342
349 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
350
351 private:
354 bool m_closed;
355};
356
357TcpTimeRtoTest::TcpTimeRtoTest(const TypeId& congControl, const std::string& desc)
358 : TcpGeneralTest(desc),
359 m_senderSentSegments(0),
360 m_closed(false)
361{
362 m_congControlTypeId = congControl;
363}
364
365void
367{
368 TcpGeneralTest::ConfigureEnvironment();
369 SetAppPktCount(100);
370}
371
374{
375 Ptr<TcpSocketMsgBase> s = TcpGeneralTest::CreateSenderSocket(node);
376 s->SetAttribute("DataRetries", UintegerValue(6));
377
378 return s;
379}
380
383{
384 Ptr<TcpSeqErrorModel> errorModel = CreateObject<TcpSeqErrorModel>();
385
386 // Drop packet for 7 times. At the 7th, the connection should be dropped.
387 for (uint32_t i = 0; i < 7; ++i)
388 {
389 errorModel->AddSeqToKill(SequenceNumber32(1));
390 }
391
393
394 return errorModel;
395}
396
397void
399{
400 NS_LOG_FUNCTION(this << p << h << who);
401
402 if (who == SENDER)
403 {
405 NS_LOG_INFO("Measured RTO:" << GetRto(SENDER).GetSeconds());
406
407 if (h.GetFlags() & TcpHeader::SYN)
408 {
410 1,
411 "Number of segments sent is different than 1");
412
413 Time s_rto = GetRto(SENDER);
416 "SYN packet sent without respecting "
417 "ConnTimeout attribute");
418 }
419 else
420 {
421 NS_LOG_INFO("TX: " << h << m_senderSentSegments);
422
424 1,
425 "First packet was not correctly sent");
426
427 // Remember, from RFC:
428 // m_rto = Max (m_rtt->GetEstimate () +
429 // Max (m_clockGranularity, m_rtt->GetVariation ()*4), m_minRto);
430
431 if (m_senderSentSegments == 2)
432 { // ACK of SYN-ACK, rto set for the first time, since now we have
433 // an estimation of RTT
434
436 Time clockGranularity = GetClockGranularity(SENDER);
437 m_previousRTO = rttEstimator->GetEstimate();
438
439 if (clockGranularity > rttEstimator->GetVariation() * 4)
440 {
441 m_previousRTO += clockGranularity;
442 }
443 else
444 {
445 m_previousRTO += rttEstimator->GetVariation() * 4;
446 }
447
449
452 Seconds(0.01),
453 "RTO value differs from calculation");
454 }
455 else if (m_senderSentSegments == 3)
456 { // First data packet. RTO should be the same as before
457
460 Seconds(0.01),
461 "RTO value has changed unexpectedly");
462 }
463 }
464 }
465 else if (who == RECEIVER)
466 {
467 }
468}
469
470void
472{
473 m_closed = true;
474}
475
476void
478{
479 NS_TEST_ASSERT_MSG_EQ(who, SENDER, "RTO in Receiver. That's unexpected");
480
481 Time actualRto = GetRto(SENDER);
482
483 if (actualRto < Seconds(60))
484 {
487 Seconds(0.01),
488 "RTO has not doubled after an expiration");
490 }
491 else
492 {
493 NS_TEST_ASSERT_MSG_EQ(actualRto, Seconds(60), "RTO goes beyond 60 second limit");
494 }
495}
496
497void
499{
500 NS_LOG_INFO("DROPPED! " << tcpH);
501}
502
503void
505{
507 true,
508 "Socket has not been closed after retrying data retransmissions");
509}
510
518{
519 public:
521 : TestSuite("tcp-rto-test", UNIT)
522 {
523 std::list<TypeId> types = {
524 TcpNewReno::GetTypeId(),
525 };
526
527 for (const auto& t : types)
528 {
529 AddTestCase(new TcpRtoTest(t, t.GetName() + " RTO retransmit testing"),
530 TestCase::QUICK);
531
532 constexpr uint32_t seqToDrop = 25001;
533
534 // With RTO of 0.5 seconds, BytesInFlight winds down to zero before RTO
536 seqToDrop,
537 Seconds(0.5),
538 t.GetName() + " RTO ssthresh testing, set to 2*MSL"),
539 TestCase::QUICK);
540
541 // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
543 t,
544 seqToDrop,
545 Seconds(0.005),
546 t.GetName() + " RTO ssthresh testing, set to half of BytesInFlight"),
547 TestCase::QUICK);
548
549 AddTestCase(new TcpTimeRtoTest(t, t.GetName() + " RTO timing testing"),
550 TestCase::QUICK);
551 }
552 }
553};
554
#define max(a, b)
Definition: 80211b.c:43
#define Max(a, b)
Testing the moments after an RTO expiration.
Definition: tcp-rto-test.cc:45
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:70
bool m_segmentReceived
True if segments have been received.
Definition: tcp-rto-test.cc:67
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
Definition: tcp-rto-test.cc:93
void ConfigureProperties() override
Change the configuration of the socket properties.
Definition: tcp-rto-test.cc:86
bool m_afterRTOExpired
True if RTO is expired.
Definition: tcp-rto-test.cc:66
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:79
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: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.
Ptr< RttEstimator > GetRttEstimator(SocketWho who)
Get the Rtt estimator of the socket.
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.
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.
Ptr< TcpSocketMsgBase > GetSenderSocket()
Get the pointer to a previously created sender socket.
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
void AddSeqToKill(const SequenceNumber32 &seq)
Add the sequence number to the list of segments to be killed.
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
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
AttributeValue implementation for Time.
Definition: nstime.h:1425
a unique identifier for an interface.
Definition: type-id.h:60
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:144
#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:337
static TcpSocketState::TcpCongState_t GetCongStateFrom(Ptr< const TcpSocketState > tcb)
Convenience function to retrieve the ACK state from a TCB.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
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 TcpRtoTestSuite g_TcpRtoTestSuite
Static variable for test initialization.