/*
* Copyright (c) 2015 Universita' degli Studi di Napoli Federico II
*
* 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: Pasquale Imputato
* Stefano Avallone
*/
// This example serves as a benchmark for all the queue discs (with BQL enabled or not)
//
// Network topology
//
// 192.168.1.0 192.168.2.0
// n1 ------------------------------------ n2 ----------------------------------- n3
// point-to-point (access link) point-to-point (bottleneck link)
// 100 Mbps, 0.1 ms bandwidth [10 Mbps], delay [5 ms]
// qdiscs PfifoFast with capacity qdiscs queueDiscType in {PfifoFast, ARED, CoDel,
// FqCoDel, PIE} [PfifoFast] of 1000 packets with capacity of
// queueDiscSize packets [1000] netdevices queues with size of 100 packets netdevices queues with
// size of netdevicesQueueSize packets [100] without BQL bql BQL
// [false]
// *** fixed configuration ***
//
// Two TCP flows are generated: one from n1 to n3 and the other from n3 to n1.
// Additionally, n1 pings n3, so that the RTT can be measured.
//
// The output will consist of a number of ping Rtt such as:
//
// /NodeList/0/ApplicationList/2/$ns3::V4Ping/Rtt=111 ms
// /NodeList/0/ApplicationList/2/$ns3::V4Ping/Rtt=111 ms
// /NodeList/0/ApplicationList/2/$ns3::V4Ping/Rtt=110 ms
// /NodeList/0/ApplicationList/2/$ns3::V4Ping/Rtt=111 ms
// /NodeList/0/ApplicationList/2/$ns3::V4Ping/Rtt=111 ms
// /NodeList/0/ApplicationList/2/$ns3::V4Ping/Rtt=112 ms
// /NodeList/0/ApplicationList/2/$ns3::V4Ping/Rtt=111 ms
//
// The files output will consist of a trace file with bytes in queue and of a trace file for limits
// (when BQL is enabled) both for bottleneck NetDevice on n2, two files with upload and download
// goodput for flows configuration and a file with flow monitor stats.
//
// If you use an AQM as queue disc on the bottleneck netdevices, you can observe that the ping Rtt
// decrease. A further decrease can be observed when you enable BQL.
#include "ns3/applications-module.h"
#include "ns3/core-module.h"
#include "ns3/flow-monitor-module.h"
#include "ns3/internet-apps-module.h"
#include "ns3/internet-module.h"
#include "ns3/network-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/traffic-control-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("BenchmarkQueueDiscs");
/**
* Print the queue limitis.
*
* \param stream The ouput stream.
* \param oldVal Old value.
* \param newVal New value.
*/
void
LimitsTrace(Ptr stream, uint32_t oldVal, uint32_t newVal)
{
*stream->GetStream() << Simulator::Now().GetSeconds() << " " << newVal << std::endl;
}
/**
* Print the bytes in the queue.
*
* \param stream The ouput stream.
* \param oldVal Old value.
* \param newVal New value.
*/
void
BytesInQueueTrace(Ptr stream, uint32_t oldVal, uint32_t newVal)
{
*stream->GetStream() << Simulator::Now().GetSeconds() << " " << newVal << std::endl;
}
/**
* Sample and print the queue goodput.
*
* \param app The Tx app.
* \param stream The ouput stream.
* \param period The sampling period.
*/
static void
GoodputSampling(ApplicationContainer app, Ptr stream, float period)
{
Simulator::Schedule(Seconds(period), &GoodputSampling, app, stream, period);
double goodput;
uint64_t totalPackets = DynamicCast(app.Get(0))->GetTotalRx();
goodput = totalPackets * 8 / (Simulator::Now().GetSeconds() * 1024); // Kbit/s
*stream->GetStream() << Simulator::Now().GetSeconds() << " " << goodput << std::endl;
}
/**
* Print the ping RTT.
*
* \param context The context.
* \param rtt The RTT.
*/
static void
PingRtt(std::string context, Time rtt)
{
std::cout << context << "=" << rtt.GetMilliSeconds() << " ms" << std::endl;
}
int
main(int argc, char* argv[])
{
std::string bandwidth = "10Mbps";
std::string delay = "5ms";
std::string queueDiscType = "PfifoFast";
uint32_t queueDiscSize = 1000;
uint32_t netdevicesQueueSize = 50;
bool bql = false;
std::string flowsDatarate = "20Mbps";
uint32_t flowsPacketsSize = 1000;
float startTime = 0.1F; // in s
float simDuration = 60;
float samplingPeriod = 1;
CommandLine cmd(__FILE__);
cmd.AddValue("bandwidth", "Bottleneck bandwidth", bandwidth);
cmd.AddValue("delay", "Bottleneck delay", delay);
cmd.AddValue("queueDiscType",
"Bottleneck queue disc type in {PfifoFast, ARED, CoDel, FqCoDel, PIE, prio}",
queueDiscType);
cmd.AddValue("queueDiscSize", "Bottleneck queue disc size in packets", queueDiscSize);
cmd.AddValue("netdevicesQueueSize",
"Bottleneck netdevices queue size in packets",
netdevicesQueueSize);
cmd.AddValue("bql", "Enable byte queue limits on bottleneck netdevices", bql);
cmd.AddValue("flowsDatarate", "Upload and download flows datarate", flowsDatarate);
cmd.AddValue("flowsPacketsSize", "Upload and download flows packets sizes", flowsPacketsSize);
cmd.AddValue("startTime", "Simulation start time", startTime);
cmd.AddValue("simDuration", "Simulation duration in seconds", simDuration);
cmd.AddValue("samplingPeriod", "Goodput sampling period in seconds", samplingPeriod);
cmd.Parse(argc, argv);
float stopTime = startTime + simDuration;
// Create nodes
NodeContainer n1;
NodeContainer n2;
NodeContainer n3;
n1.Create(1);
n2.Create(1);
n3.Create(1);
// Create and configure access link and bottleneck link
PointToPointHelper accessLink;
accessLink.SetDeviceAttribute("DataRate", StringValue("100Mbps"));
accessLink.SetChannelAttribute("Delay", StringValue("0.1ms"));
accessLink.SetQueue("ns3::DropTailQueue", "MaxSize", StringValue("100p"));
PointToPointHelper bottleneckLink;
bottleneckLink.SetDeviceAttribute("DataRate", StringValue(bandwidth));
bottleneckLink.SetChannelAttribute("Delay", StringValue(delay));
bottleneckLink.SetQueue("ns3::DropTailQueue",
"MaxSize",
StringValue(std::to_string(netdevicesQueueSize) + "p"));
InternetStackHelper stack;
stack.InstallAll();
// Access link traffic control configuration
TrafficControlHelper tchPfifoFastAccess;
tchPfifoFastAccess.SetRootQueueDisc("ns3::PfifoFastQueueDisc", "MaxSize", StringValue("1000p"));
// Bottleneck link traffic control configuration
TrafficControlHelper tchBottleneck;
if (queueDiscType == "PfifoFast")
{
tchBottleneck.SetRootQueueDisc(
"ns3::PfifoFastQueueDisc",
"MaxSize",
QueueSizeValue(QueueSize(QueueSizeUnit::PACKETS, queueDiscSize)));
}
else if (queueDiscType == "ARED")
{
tchBottleneck.SetRootQueueDisc("ns3::RedQueueDisc");
Config::SetDefault("ns3::RedQueueDisc::ARED", BooleanValue(true));
Config::SetDefault("ns3::RedQueueDisc::MaxSize",
QueueSizeValue(QueueSize(QueueSizeUnit::PACKETS, queueDiscSize)));
}
else if (queueDiscType == "CoDel")
{
tchBottleneck.SetRootQueueDisc("ns3::CoDelQueueDisc");
Config::SetDefault("ns3::CoDelQueueDisc::MaxSize",
QueueSizeValue(QueueSize(QueueSizeUnit::PACKETS, queueDiscSize)));
}
else if (queueDiscType == "FqCoDel")
{
tchBottleneck.SetRootQueueDisc("ns3::FqCoDelQueueDisc");
Config::SetDefault("ns3::FqCoDelQueueDisc::MaxSize",
QueueSizeValue(QueueSize(QueueSizeUnit::PACKETS, queueDiscSize)));
}
else if (queueDiscType == "PIE")
{
tchBottleneck.SetRootQueueDisc("ns3::PieQueueDisc");
Config::SetDefault("ns3::PieQueueDisc::MaxSize",
QueueSizeValue(QueueSize(QueueSizeUnit::PACKETS, queueDiscSize)));
}
else if (queueDiscType == "prio")
{
uint16_t handle =
tchBottleneck.SetRootQueueDisc("ns3::PrioQueueDisc",
"Priomap",
StringValue("0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1"));
TrafficControlHelper::ClassIdList cid =
tchBottleneck.AddQueueDiscClasses(handle, 2, "ns3::QueueDiscClass");
tchBottleneck.AddChildQueueDisc(handle, cid[0], "ns3::FifoQueueDisc");
tchBottleneck.AddChildQueueDisc(handle, cid[1], "ns3::RedQueueDisc");
}
else
{
NS_ABORT_MSG("--queueDiscType not valid");
}
if (bql)
{
tchBottleneck.SetQueueLimits("ns3::DynamicQueueLimits");
}
NetDeviceContainer devicesAccessLink = accessLink.Install(n1.Get(0), n2.Get(0));
tchPfifoFastAccess.Install(devicesAccessLink);
Ipv4AddressHelper address;
address.SetBase("192.168.0.0", "255.255.255.0");
address.NewNetwork();
Ipv4InterfaceContainer interfacesAccess = address.Assign(devicesAccessLink);
NetDeviceContainer devicesBottleneckLink = bottleneckLink.Install(n2.Get(0), n3.Get(0));
QueueDiscContainer qdiscs;
qdiscs = tchBottleneck.Install(devicesBottleneckLink);
address.NewNetwork();
Ipv4InterfaceContainer interfacesBottleneck = address.Assign(devicesBottleneckLink);
Ptr interface =
devicesBottleneckLink.Get(0)->GetObject();
Ptr queueInterface = interface->GetTxQueue(0);
Ptr queueLimits =
StaticCast(queueInterface->GetQueueLimits());
AsciiTraceHelper ascii;
if (bql)
{
queueDiscType = queueDiscType + "-bql";
Ptr streamLimits =
ascii.CreateFileStream(queueDiscType + "-limits.txt");
queueLimits->TraceConnectWithoutContext("Limit",
MakeBoundCallback(&LimitsTrace, streamLimits));
}
Ptr> queue =
StaticCast(devicesBottleneckLink.Get(0))->GetQueue();
Ptr streamBytesInQueue =
ascii.CreateFileStream(queueDiscType + "-bytesInQueue.txt");
queue->TraceConnectWithoutContext("BytesInQueue",
MakeBoundCallback(&BytesInQueueTrace, streamBytesInQueue));
Ipv4InterfaceContainer n1Interface;
n1Interface.Add(interfacesAccess.Get(0));
Ipv4InterfaceContainer n3Interface;
n3Interface.Add(interfacesBottleneck.Get(1));
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(flowsPacketsSize));
// Flows configuration
// Bidirectional TCP streams with ping like flent tcp_bidirectional test.
uint16_t port = 7;
ApplicationContainer uploadApp;
ApplicationContainer downloadApp;
ApplicationContainer sourceApps;
// Configure and install upload flow
Address addUp(InetSocketAddress(Ipv4Address::GetAny(), port));
PacketSinkHelper sinkHelperUp("ns3::TcpSocketFactory", addUp);
sinkHelperUp.SetAttribute("Protocol", TypeIdValue(TcpSocketFactory::GetTypeId()));
uploadApp.Add(sinkHelperUp.Install(n3));
InetSocketAddress socketAddressUp = InetSocketAddress(n3Interface.GetAddress(0), port);
OnOffHelper onOffHelperUp("ns3::TcpSocketFactory", Address());
onOffHelperUp.SetAttribute("Remote", AddressValue(socketAddressUp));
onOffHelperUp.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
onOffHelperUp.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
onOffHelperUp.SetAttribute("PacketSize", UintegerValue(flowsPacketsSize));
onOffHelperUp.SetAttribute("DataRate", StringValue(flowsDatarate));
sourceApps.Add(onOffHelperUp.Install(n1));
port = 8;
// Configure and install download flow
Address addDown(InetSocketAddress(Ipv4Address::GetAny(), port));
PacketSinkHelper sinkHelperDown("ns3::TcpSocketFactory", addDown);
sinkHelperDown.SetAttribute("Protocol", TypeIdValue(TcpSocketFactory::GetTypeId()));
downloadApp.Add(sinkHelperDown.Install(n1));
InetSocketAddress socketAddressDown = InetSocketAddress(n1Interface.GetAddress(0), port);
OnOffHelper onOffHelperDown("ns3::TcpSocketFactory", Address());
onOffHelperDown.SetAttribute("Remote", AddressValue(socketAddressDown));
onOffHelperDown.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
onOffHelperDown.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
onOffHelperDown.SetAttribute("PacketSize", UintegerValue(flowsPacketsSize));
onOffHelperDown.SetAttribute("DataRate", StringValue(flowsDatarate));
sourceApps.Add(onOffHelperDown.Install(n3));
// Configure and install ping
V4PingHelper ping = V4PingHelper(n3Interface.GetAddress(0));
ping.Install(n1);
Config::Connect("/NodeList/*/ApplicationList/*/$ns3::V4Ping/Rtt", MakeCallback(&PingRtt));
uploadApp.Start(Seconds(0));
uploadApp.Stop(Seconds(stopTime));
downloadApp.Start(Seconds(0));
downloadApp.Stop(Seconds(stopTime));
sourceApps.Start(Seconds(0 + 0.1));
sourceApps.Stop(Seconds(stopTime - 0.1));
Ptr uploadGoodputStream =
ascii.CreateFileStream(queueDiscType + "-upGoodput.txt");
Simulator::Schedule(Seconds(samplingPeriod),
&GoodputSampling,
uploadApp,
uploadGoodputStream,
samplingPeriod);
Ptr downloadGoodputStream =
ascii.CreateFileStream(queueDiscType + "-downGoodput.txt");
Simulator::Schedule(Seconds(samplingPeriod),
&GoodputSampling,
downloadApp,
downloadGoodputStream,
samplingPeriod);
// Flow monitor
Ptr flowMonitor;
FlowMonitorHelper flowHelper;
flowMonitor = flowHelper.InstallAll();
Simulator::Stop(Seconds(stopTime));
Simulator::Run();
flowMonitor->SerializeToXmlFile(queueDiscType + "-flowMonitor.xml", true, true);
Simulator::Destroy();
return 0;
}