A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tcp-bbr-example.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018-20 NITK Surathkal
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Authors: Aarti Nandagiri <aarti.nandagiri@gmail.com>
18 * Vivek Jain <jain.vivek.anand@gmail.com>
19 * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
20 */
21
22// This program simulates the following topology:
23//
24// 1000 Mbps 10Mbps 1000 Mbps
25// Sender -------------- R1 -------------- R2 -------------- Receiver
26// 5ms 10ms 5ms
27//
28// The link between R1 and R2 is a bottleneck link with 10 Mbps. All other
29// links are 1000 Mbps.
30//
31// This program runs by default for 100 seconds and creates a new directory
32// called 'bbr-results' in the ns-3 root directory. The program creates one
33// sub-directory called 'pcap' in 'bbr-results' directory (if pcap generation
34// is enabled) and three .dat files.
35//
36// (1) 'pcap' sub-directory contains six PCAP files:
37// * bbr-0-0.pcap for the interface on Sender
38// * bbr-1-0.pcap for the interface on Receiver
39// * bbr-2-0.pcap for the first interface on R1
40// * bbr-2-1.pcap for the second interface on R1
41// * bbr-3-0.pcap for the first interface on R2
42// * bbr-3-1.pcap for the second interface on R2
43// (2) cwnd.dat file contains congestion window trace for the sender node
44// (3) throughput.dat file contains sender side throughput trace
45// (4) queueSize.dat file contains queue length trace from the bottleneck link
46//
47// BBR algorithm enters PROBE_RTT phase in every 10 seconds. The congestion
48// window is fixed to 4 segments in this phase with a goal to achieve a better
49// estimate of minimum RTT (because queue at the bottleneck link tends to drain
50// when the congestion window is reduced to 4 segments).
51//
52// The congestion window and queue occupancy traces output by this program show
53// periodic drops every 10 seconds when BBR algorithm is in PROBE_RTT phase.
54
55#include "ns3/applications-module.h"
56#include "ns3/core-module.h"
57#include "ns3/flow-monitor-module.h"
58#include "ns3/internet-module.h"
59#include "ns3/network-module.h"
60#include "ns3/point-to-point-module.h"
61#include "ns3/traffic-control-module.h"
62
63using namespace ns3;
64
65std::string dir;
68
69// Calculate throughput
70static void
72{
73 FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
74 auto itr = stats.begin();
75 Time curTime = Now();
76 std::ofstream thr(dir + "/throughput.dat", std::ios::out | std::ios::app);
77 thr << curTime << " "
78 << 8 * (itr->second.txBytes - prev) /
79 (1000 * 1000 * (curTime.GetSeconds() - prevTime.GetSeconds()))
80 << std::endl;
81 prevTime = curTime;
82 prev = itr->second.txBytes;
84}
85
86// Check the queue size
87void
89{
90 uint32_t qsize = qd->GetCurrentSize().GetValue();
92 std::ofstream q(dir + "/queueSize.dat", std::ios::out | std::ios::app);
93 q << Simulator::Now().GetSeconds() << " " << qsize << std::endl;
94 q.close();
95}
96
97// Trace congestion window
98static void
100{
101 *stream->GetStream() << Simulator::Now().GetSeconds() << " " << newval / 1448.0 << std::endl;
102}
103
104void
105TraceCwnd(uint32_t nodeId, uint32_t socketId)
106{
107 AsciiTraceHelper ascii;
108 Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream(dir + "/cwnd.dat");
109 Config::ConnectWithoutContext("/NodeList/" + std::to_string(nodeId) +
110 "/$ns3::TcpL4Protocol/SocketList/" +
111 std::to_string(socketId) + "/CongestionWindow",
112 MakeBoundCallback(&CwndTracer, stream));
113}
114
115int
116main(int argc, char* argv[])
117{
118 // Naming the output directory using local system time
119 time_t rawtime;
120 struct tm* timeinfo;
121 char buffer[80];
122 time(&rawtime);
123 timeinfo = localtime(&rawtime);
124 strftime(buffer, sizeof(buffer), "%d-%m-%Y-%I-%M-%S", timeinfo);
125 std::string currentTime(buffer);
126
127 std::string tcpTypeId = "TcpBbr";
128 std::string queueDisc = "FifoQueueDisc";
129 uint32_t delAckCount = 2;
130 bool bql = true;
131 bool enablePcap = false;
132 Time stopTime = Seconds(100);
133
134 CommandLine cmd(__FILE__);
135 cmd.AddValue("tcpTypeId", "Transport protocol to use: TcpNewReno, TcpBbr", tcpTypeId);
136 cmd.AddValue("delAckCount", "Delayed ACK count", delAckCount);
137 cmd.AddValue("enablePcap", "Enable/Disable pcap file generation", enablePcap);
138 cmd.AddValue("stopTime",
139 "Stop time for applications / simulation time will be stopTime + 1",
140 stopTime);
141 cmd.Parse(argc, argv);
142
143 queueDisc = std::string("ns3::") + queueDisc;
144
145 Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::" + tcpTypeId));
146 Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(4194304));
147 Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(6291456));
148 Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10));
149 Config::SetDefault("ns3::TcpSocket::DelAckCount", UintegerValue(delAckCount));
150 Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(1448));
151 Config::SetDefault("ns3::DropTailQueue<Packet>::MaxSize", QueueSizeValue(QueueSize("1p")));
152 Config::SetDefault(queueDisc + "::MaxSize", QueueSizeValue(QueueSize("100p")));
153
154 NodeContainer sender;
155 NodeContainer receiver;
156 NodeContainer routers;
157 sender.Create(1);
158 receiver.Create(1);
159 routers.Create(2);
160
161 // Create the point-to-point link helpers
162 PointToPointHelper bottleneckLink;
163 bottleneckLink.SetDeviceAttribute("DataRate", StringValue("10Mbps"));
164 bottleneckLink.SetChannelAttribute("Delay", StringValue("10ms"));
165
166 PointToPointHelper edgeLink;
167 edgeLink.SetDeviceAttribute("DataRate", StringValue("1000Mbps"));
168 edgeLink.SetChannelAttribute("Delay", StringValue("5ms"));
169
170 // Create NetDevice containers
171 NetDeviceContainer senderEdge = edgeLink.Install(sender.Get(0), routers.Get(0));
172 NetDeviceContainer r1r2 = bottleneckLink.Install(routers.Get(0), routers.Get(1));
173 NetDeviceContainer receiverEdge = edgeLink.Install(routers.Get(1), receiver.Get(0));
174
175 // Install Stack
177 internet.Install(sender);
178 internet.Install(receiver);
179 internet.Install(routers);
180
181 // Configure the root queue discipline
183 tch.SetRootQueueDisc(queueDisc);
184
185 if (bql)
186 {
187 tch.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1000ms"));
188 }
189
190 tch.Install(senderEdge);
191 tch.Install(receiverEdge);
192
193 // Assign IP addresses
195 ipv4.SetBase("10.0.0.0", "255.255.255.0");
196
197 Ipv4InterfaceContainer i1i2 = ipv4.Assign(r1r2);
198
199 ipv4.NewNetwork();
200 Ipv4InterfaceContainer is1 = ipv4.Assign(senderEdge);
201
202 ipv4.NewNetwork();
203 Ipv4InterfaceContainer ir1 = ipv4.Assign(receiverEdge);
204
205 // Populate routing tables
207
208 // Select sender side port
209 uint16_t port = 50001;
210
211 // Install application on the sender
212 BulkSendHelper source("ns3::TcpSocketFactory", InetSocketAddress(ir1.GetAddress(1), port));
213 source.SetAttribute("MaxBytes", UintegerValue(0));
214 ApplicationContainer sourceApps = source.Install(sender.Get(0));
215 sourceApps.Start(Seconds(0.1));
216 // Hook trace source after application starts
218 sourceApps.Stop(stopTime);
219
220 // Install application on the receiver
221 PacketSinkHelper sink("ns3::TcpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), port));
222 ApplicationContainer sinkApps = sink.Install(receiver.Get(0));
223 sinkApps.Start(Seconds(0.0));
224 sinkApps.Stop(stopTime);
225
226 // Create a new directory to store the output of the program
227 dir = "bbr-results/" + currentTime + "/";
228 std::string dirToSave = "mkdir -p " + dir;
229 if (system(dirToSave.c_str()) == -1)
230 {
231 exit(1);
232 }
233
234 // The plotting scripts are provided in the following repository, if needed:
235 // https://github.com/mohittahiliani/BBR-Validation/
236 //
237 // Download 'PlotScripts' directory (which is inside ns-3 scripts directory)
238 // from the link given above and place it in the ns-3 root directory.
239 // Uncomment the following three lines to generate plots for Congestion
240 // Window, sender side throughput and queue occupancy on the bottleneck link.
241 //
242 // system (("cp -R PlotScripts/gnuplotScriptCwnd " + dir).c_str ());
243 // system (("cp -R PlotScripts/gnuplotScriptThroughput " + dir).c_str ());
244 // system (("cp -R PlotScripts/gnuplotScriptQueueSize " + dir).c_str ());
245
246 // Trace the queue occupancy on the second interface of R1
247 tch.Uninstall(routers.Get(0)->GetDevice(1));
249 qd = tch.Install(routers.Get(0)->GetDevice(1));
251
252 // Generate PCAP traces if it is enabled
253 if (enablePcap)
254 {
255 if (system((dirToSave + "/pcap/").c_str()) == -1)
256 {
257 exit(1);
258 }
259 bottleneckLink.EnablePcapAll(dir + "/pcap/bbr", true);
260 }
261
262 // Check for dropped packets using Flow Monitor
263 FlowMonitorHelper flowmon;
264 Ptr<FlowMonitor> monitor = flowmon.InstallAll();
265 Simulator::Schedule(Seconds(0 + 0.000001), &TraceThroughput, monitor);
266
267 Simulator::Stop(stopTime + TimeStep(1));
270
271 return 0;
272}
Ipv4InterfaceContainer i1i2
IPv4 interface container i1 + i2.
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.
Manage ASCII trace files for device models.
Definition: trace-helper.h:173
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.
Definition: command-line.h:232
Helper to enable IP flow monitoring on a set of Nodes.
Ptr< FlowMonitor > InstallAll()
Enable flow monitoring on all nodes.
std::map< FlowId, FlowStats > FlowStatsContainer
Container: FlowId, FlowStats.
Definition: flow-monitor.h:230
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.
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:152
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.
Definition: ptr.h:78
Holds a vector of ns3::QueueDisc pointers.
Ptr< QueueDisc > Get(std::size_t i) const
Get the Ptr<QueueDisc> stored in this container at a given index.
Class for representing queue sizes.
Definition: queue-size.h:96
AttributeValue implementation for QueueSize.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:140
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static void Run()
Run the simulation.
Definition: simulator.cc:176
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:606
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:184
Hold variables of type string.
Definition: string.h:56
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
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.
void Uninstall(NetDeviceContainer c)
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:891
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition: config.cc:951
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition: callback.h:763
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns cmd
Definition: second.py:33
Time prevTime
static void CwndTracer(Ptr< OutputStreamWrapper > stream, uint32_t oldval, uint32_t newval)
void TraceCwnd(uint32_t nodeId, uint32_t socketId)
uint32_t prev
static void TraceThroughput(Ptr< FlowMonitor > monitor)
std::string dir
void CheckQueueSize(Ptr< QueueDisc > qd)
Ptr< PacketSink > sink
Pointer to the packet sink application.
Definition: wifi-tcp.cc:55