Files
unison/examples/tcp/tcp-linux-reno.cc

294 lines
11 KiB
C++
Raw Permalink Normal View History

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.
// - 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
// - 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;
std::string dir = "results/";
2022-10-07 20:08:35 +00:00
Time stopTime = Seconds(60);
uint32_t segmentSize = 524;
2019-08-04 20:47:51 -07:00
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
{
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);
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);
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)));
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;
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
}
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");
// 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();
fPlotQueue.close();
fPlotCwnd.close();
2022-10-07 20:08:35 +00:00
return 0;
2019-08-04 20:47:51 -07:00
}