2019-08-04 20:47:51 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2019 NITK Surathkal
|
|
|
|
|
*
|
2024-06-17 16:17:10 +02:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
2019-08-04 20:47:51 -07:00
|
|
|
*
|
|
|
|
|
* Authors: Apoorva Bhargava <apoorvabhargava13@gmail.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Network topology
|
|
|
|
|
//
|
|
|
|
|
// n0 ---------- n1 ---------- n2 ---------- n3
|
|
|
|
|
// 10 Mbps 1 Mbps 10 Mbps
|
|
|
|
|
// 1 ms 10 ms 1 ms
|
|
|
|
|
//
|
|
|
|
|
// - TCP flow from n0 to n3 using BulkSendApplication.
|
2020-08-06 13:23:37 -07:00
|
|
|
// - The following simulation output is stored in results/ in ns-3 top-level directory:
|
2019-08-04 20:47:51 -07:00
|
|
|
// - cwnd traces are stored in cwndTraces folder
|
2020-08-06 13:23:37 -07:00
|
|
|
// - queue length statistics are stored in queue-size.dat file
|
2019-08-04 20:47:51 -07:00
|
|
|
// - pcaps are stored in pcap folder
|
|
|
|
|
// - queueTraces folder contain the drop statistics at queue
|
|
|
|
|
// - queueStats.txt file contains the queue stats and config.txt file contains
|
|
|
|
|
// the simulation configuration.
|
|
|
|
|
// - The cwnd and queue length traces obtained from this example were tested against
|
|
|
|
|
// the respective traces obtained from Linux Reno by using ns-3 Direct Code Execution.
|
|
|
|
|
// See internet/doc/tcp.rst for more details.
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
#include "ns3/applications-module.h"
|
2019-08-04 20:47:51 -07:00
|
|
|
#include "ns3/core-module.h"
|
|
|
|
|
#include "ns3/internet-module.h"
|
2022-10-07 20:08:35 +00:00
|
|
|
#include "ns3/network-module.h"
|
2019-08-04 20:47:51 -07:00
|
|
|
#include "ns3/point-to-point-module.h"
|
|
|
|
|
#include "ns3/traffic-control-module.h"
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
#include <fstream>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
2019-08-04 20:47:51 -07:00
|
|
|
using namespace ns3;
|
2020-08-06 13:23:37 -07:00
|
|
|
std::string dir = "results/";
|
2022-10-07 20:08:35 +00:00
|
|
|
Time stopTime = Seconds(60);
|
2020-08-06 13:23:37 -07:00
|
|
|
uint32_t segmentSize = 524;
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2024-01-31 19:12:37 +05:30
|
|
|
std::ofstream fPlotQueue;
|
|
|
|
|
std::ofstream fPlotCwnd;
|
|
|
|
|
|
2019-08-04 20:47:51 -07:00
|
|
|
// Function to check queue length of Router 1
|
|
|
|
|
void
|
2022-10-07 20:08:35 +00:00
|
|
|
CheckQueueSize(Ptr<QueueDisc> queue)
|
2019-08-04 20:47:51 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
uint32_t qSize = queue->GetCurrentSize().GetValue();
|
|
|
|
|
|
|
|
|
|
// Check queue size every 1/100 of a second
|
|
|
|
|
Simulator::Schedule(Seconds(0.001), &CheckQueueSize, queue);
|
|
|
|
|
fPlotQueue << Simulator::Now().GetSeconds() << " " << qSize << std::endl;
|
2019-08-04 20:47:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Function to trace change in cwnd at n0
|
|
|
|
|
static void
|
2022-10-07 20:08:35 +00:00
|
|
|
CwndChange(uint32_t oldCwnd, uint32_t newCwnd)
|
2019-08-04 20:47:51 -07:00
|
|
|
{
|
2024-01-31 19:12:37 +05:30
|
|
|
fPlotCwnd << Simulator::Now().GetSeconds() << " " << newCwnd / segmentSize << std::endl;
|
2019-08-04 20:47:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Function to calculate drops in a particular Queue
|
|
|
|
|
static void
|
2022-10-07 20:08:35 +00:00
|
|
|
DropAtQueue(Ptr<OutputStreamWrapper> stream, Ptr<const QueueDiscItem> item)
|
2019-08-04 20:47:51 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
*stream->GetStream() << Simulator::Now().GetSeconds() << " 1" << std::endl;
|
2019-08-04 20:47:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Trace Function for cwnd
|
|
|
|
|
void
|
2022-10-07 20:08:35 +00:00
|
|
|
TraceCwnd(uint32_t node, uint32_t cwndWindow, Callback<void, uint32_t, uint32_t> CwndTrace)
|
2019-08-04 20:47:51 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
Config::ConnectWithoutContext("/NodeList/" + std::to_string(node) +
|
|
|
|
|
"/$ns3::TcpL4Protocol/SocketList/" +
|
|
|
|
|
std::to_string(cwndWindow) + "/CongestionWindow",
|
|
|
|
|
CwndTrace);
|
2019-08-04 20:47:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Function to install BulkSend application
|
2022-10-07 20:08:35 +00:00
|
|
|
void
|
|
|
|
|
InstallBulkSend(Ptr<Node> node,
|
|
|
|
|
Ipv4Address address,
|
|
|
|
|
uint16_t port,
|
|
|
|
|
std::string socketFactory,
|
|
|
|
|
uint32_t nodeId,
|
|
|
|
|
uint32_t cwndWindow,
|
|
|
|
|
Callback<void, uint32_t, uint32_t> CwndTrace)
|
2019-08-04 20:47:51 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
BulkSendHelper source(socketFactory, InetSocketAddress(address, port));
|
|
|
|
|
source.SetAttribute("MaxBytes", UintegerValue(0));
|
|
|
|
|
ApplicationContainer sourceApps = source.Install(node);
|
2024-11-08 18:01:13 +00:00
|
|
|
sourceApps.Start(Seconds(10));
|
|
|
|
|
Simulator::Schedule(Seconds(10) + Seconds(0.001), &TraceCwnd, nodeId, cwndWindow, CwndTrace);
|
2022-10-07 20:08:35 +00:00
|
|
|
sourceApps.Stop(stopTime);
|
2019-08-04 20:47:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Function to install sink application
|
2022-10-07 20:08:35 +00:00
|
|
|
void
|
|
|
|
|
InstallPacketSink(Ptr<Node> node, uint16_t port, std::string socketFactory)
|
2019-08-04 20:47:51 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
PacketSinkHelper sink(socketFactory, InetSocketAddress(Ipv4Address::GetAny(), port));
|
|
|
|
|
ApplicationContainer sinkApps = sink.Install(node);
|
2024-11-08 18:01:13 +00:00
|
|
|
sinkApps.Start(Seconds(10));
|
2022-10-07 20:08:35 +00:00
|
|
|
sinkApps.Stop(stopTime);
|
2019-08-04 20:47:51 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
int
|
|
|
|
|
main(int argc, char* argv[])
|
2019-08-04 20:47:51 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
uint32_t stream = 1;
|
|
|
|
|
std::string socketFactory = "ns3::TcpSocketFactory";
|
|
|
|
|
std::string tcpTypeId = "ns3::TcpLinuxReno";
|
|
|
|
|
std::string qdiscTypeId = "ns3::FifoQueueDisc";
|
|
|
|
|
bool isSack = true;
|
|
|
|
|
uint32_t delAckCount = 1;
|
|
|
|
|
std::string recovery = "ns3::TcpClassicRecovery";
|
|
|
|
|
|
|
|
|
|
CommandLine cmd;
|
|
|
|
|
cmd.AddValue("tcpTypeId",
|
|
|
|
|
"TCP variant to use (e.g., ns3::TcpNewReno, ns3::TcpLinuxReno, etc.)",
|
|
|
|
|
tcpTypeId);
|
|
|
|
|
cmd.AddValue("qdiscTypeId", "Queue disc for gateway (e.g., ns3::CoDelQueueDisc)", qdiscTypeId);
|
|
|
|
|
cmd.AddValue("segmentSize", "TCP segment size (bytes)", segmentSize);
|
|
|
|
|
cmd.AddValue("delAckCount", "Delayed ack count", delAckCount);
|
|
|
|
|
cmd.AddValue("enableSack", "Flag to enable/disable sack in TCP", isSack);
|
|
|
|
|
cmd.AddValue("stopTime",
|
|
|
|
|
"Stop time for applications / simulation time will be stopTime",
|
|
|
|
|
stopTime);
|
|
|
|
|
cmd.AddValue("recovery", "Recovery algorithm type to use (e.g., ns3::TcpPrrRecovery", recovery);
|
|
|
|
|
cmd.Parse(argc, argv);
|
|
|
|
|
|
|
|
|
|
TypeId qdTid;
|
|
|
|
|
NS_ABORT_MSG_UNLESS(TypeId::LookupByNameFailSafe(qdiscTypeId, &qdTid),
|
|
|
|
|
"TypeId " << qdiscTypeId << " not found");
|
|
|
|
|
|
|
|
|
|
// Set recovery algorithm and TCP variant
|
|
|
|
|
Config::SetDefault("ns3::TcpL4Protocol::RecoveryType",
|
|
|
|
|
TypeIdValue(TypeId::LookupByName(recovery)));
|
2022-11-13 11:21:42 +01:00
|
|
|
TypeId tcpTid;
|
|
|
|
|
NS_ABORT_MSG_UNLESS(TypeId::LookupByNameFailSafe(tcpTypeId, &tcpTid),
|
|
|
|
|
"TypeId " << tcpTypeId << " not found");
|
|
|
|
|
Config::SetDefault("ns3::TcpL4Protocol::SocketType",
|
|
|
|
|
TypeIdValue(TypeId::LookupByName(tcpTypeId)));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Create nodes
|
|
|
|
|
NodeContainer leftNodes;
|
|
|
|
|
NodeContainer rightNodes;
|
|
|
|
|
NodeContainer routers;
|
|
|
|
|
routers.Create(2);
|
|
|
|
|
leftNodes.Create(1);
|
|
|
|
|
rightNodes.Create(1);
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
std::vector<NetDeviceContainer> leftToRouter;
|
|
|
|
|
std::vector<NetDeviceContainer> routerToRight;
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Create the point-to-point link helpers and connect two router nodes
|
|
|
|
|
PointToPointHelper pointToPointRouter;
|
|
|
|
|
pointToPointRouter.SetDeviceAttribute("DataRate", StringValue("1Mbps"));
|
|
|
|
|
pointToPointRouter.SetChannelAttribute("Delay", StringValue("10ms"));
|
|
|
|
|
NetDeviceContainer r1r2ND = pointToPointRouter.Install(routers.Get(0), routers.Get(1));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Create the point-to-point link helpers and connect leaf nodes to router
|
|
|
|
|
PointToPointHelper pointToPointLeaf;
|
|
|
|
|
pointToPointLeaf.SetDeviceAttribute("DataRate", StringValue("10Mbps"));
|
|
|
|
|
pointToPointLeaf.SetChannelAttribute("Delay", StringValue("1ms"));
|
|
|
|
|
leftToRouter.push_back(pointToPointLeaf.Install(leftNodes.Get(0), routers.Get(0)));
|
|
|
|
|
routerToRight.push_back(pointToPointLeaf.Install(routers.Get(1), rightNodes.Get(0)));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
InternetStackHelper internetStack;
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
internetStack.Install(leftNodes);
|
|
|
|
|
internetStack.Install(rightNodes);
|
|
|
|
|
internetStack.Install(routers);
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Assign IP addresses to all the network devices
|
|
|
|
|
Ipv4AddressHelper ipAddresses("10.0.0.0", "255.255.255.0");
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
Ipv4InterfaceContainer r1r2IPAddress = ipAddresses.Assign(r1r2ND);
|
|
|
|
|
ipAddresses.NewNetwork();
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
std::vector<Ipv4InterfaceContainer> leftToRouterIPAddress;
|
|
|
|
|
leftToRouterIPAddress.push_back(ipAddresses.Assign(leftToRouter[0]));
|
|
|
|
|
ipAddresses.NewNetwork();
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
std::vector<Ipv4InterfaceContainer> routerToRightIPAddress;
|
|
|
|
|
routerToRightIPAddress.push_back(ipAddresses.Assign(routerToRight[0]));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Set default sender and receiver buffer size as 1MB
|
|
|
|
|
Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(1 << 20));
|
|
|
|
|
Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(1 << 20));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Set default initial congestion window as 10 segments
|
|
|
|
|
Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Set default delayed ack count to a specified value
|
|
|
|
|
Config::SetDefault("ns3::TcpSocket::DelAckCount", UintegerValue(delAckCount));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Set default segment size of TCP packet to a specified value
|
|
|
|
|
Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(segmentSize));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Enable/Disable SACK in TCP
|
|
|
|
|
Config::SetDefault("ns3::TcpSocketBase::Sack", BooleanValue(isSack));
|
2019-08-04 20:47:51 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Create directories to store dat files
|
|
|
|
|
struct stat buffer;
|
2022-10-20 14:41:18 +00:00
|
|
|
int retVal [[maybe_unused]];
|
2022-10-07 20:08:35 +00:00
|
|
|
if ((stat(dir.c_str(), &buffer)) == 0)
|
2019-08-04 20:47:51 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
std::string dirToRemove = "rm -rf " + dir;
|
|
|
|
|
retVal = system(dirToRemove.c_str());
|
|
|
|
|
NS_ASSERT_MSG(retVal == 0, "Error in return value");
|
2019-08-04 20:47:51 -07:00
|
|
|
}
|
2024-01-31 19:12:37 +05:30
|
|
|
|
|
|
|
|
SystemPath::MakeDirectories(dir);
|
|
|
|
|
SystemPath::MakeDirectories(dir + "/pcap/");
|
|
|
|
|
SystemPath::MakeDirectories(dir + "/queueTraces/");
|
|
|
|
|
SystemPath::MakeDirectories(dir + "/cwndTraces/");
|
2022-10-07 20:08:35 +00:00
|
|
|
|
|
|
|
|
// Set default parameters for queue discipline
|
|
|
|
|
Config::SetDefault(qdiscTypeId + "::MaxSize", QueueSizeValue(QueueSize("100p")));
|
|
|
|
|
|
|
|
|
|
// Install queue discipline on router
|
|
|
|
|
TrafficControlHelper tch;
|
|
|
|
|
tch.SetRootQueueDisc(qdiscTypeId);
|
|
|
|
|
QueueDiscContainer qd;
|
|
|
|
|
tch.Uninstall(routers.Get(0)->GetDevice(0));
|
|
|
|
|
qd.Add(tch.Install(routers.Get(0)->GetDevice(0)).Get(0));
|
|
|
|
|
|
|
|
|
|
// Enable BQL
|
|
|
|
|
tch.SetQueueLimits("ns3::DynamicQueueLimits");
|
|
|
|
|
|
2024-01-31 19:12:37 +05:30
|
|
|
// Open files for writing queue size and cwnd traces
|
|
|
|
|
fPlotQueue.open(dir + "queue-size.dat", std::ios::out);
|
|
|
|
|
fPlotCwnd.open(dir + "cwndTraces/n0.dat", std::ios::out);
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Calls function to check queue size
|
|
|
|
|
Simulator::ScheduleNow(&CheckQueueSize, qd.Get(0));
|
|
|
|
|
|
|
|
|
|
AsciiTraceHelper asciiTraceHelper;
|
|
|
|
|
Ptr<OutputStreamWrapper> streamWrapper;
|
|
|
|
|
|
|
|
|
|
// Create dat to store packets dropped and marked at the router
|
|
|
|
|
streamWrapper = asciiTraceHelper.CreateFileStream(dir + "/queueTraces/drop-0.dat");
|
|
|
|
|
qd.Get(0)->TraceConnectWithoutContext("Drop", MakeBoundCallback(&DropAtQueue, streamWrapper));
|
|
|
|
|
|
|
|
|
|
// Install packet sink at receiver side
|
|
|
|
|
uint16_t port = 50000;
|
|
|
|
|
InstallPacketSink(rightNodes.Get(0), port, "ns3::TcpSocketFactory");
|
|
|
|
|
|
|
|
|
|
// Install BulkSend application
|
|
|
|
|
InstallBulkSend(leftNodes.Get(0),
|
|
|
|
|
routerToRightIPAddress[0].GetAddress(1),
|
|
|
|
|
port,
|
|
|
|
|
socketFactory,
|
|
|
|
|
2,
|
|
|
|
|
0,
|
|
|
|
|
MakeCallback(&CwndChange));
|
|
|
|
|
|
|
|
|
|
// Enable PCAP on all the point to point interfaces
|
|
|
|
|
pointToPointLeaf.EnablePcapAll(dir + "pcap/ns-3", true);
|
|
|
|
|
|
|
|
|
|
Simulator::Stop(stopTime);
|
|
|
|
|
Simulator::Run();
|
|
|
|
|
|
|
|
|
|
// Store queue stats in a file
|
|
|
|
|
std::ofstream myfile;
|
|
|
|
|
myfile.open(dir + "queueStats.txt", std::fstream::in | std::fstream::out | std::fstream::app);
|
|
|
|
|
myfile << std::endl;
|
|
|
|
|
myfile << "Stat for Queue 1";
|
|
|
|
|
myfile << qd.Get(0)->GetStats();
|
|
|
|
|
myfile.close();
|
|
|
|
|
|
|
|
|
|
// Store configuration of the simulation in a file
|
|
|
|
|
myfile.open(dir + "config.txt", std::fstream::in | std::fstream::out | std::fstream::app);
|
|
|
|
|
myfile << "qdiscTypeId " << qdiscTypeId << "\n";
|
|
|
|
|
myfile << "stream " << stream << "\n";
|
|
|
|
|
myfile << "segmentSize " << segmentSize << "\n";
|
|
|
|
|
myfile << "delAckCount " << delAckCount << "\n";
|
|
|
|
|
myfile << "stopTime " << stopTime.As(Time::S) << "\n";
|
|
|
|
|
myfile.close();
|
|
|
|
|
|
|
|
|
|
Simulator::Destroy();
|
|
|
|
|
|
2024-01-31 19:12:37 +05:30
|
|
|
fPlotQueue.close();
|
|
|
|
|
fPlotCwnd.close();
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return 0;
|
2019-08-04 20:47:51 -07:00
|
|
|
}
|