A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ns3tcp-cubic-test-suite.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010 University of Washington (trace writing)
3 * Copyright (c) 2018-20 NITK Surathkal (topology setup)
4 * Copyright (c) 2024 Tom Henderson (test definition)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20// Test suite based on tcp-bbr-example.cc modified topology setup:
21//
22// 1 Gbps 50/100Mbps 1 Gbps
23// Sender -------------- R1 -------------- R2 -------------- Receiver
24// 5us baseRtt/2 5us
25//
26// This is a test suite written initially to test the addition of
27// TCP friendliness but can also be extended for other Cubic tests. By
28// changing some compile-time constants below, it can be used to also produce
29// gnuplots and pcaps that demonstrate the behavior. See the WRITE_PCAP and
30// WRITE_GNUPLOT booleans below to enable this output.
31//
32// There are four cases configured presently.
33// 1. A Cubic TCP on a 5 ms RTT bottleneck, with no fast convergence nor
34// TCP friendliness configured
35// 2. A Cubic TCP on a 5 ms RTT bottleneck, with fast convergence but no
36// TCP friendliness configured. This exhibits a different cwnd plot from 1.
37// 3. A Cubic TCP on a 20 ms RTT bottleneck, with fast convergence but no
38// TCP friendliness configured. There is a step change increase in
39// bottleneck link capacity but the TCP is slow to exploit it.
40// 4. A Cubic TCP on a 20 ms RTT bottleneck, with fast convergence and
41// TCP friendliness configured. There is a step change increase in
42// bottleneck link capacity and the TCP responds more quickly than in 3.
43
44#include "ns3/abort.h"
45#include "ns3/bulk-send-helper.h"
46#include "ns3/config.h"
47#include "ns3/data-rate.h"
48#include "ns3/error-model.h"
49#include "ns3/gnuplot.h"
50#include "ns3/inet-socket-address.h"
51#include "ns3/internet-stack-helper.h"
52#include "ns3/ipv4-address-helper.h"
53#include "ns3/ipv4-global-routing-helper.h"
54#include "ns3/log.h"
55#include "ns3/node-container.h"
56#include "ns3/output-stream-wrapper.h"
57#include "ns3/packet-sink-helper.h"
58#include "ns3/pcap-file.h"
59#include "ns3/point-to-point-helper.h"
60#include "ns3/point-to-point-net-device.h"
61#include "ns3/pointer.h"
62#include "ns3/simulator.h"
63#include "ns3/string.h"
64#include "ns3/tcp-header.h"
65#include "ns3/tcp-socket-factory.h"
66#include "ns3/test.h"
67#include "ns3/trace-helper.h"
68#include "ns3/traffic-control-helper.h"
69#include "ns3/uinteger.h"
70
71#include <iomanip>
72
73using namespace ns3;
74
75NS_LOG_COMPONENT_DEFINE("Ns3TcpCubicTest");
76
77static constexpr bool WRITE_PCAP = false;
78static constexpr bool WRITE_GNUPLOT = false;
79
91void
93 std::map<Time, double>* timeSeries,
94 uint32_t oldval,
95 uint32_t newval)
96{
97 // We store data in two structures because Gnuplot2DDataset data is not exportable
98 NS_LOG_DEBUG("cwnd " << newval / 1448.0);
99 gnuplotTimeSeries->Add(Simulator::Now().GetSeconds(), newval / 1448.0);
100 timeSeries->insert_or_assign(Simulator::Now(), newval / 1448.0);
101}
102
107{
108 public:
119 Ns3TcpCubicTestCase(std::string testCase,
120 std::string prefix,
121 bool fastConvergence,
122 bool tcpFriendliness,
123 Time baseRtt,
124 bool capacityIncrease);
125 ~Ns3TcpCubicTestCase() override;
126
127 private:
128 void DoRun() override;
129
136 void ConnectCwndTrace(uint32_t nodeId, uint32_t socketId);
137
143
152 bool CheckValues(Time start, Time end, double lowerBound, double upperBound);
153
157 std::map<Time, double> m_timeSeries;
158 std::string m_prefix;
163};
164
166 std::string prefix,
167 bool fastConvergence,
168 bool tcpFriendliness,
169 Time baseRtt,
170 bool capacityIncrease)
171 : TestCase(testCase),
172 m_prefix(prefix),
173 m_fastConvergence(fastConvergence),
174 m_tcpFriendliness(tcpFriendliness),
175 m_baseRtt(baseRtt),
176 m_capacityIncrease(capacityIncrease)
177{
178}
179
181{
182}
183
184void
186{
187 device->SetDataRate(DataRate("100Mbps"));
188}
189
190void
192{
194 "/NodeList/" + std::to_string(nodeId) + "/$ns3::TcpL4Protocol/SocketList/" +
195 std::to_string(socketId) + "/CongestionWindow",
197}
198
199bool
200Ns3TcpCubicTestCase::CheckValues(Time start, Time end, double lowerBound, double upperBound)
201{
202 auto itStart = m_timeSeries.lower_bound(start);
203 auto itEnd = m_timeSeries.upper_bound(end);
204 for (auto it = itStart; it != itEnd; it++)
205 {
206 if (it->second < lowerBound || it->second > upperBound)
207 {
208 NS_LOG_DEBUG("Value " << it->second << " at time " << it->first.GetSeconds()
209 << " outside range (" << lowerBound << "," << upperBound << ")");
210 return false;
211 }
212 }
213 return true;
214}
215
216void
218{
219 NS_LOG_DEBUG("Running " << m_prefix);
220 // The maximum bandwidth delay product is 20 ms (base RTT) times 100 Mbps
221 // which works out to 250KB. Setting the socket buffer sizes to four times
222 // that value (1MB) should be more than enough.
223 Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(1000000));
224 Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(1000000));
225 Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10));
226 Config::SetDefault("ns3::TcpSocket::DelAckCount", UintegerValue(2));
227 Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(1448));
228 Config::SetDefault("ns3::TcpSocketState::EnablePacing", BooleanValue(true));
229 Config::SetDefault("ns3::TcpSocketState::PaceInitialWindow", BooleanValue(true));
230 Config::SetDefault("ns3::TcpCubic::FastConvergence", BooleanValue(m_fastConvergence));
231 Config::SetDefault("ns3::TcpCubic::TcpFriendliness", BooleanValue(m_tcpFriendliness));
232
233 Time stopTime = Seconds(20);
234
235 NodeContainer sender;
236 NodeContainer receiver;
237 NodeContainer routers;
238 sender.Create(1);
239 receiver.Create(1);
240 routers.Create(2);
241
242 // Create the point-to-point link helpers
243 PointToPointHelper bottleneckLink;
244 // With the DynamicQueueLimits setting below, the following statement
245 // will minimize the buffering in the device and force most buffering
246 // into the AQM
247 bottleneckLink.SetQueue("ns3::DropTailQueue", "MaxSize", StringValue("2p"));
249 {
250 // Start at a lower capacity, and increase later
251 bottleneckLink.SetDeviceAttribute("DataRate", StringValue("50Mbps"));
252 }
253 else
254 {
255 bottleneckLink.SetDeviceAttribute("DataRate", StringValue("100Mbps"));
256 }
257 bottleneckLink.SetChannelAttribute("Delay", TimeValue(m_baseRtt / 2));
258
259 PointToPointHelper edgeLink;
260 edgeLink.SetDeviceAttribute("DataRate", StringValue("1000Mbps"));
261 edgeLink.SetChannelAttribute("Delay", StringValue("5us"));
262
263 // Create NetDevice containers
264 NetDeviceContainer senderEdge = edgeLink.Install(sender.Get(0), routers.Get(0));
265 NetDeviceContainer r1r2 = bottleneckLink.Install(routers.Get(0), routers.Get(1));
266 NetDeviceContainer receiverEdge = edgeLink.Install(routers.Get(1), receiver.Get(0));
267
268 // Install Stack
269 InternetStackHelper internet;
270 internet.Install(sender);
271 internet.Install(receiver);
272 internet.Install(routers);
273
274 // Configure the root queue discipline
276 tch.SetRootQueueDisc("ns3::FqCoDelQueueDisc");
277 tch.SetQueueLimits("ns3::DynamicQueueLimits");
278
279 tch.Install(senderEdge);
280 tch.Install(receiverEdge);
281
282 // Assign IP addresses
284 ipv4.SetBase("10.0.0.0", "255.255.255.0");
285
286 Ipv4InterfaceContainer i1i2 = ipv4.Assign(r1r2);
287 ipv4.NewNetwork();
288 Ipv4InterfaceContainer is1 = ipv4.Assign(senderEdge);
289 ipv4.NewNetwork();
290 Ipv4InterfaceContainer ir1 = ipv4.Assign(receiverEdge);
291
292 // Populate routing tables
294
295 // Select sender side port
296 uint16_t port = 50001;
297
298 // Install application on the sender
299 BulkSendHelper source("ns3::TcpSocketFactory", InetSocketAddress(ir1.GetAddress(1), port));
300 source.SetAttribute("MaxBytes", UintegerValue(0));
301 ApplicationContainer sourceApps = source.Install(sender.Get(0));
302 sourceApps.Start(Seconds(0.1));
303 // Hook trace source after application starts
306 this,
307 0,
308 0);
309 sourceApps.Stop(stopTime);
310
311 // Install application on the receiver
312 PacketSinkHelper sink("ns3::TcpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), port));
313 ApplicationContainer sinkApps = sink.Install(receiver.Get(0));
314 sinkApps.Start(Seconds(0.0));
315 sinkApps.Stop(stopTime);
316
318 {
319 // Double the capacity of the bottleneck link at 10 seconds
320 Ptr<PointToPointNetDevice> device = r1r2.Get(0)->GetObject<PointToPointNetDevice>();
322 }
323
324 std::ostringstream oss;
325 oss << m_prefix;
326 if (m_writeResults)
327 {
328 edgeLink.EnablePcap(oss.str(), senderEdge.Get(0));
329 edgeLink.EnablePcap(oss.str(), receiverEdge.Get(0));
330 edgeLink.EnableAscii(oss.str(), senderEdge.Get(0));
331 edgeLink.EnableAscii(oss.str(), receiverEdge.Get(0));
332 }
335
336 if (m_writeGnuplot)
337 {
338 std::ofstream outfile(oss.str() + ".plt");
339
340 std::string capacityIncreaseString;
342 {
343 capacityIncreaseString = " capacity increase = 1";
344 }
345 Gnuplot gnuplot = Gnuplot(
346 oss.str() + ".eps",
347 "Cubic concave/convex response (" + std::to_string(m_baseRtt.GetMilliSeconds()) +
348 " ms RTT, 1448 byte segs, 100 Mbps bottleneck)\\nFast convergence = " +
349 std::to_string(m_fastConvergence) +
350 " friendliness = " + std::to_string(m_tcpFriendliness) + capacityIncreaseString);
351 gnuplot.SetTerminal("post eps color enhanced");
352 gnuplot.SetLegend("Time (seconds)", "Cwnd (segments)");
355 gnuplot.GenerateOutput(outfile);
356 }
357
358 // Check that cwnd values are within tolerance of expected values
359 // The expected values were determined by inspecting the plots generated
360 if (m_prefix == "ns3-tcp-cubic-no-heuristic")
361 {
362 // Check overall min and max
364 true,
365 "cwnd outside range");
366 // Time just before a reduction does not have much variation
368 true,
369 "cwnd outside range");
370 }
371 else if (m_prefix == "ns3-tcp-cubic-fast-conv")
372 {
373 // Check overall min and max
375 true,
376 "cwnd outside range");
377 // Initial convex region does not have much variation
379 true,
380 "cwnd outside range");
381 }
382 else if (m_prefix == "ns3-tcp-cubic-no-friendly")
383 {
384 // Between time 12 and 16, cwnd should be fairly constant
385 // because without TCP friendliness, Cubic does not respond quickly
387 true,
388 "cwnd outside range");
389 // After time 19.5, cwnd should have grown much higher
390 NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(19.5), Seconds(20), 180, 210),
391 true,
392 "cwnd outside range");
393 }
394 else if (m_prefix == "ns3-tcp-cubic-friendly")
395 {
396 // In contrast to previous case, cwnd should grow above 150 much sooner
398 true,
399 "cwnd outside range");
400 }
401
403}
404
410{
411 public:
413};
414
416 : TestSuite("ns3-tcp-cubic", UNIT)
417{
418 // Test Cubic with no fast convergence or TCP friendliness enabled
419 // This results in a cwnd plot that has only the concave portion of
420 // returning cwnd to Wmax
421 AddTestCase(new Ns3TcpCubicTestCase("no heuristic",
422 "ns3-tcp-cubic-no-heuristic",
423 false,
424 false,
425 MilliSeconds(5),
426 false),
428
429 // Test Cubic with fast convergence but no TCP friendliness enabled
430 // This results in a cwnd plot that has concave and convex regions, as
431 // well as convex-only regions; also observed on Linux testbeds
432 AddTestCase(new Ns3TcpCubicTestCase("fast convergence on",
433 "ns3-tcp-cubic-fast-conv",
434 true,
435 false,
436 MilliSeconds(5),
437 false),
439
440 // Test Cubic with fast convergence but no TCP friendliness enabled
441 // with a higher RTT (20ms) and a step change in capacity at time 10s.
442 // This results in a sluggish response by TCP Cubic to use the new capacity.
443 AddTestCase(new Ns3TcpCubicTestCase("fast convergence on, Reno friendliness off",
444 "ns3-tcp-cubic-no-friendly",
445 true,
446 false,
447 MilliSeconds(20),
448 true),
450
451 // Test Cubic with fast convergence but with TCP friendliness enabled
452 // with a higher RTT (20ms) and a step change in capacity at time 10s.
453 // This results in a faster response by TCP Cubic to use the new capacity.
454 AddTestCase(new Ns3TcpCubicTestCase("fast convergence on, Reno friendliness on",
455 "ns3-tcp-cubic-friendly",
456 true,
457 true,
458 MilliSeconds(20),
459 true),
461}
462
Ipv4InterfaceContainer i1i2
IPv4 interface container i1 + i2.
Gnuplot2dDataset m_cwndTimeSeries
cwnd time series
bool m_tcpFriendliness
whether to enable TCP friendliness
void DoRun() override
Implementation to actually run this TestCase.
Time m_baseRtt
the base RTT to use
void ConnectCwndTrace(uint32_t nodeId, uint32_t socketId)
Connect TCP cwnd trace after socket is instantiated.
std::string m_prefix
filename prefix if writing files
Ns3TcpCubicTestCase(std::string testCase, std::string prefix, bool fastConvergence, bool tcpFriendliness, Time baseRtt, bool capacityIncrease)
Constructor.
bool m_writeGnuplot
Whether to write gnuplot files.
bool m_capacityIncrease
whether to trigger a capacity increase
bool m_fastConvergence
whether to enable fast convergence
bool m_writeResults
Whether to write pcaps.
std::map< Time, double > m_timeSeries
time series to check
void IncreaseBandwidth(Ptr< PointToPointNetDevice > device)
Increases the device bandwidth to 100 Mbps.
bool CheckValues(Time start, Time end, double lowerBound, double upperBound)
Check that time series values within a time range are within a value range.
TestSuite for module tcp-cubic.
holds a vector of ns3::Application pointers.
void Start(Time start) const
Start all of the Applications in this container at the start time given as a parameter.
void Stop(Time stop) const
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter.
void EnableAscii(std::string prefix, Ptr< NetDevice > nd, bool explicitFilename=false)
Enable ascii trace output on the indicated net device.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
A helper to make it easier to instantiate an ns3::BulkSendApplication on a set of nodes.
void SetAttribute(std::string name, const AttributeValue &value)
Helper function used to set the underlying application attributes, not the socket attributes.
ApplicationContainer Install(NodeContainer c) const
Install an ns3::BulkSendApplication on each node of the input container configured with all the attri...
Class for representing data rates.
Definition: data-rate.h:89
Class to represent a 2D points plot.
Definition: gnuplot.h:116
void Add(double x, double y)
Definition: gnuplot.cc:377
void SetTitle(const std::string &title)
Change line title.
Definition: gnuplot.cc:148
a simple class to generate gnuplot-ready plotting commands from a set of datasets.
Definition: gnuplot.h:370
void AddDataset(const GnuplotDataset &dataset)
Definition: gnuplot.cc:796
void SetLegend(const std::string &xLegend, const std::string &yLegend)
Definition: gnuplot.cc:776
void SetTerminal(const std::string &terminal)
Definition: gnuplot.cc:764
void GenerateOutput(std::ostream &os)
Writes gnuplot commands and data values to a single output stream.
Definition: gnuplot.cc:802
an Inet address class
aggregate IP/TCP/UDP functionality to existing Nodes.
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
static Ipv4Address GetAny()
static void PopulateRoutingTables()
Build a routing database and initialize the routing tables of the nodes in the simulation.
holds a vector of std::pair of Ptr<Ipv4> and interface index.
Ipv4Address GetAddress(uint32_t i, uint32_t j=0) const
holds a vector of ns3::NetDevice pointers
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
A helper to make it easier to instantiate an ns3::PacketSinkApplication on a set of nodes.
void EnablePcap(std::string prefix, Ptr< NetDevice > nd, bool promiscuous=false, bool explicitFilename=false)
Enable pcap output the indicated net device.
Build a set of PointToPointNetDevice objects.
void SetDeviceAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each NetDevice created by the helper.
void SetChannelAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each Channel created by the helper.
void SetQueue(std::string type, Ts &&... args)
Each point to point net device must have a queue to pass packets through.
NetDeviceContainer Install(NodeContainer c)
A Device for a Point to Point Network Link.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1060
@ QUICK
Fast test.
Definition: test.h:1065
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:408
AttributeValue implementation for Time.
Definition: nstime.h:1413
Build a set of QueueDisc objects.
QueueDiscContainer Install(NetDeviceContainer c)
uint16_t SetRootQueueDisc(const std::string &type, Args &&... args)
Helper function used to set a root queue disc of the given type and with the given attributes.
void SetQueueLimits(std::string type, Args &&... args)
Helper function used to add a queue limits object to the transmission queues of the devices.
Hold an unsigned integer type.
Definition: uinteger.h:45
uint16_t port
Definition: dsdv-manet.cc:44
Time stopTime
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:890
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition: config.cc:950
#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
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition: callback.h:765
void CubicCwndTracer(Gnuplot2dDataset *gnuplotTimeSeries, std::map< Time, double > *timeSeries, uint32_t oldval, uint32_t newval)
Add sample trace values to data structures.
#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
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static constexpr bool WRITE_PCAP
Set to true to write out pcap.
static Ns3TcpCubicTestSuite ns3TcpCubicTestSuite
Static variable for test initialization.
static constexpr bool WRITE_GNUPLOT
Set to true to write out gnuplot.
Ptr< PacketSink > sink
Pointer to the packet sink application.
Definition: wifi-tcp.cc:55