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::TcpCubic";
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 }
holds a vector of ns3::Application pointers.
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:557
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
Manage ASCII trace files for device models.
Definition: trace-helper.h:162
an Inet address class
static Ipv4Address GetAny(void)
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
AttributeValue implementation for Boolean.
Definition: boolean.h:36
QueueDiscContainer Install(NetDeviceContainer c)
A helper to make it easier to instantiate an ns3::BulkSendApplication on a set of nodes...
uint32_t GetInteger(uint32_t min, uint32_t max)
Get the next random value, as an unsigned integer in the specified range .
holds a vector of std::pair of Ptr<Ipv4> and interface index.
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:852
static void PopulateRoutingTables(void)
Build a routing database and initialize the routing tables of the nodes in the simulation.
void CheckForLostPackets()
Check right now for packets that appear to be lost.
NodeContainer n3n5
NetDeviceContainer Install(NodeContainer c)
static void SsThreshTracer(uint32_t oldval, uint32_t newval)
Definition: tcp-pacing.cc:118
static void RxTracer(Ptr< const Packet > p, Ptr< Ipv4 > ipv4, uint32_t interface)
Definition: tcp-pacing.cc:130
Ipv4Address destinationAddress
Destination address.
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:380
static void Run(void)
Run the simulation.
Definition: simulator.cc:172
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
const FlowStatsContainer & GetFlowStats() const
Retrieve all collected the flow statistics.
aggregate IP/TCP/UDP functionality to existing Nodes.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
A helper to make it easier to instantiate an ns3::PacketSinkApplication on a set of nodes...
cmd
Definition: second.py:35
Ptr< OutputStreamWrapper > CreateFileStream(std::string filename, std::ios::openmode filemode=std::ios::out)
Create and initialize an output stream object we&#39;ll use to write the traced bits. ...
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.
uint64_t GetBitRate() const
Get the underlying bitrate.
Definition: data-rate.cc:287
stack
Definition: first.py:41
a polymophic address class
Definition: address.h:90
NodeContainer n3n4
Class for representing data rates.
Definition: data-rate.h:88
std::map< FlowId, FlowStats > FlowStatsContainer
Container: FlowId, FlowStats.
Definition: flow-monitor.h:218
std::ofstream pacingRateStream
Definition: tcp-pacing.cc:101
Hold variables of type enum.
Definition: enum.h:54
static void PacingRateTracer(DataRate oldval, DataRate newval)
Definition: tcp-pacing.cc:112
AttributeValue implementation for Time.
Definition: nstime.h:1353
Ipv4Address GetAddress(uint32_t i, uint32_t j=0) const
Hold an unsigned integer type.
Definition: uinteger.h:44
holds a vector of ns3::NetDevice pointers
AttributeValue implementation for TypeId.
Definition: type-id.h:595
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition: config.cc:901
Build a set of QueueDisc objects.
Ptr< FlowMonitor > InstallAll()
Enable flow monitoring on all nodes.
void Start(Time start)
Arrange for all of the Applications in this container to Start() at the Time given as a parameter...
Parse command-line arguments.
Definition: command-line.h:227
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 void Destroy(void)
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:136
Ptr< FlowClassifier > GetClassifier()
Retrieve the FlowClassifier object for IPv4 created by the Install* methods.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
keep track of a set of node pointers.
NodeContainer n2n3
Helper to enable IP flow monitoring on a set of Nodes.
Structure to classify a packet.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
void ConnectSocketTraces(void)
Definition: tcp-pacing.cc:136
void SetChannelAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each Channel created by the helper.
static void CwndTracer(uint32_t oldval, uint32_t newval)
Definition: tcp-pacing.cc:106
FiveTuple FindFlow(FlowId flowId) const
Searches for the FiveTuple corresponding to the given flowId.
void Stop(Time stop)
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter...
std::ofstream packetTraceStream
Definition: tcp-pacing.cc:103
Ipv4InterfaceContainer Assign(const NetDeviceContainer &c)
Assign IP addresses to the net devices specified in the container based on the current network prefix...
static void TxTracer(Ptr< const Packet > p, Ptr< Ipv4 > ipv4, uint32_t interface)
Definition: tcp-pacing.cc:124
AttributeValue implementation for DataRate.
Definition: data-rate.h:298
static void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:180
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1289
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:849
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1305
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
std::ofstream ssThreshStream
Definition: tcp-pacing.cc:102
std::ofstream cwndStream
Definition: tcp-pacing.cc:98
NodeContainer n0n2
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:329
Ipv4Address sourceAddress
Source address.
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:1642
NodeContainer n1n2
bool tracing
Flag to enable/disable generation of tracing files.
Definition: wifi-bianchi.cc:85
void SetBase(Ipv4Address network, Ipv4Mask mask, Ipv4Address base="0.0.0.1")
Set the base network number, network mask and base address.
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition: type-id.cc:830