internet: Remove Network Simulation Cradle (NSC)
This commit is contained in:
@@ -58,7 +58,7 @@ us a note on ns-developers mailing list.</p>
|
||||
</ul>
|
||||
<h2>Changes to existing API:</h2>
|
||||
<ul>
|
||||
<li></li>
|
||||
<li>internet: Support for Network Simulation Cradle (NSC) TCP has been removed.</li>
|
||||
</ul>
|
||||
<h2>Changes to build system:</h2>
|
||||
<ul>
|
||||
|
||||
@@ -79,7 +79,6 @@ option(NS3_MONOLIB
|
||||
)
|
||||
option(NS3_MPI "Build with MPI support" ON)
|
||||
option(NS3_NATIVE_OPTIMIZATIONS "Build with -march=native -mtune=native" OFF)
|
||||
option(NS3_NSC "Build with NSC support" OFF) # currently not supported
|
||||
set(NS3_OUTPUT_DIRECTORY "" CACHE STRING "Directory to store built artifacts")
|
||||
option(NS3_PRECOMPILE_HEADERS
|
||||
"Precompile module headers to speed up compilation" ON
|
||||
|
||||
@@ -56,7 +56,6 @@ function(generate_c4che_cachepy)
|
||||
"NS3_MODULE_PATH = ['${PATH_LIST}', '${CMAKE_OUTPUT_DIRECTORY}', '${CMAKE_LIBRARY_OUTPUT_DIRECTORY}']\n"
|
||||
)
|
||||
|
||||
cache_cmake_flag(NS3_NSC "NSC_ENABLED" cache_contents) # missing support
|
||||
cache_cmake_flag(ENABLE_REALTIME "ENABLE_REAL_TIME" cache_contents)
|
||||
cache_cmake_flag(NS3_PTHREAD "ENABLE_THREADING" cache_contents)
|
||||
cache_cmake_flag(ENABLE_EXAMPLES "ENABLE_EXAMPLES" cache_contents)
|
||||
|
||||
@@ -337,7 +337,8 @@ contains the tuple ``(example_name, do_run, do_valgrind_run)``, where
|
||||
crashes with some tests when they are run under valgrind.)
|
||||
|
||||
Note that the two conditions are Python statements that
|
||||
can depend on ``ns3`` configuration variables. For example,
|
||||
can depend on ``ns3`` configuration variables. For example, using the
|
||||
NSC_ENABLED variable that was defined up until ns-3.35:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
|
||||
@@ -1,28 +1,3 @@
|
||||
if(${NS3_NSC})
|
||||
set(name tcp-nsc-lfn)
|
||||
set(source_files ${name}.cc)
|
||||
set(libraries_to_link ${libpoint-to-point} ${libapplications} ${libinternet})
|
||||
build_example(
|
||||
"${name}" "${source_files}" "${header_files}" "${libraries_to_link}"
|
||||
)
|
||||
|
||||
set(name tcp-nsc-zoo)
|
||||
set(source_files ${name}.cc)
|
||||
set(libraries_to_link ${libcsma} ${libinternet} ${libapplications})
|
||||
build_example(
|
||||
"${name}" "${source_files}" "${header_files}" "${libraries_to_link}"
|
||||
)
|
||||
|
||||
set(name tcp-nsc-comparison)
|
||||
set(source_files ${name}.cc)
|
||||
set(libraries_to_link ${libpoint-to-point} ${libinternet} ${libapplications}
|
||||
${libflow-monitor}
|
||||
)
|
||||
build_example(
|
||||
"${name}" "${source_files}" "${header_files}" "${libraries_to_link}"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(name tcp-large-transfer)
|
||||
set(source_files ${name}.cc)
|
||||
set(libraries_to_link ${libpoint-to-point} ${libapplications} ${libinternet})
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
cpp_examples = [
|
||||
("star", "True", "True"),
|
||||
("tcp-large-transfer", "True", "True"),
|
||||
("tcp-nsc-lfn", "NSC_ENABLED == True", "False"),
|
||||
("tcp-nsc-zoo", "NSC_ENABLED == True", "False"),
|
||||
("tcp-star-server", "True", "True"),
|
||||
("tcp-variants-comparison", "True", "True"),
|
||||
("tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=10ms --queueUseEcn=1 --stopTime=15s --validate=dctcp-10ms", "True", "True"),
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2012 NICT
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Author: Hajime Tazaki <tazaki@nict.go.jp>
|
||||
*
|
||||
* This code is a modified version of the code used for the the experiments in the paper
|
||||
* "DCE Cradle: Simulate Network Protocols with Real Stacks for Better Realism"
|
||||
* by Hajime Tazaki, Frederic Urbani and Thierry Turlett presented at WNS3 2013
|
||||
*
|
||||
* By default, TCP timestamps, window scale, and SACK are disabled because
|
||||
* they were not supported in ns-3 at the time of this paper. TCP timestamp
|
||||
* and window scale can be enabled by command line arguments.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#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/flow-monitor-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpNscComparison");
|
||||
|
||||
std::string m_stack = "nsc-linux";
|
||||
std::string sock_factory;
|
||||
uint32_t m_seed = 1;
|
||||
double startTime = 4.0;
|
||||
double stopTime = 20.0;
|
||||
uint32_t m_nNodes = 2;
|
||||
bool enablePcap = false;
|
||||
bool enableTimestamps = false;
|
||||
bool enableWindowScale = false;
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
//ensure the ns3 TCP default values match what nsc is using
|
||||
Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1448));
|
||||
Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1));
|
||||
|
||||
CommandLine cmd (__FILE__);
|
||||
cmd.AddValue ("stack", "choose network stack", m_stack);
|
||||
cmd.AddValue ("seed", "randomize seed", m_seed);
|
||||
cmd.AddValue ("nNodes", "the number of source and sink nodes", m_nNodes);
|
||||
cmd.AddValue ("stopTime", "duration", stopTime);
|
||||
cmd.AddValue ("enablePcap", "pcap", enablePcap);
|
||||
cmd.AddValue ("enableTimestamps", "use TCP Timestamps option", enableTimestamps);
|
||||
cmd.AddValue ("enableWindowScale", "use TCP Window Scale option", enableWindowScale);
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
SeedManager::SetSeed (m_seed);
|
||||
|
||||
if (m_stack != "nsc-linux" && m_stack != "ns3")
|
||||
{
|
||||
NS_FATAL_ERROR ("Error, stack named " << m_stack << " is not supported");
|
||||
}
|
||||
|
||||
NodeContainer lefts, routers, rights, nodes;
|
||||
lefts.Create (m_nNodes);
|
||||
routers.Create (2);
|
||||
rights.Create (m_nNodes);
|
||||
nodes = NodeContainer (lefts, routers, rights);
|
||||
|
||||
InternetStackHelper internetStack;
|
||||
|
||||
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
|
||||
if (m_stack == "ns3")
|
||||
{
|
||||
sock_factory = "ns3::TcpSocketFactory";
|
||||
if (enableTimestamps == false)
|
||||
{
|
||||
Config::SetDefault ("ns3::TcpSocketBase::WindowScaling", BooleanValue (false));
|
||||
}
|
||||
if (enableWindowScale == false)
|
||||
{
|
||||
Config::SetDefault ("ns3::TcpSocketBase::Timestamp", BooleanValue (false));
|
||||
}
|
||||
internetStack.Install (nodes);
|
||||
}
|
||||
else if (m_stack == "nsc-linux")
|
||||
{
|
||||
internetStack.Install (routers);
|
||||
sock_factory = "ns3::TcpSocketFactory";
|
||||
internetStack.SetTcp ("ns3::NscTcpL4Protocol",
|
||||
"Library", StringValue ("liblinux2.6.26.so"));
|
||||
internetStack.Install (lefts);
|
||||
internetStack.Install (rights);
|
||||
|
||||
// at the time this program was written, these were not implemented
|
||||
// in ns3 tcp, so disable for comparison
|
||||
Config::Set ("/NodeList/*/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_sack", StringValue ("0"));
|
||||
if (enableTimestamps == false)
|
||||
{
|
||||
Config::Set ("/NodeList/*/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_timestamps", StringValue ("0"));
|
||||
}
|
||||
if (enableWindowScale == false)
|
||||
{
|
||||
Config::Set ("/NodeList/*/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_window_scaling", StringValue ("0"));
|
||||
}
|
||||
}
|
||||
|
||||
PointToPointHelper pointToPoint;
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("1ns"));
|
||||
|
||||
Ipv4AddressHelper address;
|
||||
Ipv4InterfaceContainer interfaces;
|
||||
|
||||
NetDeviceContainer dev0, dev1, dev2;
|
||||
for (uint32_t i = 0; i < m_nNodes; i++)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "10.0." << i << ".0";
|
||||
address.SetBase (oss.str ().c_str (), "255.255.255.0");
|
||||
dev0 = pointToPoint.Install (NodeContainer (lefts.Get (i), routers.Get (0)));
|
||||
address.Assign (dev0);
|
||||
}
|
||||
|
||||
// bottle neck link
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("2Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("100ms"));
|
||||
dev1 = pointToPoint.Install (NodeContainer (routers.Get (0), routers.Get (1)));
|
||||
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("1ns"));
|
||||
// for right links
|
||||
for (uint32_t i = 0; i < m_nNodes; i++)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "10.2." << i << ".0";
|
||||
address.SetBase (oss.str ().c_str (), "255.255.255.0");
|
||||
dev2 = pointToPoint.Install (NodeContainer (routers.Get (1), rights.Get (i)));
|
||||
address.Assign (dev2);
|
||||
}
|
||||
|
||||
// bottle neck link
|
||||
Ptr<RateErrorModel> em1 =
|
||||
CreateObjectWithAttributes<RateErrorModel> (
|
||||
"ErrorRate", DoubleValue (0.05),
|
||||
"ErrorUnit", EnumValue (RateErrorModel::ERROR_UNIT_PACKET)
|
||||
);
|
||||
dev1.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em1));
|
||||
|
||||
address.SetBase ("10.1.0.0", "255.255.255.0");
|
||||
address.Assign (dev1);
|
||||
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
|
||||
|
||||
ApplicationContainer apps;
|
||||
|
||||
OnOffHelper onoff = OnOffHelper (sock_factory,
|
||||
InetSocketAddress (Ipv4Address ("10.2.0.2"), 2000));
|
||||
onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
|
||||
onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
|
||||
|
||||
// Flow 1 - n
|
||||
for (uint32_t i = 0; i < m_nNodes; i++)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "10.2." << i << ".2";
|
||||
onoff.SetAttribute ("Remote", AddressValue (InetSocketAddress (Ipv4Address (oss.str ().c_str ()), 2000)));
|
||||
onoff.SetAttribute ("PacketSize", StringValue ("1024"));
|
||||
onoff.SetAttribute ("DataRate", StringValue ("1Mbps"));
|
||||
onoff.SetAttribute ("StartTime", TimeValue (Seconds (startTime)));
|
||||
apps = onoff.Install (lefts.Get (i));
|
||||
}
|
||||
|
||||
PacketSinkHelper sink = PacketSinkHelper (sock_factory,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), 2000));
|
||||
apps = sink.Install (rights);
|
||||
apps.Start (Seconds (3.9999));
|
||||
|
||||
if (enablePcap)
|
||||
{
|
||||
pointToPoint.EnablePcapAll ("nsc.pcap");
|
||||
}
|
||||
|
||||
Simulator::Stop (Seconds (stopTime));
|
||||
Simulator::Run ();
|
||||
|
||||
Ptr<PacketSink> pktsink;
|
||||
std::cout << "Total ";
|
||||
for (uint32_t i = 0; i < m_nNodes; i++)
|
||||
{
|
||||
pktsink = apps.Get (i)->GetObject<PacketSink> ();
|
||||
std::cout << "Rx(" << i << ") = " << pktsink->GetTotalRx () <<
|
||||
" bytes (" << pktsink->GetTotalRx () * 8 / (stopTime - startTime) << " bps), ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
Simulator::Destroy ();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 6Mb/s, 500ms
|
||||
// n0-----------------n1
|
||||
//
|
||||
// - a 'lossy' network with long delay
|
||||
// - TCP flow from n0 to n1 and from n1 to n0
|
||||
// - pcap traces generated as tcp-nsc-lfn-0-0.pcap and tcp-nsc-lfn-1-0.pcap
|
||||
// Usage (e.g.): ./ns3 --run 'tcp-nsc-lfn --TCP_CONGESTION=hybla --runtime=30'
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#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/ipv4-global-routing-helper.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpNscLfn");
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (4096));
|
||||
Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("6Mbps"));
|
||||
|
||||
// cubic is the default congestion algorithm in Linux 2.6.26
|
||||
std::string tcpCong = "cubic";
|
||||
// this is the default error rate of our link, that is, the the probability of a single
|
||||
// byte being 'corrupted' during transfer.
|
||||
double errRate = 0.000001;
|
||||
// how long the sender should be running, in seconds.
|
||||
unsigned int runtime = 120;
|
||||
// the name of the NSC stack library that should be used
|
||||
std::string nscStack = "liblinux2.6.26.so";
|
||||
|
||||
CommandLine cmd (__FILE__);
|
||||
// Here, we define additional command line options.
|
||||
// This allows a user to override the defaults set above from the command line.
|
||||
cmd.AddValue ("TCP_CONGESTION", "Linux 2.6.26 Tcp Congestion control algorithm to use", tcpCong);
|
||||
cmd.AddValue ("error-rate", "Error rate to apply to link", errRate);
|
||||
cmd.AddValue ("runtime", "How long the applications should send data (default 120 seconds)", runtime);
|
||||
cmd.AddValue ("nscstack", "Set name of NSC stack (shared library) to use (default liblinux2.6.26.so)", nscStack);
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
NodeContainer n;
|
||||
n.Create (2);
|
||||
|
||||
PointToPointHelper p2p;
|
||||
// create point-to-point link with a bandwidth of 6MBit/s and a large delay (0.5 seconds)
|
||||
p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (6 * 1000 * 1000)));
|
||||
p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (500)));
|
||||
|
||||
NetDeviceContainer p2pInterfaces = p2p.Install (n);
|
||||
// The default MTU of the p2p link would be 65535, which doesn't work
|
||||
// well with our default errRate (most packets would arrive corrupted).
|
||||
p2pInterfaces.Get (0)->SetMtu (1500);
|
||||
p2pInterfaces.Get (1)->SetMtu (1500);
|
||||
|
||||
InternetStackHelper internet;
|
||||
// The next statement switches the nodes to 'NSC'-Mode.
|
||||
// It disables the native ns-3 TCP model and loads the NSC library.
|
||||
internet.SetTcp ("ns3::NscTcpL4Protocol","Library",StringValue (nscStack));
|
||||
internet.Install (n);
|
||||
|
||||
if (tcpCong != "cubic") // make sure we only fail if both --nscstack and --TCP_CONGESTION are used
|
||||
{
|
||||
// This uses ns-3s attribute system to set the 'net.ipv4.tcp_congestion_control' sysctl of the
|
||||
// stack.
|
||||
// The same mechanism could be used to e.g. disable TCP timestamps:
|
||||
// Config::Set ("/NodeList/*/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_timestamps", StringValue ("0"));
|
||||
Config::Set ("/NodeList/*/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_congestion_control", StringValue (tcpCong));
|
||||
}
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.0.0.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer ipv4Interfaces = ipv4.Assign (p2pInterfaces);
|
||||
|
||||
DoubleValue rate (errRate);
|
||||
Ptr<RateErrorModel> em1 =
|
||||
CreateObjectWithAttributes<RateErrorModel> ("RanVar", StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=1.0]"), "ErrorRate", rate);
|
||||
Ptr<RateErrorModel> em2 =
|
||||
CreateObjectWithAttributes<RateErrorModel> ("RanVar", StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=1.0]"), "ErrorRate", rate);
|
||||
|
||||
// This enables the specified errRate on both link endpoints.
|
||||
p2pInterfaces.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (em1));
|
||||
p2pInterfaces.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em2));
|
||||
|
||||
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
|
||||
|
||||
uint16_t servPort = 8080;
|
||||
PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort));
|
||||
ApplicationContainer sinkApp = sinkHelper.Install (n);
|
||||
sinkApp.Start (Seconds (0.0));
|
||||
// this makes sure that the receiver will run one minute longer than the sender applicaton.
|
||||
sinkApp.Stop (Seconds (runtime + 60.0));
|
||||
|
||||
// This sets up two TCP flows, one from A -> B, one from B -> A.
|
||||
for (int i = 0, j = 1; i < 2; j--, i++)
|
||||
{
|
||||
Address remoteAddress (InetSocketAddress (ipv4Interfaces.GetAddress (i), servPort));
|
||||
OnOffHelper clientHelper ("ns3::TcpSocketFactory", remoteAddress);
|
||||
clientHelper.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
|
||||
clientHelper.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
|
||||
ApplicationContainer clientApp = clientHelper.Install (n.Get (j));
|
||||
clientApp.Start (Seconds (1.0 + i));
|
||||
clientApp.Stop (Seconds (runtime + 1.0 + i));
|
||||
}
|
||||
|
||||
// This tells ns-3 to generate pcap traces.
|
||||
p2p.EnablePcapAll ("tcp-nsc-lfn");
|
||||
|
||||
Simulator::Stop (Seconds (900));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Network topology
|
||||
//
|
||||
// n0 n1 n2 n3
|
||||
// | | | |
|
||||
// =================
|
||||
// LAN
|
||||
//
|
||||
// - Pcap traces are saved as tcp-nsc-zoo-$n-0.pcap, where $n represents the node number
|
||||
// - TCP flows from n0 to n1, n2, n3, from n1 to n0, n2, n3, etc.
|
||||
// Usage (e.g.): ./ns3 --run 'tcp-nsc-zoo --nodes=5'
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/network-module.h"
|
||||
#include "ns3/csma-module.h"
|
||||
#include "ns3/internet-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpNscZoo");
|
||||
|
||||
// Simulates a diverse network with various stacks supported by NSC.
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
CsmaHelper csma;
|
||||
unsigned int MaxNodes = 4;
|
||||
unsigned int runtime = 3;
|
||||
|
||||
Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (2048));
|
||||
Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("8kbps"));
|
||||
CommandLine cmd (__FILE__);
|
||||
// this allows the user to raise the number of nodes using --nodes=X command-line argument.
|
||||
cmd.AddValue ("nodes", "Number of nodes in the network (must be > 1)", MaxNodes);
|
||||
cmd.AddValue ("runtime", "How long the applications should send data (default 3 seconds)", runtime);
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
if (MaxNodes < 2)
|
||||
{
|
||||
std::cerr << "--nodes: must be >= 2" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate (100 * 1000 * 1000)));
|
||||
csma.SetChannelAttribute ("Delay", TimeValue (MicroSeconds (200)));
|
||||
|
||||
NodeContainer n;
|
||||
n.Create (MaxNodes);
|
||||
NetDeviceContainer ethInterfaces = csma.Install (n);
|
||||
|
||||
InternetStackHelper internetStack;
|
||||
internetStack.SetTcp ("ns3::NscTcpL4Protocol","Library",StringValue ("liblinux2.6.26.so"));
|
||||
// this switches nodes 0 and 1 to NSCs Linux 2.6.26 stack.
|
||||
internetStack.Install (n.Get (0));
|
||||
internetStack.Install (n.Get (1));
|
||||
// this disables TCP SACK, wscale and timestamps on node 1 (the attributes represent sysctl-values).
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_sack", StringValue ("0"));
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_timestamps", StringValue ("0"));
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_window_scaling", StringValue ("0"));
|
||||
|
||||
if (MaxNodes > 2)
|
||||
{
|
||||
internetStack.Install (n.Get (2));
|
||||
}
|
||||
|
||||
if (MaxNodes > 3)
|
||||
{
|
||||
// the next statement doesn't change anything for the nodes 0, 1, and 2; since they
|
||||
// already have a stack assigned.
|
||||
internetStack.SetTcp ("ns3::NscTcpL4Protocol","Library",StringValue ("liblinux2.6.26.so"));
|
||||
// this switches node 3 to NSCs Linux 2.6.26 stack.
|
||||
internetStack.Install (n.Get (3));
|
||||
// and then again disables sack/timestamps/wscale on node 3.
|
||||
Config::Set ("/NodeList/3/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_sack", StringValue ("0"));
|
||||
Config::Set ("/NodeList/3/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_timestamps", StringValue ("0"));
|
||||
Config::Set ("/NodeList/3/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_window_scaling", StringValue ("0"));
|
||||
}
|
||||
// the freebsd stack is not yet built by default, so its commented out for now.
|
||||
// internetStack.SetNscStack ("libfreebsd5.so");
|
||||
for (unsigned int i =4; i < MaxNodes; i++)
|
||||
{
|
||||
internetStack.Install (n.Get (i));
|
||||
}
|
||||
Ipv4AddressHelper ipv4;
|
||||
|
||||
ipv4.SetBase ("10.0.0.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer ipv4Interfaces = ipv4.Assign (ethInterfaces);
|
||||
|
||||
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
|
||||
|
||||
uint16_t servPort = 8080;
|
||||
PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort));
|
||||
// start a sink client on all nodes
|
||||
ApplicationContainer sinkApp = sinkHelper.Install (n);
|
||||
sinkApp.Start (Seconds (0));
|
||||
sinkApp.Stop (Seconds (30.0));
|
||||
|
||||
// This tells every node on the network to start a flow to all other nodes on the network ...
|
||||
for (unsigned int i = 0; i < MaxNodes; i++)
|
||||
{
|
||||
for (unsigned int j = 0; j < MaxNodes; j++)
|
||||
{
|
||||
if (i == j)
|
||||
{ // ...but we don't want a node to talk to itself.
|
||||
continue;
|
||||
}
|
||||
Address remoteAddress (InetSocketAddress (ipv4Interfaces.GetAddress (j), servPort));
|
||||
OnOffHelper clientHelper ("ns3::TcpSocketFactory", remoteAddress);
|
||||
clientHelper.SetAttribute
|
||||
("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
|
||||
clientHelper.SetAttribute
|
||||
("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
|
||||
ApplicationContainer clientApp = clientHelper.Install (n.Get (i));
|
||||
clientApp.Start (Seconds (j)); /* delay startup depending on node number */
|
||||
clientApp.Stop (Seconds (j + runtime));
|
||||
}
|
||||
}
|
||||
|
||||
csma.EnablePcapAll ("tcp-nsc-zoo", false);
|
||||
|
||||
Simulator::Stop (Seconds (100));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5,14 +5,6 @@ def build(bld):
|
||||
['point-to-point', 'applications', 'internet'])
|
||||
obj.source = 'tcp-large-transfer.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-nsc-lfn',
|
||||
['point-to-point', 'applications', 'internet'])
|
||||
obj.source = 'tcp-nsc-lfn.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-nsc-zoo',
|
||||
['csma', 'internet', 'applications'])
|
||||
obj.source = 'tcp-nsc-zoo.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-star-server',
|
||||
['point-to-point', 'applications', 'internet'])
|
||||
obj.source = 'tcp-star-server.cc'
|
||||
@@ -29,11 +21,6 @@ def build(bld):
|
||||
['point-to-point', 'applications', 'internet'])
|
||||
obj.source = 'tcp-pcap-nanosec-example.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-nsc-comparison',
|
||||
['point-to-point', 'internet', 'applications', 'flow-monitor'])
|
||||
|
||||
obj.source = 'tcp-nsc-comparison.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-variants-comparison',
|
||||
['point-to-point', 'internet', 'applications', 'flow-monitor'])
|
||||
|
||||
|
||||
@@ -1,18 +1,6 @@
|
||||
set(name internet)
|
||||
|
||||
set(nsc_sources)
|
||||
set(nsc_headers)
|
||||
if(${NS3_NSC})
|
||||
set(nsc_sources nsc-sysctl.cc nsc-tcp-l4-protocol.cc
|
||||
nsc-tcp-socket-factory-impl.cc nsc-tcp-socket-impl.cc
|
||||
)
|
||||
set(nsc_headers nsc-sysctl.h nsc-tcp-l4-protocol.h
|
||||
nsc-tcp-socket-factory-impl.h nsc-tcp-socket-impl.h
|
||||
)
|
||||
endif()
|
||||
|
||||
set(source_files
|
||||
${nsc_sources}
|
||||
helper/internet-stack-helper.cc
|
||||
helper/internet-trace-helper.cc
|
||||
helper/ipv4-address-helper.cc
|
||||
|
||||
@@ -25,16 +25,12 @@ There are three important abstract base classes:
|
||||
* class :cpp:class:`TcpCongestionOps`: This supports different variants of
|
||||
congestion control-- a key topic of simulation-based TCP research.
|
||||
|
||||
There are presently two active and one legacy implementations of TCP available for |ns3|.
|
||||
There are presently two active implementations of TCP available for |ns3|.
|
||||
|
||||
* a natively implemented TCP for ns-3
|
||||
* support for kernel implementations via `Direct Code Execution (DCE) <https://www.nsnam.org/overview/projects/direct-code-execution/>`__
|
||||
* (legacy) support for kernel implementations for the `Network Simulation Cradle (NSC) <http://www.wand.net.nz/~stj2/nsc/>`__
|
||||
|
||||
NSC is no longer actively supported; it requires use of gcc-5 or gcc-4.9, and
|
||||
only covers up to Linux kernel version 2.6.29.
|
||||
|
||||
Direct Code Execution is also limited in its support for newer kernels; at
|
||||
Direct Code Execution is limited in its support for newer kernels; at
|
||||
present, only Linux kernel 4.4 is supported. However, the TCP implementations
|
||||
in kernel 4.4 can still be used for ns-3 validation or for specialized
|
||||
simulation use cases.
|
||||
@@ -137,8 +133,7 @@ The careful reader will note above that we have specified the TypeId of an
|
||||
abstract base class :cpp:class:`TcpSocketFactory`. How does the script tell
|
||||
|ns3| that it wants the native |ns3| TCP vs. some other one? Well, when
|
||||
internet stacks are added to the node, the default TCP implementation that is
|
||||
aggregated to the node is the |ns3| TCP. This can be overridden as we show
|
||||
below when using Network Simulation Cradle. So, by default, when using the |ns3|
|
||||
aggregated to the node is the |ns3| TCP. So, by default, when using the |ns3|
|
||||
helper API, the TCP that is aggregated to nodes with an Internet stack is the
|
||||
native |ns3| TCP.
|
||||
|
||||
@@ -1406,14 +1401,9 @@ section below on :ref:`Writing-tcp-tests`.
|
||||
* **tcp-pacing-test:** Unit tests on dynamic TCP pacing rate
|
||||
|
||||
Several tests have dependencies outside of the ``internet`` module, so they
|
||||
are located in a system test directory called ``src/test/ns3tcp``. Three
|
||||
of these six tests involve use of the Network Simulation Cradle, and are
|
||||
disabled if NSC is not enabled in the build.
|
||||
are located in a system test directory called ``src/test/ns3tcp``.
|
||||
|
||||
* **ns3-tcp-cwnd:** Check to see that ns-3 TCP congestion control works against liblinux2.6.26.so implementation
|
||||
* **ns3-tcp-interoperability:** Check to see that ns-3 TCP interoperates with liblinux2.6.26.so implementation
|
||||
* **ns3-tcp-loss:** Check behavior of ns-3 TCP upon packet losses
|
||||
* **nsc-tcp-loss:** Check behavior of NSC TCP upon packet losses
|
||||
* **ns3-tcp-no-delay:** Check that ns-3 TCP Nagle's algorithm works correctly and that it can be disabled
|
||||
* **ns3-tcp-socket:** Check that ns-3 TCP successfully transfers an application data write of various sizes
|
||||
* **ns3-tcp-state:** Check the operation of the TCP state machine for several cases
|
||||
@@ -2171,307 +2161,3 @@ and then, hit "Run".
|
||||
process. For instance, commits created to make this test case running without
|
||||
errors are 11633:6b74df04cf44, (others to be merged).
|
||||
|
||||
Network Simulation Cradle
|
||||
*************************
|
||||
|
||||
The `Network Simulation Cradle (NSC) <http://www.wand.net.nz/~stj2/nsc/>`_ is a
|
||||
framework for wrapping real-world network code into simulators, allowing
|
||||
simulation of real-world behavior at little extra cost. This work has been
|
||||
validated by comparing situations using a test network with the same situations
|
||||
in the simulator. To date, it has been shown that the NSC is able to produce
|
||||
extremely accurate results. NSC supports four real world stacks: FreeBSD,
|
||||
OpenBSD, lwIP and Linux. Emphasis has been placed on not changing any of the
|
||||
network stacks by hand. Not a single line of code has been changed in the
|
||||
network protocol implementations of any of the above four stacks. However, a
|
||||
custom C parser was built to programmatically change source code.
|
||||
|
||||
NSC has previously been ported to |ns2| and OMNeT++, and was
|
||||
was added to |ns3| in September 2008 (ns-3.2 release). This section
|
||||
describes the |ns3| port of NSC and how to use it.
|
||||
|
||||
NSC has been obsoleted by the Linux kernel support within
|
||||
`Direct Code Execution (DCE) <http://www.nsnam.org/docs/dce/manual/singlehtml/index.html>`__. However, NSC is still available through the bake build
|
||||
system. NSC supports Linux kernels 2.6.18 and 2.6.26, and an experimental
|
||||
version of 2.6.29 exists on ns-3's code server
|
||||
(http://code.nsnam.org/fw/nsc-linux-2.6.29/), but newer
|
||||
versions of the kernel have not been ported.
|
||||
|
||||
Prerequisites
|
||||
+++++++++++++
|
||||
|
||||
Presently, NSC has been tested and shown to work on these platforms:
|
||||
Linux i386 and Linux x86-64. NSC does not support powerpc. Use on
|
||||
FreeBSD or OS X is unsupported (although it may be able to work).
|
||||
|
||||
Building NSC requires the packages flex and bison.
|
||||
|
||||
NSC requires use of gcc-4.9 or gcc-5 series, and will not build on
|
||||
newer systems lacking the older compilers.
|
||||
|
||||
Configuring and Downloading
|
||||
+++++++++++++++++++++++++++
|
||||
|
||||
NSC must either be downloaded separately from
|
||||
its own repository, or downloading when using the
|
||||
`bake build system <http://www.nsnam.org/docs/tutorial/html/getting-started.html#downloading-ns3-using-bake>`_ of
|
||||
|ns3|.
|
||||
|
||||
For ns-3.17 through ns-3.28 releases, when using bake, one obtains NSC implicitly as part of an "allinone" configuration, such as:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ cd bake
|
||||
$ python bake.py configure -e ns-allinone-3.27
|
||||
$ python bake.py download
|
||||
$ python bake.py build
|
||||
|
||||
For ns-3.29 and later versions, including the 'ns-3-allinone' development
|
||||
version, one must explicitly add NSC ('nsc-0.5.3') to the bake configuration,
|
||||
such as:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ cd bake
|
||||
$ python bake.py configure -e ns-allinone-3.29 -e nsc-0.5.3
|
||||
$ python bake.py download
|
||||
$ python bake.py build
|
||||
|
||||
Instead of a released version, one may use the ns-3 development version
|
||||
by specifying "ns-3-allinone" to the configure step above.
|
||||
|
||||
NSC may also be downloaded from
|
||||
`its download site <http://research.wand.net.nz/software/nsc.php>`_
|
||||
using Mercurial:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ hg clone https://secure.wand.net.nz/mercurial/nsc
|
||||
|
||||
Prior to the ns-3.17 release, NSC was included in the allinone tarball and
|
||||
the released version did not need to be separately downloaded.
|
||||
|
||||
Building and validating
|
||||
+++++++++++++++++++++++
|
||||
|
||||
NSC may be built as part of the bake build process; alternatively, one
|
||||
may build NSC by itself using its build system; e.g.:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ cd nsc-dev
|
||||
$ python scons.py
|
||||
|
||||
Once NSC has been built either manually or through the bake system, change
|
||||
into the |ns3| source directory and try running the following configuration:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ ./ns3 configure
|
||||
|
||||
If NSC has been previously built and found by ns3, then you will see:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
Network Simulation Cradle : enabled
|
||||
|
||||
If NSC has not been found, you will see:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
Network Simulation Cradle : not enabled (NSC not found (see option --with-nsc))
|
||||
|
||||
In this case, you must pass the relative or absolute path to the NSC libraries
|
||||
with the "--with-nsc" configure option; e.g.
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ ./ns3 configure --with-nsc=/path/to/my/nsc/directory
|
||||
|
||||
For |ns3| releases prior to the ns-3.17 release, using the ``build.py``
|
||||
script in ns-3-allinone directory, NSC will be built by default unless the
|
||||
platform does not support it. To explicitly disable it when building |ns3|,
|
||||
type:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ ./ns3 configure --enable-examples --enable-tests --disable-nsc
|
||||
|
||||
If ns3 detects NSC, then building |ns3| with NSC is performed the same way
|
||||
with ns3 as without it. Once |ns3| is built, try running the following
|
||||
test suite:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ ./test.py -s ns3-tcp-interoperability
|
||||
|
||||
If NSC has been successfully built, the following test should show up
|
||||
in the results:
|
||||
|
||||
.. sourcecode:: text
|
||||
|
||||
PASS TestSuite ns3-tcp-interoperability
|
||||
|
||||
This confirms that NSC is ready to use.
|
||||
|
||||
Usage
|
||||
+++++
|
||||
|
||||
There are a few example files. Try:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ ./ns3 --run tcp-nsc-zoo
|
||||
$ ./ns3 --run tcp-nsc-lfn
|
||||
|
||||
These examples will deposit some ``.pcap`` files in your directory,
|
||||
which can be examined by tcpdump or wireshark.
|
||||
|
||||
Let's look at the ``examples/tcp/tcp-nsc-zoo.cc`` file for some typical
|
||||
usage. How does it differ from using native |ns3| TCP? There is one main
|
||||
configuration line, when using NSC and the |ns3| helper API, that needs to be
|
||||
set::
|
||||
|
||||
InternetStackHelper internetStack;
|
||||
|
||||
internetStack.SetNscStack ("liblinux2.6.26.so");
|
||||
// this switches nodes 0 and 1 to NSCs Linux 2.6.26 stack.
|
||||
internetStack.Install (n.Get(0));
|
||||
internetStack.Install (n.Get(1));
|
||||
|
||||
|
||||
The key line is the ``SetNscStack``. This tells the InternetStack
|
||||
helper to aggregate instances of NSC TCP instead of native |ns3| TCP
|
||||
to the remaining nodes. It is important that this function be called
|
||||
**before** calling the ``Install()`` function, as shown above.
|
||||
|
||||
Which stacks are available to use? Presently, the focus has been on
|
||||
Linux 2.6.18 and Linux 2.6.26 stacks for |ns3|. To see which stacks
|
||||
were built, one can execute the following find command at the |ns3| top level
|
||||
directory:
|
||||
|
||||
.. sourcecode:: bash
|
||||
|
||||
$ find nsc -name "*.so" -type f
|
||||
nsc/linux-2.6.18/liblinux2.6.18.so
|
||||
nsc/linux-2.6.26/liblinux2.6.26.so
|
||||
|
||||
This tells us that we may either pass the library name liblinux2.6.18.so or
|
||||
liblinux2.6.26.so to the above configuration step.
|
||||
|
||||
Stack configuration
|
||||
+++++++++++++++++++
|
||||
|
||||
NSC TCP shares the same configuration attributes that are common across TCP
|
||||
sockets, as described above and documented in `Doxygen
|
||||
<http://www.nsnam.org/doxygen/classns3_1_1_tcp_socket.html>`_
|
||||
|
||||
Additionally, NSC TCP exports a lot of configuration variables into the
|
||||
|ns3| attributes system, via a `sysctl <http://en.wikipedia.org/wiki/Sysctl>`_-like interface. In the ``examples/tcp/tcp-nsc-zoo`` example, you
|
||||
can see the following configuration::
|
||||
|
||||
|
||||
// this disables TCP SACK, wscale and timestamps on node 1 (the attributes
|
||||
represent sysctl-values).
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_sack",
|
||||
StringValue ("0"));
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_timestamps",
|
||||
StringValue ("0"));
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_window_scaling",
|
||||
StringValue ("0"));
|
||||
|
||||
These additional configuration variables are not available to native |ns3| TCP.
|
||||
|
||||
Also note that default values for TCP attributes in |ns3| TCP may differ from the NSC TCP implementation. Specifically in |ns3|:
|
||||
|
||||
1) TCP default MSS is 536
|
||||
2) TCP Delayed ACK count is 2
|
||||
|
||||
Therefore when making comparisons between results obtained using NSC and |ns3| TCP, care must be taken to ensure these values are set appropriately. See /examples/tcp/tcp-nsc-comparison.cc for an example.
|
||||
|
||||
NSC API
|
||||
+++++++
|
||||
|
||||
This subsection describes the API that NSC presents to |ns3| or any other
|
||||
simulator. NSC provides its API in the form of a number of classes that are
|
||||
defined in ``sim/sim_interface.h`` in the nsc directory.
|
||||
|
||||
* **INetStack** INetStack contains the 'low level' operations for the operating
|
||||
system network stack, e.g. in and output functions from and to the network
|
||||
stack (think of this as the 'network driver interface'). There are also
|
||||
functions to create new TCP or UDP sockets.
|
||||
* **ISendCallback** This is called by NSC when a packet should be sent out to
|
||||
the network. This simulator should use this callback to re-inject the packet
|
||||
into the simulator so the actual data can be delivered/routed to its
|
||||
destination, where it will eventually be handed into Receive() (and eventually
|
||||
back to the receivers NSC instance via INetStack->if_receive()).
|
||||
* **INetStreamSocket** This is the structure defining a particular connection
|
||||
endpoint (file descriptor). It contains methods to operate on this endpoint,
|
||||
e.g. connect, disconnect, accept, listen, send_data/read_data, ...
|
||||
* **IInterruptCallback** This contains the wakeup() callback, which is called by
|
||||
NSC whenever something of interest happens. Think of wakeup() as a replacement
|
||||
of the operating systems wakeup function: Whenever the operating system would
|
||||
wake up a process that has been waiting for an operation to complete (for
|
||||
example the TCP handshake during connect()), NSC invokes the wakeup() callback
|
||||
to allow the simulator to check for state changes in its connection endpoints.
|
||||
|
||||
ns-3 implementation
|
||||
+++++++++++++++++++
|
||||
|
||||
The |ns3| implementation makes use of the above NSC API, and is implemented as
|
||||
follows.
|
||||
|
||||
The three main parts are:
|
||||
|
||||
* :cpp:class:`ns3::NscTcpL4Protocol`: a subclass of Ipv4L4Protocol (and two NSC
|
||||
classes: ISendCallback and IInterruptCallback)
|
||||
* :cpp:class:`ns3::NscTcpSocketImpl`: a subclass of TcpSocket
|
||||
* :cpp:class:`ns3::NscTcpSocketFactoryImpl`: a factory to create new NSC
|
||||
sockets
|
||||
|
||||
``src/internet/model/nsc-tcp-l4-protocol`` is the main class. Upon
|
||||
Initialization, it loads an NSC network stack to use (via dlopen()). Each
|
||||
instance of this class may use a different stack. The stack (=shared library) to
|
||||
use is set using the SetNscLibrary() method (at this time its called indirectly
|
||||
via the internet stack helper). The NSC stack is then set up accordingly (timers
|
||||
etc). The NscTcpL4Protocol::Receive() function hands the packet it receives
|
||||
(must be a complete TCP/IP packet) to the NSC stack for further processing. To
|
||||
be able to send packets, this class implements the NSC send_callback() method.
|
||||
This method is called by NSC whenever the NSC stack wishes to send a packet out
|
||||
to the network. Its arguments are a raw buffer, containing a complete TCP/IP
|
||||
packet, and a length value. This method therefore has to convert the raw data to
|
||||
a Ptr<Packet> usable by |ns3|. In order to avoid various IPv4 header issues,
|
||||
the NSC IP header is not included. Instead, the TCP header and the actual
|
||||
payload are put into the Ptr<Packet>, after this the Packet is passed down to
|
||||
layer 3 for sending the packet out (no further special treatment is needed in
|
||||
the send code path).
|
||||
|
||||
This class calls ``ns3::NscTcpSocketImpl`` both from the NSC wakeup() callback
|
||||
and from the receive path (to ensure that possibly queued data is scheduled for
|
||||
sending).
|
||||
|
||||
``src/internet/model/nsc-tcp-socket-impl`` implements the NSC socket interface.
|
||||
Each instance has its own m_nscTcpSocket. Data that is sent will be handed to
|
||||
the NSC stack via m_nscTcpSocket->send_data() (and not to NscTcpL4Protocol, this
|
||||
is the major difference compared to |ns3| TCP). The class also queues up data
|
||||
that is sent before the underlying descriptor has entered an ESTABLISHED state.
|
||||
This class is called from the NscTcpL4Protocol class, when the NscTcpL4Protocol
|
||||
wakeup() callback is invoked by NSC. NscTcpSocketImpl then checks the current
|
||||
connection state (SYN_SENT, ESTABLISHED, LISTEN...) and schedules appropriate
|
||||
callbacks as needed, e.g. a LISTEN socket will schedule accept() to see if a new
|
||||
connection must be accepted, an ESTABLISHED socket schedules any pending data
|
||||
for writing, schedule a read() callback, etc.
|
||||
|
||||
Note that ``ns3::NscTcpSocketImpl`` does not interact with NSC TCP directly:
|
||||
instead, data is redirected to NSC. NSC TCP calls the NSC TCP sockets of a node
|
||||
when its wakeup() callback is invoked by NSC.
|
||||
|
||||
Limitations
|
||||
+++++++++++
|
||||
|
||||
* NSC only works on single-interface nodes; attempting to run it on a
|
||||
multi-interface node will cause a program error.
|
||||
* Cygwin and OS X PPC are not supported; OS X Intel is not supported but may work
|
||||
* The non-Linux stacks of NSC are not supported in |ns3|
|
||||
* Not all socket API callbacks are supported
|
||||
|
||||
For more information, see `this wiki page <http://www.nsnam.org/wiki/Network_Simulation_Cradle_Integration>`_.
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "ns3/string.h"
|
||||
#include "nsc-sysctl.h"
|
||||
|
||||
#include "sim_interface.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup nsctcp
|
||||
*
|
||||
* This object represent the underlying nsc stack attributes and
|
||||
* provide a ns-3-like system to access them though sysctls
|
||||
*/
|
||||
class NscStackStringAccessor : public AttributeAccessor
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Constructor
|
||||
* \param name name of the attribute
|
||||
*/
|
||||
NscStackStringAccessor (std::string name) : m_name (name) {}
|
||||
|
||||
virtual bool Set (ObjectBase * object, const AttributeValue &val) const;
|
||||
virtual bool Get (const ObjectBase * object, AttributeValue &val) const;
|
||||
virtual bool HasGetter (void) const;
|
||||
virtual bool HasSetter (void) const;
|
||||
private:
|
||||
std::string m_name; //!< name of the attribute
|
||||
};
|
||||
|
||||
bool NscStackStringAccessor::HasGetter (void) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NscStackStringAccessor::HasSetter (void) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NscStackStringAccessor::Set (ObjectBase * object, const AttributeValue & val) const
|
||||
{
|
||||
const StringValue *value = dynamic_cast<const StringValue *> (&val);
|
||||
if (value == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Ns3NscStack *obj = dynamic_cast<Ns3NscStack *> (object);
|
||||
if (obj == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
obj->Set (m_name, value->Get ());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NscStackStringAccessor::Get (const ObjectBase * object, AttributeValue &val) const
|
||||
{
|
||||
StringValue *value = dynamic_cast<StringValue *> (&val);
|
||||
if (value == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const Ns3NscStack *obj = dynamic_cast<const Ns3NscStack *> (object);
|
||||
if (obj == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
value->Set (obj->Get (m_name));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
TypeId
|
||||
Ns3NscStack::GetInstanceTypeId (void) const
|
||||
{
|
||||
if (m_stack == 0)
|
||||
{
|
||||
// if we have no stack, we are a normal NscStack without any attributes.
|
||||
return GetTypeId ();
|
||||
}
|
||||
std::string name = "ns3::Ns3NscStack<";
|
||||
name += m_stack->get_name ();
|
||||
name += ">";
|
||||
TypeId tid;
|
||||
if (TypeId::LookupByNameFailSafe (name, &tid))
|
||||
{
|
||||
// if the relevant TypeId has already been registered, no need to do it again.
|
||||
return tid;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now, we register a new TypeId for this stack which will look
|
||||
// like a subclass of the Ns3NscStack. The class Ns3NscStack is effectively
|
||||
// mutating into a subclass of itself from the point of view of the TypeId
|
||||
// system _here_
|
||||
tid = TypeId (name.c_str ());
|
||||
tid.SetParent<Ns3NscStack> ();
|
||||
char buf[256];
|
||||
for (int i=0; m_stack->sysctl_getnum (i, buf, sizeof(buf)) > 0; i++)
|
||||
{
|
||||
char value[256];
|
||||
if (m_stack->sysctl_get (buf, value, sizeof(value)) > 0)
|
||||
{
|
||||
tid.AddAttribute (buf, "Help text",
|
||||
StringValue (value),
|
||||
Create<NscStackStringAccessor> (buf),
|
||||
MakeStringChecker ());
|
||||
}
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Ns3NscStack::Get (std::string name) const
|
||||
{
|
||||
char buf[512];
|
||||
if (m_stack->sysctl_get (name.c_str (), buf, sizeof(buf)) <= 0)
|
||||
{ // name.c_str () is not a valid sysctl name, or internal NSC error (eg. error converting value)
|
||||
return NULL;
|
||||
}
|
||||
return std::string (buf);
|
||||
}
|
||||
|
||||
void
|
||||
Ns3NscStack::Set (std::string name, std::string value)
|
||||
{
|
||||
int ret = m_stack->sysctl_set (name.c_str (), value.c_str ());
|
||||
if (ret < 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("setting " << name << " to " << value << "failed (retval " << ret << ")");
|
||||
}
|
||||
}
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (Ns3NscStack);
|
||||
|
||||
TypeId
|
||||
Ns3NscStack::Ns3NscStack::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::Ns3NscStack")
|
||||
.SetParent<Object> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -1,70 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ns3/attribute.h"
|
||||
#include "ns3/object.h"
|
||||
|
||||
struct INetStack;
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup nsctcp
|
||||
*
|
||||
* This object represents the underlying nsc stack,
|
||||
* which is aggregated to a Node object, and which provides access to the
|
||||
* sysctls of the nsc stack through attributes.
|
||||
*/
|
||||
class Ns3NscStack : public Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
/**
|
||||
* \brief Set the underlying stack
|
||||
* \param stack the stack
|
||||
*/
|
||||
void SetStack (INetStack *stack) { m_stack = stack; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief NscStackStringAccessor friend class.
|
||||
* \relates NscStackStringAccessor
|
||||
*/
|
||||
friend class NscStackStringAccessor;
|
||||
/**
|
||||
* \brief Set an attribute
|
||||
* \param name the attribute name
|
||||
* \param value the attribute value
|
||||
*/
|
||||
void Set (std::string name, std::string value);
|
||||
/**
|
||||
* \brief Get an attribute
|
||||
* \param name the attribute name
|
||||
* \returns the attribute value
|
||||
*/
|
||||
std::string Get (std::string name) const;
|
||||
INetStack *m_stack; //!< the underlying stack
|
||||
};
|
||||
} // namespace ns3
|
||||
@@ -1,526 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* based on earlier integration work by Tom Henderson and Sam Jansen.
|
||||
* 2008 Florian Westphal <fw@strlen.de>
|
||||
*/
|
||||
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
|
||||
#include "ns3/object-vector.h"
|
||||
#include "ns3/string.h"
|
||||
#include "tcp-header.h"
|
||||
#include "ipv4-end-point-demux.h"
|
||||
#include "ipv4-end-point.h"
|
||||
#include "ipv4-l3-protocol.h"
|
||||
#include "nsc-tcp-l4-protocol.h"
|
||||
#include "nsc-tcp-socket-impl.h"
|
||||
#include "nsc-sysctl.h"
|
||||
#include "nsc-tcp-socket-factory-impl.h"
|
||||
#include "sim_interface.h"
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <dlfcn.h>
|
||||
#include <iomanip>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("NscTcpL4Protocol");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (NscTcpL4Protocol);
|
||||
|
||||
/* see http://www.iana.org/assignments/protocol-numbers */
|
||||
const uint8_t NscTcpL4Protocol::PROT_NUMBER = 6;
|
||||
|
||||
/**
|
||||
* \ingroup nsctcp
|
||||
* \brief Nsc interface implementation class.
|
||||
*/
|
||||
class NscInterfaceImpl : public ISendCallback, public IInterruptCallback
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* \param prot the NSC TCP protocol
|
||||
*/
|
||||
NscInterfaceImpl (Ptr<NscTcpL4Protocol> prot);
|
||||
private:
|
||||
/**
|
||||
* \brief Invoked by NSCs 'ethernet driver' to re-inject a packet into ns-3.
|
||||
*
|
||||
* A packet is an octet soup consisting of an IP Header, TCP Header
|
||||
* and user payload, if any
|
||||
*
|
||||
* \param data the data
|
||||
* \param datalen the data length
|
||||
*/
|
||||
virtual void send_callback (const void *data, int datalen);
|
||||
/**
|
||||
* \brief Called by the NSC stack whenever something of interest has happened
|
||||
*
|
||||
* Examples: when data arrives on a socket, a listen socket
|
||||
* has a new connection pending, etc.
|
||||
*/
|
||||
virtual void wakeup ();
|
||||
/**
|
||||
* \brief Called by the Linux stack RNG initialization
|
||||
*
|
||||
* Its also used by the cradle code to add a timestamp to
|
||||
* printk/printf/debug output.
|
||||
*
|
||||
* \param [out] sec seconds
|
||||
* \param [out] usec microseconds
|
||||
*
|
||||
*/
|
||||
virtual void gettime (unsigned int *sec, unsigned int *usec);
|
||||
private:
|
||||
Ptr<NscTcpL4Protocol> m_prot; //!< the NSC TCP protocol
|
||||
};
|
||||
|
||||
NscInterfaceImpl::NscInterfaceImpl (Ptr<NscTcpL4Protocol> prot)
|
||||
: m_prot (prot)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NscInterfaceImpl::send_callback (const void *data, int datalen)
|
||||
{
|
||||
m_prot->send_callback (data, datalen);
|
||||
}
|
||||
void
|
||||
NscInterfaceImpl::wakeup ()
|
||||
{
|
||||
m_prot->wakeup ();
|
||||
}
|
||||
void
|
||||
NscInterfaceImpl::gettime (unsigned int *sec, unsigned int *usec)
|
||||
{
|
||||
m_prot->gettime (sec,usec);
|
||||
}
|
||||
|
||||
|
||||
#undef NS_LOG_APPEND_CONTEXT
|
||||
#define NS_LOG_APPEND_CONTEXT \
|
||||
if (m_node) { std::clog << Simulator::Now ().As (Time::S) << " [node " << m_node->GetId () << "] "; }
|
||||
|
||||
TypeId
|
||||
NscTcpL4Protocol::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::NscTcpL4Protocol")
|
||||
.SetParent<IpL4Protocol> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddConstructor<NscTcpL4Protocol>()
|
||||
.AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
|
||||
ObjectVectorValue (),
|
||||
MakeObjectVectorAccessor (&NscTcpL4Protocol::m_sockets),
|
||||
MakeObjectVectorChecker<NscTcpSocketImpl> ())
|
||||
.AddAttribute ("Library",
|
||||
"Set the linux library to be used to create the stack",
|
||||
TypeId::ATTR_GET|TypeId::ATTR_CONSTRUCT,
|
||||
StringValue ("liblinux2.6.26.so"),
|
||||
MakeStringAccessor (&NscTcpL4Protocol::GetNscLibrary,&NscTcpL4Protocol::SetNscLibrary),
|
||||
MakeStringChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief External Random number generator
|
||||
*
|
||||
* \todo make it random...
|
||||
*
|
||||
* \returns a random number
|
||||
*/
|
||||
int external_rand ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
NscTcpL4Protocol::NscTcpL4Protocol ()
|
||||
: m_endPoints (new Ipv4EndPointDemux ()),
|
||||
m_nscStack (0),
|
||||
m_nscInterface (new NscInterfaceImpl (this)),
|
||||
m_softTimer (Timer::CANCEL_ON_DESTROY)
|
||||
{
|
||||
m_dlopenHandle = NULL;
|
||||
NS_LOG_LOGIC ("Made a NscTcpL4Protocol "<<this);
|
||||
}
|
||||
|
||||
NscTcpL4Protocol::~NscTcpL4Protocol ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
dlclose (m_dlopenHandle);
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpL4Protocol::SetNscLibrary (const std::string &soname)
|
||||
{
|
||||
if (soname!="")
|
||||
{
|
||||
m_nscLibrary = soname;
|
||||
NS_ASSERT (!m_dlopenHandle);
|
||||
m_dlopenHandle = dlopen (soname.c_str (), RTLD_NOW);
|
||||
if (m_dlopenHandle == NULL)
|
||||
NS_FATAL_ERROR (dlerror ());
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
NscTcpL4Protocol::GetNscLibrary () const
|
||||
{
|
||||
return m_nscLibrary;
|
||||
}
|
||||
void
|
||||
NscTcpL4Protocol::SetNode (Ptr<Node> node)
|
||||
{
|
||||
m_node = node;
|
||||
|
||||
if (m_nscStack)
|
||||
{ // stack has already been loaded...
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERT (m_dlopenHandle);
|
||||
|
||||
FCreateStack create = (FCreateStack)dlsym (m_dlopenHandle, "nsc_create_stack");
|
||||
NS_ASSERT (create);
|
||||
m_nscStack = create (m_nscInterface, m_nscInterface, external_rand);
|
||||
int hzval = m_nscStack->get_hz ();
|
||||
|
||||
NS_ASSERT (hzval > 0);
|
||||
|
||||
m_softTimer.SetFunction (&NscTcpL4Protocol::SoftInterrupt, this);
|
||||
m_softTimer.SetDelay (MilliSeconds (1000/hzval));
|
||||
m_nscStack->init (hzval);
|
||||
// This enables stack and NSC debug messages
|
||||
// m_nscStack->set_diagnostic(1000);
|
||||
|
||||
Ptr<Ns3NscStack> nscStack = Create<Ns3NscStack> ();
|
||||
nscStack->SetStack (m_nscStack);
|
||||
node->AggregateObject (nscStack);
|
||||
|
||||
m_softTimer.Schedule ();
|
||||
|
||||
// its likely no ns-3 interface exits at this point, so
|
||||
// we dealy adding the nsc interface until the start of the simulation.
|
||||
Simulator::ScheduleNow (&NscTcpL4Protocol::AddInterface, this);
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpL4Protocol::NotifyNewAggregate ()
|
||||
{
|
||||
if (m_node == 0)
|
||||
{
|
||||
Ptr<Node>node = this->GetObject<Node> ();
|
||||
if (node != 0)
|
||||
{
|
||||
Ptr<Ipv4L3Protocol> ipv4 = this->GetObject<Ipv4L3Protocol> ();
|
||||
if (ipv4 != 0 && m_downTarget.IsNull ())
|
||||
{
|
||||
this->SetNode (node);
|
||||
ipv4->Insert (this);
|
||||
Ptr<NscTcpSocketFactoryImpl> tcpFactory = CreateObject<NscTcpSocketFactoryImpl> ();
|
||||
tcpFactory->SetTcp (this);
|
||||
node->AggregateObject (tcpFactory);
|
||||
this->SetDownTarget (MakeCallback (&Ipv4L3Protocol::Send, ipv4));
|
||||
}
|
||||
}
|
||||
}
|
||||
IpL4Protocol::NotifyNewAggregate ();
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpL4Protocol::GetProtocolNumber (void) const
|
||||
{
|
||||
return PROT_NUMBER;
|
||||
}
|
||||
int
|
||||
NscTcpL4Protocol::GetVersion (void) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpL4Protocol::DoDispose (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
for (std::vector<Ptr<NscTcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
|
||||
{
|
||||
*i = 0;
|
||||
}
|
||||
m_sockets.clear ();
|
||||
|
||||
|
||||
if (m_endPoints != 0)
|
||||
{
|
||||
delete m_endPoints;
|
||||
m_endPoints = 0;
|
||||
}
|
||||
m_node = 0;
|
||||
delete m_nscInterface;
|
||||
m_nscInterface = 0;
|
||||
m_downTarget.Nullify ();
|
||||
IpL4Protocol::DoDispose ();
|
||||
}
|
||||
|
||||
Ptr<Socket>
|
||||
NscTcpL4Protocol::CreateSocket (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<NscTcpSocketImpl> socket = CreateObject<NscTcpSocketImpl> ();
|
||||
socket->SetNode (m_node);
|
||||
socket->SetTcp (this);
|
||||
m_sockets.push_back (socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
Ipv4EndPoint *
|
||||
NscTcpL4Protocol::Allocate (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_endPoints->Allocate ();
|
||||
}
|
||||
|
||||
Ipv4EndPoint *
|
||||
NscTcpL4Protocol::Allocate (Ipv4Address address)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << address);
|
||||
return m_endPoints->Allocate (address);
|
||||
}
|
||||
|
||||
Ipv4EndPoint *
|
||||
NscTcpL4Protocol::Allocate (Ptr<NetDevice> boundNetDevice, uint16_t port)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << boundNetDevice << port);
|
||||
return m_endPoints->Allocate (boundNetDevice, port);
|
||||
}
|
||||
|
||||
Ipv4EndPoint *
|
||||
NscTcpL4Protocol::Allocate (Ptr<NetDevice> boundNetDevice, Ipv4Address address, uint16_t port)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << boundNetDevice << address << port);
|
||||
return m_endPoints->Allocate (boundNetDevice, address, port);
|
||||
}
|
||||
|
||||
Ipv4EndPoint *
|
||||
NscTcpL4Protocol::Allocate (Ptr<NetDevice> boundNetDevice,
|
||||
Ipv4Address localAddress, uint16_t localPort,
|
||||
Ipv4Address peerAddress, uint16_t peerPort)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << boundNetDevice << localAddress << localPort << peerAddress << peerPort);
|
||||
return m_endPoints->Allocate (boundNetDevice,
|
||||
localAddress, localPort,
|
||||
peerAddress, peerPort);
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << endPoint);
|
||||
// NSC m_endPoints->DeAllocate (endPoint);
|
||||
}
|
||||
|
||||
IpL4Protocol::RxStatus
|
||||
NscTcpL4Protocol::Receive (Ptr<Packet> packet,
|
||||
Ipv4Header const &header,
|
||||
Ptr<Ipv4Interface> incomingInterface)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << packet << header << incomingInterface);
|
||||
Ipv4Header ipHeader;
|
||||
uint32_t packetSize = packet->GetSize ();
|
||||
|
||||
// The way things work at the moment, the IP header has been removed
|
||||
// by the ns-3 IPv4 processing code. However, the NSC stack expects
|
||||
// a complete IP packet, so we add the IP header back.
|
||||
// Since the original header is already gone, we create a new one
|
||||
// based on the information we have.
|
||||
ipHeader.SetSource (header.GetSource ());
|
||||
ipHeader.SetDestination (header.GetDestination ());
|
||||
ipHeader.SetProtocol (PROT_NUMBER);
|
||||
ipHeader.SetPayloadSize (packetSize);
|
||||
ipHeader.SetTtl (1);
|
||||
// all NSC stacks check the IP checksum
|
||||
ipHeader.EnableChecksum ();
|
||||
|
||||
packet->AddHeader (ipHeader);
|
||||
packetSize = packet->GetSize ();
|
||||
|
||||
uint8_t *buf = new uint8_t[packetSize];
|
||||
packet->CopyData (buf, packetSize);
|
||||
const uint8_t *data = const_cast<uint8_t *>(buf);
|
||||
|
||||
// deliver complete packet to the NSC network stack
|
||||
m_nscStack->if_receive_packet (0, data, packetSize);
|
||||
delete[] buf;
|
||||
|
||||
wakeup ();
|
||||
return IpL4Protocol::RX_OK;
|
||||
}
|
||||
|
||||
IpL4Protocol::RxStatus
|
||||
NscTcpL4Protocol::Receive(Ptr<Packet>, Ipv6Header const &, Ptr<Ipv6Interface>)
|
||||
{
|
||||
return IpL4Protocol::RX_ENDPOINT_UNREACH;
|
||||
}
|
||||
|
||||
void NscTcpL4Protocol::SoftInterrupt (void)
|
||||
{
|
||||
m_nscStack->timer_interrupt ();
|
||||
m_nscStack->increment_ticks ();
|
||||
m_softTimer.Schedule ();
|
||||
}
|
||||
|
||||
void NscTcpL4Protocol::send_callback (const void* data, int datalen)
|
||||
{
|
||||
Ptr<Packet> p;
|
||||
uint32_t ipv4Saddr, ipv4Daddr;
|
||||
|
||||
NS_ASSERT (datalen > 20);
|
||||
|
||||
|
||||
// create packet, without IP header. The TCP header is not touched.
|
||||
// Not using the IP header makes integration easier, but it destroys
|
||||
// eg. ECN.
|
||||
const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
|
||||
rawdata += 20; // skip IP header. IP options aren't supported at this time.
|
||||
datalen -= 20;
|
||||
p = Create<Packet> (rawdata, datalen);
|
||||
|
||||
// we need the real source/destination ipv4 addresses for Send ().
|
||||
const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
|
||||
ipv4Saddr = *(ipheader+3);
|
||||
ipv4Daddr = *(ipheader+4);
|
||||
|
||||
Ipv4Address saddr (ntohl (ipv4Saddr));
|
||||
Ipv4Address daddr (ntohl (ipv4Daddr));
|
||||
|
||||
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
|
||||
NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
|
||||
|
||||
m_downTarget (p, saddr, daddr, PROT_NUMBER, 0);
|
||||
m_nscStack->if_send_finish (0);
|
||||
}
|
||||
|
||||
void NscTcpL4Protocol::wakeup ()
|
||||
{
|
||||
// \todo
|
||||
// this should schedule a timer to read from all tcp sockets now... this is
|
||||
// an indication that data might be waiting on the socket
|
||||
|
||||
Ipv4EndPointDemux::EndPoints endPoints = m_endPoints->GetAllEndPoints ();
|
||||
for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
|
||||
endPoint != endPoints.end (); endPoint++) {
|
||||
// NSC HACK: (ab)use TcpSocket::ForwardUp for signalling
|
||||
(*endPoint)->ForwardUp (NULL, Ipv4Header (), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void NscTcpL4Protocol::gettime (unsigned int* sec, unsigned int* usec)
|
||||
{
|
||||
// Only used by the Linux network stack, e.g. during ISN generation
|
||||
// and in the kernel rng initialization routine. Also used in Linux
|
||||
// printk output.
|
||||
Time t = Simulator::Now ();
|
||||
int64_t us = t.GetMicroSeconds ();
|
||||
*sec = us / (1000*1000);
|
||||
*usec = us - *sec * (1000*1000);
|
||||
}
|
||||
|
||||
|
||||
void NscTcpL4Protocol::AddInterface (void)
|
||||
{
|
||||
Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
|
||||
const uint32_t nInterfaces = ip->GetNInterfaces ();
|
||||
|
||||
NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node");
|
||||
|
||||
// start from 1, ignore the loopback interface (HACK)
|
||||
// we really don't need the loop, but its here to illustrate
|
||||
// how things _should_ be (once nsc can deal with multiple interfaces...)
|
||||
for (uint32_t i = 1; i < nInterfaces; i++)
|
||||
{
|
||||
Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
|
||||
Ipv4Address addr = ifAddr.GetLocal ();
|
||||
Ipv4Mask mask = ifAddr.GetMask ();
|
||||
uint16_t mtu = ip->GetMtu (i);
|
||||
|
||||
std::ostringstream addrOss, maskOss;
|
||||
|
||||
addr.Print (addrOss);
|
||||
mask.Print (maskOss);
|
||||
|
||||
NS_LOG_LOGIC ("if_attach " << addrOss.str ().c_str () << " " << maskOss.str ().c_str () << " " << mtu);
|
||||
|
||||
std::string addrStr = addrOss.str ();
|
||||
std::string maskStr = maskOss.str ();
|
||||
const char* addrCStr = addrStr.c_str ();
|
||||
const char* maskCStr = maskStr.c_str ();
|
||||
m_nscStack->if_attach (addrCStr, maskCStr, mtu);
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
// The NSC stack requires a default gateway and only supports
|
||||
// single-interface nodes. The below is a hack, but
|
||||
// it turns out that we can pass the interface address to nsc as
|
||||
// a default gateway. Bug 1398 has been opened to track this
|
||||
// issue (NSC's limitation to single-interface nodes)
|
||||
//
|
||||
// Previous versions of this code tried to assign the "next"
|
||||
// IP address of the subnet but this was found to fail for
|
||||
// some use cases in /30 subnets.
|
||||
|
||||
// \todo \bugid{1398} NSC's limitation to single-interface nodes
|
||||
m_nscStack->add_default_gateway (addrOss.str ().c_str ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpL4Protocol::SetDownTarget (IpL4Protocol::DownTargetCallback callback)
|
||||
{
|
||||
m_downTarget = callback;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpL4Protocol::SetDownTarget6 (IpL4Protocol::DownTargetCallback6 callback)
|
||||
{
|
||||
}
|
||||
|
||||
IpL4Protocol::DownTargetCallback
|
||||
NscTcpL4Protocol::GetDownTarget (void) const
|
||||
{
|
||||
return m_downTarget;
|
||||
}
|
||||
|
||||
IpL4Protocol::DownTargetCallback6
|
||||
NscTcpL4Protocol::GetDownTarget6 (void) const
|
||||
{
|
||||
return (IpL4Protocol::DownTargetCallback6)0;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
|
||||
#ifndef NSC_TCP_L4_PROTOCOL_H
|
||||
#define NSC_TCP_L4_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include "ns3/timer.h"
|
||||
#include "ip-l4-protocol.h"
|
||||
|
||||
struct INetStack;
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Node;
|
||||
class Socket;
|
||||
class Ipv4EndPointDemux;
|
||||
class Ipv4Interface;
|
||||
class NscTcpSocketImpl;
|
||||
class Ipv4EndPoint;
|
||||
class NscInterfaceImpl;
|
||||
class NetDevice;
|
||||
|
||||
/**
|
||||
* \ingroup nsctcp
|
||||
*
|
||||
* \brief Nsc wrapper glue, to interface with the Ipv4 protocol underneath.
|
||||
*/
|
||||
class NscTcpL4Protocol : public IpL4Protocol {
|
||||
public:
|
||||
static const uint8_t PROT_NUMBER; //!< protocol number (0x6)
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
NscTcpL4Protocol ();
|
||||
virtual ~NscTcpL4Protocol ();
|
||||
|
||||
/**
|
||||
* Set node associated with this stack
|
||||
* \param node the node
|
||||
*/
|
||||
void SetNode (Ptr<Node> node);
|
||||
|
||||
/**
|
||||
* Set the NSC library to be used
|
||||
* \param lib the library path
|
||||
*/
|
||||
void SetNscLibrary (const std::string &lib);
|
||||
|
||||
/**
|
||||
* Get the NSC library being used
|
||||
* \returns the library path
|
||||
*/
|
||||
std::string GetNscLibrary (void) const;
|
||||
virtual int GetProtocolNumber (void) const;
|
||||
|
||||
/**
|
||||
* Get the NSC version
|
||||
* \returns the NSC version
|
||||
*/
|
||||
virtual int GetVersion (void) const;
|
||||
|
||||
/**
|
||||
* \return A smart Socket pointer to a NscTcpSocketImpl, allocated by this instance
|
||||
* of the TCP protocol
|
||||
*/
|
||||
Ptr<Socket> CreateSocket (void);
|
||||
|
||||
/**
|
||||
* \brief Allocate an IPv4 Endpoint
|
||||
* \return the Endpoint
|
||||
*/
|
||||
Ipv4EndPoint *Allocate (void);
|
||||
/**
|
||||
* \brief Allocate an IPv4 Endpoint
|
||||
* \param address address to use
|
||||
* \return the Endpoint
|
||||
*/
|
||||
Ipv4EndPoint *Allocate (Ipv4Address address);
|
||||
/**
|
||||
* \brief Allocate an IPv4 Endpoint
|
||||
* \param boundNetDevice Bound NetDevice (if any)
|
||||
* \param port port to use
|
||||
* \return the Endpoint
|
||||
*/
|
||||
Ipv4EndPoint *Allocate (Ptr<NetDevice> boundNetDevice, uint16_t port);
|
||||
/**
|
||||
* \brief Allocate an IPv4 Endpoint
|
||||
* \param boundNetDevice Bound NetDevice (if any)
|
||||
* \param address address to use
|
||||
* \param port port to use
|
||||
* \return the Endpoint
|
||||
*/
|
||||
Ipv4EndPoint *Allocate (Ptr<NetDevice> boundNetDevice, Ipv4Address address, uint16_t port);
|
||||
/**
|
||||
* \brief Allocate an IPv4 Endpoint
|
||||
* \param boundNetDevice Bound NetDevice (if any)
|
||||
* \param localAddress local address to use
|
||||
* \param localPort local port to use
|
||||
* \param peerAddress remote address to use
|
||||
* \param peerPort remote port to use
|
||||
* \return the Endpoint
|
||||
*/
|
||||
Ipv4EndPoint *Allocate (Ptr<NetDevice> boundNetDevice,
|
||||
Ipv4Address localAddress, uint16_t localPort,
|
||||
Ipv4Address peerAddress, uint16_t peerPort);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Remove an IPv4 Endpoint.
|
||||
* \param endPoint the end point to remove
|
||||
*/
|
||||
void DeAllocate (Ipv4EndPoint *endPoint);
|
||||
|
||||
virtual IpL4Protocol::RxStatus Receive (Ptr<Packet> p,
|
||||
Ipv4Header const &header,
|
||||
Ptr<Ipv4Interface> incomingInterface);
|
||||
virtual IpL4Protocol::RxStatus Receive (Ptr<Packet> p,
|
||||
Ipv6Header const &header,
|
||||
Ptr<Ipv6Interface> interface);
|
||||
|
||||
// From IpL4Protocol
|
||||
virtual void SetDownTarget (IpL4Protocol::DownTargetCallback cb);
|
||||
virtual void SetDownTarget6 (IpL4Protocol::DownTargetCallback6 cb);
|
||||
// From IpL4Protocol
|
||||
virtual IpL4Protocol::DownTargetCallback GetDownTarget (void) const;
|
||||
virtual IpL4Protocol::DownTargetCallback6 GetDownTarget6 (void) const;
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
virtual void NotifyNewAggregate ();
|
||||
private:
|
||||
/**
|
||||
* \brief Copy constructor
|
||||
*
|
||||
* Defined and not implemented to avoid misuse
|
||||
*/
|
||||
NscTcpL4Protocol (NscTcpL4Protocol const &);
|
||||
/**
|
||||
* \brief Copy constructor
|
||||
*
|
||||
* Defined and not implemented to avoid misuse
|
||||
* \returns
|
||||
*/
|
||||
NscTcpL4Protocol& operator= (NscTcpL4Protocol const &);
|
||||
|
||||
// NSC callbacks.
|
||||
// NSC invokes these hooks to interact with the simulator.
|
||||
// In any case, these methods are only to be called by NSC.
|
||||
|
||||
/**
|
||||
* \brief Invoked by NSCs 'ethernet driver' to re-inject a packet into ns-3.
|
||||
*
|
||||
* A packet is an octet soup consisting of an IP Header, TCP Header
|
||||
* and user payload, if any
|
||||
*
|
||||
* \param data the data
|
||||
* \param datalen the data length
|
||||
*/
|
||||
void send_callback (const void *data, int datalen);
|
||||
/**
|
||||
* \brief Called by the NSC stack whenever something of interest has happened
|
||||
*
|
||||
* Examples: when data arrives on a socket, a listen socket
|
||||
* has a new connection pending, etc.
|
||||
*/
|
||||
void wakeup ();
|
||||
/**
|
||||
* \brief Called by the Linux stack RNG initialization
|
||||
*
|
||||
* Its also used by the cradle code to add a timestamp to
|
||||
* printk/printf/debug output.
|
||||
* \param sec seconds
|
||||
* \param usec microseconds
|
||||
*/
|
||||
void gettime (unsigned int *sec, unsigned int *usec);
|
||||
/**
|
||||
* \brief Add an interface
|
||||
*
|
||||
* Actually NSC only supports one interface per node (\bugid{1398})
|
||||
*/
|
||||
void AddInterface (void);
|
||||
|
||||
/**
|
||||
* \brief Provide a "soft" interrupt to NSC
|
||||
*/
|
||||
void SoftInterrupt (void);
|
||||
/**
|
||||
* \brief NscInterfaceImpl friend class.
|
||||
* \relates NscInterfaceImpl
|
||||
*/
|
||||
friend class NscInterfaceImpl;
|
||||
/**
|
||||
* \brief NscTcpSocketImpl friend class.
|
||||
* \relates NscTcpSocketImpl
|
||||
*/
|
||||
friend class NscTcpSocketImpl;
|
||||
|
||||
Ptr<Node> m_node; //!< the node this stack is associated with
|
||||
Ipv4EndPointDemux *m_endPoints; //!< A list of IPv4 end points.
|
||||
INetStack* m_nscStack; //!< the NSC stack.
|
||||
NscInterfaceImpl *m_nscInterface; //!< the NSC Interface.
|
||||
void *m_dlopenHandle; //!< dynamic library handle.
|
||||
std::string m_nscLibrary; //!< path to the NSC library.
|
||||
Timer m_softTimer; //!< Soft interrupt timer
|
||||
std::vector<Ptr<NscTcpSocketImpl> > m_sockets; //!< list of sockets
|
||||
IpL4Protocol::DownTargetCallback m_downTarget; //!< Callback to send packets over IPv4
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* NSC_TCP_L4_PROTOCOL_H */
|
||||
@@ -1,51 +0,0 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
#include "nsc-tcp-l4-protocol.h"
|
||||
#include "nsc-tcp-socket-factory-impl.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NscTcpSocketFactoryImpl::NscTcpSocketFactoryImpl ()
|
||||
: m_tcp (0)
|
||||
{
|
||||
}
|
||||
NscTcpSocketFactoryImpl::~NscTcpSocketFactoryImpl ()
|
||||
{
|
||||
NS_ASSERT (m_tcp == 0);
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketFactoryImpl::SetTcp (Ptr<NscTcpL4Protocol> tcp)
|
||||
{
|
||||
m_tcp = tcp;
|
||||
}
|
||||
|
||||
Ptr<Socket>
|
||||
NscTcpSocketFactoryImpl::CreateSocket (void)
|
||||
{
|
||||
return m_tcp->CreateSocket ();
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketFactoryImpl::DoDispose (void)
|
||||
{
|
||||
m_tcp = 0;
|
||||
TcpSocketFactory::DoDispose ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -1,66 +0,0 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
#ifndef NSC_TCP_SOCKET_FACTORY_IMPL_H
|
||||
#define NSC_TCP_SOCKET_FACTORY_IMPL_H
|
||||
|
||||
#include "ns3/tcp-socket-factory.h"
|
||||
#include "ns3/ptr.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class NscTcpL4Protocol;
|
||||
|
||||
/**
|
||||
* \ingroup internet
|
||||
* \defgroup nsctcp NscTcp
|
||||
*
|
||||
* An alternate implementation of TCP for ns-3 is provided by the
|
||||
* Network Simulation Cradle (NSC) project. NSC is a separately linked
|
||||
* library that provides ported TCP stacks from popular operating systems
|
||||
* such as Linux and FreeBSD. Glue code such as the ns-3 NSC code
|
||||
* allows users to delegate Internet stack processing to the logic
|
||||
* from these operating systems. This allows a user to reproduce
|
||||
* with high fidelity the behavior of a real TCP stack.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup nsctcp
|
||||
*
|
||||
* \brief socket factory implementation for creating instances of NSC TCP
|
||||
*/
|
||||
class NscTcpSocketFactoryImpl : public TcpSocketFactory
|
||||
{
|
||||
public:
|
||||
NscTcpSocketFactoryImpl ();
|
||||
virtual ~NscTcpSocketFactoryImpl ();
|
||||
|
||||
/**
|
||||
* \brief Set the associated TCP L4 protocol.
|
||||
* \param tcp the TCP L4 protocol
|
||||
*/
|
||||
void SetTcp (Ptr<NscTcpL4Protocol> tcp);
|
||||
|
||||
virtual Ptr<Socket> CreateSocket (void);
|
||||
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
private:
|
||||
Ptr<NscTcpL4Protocol> m_tcp; //!< the associated TCP L4 protocol
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* NSC_TCP_SOCKET_FACTORY_IMPL_H */
|
||||
@@ -1,937 +0,0 @@
|
||||
/* -*- 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
|
||||
*
|
||||
* based on tcp-socket-impl.cc, Author: Raj Bhattacharjea <raj.b@gatech.edu>
|
||||
* Author: Florian Westphal <fw@strlen.de>
|
||||
*/
|
||||
|
||||
#define NS_LOG_APPEND_CONTEXT \
|
||||
if (m_node) { std::clog << Simulator::Now ().As (Time::S) << " [node " << m_node->GetId () << "] "; }
|
||||
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ipv4-end-point.h"
|
||||
#include "nsc-tcp-l4-protocol.h"
|
||||
#include "nsc-tcp-socket-impl.h"
|
||||
#include "ns3/simulation-singleton.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// for ntohs().
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include "sim_interface.h"
|
||||
|
||||
#include "sim_errno.h"
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("NscTcpSocketImpl");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (NscTcpSocketImpl);
|
||||
|
||||
TypeId
|
||||
NscTcpSocketImpl::GetTypeId ()
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::NscTcpSocketImpl")
|
||||
.SetParent<TcpSocket> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddTraceSource ("CongestionWindow",
|
||||
"The TCP connection's congestion window",
|
||||
MakeTraceSourceAccessor (&NscTcpSocketImpl::m_cWnd),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
.AddTraceSource ("SlowStartThreshold",
|
||||
"TCP slow start threshold (bytes)",
|
||||
MakeTraceSourceAccessor (&NscTcpSocketImpl::m_ssThresh),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
.AddTraceSource ("State",
|
||||
"TCP state",
|
||||
MakeTraceSourceAccessor (&NscTcpSocketImpl::m_state),
|
||||
"ns3::TcpStatesTracedValueCallback")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
NscTcpSocketImpl::NscTcpSocketImpl ()
|
||||
: m_endPoint (0),
|
||||
m_node (0),
|
||||
m_tcp (0),
|
||||
m_localAddress (Ipv4Address::GetZero ()),
|
||||
m_localPort (0),
|
||||
m_peerAddress ("0.0.0.0", 0),
|
||||
m_errno (ERROR_NOTERROR),
|
||||
m_shutdownSend (false),
|
||||
m_shutdownRecv (false),
|
||||
m_connected (false),
|
||||
m_state (CLOSED),
|
||||
m_closeOnEmpty (false),
|
||||
m_txBufferSize (0),
|
||||
m_lastMeasuredRtt (Seconds (0.0))
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
NscTcpSocketImpl::NscTcpSocketImpl(const NscTcpSocketImpl& sock)
|
||||
: TcpSocket (sock), //copy the base class callbacks
|
||||
m_delAckMaxCount (sock.m_delAckMaxCount),
|
||||
m_delAckTimeout (sock.m_delAckTimeout),
|
||||
m_noDelay (sock.m_noDelay),
|
||||
m_endPoint (0),
|
||||
m_node (sock.m_node),
|
||||
m_tcp (sock.m_tcp),
|
||||
m_remoteAddress (sock.m_remoteAddress),
|
||||
m_remotePort (sock.m_remotePort),
|
||||
m_localAddress (sock.m_localAddress),
|
||||
m_localPort (sock.m_localPort),
|
||||
m_peerAddress (sock.m_peerAddress),
|
||||
m_errno (sock.m_errno),
|
||||
m_shutdownSend (sock.m_shutdownSend),
|
||||
m_shutdownRecv (sock.m_shutdownRecv),
|
||||
m_connected (sock.m_connected),
|
||||
m_state (sock.m_state),
|
||||
m_closeOnEmpty (sock.m_closeOnEmpty),
|
||||
m_txBufferSize (sock.m_txBufferSize),
|
||||
m_segmentSize (sock.m_segmentSize),
|
||||
m_rxWindowSize (sock.m_rxWindowSize),
|
||||
m_advertisedWindowSize (sock.m_advertisedWindowSize),
|
||||
m_cWnd (sock.m_cWnd),
|
||||
m_ssThresh (sock.m_ssThresh),
|
||||
m_initialCWnd (sock.m_initialCWnd),
|
||||
m_initialSsThresh (sock.m_initialSsThresh),
|
||||
m_lastMeasuredRtt (Seconds (0.0)),
|
||||
m_cnTimeout (sock.m_cnTimeout),
|
||||
m_synRetries (sock.m_synRetries),
|
||||
m_rxAvailable (0),
|
||||
m_nscTcpSocket (0),
|
||||
m_sndBufSize (sock.m_sndBufSize)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC ("Invoked the copy constructor");
|
||||
//copy the pending data if necessary
|
||||
if(!sock.m_txBuffer.empty () )
|
||||
{
|
||||
m_txBuffer = sock.m_txBuffer;
|
||||
}
|
||||
//can't "copy" the endpoint just yes, must do this when we know the peer info
|
||||
//too; this is in SYN_ACK_TX
|
||||
}
|
||||
|
||||
NscTcpSocketImpl::~NscTcpSocketImpl ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_node = 0;
|
||||
if (m_endPoint != 0)
|
||||
{
|
||||
NS_ASSERT (m_tcp != 0);
|
||||
/**
|
||||
* Note that this piece of code is a bit tricky:
|
||||
* when DeAllocate is called, it will call into
|
||||
* Ipv4EndPointDemux::Deallocate which triggers
|
||||
* a delete of the associated endPoint which triggers
|
||||
* in turn a call to the method NscTcpSocketImpl::Destroy below
|
||||
* will will zero the m_endPoint field.
|
||||
*/
|
||||
NS_ASSERT (m_endPoint != 0);
|
||||
m_tcp->DeAllocate (m_endPoint);
|
||||
NS_ASSERT (m_endPoint == 0);
|
||||
}
|
||||
m_tcp = 0;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetNode (Ptr<Node> node)
|
||||
{
|
||||
m_node = node;
|
||||
// Initialize some variables
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
m_ssThresh = m_initialSsThresh;
|
||||
m_rxWindowSize = m_advertisedWindowSize;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetTcp (Ptr<NscTcpL4Protocol> tcp)
|
||||
{
|
||||
m_nscTcpSocket = tcp->m_nscStack->new_tcp_socket ();
|
||||
m_tcp = tcp;
|
||||
}
|
||||
|
||||
|
||||
enum Socket::SocketErrno
|
||||
NscTcpSocketImpl::GetErrno (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_errno;
|
||||
}
|
||||
|
||||
enum Socket::SocketType
|
||||
NscTcpSocketImpl::GetSocketType (void) const
|
||||
{
|
||||
return NS3_SOCK_STREAM;
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
NscTcpSocketImpl::GetNode (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_node;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::Destroy (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_node = 0;
|
||||
m_endPoint = 0;
|
||||
m_tcp = 0;
|
||||
}
|
||||
int
|
||||
NscTcpSocketImpl::FinishBind (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (m_endPoint == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
m_endPoint->SetRxCallback (MakeCallback (&NscTcpSocketImpl::ForwardUp, Ptr<NscTcpSocketImpl>(this)));
|
||||
m_endPoint->SetDestroyCallback (MakeCallback (&NscTcpSocketImpl::Destroy, Ptr<NscTcpSocketImpl>(this)));
|
||||
m_localAddress = m_endPoint->GetLocalAddress ();
|
||||
m_localPort = m_endPoint->GetLocalPort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::Bind (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_endPoint = m_tcp->Allocate ();
|
||||
return FinishBind ();
|
||||
}
|
||||
int
|
||||
NscTcpSocketImpl::Bind6 ()
|
||||
{
|
||||
NS_LOG_LOGIC ("NscTcpSocketImpl: ERROR_AFNOSUPPORT - Bind6 not supported");
|
||||
m_errno = ERROR_AFNOSUPPORT;
|
||||
return (-1);
|
||||
}
|
||||
int
|
||||
NscTcpSocketImpl::Bind (const Address &address)
|
||||
{
|
||||
NS_LOG_FUNCTION (this<<address);
|
||||
if (!InetSocketAddress::IsMatchingType (address))
|
||||
{
|
||||
return ERROR_INVAL;
|
||||
}
|
||||
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
|
||||
Ipv4Address ipv4 = transport.GetIpv4 ();
|
||||
uint16_t port = transport.GetPort ();
|
||||
if (ipv4 == Ipv4Address::GetAny () && port == 0)
|
||||
{
|
||||
m_endPoint = m_tcp->Allocate ();
|
||||
NS_LOG_LOGIC ("NscTcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
|
||||
}
|
||||
else if (ipv4 == Ipv4Address::GetAny () && port != 0)
|
||||
{
|
||||
m_endPoint = m_tcp->Allocate (GetBoundNetDevice (), port);
|
||||
NS_LOG_LOGIC ("NscTcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
|
||||
}
|
||||
else if (ipv4 != Ipv4Address::GetAny () && port == 0)
|
||||
{
|
||||
m_endPoint = m_tcp->Allocate (ipv4);
|
||||
NS_LOG_LOGIC ("NscTcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
|
||||
}
|
||||
else if (ipv4 != Ipv4Address::GetAny () && port != 0)
|
||||
{
|
||||
m_endPoint = m_tcp->Allocate (GetBoundNetDevice (), ipv4, port);
|
||||
NS_LOG_LOGIC ("NscTcpSocketImpl "<<this<<" got an endpoint: "<<m_endPoint);
|
||||
}
|
||||
|
||||
m_localPort = port;
|
||||
return FinishBind ();
|
||||
}
|
||||
|
||||
/* Inherit from Socket class: Bind this socket to the specified NetDevice */
|
||||
void
|
||||
NscTcpSocketImpl::BindToNetDevice (Ptr<NetDevice> netdevice)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << netdevice);
|
||||
Socket::BindToNetDevice (netdevice); // Includes sanity check
|
||||
if (m_endPoint != 0)
|
||||
{
|
||||
m_endPoint->BindToNetDevice (netdevice);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::ShutdownSend (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_shutdownSend = true;
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
NscTcpSocketImpl::ShutdownRecv (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_shutdownRecv = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::Close (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << m_state);
|
||||
|
||||
if (m_state == CLOSED)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!m_txBuffer.empty ())
|
||||
{ // App close with pending data must wait until all data transmitted
|
||||
m_closeOnEmpty = true;
|
||||
NS_LOG_LOGIC ("Socket " << this <<
|
||||
" deferring close, state " << m_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_LOG_LOGIC ("NscTcp socket " << this << " calling disconnect(); moving to CLOSED");
|
||||
m_nscTcpSocket->disconnect ();
|
||||
m_state = CLOSED;
|
||||
ShutdownSend ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::Connect (const Address & address)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << address);
|
||||
if (m_endPoint == 0)
|
||||
{
|
||||
if (Bind () == -1)
|
||||
{
|
||||
NS_ASSERT (m_endPoint == 0);
|
||||
return -1;
|
||||
}
|
||||
NS_ASSERT (m_endPoint != 0);
|
||||
}
|
||||
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
|
||||
m_remoteAddress = transport.GetIpv4 ();
|
||||
m_remotePort = transport.GetPort ();
|
||||
|
||||
std::ostringstream ss;
|
||||
m_remoteAddress.Print (ss);
|
||||
std::string ipstring = ss.str ();
|
||||
|
||||
m_nscTcpSocket->connect (ipstring.c_str (), m_remotePort);
|
||||
m_state = SYN_SENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::Send (const Ptr<Packet> p, uint32_t flags)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << p);
|
||||
|
||||
NS_ASSERT (p->GetSize () > 0);
|
||||
if (m_state == ESTABLISHED || m_state == SYN_SENT || m_state == CLOSE_WAIT)
|
||||
{
|
||||
if (p->GetSize () > GetTxAvailable ())
|
||||
{
|
||||
m_errno = ERROR_MSGSIZE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t sent = p->GetSize ();
|
||||
if (m_state == ESTABLISHED)
|
||||
{
|
||||
m_txBuffer.push (p);
|
||||
m_txBufferSize += sent;
|
||||
SendPendingData ();
|
||||
}
|
||||
else
|
||||
{ // SYN_SET -- Queue Data
|
||||
m_txBuffer.push (p);
|
||||
m_txBufferSize += sent;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errno = ERROR_NOTCONN;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << address << p);
|
||||
if (!m_connected)
|
||||
{
|
||||
m_errno = ERROR_NOTCONN;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Send (p, flags); //drop the address according to BSD manpages
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetTxAvailable (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (m_txBufferSize != 0)
|
||||
{
|
||||
NS_ASSERT (m_txBufferSize <= m_sndBufSize);
|
||||
return m_sndBufSize - m_txBufferSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_sndBufSize;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::Listen (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_nscTcpSocket->listen (m_localPort);
|
||||
m_state = LISTEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::NSCWakeup ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
switch (m_state) {
|
||||
case SYN_SENT:
|
||||
if (!m_nscTcpSocket->is_connected ())
|
||||
break;
|
||||
m_state = ESTABLISHED;
|
||||
Simulator::ScheduleNow (&NscTcpSocketImpl::ConnectionSucceeded, this);
|
||||
// fall through to schedule read/write events
|
||||
case ESTABLISHED:
|
||||
if (!m_txBuffer.empty ())
|
||||
{
|
||||
Simulator::ScheduleNow (&NscTcpSocketImpl::SendPendingData, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetTxAvailable ())
|
||||
{
|
||||
NotifySend (GetTxAvailable ());
|
||||
}
|
||||
}
|
||||
Simulator::ScheduleNow (&NscTcpSocketImpl::ReadPendingData, this);
|
||||
break;
|
||||
case LISTEN:
|
||||
Simulator::ScheduleNow (&NscTcpSocketImpl::Accept, this);
|
||||
break;
|
||||
case CLOSED: break;
|
||||
default:
|
||||
NS_LOG_DEBUG (this << " invalid state: " << m_state);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Packet>
|
||||
NscTcpSocketImpl::Recv (uint32_t maxSize, uint32_t flags)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << maxSize << flags);
|
||||
if (m_deliveryQueue.empty () )
|
||||
{
|
||||
m_errno = ERROR_AGAIN;
|
||||
return 0;
|
||||
}
|
||||
Ptr<Packet> p = m_deliveryQueue.front ();
|
||||
if (p->GetSize () <= maxSize)
|
||||
{
|
||||
m_deliveryQueue.pop ();
|
||||
m_rxAvailable -= p->GetSize ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errno = ERROR_AGAIN;
|
||||
p = 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
Ptr<Packet>
|
||||
NscTcpSocketImpl::RecvFrom (uint32_t maxSize, uint32_t flags,
|
||||
Address &fromAddress)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << maxSize << flags);
|
||||
Ptr<Packet> packet = Recv (maxSize, flags);
|
||||
GetPeerName (fromAddress);
|
||||
return packet;
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::GetSockName (Address &address) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << address);
|
||||
address = InetSocketAddress (m_localAddress, m_localPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NscTcpSocketImpl::GetPeerName (Address &address) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << address);
|
||||
|
||||
if (!m_endPoint)
|
||||
{
|
||||
m_errno = ERROR_NOTCONN;
|
||||
return -1;
|
||||
}
|
||||
address = InetSocketAddress (m_endPoint->GetPeerAddress (),
|
||||
m_endPoint->GetPeerPort ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetRxAvailable (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
// We separately maintain this state to avoid walking the queue
|
||||
// every time this might be called
|
||||
return m_rxAvailable;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::ForwardUp (Ptr<Packet> packet, Ipv4Header header, uint16_t port,
|
||||
Ptr<Ipv4Interface> incomingInterface)
|
||||
{
|
||||
NSCWakeup ();
|
||||
}
|
||||
|
||||
void NscTcpSocketImpl::CompleteFork (void)
|
||||
{
|
||||
// The address pairs (m_localAddress, m_localPort, m_remoteAddress, m_remotePort)
|
||||
// are bogus, but this isn't important at the moment, because
|
||||
// address <-> Socket handling is done by NSC internally.
|
||||
// We only need to add the new ns-3 socket to the list of sockets, so
|
||||
// we use plain Allocate() instead of Allocate(m_localAddress, ... )
|
||||
struct sockaddr_in sin;
|
||||
size_t sin_len = sizeof(sin);
|
||||
|
||||
if (0 == m_nscTcpSocket->getpeername ((struct sockaddr*) &sin, &sin_len)) {
|
||||
m_remotePort = ntohs (sin.sin_port);
|
||||
m_remoteAddress = Ipv4Address::Deserialize ((const uint8_t*) &sin.sin_addr);
|
||||
m_peerAddress = InetSocketAddress (m_remoteAddress, m_remotePort);
|
||||
}
|
||||
|
||||
m_endPoint = m_tcp->Allocate ();
|
||||
|
||||
//the cloned socket with be in listen state, so manually change state
|
||||
NS_ASSERT (m_state == LISTEN);
|
||||
m_state = ESTABLISHED;
|
||||
|
||||
sin_len = sizeof(sin);
|
||||
|
||||
if (0 == m_nscTcpSocket->getsockname ((struct sockaddr *) &sin, &sin_len))
|
||||
m_localAddress = Ipv4Address::Deserialize ((const uint8_t*) &sin.sin_addr);
|
||||
|
||||
NS_LOG_LOGIC ("NscTcpSocketImpl " << this << " accepted connection from "
|
||||
<< m_remoteAddress << ":" << m_remotePort
|
||||
<< " to " << m_localAddress << ":" << m_localPort);
|
||||
//equivalent to FinishBind
|
||||
m_endPoint->SetRxCallback (MakeCallback (&NscTcpSocketImpl::ForwardUp, Ptr<NscTcpSocketImpl>(this)));
|
||||
m_endPoint->SetDestroyCallback (MakeCallback (&NscTcpSocketImpl::Destroy, Ptr<NscTcpSocketImpl>(this)));
|
||||
|
||||
NotifyNewConnectionCreated (this, m_peerAddress);
|
||||
}
|
||||
|
||||
void NscTcpSocketImpl::ConnectionSucceeded ()
|
||||
{ // We would preferred to have scheduled an event directly to
|
||||
// NotifyConnectionSucceeded, but (sigh) these are protected
|
||||
// and we can get the address of it :(
|
||||
struct sockaddr_in sin;
|
||||
size_t sin_len = sizeof(sin);
|
||||
if (0 == m_nscTcpSocket->getsockname ((struct sockaddr *) &sin, &sin_len)) {
|
||||
m_localAddress = Ipv4Address::Deserialize ((const uint8_t*)&sin.sin_addr);
|
||||
m_localPort = ntohs (sin.sin_port);
|
||||
}
|
||||
|
||||
NS_LOG_LOGIC ("NscTcpSocketImpl " << this << " connected to "
|
||||
<< m_remoteAddress << ":" << m_remotePort
|
||||
<< " from " << m_localAddress << ":" << m_localPort);
|
||||
NotifyConnectionSucceeded ();
|
||||
}
|
||||
|
||||
|
||||
bool NscTcpSocketImpl::Accept (void)
|
||||
{
|
||||
if (m_state == CLOSED)
|
||||
{ // Happens if application closes listening socket after Accept() was scheduled.
|
||||
return false;
|
||||
}
|
||||
NS_ASSERT (m_state == LISTEN);
|
||||
|
||||
if (!m_nscTcpSocket->is_listening ())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
INetStreamSocket *newsock;
|
||||
int res = m_nscTcpSocket->accept (&newsock);
|
||||
if (res != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// We could obtain a fromAddress using getpeername, but we've already
|
||||
// finished the tcp handshake here, i.e. this is a new connection
|
||||
// and not a connection request.
|
||||
// if (!NotifyConnectionRequest(fromAddress))
|
||||
// return true;
|
||||
|
||||
// Clone the socket
|
||||
Ptr<NscTcpSocketImpl> newSock = Copy ();
|
||||
newSock->m_nscTcpSocket = newsock;
|
||||
NS_LOG_LOGIC ("Cloned a NscTcpSocketImpl " << newSock);
|
||||
|
||||
Simulator::ScheduleNow (&NscTcpSocketImpl::CompleteFork, newSock);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NscTcpSocketImpl::ReadPendingData (void)
|
||||
{
|
||||
if (m_state != ESTABLISHED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int len, err;
|
||||
uint8_t buffer[8192];
|
||||
len = sizeof(buffer);
|
||||
m_errno = ERROR_NOTERROR;
|
||||
err = m_nscTcpSocket->read_data (buffer, &len);
|
||||
if (err == 0 && len == 0)
|
||||
{
|
||||
NS_LOG_LOGIC ("ReadPendingData got EOF from socket");
|
||||
m_state = CLOSE_WAIT;
|
||||
return false;
|
||||
}
|
||||
m_errno = GetNativeNs3Errno (err);
|
||||
switch (m_errno)
|
||||
{
|
||||
case ERROR_NOTERROR: break; // some data was sent
|
||||
case ERROR_AGAIN: return false;
|
||||
default:
|
||||
NS_LOG_WARN ("Error (" << err << ") " <<
|
||||
"during read_data, ns-3 errno set to" << m_errno);
|
||||
m_state = CLOSED;
|
||||
return false;
|
||||
}
|
||||
|
||||
Ptr<Packet> p = Create<Packet> (buffer, len);
|
||||
|
||||
m_deliveryQueue.push (p);
|
||||
m_rxAvailable += p->GetSize ();
|
||||
|
||||
NotifyDataRecv ();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NscTcpSocketImpl::SendPendingData (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC ("ENTERING SendPendingData");
|
||||
|
||||
if (m_txBuffer.empty ())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret;
|
||||
size_t size, written = 0;
|
||||
|
||||
do {
|
||||
NS_ASSERT (!m_txBuffer.empty ());
|
||||
Ptr<Packet> &p = m_txBuffer.front ();
|
||||
size = p->GetSize ();
|
||||
NS_ASSERT (size > 0);
|
||||
|
||||
m_errno = ERROR_NOTERROR;
|
||||
|
||||
uint8_t *buf = new uint8_t[size];
|
||||
p->CopyData (buf, size);
|
||||
ret = m_nscTcpSocket->send_data ((const char *)buf, size);
|
||||
delete[] buf;
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
written += ret;
|
||||
|
||||
NS_ASSERT (m_txBufferSize >= (size_t)ret);
|
||||
m_txBufferSize -= ret;
|
||||
|
||||
if ((size_t)ret < size)
|
||||
{
|
||||
p->RemoveAtStart (ret);
|
||||
break;
|
||||
}
|
||||
|
||||
m_txBuffer.pop ();
|
||||
|
||||
if (m_txBuffer.empty ())
|
||||
{
|
||||
if (m_closeOnEmpty)
|
||||
{
|
||||
m_nscTcpSocket->disconnect ();
|
||||
m_state = CLOSED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while ((size_t) ret == size);
|
||||
|
||||
if (written > 0)
|
||||
{
|
||||
NS_LOG_DEBUG ("Notifying data sent, remaining txbuffer size: " << m_txBufferSize);
|
||||
Simulator::ScheduleNow (&NscTcpSocketImpl::NotifyDataSent, this, ret);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG ("Not notifying data sent, return value " << ret);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Ptr<NscTcpSocketImpl> NscTcpSocketImpl::Copy ()
|
||||
{
|
||||
return CopyObject<NscTcpSocketImpl> (this);
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetSndBufSize (uint32_t size)
|
||||
{
|
||||
m_sndBufSize = size;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetSndBufSize (void) const
|
||||
{
|
||||
return m_sndBufSize;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetRcvBufSize (uint32_t size)
|
||||
{
|
||||
m_rcvBufSize = size;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetRcvBufSize (void) const
|
||||
{
|
||||
return m_rcvBufSize;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetSegSize (uint32_t size)
|
||||
{
|
||||
m_segmentSize = size;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetSegSize (void) const
|
||||
{
|
||||
return m_segmentSize;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetAdvWin (uint32_t window)
|
||||
{
|
||||
m_advertisedWindowSize = window;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetAdvWin (void) const
|
||||
{
|
||||
return m_advertisedWindowSize;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetInitialSSThresh (uint32_t threshold)
|
||||
{
|
||||
m_initialSsThresh = threshold;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetInitialSSThresh (void) const
|
||||
{
|
||||
return m_initialSsThresh;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetInitialCwnd (uint32_t cwnd)
|
||||
{
|
||||
m_initialCWnd = cwnd;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetInitialCwnd (void) const
|
||||
{
|
||||
return m_initialCWnd;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetConnTimeout (Time timeout)
|
||||
{
|
||||
m_cnTimeout = timeout;
|
||||
}
|
||||
|
||||
Time
|
||||
NscTcpSocketImpl::GetConnTimeout (void) const
|
||||
{
|
||||
return m_cnTimeout;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetSynRetries (uint32_t count)
|
||||
{
|
||||
m_synRetries = count;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetSynRetries (void) const
|
||||
{
|
||||
return m_synRetries;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetDelAckTimeout (Time timeout)
|
||||
{
|
||||
m_delAckTimeout = timeout;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetDataRetries (uint32_t retries)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << retries);
|
||||
m_dataRetries = retries;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetDataRetries (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_dataRetries;
|
||||
}
|
||||
|
||||
Time
|
||||
NscTcpSocketImpl::GetDelAckTimeout (void) const
|
||||
{
|
||||
return m_delAckTimeout;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetDelAckMaxCount (uint32_t count)
|
||||
{
|
||||
m_delAckMaxCount = count;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NscTcpSocketImpl::GetDelAckMaxCount (void) const
|
||||
{
|
||||
return m_delAckMaxCount;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetTcpNoDelay (bool noDelay)
|
||||
{
|
||||
m_noDelay = noDelay;
|
||||
}
|
||||
|
||||
bool
|
||||
NscTcpSocketImpl::GetTcpNoDelay (void) const
|
||||
{
|
||||
return m_noDelay;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetPersistTimeout (Time timeout)
|
||||
{
|
||||
m_persistTimeout = timeout;
|
||||
}
|
||||
|
||||
Time
|
||||
NscTcpSocketImpl::GetPersistTimeout (void) const
|
||||
{
|
||||
return m_persistTimeout;
|
||||
}
|
||||
|
||||
enum Socket::SocketErrno
|
||||
NscTcpSocketImpl::GetNativeNs3Errno (int error) const
|
||||
{
|
||||
enum nsc_errno err;
|
||||
|
||||
if (error >= 0)
|
||||
{
|
||||
return ERROR_NOTERROR;
|
||||
}
|
||||
err = (enum nsc_errno) error;
|
||||
switch (err)
|
||||
{
|
||||
case NSC_EADDRINUSE: // fallthrough
|
||||
case NSC_EADDRNOTAVAIL: return ERROR_AFNOSUPPORT;
|
||||
case NSC_EINPROGRESS: // Although nsc sockets are nonblocking, we pretend they're not.
|
||||
case NSC_EAGAIN: return ERROR_AGAIN;
|
||||
case NSC_EISCONN: // fallthrough
|
||||
case NSC_EALREADY: return ERROR_ISCONN;
|
||||
case NSC_ECONNREFUSED: return ERROR_NOROUTETOHOST; /// \todo better mapping?
|
||||
case NSC_ECONNRESET: // for no, all of these fall through
|
||||
case NSC_EHOSTDOWN:
|
||||
case NSC_ENETUNREACH:
|
||||
case NSC_EHOSTUNREACH: return ERROR_NOROUTETOHOST;
|
||||
case NSC_EMSGSIZE: return ERROR_MSGSIZE;
|
||||
case NSC_ENOTCONN: return ERROR_NOTCONN;
|
||||
case NSC_ESHUTDOWN: return ERROR_SHUTDOWN;
|
||||
case NSC_ETIMEDOUT: return ERROR_NOTCONN; /// \todo this mapping isn't correct
|
||||
case NSC_ENOTDIR: // used by eg. sysctl(2). Shouldn't happen normally,
|
||||
// but is triggered by e.g. show_config().
|
||||
case NSC_EUNKNOWN: return ERROR_INVAL; // Catches stacks that 'return -1' without real mapping
|
||||
}
|
||||
NS_ASSERT_MSG (0, "Unknown NSC error");
|
||||
return ERROR_INVAL;
|
||||
}
|
||||
|
||||
bool
|
||||
NscTcpSocketImpl::SetAllowBroadcast (bool allowBroadcast)
|
||||
{
|
||||
if (allowBroadcast)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
NscTcpSocketImpl::GetAllowBroadcast () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -1,277 +0,0 @@
|
||||
/* -*- 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
|
||||
*/
|
||||
#ifndef NSC_TCP_SOCKET_IMPL_H
|
||||
#define NSC_TCP_SOCKET_IMPL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/traced-value.h"
|
||||
#include "ns3/tcp-socket.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "pending-data.h"
|
||||
#include "ns3/sequence-number.h"
|
||||
|
||||
struct INetStreamSocket;
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Ipv4EndPoint;
|
||||
class Node;
|
||||
class Packet;
|
||||
class NscTcpL4Protocol;
|
||||
class TcpHeader;
|
||||
|
||||
/**
|
||||
* \ingroup socket
|
||||
* \ingroup nsctcp
|
||||
*
|
||||
* \brief Socket logic for the NSC TCP sockets.
|
||||
*
|
||||
* Most of the TCP internal
|
||||
* logic is handled by the NSC tcp library itself; this class maps ns3::Socket
|
||||
* calls to the NSC TCP library.
|
||||
*/
|
||||
class NscTcpSocketImpl : public TcpSocket
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* Create an unbound tcp socket.
|
||||
*/
|
||||
NscTcpSocketImpl ();
|
||||
|
||||
/**
|
||||
* Clone a TCP socket, for use upon receiving a connection request in LISTEN state
|
||||
*
|
||||
* \param sock the original Tcp Socket
|
||||
*/
|
||||
NscTcpSocketImpl (const NscTcpSocketImpl& sock);
|
||||
virtual ~NscTcpSocketImpl ();
|
||||
|
||||
/**
|
||||
* \brief Set the associated node.
|
||||
* \param node the node
|
||||
*/
|
||||
void SetNode (Ptr<Node> node);
|
||||
|
||||
/**
|
||||
* \brief Set the associated TCP L4 protocol.
|
||||
* \param tcp the TCP L4 protocol
|
||||
*/
|
||||
void SetTcp (Ptr<NscTcpL4Protocol> tcp);
|
||||
|
||||
virtual enum SocketErrno GetErrno (void) const;
|
||||
virtual enum SocketType GetSocketType (void) const;
|
||||
virtual int GetPeerName (Address &address) const;
|
||||
virtual Ptr<Node> GetNode (void) const;
|
||||
virtual int Bind (void);
|
||||
virtual int Bind6 (void);
|
||||
virtual int Bind (const Address &address);
|
||||
virtual int Close (void);
|
||||
virtual int ShutdownSend (void);
|
||||
virtual int ShutdownRecv (void);
|
||||
virtual int Connect (const Address &address);
|
||||
virtual int Listen (void);
|
||||
virtual uint32_t GetTxAvailable (void) const;
|
||||
virtual int Send (Ptr<Packet> p, uint32_t flags);
|
||||
virtual int SendTo (Ptr<Packet> p, uint32_t flags, const Address &toAddress);
|
||||
virtual uint32_t GetRxAvailable (void) const;
|
||||
virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags);
|
||||
virtual Ptr<Packet> RecvFrom (uint32_t maxSize, uint32_t flags,
|
||||
Address &fromAddress);
|
||||
virtual int GetSockName (Address &address) const;
|
||||
virtual bool SetAllowBroadcast (bool allowBroadcast);
|
||||
virtual bool GetAllowBroadcast () const;
|
||||
virtual void BindToNetDevice (Ptr<NetDevice> netdevice); // NetDevice with my m_endPoint
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Called by NscTcpSocketImpl::ForwardUp()
|
||||
*
|
||||
* Actually performs the ForwardUp operations
|
||||
*/
|
||||
void NSCWakeup (void);
|
||||
/**
|
||||
* \brief Tcp friend class.
|
||||
* \relates Tcp
|
||||
*/
|
||||
friend class Tcp;
|
||||
// invoked by Tcp class
|
||||
/**
|
||||
* Finish the binding process
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
int FinishBind (void);
|
||||
/**
|
||||
* \brief Called by the L3 protocol when it received a packet to pass on to TCP.
|
||||
*
|
||||
* \param p the incoming packet
|
||||
* \param header the packet's IPv4 header
|
||||
* \param port the incoming port
|
||||
* \param incomingInterface the incoming interface
|
||||
*/
|
||||
void ForwardUp (Ptr<Packet> p, Ipv4Header header, uint16_t port,
|
||||
Ptr<Ipv4Interface> incomingInterface);
|
||||
/**
|
||||
* \brief Kill this socket by zeroing its attributes (IPv4)
|
||||
*
|
||||
* This is a callback function configured to m_endpoint in
|
||||
* SetupCallback(), invoked when the endpoint is destroyed.
|
||||
*/
|
||||
void Destroy (void);
|
||||
//methods for state
|
||||
/**
|
||||
* \brief Send all the pending data
|
||||
* \returns true on success
|
||||
*/
|
||||
bool SendPendingData (void);
|
||||
/**
|
||||
* \brief Read all the pending data
|
||||
* \returns true on success
|
||||
*/
|
||||
bool ReadPendingData (void);
|
||||
/**
|
||||
* \brief Accept an incoming connection
|
||||
* \returns true on success
|
||||
*/
|
||||
bool Accept (void);
|
||||
/**
|
||||
* \brief Complete the Fork operations (after a connection has been accepted)
|
||||
*/
|
||||
void CompleteFork (void);
|
||||
|
||||
/**
|
||||
* \brief Called when a connection is in Established state
|
||||
*/
|
||||
void ConnectionSucceeded ();
|
||||
|
||||
// Manage data tx/rx
|
||||
// \todo This should be virtual and overridden
|
||||
/**
|
||||
* \brief Copy self
|
||||
* \returns a copy of self
|
||||
*/
|
||||
Ptr<NscTcpSocketImpl> Copy ();
|
||||
|
||||
// attribute related
|
||||
virtual void SetSndBufSize (uint32_t size);
|
||||
virtual uint32_t GetSndBufSize (void) const;
|
||||
virtual void SetRcvBufSize (uint32_t size);
|
||||
virtual uint32_t GetRcvBufSize (void) const;
|
||||
virtual void SetSegSize (uint32_t size);
|
||||
virtual uint32_t GetSegSize (void) const;
|
||||
/**
|
||||
* \brief Set the Advertised Window size
|
||||
* \param window the window size
|
||||
*/
|
||||
virtual void SetAdvWin (uint32_t window);
|
||||
/**
|
||||
* \brief Get the Advertised Window size
|
||||
* \returns the window size
|
||||
*/
|
||||
virtual uint32_t GetAdvWin (void) const;
|
||||
virtual void SetInitialSSThresh (uint32_t threshold);
|
||||
virtual uint32_t GetInitialSSThresh (void) const;
|
||||
virtual void SetInitialCwnd (uint32_t cwnd);
|
||||
virtual uint32_t GetInitialCwnd (void) const;
|
||||
virtual void SetConnTimeout (Time timeout);
|
||||
virtual Time GetConnTimeout (void) const;
|
||||
virtual uint32_t GetSynRetries (void) const;
|
||||
virtual void SetSynRetries (uint32_t count);
|
||||
virtual void SetDataRetries (uint32_t retries);
|
||||
virtual uint32_t GetDataRetries (void) const;
|
||||
virtual void SetDelAckTimeout (Time timeout);
|
||||
virtual Time GetDelAckTimeout (void) const;
|
||||
virtual void SetDelAckMaxCount (uint32_t count);
|
||||
virtual uint32_t GetDelAckMaxCount (void) const;
|
||||
virtual void SetTcpNoDelay (bool noDelay);
|
||||
virtual bool GetTcpNoDelay (void) const;
|
||||
virtual void SetPersistTimeout (Time timeout);
|
||||
virtual Time GetPersistTimeout (void) const;
|
||||
|
||||
/**
|
||||
* \brief Translate between a NSC error and a ns-3 error code
|
||||
* \param err NSC error
|
||||
* \returns ns-3 error code
|
||||
*/
|
||||
enum Socket::SocketErrno GetNativeNs3Errno (int err) const;
|
||||
uint32_t m_delAckMaxCount; //!< Number of packet to fire an ACK before delay timeout
|
||||
Time m_delAckTimeout; //!< Time to delay an ACK
|
||||
bool m_noDelay; //!< Disable ACk delay
|
||||
|
||||
Ipv4EndPoint *m_endPoint; //!< the IPv4 endpoint
|
||||
Ptr<Node> m_node; //!< the associated node
|
||||
Ptr<NscTcpL4Protocol> m_tcp; //!< the associated TCP L4 protocol
|
||||
Ipv4Address m_remoteAddress; //!< peer IP address
|
||||
uint16_t m_remotePort; //!< peer port
|
||||
//these two are so that the socket/endpoint cloning works
|
||||
Ipv4Address m_localAddress; //!< local address
|
||||
uint16_t m_localPort; //!< local port
|
||||
InetSocketAddress m_peerAddress; //!< peer IP and port
|
||||
mutable enum SocketErrno m_errno; //!< last error number
|
||||
bool m_shutdownSend; //!< Send no longer allowed
|
||||
bool m_shutdownRecv; //!< Receive no longer allowed
|
||||
bool m_connected; //!< Connection established
|
||||
|
||||
//manage the state information
|
||||
TracedValue<TcpStates_t> m_state; //!< state information
|
||||
bool m_closeOnEmpty; //!< true if socket will close when buffer is empty
|
||||
|
||||
//needed to queue data when in SYN_SENT state
|
||||
std::queue<Ptr<Packet> > m_txBuffer; //!< transmission buffer
|
||||
uint32_t m_txBufferSize; //!< transmission buffer size
|
||||
|
||||
// Window management
|
||||
uint32_t m_segmentSize; //!< SegmentSize
|
||||
uint32_t m_rxWindowSize; //!< Receive window size
|
||||
uint32_t m_advertisedWindowSize; //!< Window to advertise
|
||||
TracedValue<uint32_t> m_cWnd; //!< Congestion window
|
||||
TracedValue<uint32_t> m_ssThresh; //!< Slow Start Threshold
|
||||
uint32_t m_initialCWnd; //!< Initial cWnd value
|
||||
uint32_t m_initialSsThresh; //!< Initial Slow Start Threshold
|
||||
|
||||
// Round trip time estimation
|
||||
Time m_lastMeasuredRtt; //!< Last measured RTT
|
||||
|
||||
// Timer-related members
|
||||
Time m_cnTimeout; //!< Timeout for connection retry
|
||||
uint32_t m_synRetries; //!< Count of remaining connection retries
|
||||
uint32_t m_dataRetries; //!< Count of remaining data retransmission attempts
|
||||
Time m_persistTimeout; //!< Time between sending 1-byte probes
|
||||
|
||||
// Temporary queue for delivering data to application
|
||||
std::queue<Ptr<Packet> > m_deliveryQueue; //!< receive buffer
|
||||
uint32_t m_rxAvailable; //!< receive buffer available size
|
||||
INetStreamSocket* m_nscTcpSocket; //!< the real NSC TCP socket
|
||||
|
||||
// Attributes
|
||||
uint32_t m_sndBufSize; //!< buffer limit for the outgoing queue
|
||||
uint32_t m_rcvBufSize; //!< maximum receive socket buffer size
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* NSC_TCP_SOCKET_IMPL_H */
|
||||
@@ -4,104 +4,6 @@ import sys
|
||||
|
||||
from waflib import Options, Logs, Utils, Task
|
||||
|
||||
|
||||
# Required NSC version
|
||||
NSC_RELEASE_NAME = "nsc-0.5.3"
|
||||
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--with-nsc',
|
||||
help=('Use Network Simulation Cradle, given by the indicated path,'
|
||||
' to allow the use of real-world network stacks'),
|
||||
default='', dest='with_nsc')
|
||||
opt.add_option('--disable-nsc',
|
||||
help=('Disable Network Simulation Cradle support'),
|
||||
dest='disable_nsc', default=False, action="store_true")
|
||||
|
||||
def configure(conf):
|
||||
conf.env['ENABLE_NSC'] = False
|
||||
|
||||
if Options.options.disable_nsc:
|
||||
conf.report_optional_feature("nsc", "Network Simulation Cradle", False,
|
||||
"disabled by user request")
|
||||
return
|
||||
|
||||
# checks for flex and bison, which is needed to build NSCs globaliser
|
||||
# TODO: how to move these checks into the allinone scripts?
|
||||
#def check_nsc_buildutils():
|
||||
# import flex
|
||||
# import bison
|
||||
# conf.check_tool('flex bison')
|
||||
# conf.check(lib='fl', mandatory=True)
|
||||
|
||||
# Check for the location of NSC
|
||||
lib_to_check = 'liblinux2.6.26.so'
|
||||
if Options.options.with_nsc:
|
||||
if os.path.isdir(Options.options.with_nsc):
|
||||
conf.msg("Checking for NSC location", ("%s (given)" % Options.options.with_nsc))
|
||||
conf.env['WITH_NSC'] = os.path.abspath(Options.options.with_nsc)
|
||||
else:
|
||||
# bake.py uses ../../build, while ns-3-dev uses ../nsc,
|
||||
# and ns-3 release uses ../NSC_RELEASE_NAME
|
||||
nsc_bake_build_dir = os.path.join('..', '..', 'build')
|
||||
nsc_bake_lib_dir = os.path.join(nsc_bake_build_dir, 'lib')
|
||||
nsc_dir = os.path.join('..', "nsc")
|
||||
nsc_release_dir = os.path.join('..', NSC_RELEASE_NAME)
|
||||
if os.path.exists(os.path.join(nsc_bake_lib_dir, lib_to_check)):
|
||||
conf.msg("Checking for NSC location",("%s (guessed)" % nsc_bake_build_dir))
|
||||
conf.env['WITH_NSC'] = os.path.abspath(nsc_bake_build_dir)
|
||||
elif os.path.isdir(nsc_dir):
|
||||
conf.msg("Checking for NSC location",("%s (guessed)" % nsc_dir))
|
||||
conf.env['WITH_NSC'] = os.path.abspath(nsc_dir)
|
||||
elif os.path.isdir(nsc_release_dir):
|
||||
conf.msg("Checking for NSC location", ("%s (guessed)" % nsc_release_dir))
|
||||
conf.env['WITH_NSC'] = os.path.abspath(nsc_release_dir)
|
||||
del nsc_bake_build_dir
|
||||
del nsc_bake_lib_dir
|
||||
del nsc_dir
|
||||
del nsc_release_dir
|
||||
|
||||
if not conf.env['WITH_NSC']:
|
||||
conf.msg("Checking for NSC location", False)
|
||||
conf.report_optional_feature("nsc", "Network Simulation Cradle", False,
|
||||
"NSC not found (see option --with-nsc)")
|
||||
return
|
||||
|
||||
if Utils.unversioned_sys_platform() in ['linux', 'freebsd']:
|
||||
arch = os.uname()[4]
|
||||
else:
|
||||
arch = None
|
||||
ok = False
|
||||
if arch in ('amd64', 'x86_64', 'i686', 'i586', 'i486', 'i386'):
|
||||
conf.env['NSC_ENABLED'] = True
|
||||
conf.env.append_value('CXXDEFINES', 'NETWORK_SIMULATION_CRADLE')
|
||||
conf.check_nonfatal(mandatory=True, lib='dl', define_name='HAVE_DL', uselib_store='DL')
|
||||
ok = True
|
||||
conf.msg('Checking for NSC supported architecture ' + (arch or ''), ok)
|
||||
|
||||
if not ok:
|
||||
conf.env['NSC_ENABLED'] = False
|
||||
conf.report_optional_feature("nsc", "Network Simulation Cradle", False,
|
||||
"architecture %r not supported" % arch)
|
||||
return
|
||||
|
||||
found = False
|
||||
for path in ['.', 'lib', 'lib64', 'linux-2.6.26']:
|
||||
if os.path.exists(os.path.join(conf.env['WITH_NSC'], path, lib_to_check)):
|
||||
# append the NSC kernel dir to the module path so that this dir
|
||||
# will end up in the LD_LIBRARY_PATH, thus allowing the NSC NS-3
|
||||
# module to find the necessary NSC shared libraries.
|
||||
found = True
|
||||
conf.env.append_value('NS3_MODULE_PATH',
|
||||
os.path.abspath(os.path.join(conf.env['WITH_NSC'], path)))
|
||||
if not found:
|
||||
conf.env['NSC_ENABLED'] = False
|
||||
conf.report_optional_feature("nsc", "Network Simulation Cradle", False,
|
||||
"NSC library %s is missing: NSC has not been built?" % lib_to_check)
|
||||
else:
|
||||
conf.report_optional_feature("nsc", "Network Simulation Cradle", True, "")
|
||||
|
||||
|
||||
def build(bld):
|
||||
# bridge dependency is due to global routing
|
||||
obj = bld.create_ns3_module('internet', ['bridge', 'traffic-control', 'network', 'core'])
|
||||
@@ -445,15 +347,6 @@ def build(bld):
|
||||
'helper/rip-helper.h',
|
||||
]
|
||||
|
||||
if bld.env['NSC_ENABLED']:
|
||||
obj.source.append ('model/nsc-tcp-socket-impl.cc')
|
||||
obj.source.append ('model/nsc-tcp-l4-protocol.cc')
|
||||
obj.source.append ('model/nsc-tcp-socket-factory-impl.cc')
|
||||
obj.source.append ('model/nsc-sysctl.cc')
|
||||
headers.source.append('model/nsc-tcp-l4-protocol.h')
|
||||
obj.use.append('DL')
|
||||
internet_test.use.append('DL')
|
||||
|
||||
if (bld.env['ENABLE_EXAMPLES']):
|
||||
bld.recurse('examples')
|
||||
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
set(name test)
|
||||
|
||||
set(nsc_sources)
|
||||
if(${NS3_NSC})
|
||||
set(nsc_sources
|
||||
ns3tcp/ns3tcp-cwnd-test-suite.cc ns3tcp/ns3tcp-interop-test-suite.cc
|
||||
ns3tcp/nsctcp-loss-test-suite.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
set(csma-layout_sources)
|
||||
if(csma-layout IN_LIST ns3-all-enabled-modules)
|
||||
set(csma-layout_sources csma-system-test-suite.cc)
|
||||
@@ -23,13 +15,10 @@ set(wifi_sources)
|
||||
if(applications IN_LIST ns3-all-enabled-modules)
|
||||
if(point-to-point IN_LIST ns3-all-enabled-modules)
|
||||
set(applications_sources
|
||||
ns3tcp/ns3tcp-cwnd-test-suite.cc
|
||||
ns3tcp/ns3tcp-interop-test-suite.cc
|
||||
ns3tcp/ns3tcp-loss-test-suite.cc
|
||||
ns3tcp/ns3tcp-no-delay-test-suite.cc
|
||||
ns3tcp/ns3tcp-socket-test-suite.cc
|
||||
ns3tcp/ns3tcp-state-test-suite.cc
|
||||
ns3tcp/nsctcp-loss-test-suite.cc
|
||||
)
|
||||
endif()
|
||||
if(wifi IN_LIST ns3-all-enabled-modules)
|
||||
@@ -63,7 +52,6 @@ add_library(
|
||||
${csma-layout_sources}
|
||||
${dsr_sources}
|
||||
${internet_sources}
|
||||
${nsc_sources}
|
||||
${traffic-control_sources}
|
||||
traced/traced-value-callback-typedef-test-suite.cc
|
||||
${wifi_sources}
|
||||
|
||||
@@ -1,631 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/pcap-file.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/point-to-point-helper.h"
|
||||
#include "ns3/internet-stack-helper.h"
|
||||
#include "ns3/ipv4-global-routing-helper.h"
|
||||
#include "ns3/ipv4-address-helper.h"
|
||||
#include "ns3/packet-sink-helper.h"
|
||||
#include "ns3/tcp-socket-factory.h"
|
||||
#include "ns3/traffic-control-helper.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/queue.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("Ns3CwndTest");
|
||||
|
||||
// ===========================================================================
|
||||
// This is a simple test to demonstrate how a known good model (a reference
|
||||
// implementation) may be used to test another model without resorting to
|
||||
// storing stimulus or response vectors.
|
||||
//
|
||||
// Node zero contains the model under test, in this case the ns-3 TCP
|
||||
// implementation. Node one contains the reference implementation that we
|
||||
// assume will generate good test vectors for us. In this case, a Linux
|
||||
// TCP implementation is used to stimulate the ns-3 TCP model with what we
|
||||
// assume are perfectly good packets. We watch the ns-3 implementation to
|
||||
// see what it does in the presence of these assumed good stimuli.
|
||||
//
|
||||
// The test is arranged as a typical ns-3 script, but we use the trace system
|
||||
// to peek into the running system and monitor the ns-3 TCP.
|
||||
//
|
||||
// The topology is just two nodes communicating over a point-to-point network.
|
||||
// The point-to-point network is chosen because it is simple and allows us to
|
||||
// easily generate pcap traces we can use to separately verify that the ns-3
|
||||
// implementation is responding correctly. Once the operation is verified, we
|
||||
// enter a list of responses that capture the response succinctly.
|
||||
//
|
||||
// node 0 node 1
|
||||
// +----------------+ +----------------+
|
||||
// | ns-3 TCP | | Linux TCP |
|
||||
// +----------------+ +----------------+
|
||||
// | 10.1.1.1 | | 10.1.1.2 |
|
||||
// +----------------+ +----------------+
|
||||
// | point-to-point | | point-to-point |
|
||||
// +----------------+ +----------------+
|
||||
// | |
|
||||
// +---------------------+
|
||||
// 5 Mbps, 2 ms
|
||||
//
|
||||
// ===========================================================================
|
||||
//
|
||||
class SimpleSource : public Application
|
||||
{
|
||||
public:
|
||||
|
||||
SimpleSource ();
|
||||
virtual ~SimpleSource();
|
||||
|
||||
/**
|
||||
* Register this type.
|
||||
* \return The TypeId.
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
|
||||
|
||||
private:
|
||||
virtual void StartApplication (void);
|
||||
virtual void StopApplication (void);
|
||||
|
||||
void ScheduleTx (void);
|
||||
void SendPacket (void);
|
||||
|
||||
Ptr<Socket> 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;
|
||||
};
|
||||
|
||||
SimpleSource::SimpleSource ()
|
||||
: m_socket (0),
|
||||
m_peer (),
|
||||
m_packetSize (0),
|
||||
m_nPackets (0),
|
||||
m_dataRate (0),
|
||||
m_sendEvent (),
|
||||
m_running (false),
|
||||
m_packetsSent (0)
|
||||
{
|
||||
}
|
||||
|
||||
SimpleSource::~SimpleSource()
|
||||
{
|
||||
m_socket = 0;
|
||||
}
|
||||
|
||||
/* static */
|
||||
TypeId
|
||||
SimpleSource::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("SimpleSource")
|
||||
.SetParent<Application> ()
|
||||
.SetGroupName ("Stats")
|
||||
.AddConstructor<SimpleSource> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
void
|
||||
SimpleSource::Setup (Ptr<Socket> 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;
|
||||
}
|
||||
|
||||
void
|
||||
SimpleSource::StartApplication (void)
|
||||
{
|
||||
m_running = true;
|
||||
m_packetsSent = 0;
|
||||
m_socket->Bind ();
|
||||
m_socket->Connect (m_peer);
|
||||
SendPacket ();
|
||||
}
|
||||
|
||||
void
|
||||
SimpleSource::StopApplication (void)
|
||||
{
|
||||
m_running = false;
|
||||
|
||||
if (m_sendEvent.IsRunning ())
|
||||
{
|
||||
Simulator::Cancel (m_sendEvent);
|
||||
}
|
||||
|
||||
if (m_socket)
|
||||
{
|
||||
m_socket->Close ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SimpleSource::SendPacket (void)
|
||||
{
|
||||
Ptr<Packet> packet = Create<Packet> (m_packetSize);
|
||||
m_socket->Send (packet);
|
||||
|
||||
if (++m_packetsSent < m_nPackets)
|
||||
{
|
||||
ScheduleTx ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SimpleSource::ScheduleTx (void)
|
||||
{
|
||||
if (m_running)
|
||||
{
|
||||
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
|
||||
m_sendEvent = Simulator::Schedule (tNext, &SimpleSource::SendPacket, this);
|
||||
}
|
||||
}
|
||||
|
||||
class Ns3TcpCwndTestCase1 : public TestCase
|
||||
{
|
||||
public:
|
||||
Ns3TcpCwndTestCase1 ();
|
||||
virtual ~Ns3TcpCwndTestCase1 ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
bool m_writeResults;
|
||||
|
||||
class CwndEvent {
|
||||
public:
|
||||
uint32_t m_oldCwnd;
|
||||
uint32_t m_newCwnd;
|
||||
};
|
||||
|
||||
TestVectors<CwndEvent> m_responses;
|
||||
|
||||
void CwndChange (uint32_t oldCwnd, uint32_t newCwnd);
|
||||
};
|
||||
|
||||
Ns3TcpCwndTestCase1::Ns3TcpCwndTestCase1 ()
|
||||
: TestCase ("Check to see that the ns-3 TCP congestion window works as expected against liblinux2.6.26.so"),
|
||||
m_writeResults (false)
|
||||
{
|
||||
}
|
||||
|
||||
Ns3TcpCwndTestCase1::~Ns3TcpCwndTestCase1 ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpCwndTestCase1::CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
|
||||
{
|
||||
CwndEvent event;
|
||||
|
||||
event.m_oldCwnd = oldCwnd;
|
||||
event.m_newCwnd = newCwnd;
|
||||
|
||||
m_responses.Add (event);
|
||||
|
||||
NS_LOG_DEBUG ("Cwnd change event " << m_responses.GetN () << " at " << Now ().As (Time::S) << " " << oldCwnd << " " << newCwnd);
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpCwndTestCase1::DoRun (void)
|
||||
{
|
||||
NS_LOG_DEBUG ("Starting test case 1");
|
||||
// This test was written with initial window of 1 segment
|
||||
Config::SetDefault ("ns3::TcpSocket::InitialCwnd", UintegerValue (1));
|
||||
|
||||
//
|
||||
// Create two nodes. One (node zero) will be the node with the TCP
|
||||
// under test which is the ns-3 TCP implementation. The other node (node
|
||||
// one) will be the node with the reference implementation we use to drive
|
||||
// the tests.
|
||||
//
|
||||
NodeContainer nodes;
|
||||
nodes.Create (2);
|
||||
|
||||
//
|
||||
// For this test we'll use a point-to-point net device. It's not as simple
|
||||
// as a simple-net-device, but it provides nice places to hook trace events
|
||||
// so we can see what's moving between our nodes.
|
||||
//
|
||||
PointToPointHelper pointToPoint;
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
|
||||
|
||||
NetDeviceContainer devices;
|
||||
devices = pointToPoint.Install (nodes);
|
||||
|
||||
//
|
||||
// Install two variants of the internet stack. The first, on node zero
|
||||
// uses the TCP under test, which is the default ns-3 TCP implementation.
|
||||
//
|
||||
InternetStackHelper stack;
|
||||
stack.Install (nodes.Get (0));
|
||||
|
||||
//
|
||||
// The other node, node one, is going to be set up to use a Linux TCP
|
||||
// implementation that we consider a known good TCP.
|
||||
//
|
||||
std::string nscStack = "liblinux2.6.26.so";
|
||||
stack.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
|
||||
stack.Install (nodes.Get (1));
|
||||
|
||||
//
|
||||
// Assign the address 10.1.1.1 to the TCP implementation under test (index
|
||||
// zero) and 10.1.1.2 to the reference implementation (index one).
|
||||
//
|
||||
Ipv4AddressHelper address;
|
||||
address.SetBase ("10.1.1.0", "255.255.255.252");
|
||||
Ipv4InterfaceContainer interfaces = address.Assign (devices);
|
||||
|
||||
//
|
||||
// We need a place to send our TCP data on the node with the reference TCP
|
||||
// implementation. We aren't really concerned about what happens there, so
|
||||
// just create a sink.
|
||||
//
|
||||
uint16_t sinkPort = 8080;
|
||||
Address sinkAddress (InetSocketAddress (interfaces.GetAddress (1), sinkPort));
|
||||
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
|
||||
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
|
||||
sinkApps.Start (Seconds (0.));
|
||||
sinkApps.Stop (Seconds (1.1));
|
||||
|
||||
//
|
||||
// This test uses a custom application that provides a direct handle to
|
||||
// the socket (the socket of applications such as the OnOffApplication
|
||||
// is not created until Application Start time, and is not easily accessible).
|
||||
//
|
||||
// So first, we create a socket and do the trace connect on it; then we pass this
|
||||
// socket into the constructor of our simple application which we then install
|
||||
// in the node with the ns-3 TCP.
|
||||
//
|
||||
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
|
||||
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindowInflated", MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, this));
|
||||
|
||||
Ptr<SimpleSource> app = CreateObject<SimpleSource> ();
|
||||
// 1040 is size of packet objects used to write data to the socket (note:
|
||||
// the actual TCP segment size will be 536 bytes). 10 is the number
|
||||
// of packets, so we write 10 * 1040 bytes. This requires 20 segments
|
||||
// of payload size 536, with the last one being a partially full segment
|
||||
app->Setup (ns3TcpSocket, sinkAddress, 1040, 10, DataRate ("5Mbps"));
|
||||
nodes.Get (0)->AddApplication (app);
|
||||
app->SetStartTime (Seconds (1.));
|
||||
app->SetStopTime (Seconds (1.1));
|
||||
|
||||
//
|
||||
// The idea here is that someone will look very closely at the all of the
|
||||
// communications between the reference TCP and the TCP under test in this
|
||||
// simulation and determine that all of the responses are correct. We expect
|
||||
// that this means generating a pcap trace file from the point-to-point link
|
||||
// and examining the packets closely using tcpdump, wireshark or some such
|
||||
// program. So we provide the ability to generate a pcap trace of the
|
||||
// test execution for your perusal.
|
||||
//
|
||||
// Once the validation test is determined to be running exactly as expected,
|
||||
// the set of congestion window changes is collected and hard coded into the
|
||||
// test results which will then be checked during the actual execution of the
|
||||
// test.
|
||||
//
|
||||
|
||||
if (m_writeResults)
|
||||
{
|
||||
pointToPoint.EnablePcapAll ("tcp-cwnd");
|
||||
}
|
||||
|
||||
Simulator::Stop (Seconds (2));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
//
|
||||
// As new acks are received by the TCP under test, the congestion window
|
||||
// should be opened up by one segment (MSS bytes) each time. This should
|
||||
// trigger a congestion window change event which we hooked and saved above.
|
||||
// We should now be able to look through the saved response vectors and follow
|
||||
// the congestion window as it opens up when the ns-3 TCP under test
|
||||
// transmits its bits
|
||||
//
|
||||
// From inspecting the results, we know that we should see N_EVENTS congestion
|
||||
// window change events (each time by MSS bytes) until reaching the largest
|
||||
// value when the client closes.
|
||||
//
|
||||
const uint32_t MSS = 536;
|
||||
const uint32_t N_EVENTS = 20;
|
||||
|
||||
CwndEvent event;
|
||||
|
||||
NS_TEST_ASSERT_MSG_EQ (m_responses.GetN (), N_EVENTS, "Unexpectedly low number of cwnd change events");
|
||||
|
||||
// Ignore the first event logged (i=0) when m_cWnd goes from 0 to MSS bytes
|
||||
for (uint32_t i = 1, from = MSS, to = MSS * 2; i < N_EVENTS; ++i, from += MSS, to += MSS)
|
||||
{
|
||||
event = m_responses.Get (i);
|
||||
NS_TEST_ASSERT_MSG_EQ (event.m_oldCwnd, from, "Wrong old cwnd value in cwnd change event " << i);
|
||||
NS_TEST_ASSERT_MSG_EQ (event.m_newCwnd, to, "Wrong new cwnd value in cwnd change event " << i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
// Test case for cwnd changes due to out-of-order packets. A bottleneck
|
||||
// link is created, and a limited droptail queue is used in order to
|
||||
// force dropped packets, resulting in out-of-order packet delivery.
|
||||
// This out-of-order delivery will result in a different congestion
|
||||
// window behavior than testcase 1. Specifically, duplicate ACKs
|
||||
// are encountered.
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 1Mb/s, 10ms 100kb/s, 10ms 1Mb/s, 10ms
|
||||
// n0--------------n1-----------------n2---------------n3
|
||||
//
|
||||
// ===========================================================================
|
||||
class Ns3TcpCwndTestCase2 : public TestCase
|
||||
{
|
||||
public:
|
||||
Ns3TcpCwndTestCase2 ();
|
||||
virtual ~Ns3TcpCwndTestCase2 ();
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
void VerifyCwndRun (uint32_t beginIdx, uint32_t endIdx, uint32_t initialCwnd, uint32_t mss);
|
||||
bool m_writeResults;
|
||||
|
||||
class CwndEvent {
|
||||
public:
|
||||
uint32_t m_oldCwnd;
|
||||
uint32_t m_newCwnd;
|
||||
};
|
||||
|
||||
TestVectors<CwndEvent> m_responses;
|
||||
|
||||
void CwndChange (uint32_t oldCwnd, uint32_t newCwnd);
|
||||
void CwndChangeNotInflated (uint32_t oldCwnd, uint32_t newCwnd);
|
||||
};
|
||||
|
||||
Ns3TcpCwndTestCase2::Ns3TcpCwndTestCase2 ()
|
||||
: TestCase ("Check to see that the ns-3 TCP congestion window works as expected for out-of-order packet delivery"),
|
||||
m_writeResults (false)
|
||||
{
|
||||
}
|
||||
|
||||
Ns3TcpCwndTestCase2::~Ns3TcpCwndTestCase2 ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpCwndTestCase2::CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
|
||||
{
|
||||
CwndEvent event;
|
||||
|
||||
event.m_oldCwnd = oldCwnd;
|
||||
event.m_newCwnd = newCwnd;
|
||||
|
||||
m_responses.Add (event);
|
||||
NS_LOG_DEBUG ("Cwnd change event " << m_responses.GetN () << " at " << Now ().As (Time::S) << " " << oldCwnd << " " << newCwnd);
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpCwndTestCase2::CwndChangeNotInflated (uint32_t oldCwnd, uint32_t newCwnd)
|
||||
{
|
||||
NS_LOG_DEBUG ("Cwnd NOT INFLATED change event " << m_responses.GetN () << " at " << Now ().As (Time::S) << " " << oldCwnd << " " << newCwnd);
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpCwndTestCase2::DoRun (void)
|
||||
{
|
||||
NS_LOG_DEBUG ("Starting test case 2");
|
||||
// Set up some default values for the simulation.
|
||||
Config::SetDefault ("ns3::QueueBase::MaxSize", QueueSizeValue (QueueSize (QueueSizeUnit::PACKETS, 4)));
|
||||
Packet::EnablePrinting ();
|
||||
// This test was written with initial window of 1 segment
|
||||
Config::SetDefault ("ns3::TcpSocket::InitialCwnd", UintegerValue (1));
|
||||
|
||||
NodeContainer n0n1;
|
||||
n0n1.Create (2);
|
||||
|
||||
NodeContainer n1n2;
|
||||
n1n2.Add (n0n1.Get (1));
|
||||
n1n2.Create (1);
|
||||
|
||||
NodeContainer n2n3;
|
||||
n2n3.Add (n1n2.Get (1));
|
||||
n2n3.Create (1);
|
||||
|
||||
PointToPointHelper p2p1;
|
||||
p2p1.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (1000000)));
|
||||
p2p1.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (10)));
|
||||
PointToPointHelper p2p2;
|
||||
p2p2.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (100000)));
|
||||
p2p2.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (10)));
|
||||
|
||||
// And then install devices and channels connecting our topology.
|
||||
NetDeviceContainer dev0 = p2p1.Install (n0n1);
|
||||
NetDeviceContainer dev1 = p2p2.Install (n1n2);
|
||||
NetDeviceContainer dev2 = p2p1.Install (n2n3);
|
||||
|
||||
// Now add ip/tcp stack to all nodes.
|
||||
InternetStackHelper internet;
|
||||
internet.InstallAll ();
|
||||
|
||||
// Later, we add IP addresses.
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
|
||||
ipv4.Assign (dev0);
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
ipv4.Assign (dev1);
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer ipInterfs = ipv4.Assign (dev2);
|
||||
|
||||
// and setup ip routing tables to get total ip-level connectivity.
|
||||
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
|
||||
|
||||
// Disable traffic control layer so that drops occur
|
||||
TrafficControlHelper tch;
|
||||
tch.Uninstall (dev0);
|
||||
tch.Uninstall (dev1);
|
||||
tch.Uninstall (dev2);
|
||||
|
||||
// Set up the apps
|
||||
uint16_t servPort = 50000;
|
||||
|
||||
// Create a packet sink to receive these packets on n3
|
||||
PacketSinkHelper sink ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort));
|
||||
|
||||
ApplicationContainer apps = sink.Install (n2n3.Get (1));
|
||||
apps.Start (Seconds (0.0));
|
||||
apps.Stop (Seconds (5.4));
|
||||
|
||||
// Create the socket for n0
|
||||
Address sinkAddress (InetSocketAddress (ipInterfs.GetAddress (1), servPort));
|
||||
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (n0n1.Get (0), TcpSocketFactory::GetTypeId ());
|
||||
// Disable SACK because this test is testing NewReno behavior
|
||||
ns3TcpSocket->SetAttribute ("Sack", BooleanValue (false));
|
||||
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindowInflated", MakeCallback (&Ns3TcpCwndTestCase2::CwndChange, this));
|
||||
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&Ns3TcpCwndTestCase2::CwndChangeNotInflated, this));
|
||||
|
||||
// Create and start the app for n0
|
||||
Ptr<SimpleSource> app = CreateObject<SimpleSource> ();
|
||||
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
|
||||
n0n1.Get (0)->AddApplication (app);
|
||||
app->SetStartTime (Seconds (1.0));
|
||||
app->SetStopTime (Seconds (4.1));
|
||||
|
||||
if (m_writeResults)
|
||||
{
|
||||
// Write a pcap for tcp cwnd testcase with out-of-order delivery
|
||||
PointToPointHelper pointToPoint;
|
||||
pointToPoint.EnablePcapAll ("tcp-cwnd-ood");
|
||||
}
|
||||
|
||||
// Finally, set up the simulator to run.
|
||||
Simulator::Stop (Seconds (4.1));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
//
|
||||
// As new acks are received by the TCP under test, the congestion window
|
||||
// should be opened up by one segment (MSS bytes) each time. This should
|
||||
// trigger a congestion window change event which we hooked and saved above.
|
||||
// We should now be able to look through the saved response vectors and follow
|
||||
// the congestion window as it opens up when the ns-3 TCP under test
|
||||
// transmits its bits
|
||||
//
|
||||
// From inspecting the results, we know that we should see N_EVENTS congestion
|
||||
// window change events. On the tenth change event, the window should
|
||||
// be cut from 5360 to 4288 due to 3 dup acks (NewReno behavior is to
|
||||
// cut in half, and then add 3 segments (5360/2 + 3*536 = 4288)
|
||||
//
|
||||
|
||||
const uint32_t MSS = 536;
|
||||
const uint32_t N_EVENTS = 38;
|
||||
|
||||
CwndEvent event;
|
||||
|
||||
NS_LOG_DEBUG ("Number of response events: " << m_responses.GetN ());
|
||||
//NS_TEST_ASSERT_MSG_EQ (m_responses.GetN (), N_EVENTS, "Unexpected number of cwnd change events");
|
||||
|
||||
// Ignore the first event logged (i=0) when m_cWnd goes from 0 to MSS bytes
|
||||
VerifyCwndRun (1, 10, 2 * MSS, MSS);
|
||||
|
||||
// At the point of loss, sndNxt = 15545; sndUna = 9113. FlightSize is 4824,
|
||||
// so there are 9 segments outstanding. Cut ssthresh to 9/2 (2412) and
|
||||
// cwnd to (9/2 + 3) = 4020
|
||||
event = m_responses.Get (10);
|
||||
NS_TEST_ASSERT_MSG_EQ (event.m_newCwnd, (MSS * 15)/2, "Wrong new cwnd value in cwnd change event " << 10);
|
||||
|
||||
// Verify that cwnd increments by one for a few segments
|
||||
// from 8.5 at index 11 to 12.5 at index 15
|
||||
VerifyCwndRun (11, 15, (MSS * 17)/2, MSS);
|
||||
|
||||
// partial ack at event 16, cwnd reset from 6700 (12.5*MSS) to 5092 (9.5*MSS)
|
||||
NS_TEST_ASSERT_MSG_EQ (m_responses.Get (16).m_newCwnd, (MSS * 19)/2, "Wrong new cwnd value in cwnd change event " << 16);
|
||||
|
||||
// partial ack again of 3 segments after one more acks, cwnd reset to 7.5
|
||||
NS_TEST_ASSERT_MSG_EQ (m_responses.Get (18).m_newCwnd, (MSS * 15)/2, "Wrong new cwnd value in cwnd change event " << 18);
|
||||
|
||||
//DUP ACKS in remaining fast recovery
|
||||
VerifyCwndRun (18, 20, (MSS * 15)/2, MSS);
|
||||
|
||||
// Process another partial ack
|
||||
VerifyCwndRun (21, 24, (MSS * 13)/2, MSS);
|
||||
|
||||
// Leaving fast recovery at event 25; set cwnd to 4 segments as per RFC 2582
|
||||
// Sec. 3 para. 5 option 2 (sshthresh is 2412, 4.5 times MSS)
|
||||
NS_TEST_ASSERT_MSG_EQ (m_responses.Get (25).m_newCwnd, 2412, "Wrong new cwnd value in cwnd change event " << 25);
|
||||
|
||||
//In CongAvoid each event will increase cwnd by (MSS * MSS / cwnd)
|
||||
uint32_t cwnd = 2412;
|
||||
for (uint32_t i = 26; i < N_EVENTS; ++i)
|
||||
{
|
||||
double adder = static_cast<double> (MSS * MSS) / cwnd;
|
||||
adder = std::max (1.0, adder);
|
||||
cwnd += static_cast<uint32_t> (adder);
|
||||
NS_TEST_ASSERT_MSG_EQ (m_responses.Get (i).m_newCwnd, cwnd, "Wrong new cwnd value in cwnd change event " << i);
|
||||
}
|
||||
NS_LOG_DEBUG ("Reading out the cwnd event log");
|
||||
for (uint32_t i = 0; i < N_EVENTS; ++i)
|
||||
{
|
||||
NS_LOG_DEBUG ("i: " << i << " newCwnd: " << m_responses.Get(i).m_newCwnd << " newCwnd segments " << static_cast<double> (m_responses.Get(i).m_newCwnd)/MSS);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpCwndTestCase2::VerifyCwndRun (uint32_t beginIdx, uint32_t endIdx, uint32_t initialCwnd, uint32_t mss)
|
||||
{
|
||||
|
||||
CwndEvent event;
|
||||
|
||||
for(uint32_t i = beginIdx, to = initialCwnd; i < endIdx; ++i, to += mss)
|
||||
{
|
||||
event = m_responses.Get (i);
|
||||
NS_TEST_ASSERT_MSG_EQ (event.m_newCwnd, to, "Wrong new cwnd value in cwnd change event " << i);
|
||||
}
|
||||
}
|
||||
|
||||
class Ns3TcpCwndTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
Ns3TcpCwndTestSuite ();
|
||||
};
|
||||
|
||||
Ns3TcpCwndTestSuite::Ns3TcpCwndTestSuite ()
|
||||
: TestSuite ("ns3-tcp-cwnd", SYSTEM)
|
||||
{
|
||||
AddTestCase (new Ns3TcpCwndTestCase1, TestCase::QUICK);
|
||||
AddTestCase (new Ns3TcpCwndTestCase2, TestCase::QUICK);
|
||||
}
|
||||
|
||||
Ns3TcpCwndTestSuite ns3TcpCwndTestSuite;
|
||||
@@ -1,325 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/pcap-file.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/point-to-point-helper.h"
|
||||
#include "ns3/internet-stack-helper.h"
|
||||
#include "ns3/ipv4-address-helper.h"
|
||||
#include "ns3/ipv4-header.h"
|
||||
#include "ns3/packet-sink-helper.h"
|
||||
#include "ns3/on-off-helper.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("Ns3TcpInteropTest");
|
||||
|
||||
// The below boolean constants should only be changed to 'true'
|
||||
// during test debugging (i.e. do not commit the value 'true')
|
||||
|
||||
// set to 'true' to have the test suite overwrite the response vectors
|
||||
// stored in the test directory. This should only be done if you are
|
||||
// convinced through other means (e.g. pcap tracing or logging) that the
|
||||
// revised vectors are the correct ones. In other words, don't simply
|
||||
// enable this to true to clear a failing test without looking at the
|
||||
// results closely.
|
||||
const bool WRITE_VECTORS = false; // set to true to write response vectors
|
||||
const bool WRITE_PCAP = false; // set to true to write out pcap
|
||||
const uint32_t PCAP_LINK_TYPE = 1187373553; // Some large random number -- we use to verify data was written by this program
|
||||
const uint32_t PCAP_SNAPLEN = 64; // Don't bother to save much data
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
// This is a simple test to demonstrate how a known good model (a reference
|
||||
// implementation) may be used to test another model in a relatively simple
|
||||
// way.
|
||||
//
|
||||
// Node zero contains the model under test, in this case the ns-3 TCP
|
||||
// implementation. Node one contains the reference implementation that we
|
||||
// assume will generate good test vectors for us. In this case, a Linux
|
||||
// TCP implementation is used to stimulate the ns-3 TCP model with what we
|
||||
// assume are perfectly good packets. We watch the ns-3 implementation to
|
||||
// see what it does in the presence of these assumed good stimuli.
|
||||
//
|
||||
// The test is arranged as a typical ns-3 script, but we use the trace system
|
||||
// to peek into the running system and monitor the ns-3 TCP.
|
||||
//
|
||||
// The topology is just two nodes communicating over a point-to-point network.
|
||||
// The point-to-point network is chosen because it is simple and allows us to
|
||||
// easily generate pcap traces we can use to separately verify that the ns-3
|
||||
// implementation is responding correctly. Once the operation is verified, we
|
||||
// capture a set of response vectors that are then checked in the test to
|
||||
// ensure that the ns-3 TCP continues to respond correctly over time.
|
||||
//
|
||||
// node 0 node 1
|
||||
// +----------------+ +----------------+
|
||||
// | ns-3 TCP | | Linux TCP |
|
||||
// +----------------+ +----------------+
|
||||
// | 10.1.1.1 | | 10.1.1.2 |
|
||||
// +----------------+ +----------------+
|
||||
// | point-to-point | | point-to-point |
|
||||
// +----------------+ +----------------+
|
||||
// | |
|
||||
// +---------------------+
|
||||
// 5 Mbps, 2 ms
|
||||
//
|
||||
// ===========================================================================
|
||||
class Ns3TcpInteroperabilityTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
Ns3TcpInteroperabilityTestCase ();
|
||||
virtual ~Ns3TcpInteroperabilityTestCase ();
|
||||
|
||||
private:
|
||||
virtual void DoSetup (void);
|
||||
virtual void DoRun (void);
|
||||
virtual void DoTeardown (void);
|
||||
|
||||
void Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
|
||||
|
||||
std::string m_pcapFilename;
|
||||
PcapFile m_pcapFile;
|
||||
bool m_writeVectors;
|
||||
bool m_writeResults;
|
||||
};
|
||||
|
||||
Ns3TcpInteroperabilityTestCase::Ns3TcpInteroperabilityTestCase ()
|
||||
: TestCase ("Check to see that the ns-3 TCP can work with liblinux2.6.26.so"), m_writeVectors (WRITE_VECTORS), m_writeResults (WRITE_PCAP)
|
||||
{
|
||||
}
|
||||
|
||||
Ns3TcpInteroperabilityTestCase::~Ns3TcpInteroperabilityTestCase ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpInteroperabilityTestCase::DoSetup (void)
|
||||
{
|
||||
//
|
||||
// We expect there to be a file called tcp-interop-response-vectors.pcap in
|
||||
// the data directory
|
||||
//
|
||||
m_pcapFilename = CreateDataDirFilename ("ns3tcp-interop-response-vectors.pcap");
|
||||
|
||||
if (m_writeVectors)
|
||||
{
|
||||
m_pcapFile.Open (m_pcapFilename, std::ios::out|std::ios::binary);
|
||||
m_pcapFile.Init (PCAP_LINK_TYPE, PCAP_SNAPLEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pcapFile.Open (m_pcapFilename, std::ios::in|std::ios::binary);
|
||||
NS_ABORT_MSG_UNLESS (m_pcapFile.GetDataLinkType () == PCAP_LINK_TYPE, "Wrong response vectors in directory");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpInteroperabilityTestCase::DoTeardown (void)
|
||||
{
|
||||
m_pcapFile.Close ();
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpInteroperabilityTestCase::Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
|
||||
{
|
||||
//
|
||||
// We're not testing IP so remove and toss the header. In order to do this,
|
||||
// though, we need to copy the packet since we have a const version.
|
||||
//
|
||||
Ptr<Packet> p = packet->Copy ();
|
||||
Ipv4Header ipHeader;
|
||||
p->RemoveHeader (ipHeader);
|
||||
|
||||
//
|
||||
// What is left is the TCP header and any data that may be sent. We aren't
|
||||
// sending any TCP data, so we expect what remains is only TCP header, which
|
||||
// is a small thing to save.
|
||||
//
|
||||
if (m_writeVectors)
|
||||
{
|
||||
//
|
||||
// Save the TCP under test response for later testing.
|
||||
//
|
||||
Time tNow = Simulator::Now ();
|
||||
int64_t tMicroSeconds = tNow.GetMicroSeconds ();
|
||||
|
||||
m_pcapFile.Write (uint32_t (tMicroSeconds / 1000000),
|
||||
uint32_t (tMicroSeconds % 1000000),
|
||||
p
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Read the TCP under test expected response from the expected vector
|
||||
// file and see if it still does the right thing.
|
||||
//
|
||||
uint8_t expected[PCAP_SNAPLEN];
|
||||
uint32_t tsSec, tsUsec, inclLen, origLen, readLen;
|
||||
m_pcapFile.Read (expected, sizeof(expected), tsSec, tsUsec, inclLen, origLen, readLen);
|
||||
|
||||
uint8_t *actual = new uint8_t[readLen];
|
||||
p->CopyData (actual, readLen);
|
||||
|
||||
uint32_t result = memcmp (actual, expected, readLen);
|
||||
|
||||
delete [] actual;
|
||||
|
||||
//
|
||||
// Avoid streams of errors -- only report the first.
|
||||
//
|
||||
if (IsStatusSuccess ())
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ (result, 0, "Expected data comparison error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Ns3TcpInteroperabilityTestCase::DoRun (void)
|
||||
{
|
||||
//
|
||||
// Just create two nodes. One (node zero) will be the node with the TCP
|
||||
// under test which is the ns-3 TCP implementation. The other node (node
|
||||
// one) will be the node with the reference implementation we use to drive
|
||||
// the tests.
|
||||
//
|
||||
NodeContainer nodes;
|
||||
nodes.Create (2);
|
||||
|
||||
//
|
||||
// For this test we'll use a point-to-point net device. It's not as simple
|
||||
// as a simple-net-device, but it provides nice places to hook trace events
|
||||
// so we can see what's moving between our nodes.
|
||||
//
|
||||
PointToPointHelper pointToPoint;
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
|
||||
|
||||
//
|
||||
// Install the point-to-point devices on both nodes and connec them up.
|
||||
//
|
||||
NetDeviceContainer devices;
|
||||
devices = pointToPoint.Install (nodes);
|
||||
|
||||
//
|
||||
// Install two variants of the internet stack. The first, on node zero
|
||||
// uses the TCP under test, which is the default ns-3 TCP implementation.
|
||||
//
|
||||
InternetStackHelper stack;
|
||||
stack.Install (nodes.Get (0));
|
||||
|
||||
//
|
||||
// The other node, node one, is going to be set up to use a Linux TCP
|
||||
// implementation that we consider a known good TCP.
|
||||
//
|
||||
std::string nscStack = "liblinux2.6.26.so";
|
||||
stack.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
|
||||
stack.Install (nodes.Get (1));
|
||||
|
||||
//
|
||||
// Assign the address 10.1.1.1 to the TCP implementation under test (index
|
||||
// zero) and 10.1.1.2 to the reference implementation (index one).
|
||||
//
|
||||
Ipv4AddressHelper address;
|
||||
address.SetBase ("10.1.1.0", "255.255.255.252");
|
||||
Ipv4InterfaceContainer interfaces = address.Assign (devices);
|
||||
|
||||
//
|
||||
// We need a place for the TCP data to go on the node with the TCP under
|
||||
// test, so just create a sink on node zero.
|
||||
//
|
||||
uint16_t sinkPort = 8080;
|
||||
Address sinkAddress (InetSocketAddress (interfaces.GetAddress (0), sinkPort));
|
||||
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
|
||||
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (0));
|
||||
sinkApps.Start (Seconds (0.));
|
||||
|
||||
//
|
||||
// We need something to shove data down the pipe, so we create an on-off
|
||||
// application on the source node with the reference TCP implementation.
|
||||
// The default behavior is to send for one second, then go quiet for one
|
||||
// second, and repeat.
|
||||
//
|
||||
OnOffHelper onOffHelper ("ns3::TcpSocketFactory", sinkAddress);
|
||||
onOffHelper.SetAttribute ("MaxBytes", UintegerValue (100000));
|
||||
ApplicationContainer sourceApps = onOffHelper.Install (nodes.Get (1));
|
||||
sourceApps.Start (Seconds (1.));
|
||||
sourceApps.Stop (Seconds (10.));
|
||||
|
||||
//
|
||||
// There are currently a limited number of trace hooks in the ns-3 TCP code.
|
||||
// Rather than editing TCP to insert a bunch of trace hooks, we can just
|
||||
// intercept the packets at the IPv4 layer. See internet-stack-helper.cc
|
||||
// for complete description of the trace hooks. We're interested in the
|
||||
// responses of the TCP under test, which implies we need to hook the node
|
||||
// zero Ipv4 layer three transmit trace source. We'll then get all of the
|
||||
// responses we need
|
||||
//
|
||||
Config::Connect ("/NodeList/0/$ns3::Ipv4L3Protocol/Tx",
|
||||
MakeCallback (&Ns3TcpInteroperabilityTestCase::Ipv4L3Tx, this));
|
||||
|
||||
//
|
||||
// The idea here is that someone will look very closely at the all of the
|
||||
// communications between the reference TCP and the TCP under test in this
|
||||
// simulation and determine that all of the responses are correct. We expect
|
||||
// that this means generating a pcap trace file from the point-to-point link
|
||||
// and examining the packets closely using tcpdump, wireshark or some such
|
||||
// program. So we provide the ability to generate a pcap trace of the
|
||||
// test execution for your perusal.
|
||||
//
|
||||
// Once the validation test is determined to be running exactly as expected,
|
||||
// we allow you to generate a file that contains the response vectors that
|
||||
// will be checked during the actual execution of the test.
|
||||
//
|
||||
|
||||
if (m_writeResults)
|
||||
{
|
||||
pointToPoint.EnablePcapAll ("ns3-tcp-interop");
|
||||
}
|
||||
|
||||
Simulator::Stop (Seconds (20));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
class Ns3TcpInteroperabilityTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
Ns3TcpInteroperabilityTestSuite ();
|
||||
};
|
||||
|
||||
Ns3TcpInteroperabilityTestSuite::Ns3TcpInteroperabilityTestSuite ()
|
||||
: TestSuite ("ns3-tcp-interoperability", SYSTEM)
|
||||
{
|
||||
// We can't use NS_TEST_SOURCEDIR variable here because we use subdirectories
|
||||
SetDataDir ("src/test/ns3tcp/response-vectors");
|
||||
|
||||
AddTestCase (new Ns3TcpInteroperabilityTestCase, TestCase::QUICK);
|
||||
}
|
||||
|
||||
static Ns3TcpInteroperabilityTestSuite ns3TcpInteroperabilityTestSuite;
|
||||
@@ -1,282 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/pcap-file.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/point-to-point-helper.h"
|
||||
#include "ns3/internet-stack-helper.h"
|
||||
#include "ns3/ipv4-global-routing-helper.h"
|
||||
#include "ns3/ipv4-address-helper.h"
|
||||
#include "ns3/packet-sink-helper.h"
|
||||
#include "ns3/tcp-socket-factory.h"
|
||||
#include "ns3/node-container.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "../ns3tcp/ns3tcp-socket-writer.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("NscTcpLossTest");
|
||||
|
||||
// ===========================================================================
|
||||
// Tests of TCP implementation loss behavior
|
||||
// ===========================================================================
|
||||
//
|
||||
|
||||
class NscTcpLossTestCase1 : public TestCase
|
||||
{
|
||||
public:
|
||||
NscTcpLossTestCase1 ();
|
||||
virtual ~NscTcpLossTestCase1 () {}
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
bool m_writeResults;
|
||||
|
||||
void SinkRx (std::string path, Ptr<const Packet> p, const Address &address);
|
||||
|
||||
TestVectors<uint32_t> m_inputs;
|
||||
TestVectors<uint32_t> m_responses;
|
||||
};
|
||||
|
||||
NscTcpLossTestCase1::NscTcpLossTestCase1 ()
|
||||
: TestCase ("Check that nsc TCP survives loss of first two SYNs"),
|
||||
m_writeResults (false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpLossTestCase1::SinkRx (std::string path, Ptr<const Packet> p, const Address &address)
|
||||
{
|
||||
m_responses.Add (p->GetSize ());
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpLossTestCase1::DoRun (void)
|
||||
{
|
||||
uint16_t sinkPort = 50000;
|
||||
double sinkStopTime = 40; // sec; will trigger Socket::Close
|
||||
double writerStopTime = 30; // sec; will trigger Socket::Close
|
||||
double simStopTime = 60; // sec
|
||||
Time sinkStopTimeObj = Seconds (sinkStopTime);
|
||||
Time writerStopTimeObj = Seconds (writerStopTime);
|
||||
Time simStopTimeObj= Seconds (simStopTime);
|
||||
// This test was written with initial window of 1 segment
|
||||
Config::SetDefault ("ns3::TcpSocket::InitialCwnd", UintegerValue (1));
|
||||
|
||||
Ptr<Node> n0 = CreateObject<Node> ();
|
||||
Ptr<Node> n1 = CreateObject<Node> ();
|
||||
|
||||
PointToPointHelper pointToPoint;
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("200ms"));
|
||||
|
||||
NetDeviceContainer devices;
|
||||
devices = pointToPoint.Install (n0, n1);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
|
||||
internet.InstallAll ();
|
||||
|
||||
Ipv4AddressHelper address;
|
||||
address.SetBase ("10.1.1.0", "255.255.255.252");
|
||||
Ipv4InterfaceContainer ifContainer = address.Assign (devices);
|
||||
|
||||
Ptr<SocketWriter> socketWriter = CreateObject<SocketWriter> ();
|
||||
Address sinkAddress (InetSocketAddress (ifContainer.GetAddress (1), sinkPort));
|
||||
socketWriter->Setup (n0, sinkAddress);
|
||||
n0->AddApplication (socketWriter);
|
||||
socketWriter->SetStartTime (Seconds (0.));
|
||||
socketWriter->SetStopTime (writerStopTimeObj);
|
||||
|
||||
PacketSinkHelper sink ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
|
||||
ApplicationContainer apps = sink.Install (n1);
|
||||
// Start the sink application at time zero, and stop it at sinkStopTime
|
||||
apps.Start (Seconds (0.0));
|
||||
apps.Stop (sinkStopTimeObj);
|
||||
|
||||
Config::Connect ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx",
|
||||
MakeCallback (&NscTcpLossTestCase1::SinkRx, this));
|
||||
|
||||
Simulator::Schedule (Seconds (2), &SocketWriter::Connect, socketWriter);
|
||||
Simulator::Schedule (Seconds (10), &SocketWriter::Write, socketWriter, 500);
|
||||
m_inputs.Add (500);
|
||||
Simulator::Schedule (writerStopTimeObj, &SocketWriter::Close, socketWriter);
|
||||
|
||||
std::list<uint32_t> sampleList;
|
||||
// Lose first two SYNs
|
||||
sampleList.push_back (0);
|
||||
sampleList.push_back (1);
|
||||
// This time, we'll explicitly create the error model we want
|
||||
Ptr<ReceiveListErrorModel> pem = CreateObject<ReceiveListErrorModel> ();
|
||||
pem->SetList (sampleList);
|
||||
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (pem));
|
||||
|
||||
if (m_writeResults)
|
||||
{
|
||||
pointToPoint.EnablePcapAll ("nsc-tcp-loss-test-case-1");
|
||||
pointToPoint.EnableAsciiAll ("nsc-tcp-loss-test-case-1");
|
||||
}
|
||||
|
||||
Simulator::Stop (simStopTimeObj);
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
// Compare inputs and outputs
|
||||
NS_TEST_ASSERT_MSG_EQ (m_inputs.GetN (), m_responses.GetN (), "Incorrect number of expected receive events");
|
||||
for (uint32_t i = 0; i < m_responses.GetN (); i++)
|
||||
{
|
||||
uint32_t in = m_inputs.Get (i);
|
||||
uint32_t out = m_responses.Get (i);
|
||||
NS_TEST_ASSERT_MSG_EQ (in, out, "Mismatch: expected " << in << " bytes, got " << out << " bytes");
|
||||
}
|
||||
}
|
||||
|
||||
class NscTcpLossTestCase2 : public TestCase
|
||||
{
|
||||
public:
|
||||
NscTcpLossTestCase2 ();
|
||||
virtual ~NscTcpLossTestCase2 () {}
|
||||
|
||||
private:
|
||||
virtual void DoRun (void);
|
||||
bool m_writeResults;
|
||||
|
||||
void SinkRx (std::string path, Ptr<const Packet> p, const Address &address);
|
||||
|
||||
TestVectors<uint32_t> m_inputs;
|
||||
TestVectors<uint32_t> m_responses;
|
||||
};
|
||||
|
||||
NscTcpLossTestCase2::NscTcpLossTestCase2 ()
|
||||
: TestCase ("Check that nsc TCP survives loss of first data packet"),
|
||||
m_writeResults (false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpLossTestCase2::SinkRx (std::string path, Ptr<const Packet> p, const Address &address)
|
||||
{
|
||||
m_responses.Add (p->GetSize ());
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpLossTestCase2::DoRun (void)
|
||||
{
|
||||
uint16_t sinkPort = 50000;
|
||||
double sinkStopTime = 40; // sec; will trigger Socket::Close
|
||||
double writerStopTime = 12; // sec; will trigger Socket::Close
|
||||
double simStopTime = 60; // sec
|
||||
Time sinkStopTimeObj = Seconds (sinkStopTime);
|
||||
Time writerStopTimeObj = Seconds (writerStopTime);
|
||||
Time simStopTimeObj= Seconds (simStopTime);
|
||||
// This test was written with initial window of 1 segment
|
||||
Config::SetDefault ("ns3::TcpSocket::InitialCwnd", UintegerValue (1));
|
||||
|
||||
Ptr<Node> n0 = CreateObject<Node> ();
|
||||
Ptr<Node> n1 = CreateObject<Node> ();
|
||||
|
||||
PointToPointHelper pointToPoint;
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("200ms"));
|
||||
|
||||
NetDeviceContainer devices;
|
||||
devices = pointToPoint.Install (n0, n1);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
|
||||
internet.InstallAll ();
|
||||
|
||||
Ipv4AddressHelper address;
|
||||
address.SetBase ("10.1.1.0", "255.255.255.252");
|
||||
Ipv4InterfaceContainer ifContainer = address.Assign (devices);
|
||||
|
||||
Ptr<SocketWriter> socketWriter = CreateObject<SocketWriter> ();
|
||||
Address sinkAddress (InetSocketAddress (ifContainer.GetAddress (1), sinkPort));
|
||||
socketWriter->Setup (n0, sinkAddress);
|
||||
n0->AddApplication (socketWriter);
|
||||
socketWriter->SetStartTime (Seconds (0.));
|
||||
socketWriter->SetStopTime (writerStopTimeObj);
|
||||
|
||||
PacketSinkHelper sink ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
|
||||
ApplicationContainer apps = sink.Install (n1);
|
||||
// Start the sink application at time zero, and stop it at sinkStopTime
|
||||
apps.Start (Seconds (0.0));
|
||||
apps.Stop (sinkStopTimeObj);
|
||||
|
||||
Config::Connect ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx",
|
||||
MakeCallback (&NscTcpLossTestCase2::SinkRx, this));
|
||||
|
||||
Simulator::Schedule (Seconds (2), &SocketWriter::Connect, socketWriter);
|
||||
Simulator::Schedule (Seconds (10), &SocketWriter::Write, socketWriter, 500);
|
||||
m_inputs.Add (500);
|
||||
Simulator::Schedule (writerStopTimeObj, &SocketWriter::Close, socketWriter);
|
||||
|
||||
std::list<uint32_t> sampleList;
|
||||
// Lose first data segment
|
||||
sampleList.push_back (2);
|
||||
// This time, we'll explicitly create the error model we want
|
||||
Ptr<ReceiveListErrorModel> pem = CreateObject<ReceiveListErrorModel> ();
|
||||
pem->SetList (sampleList);
|
||||
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (pem));
|
||||
|
||||
if (m_writeResults)
|
||||
{
|
||||
pointToPoint.EnablePcapAll ("nsc-tcp-loss-test-case-2");
|
||||
pointToPoint.EnableAsciiAll ("nsc-tcp-loss-test-case-2");
|
||||
}
|
||||
|
||||
Simulator::Stop (simStopTimeObj);
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
// Compare inputs and outputs
|
||||
NS_TEST_ASSERT_MSG_EQ (m_inputs.GetN (), m_responses.GetN (), "Incorrect number of expected receive events");
|
||||
for (uint32_t i = 0; i < m_responses.GetN (); i++)
|
||||
{
|
||||
uint32_t in = m_inputs.Get (i);
|
||||
uint32_t out = m_responses.Get (i);
|
||||
NS_TEST_ASSERT_MSG_EQ (in, out, "Mismatch: expected " << in << " bytes, got " << out << " bytes");
|
||||
}
|
||||
}
|
||||
|
||||
class NscTcpLossTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
NscTcpLossTestSuite ();
|
||||
};
|
||||
|
||||
NscTcpLossTestSuite::NscTcpLossTestSuite ()
|
||||
: TestSuite ("nsc-tcp-loss", SYSTEM)
|
||||
{
|
||||
AddTestCase (new NscTcpLossTestCase1, TestCase::QUICK);
|
||||
AddTestCase (new NscTcpLossTestCase2, TestCase::QUICK);
|
||||
}
|
||||
|
||||
static NscTcpLossTestSuite nscTcpLossTestSuite;
|
||||
Binary file not shown.
@@ -34,13 +34,10 @@ def build(bld):
|
||||
'ns3tc/fq-cobalt-queue-disc-test-suite.cc',
|
||||
'ns3tc/fq-pie-queue-disc-test-suite.cc',
|
||||
'ns3tc/pfifo-fast-queue-disc-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-cwnd-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-interop-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-loss-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-no-delay-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-socket-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-state-test-suite.cc',
|
||||
'ns3tcp/nsctcp-loss-test-suite.cc',
|
||||
'ns3tcp/ns3tcp-socket-writer.cc',
|
||||
'ns3wifi/wifi-msdu-aggregator-test-suite.cc',
|
||||
'ns3wifi/wifi-ac-mapping-test-suite.cc',
|
||||
|
||||
37
test.py
37
test.py
@@ -60,7 +60,6 @@ interesting_config_items = [
|
||||
"NS3_ENABLED_MODULES",
|
||||
"NS3_ENABLED_CONTRIBUTED_MODULES",
|
||||
"NS3_MODULE_PATH",
|
||||
"NSC_ENABLED",
|
||||
"ENABLE_REAL_TIME",
|
||||
"ENABLE_THREADING",
|
||||
"ENABLE_EXAMPLES",
|
||||
@@ -77,7 +76,6 @@ interesting_config_items = [
|
||||
"VALGRIND_FOUND",
|
||||
]
|
||||
|
||||
NSC_ENABLED = False
|
||||
ENABLE_REAL_TIME = False
|
||||
ENABLE_THREADING = False
|
||||
ENABLE_EXAMPLES = True
|
||||
@@ -106,13 +104,9 @@ test_runner_name = "test-runner"
|
||||
core_kinds = ["core", "performance", "system", "unit"]
|
||||
|
||||
#
|
||||
# There are some special cases for test suites that kill valgrind. This is
|
||||
# because NSC causes illegal instruction crashes when run under valgrind.
|
||||
# Exclude tests that are problematic for valgrind.
|
||||
#
|
||||
core_valgrind_skip_tests = [
|
||||
"ns3-tcp-cwnd",
|
||||
"nsc-tcp-loss",
|
||||
"ns3-tcp-interoperability",
|
||||
"routing-click",
|
||||
"lte-rr-ff-mac-scheduler",
|
||||
"lte-tdmt-ff-mac-scheduler",
|
||||
@@ -126,16 +120,6 @@ core_valgrind_skip_tests = [
|
||||
"lte-pss-ff-mac-scheduler",
|
||||
]
|
||||
|
||||
#
|
||||
# There are some special cases for test suites that fail when NSC is
|
||||
# missing.
|
||||
#
|
||||
core_nsc_missing_skip_tests = [
|
||||
"ns3-tcp-cwnd",
|
||||
"nsc-tcp-loss",
|
||||
"ns3-tcp-interoperability",
|
||||
]
|
||||
|
||||
#
|
||||
# Parse the examples-to-run file if it exists.
|
||||
#
|
||||
@@ -165,6 +149,7 @@ def parse_examples_to_run_file(
|
||||
#
|
||||
# Note that the two conditions are Python statements that
|
||||
# can depend on waf configuration variables. For example,
|
||||
# when NSC was in the codebase, we could write:
|
||||
#
|
||||
# ("tcp-nsc-lfn", "NSC_ENABLED == True", "NSC_ENABLED == False"),
|
||||
#
|
||||
@@ -600,8 +585,8 @@ def sigint_hook(signal, frame):
|
||||
#
|
||||
# Examples, however, are a different story. In that case, we are just given
|
||||
# a list of examples that could be run. Instead of just failing, for example,
|
||||
# nsc-tcp-zoo if NSC is not present, we look into the waf saved configuration
|
||||
# for relevant configuration items.
|
||||
# an example if its library support is not present, we look into the waf
|
||||
# saved configuration for relevant configuration items.
|
||||
#
|
||||
# XXX This function pokes around in the waf internal state file. To be a
|
||||
# little less hacky, we should add a command to waf to return this info
|
||||
@@ -1476,11 +1461,6 @@ def run_tests():
|
||||
job.set_is_skip(True)
|
||||
job.set_skip_reason("crashes valgrind")
|
||||
|
||||
# Skip tests that will fail if NSC is missing.
|
||||
if not NSC_ENABLED and test in core_nsc_missing_skip_tests:
|
||||
job.set_is_skip(True)
|
||||
job.set_skip_reason("requires NSC")
|
||||
|
||||
if options.verbose:
|
||||
print("Queue %s" % test)
|
||||
|
||||
@@ -1494,14 +1474,7 @@ def run_tests():
|
||||
# the example programs it makes sense to try and run. Each example will
|
||||
# have a condition associated with it that must evaluate to true for us
|
||||
# to try and execute it. This is used to determine if the example has
|
||||
# a dependency that is not satisfied. For example, if an example depends
|
||||
# on NSC being configured by waf, that example should have a condition
|
||||
# that evaluates to true if NSC is enabled. For example,
|
||||
#
|
||||
# ("tcp-nsc-zoo", "NSC_ENABLED == True"),
|
||||
#
|
||||
# In this case, the example "tcp-nsc-zoo" will only be run if we find the
|
||||
# waf configuration variable "NSC_ENABLED" to be True.
|
||||
# a dependency that is not satisfied.
|
||||
#
|
||||
# We don't care at all how the trace files come out, so we just write them
|
||||
# to a single temporary directory.
|
||||
|
||||
Reference in New Issue
Block a user