internet: Remove Network Simulation Cradle (NSC)

This commit is contained in:
Tom Henderson
2021-12-02 21:30:16 -08:00
parent b26b2b8a17
commit 2c19b5b453
29 changed files with 12 additions and 4588 deletions

View File

@@ -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>

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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})

View File

@@ -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"),

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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'])

View File

@@ -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

View File

@@ -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>`_.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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 */

View File

@@ -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')

View File

@@ -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}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
View File

@@ -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.

View File

@@ -107,7 +107,6 @@ def dist_hook():
import tarfile
shutil.rmtree("doc/html", True)
shutil.rmtree("doc/latex", True)
shutil.rmtree("nsc", True)
# Print the sorted list of module names in columns.
def print_module_names(names):