//
// 100Mb/s, 20ms 10Mb/s, 5ms
// n0-----------------------n1-------------------------n2
PointToPointHelper leftlink;
leftlink.SetDeviceAttribute ("DataRate", StringValue ("100Mbps"));
leftlink.SetChannelAttribute ("Delay", StringValue ("20ms"));
PointToPointHelper rightlink;
rightlink.SetDeviceAttribute ("DataRate", StringValue ("10Mbps"));
rightlink.SetChannelAttribute ("Delay", StringValue ("5ms"));
for (int port=10; port < 10+tcpflows; port++){
//sink application
PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port));
ApplicationContainer sinkApps = sink.Install (n1n2.Get (1));
sinkApps.Start (Seconds (1.0));
sinkApps.Stop (Seconds (20.0));
//source(s) application
ApplicationContainer sourceApps;
//loop for creating multiple applications (flows) from source
BulkSendHelper sources("ns3::TcpSocketFactory", InetSocketAddress (interface12.GetAddress (1), port));
//Set the amount of data to send in bytes. Zero is unlimited.
sources.SetAttribute ("SendSize", UintegerValue (tcp_app_data_unit_size));
sources.SetAttribute ("MaxBytes", UintegerValue (maxBytes));
sourceApps = sources.Install (n0n1.Get (0));
int start = 0.0+(port - 9);
sourceApps.Start (Seconds (start));
sourceApps.Stop (Seconds (20.0));
}
total_throughput = 0;
for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin (); i != stats.end (); ++i){
Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow (i->first);
if ((t.sourceAddress=="10.1.1.1" && t.destinationAddress == "10.1.2.2")){
double flow_throughput = (i->second.rxBytes * 8.0) / (i->second.timeLastRxPacket.GetSeconds() - i->second.timeFirstTxPacket.GetSeconds());
flow_throughput /= 1024;
flow_throughput /= 1024;
total_throughput += flow_throughput;
std::cout << "Flow " << i->first << " (" << t.sourceAddress << " -> " << t.destinationAddress << ")\n";
std::cout << " Tx Bytes: " << i->second.txBytes << "\n";
std::cout << " Rx Bytes: " << i->second.rxBytes << "\n";
std::cout << " Throughput: " << flow_throughput << " Mbps\n";
}
}
//
// Network topology
//
// 100Mb/s, 20ms 10Mb/s, 5ms
// n0-----------------n1-----------------n2
//
//
// - Tracing of queues and packet receptions to file
// flow monitor used for the links between n0 and n2
// - pcap traces also generated in the following files
// "bottleneckrouter-$n-$i.pcap" where n and i represent node and interface
// numbers respectively
// Usage (e.g.): ./waf --run path-to-containing-folder/bottleneckrouter
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip> // std::setw
#include "ns3/netanim-module.h"
#include "ns3/core-module.h"
#include "ns3/applications-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/ipv4-global-routing-helper.h"
#include "ns3/flow-monitor-helper.h"
#include "ns3/error-model.h"
#include "ns3/netanim-module.h"
#include "ns3/queue.h"
#include "ns3/rng-seed-manager.h"
#include "ns3/ipv4-flow-classifier.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("bottleneckrouter");
///////////// variables /////////////////
int tcpflows = 1; //number of tcp flows default = 1
int maxBytes = 0; //setting up max number of bytes to send default = 0, 0 is unlimited
double lossp = 0.01; //loss probability default = 0.01 - 1%
int queue_size = 1000; // Queue size at node 1 (router) default 1000 packets
int seed = 1; // Seed number for random number generator default = 1
int tcp_app_data_unit_size = 1460;
int main(int argc, char *argv[]){
////////// logging and command line arguments //////////
//enable logging module
LogComponentEnable("bottleneckrouter", LOG_LEVEL_LOGIC);
//enable commandline argument passing
CommandLine cmd;
cmd.AddValue ("tcpflows", "number of tcp flows", tcpflows);
cmd.AddValue ("lossp", "loss probability between 0.0 and 1.0", lossp);
cmd.AddValue ("seed", "seed number for random number generator", seed);
cmd.AddValue ("queue", "queue size of the node in between", queue_size);
cmd.Parse (argc, argv);
////////////// global configurations /////////////////////
//setting up seed number for random number generator
Config::SetGlobal ("RngSeed", IntegerValue(seed));
//setting up tcp configurations
Config::SetDefault ("ns3::TcpL4Protocol::SocketType", TypeIdValue (TcpNewReno::GetTypeId ()));
Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1500));
////////////// creating topology ///////////////
//creating 2 node containers one for left side one for right side
NodeContainer n0n1;
n0n1.Create(2);
NodeContainer n1n2;
n1n2.Add(n0n1.Get(1));
n1n2.Create(1);
//setting up error model for simulating loss rate
Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable> ();
uv->SetStream (100);
RateErrorModel error_model;
error_model.SetRandomVariable (uv);
error_model.SetUnit (RateErrorModel::ERROR_UNIT_PACKET);
error_model.SetRate (lossp); //error rate
//defining the 2 point to point links between the nodes
PointToPointHelper leftlink;
leftlink.SetDeviceAttribute ("DataRate", StringValue ("100Mbps"));
leftlink.SetChannelAttribute ("Delay", StringValue ("20ms"));
PointToPointHelper rightlink;
rightlink.SetDeviceAttribute ("DataRate", StringValue ("10Mbps"));
rightlink.SetChannelAttribute ("Delay", StringValue ("5ms"));
rightlink.SetDeviceAttribute ("ReceiveErrorModel", PointerValue(&error_model)); //assigning the error model to the link
//installing devices for nodes 0, 1
NetDeviceContainer devices01;
devices01 = leftlink.Install(n0n1);
//installing devices for nodes 1, 2
NetDeviceContainer devices12;
devices12 = rightlink.Install(n1n2);
//setting up queue sizes for nodes
//std::cout<<queue_size<<"\n";
Ptr<DropTailQueue> queue = DynamicCast<DropTailQueue> (DynamicCast<PointToPointNetDevice> (devices01.Get (1))->GetQueue ()); //middle node
queue -> SetAttribute("MaxPackets", UintegerValue(1000));
DynamicCast<PointToPointNetDevice> (devices01.Get (1))->SetQueue (queue);
Ptr<DropTailQueue> endqueue = DynamicCast<DropTailQueue> (DynamicCast<PointToPointNetDevice> (devices12.Get (0))->GetQueue ()); //middle right side node
endqueue -> SetAttribute("MaxPackets", UintegerValue(queue_size));
DynamicCast<PointToPointNetDevice> (devices12.Get (0))->SetQueue (endqueue);
// installing IP stack
InternetStackHelper stack;
stack.InstallAll();
//defining addresses
Ipv4AddressHelper address;
//defining address for nodes 0, 1
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interface01 = address.Assign(devices01);
//defining addresses for nodes 1, 2
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer interface12 = address.Assign(devices12);
//applying global routing
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
////////////////// creating application //////////////////////
for (int port=10; port < 10+tcpflows; port++){
//sink application
PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port));
ApplicationContainer sinkApps = sink.Install (n1n2.Get (1));
sinkApps.Start (Seconds (1.0));
sinkApps.Stop (Seconds (20.0));
//source(s) application
ApplicationContainer sourceApps;
//loop for creating multiple applications (flows) from source
BulkSendHelper sources("ns3::TcpSocketFactory", InetSocketAddress (interface12.GetAddress (1), port));
//Set the amount of data to send in bytes. Zero is unlimited.
sources.SetAttribute ("SendSize", UintegerValue (tcp_app_data_unit_size));
sources.SetAttribute ("MaxBytes", UintegerValue (maxBytes));
sourceApps = sources.Install (n0n1.Get (0));
int start = 0.0+(port - 9);
sourceApps.Start (Seconds (start));
sourceApps.Stop (Seconds (20.0));
}
////////////////////// utilities //////////////////////////
//using flow monitor
Ptr<FlowMonitor> flowMonitor;
FlowMonitorHelper flowHelper;
flowMonitor = flowHelper.InstallAll();
//using pcap tracing
rightlink.EnablePcapAll("rightlink");
leftlink.EnablePcapAll("leftlink");
std::ostringstream losspstr;
std::ostringstream tcpflowsstr;
std::ostringstream qsizestr;
losspstr << lossp;
tcpflowsstr << tcpflows;
qsizestr << queue_size;
leftlink.EnablePcapAll ("bottleneckrouter-p: "+losspstr.str()+"-n: "+tcpflowsstr.str(), false);
//run the simlulation
Simulator::Stop(Seconds(20.0));
Simulator::Run();
/////////////////////////making results file//////////////////
std::ofstream file;
file.open("results.txt", std::ios_base::app);
file <<std::left<<std::setw(18)<<queue_size <<","<< std::setw(18)<< lossp <<","<< std::setw(18) << tcpflows <<","<< std::setw(18) << seed <<","<< std::setw(18);
//calculating the throughput
Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier> (flowHelper.GetClassifier ());
std::map<FlowId, FlowMonitor::FlowStats> stats = flowMonitor->GetFlowStats ();
double total_throughput = 0;
for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i = stats.begin (); i != stats.end (); ++i){
Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow (i->first);
if ((t.sourceAddress=="10.1.1.1" && t.destinationAddress == "10.1.2.2")){
double flow_throughput = (i->second.rxBytes * 8.0) / (i->second.timeLastRxPacket.GetSeconds() - i->second.timeFirstTxPacket.GetSeconds());
flow_throughput /= 1024;
flow_throughput /= 1024;
total_throughput += flow_throughput;
std::cout << "Flow " << i->first << " (" << t.sourceAddress << " -> " << t.destinationAddress << ")\n";
std::cout << " Tx Bytes: " << i->second.txBytes << "\n";
std::cout << " Rx Bytes: " << i->second.rxBytes << "\n";
std::cout << " Throughput: " << flow_throughput << " Mbps\n";
}
}
file << total_throughput << ",\n";
file.close();
//////////////////////////// end test code//////////////////////////////////////
//saving flow monitor results before destroying simulator
flowMonitor->SerializeToXmlFile("flowmonitor-p: "+losspstr.str()+"-n: "+tcpflowsstr.str()+" q: "+qsizestr.str()+".xml", true, true);
Simulator::Destroy();
return 0;
}