diff --git a/examples/tcp/tcp-bbr-example.cc b/examples/tcp/tcp-bbr-example.cc new file mode 100644 index 000000000..4a78464f6 --- /dev/null +++ b/examples/tcp/tcp-bbr-example.cc @@ -0,0 +1,246 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2018-20 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Aarti Nandagiri + * Vivek Jain + * Mohit P. Tahiliani + */ + +// This program simulates the following topology: +// +// 1000 Mbps 10Mbps 1000 Mbps +// Sender -------------- R1 -------------- R2 -------------- Receiver +// 5ms 10ms 5ms +// +// The link between R1 and R2 is a bottleneck link with 10 Mbps. All other +// links are 1000 Mbps. +// +// This program runs by default for 100 seconds and creates a new directory +// called 'bbr-results' in the ns-3 root directory. The program creates one +// sub-directory in 'bbr-results' directory and three .plotme files. +// +// (1) 'pcap' sub-directory contains six PCAP files: +// * bbr-0-0.pcap for the interface on Sender +// * bbr-1-0.pcap for the interface on Receiver +// * bbr-2-0.pcap for the first interface on R1 +// * bbr-2-1.pcap for the second interface on R1 +// * bbr-3-0.pcap for the first interface on R2 +// * bbr-3-1.pcap for the second interface on R2 +// (2) cwnd.plotme contains congestion window trace for the sender node +// (3) throughput.plotme contains sender side throughput trace +// (4) queueSize.plotme contains queue length trace from the bottleneck link + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/applications-module.h" +#include "ns3/traffic-control-module.h" +#include "ns3/flow-monitor-module.h" + +using namespace ns3; + +Ptr uv = CreateObject (); +double stopTime = 100; + +std::string dir; +std::string str; +uint32_t prev = 0; +double prevtime = 0; + +// Calculate throughput +static void +TraceThroughput (Ptr monitor) +{ + FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats (); + auto itr = stats.begin (); + double curtime = Simulator::Now ().GetSeconds (); + std::ofstream thr (dir + "/throughput.plotme", std::ios::out | std::ios::app); + thr << curtime << " " << 8 * (itr->second.txBytes - prev) / (1000 * 1000 * (curtime - prevtime)) << std::endl; + prevtime = curtime; + prev = itr->second.txBytes; + Simulator::Schedule (Seconds (0.2), &TraceThroughput, monitor); +} + +// Check the queue size +void CheckQueueSize (Ptr qd) +{ + uint32_t qsize = qd->GetCurrentSize ().GetValue (); + Simulator::Schedule (Seconds (0.2), &CheckQueueSize, qd); + std::ofstream q (dir + "/queueSize.plotme", std::ios::out | std::ios::app); + q << Simulator::Now ().GetSeconds () << " " << qsize << std::endl; + q.close (); +} + +// Trace congestion window +static void CwndTracer (Ptr stream, uint32_t oldval, uint32_t newval) +{ + *stream->GetStream () << Simulator::Now ().GetSeconds () << " " << newval / 1448.0 << std::endl; +} + +void TraceCwnd (uint32_t nodeId, uint32_t socketId) +{ + AsciiTraceHelper ascii; + Ptr stream = ascii.CreateFileStream (dir + "/cwnd.plotme"); + Config::ConnectWithoutContext ("/NodeList/" + std::to_string (nodeId) + "/$ns3::TcpL4Protocol/SocketList/" + std::to_string (socketId) + "/CongestionWindow", MakeBoundCallback (&CwndTracer, stream)); +} + +int main (int argc, char *argv []) +{ + // Naming the output directory using local system time + time_t rawtime; + struct tm * timeinfo; + char buffer [80]; + time (&rawtime); + timeinfo = localtime (&rawtime); + strftime (buffer, sizeof (buffer), "%d-%m-%Y-%I-%M-%S", timeinfo); + std::string currentTime (buffer); + + uint32_t stream = 1; + std::string tcpTypeId = "TcpBbr"; + std::string queueDisc = "FifoQueueDisc"; + uint32_t delAckCount = 2; + bool bql = true; + + CommandLine cmd (__FILE__); + cmd.AddValue ("stream", "Seed value for random variable", stream); + cmd.AddValue ("tcpTypeId", "Transport protocol to use: TcpNewReno, TcpBbr", tcpTypeId); + cmd.AddValue ("delAckCount", "Delayed ACK count", delAckCount); + cmd.AddValue ("stopTime", "Stop time for applications / simulation time will be stopTime + 1", stopTime); + cmd.Parse (argc, argv); + + uv->SetStream (stream); + + queueDisc = std::string ("ns3::") + queueDisc; + + Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue ("ns3::" + tcpTypeId)); + Config::SetDefault ("ns3::TcpSocket::SndBufSize", UintegerValue (4194304)); + Config::SetDefault ("ns3::TcpSocket::RcvBufSize", UintegerValue (6291456)); + Config::SetDefault ("ns3::TcpSocket::InitialCwnd", UintegerValue (10)); + Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (delAckCount)); + Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1448)); + Config::SetDefault ("ns3::DropTailQueue::MaxSize", QueueSizeValue (QueueSize ("1p"))); + Config::SetDefault (queueDisc + "::MaxSize", QueueSizeValue (QueueSize ("100p"))); + + NodeContainer sender, receiver; + NodeContainer routers; + sender.Create (1); + receiver.Create (1); + routers.Create (2); + + // Create the point-to-point link helpers + PointToPointHelper bottleneckLink; + bottleneckLink.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + bottleneckLink.SetChannelAttribute ("Delay", StringValue ("10ms")); + + PointToPointHelper edgeLink; + edgeLink.SetDeviceAttribute ("DataRate", StringValue ("1000Mbps")); + edgeLink.SetChannelAttribute ("Delay", StringValue ("5ms")); + + // Create NetDevice containers + NetDeviceContainer senderEdge = edgeLink.Install (sender.Get (0), routers.Get (0)); + NetDeviceContainer r1r2 = bottleneckLink.Install (routers.Get (0), routers.Get (1)); + NetDeviceContainer receiverEdge = edgeLink.Install (routers.Get (1), receiver.Get (0)); + + // Install Stack + InternetStackHelper internet; + internet.Install (sender); + internet.Install (receiver); + internet.Install (routers); + + // Configure the root queue discipline + TrafficControlHelper tch; + tch.SetRootQueueDisc (queueDisc); + + if (bql) + { + tch.SetQueueLimits ("ns3::DynamicQueueLimits", "HoldTime", StringValue ("1000ms")); + } + + tch.Install (senderEdge); + tch.Install (receiverEdge); + + // Assign IP addresses + Ipv4AddressHelper ipv4; + ipv4.SetBase ("10.0.0.0", "255.255.255.0"); + + Ipv4InterfaceContainer i1i2 = ipv4.Assign (r1r2); + + ipv4.NewNetwork (); + Ipv4InterfaceContainer is1 = ipv4.Assign (senderEdge); + + ipv4.NewNetwork (); + Ipv4InterfaceContainer ir1 = ipv4.Assign (receiverEdge); + + // Populate routing tables + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + + // Select sender side port + uint16_t port = 50001; + + // Install application on the sender + BulkSendHelper source ("ns3::TcpSocketFactory", InetSocketAddress (ir1.GetAddress (1), port)); + source.SetAttribute ("MaxBytes", UintegerValue (0)); + ApplicationContainer sourceApps = source.Install (sender.Get (0)); + sourceApps.Start (Seconds (0.0)); + Simulator::Schedule (Seconds (0.2), &TraceCwnd, 0, 0); + sourceApps.Stop (Seconds (stopTime)); + + // Install application on the receiver + PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port)); + ApplicationContainer sinkApps = sink.Install (receiver.Get (0)); + sinkApps.Start (Seconds (0.0)); + sinkApps.Stop (Seconds (stopTime)); + + // Create a new directory to store the output of the program + dir = "bbr-results/" + currentTime + "/"; + std::string dirToSave = "mkdir -p " + dir; + system (dirToSave.c_str ()); + system ((dirToSave + "/pcap/").c_str ()); + + // The plotting scripts are provided in the following repository, if needed: + // https://github.com/mohittahiliani/BBR-Validation/ + // + // Download 'PlotScripts' directory (which is inside ns-3 scripts directory) + // from the link given above and place it in the ns-3 root directory. + // Uncomment the following three lines to generate plots for Congestion + // Window, sender side throughput and queue occupancy on the bottleneck link. + // + // system (("cp -R PlotScripts/gnuplotScriptCwnd " + dir).c_str ()); + // system (("cp -R PlotScripts/gnuplotScriptThroughput " + dir).c_str ()); + // system (("cp -R PlotScripts/gnuplotScriptQueueSize " + dir).c_str ()); + + // Trace the queue occupancy on the second interface of R1 + tch.Uninstall (routers.Get (0)->GetDevice (1)); + QueueDiscContainer qd; + qd = tch.Install (routers.Get (0)->GetDevice (1)); + Simulator::ScheduleNow (&CheckQueueSize, qd.Get (0)); + + // Enable PCAP traces + bottleneckLink.EnablePcapAll (dir + "/pcap/bbr", true); + + // Check for dropped packets using Flow Monitor + FlowMonitorHelper flowmon; + Ptr monitor = flowmon.InstallAll (); + Simulator::Schedule (Seconds (0 + 0.000001), &TraceThroughput, monitor); + + Simulator::Stop (Seconds (stopTime)); + Simulator::Run (); + Simulator::Destroy (); + + return 0; +} diff --git a/examples/tcp/wscript b/examples/tcp/wscript index bfc212f13..efaebec41 100644 --- a/examples/tcp/wscript +++ b/examples/tcp/wscript @@ -57,3 +57,8 @@ def build(bld): ['point-to-point', 'internet', 'applications', 'traffic-control', 'network', 'internet-apps']) obj.source = 'tcp-validation.cc' + + obj = bld.create_ns3_program('tcp-bbr-example', + ['point-to-point', 'internet', 'applications', 'traffic-control', 'network', 'internet-apps', 'flow-monitor']) + + obj.source = 'tcp-bbr-example.cc'