A Discrete-Event Network Simulator
API
tcp-bbr-example.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2018-20 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: Aarti Nandagiri <aarti.nandagiri@gmail.com>
19  * Vivek Jain <jain.vivek.anand@gmail.com>
20  * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
21  */
22 
23 // This program simulates the following topology:
24 //
25 // 1000 Mbps 10Mbps 1000 Mbps
26 // Sender -------------- R1 -------------- R2 -------------- Receiver
27 // 5ms 10ms 5ms
28 //
29 // The link between R1 and R2 is a bottleneck link with 10 Mbps. All other
30 // links are 1000 Mbps.
31 //
32 // This program runs by default for 100 seconds and creates a new directory
33 // called 'bbr-results' in the ns-3 root directory. The program creates one
34 // sub-directory called 'pcap' in 'bbr-results' directory (if pcap generation
35 // is enabled) and three .dat files.
36 //
37 // (1) 'pcap' sub-directory contains six PCAP files:
38 // * bbr-0-0.pcap for the interface on Sender
39 // * bbr-1-0.pcap for the interface on Receiver
40 // * bbr-2-0.pcap for the first interface on R1
41 // * bbr-2-1.pcap for the second interface on R1
42 // * bbr-3-0.pcap for the first interface on R2
43 // * bbr-3-1.pcap for the second interface on R2
44 // (2) cwnd.dat file contains congestion window trace for the sender node
45 // (3) throughput.dat file contains sender side throughput trace
46 // (4) queueSize.dat file contains queue length trace from the bottleneck link
47 //
48 // BBR algorithm enters PROBE_RTT phase in every 10 seconds. The congestion
49 // window is fixed to 4 segments in this phase with a goal to achieve a better
50 // estimate of minimum RTT (because queue at the bottleneck link tends to drain
51 // when the congestion window is reduced to 4 segments).
52 //
53 // The congestion window and queue occupancy traces output by this program show
54 // periodic drops every 10 seconds when BBR algorithm is in PROBE_RTT phase.
55 
56 #include "ns3/core-module.h"
57 #include "ns3/network-module.h"
58 #include "ns3/internet-module.h"
59 #include "ns3/point-to-point-module.h"
60 #include "ns3/applications-module.h"
61 #include "ns3/traffic-control-module.h"
62 #include "ns3/flow-monitor-module.h"
63 
64 using namespace ns3;
65 
66 std::string dir;
67 uint32_t prev = 0;
69 
70 // Calculate throughput
71 static void
73 {
75  auto itr = stats.begin ();
76  Time curTime = Now ();
77  std::ofstream thr (dir + "/throughput.dat", std::ios::out | std::ios::app);
78  thr << curTime << " " << 8 * (itr->second.txBytes - prev) / (1000 * 1000 * (curTime.GetSeconds () - prevTime.GetSeconds ())) << std::endl;
79  prevTime = curTime;
80  prev = itr->second.txBytes;
81  Simulator::Schedule (Seconds (0.2), &TraceThroughput, monitor);
82 }
83 
84 // Check the queue size
86 {
87  uint32_t qsize = qd->GetCurrentSize ().GetValue ();
89  std::ofstream q (dir + "/queueSize.dat", std::ios::out | std::ios::app);
90  q << Simulator::Now ().GetSeconds () << " " << qsize << std::endl;
91  q.close ();
92 }
93 
94 // Trace congestion window
95 static void CwndTracer (Ptr<OutputStreamWrapper> stream, uint32_t oldval, uint32_t newval)
96 {
97  *stream->GetStream () << Simulator::Now ().GetSeconds () << " " << newval / 1448.0 << std::endl;
98 }
99 
100 void TraceCwnd (uint32_t nodeId, uint32_t socketId)
101 {
102  AsciiTraceHelper ascii;
103  Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream (dir + "/cwnd.dat");
104  Config::ConnectWithoutContext ("/NodeList/" + std::to_string (nodeId) + "/$ns3::TcpL4Protocol/SocketList/" + std::to_string (socketId) + "/CongestionWindow", MakeBoundCallback (&CwndTracer, stream));
105 }
106 
107 int main (int argc, char *argv [])
108 {
109  // Naming the output directory using local system time
110  time_t rawtime;
111  struct tm * timeinfo;
112  char buffer [80];
113  time (&rawtime);
114  timeinfo = localtime (&rawtime);
115  strftime (buffer, sizeof (buffer), "%d-%m-%Y-%I-%M-%S", timeinfo);
116  std::string currentTime (buffer);
117 
118  std::string tcpTypeId = "TcpBbr";
119  std::string queueDisc = "FifoQueueDisc";
120  uint32_t delAckCount = 2;
121  bool bql = true;
122  bool enablePcap = false;
123  Time stopTime = Seconds (100);
124 
125  CommandLine cmd (__FILE__);
126  cmd.AddValue ("tcpTypeId", "Transport protocol to use: TcpNewReno, TcpBbr", tcpTypeId);
127  cmd.AddValue ("delAckCount", "Delayed ACK count", delAckCount);
128  cmd.AddValue ("enablePcap", "Enable/Disable pcap file generation", enablePcap);
129  cmd.AddValue ("stopTime", "Stop time for applications / simulation time will be stopTime + 1", stopTime);
130  cmd.Parse (argc, argv);
131 
132  queueDisc = std::string ("ns3::") + queueDisc;
133 
134  Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue ("ns3::" + tcpTypeId));
135  Config::SetDefault ("ns3::TcpSocket::SndBufSize", UintegerValue (4194304));
136  Config::SetDefault ("ns3::TcpSocket::RcvBufSize", UintegerValue (6291456));
137  Config::SetDefault ("ns3::TcpSocket::InitialCwnd", UintegerValue (10));
138  Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (delAckCount));
139  Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1448));
140  Config::SetDefault ("ns3::DropTailQueue<Packet>::MaxSize", QueueSizeValue (QueueSize ("1p")));
141  Config::SetDefault (queueDisc + "::MaxSize", QueueSizeValue (QueueSize ("100p")));
142 
143  NodeContainer sender, receiver;
144  NodeContainer routers;
145  sender.Create (1);
146  receiver.Create (1);
147  routers.Create (2);
148 
149  // Create the point-to-point link helpers
150  PointToPointHelper bottleneckLink;
151  bottleneckLink.SetDeviceAttribute ("DataRate", StringValue ("10Mbps"));
152  bottleneckLink.SetChannelAttribute ("Delay", StringValue ("10ms"));
153 
154  PointToPointHelper edgeLink;
155  edgeLink.SetDeviceAttribute ("DataRate", StringValue ("1000Mbps"));
156  edgeLink.SetChannelAttribute ("Delay", StringValue ("5ms"));
157 
158  // Create NetDevice containers
159  NetDeviceContainer senderEdge = edgeLink.Install (sender.Get (0), routers.Get (0));
160  NetDeviceContainer r1r2 = bottleneckLink.Install (routers.Get (0), routers.Get (1));
161  NetDeviceContainer receiverEdge = edgeLink.Install (routers.Get (1), receiver.Get (0));
162 
163  // Install Stack
164  InternetStackHelper internet;
165  internet.Install (sender);
166  internet.Install (receiver);
167  internet.Install (routers);
168 
169  // Configure the root queue discipline
171  tch.SetRootQueueDisc (queueDisc);
172 
173  if (bql)
174  {
175  tch.SetQueueLimits ("ns3::DynamicQueueLimits", "HoldTime", StringValue ("1000ms"));
176  }
177 
178  tch.Install (senderEdge);
179  tch.Install (receiverEdge);
180 
181  // Assign IP addresses
182  Ipv4AddressHelper ipv4;
183  ipv4.SetBase ("10.0.0.0", "255.255.255.0");
184 
185  Ipv4InterfaceContainer i1i2 = ipv4.Assign (r1r2);
186 
187  ipv4.NewNetwork ();
188  Ipv4InterfaceContainer is1 = ipv4.Assign (senderEdge);
189 
190  ipv4.NewNetwork ();
191  Ipv4InterfaceContainer ir1 = ipv4.Assign (receiverEdge);
192 
193  // Populate routing tables
195 
196  // Select sender side port
197  uint16_t port = 50001;
198 
199  // Install application on the sender
200  BulkSendHelper source ("ns3::TcpSocketFactory", InetSocketAddress (ir1.GetAddress (1), port));
201  source.SetAttribute ("MaxBytes", UintegerValue (0));
202  ApplicationContainer sourceApps = source.Install (sender.Get (0));
203  sourceApps.Start (Seconds (0.0));
204  Simulator::Schedule (Seconds (0.2), &TraceCwnd, 0, 0);
205  sourceApps.Stop (stopTime);
206 
207  // Install application on the receiver
208  PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port));
209  ApplicationContainer sinkApps = sink.Install (receiver.Get (0));
210  sinkApps.Start (Seconds (0.0));
211  sinkApps.Stop (stopTime);
212 
213  // Create a new directory to store the output of the program
214  dir = "bbr-results/" + currentTime + "/";
215  std::string dirToSave = "mkdir -p " + dir;
216  if (system (dirToSave.c_str ()) == -1)
217  {
218  exit (1);
219  }
220 
221  // The plotting scripts are provided in the following repository, if needed:
222  // https://github.com/mohittahiliani/BBR-Validation/
223  //
224  // Download 'PlotScripts' directory (which is inside ns-3 scripts directory)
225  // from the link given above and place it in the ns-3 root directory.
226  // Uncomment the following three lines to generate plots for Congestion
227  // Window, sender side throughput and queue occupancy on the bottleneck link.
228  //
229  // system (("cp -R PlotScripts/gnuplotScriptCwnd " + dir).c_str ());
230  // system (("cp -R PlotScripts/gnuplotScriptThroughput " + dir).c_str ());
231  // system (("cp -R PlotScripts/gnuplotScriptQueueSize " + dir).c_str ());
232 
233  // Trace the queue occupancy on the second interface of R1
234  tch.Uninstall (routers.Get (0)->GetDevice (1));
236  qd = tch.Install (routers.Get (0)->GetDevice (1));
238 
239  // Generate PCAP traces if it is enabled
240  if (enablePcap)
241  {
242  if (system ((dirToSave + "/pcap/").c_str ()) == -1)
243  {
244  exit (1);
245  }
246  bottleneckLink.EnablePcapAll (dir + "/pcap/bbr", true);
247  }
248 
249  // Check for dropped packets using Flow Monitor
250  FlowMonitorHelper flowmon;
251  Ptr<FlowMonitor> monitor = flowmon.InstallAll ();
252  Simulator::Schedule (Seconds (0 + 0.000001), &TraceThroughput, monitor);
253 
254  Simulator::Stop (stopTime + TimeStep (1));
255  Simulator::Run ();
257 
258  return 0;
259 }
Ptr< PacketSink > sink
Definition: wifi-tcp.cc:56
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)
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
QueueDiscContainer Install(NetDeviceContainer c)
Class for representing queue sizes.
Definition: queue-size.h:94
A helper to make it easier to instantiate an ns3::BulkSendApplication on a set of nodes...
holds a vector of std::pair of Ptr<Ipv4> and interface index.
static void PopulateRoutingTables(void)
Build a routing database and initialize the routing tables of the nodes in the simulation.
Hold variables of type string.
Definition: string.h:41
uint32_t GetValue() const
Get the underlying value.
Definition: queue-size.cc:175
NetDeviceContainer Install(NodeContainer c)
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:144
QueueSize GetCurrentSize(void)
Get the current size of the queue disc in bytes, if operating in bytes mode, or packets, otherwise.
Definition: queue-disc.cc:523
bool enablePcap
Callback< R > MakeBoundCallback(R(*fnPtr)(TX), ARG a1)
Make Callbacks with one bound argument.
Definition: callback.h:1703
void SetQueueLimits(std::string type, Args &&... args)
Helper function used to add a queue limits object to the transmission queues of the devices...
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:380
Ipv4InterfaceContainer i1i2
static void Run(void)
Run the simulation.
Definition: simulator.cc:172
const FlowStatsContainer & GetFlowStats() const
Retrieve all collected the flow statistics.
aggregate IP/TCP/UDP functionality to existing Nodes.
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 Uninstall(NetDeviceContainer c)
void SetDeviceAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each NetDevice created by the helper.
uint16_t port
Definition: dsdv-manet.cc:45
uint32_t prev
Holds a vector of ns3::QueueDisc pointers.
std::map< FlowId, FlowStats > FlowStatsContainer
Container: FlowId, FlowStats.
Definition: flow-monitor.h:218
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 ...
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:588
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
void CheckQueueSize(Ptr< QueueDisc > qd)
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition: config.cc:901
Build a set of QueueDisc objects.
Time stopTime
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...
std::string dir
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
Every class exported by the ns3 library is enclosed in the ns3 namespace.
keep track of a set of node pointers.
Ptr< QueueDisc > Get(std::size_t i) const
Get the Ptr<QueueDisc> stored in this container at a given index.
Helper to enable IP flow monitoring on a set of Nodes.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
void SetChannelAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each Channel created by the helper.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
void Stop(Time stop)
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter...
Ipv4InterfaceContainer Assign(const NetDeviceContainer &c)
Assign IP addresses to the net devices specified in the container based on the current network prefix...
void TraceCwnd(uint32_t nodeId, uint32_t socketId)
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
Time prevTime
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
Ipv4Address NewNetwork(void)
Increment the network number and reset the IP address counter to the base value provided in the SetBa...
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
static void CwndTracer(Ptr< OutputStreamWrapper > stream, uint32_t oldval, uint32_t newval)
static void TraceThroughput(Ptr< FlowMonitor > monitor)
std::ostream * GetStream(void)
Return a pointer to an ostream previously set in the wrapper.
void SetBase(Ipv4Address network, Ipv4Mask mask, Ipv4Address base="0.0.0.1")
Set the base network number, network mask and base address.