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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8#include "tcp-error-model.h"
9#include "tcp-general-test.h"
10
11#include "ns3/log.h"
12#include "ns3/node.h"
13#include "ns3/rtt-estimator.h"
14#include "ns3/simple-channel.h"
15
16NS_LOG_COMPONENT_DEFINE("TcpRtoTest");
17
18using namespace ns3;
19
20/**
21 * \ingroup internet-test
22 *
23 * \brief Testing the moments after an RTO expiration
24 *
25 * The scope of this test is to be sure that, after an RTO expiration,
26 * the TCP implementation set the correct state in the ACK state machine,
27 * and marks the lost segment as lost; then, after the retransmission, the
28 * state is fully recovered. This is the base check, where only one segment
29 * (the first) is lost and retransmitted.
30 *
31 */
33{
34 public:
35 /**
36 * \brief Constructor.
37 * \param congControl Congestion control type.
38 * \param msg Test description.
39 */
40 TcpRtoTest(const TypeId& congControl, const std::string& msg);
41
42 protected:
44 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
45 void RcvAck(const Ptr<const TcpSocketState> tcb, const TcpHeader& h, SocketWho who) override;
47 const TcpHeader& h,
48 SocketWho who) override;
49 void FinalChecks() override;
50 void ConfigureProperties() override;
51 void ConfigureEnvironment() override;
52
53 private:
54 bool m_afterRTOExpired; //!< True if RTO is expired.
55 bool m_segmentReceived; //!< True if segments have been received.
56};
57
58TcpRtoTest::TcpRtoTest(const TypeId& congControl, const std::string& desc)
59 : TcpGeneralTest(desc),
60 m_afterRTOExpired(false),
61 m_segmentReceived(false)
62{
63 m_congControlTypeId = congControl;
64}
65
66void
72
73void
79
82{
83 // Get a really low RTO, and let them fire as soon as possible since
84 // we are interested only in what happen after it expires
86 socket->SetAttribute("MinRto", TimeValue(Seconds(0.5)));
87
88 return socket;
89}
90
91void
93{
94 // In this test, the RTO fires for the first segment (and no more).
95 // This function is called after the management of the RTO expiration,
96 // and because of this we must check all the involved variables.
97 NS_TEST_ASSERT_MSG_EQ(m_afterRTOExpired, false, "Second RTO expired");
98 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
100 "Ack state machine not in LOSS state after a loss");
101
102 m_afterRTOExpired = true;
103}
104
105void
107{
108 // Called after the first ack is received (the lost segment has been
109 // successfully retransmitted. We must check on the sender that variables
110 // are in the same state as they where after AfterRTOExpired if it is the first
111 // ACK after the loss; in every other case, all must be OPEN and the counter
112 // set to 0.
113
114 if (m_afterRTOExpired && who == SENDER)
115 {
116 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
118 "Ack state machine not in LOSS state after a loss");
119 }
120 else
121 {
122 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
124 "Ack state machine not in OPEN state after recovering "
125 "from loss");
126 }
127}
128
129void
131{
132 // Called after the ACK processing. Every time we should be in OPEN state,
133 // without any packet lost or marked as retransmitted, in both the sockets
134
135 NS_TEST_ASSERT_MSG_EQ(tcb->m_congState.Get(),
137 "Ack state machine not in OPEN state after recovering "
138 "from loss");
139
140 if (who == SENDER)
141 {
142 m_afterRTOExpired = false;
143 m_segmentReceived = true;
144 }
145}
146
147void
149{
150 // At least one time we should process an ACK; otherwise, the segment
151 // has not been retransmitted, and this is bad
152
153 NS_TEST_ASSERT_MSG_EQ(m_segmentReceived, true, "Retransmission has not been done");
154}
155
156/**
157 * \ingroup internet-test
158 *
159 * \brief Testing the ssthresh behavior after the RTO expires
160 *
161 * The scope of this test is to be sure that, after an RTO expiration,
162 * the TCP implementation sets the correct ssthresh value
163 *
164 */
166{
167 public:
168 /**
169 * \brief Constructor.
170 * \param congControl congestion control type
171 * \param seqToDrop sequence number to drop
172 * \param minRto minimum RTO
173 * \param msg test description
174 */
175 TcpSsThreshRtoTest(const TypeId& congControl,
176 uint32_t seqToDrop,
177 Time minRto,
178 const std::string& msg);
179
180 protected:
183 void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override;
184 void SsThreshTrace(uint32_t oldValue, uint32_t newValue) override;
185 void BeforeRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
186 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
187
188 void ConfigureEnvironment() override;
189
190 /**
191 * \brief Called when a packet has been dropped.
192 * \param ipH IPv4 header.
193 * \param tcpH TCP header.
194 * \param p The packet.
195 */
196 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
197
198 private:
199 uint32_t m_bytesInFlight; //!< Store the number of bytes in flight
201 m_bytesInFlightBeforeRto; //!< Store the number of bytes in flight before the RTO expiration
202 uint32_t m_ssThreshSocket; //!< the ssThresh as computed by the socket
203 uint32_t m_seqToDrop; //!< the sequence number to drop
204 Time m_minRtoTime; //!< the minimum RTO time
205};
206
208 uint32_t seqToDrop,
209 Time minRto,
210 const std::string& desc)
211 : TcpGeneralTest(desc),
212 m_seqToDrop(seqToDrop),
213 m_minRtoTime(minRto)
214{
215 m_congControlTypeId = congControl;
216}
217
218void
226
229{
231 socket->SetAttribute("MinRto", TimeValue(m_minRtoTime));
232 NS_LOG_DEBUG("TcpSsThreshRtoTest create sender socket");
233
234 return socket;
235}
236
239{
240 NS_LOG_DEBUG("TcpSsThreshRtoTest create errorModel");
241
243
244 for (uint32_t i = 0; i < 3; ++i)
245 {
246 errorModel->AddSeqToKill(SequenceNumber32(m_seqToDrop));
247 }
248
249 errorModel->SetDropCallback(MakeCallback(&TcpSsThreshRtoTest::PktDropped, this));
250
251 return errorModel;
252}
253
254void
256{
257 NS_LOG_DEBUG("DROPPED! " << tcpH);
258}
259
260void
262{
263 NS_LOG_DEBUG("Socket BytesInFlight=" << newValue);
264 m_bytesInFlight = newValue;
265}
266
267void
269{
270 NS_LOG_DEBUG("Socket ssThresh=" << newValue);
271 m_ssThreshSocket = newValue;
272}
273
274void
276{
277 NS_LOG_DEBUG("Before RTO for connection " << who);
278
279 // Get the bytesInFlight value before the expiration of the RTO
280
281 if (who == SENDER)
282 {
284 NS_LOG_DEBUG("BytesInFlight before RTO Expired " << m_bytesInFlight);
285 }
286}
287
288void
290{
291 NS_LOG_DEBUG("After RTO for " << who);
292 Ptr<TcpSocketMsgBase> senderSocket = GetSenderSocket();
293
294 // compute the ssThresh according to RFC 5681, using the
295 uint32_t ssThresh = std::max(m_bytesInFlightBeforeRto / 2, 2 * tcb->m_segmentSize);
296
297 NS_LOG_DEBUG("ssThresh " << ssThresh << " m_ssThreshSocket " << m_ssThreshSocket);
298
299 NS_TEST_ASSERT_MSG_EQ(ssThresh, m_ssThreshSocket, "Slow Start Threshold is incorrect");
300}
301
302/**
303 * \ingroup internet-test
304 *
305 * \brief Testing the timing of RTO
306 *
307 * Checking if RTO is doubled ONLY after a retransmission.
308 */
310{
311 public:
312 /**
313 * \brief Constructor.
314 * \param congControl Congestion control type.
315 * \param msg Test description.
316 */
317 TcpTimeRtoTest(const TypeId& congControl, const std::string& msg);
318
319 protected:
322 void ErrorClose(SocketWho who) override;
323 void AfterRTOExpired(const Ptr<const TcpSocketState> tcb, SocketWho who) override;
324 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
325 void FinalChecks() override;
326
327 void ConfigureEnvironment() override;
328
329 /**
330 * \brief Called when a packet has been dropped.
331 * \param ipH IPv4 header.
332 * \param tcpH TCP header.
333 * \param p The packet.
334 */
335 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
336
337 private:
338 uint32_t m_senderSentSegments; //!< Number of segments sent.
339 Time m_previousRTO; //!< Previous RTO.
340 bool m_closed; //!< True if the connection is closed.
341};
342
343TcpTimeRtoTest::TcpTimeRtoTest(const TypeId& congControl, const std::string& desc)
344 : TcpGeneralTest(desc),
345 m_senderSentSegments(0),
346 m_closed(false)
347{
348 m_congControlTypeId = congControl;
349}
350
351void
357
360{
362 s->SetAttribute("DataRetries", UintegerValue(6));
363
364 return s;
365}
366
369{
371
372 // Drop packet for 7 times. At the 7th, the connection should be dropped.
373 for (uint32_t i = 0; i < 7; ++i)
374 {
375 errorModel->AddSeqToKill(SequenceNumber32(1));
376 }
377
378 errorModel->SetDropCallback(MakeCallback(&TcpTimeRtoTest::PktDropped, this));
379
380 return errorModel;
381}
382
383void
385{
386 NS_LOG_FUNCTION(this << p << h << who);
387
388 if (who == SENDER)
389 {
391 NS_LOG_INFO("Measured RTO:" << GetRto(SENDER).GetSeconds());
392
393 if (h.GetFlags() & TcpHeader::SYN)
394 {
396 1,
397 "Number of segments sent is different than 1");
398
399 Time s_rto = GetRto(SENDER);
402 "SYN packet sent without respecting "
403 "ConnTimeout attribute");
404 }
405 else
406 {
407 NS_LOG_INFO("TX: " << h << m_senderSentSegments);
408
410 1,
411 "First packet was not correctly sent");
412
413 // Remember, from RFC:
414 // m_rto = Max (m_rtt->GetEstimate () +
415 // Max (m_clockGranularity, m_rtt->GetVariation ()*4), m_minRto);
416
417 if (m_senderSentSegments == 2)
418 { // ACK of SYN-ACK, rto set for the first time, since now we have
419 // an estimation of RTT
420
422 Time clockGranularity = GetClockGranularity(SENDER);
423 m_previousRTO = rttEstimator->GetEstimate();
424
425 if (clockGranularity > rttEstimator->GetVariation() * 4)
426 {
427 m_previousRTO += clockGranularity;
428 }
429 else
430 {
431 m_previousRTO += rttEstimator->GetVariation() * 4;
432 }
433
435
438 Seconds(0.01),
439 "RTO value differs from calculation");
440 }
441 else if (m_senderSentSegments == 3)
442 { // First data packet. RTO should be the same as before
443
446 Seconds(0.01),
447 "RTO value has changed unexpectedly");
448 }
449 }
450 }
451 else if (who == RECEIVER)
452 {
453 }
454}
455
456void
461
462void
464{
465 NS_TEST_ASSERT_MSG_EQ(who, SENDER, "RTO in Receiver. That's unexpected");
466
467 Time actualRto = GetRto(SENDER);
468
469 if (actualRto < Seconds(60))
470 {
473 Seconds(0.01),
474 "RTO has not doubled after an expiration");
476 }
477 else
478 {
479 NS_TEST_ASSERT_MSG_EQ(actualRto, Seconds(60), "RTO goes beyond 60 second limit");
480 }
481}
482
483void
485{
486 NS_LOG_INFO("DROPPED! " << tcpH);
487}
488
489void
491{
493 true,
494 "Socket has not been closed after retrying data retransmissions");
495}
496
497/**
498 * \ingroup internet-test
499 *
500 * \brief TCP RTO TestSuite
501 */
503{
504 public:
506 : TestSuite("tcp-rto-test", Type::UNIT)
507 {
508 std::list<TypeId> types = {
510 };
511
512 for (const auto& t : types)
513 {
514 AddTestCase(new TcpRtoTest(t, t.GetName() + " RTO retransmit testing"),
515 TestCase::Duration::QUICK);
516
517 constexpr uint32_t seqToDrop = 25001;
518
519 // With RTO of 0.5 seconds, BytesInFlight winds down to zero before RTO
521 seqToDrop,
522 Seconds(0.5),
523 t.GetName() + " RTO ssthresh testing, set to 2*MSL"),
524 TestCase::Duration::QUICK);
525
526 // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
528 t,
529 seqToDrop,
530 Seconds(0.005),
531 t.GetName() + " RTO ssthresh testing, set to half of BytesInFlight"),
532 TestCase::Duration::QUICK);
533
534 AddTestCase(new TcpTimeRtoTest(t, t.GetName() + " RTO timing testing"),
535 TestCase::Duration::QUICK);
536 }
537 }
538};
539
540static TcpRtoTestSuite g_TcpRtoTestSuite; //!< Static variable for test initialization
#define Max(a, b)
Testing the moments after an RTO expiration.
void ProcessedAck(const Ptr< const TcpSocketState > tcb, const TcpHeader &h, SocketWho who) override
Processed ack.
TcpRtoTest(const TypeId &congControl, const std::string &msg)
Constructor.
bool m_segmentReceived
True if segments have been received.
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
void ConfigureProperties() override
Change the configuration of the socket properties.
bool m_afterRTOExpired
True if RTO is expired.
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.
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: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.
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:36
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
uint8_t GetFlags() const
Get the flags.
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: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
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
a unique identifier for an interface.
Definition type-id.h:48
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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_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:327
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
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 TcpRtoTestSuite g_TcpRtoTestSuite
Static variable for test initialization.