A Discrete-Event Network Simulator
API
tcp-pacing-test.cc
Go to the documentation of this file.
1/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2020 NITK Surathkal
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Deepak Kumaraswamy <deepakkavoor99@gmail.com>
19 *
20 */
21#include "ns3/log.h"
22#include "ns3/simple-channel.h"
23#include "ns3/config.h"
24#include "ns3/test.h"
25#include "tcp-general-test.h"
26
27using namespace ns3;
28
29NS_LOG_COMPONENT_DEFINE ("TcpPacingTestSuite");
30
90class
92{
93public:
108 uint32_t packets, uint16_t pacingSsRatio, uint16_t pacingCaRatio,
109 uint32_t ssThresh, bool paceInitialWindow, uint32_t delAckMaxCount,
110 const TypeId& congControl, const std::string &desc);
111
112protected:
113 virtual void CWndTrace (uint32_t oldValue, uint32_t newValue);
114 virtual void RttTrace (Time oldTime, Time newTime);
115 virtual void BytesInFlightTrace (uint32_t oldValue, uint32_t newValue);
116 virtual void Tx (const Ptr<const Packet> p, const TcpHeader &h, SocketWho who);
117 virtual void Rx (const Ptr<const Packet> p, const TcpHeader &h, SocketWho who);
118 virtual void QueueDrop (SocketWho who);
119 virtual void PhyDrop (SocketWho who);
120 virtual void NormalClose (SocketWho who);
121
125 virtual void UpdateExpectedInterval (void);
126
127 virtual void ConfigureEnvironment ();
128 virtual void ConfigureProperties ();
129
130private:
152};
153
154
157 uint32_t packets,
158 uint16_t pacingSsRatio,
159 uint16_t pacingCaRatio,
160 uint32_t ssThresh,
161 bool paceInitialWindow,
162 uint32_t delAckMaxCount,
163 const TypeId &typeId,
164 const std::string &desc)
165 : TcpGeneralTest (desc),
166 m_segmentSize (segmentSize),
167 m_packetSize (packetSize),
168 m_packets (packets),
169 m_initial (true),
170 m_initialCwnd (10),
171 m_curCwnd (0),
172 m_isFullCwndSent (true),
173 m_bytesInFlight (0),
174 m_prevTxTime (0),
175 m_pacingSsRatio (pacingSsRatio),
176 m_pacingCaRatio (pacingCaRatio),
177 m_ssThresh (ssThresh),
178 m_paceInitialWindow (paceInitialWindow),
179 m_delAckMaxCount (delAckMaxCount),
180 m_isConnAboutToEnd (false),
181 m_transmissionStartTime (Seconds (0)),
182 m_expectedInterval (Seconds (0)),
183 m_packetsSent (0),
184 m_nextPacketInterval (Seconds (0)),
185 m_tracedRtt (Seconds (0))
186{
187 m_congControlTypeId = typeId;
188}
189
190void
192{
193 TcpGeneralTest::ConfigureEnvironment ();
197 SetMTU (1500);
200}
201
203{
204 TcpGeneralTest::ConfigureProperties ();
208 SetPacingStatus (SENDER, true);
211 NS_LOG_DEBUG ("segSize: " << m_segmentSize << " ssthresh: " << m_ssThresh <<
212 " paceInitialWindow: " << m_paceInitialWindow << " delAckMaxCount " << m_delAckMaxCount);
213}
214
215void
217{
218 NS_LOG_FUNCTION (this << oldTime << newTime);
219 m_tracedRtt = newTime;
221}
222
223void
225{
226 NS_LOG_FUNCTION (this << oldValue << newValue);
227 m_curCwnd = newValue;
228 if (m_initial)
229 {
230 m_initial = false;
231 }
232 // CWndTrace () is called after Rx ()
233 // Therefore, call UpdateExpectedInterval () here instead of in Rx ()
235}
236
237void
239{
240 m_bytesInFlight = newValue;
241}
242
243void
245{
246 double_t factor;
247 Time rtt = 2 * GetPropagationDelay ();
248 if (m_curCwnd < m_ssThresh / 2)
249 {
250 factor = static_cast<double> (m_pacingSsRatio) / 100;
251 }
252 else
253 {
254 factor = static_cast<double> (m_pacingCaRatio) / 100;
255 }
256
258 {
259 // If initial cwnd is not paced, we expect packet pacing interval to be zero
261 }
262 else
263 {
264 // Use the estimate according to update equation
266 }
267}
268
269void
271{
272 if (who == SENDER)
273 {
274 uint8_t flags = h.GetFlags ();
275 uint8_t hasFin = flags & TcpHeader::FIN;
276 uint8_t hasAck = flags & TcpHeader::ACK;
277 if (hasFin && hasAck)
278 {
279 m_isConnAboutToEnd = true;
280 NS_LOG_DEBUG ("Sender received a FIN/ACK packet");
281 }
282 else
283 {
284 m_isConnAboutToEnd = false;
285 NS_LOG_DEBUG ("Sender received an ACK packet");
286 }
287 }
288}
289
290void
292{
293 NS_LOG_FUNCTION (this << p << h << who);
294
295 if (who == SENDER)
296 {
298 // Start pacing checks from the second data packet onwards because
299 // an interval to check does not exist for the first data packet.
300 // The first two (non-data) packets correspond to SYN and an
301 // empty ACK, respectively, so start checking after three packets are sent
302 bool beyondInitialDataSegment = (m_packetsSent > 3);
303 Time actualInterval = Simulator::Now () - m_prevTxTime;
304 NS_LOG_DEBUG ("TX sent: packetsSent: " << m_packetsSent << " fullCwnd: " << m_isFullCwndSent << " nearEnd: " <<
305 m_isConnAboutToEnd << " beyondInitialDataSegment " << beyondInitialDataSegment);
306 if (!m_isFullCwndSent && !m_isConnAboutToEnd && beyondInitialDataSegment)
307 {
308 // Consider a small error margin, and ensure that the actual and expected intervals lie within this error
309 Time errorMargin = NanoSeconds (10);
310 NS_TEST_ASSERT_MSG_LT_OR_EQ (std::abs ((actualInterval - m_nextPacketInterval).GetSeconds ()), errorMargin.GetSeconds (), "Packet delivery in slow start didn't match pacing rate");
311 NS_LOG_DEBUG ("Pacing Check: interval (s): " << actualInterval.GetSeconds () <<
312 " expected interval (s): " << m_nextPacketInterval.GetSeconds () <<
313 " difference (s): " << std::abs ((actualInterval - m_nextPacketInterval).GetSeconds ()) <<
314 " errorMargin (s): " << errorMargin.GetSeconds ());
315 }
316
318 // bytesInFlight isn't updated yet. Its trace is called after Tx
319 // so add an additional m_segmentSize to bytesInFlight
320 uint32_t soonBytesInFlight = m_bytesInFlight + m_segmentSize;
321 bool canPacketBeSent = ((m_curCwnd - soonBytesInFlight) >= m_segmentSize);
322 if (!canPacketBeSent || (m_curCwnd == 0))
323 {
324 m_isFullCwndSent = true;
325 }
326 else
327 {
328 m_isFullCwndSent = false;
329 }
331 NS_LOG_DEBUG ("Next expected interval (s): " << m_nextPacketInterval.GetSeconds ());
332 }
333}
334
335void
337{
338 NS_FATAL_ERROR ("Drop on the queue; cannot validate congestion avoidance");
339}
340
341void
343{
344 NS_FATAL_ERROR ("Drop on the phy: cannot validate congestion avoidance");
345}
346
347void
349{
350 if (who == SENDER)
351 {
352 m_event.Cancel ();
353 }
354}
355
363{
364public:
365 TcpPacingTestSuite () : TestSuite ("tcp-pacing-test", UNIT)
366 {
367 uint16_t pacingSsRatio = 200;
368 uint16_t pacingCaRatio = 120;
369 uint32_t segmentSize = 1000;
370 uint32_t packetSize = 1000;
371 uint32_t numPackets = 40;
372 uint32_t delAckMaxCount = 1;
373 TypeId tid = TcpNewReno::GetTypeId ();
374 uint32_t ssThresh = 1e9; // default large value
375 bool paceInitialWindow = false;
376 std::string description;
377
378 description = std::string ("Pacing case 1: Slow start only, no initial pacing");
379 AddTestCase (new TcpPacingTest (segmentSize, packetSize, numPackets, pacingSsRatio, pacingCaRatio, ssThresh, paceInitialWindow, delAckMaxCount, tid, description), TestCase::QUICK);
380
381 paceInitialWindow = true;
382 description = std::string ("Pacing case 2: Slow start only, initial pacing");
383 AddTestCase (new TcpPacingTest (segmentSize, packetSize, numPackets, pacingSsRatio, pacingCaRatio, ssThresh, paceInitialWindow, delAckMaxCount, tid, description), TestCase::QUICK);
384
385 // set ssThresh to some smaller value to check that pacing
386 // slows down in second half of slow start, then transitions to CA
387 description = std::string ("Pacing case 3: Slow start, followed by transition to Congestion avoidance, no initial pacing");
388 paceInitialWindow = false;
389 ssThresh = 40;
390 numPackets = 60;
391 AddTestCase (new TcpPacingTest (segmentSize, packetSize, numPackets, pacingSsRatio, pacingCaRatio, ssThresh, paceInitialWindow, delAckMaxCount, tid, description), TestCase::QUICK);
392
393 // Repeat tests, but with more typical delAckMaxCount == 2
394 delAckMaxCount = 2;
395 paceInitialWindow = false;
396 ssThresh = 1e9;
397 numPackets = 40;
398 description = std::string ("Pacing case 4: Slow start only, no initial pacing, delayed ACKs");
399 AddTestCase (new TcpPacingTest (segmentSize, packetSize, numPackets, pacingSsRatio, pacingCaRatio, ssThresh, paceInitialWindow, delAckMaxCount, tid, description), TestCase::QUICK);
400
401 paceInitialWindow = true;
402 description = std::string ("Pacing case 5: Slow start only, initial pacing, delayed ACKs");
403 AddTestCase (new TcpPacingTest (segmentSize, packetSize, numPackets, pacingSsRatio, pacingCaRatio, ssThresh, paceInitialWindow, delAckMaxCount, tid, description), TestCase::QUICK);
404
405 description = std::string ("Pacing case 6: Slow start, followed by transition to Congestion avoidance, no initial pacing, delayed ACKs");
406 paceInitialWindow = false;
407 ssThresh = 40;
408 numPackets = 60;
409 AddTestCase (new TcpPacingTest (segmentSize, packetSize, numPackets, pacingSsRatio, pacingCaRatio, ssThresh, paceInitialWindow, delAckMaxCount, tid, description), TestCase::QUICK);
410 }
411};
412
Test the behavior of TCP pacing.
uint32_t m_initialCwnd
Initial value of cWnd.
virtual void CWndTrace(uint32_t oldValue, uint32_t newValue)
Tracks the congestion window changes.
uint16_t m_pacingSsRatio
Pacing factor during Slow Start.
virtual void RttTrace(Time oldTime, Time newTime)
Rtt changes.
virtual void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue)
Bytes in flight changes.
uint32_t m_delAckMaxCount
Delayed ack count for receiver.
Time m_tracedRtt
Traced value of RTT, which may be different from the environment RTT in case of delayed ACKs.
uint32_t m_ssThresh
Slow start threshold.
virtual void ConfigureProperties()
Change the configuration of the socket properties.
Time m_expectedInterval
Theoretical estimate of the time at which next packet is scheduled for transmission.
virtual void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet transmitted down to IP layer.
Time m_nextPacketInterval
Time maintained by Tx () trace about interval at which next packet will be sent.
uint32_t m_segmentSize
Segment size.
Time m_prevTxTime
Time when Tx was previously called.
Time m_transmissionStartTime
Time at which sender starts data transmission.
bool m_isConnAboutToEnd
True when sender receives a FIN/ACK from receiver.
uint16_t m_pacingCaRatio
Pacing factor during Congestion Avoidance.
uint32_t m_bytesInFlight
Current bytes in flight.
virtual void UpdateExpectedInterval(void)
Update the expected interval at which next packet will be sent.
virtual void ConfigureEnvironment()
Change the configuration of the environment.
bool m_paceInitialWindow
True if initial window should be paced.
uint32_t m_packets
Number of packets.
EventId m_event
Check event.
uint32_t m_curCwnd
Current sender cWnd.
virtual void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who)
Packet received from IP layer.
virtual void QueueDrop(SocketWho who)
Drop on the queue.
uint32_t m_packetsSent
Number of packets sent by sender so far.
TcpPacingTest(uint32_t segmentSize, uint32_t packetSize, uint32_t packets, uint16_t pacingSsRatio, uint16_t pacingCaRatio, uint32_t ssThresh, bool paceInitialWindow, uint32_t delAckMaxCount, const TypeId &congControl, const std::string &desc)
Constructor.
virtual void PhyDrop(SocketWho who)
Link drop.
bool m_isFullCwndSent
True if all bytes for that cWnd is sent and sender is waiting for an ACK.
bool m_initial
True on first run.
uint32_t m_packetSize
Size of the packets.
virtual void NormalClose(SocketWho who)
Socket closed normally.
TestSuite for the behavior of TCP pacing.
An identifier for simulation events.
Definition: event-id.h:54
void Cancel(void)
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:53
General infrastructure for TCP testing.
void SetPropagationDelay(Time propDelay)
Propagation delay of the bottleneck link.
void SetAppPktCount(uint32_t pktCount)
Set app packet count.
void SetDelAckMaxCount(SocketWho who, uint32_t count)
Forcefully set the delayed acknowledgement count.
SocketWho
Used as parameter of methods, specifies on what node the caller is interested (e.g.
@ RECEIVER
Receiver node.
void SetAppPktSize(uint32_t pktSize)
Set app packet size.
void SetInitialCwnd(SocketWho who, uint32_t initialCwnd)
Forcefully set the initial cwnd.
void SetPaceInitialWindow(SocketWho who, bool paceWindow)
Enable or disable pacing of the initial window.
void SetMTU(uint32_t mtu)
MTU of the bottleneck link.
Time GetPropagationDelay() const
Get the channel Propagation Delay.
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.
void SetPacingStatus(SocketWho who, bool pacing)
Enable or disable pacing in the TCP socket.
void SetTransmitStart(Time startTime)
Set the initial time at which the application sends the first data packet.
void SetSegmentSize(SocketWho who, uint32_t segmentSize)
Forcefully set the segment size.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:45
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:173
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1197
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:379
a unique identifier for an interface.
Definition: type-id.h:59
uint32_t segmentSize
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
#define NS_TEST_ASSERT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report and abort if not.
Definition: test.h:712
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1268
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1252
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static TcpPacingTestSuite g_tcpPacingTest
Static variable for test initialization.
static const uint32_t packetSize
Packet size generated at the AP.