tcp: Add example for BBR
This commit is contained in:
committed by
Tom Henderson
parent
2526c7df94
commit
b9e35ffb02
246
examples/tcp/tcp-bbr-example.cc
Normal file
246
examples/tcp/tcp-bbr-example.cc
Normal file
@@ -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 <aarti.nandagiri@gmail.com>
|
||||
* Vivek Jain <jain.vivek.anand@gmail.com>
|
||||
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
|
||||
*/
|
||||
|
||||
// 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<UniformRandomVariable> uv = CreateObject<UniformRandomVariable> ();
|
||||
double stopTime = 100;
|
||||
|
||||
std::string dir;
|
||||
std::string str;
|
||||
uint32_t prev = 0;
|
||||
double prevtime = 0;
|
||||
|
||||
// Calculate throughput
|
||||
static void
|
||||
TraceThroughput (Ptr<FlowMonitor> 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<QueueDisc> 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<OutputStreamWrapper> 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<OutputStreamWrapper> 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<Packet>::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<FlowMonitor> monitor = flowmon.InstallAll ();
|
||||
Simulator::Schedule (Seconds (0 + 0.000001), &TraceThroughput, monitor);
|
||||
|
||||
Simulator::Stop (Seconds (stopTime));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user