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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Aarti Nandagiri <aarti.nandagiri@gmail.com>
7 * Vivek Jain <jain.vivek.anand@gmail.com>
8 * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
9 */
10
11// This program simulates the following topology:
12//
13// 1000 Mbps 10Mbps 1000 Mbps
14// Sender -------------- R1 -------------- R2 -------------- Receiver
15// 5ms 10ms 5ms
16//
17// The link between R1 and R2 is a bottleneck link with 10 Mbps. All other
18// links are 1000 Mbps.
19//
20// This program runs by default for 100 seconds and creates a new directory
21// called 'bbr-results' in the ns-3 root directory. The program creates one
22// sub-directory called 'pcap' in 'bbr-results' directory (if pcap generation
23// is enabled) and three .dat files.
24//
25// (1) 'pcap' sub-directory contains six PCAP files:
26// * bbr-0-0.pcap for the interface on Sender
27// * bbr-1-0.pcap for the interface on Receiver
28// * bbr-2-0.pcap for the first interface on R1
29// * bbr-2-1.pcap for the second interface on R1
30// * bbr-3-0.pcap for the first interface on R2
31// * bbr-3-1.pcap for the second interface on R2
32// (2) cwnd.dat file contains congestion window trace for the sender node
33// (3) throughput.dat file contains sender side throughput trace (throughput is in Mbit/s)
34// (4) queueSize.dat file contains queue length trace from the bottleneck link
35//
36// BBR algorithm enters PROBE_RTT phase in every 10 seconds. The congestion
37// window is fixed to 4 segments in this phase with a goal to achieve a better
38// estimate of minimum RTT (because queue at the bottleneck link tends to drain
39// when the congestion window is reduced to 4 segments).
40//
41// The congestion window and queue occupancy traces output by this program show
42// periodic drops every 10 seconds when BBR algorithm is in PROBE_RTT phase.
43
44#include "ns3/applications-module.h"
45#include "ns3/core-module.h"
46#include "ns3/flow-monitor-module.h"
47#include "ns3/internet-module.h"
48#include "ns3/network-module.h"
49#include "ns3/point-to-point-module.h"
50#include "ns3/traffic-control-module.h"
51
52#include <filesystem>
53
54using namespace ns3;
55using namespace ns3::SystemPath;
56
57std::string dir;
58std::ofstream throughput;
59std::ofstream queueSize;
60
63
64// Calculate throughput
65static void
67{
68 FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats();
69 if (!stats.empty())
70 {
71 auto itr = stats.begin();
72 Time curTime = Now();
73
74 // Convert (curTime - prevTime) to microseconds so that throughput is in bits per
75 // microsecond (which is equivalent to Mbps)
76 throughput << curTime.GetSeconds() << "s "
77 << 8 * (itr->second.txBytes - prev) / ((curTime - prevTime).ToDouble(Time::US))
78 << " Mbps" << std::endl;
79 prevTime = curTime;
80 prev = itr->second.txBytes;
81 }
83}
84
85// Check the queue size
86void
88{
89 uint32_t qsize = qd->GetCurrentSize().GetValue();
91 queueSize << Simulator::Now().GetSeconds() << " " << qsize << std::endl;
92}
93
94// Trace congestion window
95static void
97{
98 *stream->GetStream() << Simulator::Now().GetSeconds() << " " << newval / 1448.0 << std::endl;
99}
100
101void
102TraceCwnd(uint32_t nodeId, uint32_t socketId)
103{
104 AsciiTraceHelper ascii;
105 Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream(dir + "/cwnd.dat");
106 Config::ConnectWithoutContext("/NodeList/" + std::to_string(nodeId) +
107 "/$ns3::TcpL4Protocol/SocketList/" +
108 std::to_string(socketId) + "/CongestionWindow",
109 MakeBoundCallback(&CwndTracer, stream));
110}
111
112int
113main(int argc, char* argv[])
114{
115 // Naming the output directory using local system time
116 time_t rawtime;
117 struct tm* timeinfo;
118 char buffer[80];
119 time(&rawtime);
120 timeinfo = localtime(&rawtime);
121 strftime(buffer, sizeof(buffer), "%d-%m-%Y-%I-%M-%S", timeinfo);
122 std::string currentTime(buffer);
123
124 std::string tcpTypeId = "TcpBbr";
125 std::string queueDisc = "FifoQueueDisc";
126 uint32_t delAckCount = 2;
127 bool bql = true;
128 bool enablePcap = false;
129 Time stopTime = Seconds(100);
130
131 CommandLine cmd(__FILE__);
132 cmd.AddValue("tcpTypeId", "Transport protocol to use: TcpNewReno, TcpBbr", tcpTypeId);
133 cmd.AddValue("delAckCount", "Delayed ACK count", delAckCount);
134 cmd.AddValue("enablePcap", "Enable/Disable pcap file generation", enablePcap);
135 cmd.AddValue("stopTime",
136 "Stop time for applications / simulation time will be stopTime + 1",
137 stopTime);
138 cmd.Parse(argc, argv);
139
140 queueDisc = std::string("ns3::") + queueDisc;
141
142 Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::" + tcpTypeId));
143
144 // The maximum send buffer size is set to 4194304 bytes (4MB) and the
145 // maximum receive buffer size is set to 6291456 bytes (6MB) in the Linux
146 // kernel. The same buffer sizes are used as default in this example.
147 Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(4194304));
148 Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(6291456));
149 Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10));
150 Config::SetDefault("ns3::TcpSocket::DelAckCount", UintegerValue(delAckCount));
151 Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(1448));
152 Config::SetDefault("ns3::DropTailQueue<Packet>::MaxSize", QueueSizeValue(QueueSize("1p")));
153 Config::SetDefault(queueDisc + "::MaxSize", QueueSizeValue(QueueSize("100p")));
154
155 NodeContainer sender;
156 NodeContainer receiver;
157 NodeContainer routers;
158 sender.Create(1);
159 receiver.Create(1);
160 routers.Create(2);
161
162 // Create the point-to-point link helpers
163 PointToPointHelper bottleneckLink;
164 bottleneckLink.SetDeviceAttribute("DataRate", StringValue("10Mbps"));
165 bottleneckLink.SetChannelAttribute("Delay", StringValue("10ms"));
166
167 PointToPointHelper edgeLink;
168 edgeLink.SetDeviceAttribute("DataRate", StringValue("1000Mbps"));
169 edgeLink.SetChannelAttribute("Delay", StringValue("5ms"));
170
171 // Create NetDevice containers
172 NetDeviceContainer senderEdge = edgeLink.Install(sender.Get(0), routers.Get(0));
173 NetDeviceContainer r1r2 = bottleneckLink.Install(routers.Get(0), routers.Get(1));
174 NetDeviceContainer receiverEdge = edgeLink.Install(routers.Get(1), receiver.Get(0));
175
176 // Install Stack
178 internet.Install(sender);
179 internet.Install(receiver);
180 internet.Install(routers);
181
182 // Configure the root queue discipline
184 tch.SetRootQueueDisc(queueDisc);
185
186 if (bql)
187 {
188 tch.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1000ms"));
189 }
190
191 tch.Install(senderEdge);
192 tch.Install(receiverEdge);
193
194 // Assign IP addresses
196 ipv4.SetBase("10.0.0.0", "255.255.255.0");
197
198 Ipv4InterfaceContainer i1i2 = ipv4.Assign(r1r2);
199
200 ipv4.NewNetwork();
201 Ipv4InterfaceContainer is1 = ipv4.Assign(senderEdge);
202
203 ipv4.NewNetwork();
204 Ipv4InterfaceContainer ir1 = ipv4.Assign(receiverEdge);
205
206 // Populate routing tables
208
209 // Select sender side port
210 uint16_t port = 50001;
211
212 // Install application on the sender
213 BulkSendHelper source("ns3::TcpSocketFactory", InetSocketAddress(ir1.GetAddress(1), port));
214 source.SetAttribute("MaxBytes", UintegerValue(0));
215 ApplicationContainer sourceApps = source.Install(sender.Get(0));
216 sourceApps.Start(Seconds(0.1));
217 // Hook trace source after application starts
219 sourceApps.Stop(stopTime);
220
221 // Install application on the receiver
222 PacketSinkHelper sink("ns3::TcpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), port));
223 ApplicationContainer sinkApps = sink.Install(receiver.Get(0));
224 sinkApps.Start(Seconds(0.0));
225 sinkApps.Stop(stopTime);
226
227 // Create a new directory to store the output of the program
228 dir = "bbr-results/" + currentTime + "/";
230
231 // The plotting scripts are provided in the following repository, if needed:
232 // https://github.com/mohittahiliani/BBR-Validation/
233 //
234 // Download 'PlotScripts' directory (which is inside ns-3 scripts directory)
235 // from the link given above and place it in the ns-3 root directory.
236 // Uncomment the following three lines to copy plot scripts for
237 // Congestion Window, sender side throughput and queue occupancy on the
238 // bottleneck link into the output directory.
239 //
240 // std::filesystem::copy("PlotScripts/gnuplotScriptCwnd", dir);
241 // std::filesystem::copy("PlotScripts/gnuplotScriptThroughput", dir);
242 // std::filesystem::copy("PlotScripts/gnuplotScriptQueueSize", dir);
243
244 // Trace the queue occupancy on the second interface of R1
245 tch.Uninstall(routers.Get(0)->GetDevice(1));
247 qd = tch.Install(routers.Get(0)->GetDevice(1));
249
250 // Generate PCAP traces if it is enabled
251 if (enablePcap)
252 {
253 MakeDirectories(dir + "pcap/");
254 bottleneckLink.EnablePcapAll(dir + "/pcap/bbr", true);
255 }
256
257 // Open files for writing throughput traces and queue size
258 throughput.open(dir + "/throughput.dat", std::ios::out);
259 queueSize.open(dir + "/queueSize.dat", std::ios::out);
260
261 NS_ASSERT_MSG(throughput.is_open(), "Throughput file was not opened correctly");
262 NS_ASSERT_MSG(queueSize.is_open(), "Queue size file was not opened correctly");
263
264 // Check for dropped packets using Flow Monitor
265 FlowMonitorHelper flowmon;
266 Ptr<FlowMonitor> monitor = flowmon.InstallAll();
267 Simulator::Schedule(Seconds(0 + 0.000001), &TraceThroughput, monitor);
268
269 Simulator::Stop(stopTime + TimeStep(1));
272
273 throughput.close();
274 queueSize.close();
275
276 return 0;
277}
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.
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.
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.
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:138
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.
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:85
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:594
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Hold variables of type string.
Definition string.h:45
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
@ US
microsecond
Definition nstime.h:107
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:34
uint16_t port
Definition dsdv-manet.cc:33
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:75
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition config.cc:943
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition callback.h:745
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition simulator.cc:294
void MakeDirectories(std::string path)
Create all the directories leading to path.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
Namespace for various file and directory path functions.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:44