Bosnia and Herzegovina

NS3 lab code which can be useful for beginners in NS3

Full tutorial is available on http://personal.ee.surrey.ac.uk/Personal/K.Katsaros/ns-3-workshop-part1.html#solved2

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* 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
*/

 

/*
LAB Assignment #2
1. Create a simple dumbbell topology, two client Node1 and Node2 on
the left side of the dumbbell and server nodes Node3 and Node4 on the
right side of the dumbbell. Let Node5 and Node6 form the bridge of the
dumbbell. Use point to point links.

2. Install a TCP socket instance on Node1 that will connect to Node3.

3. Install a UDP socket instance on Node2 that will connect to Node4.

4. Start the TCP application at time 1s.

5. Start the UDP application at time 20s at rate Rate1 such that it clogs
half the dumbbell bridge's link capacity.

6. Increase the UDP application's rate at time 30s to rate Rate2
such that it clogs the whole of the dumbbell bridge's capacity.

7. Use the ns-3 tracing mechanism to record changes in congestion window
size of the TCP instance over time. Use gnuplot/matplotlib to visualise plots of cwnd vs time.

8. Mark points of fast recovery and slow start in the graphs.

9. Perform the above experiment for TCP variants Tahoe, Reno and New Reno,
all of which are available with ns-3.

Solution by: Konstantinos Katsaros (K.Katsaros@surrey.ac.uk)
based on fifth.cc
*/

// Network topology
//
// n0 ---+ +--- n2
// | |
// n4 -- n5
// | |
// n1 ---+ +--- n3
//
// - All links are P2P with 500kb/s and 2ms
// - TCP flow form n0 to n2
// - UDP flow from n1 to n3

#include
#include
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/internet-module.h"
#include "ns3/flow-monitor-module.h"
#include "ns3/ipv4-global-routing-helper.h"

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("Lab2");

//Let's create an application
class MyApp : public Application
{
public:

//Constructor
MyApp ();

//Destructor
virtual ~MyApp();

//our public functions to set the paramters of the application
void Setup (Ptr socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);

//We need function that will increase the change the rate
void ChangeRate(DataRate newrate);

private:
//Start and stop functions
virtual void StartApplication (void);
virtual void StopApplication (void);

//we need some schedule functions for time manipulations
void ScheduleTx (void);

//
void SendPacket (void);

Ptr m_socket;
Address m_peer;
uint32_t m_packetSize;
uint32_t m_nPackets;
DataRate m_dataRate;
EventId m_sendEvent;
bool m_running;
uint32_t m_packetsSent;
};
//Call constructor with default values
MyApp::MyApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPackets (0),
m_dataRate (0),
m_sendEvent (),
m_running (false),
m_packetsSent (0)
{
}

//Call destructor
MyApp::~MyApp()
{
m_socket = 0;
}

//now setup some real values
void
MyApp::Setup (Ptr socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
{
m_socket = socket;
m_peer = address;
m_packetSize = packetSize;
m_nPackets = nPackets;
m_dataRate = dataRate;
}

//And start the app
void
MyApp::StartApplication (void)
{
m_running = true;
m_packetsSent = 0;
m_socket->Bind ();
m_socket->Connect (m_peer);
SendPacket ();
}

//And stop the app - default function
void
MyApp::StopApplication (void)
{
m_running = false;

if (m_sendEvent.IsRunning ())
{
Simulator::Cancel (m_sendEvent);
}

if (m_socket)
{
m_socket->Close ();
}
}

void
MyApp::SendPacket (void)
{
//create a packet
Ptr packet = Create (m_packetSize);
//and send it
m_socket->Send (packet);

//if number of packets is lower then the maximal number of packets then call schedule function to manipulate when the packet need to be send
if (++m_packetsSent< m_nPackets)
{
ScheduleTx ();
}
}

//manipulations with the simulator schedule of packages
void
MyApp::ScheduleTx (void)
{
//if application is running
if (m_running)
{
//calculate the next time event
Time tNext (Seconds (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ())));

//and set the packet to be sent at that time
m_sendEvent = Simulator::Schedule (tNext, &amp;MyApp::SendPacket, this);
}
}

//change the rate of the application and diretly change the schedule for sending of packages
void
MyApp::ChangeRate(DataRate newrate)
{
m_dataRate = newrate;
return;
}

//callback function for displaying values - time and new changed bit rate
static void
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
std::cout << Simulator::Now ().GetSeconds () << "\t" << newCwnd <<"\n";
}

