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
90{
91 public:
107 uint32_t packets,
108 uint16_t pacingSsRatio,
109 uint16_t pacingCaRatio,
110 uint32_t ssThresh,
111 bool paceInitialWindow,
112 uint32_t delAckMaxCount,
113 const TypeId& congControl,
114 const std::string& desc);
115
116 protected:
117 void CWndTrace(uint32_t oldValue, uint32_t newValue) override;
118 void RttTrace(Time oldTime, Time newTime) override;
119 void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override;
120 void Tx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
121 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
122 void QueueDrop(SocketWho who) override;
123 void PhyDrop(SocketWho who) override;
124 void NormalClose(SocketWho who) override;
125
129 virtual void UpdateExpectedInterval();
130
131 void ConfigureEnvironment() override;
132 void ConfigureProperties() override;
133
134 private:
160};
161
164 uint32_t packets,
165 uint16_t pacingSsRatio,
166 uint16_t pacingCaRatio,
167 uint32_t ssThresh,
168 bool paceInitialWindow,
169 uint32_t delAckMaxCount,
170 const TypeId& typeId,
171 const std::string& desc)
172 : TcpGeneralTest(desc),
173 m_segmentSize(segmentSize),
174 m_packetSize(packetSize),
175 m_packets(packets),
176 m_initial(true),
177 m_initialCwnd(10),
178 m_curCwnd(0),
179 m_isFullCwndSent(true),
180 m_bytesInFlight(0),
181 m_prevTxTime(0),
182 m_pacingSsRatio(pacingSsRatio),
183 m_pacingCaRatio(pacingCaRatio),
184 m_ssThresh(ssThresh),
185 m_paceInitialWindow(paceInitialWindow),
186 m_delAckMaxCount(delAckMaxCount),
187 m_isConnAboutToEnd(false),
188 m_transmissionStartTime(Seconds(0)),
189 m_expectedInterval(Seconds(0)),
190 m_packetsSent(0),
191 m_nextPacketInterval(Seconds(0)),
192 m_tracedRtt(Seconds(0))
193{
194 m_congControlTypeId = typeId;
195}
196
197void
199{
200 TcpGeneralTest::ConfigureEnvironment();
204 SetMTU(1500);
207}
208
209void
211{
212 TcpGeneralTest::ConfigureProperties();
216 SetPacingStatus(SENDER, true);
219 NS_LOG_DEBUG("segSize: " << m_segmentSize << " ssthresh: " << m_ssThresh
220 << " paceInitialWindow: " << m_paceInitialWindow << " delAckMaxCount "
222}
223
224void
226{
227 NS_LOG_FUNCTION(this << oldTime << newTime);
228 m_tracedRtt = newTime;
230}
231
232void
234{
235 NS_LOG_FUNCTION(this << oldValue << newValue);
236 m_curCwnd = newValue;
237 if (m_initial)
238 {
239 m_initial = false;
240 }
241 // CWndTrace () is called after Rx ()
242 // Therefore, call UpdateExpectedInterval () here instead of in Rx ()
244}
245
246void
248{
249 m_bytesInFlight = newValue;
250}
251
252void
254{
255 double_t factor;
256 Time rtt = 2 * GetPropagationDelay();
257 if (m_curCwnd < m_ssThresh / 2)
258 {
259 factor = static_cast<double>(m_pacingSsRatio) / 100;
260 }
261 else
262 {
263 factor = static_cast<double>(m_pacingCaRatio) / 100;
264 }
265
267 {
268 // If initial cwnd is not paced, we expect packet pacing interval to be zero
270 }
271 else
272 {
273 // Use the estimate according to update equation
276 }
277}
278
279void
281{
282 if (who == SENDER)
283 {
284 uint8_t flags = h.GetFlags();
285 uint8_t hasFin = flags & TcpHeader::FIN;
286 uint8_t hasAck = flags & TcpHeader::ACK;
287 if (hasFin && hasAck)
288 {
289 m_isConnAboutToEnd = true;
290 NS_LOG_DEBUG("Sender received a FIN/ACK packet");
291 }
292 else
293 {
294 m_isConnAboutToEnd = false;
295 NS_LOG_DEBUG("Sender received an ACK packet");
296 }
297 }
298}
299
300void
302{
303 NS_LOG_FUNCTION(this << p << h << who);
304
305 if (who == SENDER)
306 {
308 // Start pacing checks from the second data packet onwards because
309 // an interval to check does not exist for the first data packet.
310 // The first two (non-data) packets correspond to SYN and an
311 // empty ACK, respectively, so start checking after three packets are sent
312 bool beyondInitialDataSegment = (m_packetsSent > 3);
313 Time actualInterval = Simulator::Now() - m_prevTxTime;
314 NS_LOG_DEBUG("TX sent: packetsSent: " << m_packetsSent << " fullCwnd: " << m_isFullCwndSent
315 << " nearEnd: " << m_isConnAboutToEnd
316 << " beyondInitialDataSegment "
317 << beyondInitialDataSegment);
318 if (!m_isFullCwndSent && !m_isConnAboutToEnd && beyondInitialDataSegment)
319 {
320 // Consider a small error margin, and ensure that the actual and expected intervals lie
321 // within this error
322 Time errorMargin = NanoSeconds(10);
324 std::abs((actualInterval - m_nextPacketInterval).GetSeconds()),
325 errorMargin.GetSeconds(),
326 "Packet delivery in slow start didn't match pacing rate");
327 NS_LOG_DEBUG("Pacing Check: interval (s): "
328 << actualInterval.GetSeconds() << " expected interval (s): "
329 << m_nextPacketInterval.GetSeconds() << " difference (s): "
330 << std::abs((actualInterval - m_nextPacketInterval).GetSeconds())
331 << " errorMargin (s): " << errorMargin.GetSeconds());
332 }
333
335 // bytesInFlight isn't updated yet. Its trace is called after Tx
336 // so add an additional m_segmentSize to bytesInFlight
337 uint32_t soonBytesInFlight = m_bytesInFlight + m_segmentSize;
338 bool canPacketBeSent = ((m_curCwnd - soonBytesInFlight) >= m_segmentSize);
339 if (!canPacketBeSent || (m_curCwnd == 0))
340 {
341 m_isFullCwndSent = true;
342 }
343 else
344 {
345 m_isFullCwndSent = false;
346 }
348 NS_LOG_DEBUG("Next expected interval (s): " << m_nextPacketInterval.GetSeconds());
349 }
350}
351
352void
354{
355 NS_FATAL_ERROR("Drop on the queue; cannot validate congestion avoidance");
356}
357
358void
360{
361 NS_FATAL_ERROR("Drop on the phy: cannot validate congestion avoidance");
362}
363
364void
366{
367 if (who == SENDER)
368 {
369 m_event.Cancel();
370 }
371}
372
379{
380 public:
382 : TestSuite("tcp-pacing-test", UNIT)
383 {
384 uint16_t pacingSsRatio = 200;
385 uint16_t pacingCaRatio = 120;
386 uint32_t segmentSize = 1000;
387 uint32_t packetSize = 1000;
388 uint32_t numPackets = 40;
389 uint32_t delAckMaxCount = 1;
390 TypeId tid = TcpNewReno::GetTypeId();
391 uint32_t ssThresh = 1e9; // default large value
392 bool paceInitialWindow = false;
393 std::string description;
394
395 description = std::string("Pacing case 1: Slow start only, no initial pacing");
398 numPackets,
399 pacingSsRatio,
400 pacingCaRatio,
401 ssThresh,
402 paceInitialWindow,
403 delAckMaxCount,
404 tid,
405 description),
406 TestCase::QUICK);
407
408 paceInitialWindow = true;
409 description = std::string("Pacing case 2: Slow start only, initial pacing");
412 numPackets,
413 pacingSsRatio,
414 pacingCaRatio,
415 ssThresh,
416 paceInitialWindow,
417 delAckMaxCount,
418 tid,
419 description),
420 TestCase::QUICK);
421
422 // set ssThresh to some smaller value to check that pacing
423 // slows down in second half of slow start, then transitions to CA
424 description = std::string("Pacing case 3: Slow start, followed by transition to Congestion "
425 "avoidance, no initial pacing");
426 paceInitialWindow = false;
427 ssThresh = 40;
428 numPackets = 60;
431 numPackets,
432 pacingSsRatio,
433 pacingCaRatio,
434 ssThresh,
435 paceInitialWindow,
436 delAckMaxCount,
437 tid,
438 description),
439 TestCase::QUICK);
440
441 // Repeat tests, but with more typical delAckMaxCount == 2
442 delAckMaxCount = 2;
443 paceInitialWindow = false;
444 ssThresh = 1e9;
445 numPackets = 40;
446 description =
447 std::string("Pacing case 4: Slow start only, no initial pacing, delayed ACKs");
450 numPackets,
451 pacingSsRatio,
452 pacingCaRatio,
453 ssThresh,
454 paceInitialWindow,
455 delAckMaxCount,
456 tid,
457 description),
458 TestCase::QUICK);
459
460 paceInitialWindow = true;
461 description = std::string("Pacing case 5: Slow start only, initial pacing, delayed ACKs");
464 numPackets,
465 pacingSsRatio,
466 pacingCaRatio,
467 ssThresh,
468 paceInitialWindow,
469 delAckMaxCount,
470 tid,
471 description),
472 TestCase::QUICK);
473
474 description = std::string("Pacing case 6: Slow start, followed by transition to Congestion "
475 "avoidance, no initial pacing, delayed ACKs");
476 paceInitialWindow = false;
477 ssThresh = 40;
478 numPackets = 60;
481 numPackets,
482 pacingSsRatio,
483 pacingCaRatio,
484 ssThresh,
485 paceInitialWindow,
486 delAckMaxCount,
487 tid,
488 description),
489 TestCase::QUICK);
490 }
491};
492
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:59
uint32_t segmentSize
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#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:1372
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
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.