A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tcp-pacing.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 NITK Surathkal
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Vivek Jain <jain.vivek.anand@gmail.com>
7 * Deepak Kumaraswamy <deepakkavoor99@gmail.com>
8 */
9
10// The following network topology is used in this example, and is taken from
11// Figure 2 of https://homes.cs.washington.edu/~tom/pubs/pacing.pdf
12//
13// n0 n4
14// | |
15// |(4x Mbps, 5ms) |(4x Mbps, 5ms)
16// | |
17// | |
18// | (x Mbps, 40ms) |
19// n2 ------------------------ n3
20// | |
21// | |
22// |(4x Mbps, 5ms) |(4x Mbps, 5ms)
23// | |
24// n1 n5
25//
26//
27
28// This example illustrates how TCP pacing can be enabled on a socket.
29// Two long-running TCP flows are instantiated at nodes n0 and n1 to
30// send data over a bottleneck link (n2->n3) to sink nodes n4 and n5.
31// At the end of the simulation, the IP-level flow monitor tool will
32// print out summary statistics of the flows. The flow monitor detects
33// four flows, but that is because the flow records are unidirectional;
34// the latter two flows reported are actually ack streams.
35//
36// At the end of this simulation, data files are also generated
37// that track changes in Congestion Window, Slow Start threshold and
38// TCP pacing rate for the first flow (n0). Additionally, a data file
39// that contains information about packet transmission and reception times
40// (collected through TxTrace and RxTrace respectively) is also produced.
41// This transmission and reception (ack) trace is the most direct way to
42// observe the effects of pacing. All the above information is traced
43// just for the single node n0.
44//
45// A small amount of randomness is introduced to the program to control
46// the start time of the flows.
47//
48// This example has pacing enabled by default, which means that TCP
49// does not send packets back-to-back, but instead paces them out over
50// an RTT. The size of initial congestion window is set to 10, and pacing
51// of the initial window is enabled. The available command-line options and
52// their default values can be observed in the usual way by running the
53// program to print the help info; i.e.: ./ns3 run 'tcp-pacing --PrintHelp'
54//
55// When pacing is disabled, TCP sends eligible packets back-to-back. The
56// differences in behaviour when pacing is disabled can be observed from the
57// packet transmission data file. For instance, one can observe that
58// packets in the initial window are sent one after the other simultaneously,
59// without any inter-packet gaps. Another instance is when n0 receives a
60// packet in the form of an acknowledgement, and sends out data packets without
61// pacing them.
62//
63// Although this example serves as a useful demonstration of how pacing could
64// be enabled/disabled in ns-3 TCP congestion controls, we could not observe
65// significant improvements in throughput for the above topology when pacing
66// was enabled. In future, one could try and incorporate models such as
67// TCP Prague and ACK-filtering, which may show a stronger performance
68// impact for TCP pacing.
69
70#include "ns3/applications-module.h"
71#include "ns3/core-module.h"
72#include "ns3/flow-monitor-module.h"
73#include "ns3/internet-module.h"
74#include "ns3/ipv4-global-routing-helper.h"
75#include "ns3/network-module.h"
76#include "ns3/packet-sink.h"
77#include "ns3/point-to-point-module.h"
78#include "ns3/traffic-control-module.h"
79
80#include <fstream>
81#include <iomanip>
82#include <iostream>
83#include <string>
84
85using namespace ns3;
86
87NS_LOG_COMPONENT_DEFINE("TcpPacingExample");
88
89std::ofstream cwndStream;
90std::ofstream pacingRateStream;
91std::ofstream ssThreshStream;
92std::ofstream packetTraceStream;
93
94static void
96{
97 cwndStream << std::fixed << std::setprecision(6) << Simulator::Now().GetSeconds()
98 << std::setw(12) << newval << std::endl;
99}
100
101static void
103{
104 pacingRateStream << std::fixed << std::setprecision(6) << Simulator::Now().GetSeconds()
105 << std::setw(12) << newval.GetBitRate() / 1e6 << std::endl;
106}
107
108static void
110{
111 ssThreshStream << std::fixed << std::setprecision(6) << Simulator::Now().GetSeconds()
112 << std::setw(12) << newval << std::endl;
113}
114
115static void
117{
118 packetTraceStream << std::fixed << std::setprecision(6) << Simulator::Now().GetSeconds()
119 << " tx " << p->GetSize() << std::endl;
120}
121
122static void
124{
125 packetTraceStream << std::fixed << std::setprecision(6) << Simulator::Now().GetSeconds()
126 << " rx " << p->GetSize() << std::endl;
127}
128
129void
131{
132 Config::ConnectWithoutContext("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
134 Config::ConnectWithoutContext("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/PacingRate",
136 Config::ConnectWithoutContext("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/SlowStartThreshold",
138 Config::ConnectWithoutContext("/NodeList/0/$ns3::Ipv4L3Protocol/Tx", MakeCallback(&TxTracer));
139 Config::ConnectWithoutContext("/NodeList/0/$ns3::Ipv4L3Protocol/Rx", MakeCallback(&RxTracer));
140}
141
142int
143main(int argc, char* argv[])
144{
145 bool tracing = false;
146
147 uint32_t maxBytes = 0; // value of zero corresponds to unlimited send
148 std::string transportProtocol = "ns3::TcpCubic";
149
150 Time simulationEndTime = Seconds(5);
151 DataRate bottleneckBandwidth("10Mbps"); // value of x as shown in the above network topology
152 Time bottleneckDelay = MilliSeconds(40);
153 DataRate regLinkBandwidth(4 * bottleneckBandwidth.GetBitRate());
154 Time regLinkDelay = MilliSeconds(5);
155 DataRate maxPacingRate("4Gbps");
156
157 bool isPacingEnabled = true;
158 bool useEcn = true;
159 bool useQueueDisc = true;
160 bool shouldPaceInitialWindow = true;
161
162 // Configure defaults that are not based on explicit command-line arguments
163 // They may be overridden by general attribute configuration of command line
164 Config::SetDefault("ns3::TcpL4Protocol::SocketType",
165 TypeIdValue(TypeId::LookupByName(transportProtocol)));
166 Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10));
167
168 CommandLine cmd(__FILE__);
169 cmd.AddValue("tracing", "Flag to enable/disable Ascii and Pcap tracing", tracing);
170 cmd.AddValue("maxBytes", "Total number of bytes for application to send", maxBytes);
171 cmd.AddValue("isPacingEnabled", "Flag to enable/disable pacing in TCP", isPacingEnabled);
172 cmd.AddValue("maxPacingRate", "Max Pacing Rate", maxPacingRate);
173 cmd.AddValue("useEcn", "Flag to enable/disable ECN", useEcn);
174 cmd.AddValue("useQueueDisc", "Flag to enable/disable queue disc on bottleneck", useQueueDisc);
175 cmd.AddValue("shouldPaceInitialWindow",
176 "Flag to enable/disable pacing of TCP initial window",
177 shouldPaceInitialWindow);
178 cmd.AddValue("simulationEndTime", "Simulation end time", simulationEndTime);
179 cmd.Parse(argc, argv);
180
181 // Configure defaults based on command-line arguments
182 Config::SetDefault("ns3::TcpSocketState::EnablePacing", BooleanValue(isPacingEnabled));
183 Config::SetDefault("ns3::TcpSocketState::PaceInitialWindow",
184 BooleanValue(shouldPaceInitialWindow));
185 Config::SetDefault("ns3::TcpSocketBase::UseEcn",
187 Config::SetDefault("ns3::TcpSocketState::MaxPacingRate", DataRateValue(maxPacingRate));
188
189 NS_LOG_INFO("Create nodes.");
191 c.Create(6);
192
193 NS_LOG_INFO("Create channels.");
194 NodeContainer n0n2 = NodeContainer(c.Get(0), c.Get(2));
195 NodeContainer n1n2 = NodeContainer(c.Get(1), c.Get(2));
196
197 NodeContainer n2n3 = NodeContainer(c.Get(2), c.Get(3));
198
199 NodeContainer n3n4 = NodeContainer(c.Get(3), c.Get(4));
200 NodeContainer n3n5 = NodeContainer(c.Get(3), c.Get(5));
201
202 // Define Node link properties
203 PointToPointHelper regLink;
204 regLink.SetDeviceAttribute("DataRate", DataRateValue(regLinkBandwidth));
205 regLink.SetChannelAttribute("Delay", TimeValue(regLinkDelay));
206
207 NetDeviceContainer d0d2 = regLink.Install(n0n2);
208 NetDeviceContainer d1d2 = regLink.Install(n1n2);
209 NetDeviceContainer d3d4 = regLink.Install(n3n4);
210 NetDeviceContainer d3d5 = regLink.Install(n3n5);
211
212 PointToPointHelper bottleNeckLink;
213 bottleNeckLink.SetDeviceAttribute("DataRate", DataRateValue(bottleneckBandwidth));
214 bottleNeckLink.SetChannelAttribute("Delay", TimeValue(bottleneckDelay));
215
216 NetDeviceContainer d2d3 = bottleNeckLink.Install(n2n3);
217
218 // Install Internet stack
220 stack.Install(c);
221
222 // Install traffic control
223 if (useQueueDisc)
224 {
225 TrafficControlHelper tchBottleneck;
226 tchBottleneck.SetRootQueueDisc("ns3::FqCoDelQueueDisc");
227 tchBottleneck.Install(d2d3);
228 }
229
230 NS_LOG_INFO("Assign IP Addresses.");
232 ipv4.SetBase("10.1.1.0", "255.255.255.0");
233 Ipv4InterfaceContainer regLinkInterface0 = ipv4.Assign(d0d2);
234
235 ipv4.SetBase("10.1.2.0", "255.255.255.0");
236 Ipv4InterfaceContainer regLinkInterface1 = ipv4.Assign(d1d2);
237
238 ipv4.SetBase("10.1.3.0", "255.255.255.0");
239 Ipv4InterfaceContainer bottleneckInterface = ipv4.Assign(d2d3);
240
241 ipv4.SetBase("10.1.4.0", "255.255.255.0");
242 Ipv4InterfaceContainer regLinkInterface4 = ipv4.Assign(d3d4);
243
244 ipv4.SetBase("10.1.5.0", "255.255.255.0");
245 Ipv4InterfaceContainer regLinkInterface5 = ipv4.Assign(d3d5);
246
248
249 NS_LOG_INFO("Create Applications.");
250
251 // Two Sink Applications at n4 and n5
252 uint16_t sinkPort = 8080;
253 Address sinkAddress4(
254 InetSocketAddress(regLinkInterface4.GetAddress(1), sinkPort)); // interface of n4
255 Address sinkAddress5(
256 InetSocketAddress(regLinkInterface5.GetAddress(1), sinkPort)); // interface of n5
257 PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory",
259 ApplicationContainer sinkApps4 = packetSinkHelper.Install(c.Get(4)); // n4 as sink
260 ApplicationContainer sinkApps5 = packetSinkHelper.Install(c.Get(5)); // n5 as sink
261
262 sinkApps4.Start(Seconds(0));
263 sinkApps4.Stop(simulationEndTime);
264 sinkApps5.Start(Seconds(0));
265 sinkApps5.Stop(simulationEndTime);
266
267 // Randomize the start time between 0 and 1ms
269 uniformRv->SetStream(0);
270
271 // Two Source Applications at n0 and n1
272 BulkSendHelper source0("ns3::TcpSocketFactory", sinkAddress4);
273 BulkSendHelper source1("ns3::TcpSocketFactory", sinkAddress5);
274 // Set the amount of data to send in bytes. Zero is unlimited.
275 source0.SetAttribute("MaxBytes", UintegerValue(maxBytes));
276 source1.SetAttribute("MaxBytes", UintegerValue(maxBytes));
277 ApplicationContainer sourceApps0 = source0.Install(c.Get(0));
278 ApplicationContainer sourceApps1 = source1.Install(c.Get(1));
279
280 sourceApps0.Start(MicroSeconds(uniformRv->GetInteger(0, 1000)));
281 sourceApps0.Stop(simulationEndTime);
282 sourceApps1.Start(MicroSeconds(uniformRv->GetInteger(0, 1000)));
283 sourceApps1.Stop(simulationEndTime);
284
285 if (tracing)
286 {
287 AsciiTraceHelper ascii;
288 regLink.EnableAsciiAll(ascii.CreateFileStream("tcp-dynamic-pacing.tr"));
289 regLink.EnablePcapAll("tcp-dynamic-pacing", false);
290 }
291
292 cwndStream.open("tcp-dynamic-pacing-cwnd.dat", std::ios::out);
293 cwndStream << "#Time(s) Congestion Window (B)" << std::endl;
294
295 pacingRateStream.open("tcp-dynamic-pacing-pacing-rate.dat", std::ios::out);
296 pacingRateStream << "#Time(s) Pacing Rate (Mb/s)" << std::endl;
297
298 ssThreshStream.open("tcp-dynamic-pacing-ssthresh.dat", std::ios::out);
299 ssThreshStream << "#Time(s) Slow Start threshold (B)" << std::endl;
300
301 packetTraceStream.open("tcp-dynamic-pacing-packet-trace.dat", std::ios::out);
302 packetTraceStream << "#Time(s) tx/rx size (B)" << std::endl;
303
305
306 FlowMonitorHelper flowmon;
307 Ptr<FlowMonitor> monitor = flowmon.InstallAll();
308
309 NS_LOG_INFO("Run Simulation.");
310 Simulator::Stop(simulationEndTime);
312
313 monitor->CheckForLostPackets();
315 FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
316 for (auto i = stats.begin(); i != stats.end(); ++i)
317 {
318 Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(i->first);
319
320 std::cout << "Flow " << i->first << " (" << t.sourceAddress << " -> "
321 << t.destinationAddress << ")\n";
322 std::cout << " Tx Packets: " << i->second.txPackets << "\n";
323 std::cout << " Tx Bytes: " << i->second.txBytes << "\n";
324 std::cout << " TxOffered: "
325 << i->second.txBytes * 8.0 / simulationEndTime.GetSeconds() / 1000 / 1000
326 << " Mbps\n";
327 std::cout << " Rx Packets: " << i->second.rxPackets << "\n";
328 std::cout << " Rx Bytes: " << i->second.rxBytes << "\n";
329 std::cout << " Throughput: "
330 << i->second.rxBytes * 8.0 / simulationEndTime.GetSeconds() / 1000 / 1000
331 << " Mbps\n";
332 }
333
334 cwndStream.close();
335 pacingRateStream.close();
336 ssThreshStream.close();
338
339 return 0;
340}
NodeContainer n2n3
Nodecontainer n2 + n3.
NodeContainer n1n2
Nodecontainer n1 + n2.
NodeContainer n3n4
Nodecontainer n3 + n4.
NodeContainer n0n2
Nodecontainer n0 + n2.
NodeContainer n3n5
Nodecontainer n3 + n5.
a polymophic address class
Definition address.h:90
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 EnableAsciiAll(std::string prefix)
Enable ascii trace output on each device (which is of the appropriate type) in the set of all nodes c...
Manage ASCII trace files for device models.
Ptr< OutputStreamWrapper > CreateFileStream(std::string filename, std::ios::openmode filemode=std::ios::out)
Create and initialize an output stream object we'll use to write the traced bits.
A helper to make it easier to instantiate an ns3::BulkSendApplication on a set of nodes.
Parse command-line arguments.
Class for representing data rates.
Definition data-rate.h:78
uint64_t GetBitRate() const
Get the underlying bitrate.
Definition data-rate.cc:234
Hold variables of type enum.
Definition enum.h:52
Helper to enable IP flow monitoring on a set of Nodes.
Ptr< FlowClassifier > GetClassifier()
Retrieve the FlowClassifier object for IPv4 created by the Install* methods.
Ptr< FlowMonitor > InstallAll()
Enable flow monitoring on all nodes.
std::map< FlowId, FlowStats > FlowStatsContainer
Container: FlowId, FlowStats.
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
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 EnablePcapAll(std::string prefix, bool promiscuous=false)
Enable pcap output on each device (which is of the appropriate type) in the set of all nodes created ...
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.
NetDeviceContainer Install(NodeContainer c)
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Data structure that records the congestion state of a connection.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
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.
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition type-id.cc:872
Hold an unsigned integer type.
Definition uinteger.h:34
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition config.cc:943
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#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
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
stack
Definition first.py:33
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
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
Structure to classify a packet.
Ipv4Address sourceAddress
Source address.
Ipv4Address destinationAddress
Destination address.
std::ofstream packetTraceStream
Definition tcp-pacing.cc:92
static void TxTracer(Ptr< const Packet > p, Ptr< Ipv4 > ipv4, uint32_t interface)
static void RxTracer(Ptr< const Packet > p, Ptr< Ipv4 > ipv4, uint32_t interface)
std::ofstream ssThreshStream
Definition tcp-pacing.cc:91
static void CwndTracer(uint32_t oldval, uint32_t newval)
Definition tcp-pacing.cc:95
std::ofstream pacingRateStream
Definition tcp-pacing.cc:90
std::ofstream cwndStream
Definition tcp-pacing.cc:89
static void SsThreshTracer(uint32_t oldval, uint32_t newval)
static void PacingRateTracer(DataRate oldval, DataRate newval)
void ConnectSocketTraces()
bool tracing
Flag to enable/disable generation of tracing files.