//helper function that will change the rate of the app
void
IncRate (Ptr app, DataRate rate)
{
app->ChangeRate(rate);
return;
}
int main (int argc, char *argv[])
{
std::string lat = "2ms";
std::string rate = "500kb/s"; // P2P link
bool enableFlowMonitor = false;
CommandLine cmd;
cmd.AddValue ("latency", "P2P link Latency in miliseconds", lat);
cmd.AddValue ("rate", "P2P data rate in bps", rate);
cmd.AddValue ("EnableMonitor", "Enable Flow Monitor", enableFlowMonitor);

cmd.Parse (argc, argv);

//
// Explicitly create the nodes required by the topology (shown above).
//
NS_LOG_INFO ("Create nodes.");
NodeContainer c; // ALL Nodes
c.Create(6);

NodeContainer n0n4 = NodeContainer (c.Get (0), c.Get (4));
NodeContainer n1n4 = NodeContainer (c.Get (1), c.Get (4));
NodeContainer n2n5 = NodeContainer (c.Get (2), c.Get (5));
NodeContainer n3n5 = NodeContainer (c.Get (3), c.Get (5));
NodeContainer n4n5 = NodeContainer (c.Get (4), c.Get (5));

//
// Install Internet Stack
//
InternetStackHelper internet;
internet.Install (c);

// We create the channels first without any IP addressing information
NS_LOG_INFO ("Create channels.");
PointToPointHelper p2p;
p2p.SetDeviceAttribute ("DataRate", StringValue (rate));
p2p.SetChannelAttribute ("Delay", StringValue (lat));
NetDeviceContainer d0d4 = p2p.Install (n0n4);
NetDeviceContainer d1d4 = p2p.Install (n1n4);
NetDeviceContainer d4d5 = p2p.Install (n4n5);
NetDeviceContainer d2d5 = p2p.Install (n2n5);
NetDeviceContainer d3d5 = p2p.Install (n3n5);

// Later, we add IP addresses.
NS_LOG_INFO ("Assign IP Addresses.");
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer i0i4 = ipv4.Assign (d0d4);

ipv4.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer i1i4 = ipv4.Assign (d1d4);

ipv4.SetBase ("10.1.3.0", "255.255.255.0");
Ipv4InterfaceContainer i4i5 = ipv4.Assign (d4d5);

ipv4.SetBase ("10.1.4.0", "255.255.255.0");
Ipv4InterfaceContainer i2i5 = ipv4.Assign (d2d5);

ipv4.SetBase ("10.1.5.0", "255.255.255.0");
Ipv4InterfaceContainer i3i5 = ipv4.Assign (d3d5);

NS_LOG_INFO ("Enable static global routing.");
//
// Turn on global static routing so we can actually be routed across the network.
//
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
NS_LOG_INFO ("Create Applications.");

// TCP connfection from N0 to N2

uint16_t sinkPort = 8080;
Address sinkAddress (InetSocketAddress (i2i5.GetAddress (0), sinkPort)); // interface of n2
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
ApplicationContainer sinkApps = packetSinkHelper.Install (c.Get (2)); //n2 as sink
sinkApps.Start (Seconds (0.));
sinkApps.Stop (Seconds (100.));

Ptr ns3TcpSocket = Socket::CreateSocket (c.Get (0), TcpSocketFactory::GetTypeId ()); //source at n0

// Trace Congestion window
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndChange));

// Create TCP application at n0
Ptr app = CreateObject ();
app->Setup (ns3TcpSocket, sinkAddress, 1040, 100000, DataRate ("250Kbps"));
c.Get (0)->AddApplication (app);
app->SetStartTime (Seconds (1.));
app->SetStopTime (Seconds (100.));
// UDP connfection from N1 to N3

uint16_t sinkPort2 = 6;
Address sinkAddress2 (InetSocketAddress (i3i5.GetAddress (0), sinkPort2)); // interface of n3
PacketSinkHelper packetSinkHelper2 ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort2));
ApplicationContainer sinkApps2 = packetSinkHelper2.Install (c.Get (3)); //n3 as sink
sinkApps2.Start (Seconds (0.));
sinkApps2.Stop (Seconds (100.));

Ptr ns3UdpSocket = Socket::CreateSocket (c.Get (1), UdpSocketFactory::GetTypeId ()); //source at n1

// Create UDP application at n1
Ptr app2 = CreateObject ();
app2->Setup (ns3UdpSocket, sinkAddress2, 1040, 100000, DataRate ("250Kbps"));
c.Get (1)->AddApplication (app2);
app2->SetStartTime (Seconds (20.));
app2->SetStopTime (Seconds (100.));

// Increase UDP Rate
Simulator::Schedule (Seconds(30.0), &IncRate, app2, DataRate("500kbps"));

// Flow Monitor
Ptr flowmon;
if (enableFlowMonitor)
{
FlowMonitorHelper flowmonHelper;
flowmon = flowmonHelper.InstallAll ();
}

//
// Now, do the actual simulation.
//
NS_LOG_INFO ("Run Simulation.");
Simulator::Stop (Seconds(100.0));
Simulator::Run ();
if (enableFlowMonitor)
{
flowmon->CheckForLostPackets ();
flowmon->SerializeToXmlFile("lab-2.flowmon", true, true);
}
Simulator::Destroy ();
NS_LOG_INFO ("Done.");
}