A Discrete-Event Network Simulator
API
tcp-pacing-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 NITK Surathkal
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 * Authors: Deepak Kumaraswamy <deepakkavoor99@gmail.com>
18 *
19 */
20#include "tcp-general-test.h"
21
22#include "ns3/config.h"
23#include "ns3/log.h"
24#include "ns3/simple-channel.h"
25#include "ns3/test.h"
26
27using namespace ns3;
28
29NS_LOG_COMPONENT_DEFINE("TcpPacingTestSuite");
30
91{
92 public:
108 uint32_t packets,
109 uint16_t pacingSsRatio,
110 uint16_t pacingCaRatio,
111 uint32_t ssThresh,
112 bool paceInitialWindow,
113 uint32_t delAckMaxCount,
114 const TypeId& congControl,
115 const std::string& desc);
116
117 protected:
118 void CWndTrace(uint32_t oldValue, uint32_t newValue) override;
119 void RttTrace(Time oldTime, Time newTime) override;
120 void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override;
121 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
122 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
123 void QueueDrop(SocketWho who) override;
124 void PhyDrop(SocketWho who) override;
125 void NormalClose(SocketWho who) override;
126
130 virtual void UpdateExpectedInterval();
131
132 void ConfigureEnvironment() override;
133 void ConfigureProperties() override;
134
135 private:
161};
162
165 uint32_t packets,
166 uint16_t pacingSsRatio,
167 uint16_t pacingCaRatio,
168 uint32_t ssThresh,
169 bool paceInitialWindow,
170 uint32_t delAckMaxCount,
171 const TypeId& typeId,
172 const std::string& desc)
173 : TcpGeneralTest(desc),
174 m_segmentSize(segmentSize),
175 m_packetSize(packetSize),
176 m_packets(packets),
177 m_initial(true),
178 m_initialCwnd(10),
179 m_curCwnd(0),
180 m_isFullCwndSent(true),
181 m_bytesInFlight(0),
182 m_prevTxTime(0),
183 m_pacingSsRatio(pacingSsRatio),
184 m_pacingCaRatio(pacingCaRatio),
185 m_ssThresh(ssThresh),
186 m_paceInitialWindow(paceInitialWindow),
187 m_delAckMaxCount(delAckMaxCount),
188 m_isConnAboutToEnd(false),
189 m_transmissionStartTime(Seconds(0)),
190 m_expectedInterval(Seconds(0)),
191 m_packetsSent(0),
192 m_nextPacketInterval(Seconds(0)),
193 m_tracedRtt(Seconds(0))
194{
195 m_congControlTypeId = typeId;
196}
197
198void
200{
201 TcpGeneralTest::ConfigureEnvironment();
205 SetMTU(1500);
208}
209
210void
212{
213 TcpGeneralTest::ConfigureProperties();
217 SetPacingStatus(SENDER, true);
220 NS_LOG_DEBUG("segSize: " << m_segmentSize << " ssthresh: " << m_ssThresh
221 << " paceInitialWindow: " << m_paceInitialWindow << " delAckMaxCount "
223}
224
225void
227{
228 NS_LOG_FUNCTION(this << oldTime << newTime);
229 m_tracedRtt = newTime;
231}
232
233void
235{
236 NS_LOG_FUNCTION(this << oldValue << newValue);
237 m_curCwnd = newValue;
238 if (m_initial)
239 {
240 m_initial = false;
241 }
242 // CWndTrace () is called after Rx ()
243 // Therefore, call UpdateExpectedInterval () here instead of in Rx ()
245}
246
247void
249{
250 m_bytesInFlight = newValue;
251}
252
253void
255{
256 double_t factor;
257 Time rtt = 2 * GetPropagationDelay();
258 if (m_curCwnd < m_ssThresh / 2)
259 {
260 factor = static_cast<double>(m_pacingSsRatio) / 100;
261 }
262 else
263 {
264 factor = static_cast<double>(m_pacingCaRatio) / 100;
265 }
266
268 {
269 // If initial cwnd is not paced, we expect packet pacing interval to be zero
271 }
272 else
273 {
274 // Use the estimate according to update equation
277 }
278}
279
280void
282{
283 if (who == SENDER)
284 {
285 uint8_t flags = h.GetFlags();
286 uint8_t hasFin = flags & TcpHeader::FIN;
287 uint8_t hasAck = flags & TcpHeader::ACK;
288 if (hasFin && hasAck)
289 {
290 m_isConnAboutToEnd = true;
291 NS_LOG_DEBUG("Sender received a FIN/ACK packet");
292 }
293 else
294 {
295 m_isConnAboutToEnd = false;
296 NS_LOG_DEBUG("Sender received an ACK packet");
297 }
298 }
299}
300
301void
303{
304 NS_LOG_FUNCTION(this << p << h << who);
305
306 if (who == SENDER)
307 {
309 // Start pacing checks from the second data packet onwards because
310 // an interval to check does not exist for the first data packet.
311 // The first two (non-data) packets correspond to SYN and an
312 // empty ACK, respectively, so start checking after three packets are sent
313 bool beyondInitialDataSegment = (m_packetsSent > 3);
314 Time actualInterval = Simulator::Now() - m_prevTxTime;
315 NS_LOG_DEBUG("TX sent: packetsSent: " << m_packetsSent << " fullCwnd: " << m_isFullCwndSent
316 << " nearEnd: " << m_isConnAboutToEnd
317 << " beyondInitialDataSegment "
318 << beyondInitialDataSegment);
319 if (!m_isFullCwndSent && !m_isConnAboutToEnd && beyondInitialDataSegment)
320 {
321 // Consider a small error margin, and ensure that the actual and expected intervals lie
322 // within this error
323 Time errorMargin = NanoSeconds(10);
325 std::abs((actualInterval - m_nextPacketInterval).GetSeconds()),
326 errorMargin.GetSeconds(),
327 "Packet delivery in slow start didn't match pacing rate");
328 NS_LOG_DEBUG("Pacing Check: interval (s): "
329 << actualInterval.GetSeconds() << " expected interval (s): "
330 << m_nextPacketInterval.GetSeconds() << " difference (s): "
331 << std::abs((actualInterval - m_nextPacketInterval).GetSeconds())
332 << " errorMargin (s): " << errorMargin.GetSeconds());
333 }
334
336 // bytesInFlight isn't updated yet. Its trace is called after Tx
337 // so add an additional m_segmentSize to bytesInFlight
338 uint32_t soonBytesInFlight = m_bytesInFlight + m_segmentSize;
339 bool canPacketBeSent = ((m_curCwnd - soonBytesInFlight) >= m_segmentSize);
340 if (!canPacketBeSent || (m_curCwnd == 0))
341 {
342 m_isFullCwndSent = true;
343 }
344 else
345 {
346 m_isFullCwndSent = false;
347 }
349 NS_LOG_DEBUG("Next expected interval (s): " << m_nextPacketInterval.GetSeconds());
350 }
351}
352
353void
355{
356 NS_FATAL_ERROR("Drop on the queue; cannot validate congestion avoidance");
357}
358
359void
361{
362 NS_FATAL_ERROR("Drop on the phy: cannot validate congestion avoidance");
363}
364
365void
367{
368 if (who == SENDER)
369 {
370 m_event.Cancel();
371 }
372}
373
381{
382 public:
384 : TestSuite("tcp-pacing-test", UNIT)
385 {
386 uint16_t pacingSsRatio = 200;
387 uint16_t pacingCaRatio = 120;
388 uint32_t segmentSize = 1000;
389 uint32_t packetSize = 1000;
390 uint32_t numPackets = 40;
391 uint32_t delAckMaxCount = 1;
392 TypeId tid = TcpNewReno::GetTypeId();
393 uint32_t ssThresh = 1e9; // default large value
394 bool paceInitialWindow = false;
395 std::string description;
396
397 description = std::string("Pacing case 1: Slow start only, no initial pacing");
400 numPackets,
401 pacingSsRatio,
402 pacingCaRatio,
403 ssThresh,
404 paceInitialWindow,
405 delAckMaxCount,
406 tid,
407 description),
408 TestCase::QUICK);
409
410 paceInitialWindow = true;
411 description = std::string("Pacing case 2: Slow start only, initial pacing");
414 numPackets,
415 pacingSsRatio,
416 pacingCaRatio,
417 ssThresh,
418 paceInitialWindow,
419 delAckMaxCount,
420 tid,
421 description),
422 TestCase::QUICK);
423
424 // set ssThresh to some smaller value to check that pacing
425 // slows down in second half of slow start, then transitions to CA
426 description = std::string("Pacing case 3: Slow start, followed by transition to Congestion "
427 "avoidance, no initial pacing");
428 paceInitialWindow = false;
429 ssThresh = 40;
430 numPackets = 60;
433 numPackets,
434 pacingSsRatio,
435 pacingCaRatio,
436 ssThresh,
437 paceInitialWindow,
438 delAckMaxCount,
439 tid,
440 description),
441 TestCase::QUICK);
442
443 // Repeat tests, but with more typical delAckMaxCount == 2
444 delAckMaxCount = 2;
445 paceInitialWindow = false;
446 ssThresh = 1e9;
447 numPackets = 40;
448 description =
449 std::string("Pacing case 4: Slow start only, no initial pacing, delayed ACKs");
452 numPackets,
453 pacingSsRatio,
454 pacingCaRatio,
455 ssThresh,
456 paceInitialWindow,
457 delAckMaxCount,
458 tid,
459 description),
460 TestCase::QUICK);
461
462 paceInitialWindow = true;
463 description = std::string("Pacing case 5: Slow start only, initial pacing, delayed ACKs");
466 numPackets,
467 pacingSsRatio,
468 pacingCaRatio,
469 ssThresh,
470 paceInitialWindow,
471 delAckMaxCount,
472 tid,
473 description),
474 TestCase::QUICK);
475
476 description = std::string("Pacing case 6: Slow start, followed by transition to Congestion "
477 "avoidance, no initial pacing, delayed ACKs");
478 paceInitialWindow = false;
479 ssThresh = 40;
480 numPackets = 60;
483 numPackets,
484 pacingSsRatio,
485 pacingCaRatio,
486 ssThresh,
487 paceInitialWindow,
488 delAckMaxCount,
489 tid,
490 description),
491 TestCase::QUICK);
492 }
493};
494
Test the behavior of TCP pacing.
uint32_t m_initialCwnd
Initial value of cWnd.
void CWndTrace(uint32_t oldValue, uint32_t newValue) override
Tracks the congestion window changes.
uint16_t m_pacingSsRatio
Pacing factor during Slow Start.
void ConfigureProperties() override
Change the configuration of the socket properties.
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.
Time m_expectedInterval
Theoretical estimate of the time at which next packet is scheduled for transmission.
void RttTrace(Time oldTime, Time newTime) override
Rtt changes.
void Tx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet transmitted down to IP layer.
Time m_nextPacketInterval
Time maintained by Tx () trace about interval at which next packet will be sent.
void NormalClose(SocketWho who) override
Socket closed normally.
uint32_t m_segmentSize
Segment size.
void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Packet received from IP layer.
void PhyDrop(SocketWho who) override
Link drop.
Time m_prevTxTime
Time when Tx was previously called.
void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override
Bytes in flight changes.
Time m_transmissionStartTime
Time at which sender starts data transmission.
void QueueDrop(SocketWho who) override
Drop on the queue.
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.
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.
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.
bool m_isFullCwndSent
True if all bytes for that cWnd is sent and sender is waiting for an ACK.
void ConfigureEnvironment() override
Change the configuration of the environment.
virtual void UpdateExpectedInterval()
Update the expected interval at which next packet will be sent.
bool m_initial
True on first run.
uint32_t m_packetSize
Size of the packets.
TestSuite for the behavior of TCP pacing.
An identifier for simulation events.
Definition: event-id.h:55
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
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:46
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:167
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
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
a unique identifier for an interface.
Definition: type-id.h:60
uint32_t segmentSize
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:160
#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 ",...
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
#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:750
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1374
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.
static TcpPacingTestSuite g_tcpPacingTest
Static variable for test initialization.
static const uint32_t packetSize
Packet size generated at the AP.