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