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, &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."); }