You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

842 lines
30 KiB
C++

/*
* Copyright (C) 2013 - Johannes Schauer <j.schauer at email.de>
*
* 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
*
*
* This code heavily borrows from ns3 itself which are copyright of their
* respective authors and redistributable under the same conditions.
*
*/
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t
#include <stdlib.h> // for exit
#include <algorithm> // for min
#include <iomanip> // for operator<<, setw
#include <iostream> // for operator<<, basic_ostream, etc
#include <string> // for string, allocator, etc
#include <vector> // for vector
#include "ns3/address.h" // for Address
#include "ns3/application-container.h" // for ApplicationContainer
#include "ns3/application.h" // for Application
#include "ns3/boolean.h" // for BooleanValue
#include "ns3/callback.h" // for MakeCallback
#include "ns3/command-line.h" // for CommandLine
#include "ns3/config.h" // for SetDefault, Connect
#include "ns3/data-rate.h" // for DataRate
#include "ns3/double.h" // for DoubleValue
#include "ns3/enum.h" // for EnumValue
#include "ns3/error-model.h" // for RateErrorModel
#include "ns3/event-id.h" // for EventId
#include "ns3/fatal-error.h" // for NS_FATAL_ERROR
#include "ns3/global-value.h" // for GlobalValue
#include "ns3/header.h" // for Header
#include "ns3/inet-socket-address.h" // for InetSocketAddress
#include "ns3/internet-stack-helper.h" // for InternetStackHelper
#include "ns3/ipv4-address-helper.h" // for Ipv4AddressHelper
#include "ns3/ipv4-address.h" // for operator<<, Ipv4Address, etc
#include "ns3/ipv4-global-routing-helper.h"
#include "ns3/ipv4-header.h" // for Ipv4Header
#include "ns3/ipv4-interface-container.h" // for Ipv4InterfaceContainer
#include "ns3/ipv4.h" // for Ipv4
#include "ns3/net-device-container.h" // for NetDeviceContainer
#include "ns3/net-device.h" // for NetDevice
#include "ns3/node-container.h" // for NodeContainer
#include "ns3/node.h" // for Node
#include "ns3/nstime.h" // for Seconds, Time
#include "ns3/object.h" // for CreateObject
#include "ns3/packet-sink-helper.h" // for PacketSinkHelper
#include "ns3/packet.h" // for Packet
#include "ns3/point-to-point-helper.h" // for PointToPointHelper
#include "ns3/pointer.h" // for PointerValue
#include "ns3/ptr.h" // for Ptr, Create, DynamicCast
#include "ns3/rng-seed-manager.h" // for SeedManager
#include "ns3/simulator.h" // for Simulator
#include "ns3/socket.h" // for Socket, etc
#include "ns3/string.h" // for StringValue
#include "ns3/tcp-header.h" // for TcpHeader
#include "ns3/tcp-newreno.h" // for TcpNewReno
#include "ns3/tcp-reno.h" // for TcpReno
#include "ns3/tcp-socket-factory.h" // for TcpSocketFactory
#include "ns3/tcp-socket.h" // for TcpSocket
#include "ns3/tcp-tahoe.h" // for TcpTahoe
#include "ns3/tcp-westwood.h" // for TcpWestwood, etc
#include "ns3/type-id.h" // for TypeIdValue
#include "ns3/udp-header.h" // for UdpHeader
#include "ns3/udp-socket-factory.h" // for UdpSocketFactory
#include "ns3/uinteger.h" // for UintegerValue
/*
* we need to roll our own app instead of using one of the supplied helpers
* because of the following reasons:
*
* - bulktransferhelper can't do udp
* - onoffhelper doesnt allow access to the underlying sockets
* - not having access to the underlying sockets, means that any tracer can
* only be registered *after* the app created by the helper is started.
* This is ugly as it forces to start multiple tracers manually in synch
* with the app start time. Since it has to be multiple tracers, one cannot
* anymore use the wildcard mechanism to have a one-tracer-catches-all
* setup.
*
* this app allows to send an infinite number of tcp or udp packets at a fixed
* rate
* */
class LimitedRateApp : public ns3::Application
{
public:
LimitedRateApp();
virtual ~ LimitedRateApp();
void Setup(ns3::Ptr<ns3::Socket> socket, ns3::Address address,
uint32_t packetSize, ns3::DataRate dataRate);
private:
virtual void StartApplication(void);
virtual void StopApplication(void);
void ScheduleTx(void);
void SendPacket(void);
ns3::Ptr<ns3::Socket> m_socket;
ns3::Address m_peer;
uint32_t m_packetSize;
ns3::DataRate m_dataRate;
ns3::EventId m_sendEvent;
bool m_running;
};
LimitedRateApp::LimitedRateApp()
: m_socket(0),
m_peer(),
m_packetSize(0),
m_dataRate(0),
m_sendEvent(),
m_running(false)
{
}
LimitedRateApp::~LimitedRateApp()
{
m_socket = 0;
}
void
LimitedRateApp::Setup(ns3::Ptr<ns3::Socket> socket,
ns3::Address address, uint32_t packetSize,
ns3::DataRate dataRate)
{
m_socket = socket;
m_peer = address;
m_packetSize = packetSize;
m_dataRate = dataRate;
}
void LimitedRateApp::StartApplication(void)
{
m_running = true;
m_socket->Bind();
m_socket->Connect(m_peer);
SendPacket();
}
void LimitedRateApp::StopApplication(void)
{
m_running = false;
if (m_sendEvent.IsRunning()) {
ns3::Simulator::Cancel(m_sendEvent);
}
if (m_socket) {
m_socket->Close();
}
}
void LimitedRateApp::SendPacket(void)
{
ns3::Ptr<ns3::Packet> packet =
ns3::Create<ns3::Packet>(m_packetSize);
m_socket->Send(packet);
ScheduleTx();
}
void LimitedRateApp::ScheduleTx(void)
{
if (m_running) {
ns3::Time tNext(ns3::Seconds(
m_packetSize * 8 /
static_cast<double>(m_dataRate.GetBitRate())));
m_sendEvent = ns3::Simulator::Schedule(
tNext, &LimitedRateApp::SendPacket, this);
}
}
/*
* this app borrows from the BulkSendApplication but keeps sending for an
* infinite time (until Stop() is reached) and receives an already created
* socket instead of creating its own
*
* it has unlimited rate in the sense that it pushes new packets into the
* sending buffer of the socket until it is full and keeps filling that buffer
* once the socket becomes ready to send again.
*
* due to this nature of operation it is only suitable for streaming sockets
*/
class UnlimitedRateApp : public ns3::Application
{
public:
UnlimitedRateApp();
virtual ~ UnlimitedRateApp();
void Setup(ns3::Ptr<ns3::Socket> socket, ns3::Address address,
uint32_t packetSize);
private:
// inherited from Application base class.
virtual void StartApplication(void); // Called at time specified by Start
virtual void StopApplication(void); // Called at time specified by Stop
void SendData();
ns3::Ptr<ns3::Socket> m_socket; // Associated socket
ns3::Address m_peer; // Peer address
bool m_connected; // True if connected
uint32_t m_packetSize; // Size of data to send each time
void ConnectionSucceeded(ns3::Ptr<ns3::Socket> socket);
void ConnectionFailed(ns3::Ptr<ns3::Socket> socket);
void DataSend(ns3::Ptr<ns3::Socket>, uint32_t); // for socket's SetSendCallback
void Ignore(ns3::Ptr<ns3::Socket> socket);
};
UnlimitedRateApp::UnlimitedRateApp()
: m_socket(0),
m_connected(false),
m_packetSize(512)
{
}
UnlimitedRateApp::~UnlimitedRateApp()
{
m_socket = 0;
}
void
UnlimitedRateApp::Setup(ns3::Ptr<ns3::Socket> socket,
ns3::Address address, uint32_t packetSize)
{
m_socket = socket;
m_peer = address;
m_packetSize = packetSize;
// Fatal error if socket type is not NS3_SOCK_STREAM or NS3_SOCK_SEQPACKET
if (m_socket->GetSocketType() != ns3::Socket::NS3_SOCK_STREAM &&
m_socket->GetSocketType() != ns3::Socket::NS3_SOCK_SEQPACKET) {
NS_FATAL_ERROR
("Using UnlimitedRateApp with an incompatible socket type. "
"UnlimitedRateApp requires SOCK_STREAM or SOCK_SEQPACKET. "
"In other words, use TCP instead of UDP.");
}
}
void UnlimitedRateApp::StartApplication(void)
{
m_socket->Bind();
m_socket->Connect(m_peer);
m_socket->ShutdownRecv();
m_socket->SetConnectCallback(ns3::MakeCallback(
&UnlimitedRateApp::ConnectionSucceeded, this),
ns3::MakeCallback(
&UnlimitedRateApp::ConnectionFailed, this));
m_socket->SetSendCallback(ns3::MakeCallback(
&UnlimitedRateApp::DataSend, this));
if (m_connected)
SendData();
}
void UnlimitedRateApp::StopApplication(void) // Called at time specified by Stop
{
if (m_socket != 0) {
m_socket->Close();
m_connected = false;
}
}
void UnlimitedRateApp::SendData(void)
{
// We exit this loop when actual<toSend as the send side
// buffer is full. The "DataSend" callback will pop when
// some buffer space has freed ip.
for (;;) {
ns3::Ptr<ns3::Packet> packet =
ns3::Create<ns3::Packet>(m_packetSize);
int actual = m_socket->Send(packet);
if ((unsigned) actual != m_packetSize)
break;
}
}
void UnlimitedRateApp::ConnectionSucceeded(ns3::Ptr<ns3::Socket> socket)
{
m_connected = true;
SendData();
}
void UnlimitedRateApp::ConnectionFailed(ns3::Ptr<ns3::Socket> socket)
{
}
void UnlimitedRateApp::DataSend(ns3::Ptr<ns3::Socket>, uint32_t)
{
if (m_connected) { // Only send new data if the connection has completed
ns3::Simulator::ScheduleNow(&UnlimitedRateApp::SendData, this);
}
}
/*
* this app borrows from the BulkSendApplication but instead allows a socket
* being passed to it instead of creating its own socket internally.
*
* it has unlimited rate in the sense that it pushes new packets into the
* sending buffer of the socket until it is full and keeps filling that buffer
* once the socket becomes ready to send again.
*
* due to this nature of operation it is only suitable for streaming sockets
*/
class LimitedTransferApp : public ns3::Application
{
public:
LimitedTransferApp();
virtual ~ LimitedTransferApp();
void Setup(ns3::Ptr<ns3::Socket> socket, ns3::Address address,
uint32_t packetSize, uint32_t maxBytes);
private:
// inherited from Application base class.
virtual void StartApplication(void); // Called at time specified by Start
virtual void StopApplication(void); // Called at time specified by Stop
void SendData();
ns3::Ptr<ns3::Socket> m_socket; // Associated socket
ns3::Address m_peer; // Peer address
bool m_connected; // True if connected
uint32_t m_packetSize; // Size of data to send each time
uint32_t m_totBytes; // Total bytes sent so far
uint32_t m_maxBytes; // Limit total number of bytes sent
void ConnectionSucceeded(ns3::Ptr<ns3::Socket> socket);
void ConnectionFailed(ns3::Ptr<ns3::Socket> socket);
void DataSend(ns3::Ptr<ns3::Socket>, uint32_t); // for socket's SetSendCallback
void Ignore(ns3::Ptr<ns3::Socket> socket);
};
LimitedTransferApp::LimitedTransferApp()
: m_socket(0),
m_connected(false),
m_packetSize(512),
m_totBytes(0),
m_maxBytes(0)
{
}
LimitedTransferApp::~LimitedTransferApp()
{
m_socket = 0;
}
void
LimitedTransferApp::Setup(ns3::Ptr<ns3::Socket> socket,
ns3::Address address, uint32_t packetSize,
uint32_t maxBytes)
{
m_socket = socket;
m_peer = address;
m_packetSize = packetSize;
m_maxBytes = maxBytes;
// Fatal error if socket type is not NS3_SOCK_STREAM or NS3_SOCK_SEQPACKET
if (m_socket->GetSocketType() != ns3::Socket::NS3_SOCK_STREAM &&
m_socket->GetSocketType() != ns3::Socket::NS3_SOCK_SEQPACKET) {
NS_FATAL_ERROR
("Using LimitedTransferApp with an incompatible socket type. "
"LimitedTransferApp requires SOCK_STREAM or SOCK_SEQPACKET. "
"In other words, use TCP instead of UDP.");
}
}
void LimitedTransferApp::StartApplication(void)
{
m_socket->Bind();
m_socket->Connect(m_peer);
m_socket->ShutdownRecv();
m_socket->SetConnectCallback(MakeCallback(
&LimitedTransferApp::ConnectionSucceeded, this),
MakeCallback(
&LimitedTransferApp::ConnectionFailed, this));
m_socket->SetSendCallback(
ns3::MakeCallback(&LimitedTransferApp::DataSend, this));
if (m_connected)
SendData();
}
void LimitedTransferApp::StopApplication(void) // Called at time specified by Stop
{
if (m_socket != 0) {
m_socket->Close();
m_connected = false;
}
}
void LimitedTransferApp::SendData(void)
{
while (m_totBytes<m_maxBytes) {
uint32_t toSend = m_packetSize;
// Make sure we don't send too many
if (m_maxBytes> 0) {
toSend = std::min(m_packetSize, m_maxBytes - m_totBytes);
}
ns3::Ptr<ns3::Packet> packet =
ns3::Create<ns3::Packet>(toSend);
int actual = m_socket->Send(packet);
if (actual> 0) {
m_totBytes += actual;
}
// We exit this loop when actual<toSend as the send side
// buffer is full. The "DataSent" callback will pop when
// some buffer space has freed ip.
if ((unsigned) actual != toSend) {
break;
}
}
// Check if time to close (all sent)
if (m_totBytes == m_maxBytes && m_connected) {
m_socket->Close();
m_connected = false;
}
}
void LimitedTransferApp::ConnectionSucceeded(ns3::Ptr<ns3::Socket>
socket)
{
m_connected = true;
SendData();
}
void LimitedTransferApp::ConnectionFailed(ns3::Ptr<ns3::Socket> socket)
{
}
void LimitedTransferApp::DataSend(ns3::Ptr<ns3::Socket>, uint32_t)
{
if (m_connected) { // Only send new data if the connection has completed
ns3::Simulator::ScheduleNow(&LimitedTransferApp::SendData, this);
}
}
static void CwndTracer(std::string context, uint32_t oldval,
uint32_t newval)
{
if (newval> 2147483648) {
std::cerr << "impossibly high cwnd value: " << newval << std::endl;
return;
}
std::cout << std::setw(8) << ns3::Simulator::Now().GetSeconds() << " ";
std::cout << context << " " << newval << std::endl;
}
static void SsThreshTracer(std::string context, uint32_t oldval,
uint32_t newval)
{
std::cout << std::setw(8) << ns3::Simulator::Now().GetSeconds() << " ";
std::cout << context << " " << newval << std::endl;
}
static void PacketSinkRxTracer(std::string context,
ns3::Ptr<const ns3::Packet> p,
const ns3::Address & addr)
{
std::cout << std::setw(8) << ns3::Simulator::Now().GetSeconds() << " ";
std::cout << context << " " << p->GetSize() << std::endl;
}
static void TxQueueDropTracer(std::string context,
ns3::Ptr<const ns3::Packet> p)
{
ns3::Ipv4Header ipv4h;
uint32_t len = p->PeekHeader(ipv4h);
if (len == 0) {
std::cout << std::setw(8) <<
ns3::Simulator::Now().GetSeconds() << " ";
std::cout << context << " 0" << std::endl;
} else {
std::cout << std::setw(8) <<
ns3::Simulator::Now().GetSeconds() << " ";
std::cout << context << " " << ipv4h.GetSource() <<
" " << ipv4h.GetDestination() << std::endl;
}
}
static void PhyRxDropTracer(std::string context,
ns3::Ptr<const ns3::Packet> p)
{
std::cout << std::setw(8) << ns3::Simulator::Now().GetSeconds() << " ";
std::cout << context << " 0" << std::endl;
}
void printHeaderSizes()
{
ns3::Header * temp_header = new ns3::Ipv4Header();
uint32_t ip_header = temp_header->GetSerializedSize();
std::cerr << "IP Header size is: " << ip_header << std::endl;
delete temp_header;
temp_header = new ns3::TcpHeader();
uint32_t tcp_header = temp_header->GetSerializedSize();
std::cerr << "TCP Header size is: " << tcp_header << std::endl;
delete temp_header;
temp_header = new ns3::UdpHeader();
uint32_t udp_header = temp_header->GetSerializedSize();
std::cerr << "UDP Header size is: " << udp_header << std::endl;
delete temp_header;
}
int main(int argc, char *argv[])
{
std::string transport_prot = "TcpNewReno";
double error_p = 0.0;
std::string bottleneck_bandwidth = "1Mbps";
std::string access_bandwidth = "10Mbps";
std::string bottleneck_delay = "50ms";
std::string access_delay = "1ms";
uint32_t queuesize = 90;
uint32_t run = 0;
double simstop = 0.0;
bool pcaptracing = false;
ns3::CommandLine cmd;
cmd.AddValue("tcpcaa",
"Default TCP congestion-avoidance algorithm to use: "
"TcpTahoe, TcpReno, TcpNewReno, TcpWestwood, TcpWestwoodPlus ",
transport_prot);
cmd.AddValue("error_p", "Packet error rate", error_p);
cmd.AddValue("bandwidth", "Bottleneck link bandwidth",
bottleneck_bandwidth);
cmd.AddValue("access_bandwidth", "Access link bandwidth",
access_bandwidth);
cmd.AddValue("delay", "Bottleneck link delay", bottleneck_delay);
cmd.AddValue("access delay", "Access link delay", access_delay);
cmd.AddValue("run", "Run index (for setting repeatable seeds)", run);
cmd.AddValue("simstop", "Stop simulator after this many seconds",
simstop);
cmd.AddValue("tracing", "Flag to enable/disable pcap tracing",
pcaptracing);
cmd.AddValue("queue_size",
"Maximum amount of packets allowed inside the queue", queuesize);
cmd.Parse(argc, argv);
ns3::SeedManager::SetSeed(1);
ns3::SeedManager::SetRun(run);
ns3::Config::SetDefault("ns3::DropTailQueue::Mode",
ns3::StringValue("QUEUE_MODE_PACKETS"));
ns3::Config::SetDefault("ns3::DropTailQueue::MaxPackets",
ns3::UintegerValue(queuesize));
if (transport_prot.compare("TcpTahoe") == 0)
ns3::Config::SetDefault("ns3::TcpL4Protocol::SocketType",
ns3::TypeIdValue(ns3::TcpTahoe::GetTypeId()));
else if (transport_prot.compare("TcpReno") == 0)
ns3::Config::SetDefault("ns3::TcpL4Protocol::SocketType",
ns3::TypeIdValue(ns3::TcpReno::GetTypeId()));
else if (transport_prot.compare("TcpNewReno") == 0)
ns3::Config::SetDefault("ns3::TcpL4Protocol::SocketType",
ns3::TypeIdValue(ns3::TcpNewReno::GetTypeId()));
else if (transport_prot.compare("TcpWestwood") == 0) {
ns3::Config::SetDefault("ns3::TcpL4Protocol::SocketType",
ns3::TypeIdValue(ns3::TcpWestwood::GetTypeId()));
ns3::Config::SetDefault("ns3::TcpWestwood::FilterType",
ns3::EnumValue(ns3::TcpWestwood::TUSTIN));
} else if (transport_prot.compare("TcpWestwoodPlus") == 0) {
ns3::Config::SetDefault("ns3::TcpL4Protocol::SocketType",
ns3::TypeIdValue(ns3::TcpWestwood::GetTypeId()));
ns3::Config::SetDefault("ns3::TcpWestwood::ProtocolType",
ns3::EnumValue(ns3::TcpWestwood::WESTWOODPLUS));
ns3::Config::SetDefault("ns3::TcpWestwood::FilterType",
ns3::EnumValue(ns3::TcpWestwood::TUSTIN));
} else {
std::cerr << "Invalid TCP version";
exit(1);
}
/* the default is to not calculate checksums but if we want pcap traces
* then we calculate them */
if (pcaptracing)
ns3::GlobalValue::Bind("ChecksumEnabled", ns3::BooleanValue(true));
// read in traffic definitions from standard input
std::cerr << "Reading traffic descriptions from standard input..."
<< std::endl;
std::vector<std::string> inputlines;
std::string input_line;
for (std::string s; std::getline(std::cin, s);) {
inputlines.push_back(s);
}
uint32_t number_of_clients = inputlines.size();
std::cerr << "creating " << number_of_clients <<
" data streams" << std::endl;
ns3::PointToPointHelper bottleNeckLink;
bottleNeckLink.SetDeviceAttribute("DataRate",
ns3::StringValue(bottleneck_bandwidth));
bottleNeckLink.SetChannelAttribute("Delay",
ns3::StringValue(bottleneck_delay));
ns3::PointToPointHelper pointToPointLeaf;
pointToPointLeaf.SetDeviceAttribute("DataRate",
ns3::StringValue(access_bandwidth));
pointToPointLeaf.SetChannelAttribute("Delay",
ns3::StringValue(access_delay));
int port = 9000;
/* we cannot use the PointToPointDumbbellHelper because it hides the
* NetDeviceContainer it creates from us. Therefore, we are creating the
* dumbbell topology manually */
// create all the nodes
ns3::NodeContainer routers;
routers.Create(2);
ns3::NodeContainer leftleaves;
leftleaves.Create(number_of_clients);
ns3::NodeContainer rightleaves;
rightleaves.Create(number_of_clients);
// error model
ns3::Ptr<ns3::RateErrorModel> em =
ns3::CreateObject<ns3::RateErrorModel>();
em->SetAttribute("ErrorRate", ns3::DoubleValue(error_p));
// add the link connecting the routers
ns3::NetDeviceContainer routerdevices =
bottleNeckLink.Install(routers);
ns3::NetDeviceContainer leftrouterdevices;
ns3::NetDeviceContainer leftleafdevices;
ns3::NetDeviceContainer rightrouterdevices;
ns3::NetDeviceContainer rightleafdevices;
// add links on both sides
for (uint32_t i = 0; i<number_of_clients; ++i) {
// add the left side links
ns3::NetDeviceContainer cleft =
pointToPointLeaf.Install(routers.Get(0), leftleaves.Get(i));
leftrouterdevices.Add(cleft.Get(0));
leftleafdevices.Add(cleft.Get(1));
cleft.Get(0)->SetAttribute("ReceiveErrorModel",
ns3::PointerValue(em));
// add the right side links
ns3::NetDeviceContainer cright =
pointToPointLeaf.Install(routers.Get(1), rightleaves.Get(i));
rightrouterdevices.Add(cright.Get(0));
rightleafdevices.Add(cright.Get(1));
cright.Get(0)->SetAttribute("ReceiveErrorModel",
ns3::PointerValue(em));
}
// install internet stack on all nodes
ns3::InternetStackHelper stack;
stack.Install(routers);
stack.Install(leftleaves);
stack.Install(rightleaves);
// assign ipv4 addresses (ipv6 addresses apparently are still not fully
// supported by ns3)
ns3::Ipv4AddressHelper routerips =
ns3::Ipv4AddressHelper("10.3.0.0", "255.255.255.0");
ns3::Ipv4AddressHelper leftips =
ns3::Ipv4AddressHelper("10.1.0.0", "255.255.255.0");
ns3::Ipv4AddressHelper rightips =
ns3::Ipv4AddressHelper("10.2.0.0", "255.255.255.0");
ns3::Ipv4InterfaceContainer routerifs;
ns3::Ipv4InterfaceContainer leftleafifs;
ns3::Ipv4InterfaceContainer leftrouterifs;
ns3::Ipv4InterfaceContainer rightleafifs;
ns3::Ipv4InterfaceContainer rightrouterifs;
// assign addresses to connection connecting routers
routerifs = routerips.Assign(routerdevices);
// assign addresses to connection between routers and leaves
for (uint32_t i = 0; i<number_of_clients; ++i) {
// Assign to left side
ns3::NetDeviceContainer ndcleft;
ndcleft.Add(leftleafdevices.Get(i));
ndcleft.Add(leftrouterdevices.Get(i));
ns3::Ipv4InterfaceContainer ifcleft = leftips.Assign(ndcleft);
leftleafifs.Add(ifcleft.Get(0));
leftrouterifs.Add(ifcleft.Get(1));
leftips.NewNetwork();
// Assign to right side
ns3::NetDeviceContainer ndcright;
ndcright.Add(rightleafdevices.Get(i));
ndcright.Add(rightrouterdevices.Get(i));
ns3::Ipv4InterfaceContainer ifcright = rightips.Assign(ndcright);
rightleafifs.Add(ifcright.Get(0));
rightrouterifs.Add(ifcright.Get(1));
rightips.NewNetwork();
}
ns3::ApplicationContainer sinkApps, udpApp;
ns3::Address sinkLocalAddress(
ns3::InetSocketAddress(
ns3::Ipv4Address::GetAny(), port));
ns3::PacketSinkHelper TcpPacketSinkHelper("ns3::TcpSocketFactory",
sinkLocalAddress);
ns3::PacketSinkHelper UdpPacketSinkHelper("ns3::UdpSocketFactory",
sinkLocalAddress);
// create all the source and sink apps
for (size_t i = 0; i<inputlines.size(); ++i) {
ns3::Ptr<ns3::Socket> sockptr;
unsigned int pkgsize;
float start;
std::stringstream ss(inputlines[i]);
std::string app, transport;
ss >> app >> transport >> pkgsize >> start;
if (transport.compare("TCP") == 0) {
// setup source socket
sockptr =
ns3::Socket::CreateSocket(leftleaves.Get(i),
ns3::TcpSocketFactory::GetTypeId());
ns3::Ptr<ns3::TcpSocket> tcpsockptr =
ns3::DynamicCast<ns3::TcpSocket> (sockptr);
tcpsockptr->SetAttribute("SegmentSize",
ns3::UintegerValue(pkgsize));
std::stringstream nodeidss;
nodeidss << leftleaves.Get(i)->GetId();
std::string prefix = "/NodeList/" + nodeidss.str();
sockptr->TraceConnect("CongestionWindow",
prefix +
"/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
ns3::MakeCallback(&CwndTracer));
sockptr->TraceConnect("SlowStartThreshold",
prefix +
"/$ns3::TcpL4Protocol/SocketList/0/SlowStartThreshold",
ns3::MakeCallback(&SsThreshTracer));
// setup sink
sinkApps.Add(TcpPacketSinkHelper.Install(rightleaves.Get(i)));
} else if (transport.compare("UDP") == 0) {
// setup source socket
sockptr =
ns3::Socket::CreateSocket(leftleaves.Get(i),
ns3::UdpSocketFactory::GetTypeId());
// setup sink
sinkApps.Add(UdpPacketSinkHelper.Install(rightleaves.Get(i)));
} else {
std::cerr << "unknown transport type: " <<
transport << std::endl;
exit(1);
}
if (app.compare("LR") == 0) {
/* additionally read stop time and rate */
float stop;
std::string rate;
ss >> stop >> rate;
ns3::Ptr<LimitedRateApp> app =
ns3::CreateObject<LimitedRateApp> ();
app->Setup(sockptr,
ns3::InetSocketAddress(rightleafifs.GetAddress(i),
port), pkgsize,
ns3::DataRate(rate));
leftleaves.Get(i)->AddApplication(app);
app->SetStartTime(ns3::Seconds(start));
app->SetStopTime(ns3::Seconds(stop));
} else if (app.compare("UR") == 0) {
/* additionally read stop time */
float stop;
ss >> stop;
ns3::Ptr<UnlimitedRateApp> app =
ns3::CreateObject<UnlimitedRateApp> ();
app->Setup(sockptr,
ns3::InetSocketAddress(rightleafifs.GetAddress(i),
port), pkgsize);
leftleaves.Get(i)->AddApplication(app);
app->SetStartTime(ns3::Seconds(start));
app->SetStopTime(ns3::Seconds(stop));
} else if (app.compare("LT") == 0) {
/* additionally read maxtransfer */
unsigned int maxtransfer;
ss >> maxtransfer;
ns3::Ptr<LimitedTransferApp> app =
ns3::CreateObject<LimitedTransferApp> ();
app->Setup(sockptr,
ns3::InetSocketAddress(rightleafifs.GetAddress(i),
port), pkgsize, maxtransfer);
leftleaves.Get(i)->AddApplication(app);
app->SetStartTime(ns3::Seconds(start));
} else {
std::cerr << "unknown app type: " << app << std::endl;
exit(1);
}
}
sinkApps.Start(ns3::Seconds(0.0));
ns3::Ipv4GlobalRoutingHelper::PopulateRoutingTables();
// connect to some trace sources
ns3::Config::Connect("/NodeList/*/DeviceList/*/TxQueue/Drop",
ns3::MakeCallback(&TxQueueDropTracer));
ns3::Config::Connect("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx",
ns3::MakeCallback(&PacketSinkRxTracer));
ns3::Config::Connect("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/PhyRxDrop",
ns3::MakeCallback(&PhyRxDropTracer));
// pcap tracing
if (pcaptracing)
pointToPointLeaf.EnablePcapAll(argv[0], true);
if (simstop > 0.0) {
ns3::Simulator::Stop(ns3::Seconds(simstop));
}
ns3::Simulator::Run();
std::cerr << "Dumbbell Left Bottleneck NodeID " <<
routers.Get(0)->GetId() << std::endl;
std::cerr << "Dumbbell Right Bottleneck NodeID " <<
routers.Get(1)->GetId() << std::endl;
for (uint32_t i = 0; i<number_of_clients; ++i) {
std::cerr << "Dumbbell Left Leaf " << i << " NodeID " <<
leftleaves.Get(i)->GetId() << " IP Addr " <<
leftleafifs.GetAddress(i) << std::endl;
}
for (uint32_t i = 0; i<number_of_clients; ++i) {
std::cerr << "Dumbbell Right Leaf " << i << " NodeID " <<
rightleaves.Get(i)->GetId() << " IP Addr " << rightleafifs.
GetAddress(i) << std::endl;
}
ns3::Simulator::Destroy();
return 0;
}