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
63#include <filesystem>
64
65using namespace ns3;
66using namespace ns3::SystemPath;
67
68std::string dir;
69std::ofstream throughput;
70std::ofstream queueSize;
71
74
75// Calculate throughput
76static void
78{
79 FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
80 if (!stats.empty())
81 {
82 auto itr = stats.begin();
83 Time curTime = Now();
84 throughput << curTime << " "
85 << 8 * (itr->second.txBytes - prev) / ((curTime - prevTime).ToDouble(Time::US))
86 << std::endl;
87 prevTime = curTime;
88 prev = itr->second.txBytes;
89 }
91}
92
93// Check the queue size
94void
96{
97 uint32_t qsize = qd->GetCurrentSize().GetValue();
99 queueSize << Simulator::Now().GetSeconds() << " " << qsize << std::endl;
100}
101
102// Trace congestion window
103static void
105{
106 *stream->GetStream() << Simulator::Now().GetSeconds() << " " << newval / 1448.0 << std::endl;
107}
108
109void
110TraceCwnd(uint32_t nodeId, uint32_t socketId)
111{
112 AsciiTraceHelper ascii;
113 Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream(dir + "/cwnd.dat");
114 Config::ConnectWithoutContext("/NodeList/" + std::to_string(nodeId) +
115 "/$ns3::TcpL4Protocol/SocketList/" +
116 std::to_string(socketId) + "/CongestionWindow",
117 MakeBoundCallback(&CwndTracer, stream));
118}
119
120int
121main(int argc, char* argv[])
122{
123 // Naming the output directory using local system time
124 time_t rawtime;
125 struct tm* timeinfo;
126 char buffer[80];
127 time(&rawtime);
128 timeinfo = localtime(&rawtime);
129 strftime(buffer, sizeof(buffer), "%d-%m-%Y-%I-%M-%S", timeinfo);
130 std::string currentTime(buffer);
131
132 std::string tcpTypeId = "TcpBbr";
133 std::string queueDisc = "FifoQueueDisc";
134 uint32_t delAckCount = 2;
135 bool bql = true;
136 bool enablePcap = false;
137 Time stopTime = Seconds(100);
138
139 CommandLine cmd(__FILE__);
140 cmd.AddValue("tcpTypeId", "Transport protocol to use: TcpNewReno, TcpBbr", tcpTypeId);
141 cmd.AddValue("delAckCount", "Delayed ACK count", delAckCount);
142 cmd.AddValue("enablePcap", "Enable/Disable pcap file generation", enablePcap);
143 cmd.AddValue("stopTime",
144 "Stop time for applications / simulation time will be stopTime + 1",
145 stopTime);
146 cmd.Parse(argc, argv);
147
148 queueDisc = std::string("ns3::") + queueDisc;
149
150 Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::" + tcpTypeId));
151
152 // The maximum send buffer size is set to 4194304 bytes (4MB) and the
153 // maximum receive buffer size is set to 6291456 bytes (6MB) in the Linux
154 // kernel. The same buffer sizes are used as default in this example.
155 Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(4194304));
156 Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(6291456));
157 Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10));
158 Config::SetDefault("ns3::TcpSocket::DelAckCount", UintegerValue(delAckCount));
159 Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(1448));
160 Config::SetDefault("ns3::DropTailQueue<Packet>::MaxSize", QueueSizeValue(QueueSize("1p")));
161 Config::SetDefault(queueDisc + "::MaxSize", QueueSizeValue(QueueSize("100p")));
162
163 NodeContainer sender;
164 NodeContainer receiver;
165 NodeContainer routers;
166 sender.Create(1);
167 receiver.Create(1);
168 routers.Create(2);
169
170 // Create the point-to-point link helpers
171 PointToPointHelper bottleneckLink;
172 bottleneckLink.SetDeviceAttribute("DataRate", StringValue("10Mbps"));
173 bottleneckLink.SetChannelAttribute("Delay", StringValue("10ms"));
174
175 PointToPointHelper edgeLink;
176 edgeLink.SetDeviceAttribute("DataRate", StringValue("1000Mbps"));
177 edgeLink.SetChannelAttribute("Delay", StringValue("5ms"));
178
179 // Create NetDevice containers
180 NetDeviceContainer senderEdge = edgeLink.Install(sender.Get(0), routers.Get(0));
181 NetDeviceContainer r1r2 = bottleneckLink.Install(routers.Get(0), routers.Get(1));
182 NetDeviceContainer receiverEdge = edgeLink.Install(routers.Get(1), receiver.Get(0));
183
184 // Install Stack
186 internet.Install(sender);
187 internet.Install(receiver);
188 internet.Install(routers);
189
190 // Configure the root queue discipline
192 tch.SetRootQueueDisc(queueDisc);
193
194 if (bql)
195 {
196 tch.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1000ms"));
197 }
198
199 tch.Install(senderEdge);
200 tch.Install(receiverEdge);
201
202 // Assign IP addresses
204 ipv4.SetBase("10.0.0.0", "255.255.255.0");
205
206 Ipv4InterfaceContainer i1i2 = ipv4.Assign(r1r2);
207
208 ipv4.NewNetwork();
209 Ipv4InterfaceContainer is1 = ipv4.Assign(senderEdge);
210
211 ipv4.NewNetwork();
212 Ipv4InterfaceContainer ir1 = ipv4.Assign(receiverEdge);
213
214 // Populate routing tables
216
217 // Select sender side port
218 uint16_t port = 50001;
219
220 // Install application on the sender
221 BulkSendHelper source("ns3::TcpSocketFactory", InetSocketAddress(ir1.GetAddress(1), port));
222 source.SetAttribute("MaxBytes", UintegerValue(0));
223 ApplicationContainer sourceApps = source.Install(sender.Get(0));
224 sourceApps.Start(Seconds(0.1));
225 // Hook trace source after application starts
227 sourceApps.Stop(stopTime);
228
229 // Install application on the receiver
230 PacketSinkHelper sink("ns3::TcpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), port));
231 ApplicationContainer sinkApps = sink.Install(receiver.Get(0));
232 sinkApps.Start(Seconds(0.0));
233 sinkApps.Stop(stopTime);
234
235 // Create a new directory to store the output of the program
236 dir = "bbr-results/" + currentTime + "/";
238
239 // The plotting scripts are provided in the following repository, if needed:
240 // https://github.com/mohittahiliani/BBR-Validation/
241 //
242 // Download 'PlotScripts' directory (which is inside ns-3 scripts directory)
243 // from the link given above and place it in the ns-3 root directory.
244 // Uncomment the following three lines to copy plot scripts for
245 // Congestion Window, sender side throughput and queue occupancy on the
246 // bottleneck link into the output directory.
247 //
248 // std::filesystem::copy("PlotScripts/gnuplotScriptCwnd", dir);
249 // std::filesystem::copy("PlotScripts/gnuplotScriptThroughput", dir);
250 // std::filesystem::copy("PlotScripts/gnuplotScriptQueueSize", dir);
251
252 // Trace the queue occupancy on the second interface of R1
253 tch.Uninstall(routers.Get(0)->GetDevice(1));
255 qd = tch.Install(routers.Get(0)->GetDevice(1));
257
258 // Generate PCAP traces if it is enabled
259 if (enablePcap)
260 {
261 MakeDirectories(dir + "pcap/");
262 bottleneckLink.EnablePcapAll(dir + "/pcap/bbr", true);
263 }
264
265 // Open files for writing throughput traces and queue size
266 throughput.open(dir + "/throughput.dat", std::ios::out);
267 queueSize.open(dir + "/queueSize.dat", std::ios::out);
268
269 NS_ASSERT_MSG(throughput.is_open(), "Throughput file was not opened correctly");
270 NS_ASSERT_MSG(queueSize.is_open(), "Queue size file was not opened correctly");
271
272 // Check for dropped packets using Flow Monitor
273 FlowMonitorHelper flowmon;
274 Ptr<FlowMonitor> monitor = flowmon.InstallAll();
275 Simulator::Schedule(Seconds(0 + 0.000001), &TraceThroughput, monitor);
276
277 Simulator::Stop(stopTime + TimeStep(1));
280
281 throughput.close();
282 queueSize.close();
283
284 return 0;
285}
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:174
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:231
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:149
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:77
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.
Definition: queue-size.h:221
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
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:403
@ US
microsecond
Definition: nstime.h:118
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
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:894
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition: config.cc:954
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition: callback.h:767
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:305
void MakeDirectories(std::string path)
Create all the directories leading to path.
Definition: system-path.cc:330
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
Namespace for various file and directory path functions.
Definition: system-path.cc:107
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns cmd
Definition: second.py:40
std::ofstream queueSize
Time prevTime
static void CwndTracer(Ptr< OutputStreamWrapper > stream, uint32_t oldval, uint32_t newval)
void TraceCwnd(uint32_t nodeId, uint32_t socketId)
std::ofstream throughput
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