从ns-3.33版本开始,NS3支持CUBIC。
从ns-3.34版本开始,支持BBR v1。
呜呜呜,感谢前人!!!
我用的是ns-3.34, 代码直接改自ns-3.34/examples/tcp/tcp-linux-reno.cc, 呃。也不用改,直接拷贝到scratch文件夹下运行就行…不过运行的只有reno,可以稍微,稍微改一丢丢:
可以运行:NewReno,Reno,BBR, CUBIC,Veno等拥塞控制算法
// Network topology
//
// n0 ---------- n1 ---------- n2 ---------- n3
// 10 Mbps 1 Mbps 10 Mbps
// 1 ms 10 ms 1 ms
#include
#include
#include
#include
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/traffic-control-module.h"
#include "ns3/flow-monitor-module.h"
using namespace ns3;
std::string dir = "results/";
Time stopTime = Seconds (200);
uint32_t segmentSize = 524;
// Calculate throughput
uint32_t prev = 0;
Time prevTime = Seconds (0);
static void
TraceThroughput (Ptr monitor)
{
FlowMonitor::FlowStatsContainer stats = monitor->GetFlowStats ();
auto itr = stats.begin ();
Time curTime = Now ();
std::ofstream thr (dir + "/throughput.dat", std::ios::out | std::ios::app);
thr << curTime << " " << 8 * (itr->second.txBytes - prev) / (1000 * 1000 * (curTime.GetSeconds () - prevTime.GetSeconds ())) << std::endl;
prevTime = curTime;
prev = itr->second.txBytes;
Simulator::Schedule (Seconds (0.2), &TraceThroughput, monitor);
}
// Function to check queue length of Router 1
void
CheckQueueSize (Ptr queue)
{
uint32_t qSize = queue->GetCurrentSize ().GetValue ();
// Check queue size every 1/100 of a second
Simulator::Schedule (Seconds (0.001), &CheckQueueSize, queue);
std::ofstream fPlotQueue (std::stringstream (dir + "queue-size.dat").str ().c_str (), std::ios::out | std::ios::app);
fPlotQueue << Simulator::Now ().GetSeconds () << " " << qSize << std::endl;
fPlotQueue.close ();
}
// Function to trace change in cwnd at n0
static void
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
std::ofstream fPlotQueue (dir + "cwndTraces/n0.dat", std::ios::out | std::ios::app);
fPlotQueue << Simulator::Now ().GetSeconds () << " " << newCwnd / segmentSize << std::endl;
fPlotQueue.close ();
}
// Function to calculate drops in a particular Queue
static void
DropAtQueue (Ptr stream, Ptr item)
{
*stream->GetStream () << Simulator::Now ().GetSeconds () << " 1" << std::endl;
}
// Trace Function for cwnd
void
TraceCwnd (uint32_t node, uint32_t cwndWindow,
Callback CwndTrace)
{
Config::ConnectWithoutContext ("/NodeList/" + std::to_string (node) + "/$ns3::TcpL4Protocol/SocketList/" + std::to_string (cwndWindow) + "/CongestionWindow", CwndTrace);
}
// Function to install BulkSend application
void InstallBulkSend (Ptr node, Ipv4Address address, uint16_t port, std::string socketFactory,
uint32_t nodeId, uint32_t cwndWindow,
Callback CwndTrace)
{
BulkSendHelper source (socketFactory, InetSocketAddress (address, port));
source.SetAttribute ("MaxBytes", UintegerValue (0));
ApplicationContainer sourceApps = source.Install (node);
sourceApps.Start (Seconds (10.0));
Simulator::Schedule (Seconds (10.0) + Seconds (0.001), &TraceCwnd, nodeId, cwndWindow, CwndTrace);
sourceApps.Stop (stopTime);
}
// Function to install sink application
void InstallPacketSink (Ptr node, uint16_t port, std::string socketFactory)
{
PacketSinkHelper sink (socketFactory, InetSocketAddress (Ipv4Address::GetAny (), port));
ApplicationContainer sinkApps = sink.Install (node);
sinkApps.Start (Seconds (10.0));
sinkApps.Stop (stopTime);
}
int main (int argc, char *argv[])
{
uint32_t stream = 1;
std::string socketFactory = "ns3::TcpSocketFactory";
//如果要用不同的拥塞控制算法改下面的就行
// std::string tcpTypeId = "ns3::TcpLinuxReno";
// std::string tcpTypeId = "ns3::TcpNewReno";
// std::string tcpTypeId = "ns3::TcpVeno";
// std::string tcpTypeId = "ns3::TcpBic";
// std::string tcpTypeId = "ns3::TcpBbr";
std::string tcpTypeId = "ns3::TcpCubic";
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)));
if (tcpTypeId.compare ("ns3::TcpWestwoodPlus") == 0)
{
// TcpWestwoodPlus is not an actual TypeId name; we need TcpWestwood here
Config::SetDefault ("ns3::TcpL4Protocol::SocketType", TypeIdValue (TcpWestwood::GetTypeId ()));
// the default protocol type in ns3::TcpWestwood is WESTWOOD
Config::SetDefault ("ns3::TcpWestwood::ProtocolType", EnumValue (TcpWestwood::WESTWOODPLUS));
}
else
{
TypeId tcpTid;
NS_ABORT_MSG_UNLESS (TypeId::LookupByNameFailSafe (tcpTypeId, &tcpTid), "TypeId " << tcpTypeId << " not found");
Config::SetDefault ("ns3::TcpL4Protocol::SocketType", TypeIdValue (TypeId::LookupByName (tcpTypeId)));
}
// Create nodes
NodeContainer leftNodes, rightNodes, routers;
routers.Create (2);
leftNodes.Create (1);
rightNodes.Create (1);
std::vector leftToRouter;
std::vector routerToRight;
// 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));
// 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)));
InternetStackHelper internetStack;
internetStack.Install (leftNodes);
internetStack.Install (rightNodes);
internetStack.Install (routers);
// Assign IP addresses to all the network devices
Ipv4AddressHelper ipAddresses ("10.0.0.0", "255.255.255.0");
Ipv4InterfaceContainer r1r2IPAddress = ipAddresses.Assign (r1r2ND);
ipAddresses.NewNetwork ();
std::vector leftToRouterIPAddress;
leftToRouterIPAddress.push_back (ipAddresses.Assign (leftToRouter [0]));
ipAddresses.NewNetwork ();
std::vector routerToRightIPAddress;
routerToRightIPAddress.push_back (ipAddresses.Assign (routerToRight [0]));
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
// 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));
// Set default initial congestion window as 10 segments
Config::SetDefault ("ns3::TcpSocket::InitialCwnd", UintegerValue (10));
// Set default delayed ack count to a specified value
Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (delAckCount));
// Set default segment size of TCP packet to a specified value
Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (segmentSize));
// Enable/Disable SACK in TCP
Config::SetDefault ("ns3::TcpSocketBase::Sack", BooleanValue (isSack));
// Create directories to store dat files
struct stat buffer;
int retVal;
if ((stat (dir.c_str (), &buffer)) == 0)
{
std::string dirToRemove = "rm -rf " + dir;
retVal = system (dirToRemove.c_str ());
NS_ASSERT_MSG (retVal == 0, "Error in return value");
}
std::string dirToSave = "mkdir -p " + dir;
retVal = system (dirToSave.c_str ());
NS_ASSERT_MSG (retVal == 0, "Error in return value");
retVal = system ((dirToSave + "/pcap/").c_str ());
NS_ASSERT_MSG (retVal == 0, "Error in return value");
retVal = system ((dirToSave + "/queueTraces/").c_str ());
NS_ASSERT_MSG (retVal == 0, "Error in return value");
retVal = system ((dirToSave + "/cwndTraces/").c_str ());
NS_ASSERT_MSG (retVal == 0, "Error in return value");
NS_UNUSED (retVal);
// 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");
// Calls function to check queue size
Simulator::ScheduleNow (&CheckQueueSize, qd.Get (0));
AsciiTraceHelper asciiTraceHelper;
Ptr 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);
FlowMonitorHelper flowmon;
Ptr monitor = flowmon.InstallAll ();
Simulator::Schedule (Seconds (0 + 0.000001), &TraceThroughput, monitor);
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 ();
return 0;
}
直接用trace的cwnd的结果绘图: