merge
This commit is contained in:
2
.hgtags
2
.hgtags
@@ -20,3 +20,5 @@ dfd634417b8d1896d981b6f44d8f71030611596a ns-3.2-RC1
|
||||
319eb29611b18998abbad01548825643a8017bcb ns-3.2-RC2
|
||||
d783a951f8f5e64b33bc518f0415f76cae1ca6f3 ns-3.2-RC2-bis
|
||||
fa1c7b813873cfa251be7d1b7cea38373fe82fa1 ns-3.2-RC3
|
||||
68218c266a844f9fbda34a0ffddb1ae2adebd4b0 ns-3.2-RC4
|
||||
2ecac911b3ec40d73ab8301471bea6d9ba5b9885 ns-3.2
|
||||
|
||||
@@ -43,8 +43,8 @@ New user-visible features
|
||||
It is now possible to run simulations synchronized on the real-world
|
||||
wall-clock time (contributed by Craig Dowell).
|
||||
|
||||
d) Network Simulation Craddle
|
||||
It is now possible to use the Network Simulation Craddle
|
||||
d) Network Simulation Cradle
|
||||
It is now possible to use the Network Simulation Cradle
|
||||
(http://www.wand.net.nz/~stj2/nsc/) in ns-3 and run simulations
|
||||
using various versions of kernel TCP network stacks. (contributed
|
||||
by Florian Westphal as part of his Google Summer of Code work)
|
||||
|
||||
@@ -33,6 +33,9 @@ public:
|
||||
}
|
||||
virtual void Notify ()
|
||||
{
|
||||
PyGILState_STATE __py_gil_state;
|
||||
__py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0);
|
||||
|
||||
PyObject *retval = PyObject_CallObject(m_callback, m_args);
|
||||
if (retval) {
|
||||
if (retval != Py_None) {
|
||||
@@ -43,6 +46,9 @@ public:
|
||||
} else {
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
if (PyEval_ThreadsInitialized())
|
||||
PyGILState_Release(__py_gil_state);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
@chapter Attributes
|
||||
@anchor{chap:Attributes}
|
||||
|
||||
@menu
|
||||
* Object Overview::
|
||||
* Attribute Overview::
|
||||
* Extending attributes::
|
||||
* Adding new class type::
|
||||
* ConfigStore::
|
||||
@end menu
|
||||
|
||||
|
||||
In ns-3 simulations, there are two main aspects to configuration:
|
||||
@itemize @bullet
|
||||
@item the simulation topology and how objects are connected
|
||||
@@ -48,8 +57,7 @@ Let's review a couple of properties of these objects.
|
||||
@node Smart pointers
|
||||
@subsection Smart pointers
|
||||
|
||||
As introduced above in @ref{Smart Pointers 101}, ns-3 objects
|
||||
are memory managed by a
|
||||
As introduced in the ns-3 tutorial, ns-3 objects are memory managed by a
|
||||
@uref{http://en.wikipedia.org/wiki/Smart_pointer,,reference counting smart pointer implementation}, @code{class ns3::Ptr}.
|
||||
|
||||
Smart pointers are used extensively in the ns-3 APIs, to avoid passing
|
||||
@@ -496,6 +504,7 @@ None of these mistakes can be detected by the ns-3 codebase so, users
|
||||
are advised to check carefully multiple times that they got these right.
|
||||
|
||||
|
||||
@node Adding new class type
|
||||
@section Adding new class type to the attribute system
|
||||
|
||||
From the perspective of the user who writes a new class in the system and
|
||||
@@ -557,3 +566,158 @@ Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the
|
||||
modeler must specify these operators and the string syntactical representation
|
||||
of an instance of the new class.
|
||||
|
||||
@node ConfigStore
|
||||
@section ConfigStore
|
||||
|
||||
@strong{Feedback requested:} This is an experimental feature of ns-3.
|
||||
It is not in the main tree. If you like this feature and would like
|
||||
to provide feedback on it, please email us.
|
||||
|
||||
Values for ns-3 attributes can be stored in an ascii text file and
|
||||
loaded into a future simulation. This feature is known as the
|
||||
ns-3 ConfigStore.
|
||||
The ConfigStore code is in @code{src/contrib/}. It is not yet main-tree
|
||||
code, because we are seeking some user feedback.
|
||||
|
||||
We can explore this system by using an example. Copy the @code{csma-bridge.cc}
|
||||
file to the scratch directory:
|
||||
@verbatim
|
||||
cp examples/csma-bridge.cc scratch/
|
||||
./waf
|
||||
@end verbatim
|
||||
|
||||
Let's edit it to add the ConfigStore feature. First, add an include statement,
|
||||
and then add these lines:
|
||||
|
||||
@verbatim
|
||||
#include "contrib-module.h"
|
||||
...
|
||||
int main (...)
|
||||
{
|
||||
// setup topology
|
||||
|
||||
// Invoke just before entering Simulator::Run ()
|
||||
ConfigStore config;
|
||||
config.Configure ();
|
||||
|
||||
Simulator::Run ();
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
There is an attribute that governs whether the Configure() call either
|
||||
stores a simulation configuration in a file and exits, or whether
|
||||
it loads a simulation configuration file annd proceeds. First,
|
||||
the @code{LoadFilename} attribute is checked, and if non-empty,
|
||||
the program loads the configuration from the filename provided.
|
||||
If LoadFilename is empty, and if the @code{StoreFilename} attribute is
|
||||
populated, the configuration will be written to the output filename
|
||||
specified.
|
||||
|
||||
While it is possible to generate a sample config file and lightly
|
||||
edit it to change a couple of values, there are cases where this
|
||||
process will not work because the same value on the same object
|
||||
can appear multiple times in the same automatically-generated
|
||||
configuration file under different configuration paths.
|
||||
|
||||
As such, the best way to use this class is to use it to generate
|
||||
an initial configuration file, extract from that configuration
|
||||
file only the strictly necessary elements, and move these minimal
|
||||
elements to a new configuration file which can then safely
|
||||
be edited and loaded in a subsequent simulation run.
|
||||
|
||||
So, let's do that as an example. We'lll run the program once
|
||||
to create a configure file, and look at it.
|
||||
If you are running bash shell, the below command should work (which illustrates
|
||||
how to set an attribute from the command line):
|
||||
@verbatim
|
||||
./build/debug/scratch/csma-bridge --ns3::ConfigStore::StoreFilename=test.config
|
||||
@end verbatim
|
||||
or, if the above does not work (the above requires rpath support), try this:
|
||||
@verbatim
|
||||
./waf --command-template="%s --ns3::ConfigStore::StoreFilename=test.config" --run scratch/csma-bridge
|
||||
@end verbatim
|
||||
|
||||
Running the program should yield a "test.config" output configuration file
|
||||
that looks like this:
|
||||
@verbatim
|
||||
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Addre
|
||||
ss 00:00:00:00:00:01
|
||||
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Frame
|
||||
Size 1518
|
||||
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/SendE
|
||||
nable true
|
||||
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Recei
|
||||
veEnable true
|
||||
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/TxQue
|
||||
ue/$ns3::DropTailQueue/MaxPackets 100
|
||||
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Mtu 1
|
||||
500
|
||||
...
|
||||
@end verbatim
|
||||
|
||||
The above lists, for each object in the script topology, the value of each
|
||||
registered attribute. The syntax of this file is that the unique name
|
||||
of the attribute (in the attribute namespace) is specified on each line,
|
||||
followed by a value.
|
||||
|
||||
This file is intended to be a convenient record of the parameters that were
|
||||
used in a given simulation run, and can be stored with simulation
|
||||
output files. Additionally,
|
||||
this file can also be used to parameterize a simulation, instead of
|
||||
editing the script or passing in command line arguments. For instance,
|
||||
a person wanting to run the simulation can examine and tweak the values
|
||||
in a pre-existing configuration file, and pass the file to the
|
||||
program. In this case, the relevant commands are:
|
||||
@verbatim
|
||||
./build/debug/scratch/csma-bridge --ns3::ConfigStore::LoadFilename=test.config
|
||||
@end verbatim
|
||||
or, if the above does not work (the above requires rpath support), try this:
|
||||
@verbatim
|
||||
./waf --command-template="%s --ns3::ConfigStore::LoadFilename=test.config" --run scratch/csma-bridge
|
||||
@end verbatim
|
||||
|
||||
@subsection GTK-based ConfigStore
|
||||
|
||||
There is a GTK-based front end for the ConfigStore. This allows users
|
||||
to use a GUI to access and change variables. Screenshots of this
|
||||
feature are available in the
|
||||
@uref{http://www.nsnam.org/docs/ns-3-overview.pdf,,ns-3 Overview} presentation.
|
||||
|
||||
To use this feature, one must install libgtk and libgtk-dev; an example
|
||||
Ubuntu installation command is:
|
||||
@verbatim
|
||||
sudo apt-get install libgtk2.0-0 libgtk2.0-dev
|
||||
@end verbatim
|
||||
To check whether it is configured or not, check the output of the
|
||||
./waf configure step:
|
||||
@verbatim
|
||||
---- Summary of optional NS-3 features:
|
||||
Threading Primitives : enabled
|
||||
Real Time Simulator : enabled
|
||||
GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found)
|
||||
@end verbatim
|
||||
|
||||
In the above example, it was not enabled, so it cannot be used until a
|
||||
suitable version is installed and ./waf configure; ./waf is rerun.
|
||||
|
||||
Usage is almost the same as the non-GTK-based version:
|
||||
@verbatim
|
||||
// Invoke just before entering Simulator::Run ()
|
||||
GtkConfigStore config;
|
||||
config.Configure ();
|
||||
@end verbatim
|
||||
|
||||
Now, when you run the script, a GUI should pop up, allowing you to open
|
||||
menus of attributes on different nodes/objects, and then launch the
|
||||
simulation execution when you are done.
|
||||
|
||||
@subsection Future work
|
||||
There are a couple of possible improvements:
|
||||
@itemize bullet
|
||||
@item save a unique version number with date and time at start of file
|
||||
@item save rng initial seed somewhere.
|
||||
@item make each RandomVariable serialize its own initial seed and re-read
|
||||
it later
|
||||
@item add the default values
|
||||
@end itemize
|
||||
|
||||
|
||||
@@ -81,9 +81,11 @@ see @uref{http://www.nsnam.org/docs/manual.pdf}.
|
||||
* Random variables::
|
||||
* Callbacks::
|
||||
* Attributes::
|
||||
* RealTime::
|
||||
* Packets::
|
||||
* Sockets APIs::
|
||||
* Node and Internet Stack::
|
||||
* TCP::
|
||||
* Routing overview::
|
||||
* Troubleshooting
|
||||
@end menu
|
||||
@@ -91,10 +93,12 @@ see @uref{http://www.nsnam.org/docs/manual.pdf}.
|
||||
@include random.texi
|
||||
@include callbacks.texi
|
||||
@include attributes.texi
|
||||
@include realtime.texi
|
||||
@include packets.texi
|
||||
@include sockets.texi
|
||||
@include node.texi
|
||||
@c @include output.texi
|
||||
@include tcp.texi
|
||||
@include routing.texi
|
||||
@c @include other.texi
|
||||
@include troubleshoot.texi
|
||||
|
||||
100
doc/manual/realtime.texi
Normal file
100
doc/manual/realtime.texi
Normal file
@@ -0,0 +1,100 @@
|
||||
@node RealTime
|
||||
@chapter Real-Time Scheduler
|
||||
@anchor{chap:RealTime}
|
||||
|
||||
ns-3 has been designed for integration into testbed and virtual machine
|
||||
environments. To integrate with real network stacks and emit/consume
|
||||
packets, a real-time scheduler is needed to try to lock the simulation
|
||||
clock with the hardware clock. We describe here a component of this:
|
||||
the RealTime scheduler.
|
||||
|
||||
The purpose of the realtime scheduler is to cause the progression of
|
||||
the simulation clock to occur synchronously with respect to some
|
||||
external time base. Without the presence of an external time base
|
||||
(wall clock), simulation time jumps instantly from one simulated time to
|
||||
the next.
|
||||
|
||||
@section Behavior
|
||||
|
||||
When using a non-realtime scheduler (the default in ns-3), the simulator
|
||||
advances the simulation time to the next scheduled event. During event
|
||||
execution, simulation time is frozen. With the realtime scheduler, the
|
||||
behavior is similar from the perspective of simulation models (i.e.,
|
||||
simulation time is frozen during event execution), but between events,
|
||||
the simulator will attempt to keep the simulation clock aligned with
|
||||
the machine clock.
|
||||
|
||||
When an event is finished executing, and the scheduler moves to the next
|
||||
event, the scheduler compares the next event execution time with the
|
||||
machine clock. If the next event is scheduled for a future time,
|
||||
the simulator sleeps until that realtime is reached and then executes
|
||||
the next event.
|
||||
|
||||
It may happen that, due to the processing inherent in the execution
|
||||
of simulation events, that the simulator cannot keep up with realtime.
|
||||
In such a case, it is up to the user configuration what to do. There
|
||||
are two ns-3 attributes that govern the behavior. The first is
|
||||
@code{ns3::RealTimeSimulatorImpl::SynchronizationMode}. The two
|
||||
entries possible for this attribute are @code{BestEffort} (the default)
|
||||
or @code{HardLimit}. In "BestEffort" mode, the simulator will just
|
||||
try to catch up to realtime by executing events until it reaches
|
||||
a point where the next event is in the (realtime) future, or else
|
||||
the simulation ends. In BestEffort mode, then, it is possible for
|
||||
the simulation to consume more time than the wall clock time. The
|
||||
other option "HardLimit" will cause the simulation to abort if the tolerance
|
||||
threshold is exceeded. This attribute is
|
||||
@code{ns3::RealTimeSimulatorImpl::HardLimit} and the default is 0.1 seconds.
|
||||
|
||||
A different mode of operation is one in which simulated time is @strong{not}
|
||||
frozen during an event execution. This mode of realtime simulation was
|
||||
implemented but removed from the ns-3 tree because of questions of whether
|
||||
it would be useful. If users are interested in a realtime simulator
|
||||
for which simulation time does not freeze during event execution (i.e.,
|
||||
every call to @code{Simulator::Now()} returns the current wall clock time,
|
||||
not the time at which the event started executing), please contact the
|
||||
ns-developers mailing list.
|
||||
|
||||
@section Usage
|
||||
|
||||
The usage of the realtime simulator is straightforward, from a scripting
|
||||
perspective. Users just need to set the attribute
|
||||
@code{SimulatorImplementationType} to the Realtime simulator, such as follows:
|
||||
@verbatim
|
||||
GlobalValue::Bind ("SimulatorImplementationType",
|
||||
StringValue ("ns3::RealtimeSimulatorImpl"));
|
||||
@end verbatim
|
||||
|
||||
There is a script in @code{examples/realtime-udp-echo.cc} that has an
|
||||
example of how to configure the realtime behavior. Try:
|
||||
@verbatim
|
||||
./waf --run realtime-udp-echo
|
||||
@end verbatim
|
||||
|
||||
Whether the simulator will work in a best effort or hard limit policy
|
||||
fashion is governed by the attributes explained in the previous section.
|
||||
|
||||
@section Implementation
|
||||
|
||||
The implementation is contained in the following files:
|
||||
@itemize @bullet
|
||||
@item @code{src/simulator/realtime-simulator-impl.{cc,h}}
|
||||
@item @code{src/simulator/wall-clock-synchronizer.{cc,h}}
|
||||
@end itemize
|
||||
|
||||
In order to create a realtime scheduler, to a first approximation you
|
||||
just want to cause simulation time jumps to consume real time. We propose
|
||||
doing this using a combination of sleep- and busy- waits. Sleep-waits cause
|
||||
the calling process (thread) to yield the processor for some amount of time.
|
||||
Even though this specified amount of time can be passed to nanosecond
|
||||
resolution, it is actually converted to an OS-specific granularity.
|
||||
In Linux, the granularity is called a Jiffy. Typically this resolution is
|
||||
insufficient for our needs (on the order of a ten milliseconds), so we
|
||||
round down and sleep for some smaller number of Jiffies. The process is
|
||||
then awakened after the specified number of Jiffies has passed. At this
|
||||
time, we have some residual time to wait. This time is generally smaller
|
||||
than the minimum sleep time, so we busy-wait for the remainder of the time.
|
||||
This means that the thread just sits in a for loop consuming cycles until
|
||||
the desired time arrives. After the combination of sleep- and busy-waits,
|
||||
the elapsed realtime (wall) clock should agree with the simulation time
|
||||
of the next event and the simulation proceeds.
|
||||
|
||||
342
doc/manual/tcp.texi
Normal file
342
doc/manual/tcp.texi
Normal file
@@ -0,0 +1,342 @@
|
||||
@node TCP
|
||||
@chapter TCP models in ns-3
|
||||
@anchor{chap:TCP}
|
||||
|
||||
This chapter describes the TCP models available in ns-3.
|
||||
|
||||
@section Generic support for TCP
|
||||
|
||||
ns-3 was written to support multiple TCP implementations. The
|
||||
implementations inherit from a few common header classes in the
|
||||
@code{src/node} directory, so that user code can swap out implementations
|
||||
with minimal changes to the scripts.
|
||||
|
||||
There are two important abstract base classes:
|
||||
@itemize @bullet
|
||||
@item @code{class TcpSocket}: This is defined in @code{src/node/tcp-socket.{cc,h}}. This class exists for hosting TcpSocket attributes that can be
|
||||
reused across different implementations. For instance,
|
||||
@code{TcpSocket::SetInitialCwnd()} can be used for any of the implementations
|
||||
that derive from @code{class TcpSocket}.
|
||||
@item @code{class TcpSocketFactory}: This is used by applications to
|
||||
create TCP sockets. A typical usage can be seen in this snippet:
|
||||
@verbatim
|
||||
// Create the socket if not already created
|
||||
if (!m_socket)
|
||||
{
|
||||
m_socket = Socket::CreateSocket (GetNode(), m_tid);
|
||||
m_socket->Bind (m_local);
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
The parameter @code{m_tid} controls the TypeId of the actual Tcp Socket
|
||||
implementation that is instantiated. This way, the application can be
|
||||
written generically and different socket implementations can be swapped out
|
||||
by specifying the TypeId.
|
||||
@end itemize
|
||||
|
||||
@section ns-3 TCP
|
||||
|
||||
ns-3 contains a port of the TCP model from
|
||||
@uref{http://www.ece.gatech.edu/research/labs/MANIACS/GTNetS/index.html,,GTNetS}. This model is a full TCP, in that it is
|
||||
bidirectional and attempts to model the connection setup and
|
||||
close logic. In fact, it is a more complete implementation of the TCP
|
||||
state machine than ns-2's "FullTcp" model. This TCP model was originally
|
||||
written by George Riley
|
||||
as part of GTNetS and ported to ns-3 by Raj Bhattacharjea.
|
||||
|
||||
The implementation of TCP is contained in the following files:
|
||||
@verbatim
|
||||
src/internet-stack/tcp-header.{cc,h}
|
||||
src/internet-stack/tcp-l4-protocol.{cc,h}
|
||||
src/internet-stack/tcp-socket-factory-impl.{cc,h}
|
||||
src/internet-stack/tcp-socket-impl.{cc,h}
|
||||
src/internet-stack/tcp-typedefs.h
|
||||
src/internet-stack/rtt-estimator.{cc,h}
|
||||
src/internet-stack/sequence-number.{cc,h}
|
||||
@end verbatim
|
||||
|
||||
@subsection Usage
|
||||
|
||||
The file @code{examples/tcp-star-server.cc} contains an example that
|
||||
makes use of @code{ns3::OnOffApplication} and @code{ns3::PacketSink}
|
||||
applications.
|
||||
|
||||
Using the helper functions defined in @code{src/helper}, here is how
|
||||
one would create a TCP receiver:
|
||||
@verbatim
|
||||
// Create a packet sink on the star "hub" to receive these packets
|
||||
uint16_t port = 50000;
|
||||
Address sinkLocalAddress(InetSocketAddress (Ipv4Address::GetAny (), port));
|
||||
PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress);
|
||||
ApplicationContainer sinkApp = sinkHelper.Install (serverNode);
|
||||
sinkApp.Start (Seconds (1.0));
|
||||
sinkApp.Stop (Seconds (10.0));
|
||||
@end verbatim
|
||||
|
||||
Similarly, the below snippet configures OnOffApplication traffic
|
||||
source to use
|
||||
TCP:
|
||||
@verbatim
|
||||
// Create the OnOff applications to send TCP to the server
|
||||
OnOffHelper clientHelper ("ns3::TcpSocketFactory", Address ());
|
||||
@end verbatim
|
||||
|
||||
The careful reader will note above that we have specified the TypeId
|
||||
of an abstract base class @code{TcpSocketFactory}. How does the
|
||||
script tell ns-3 that it wants the native ns-3 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 ns-3 TCP.
|
||||
This can be overridden as we show below when using Network
|
||||
Simulation Cradle. So, by default, when using the ns-3 helper API,
|
||||
the TCP that is aggregated to nodes with an Internet stack is the
|
||||
native ns-3 TCP.
|
||||
|
||||
Once a TCP socket is created, you will want to follow conventional
|
||||
socket logic and either connect() and send() (for a TCP client)
|
||||
or bind(), listen(), and accept() (for a TCP server).
|
||||
@xref{Sockets APIs,,Sockets API} for a review of how sockets are used
|
||||
in ns-3.
|
||||
|
||||
To configure behavior of TCP, a number of parameters are exported through
|
||||
the @ref{Attributes,,ns-3 attribute system}. These are documented in the
|
||||
@uref{http://www.nsnam.org/doxygen/classns3_1_1_tcp_socket.html,,Doxygen}
|
||||
for @code{class TcpSocket}.
|
||||
|
||||
@subsection Current limitations
|
||||
@itemize @bullet
|
||||
@item Only Tahoe congestion control is presently supported.
|
||||
@item Only IPv4 is supported (IPv6 support will start to be added in ns-3.3).
|
||||
@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=198,,Bug 198}: TcpSocketImpl doesn't send acks with data packets in two-way transfers
|
||||
@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=250,,Bug 250}: Tcp breaks if you set the DelAckCount parameter to be greater than 2
|
||||
@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=311,,Bug 311}: Tcp socket close returns -1 but does not set errno.
|
||||
@end itemize
|
||||
|
||||
@section Network Simulation Cradle
|
||||
|
||||
The @uref{http://www.wand.net.nz/~stj2/nsc/,,Network Simulation Cradle (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 ns-2 and OMNeT++, and recently
|
||||
was added to ns-3. This section describes the ns-3 port of NSC and
|
||||
how to use it.
|
||||
|
||||
@subsection Prerequisites
|
||||
|
||||
Presently, NSC has been tested and shown to work on these platforms:
|
||||
Linux i386 and Linux x86-64. NSC does not support powerpc at the moment.
|
||||
|
||||
NSC requires the packages mercurial, flex, and bison.
|
||||
|
||||
@subsection Configuring and Downloading
|
||||
|
||||
NSC is disbled by default and must be explicitly configured in. To try
|
||||
this, type
|
||||
@verbatim
|
||||
./waf configure --enable-nsc
|
||||
@end verbatim
|
||||
the output of the configuration will show something like:
|
||||
@verbatim
|
||||
Checking for NSC supported architecture x86_64 : ok
|
||||
Pulling nsc updates from https://secure.wand.net.nz/mercurial/nsc
|
||||
pulling from https://secure.wand.net.nz/mercurial/nsc
|
||||
searching for changes
|
||||
no changes found
|
||||
---- Summary of optional NS-3 features:
|
||||
...
|
||||
Network Simulation Cradle : enabled
|
||||
...
|
||||
@end verbatim
|
||||
if successful. Note that the configure script pulls a recent copy of
|
||||
NSC from a mercurial repository. This download will not work if you are not
|
||||
online.
|
||||
|
||||
If everything went OK, you will see a directory called "nsc" in the top-level
|
||||
directory, with contents like this:
|
||||
@verbatim
|
||||
audit.sh linux-2.6/ openbsd3/ scons-time.py*
|
||||
ChangeLog linux-2.6.18/ README SConstruct
|
||||
config.log linux-2.6.26/ sconsign.py* sim/
|
||||
freebsd5/ lwip-1.3.0/ scons-LICENSE test/
|
||||
globaliser/ lwip-HEAD/ scons-local-1.0.1/
|
||||
INSTALL ns/ scons.py*
|
||||
LICENSE omnetpp/ scons-README
|
||||
@end verbatim
|
||||
|
||||
@subsection Building and validating
|
||||
|
||||
Building ns-3 with nsc support is the same as building it without; no
|
||||
additional arguments are needed for waf. Building nsc may take some time
|
||||
compared to ns-3; it is interleaved in the ns-3 building process.
|
||||
|
||||
Try running the regression tests: @code{./waf --regression}. If NSC has
|
||||
been successfully built, the following test should show up in the results:
|
||||
@verbatim
|
||||
PASS test-tcp-nsc-lfn
|
||||
@end verbatim
|
||||
|
||||
This confirms that NSC is ready to use.
|
||||
|
||||
@subsection Usage
|
||||
There are a few example files. Try
|
||||
@verbatim
|
||||
./waf --run tcp-nsc-zoo
|
||||
./waf --run tcp-nsc-lfn
|
||||
@end verbatim
|
||||
These examples will deposit some @code{.pcap} files in your directory,
|
||||
which can be examined by tcpdump or wireshark.
|
||||
|
||||
Let's look at the @code{examples/tcp-nsc-zoo.cc} file for some typical
|
||||
usage. How does it differ from using native ns-3 TCP? There is one
|
||||
main configuration line, when using NSC and the ns-3 helper API, that needs
|
||||
to be set:
|
||||
@verbatim
|
||||
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));
|
||||
@end verbatim
|
||||
|
||||
The key line is the @code{SetNscStack}. This tells the InternetStack
|
||||
helper to aggregate instances of NSC TCP instead of native ns-3 TCP
|
||||
to the remaining nodes. It is important that this function be called
|
||||
@strong{before} callling the @code{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 ns-3. To see which stacks
|
||||
were built, one can execute the following find command at the ns-3 top level
|
||||
directory:
|
||||
@verbatim
|
||||
~/ns-3.2> find nsc -name "*.so" -type f
|
||||
nsc/linux-2.6.18/liblinux2.6.18.so
|
||||
nsc/linux-2.6.26/liblinux2.6.26.so
|
||||
@end verbatim
|
||||
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.
|
||||
|
||||
@subsection Stack configuration
|
||||
NSC TCP shares the same configuration attributes that are common
|
||||
across TCP sockets, as described above and documented in
|
||||
@uref{http://www.nsnam.org/doxygen/classns3_1_1_tcp_socket.html,,Doxygen}
|
||||
|
||||
Additionally, NSC TCP exports a lot of configuration variables into the
|
||||
ns-3 @ref{Attributes} system, via a @uref{http://en.wikipedia.org/wiki/Sysctl,,
|
||||
sysctl}-like interface. In the @code{examples/tcp-nsc-zoo} example, you
|
||||
can see the following configuration:
|
||||
@verbatim
|
||||
// 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"));
|
||||
@end verbatim
|
||||
These additional configuration variables are not available to native ns-3
|
||||
TCP.
|
||||
|
||||
@subsection NSC API
|
||||
|
||||
This subsection describes the API that NSC presents to ns-3 or any other
|
||||
simulator. NSC provides its API in the form of a number of classes that
|
||||
are defined in @code{sim/sim_interface.h} in the nsc directory.
|
||||
|
||||
@itemize @bullet
|
||||
@item @strong{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.
|
||||
@item @strong{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() ).
|
||||
@item @strong{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, ...
|
||||
@item @strong{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.
|
||||
@end itemize
|
||||
|
||||
@subsection ns-3 implementation
|
||||
|
||||
The ns-3 implementation makes use of the above NSC API, and is implemented
|
||||
as follows.
|
||||
|
||||
The three main parts are:
|
||||
@itemize @bullet
|
||||
@item @code{ns3::NscTcpL4Protocol}: a subclass of Ipv4L4Protocol (and two nsc classes: ISendCallback and IInterruptCallback)
|
||||
@item @code{ns3::NscTcpSocketImpl}: a subclass of TcpSocket
|
||||
@item @code{ns3::NscTcpSocketFactoryImpl}: a factory to create new NSC
|
||||
sockets
|
||||
@end itemize
|
||||
|
||||
@code{src/internet-stack/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 ns-3.
|
||||
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 @code{ns3::NscTcpSocketImpl} both from the nsc wakeup()
|
||||
callback and from the Receive path (to ensure that possibly queued data
|
||||
is scheduled for sending).
|
||||
|
||||
|
||||
@code{src/internet-stack/nsc-tcp-socket-impl} implements the nsc socket
|
||||
interface. Each instance has its own nscTcpSocket. Data that is Send()
|
||||
will be handed to the nsc stack via m_nscTcpSocket->send_data(). (and not
|
||||
to nsc-tcp-l4, this is the major difference compared to ns-3 TCP). The
|
||||
class also queues up data that is Send() before the underlying
|
||||
descriptor has entered an ESTABLISHED state. This class is called from
|
||||
the nsc-tcp-l4 class, when the nsc-tcp-l4 wakeup() callback is invoked by
|
||||
nsc. nsc-tcp-socket-impl 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 @code{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.
|
||||
|
||||
@subsection Limitations
|
||||
@itemize @bullet
|
||||
@item NSC only works on single-interface nodes; attempting to run it on
|
||||
a multi-interface node will cause a program error. This limitation should
|
||||
be fixed by ns-3.3.
|
||||
@item Cygwin and OS X PPC are not presently supported
|
||||
@item The non-Linux stacks of NSC are not supported
|
||||
@item NSC's integration into the build system presently requires on-line
|
||||
access and mercurial, and is a slow download.
|
||||
@end itemize
|
||||
|
||||
For more information, see
|
||||
@uref{http://www.nsnam.org/wiki/index.php/Network_Simulation_Cradle_Integration,, this wiki page}.
|
||||
@@ -213,7 +213,7 @@ on the main @command{ns-3} web site.
|
||||
Once you have source code downloaded to your local system, you will need
|
||||
to compile that source to produce usable programs. Just as in the case of
|
||||
source code management, there are many tools available to perform this
|
||||
function. Probably the most will known of these tools is @code{make}. Along
|
||||
function. Probably the most well known of these tools is @code{make}. Along
|
||||
with being the most well known, @code{make} is probably the most difficult to
|
||||
use in a very large and highly configurable system. Because of this, many
|
||||
alternatives have been developed. Recently these systems have been developed
|
||||
|
||||
@@ -127,19 +127,21 @@ main (int argc, char *argv[])
|
||||
// Create an optional packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
sink.Install (terminals.Get (1));
|
||||
app = sink.Install (terminals.Get (1));
|
||||
app.Start (Seconds (0.0));
|
||||
|
||||
//
|
||||
// Create a similar flow from n3 to n0, starting at time 1.1 seconds
|
||||
//
|
||||
onoff.SetAttribute ("Remote",
|
||||
AddressValue (InetSocketAddress (Ipv4Address ("10.1.1.1"), port)));
|
||||
ApplicationContainer app2 = onoff.Install (terminals.Get (3));
|
||||
app = onoff.Install (terminals.Get (3));
|
||||
app.Start (Seconds (1.1));
|
||||
app.Stop (Seconds (10.0));
|
||||
|
||||
sink.Install (terminals.Get (0));
|
||||
app = sink.Install (terminals.Get (0));
|
||||
app.Start (Seconds (0.0));
|
||||
|
||||
app2.Start (Seconds (1.1));
|
||||
app2.Stop (Seconds (10.0));
|
||||
|
||||
//
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
|
||||
@@ -107,19 +107,20 @@ def main(argv):
|
||||
# Create an optional packet sink to receive these packets
|
||||
sink = ns3.PacketSinkHelper("ns3::UdpSocketFactory",
|
||||
ns3.Address(ns3.InetSocketAddress(ns3.Ipv4Address.GetAny(), port)))
|
||||
sink.Install(ns3.NodeContainer(terminals.Get(1)))
|
||||
app = sink.Install(ns3.NodeContainer(terminals.Get(1)))
|
||||
app.Start (ns3.Seconds (0.0))
|
||||
|
||||
#
|
||||
# Create a similar flow from n3 to n0, starting at time 1.1 seconds
|
||||
#
|
||||
onoff.SetAttribute("Remote",
|
||||
ns3.AddressValue(ns3.InetSocketAddress(ns3.Ipv4Address("10.1.1.1"), port)))
|
||||
app2 = onoff.Install(ns3.NodeContainer(terminals.Get(3)))
|
||||
app = onoff.Install(ns3.NodeContainer(terminals.Get(3)))
|
||||
app.Start(ns3.Seconds(1.1))
|
||||
app.Stop(ns3.Seconds(10.0))
|
||||
|
||||
sink.Install(ns3.NodeContainer(terminals.Get(0)))
|
||||
|
||||
app2.Start(ns3.Seconds(1.1))
|
||||
app2.Stop(ns3.Seconds(10.0))
|
||||
app = sink.Install(ns3.NodeContainer(terminals.Get(0)))
|
||||
app.Start (ns3.Seconds (0.0))
|
||||
|
||||
#
|
||||
# Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
|
||||
@@ -61,8 +61,8 @@ main (int argc, char *argv[])
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (4);
|
||||
NodeContainer nodes;
|
||||
nodes.Create (4);
|
||||
|
||||
NS_LOG_INFO ("Build Topology");
|
||||
CsmaHelper csma;
|
||||
@@ -70,24 +70,19 @@ main (int argc, char *argv[])
|
||||
csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
|
||||
//
|
||||
// Now fill out the topology by creating the net devices required to connect
|
||||
// the nodes to the channels and hooking them up. AddIpv4CsmaNetDevice will
|
||||
// create a net device, add a MAC address (in memory of the pink flamingo) and
|
||||
// connect the net device to a nodes and also to a channel. the
|
||||
// AddIpv4CsmaNetDevice method returns a net device index for the net device
|
||||
// created on the node. Interpret nd0 as the net device we created for node
|
||||
// zero.
|
||||
// the nodes to the channels and hooking them up.
|
||||
//
|
||||
NetDeviceContainer nd0 = csma.Install (c);
|
||||
NetDeviceContainer devices = csma.Install (nodes);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
internet.Install (nodes);
|
||||
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
//
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
ipv4.Assign (nd0);
|
||||
Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
|
||||
|
||||
//
|
||||
// Create an OnOff application to send UDP datagrams from node zero to node 1.
|
||||
@@ -96,11 +91,11 @@ main (int argc, char *argv[])
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address ("10.1.1.2"), port)));
|
||||
Address (InetSocketAddress (interfaces.GetAddress (1), port)));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
|
||||
ApplicationContainer app = onoff.Install (c.Get (0));
|
||||
ApplicationContainer app = onoff.Install (nodes.Get (0));
|
||||
// Start the application
|
||||
app.Start (Seconds (1.0));
|
||||
app.Stop (Seconds (10.0));
|
||||
@@ -108,19 +103,21 @@ main (int argc, char *argv[])
|
||||
// Create an optional packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
sink.Install (c.Get (1));
|
||||
app = sink.Install (nodes.Get (1));
|
||||
app.Start (Seconds (0.0));
|
||||
|
||||
//
|
||||
// Create a similar flow from n3 to n0, starting at time 1.1 seconds
|
||||
//
|
||||
onoff.SetAttribute ("Remote",
|
||||
AddressValue (InetSocketAddress (Ipv4Address ("10.1.1.1"), port)));
|
||||
ApplicationContainer app2 = onoff.Install (c.Get (3));
|
||||
AddressValue (InetSocketAddress (interfaces.GetAddress (0), port)));
|
||||
app = onoff.Install (nodes.Get (3));
|
||||
app.Start(Seconds (1.1));
|
||||
app.Stop (Seconds (10.0));
|
||||
|
||||
sink.Install (c.Get (0));
|
||||
app = sink.Install (nodes.Get (0));
|
||||
app.Start (Seconds (0.0));
|
||||
|
||||
app2.Start(Seconds (1.1));
|
||||
app2.Stop (Seconds (10.0));
|
||||
//
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
// Trace output will be sent to the file "csma-one-subnet.tr"
|
||||
|
||||
@@ -134,7 +134,7 @@ main (int argc, char *argv[])
|
||||
// Create an optional packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
apps = sink.Install (c.Get (3));
|
||||
apps = sink.Install (c.Get (2));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
|
||||
33
regression/tests/test-tcp-nsc-lfn.py
Normal file
33
regression/tests/test-tcp-nsc-lfn.py
Normal file
@@ -0,0 +1,33 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Trace-comparison-type regression test for the Network Simulation Cradle."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tracediff
|
||||
import platform
|
||||
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Run a Network Simulation Cradle test involving two TCP streams."""
|
||||
|
||||
if not tracediff.env['ENABLE_NSC']:
|
||||
print >>sys.stderr, "Skipping tcp-nsc-lfn: NSC not available."
|
||||
raise NotImplementedError
|
||||
|
||||
testName = "tcp-nsc-lfn"
|
||||
arguments = ["--ns3::OnOffApplication::DataRate=40000", "--runtime=20"]
|
||||
platform_bits = platform.architecture()[0]
|
||||
|
||||
if platform_bits == "64bit":
|
||||
traceDirName = testName + "_64bit.ref"
|
||||
elif platform_bits == "32bit":
|
||||
traceDirName = testName + "_32bit.ref"
|
||||
else:
|
||||
# Something unexpected. How should we signal an error here? Rasing a
|
||||
# string might not be the best idea?
|
||||
raise "Unknown architecture, not 64 or 32 bit?"
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName,
|
||||
testName, arguments=arguments, refTestName=traceDirName)
|
||||
@@ -39,8 +39,8 @@
|
||||
#include <dlfcn.h>
|
||||
#include <iomanip>
|
||||
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("NscTcpL4Protocol");
|
||||
|
||||
@@ -82,17 +82,15 @@ int external_rand()
|
||||
NscTcpL4Protocol::NscTcpL4Protocol ()
|
||||
: m_endPoints (new Ipv4EndPointDemux ()),
|
||||
m_nscStack (0),
|
||||
m_nscInterfacesSetUp(false),
|
||||
m_softTimer (Timer::CANCEL_ON_DESTROY)
|
||||
{
|
||||
m_dlopenHandle = NULL;
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
NS_LOG_LOGIC("Made a NscTcpL4Protocol "<<this);
|
||||
}
|
||||
|
||||
NscTcpL4Protocol::~NscTcpL4Protocol ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
NS_LOG_FUNCTION (this);
|
||||
dlclose(m_dlopenHandle);
|
||||
}
|
||||
|
||||
@@ -135,6 +133,10 @@ NscTcpL4Protocol::SetNode (Ptr<Node> node)
|
||||
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);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -151,7 +153,7 @@ NscTcpL4Protocol::GetVersion (void) const
|
||||
void
|
||||
NscTcpL4Protocol::DoDispose (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (m_endPoints != 0)
|
||||
{
|
||||
delete m_endPoints;
|
||||
@@ -164,59 +166,7 @@ NscTcpL4Protocol::DoDispose (void)
|
||||
Ptr<Socket>
|
||||
NscTcpL4Protocol::CreateSocket (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
if (!m_nscInterfacesSetUp)
|
||||
{
|
||||
Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
|
||||
|
||||
const uint32_t nInterfaces = ip->GetNInterfaces ();
|
||||
// start from 1, ignore the loopback interface (HACK)
|
||||
|
||||
NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node");
|
||||
|
||||
for (uint32_t i = 1; i < nInterfaces; i++)
|
||||
{
|
||||
Ipv4Address addr = ip->GetAddress(i);
|
||||
Ipv4Mask mask = ip->GetNetworkMask(i);
|
||||
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)
|
||||
{
|
||||
// We need to come up with a default gateway here. Can't guarantee this to be
|
||||
// correct really...
|
||||
|
||||
uint8_t addrBytes[4];
|
||||
addr.Serialize(addrBytes);
|
||||
|
||||
// XXX: this is all a bit of a horrible hack
|
||||
//
|
||||
// Just increment the last octet, this gives a decent chance of this being
|
||||
// 'enough'.
|
||||
//
|
||||
// All we need is another address on the same network as the interface. This
|
||||
// will force the stack to output the packet out of the network interface.
|
||||
addrBytes[3]++;
|
||||
addr.Deserialize(addrBytes);
|
||||
addrOss.str("");
|
||||
addr.Print(addrOss);
|
||||
m_nscStack->add_default_gateway(addrOss.str().c_str());
|
||||
}
|
||||
}
|
||||
m_nscInterfacesSetUp = true;
|
||||
}
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<RttEstimator> rtt = m_rttFactory.Create<RttEstimator> ();
|
||||
Ptr<NscTcpSocketImpl> socket = CreateObject<NscTcpSocketImpl> ();
|
||||
@@ -229,7 +179,7 @@ NscTcpL4Protocol::CreateSocket (void)
|
||||
Ipv4EndPoint *
|
||||
NscTcpL4Protocol::Allocate (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_endPoints->Allocate ();
|
||||
}
|
||||
|
||||
@@ -305,7 +255,6 @@ NscTcpL4Protocol::Receive (Ptr<Packet> packet,
|
||||
|
||||
void NscTcpL4Protocol::SoftInterrupt (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_nscStack->timer_interrupt ();
|
||||
m_nscStack->increment_ticks ();
|
||||
m_softTimer.Schedule ();
|
||||
@@ -314,27 +263,31 @@ void NscTcpL4Protocol::SoftInterrupt (void)
|
||||
void NscTcpL4Protocol::send_callback(const void* data, int datalen)
|
||||
{
|
||||
Ptr<Packet> p;
|
||||
uint32_t ipv4Saddr, ipv4Daddr;
|
||||
|
||||
NS_ASSERT(datalen > (int)sizeof(struct iphdr));
|
||||
NS_ASSERT(datalen > 20);
|
||||
|
||||
const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
|
||||
rawdata += sizeof(struct iphdr);
|
||||
|
||||
const struct iphdr *ipHdr = reinterpret_cast<const struct iphdr *>(data);
|
||||
|
||||
// create packet, without IP header. The TCP header is not touched.
|
||||
// Not using the IP header makes integration easier, but it destroys
|
||||
// eg. ECN.
|
||||
p = Create<Packet> (rawdata, datalen - sizeof(struct iphdr));
|
||||
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);
|
||||
|
||||
Ipv4Address saddr(ntohl(ipHdr->saddr));
|
||||
Ipv4Address daddr(ntohl(ipHdr->daddr));
|
||||
// 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> ();
|
||||
if (ipv4 != 0)
|
||||
{
|
||||
ipv4->Send (p, saddr, daddr, PROT_NUMBER);
|
||||
}
|
||||
NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
|
||||
|
||||
ipv4->Send (p, saddr, daddr, PROT_NUMBER);
|
||||
m_nscStack->if_send_finish(0);
|
||||
}
|
||||
|
||||
@@ -364,5 +317,58 @@ void NscTcpL4Protocol::gettime(unsigned int* sec, unsigned int* usec)
|
||||
}
|
||||
|
||||
|
||||
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++)
|
||||
{
|
||||
Ipv4Address addr = ip->GetAddress(i);
|
||||
Ipv4Mask mask = ip->GetNetworkMask(i);
|
||||
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)
|
||||
{
|
||||
// We need to come up with a default gateway here. Can't guarantee this to be
|
||||
// correct really...
|
||||
|
||||
uint8_t addrBytes[4];
|
||||
addr.Serialize(addrBytes);
|
||||
|
||||
// XXX: this is all a bit of a horrible hack
|
||||
//
|
||||
// Just increment the last octet, this gives a decent chance of this being
|
||||
// 'enough'.
|
||||
//
|
||||
// All we need is another address on the same network as the interface. This
|
||||
// will force the stack to output the packet out of the network interface.
|
||||
addrBytes[3]++;
|
||||
addr.Deserialize(addrBytes);
|
||||
addrOss.str("");
|
||||
addr.Print(addrOss);
|
||||
m_nscStack->add_default_gateway(addrOss.str().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
@@ -109,12 +109,12 @@ private:
|
||||
Ipv4EndPointDemux *m_endPoints;
|
||||
ObjectFactory m_rttFactory;
|
||||
private:
|
||||
void AddInterface (void);
|
||||
void SoftInterrupt (void);
|
||||
static ObjectFactory GetDefaultRttEstimatorFactory (void);
|
||||
friend class NscTcpSocketImpl;
|
||||
INetStack* m_nscStack;
|
||||
void *m_dlopenHandle;
|
||||
bool m_nscInterfacesSetUp;
|
||||
Timer m_softTimer;
|
||||
};
|
||||
|
||||
|
||||
@@ -33,11 +33,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
// for ntohs().
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "sim_interface.h"
|
||||
#include "sim_errno.h"
|
||||
@@ -307,13 +305,11 @@ NscTcpSocketImpl::Connect (const Address & address)
|
||||
m_remoteAddress = transport.GetIpv4 ();
|
||||
m_remotePort = transport.GetPort ();
|
||||
|
||||
struct in_addr remoteAddr;
|
||||
uint32_t addr32;
|
||||
std::ostringstream ss;
|
||||
m_remoteAddress.Print(ss);
|
||||
std::string ipstring = ss.str ();
|
||||
|
||||
m_remoteAddress.Serialize((uint8_t*)&addr32);
|
||||
remoteAddr.s_addr = addr32;
|
||||
|
||||
m_nscTcpSocket->connect(inet_ntoa(remoteAddr), m_remotePort);
|
||||
m_nscTcpSocket->connect(ipstring.c_str (), m_remotePort);
|
||||
m_state = SYN_SENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "udp-socket-impl.h"
|
||||
#include "udp-l4-protocol.h"
|
||||
#include "ipv4-end-point.h"
|
||||
#include <limits>
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("UdpSocketImpl");
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ def nsc_fetch():
|
||||
nsc_update()
|
||||
|
||||
def configure(conf):
|
||||
conf.env['ENABLE_NSC'] = False
|
||||
|
||||
# checks for flex and bison, which is needed to build NSCs globaliser
|
||||
def check_nsc_buildutils():
|
||||
import flex
|
||||
@@ -82,6 +84,7 @@ def configure(conf):
|
||||
e.define = 'HAVE_DL'
|
||||
e.uselib = 'DL'
|
||||
e.run()
|
||||
conf.env['ENABLE_NSC'] = True
|
||||
ok = True
|
||||
conf.check_message('NSC supported architecture', arch, ok)
|
||||
conf.report_optional_feature("nsc", "Network Simulation Cradle", ok,
|
||||
|
||||
10
wscript
10
wscript
@@ -820,7 +820,7 @@ class Regression(object):
|
||||
self.testdir = testdir
|
||||
self.env = Params.g_build.env_of_name('default')
|
||||
|
||||
def run_test(self, verbose, generate, refDirName, testName, arguments=[], pyscript=None):
|
||||
def run_test(self, verbose, generate, refDirName, testName, arguments=[], pyscript=None, refTestName=None):
|
||||
"""
|
||||
@param verbose: enable verbose execution
|
||||
|
||||
@@ -836,11 +836,17 @@ class Regression(object):
|
||||
parameter contains the path to the python script, relative to
|
||||
the project root dir
|
||||
|
||||
@param refTestName: if not None, this is the name of the directory under refDirName
|
||||
that contains the reference traces. Otherwise "refDirname/testName + .ref" is used.
|
||||
|
||||
"""
|
||||
if not isinstance(arguments, list):
|
||||
raise TypeError
|
||||
|
||||
refTestDirName = os.path.join(refDirName, (testName + ".ref"))
|
||||
if refTestName is None:
|
||||
refTestDirName = os.path.join(refDirName, (testName + ".ref"))
|
||||
else:
|
||||
refTestDirName = os.path.join(refDirName, refTestName)
|
||||
|
||||
if not os.path.exists(refDirName):
|
||||
print"No reference trace repository"
|
||||
|
||||
Reference in New Issue
Block a user