Compare commits

...

19 Commits

Author SHA1 Message Date
Craig Dowell d59f3b1bb4 branch merge 2009-10-19 18:47:30 -07:00
Craig Dowell 6450db55f2 tutorial nits 2009-10-19 18:47:01 -07:00
Craig Dowell 30dac288f5 Rename SimpleSource to MyApp 2009-10-19 17:35:02 -07:00
Craig Dowell 0b559a7c8c fill out tutorial tracing section with semi-real plot 2009-10-19 16:44:41 -07:00
Tom Henderson c381234e62 additional manual cleanup 2009-10-19 07:54:31 -07:00
Tom Henderson 42ba205efd some cleanup of part 1 of manual 2009-10-18 22:11:29 -07:00
Tom Henderson 6a6de8bbfa add new dia source 2009-10-17 16:02:25 -07:00
Tom Henderson 41c62223ee add figure for manual overview 2009-10-15 15:59:52 -07:00
Tom Henderson ae2b92f330 a few nits in the release notes 2009-10-16 17:17:06 -07:00
Gustavo J. A. M. Carneiro 1a742a3c02 Upgrade pybindgen to fix bug #723 2009-10-17 00:30:07 +01:00
Tom Henderson c237cbe114 Manual organization 2009-10-16 07:13:05 -07:00
Craig Dowell 117fa7f3c2 release steps tweaks 2009-10-15 23:55:06 -07:00
Craig Dowell d0ffc407ac Added tag ns-3.6-RC3 for changeset 79ff6ad1adbb 2009-10-15 22:44:41 -07:00
Andrey Mazo c0d01261d0 remove some redundant clean ups, includes 2009-10-15 14:32:19 +04:00
Andrey Mazo b252f68f9d bug 711: example mesh/mesh fails valgrind.
also fix several possible leaks.
2009-10-15 14:10:02 +04:00
Andrey Mazo af27a1388c add NS_LOG_FUNCTION to several constructors/destructors/DoDisposes 2009-10-15 13:49:42 +04:00
Craig Dowell ac9dc12e94 add flowmon to RELEASE_NOTES 2009-10-15 10:53:31 -07:00
Craig Dowell 4eba1f033e tweak release steps 2009-10-14 11:20:49 -07:00
Craig Dowell 4fb0057dc7 Added tag ns-3.6-RC2 for changeset 899604299046 2009-10-14 10:24:55 -07:00
57 changed files with 2249 additions and 1093 deletions
+2
View File
@@ -37,3 +37,5 @@ dfd0bc16dc991313896f351530a3dc5a25f62e15 ns-3.3-RC4
a600c11ff8d40a40e88c2d692acad6512dde70c8 ns-3.5-rc3
c975274c9707b1f07d94cc51f205c351122131a5 ns-3.5
549243b47311211975b388cd64fcb9111caa2fc2 ns-3.6-RC1
8996042990466b1eda718a848e1c02923c0add74 ns-3.6-RC2
79ff6ad1adbb7b4677759ddf52028b68b0515168 ns-3.6-RC3
+5 -6
View File
@@ -17,7 +17,7 @@ http://www.nsnam.org/releases/ns-allinone-3.6.tar.bz2
Supported platforms
-------------------
ns-3.6 has been tested on the following platforms:
- linux x86 gcc 4.2, 4.1, and, 3.4.6.
- linux x86 gcc 4.4.1, 4.2, 4.1, and, 3.4.6.
- linux x86_64 gcc 4.4.0, 4.3.2, 4.2.3, 4.2.1, 4.1.3, 3.4.6
- MacOS X ppc and x86 (gcc 4.0.x and 4.2.x)
- cygwin gcc 3.4.4 (debug only), gcc 4.3.2 (debug and optimized)
@@ -68,10 +68,13 @@ New user-visible features
- Previous unit tests have been ported to new framework.
- Examples are tested for run-ability.
f) A new Flow Monitor module
- To very easily measure flow metrics in a simulation
- No need to use trace callbacks or parsing trace files
API changes from ns-3.5
-----------------------
API changes for this release are documented in the file CHANGES.html.
XXX
Known issues
------------
@@ -80,10 +83,6 @@ ns-3 build is known to fail on the following platforms:
- optimized builds on gcc 3.4.4 and 3.4.5
- optimized builds on linux x86 gcc 4.0.x
Future releases
---------------
XXX
Release 3.5
===========
+1 -1
View File
@@ -15,7 +15,7 @@ import Build
import Utils
## https://launchpad.net/pybindgen/
REQUIRED_PYBINDGEN_VERSION = (0, 12, 0, 700)
REQUIRED_PYBINDGEN_VERSION = (0, 12, 0, 703)
REQUIRED_PYGCCXML_VERSION = (0, 9, 5)
+4 -1
View File
@@ -17,6 +17,7 @@ IMAGES_EPS = \
$(FIGURES)/node.eps \
$(FIGURES)/buffer.eps \
$(FIGURES)/sockets-overview.eps \
$(FIGURES)/software-organization.eps \
$(FIGURES)/routing.eps \
$(FIGURES)/routing-specialization.eps \
$(FIGURES)/testbed.eps \
@@ -71,6 +72,8 @@ figures-clean:
version:
echo -n "ns-" > VERSION-PREFIX; cat VERSION-PREFIX ../../VERSION > VERSION; rm -rf VERSION-PREFIX
clean: figures-clean
texi-clean:
rm -rf manual.aux manual.cp manual.cps manual.fn manual.ky manual.pg manual.tp
rm -rf manual.vr manual.toc manual.log manual.pdf manual.html manual/ VERSION
clean: figures-clean texi-clean
+13
View File
@@ -0,0 +1,13 @@
@node Animation
@chapter Animation
@cartouche
Placeholder chapter
@end cartouche
This wiki page: @*
@uref{http://www.nsnam.org/wiki/index.php/NetAnim,,http://www.nsnam.org/wiki/index.php/NetAnim}
contains information about the animator support that has been added to ns-3.6.
Another Python-based animator is available (ns-3-pyviz) but is not
documented.
+6
View File
@@ -0,0 +1,6 @@
@node Applications
@chapter Applications
@cartouche
Placeholder chapter
@end cartouche
+99 -50
View File
@@ -125,7 +125,8 @@ public:
This is defined in the node.cc file as follows:
@verbatim
@smallformat
@example
TypeId
Node::GetTypeId (void)
{
@@ -148,15 +149,16 @@ Node::GetTypeId (void)
;
return tid;
}
@end verbatim
@end example
@end smallformat
Look at the TypeId of an ns-3 @code{Object} class as an extended form of run
time type information (RTTI). The C++ language includes simple kind of RTTI
Consider the TypeId of an ns-3 @code{Object} class as an extended form of run
time type information (RTTI). The C++ language includes a simple kind of RTTI
in order to support @code{dynamic_cast} and @code{typeid} operators.
The ``@code{.SetParent<Object> ()}'' call in the declaration above is used in
conjunction with our object aggregation mechanisms to allow safe up- and
down-casing in inheritance trees during @code{GetObject}.
down-casting in inheritance trees during @code{GetObject}.
The ``@code{.AddConstructor<Node> ()}'' call is used in conjunction with our
abstract object factory mechanisms to allow us to construct C++ objects without
@@ -183,7 +185,7 @@ without even knowing the concrete C++ type
@verbatim
ObjectFactory factory;
const std::string typeId = "ns3::Node'';
factory.SetTypeId(typeId);
factory.SetTypeId (typeId);
Ptr<Object> node = factory.Create <Object> ();
@end verbatim
@@ -259,7 +261,8 @@ and some type of global default value.
In the ns-3 attribute system, these value definitions and accessor
functions are moved into the TypeId class; e.g.:
@verbatim
@smallformat
@example
NS_OBJECT_ENSURE_REGISTERED (DropTailQueue);
TypeId DropTailQueue::GetTypeId (void)
@@ -276,7 +279,8 @@ TypeId DropTailQueue::GetTypeId (void)
return tid;
}
@end verbatim
@end example
@end smallformat
The AddAttribute() method is performing a number of things with this
value:
@@ -295,11 +299,19 @@ section, we will provide an example script that shows how users
may manipulate these values.
Note that initialization of the attribute relies on the macro
NS_OBJECT_ENSURE_REGISTERED (DropTailQueue) being called; if you leave
@code{NS_OBJECT_ENSURE_REGISTERED} (DropTailQueue) being called; if you leave
this out of your new class implementation, your attributes will not be
initialized correctly.
@subsection Basic usage
While we have described how to create attributes, we still haven't
described how to access and manage these values. For instance, there is no
@code{globals.h} header file where these are stored; attributes are
stored with their classes. Questions that naturally arise are how
do users easily learn about all of the attributes of their models, and
how does a user access these attributes, or document their values
as part of the record of their simulation?
@subsection Default values and command-line arguments
Let's look at how a user script might access these values.
This is based on the script found at @code{samples/main-attribute-value.cc},
@@ -341,7 +353,8 @@ Now, we will create a few objects using the low-level API; here,
our newly created queues will not have a m_maxPackets initialized to
100 packets but to 80 packets, because of what we did above with
default values.
@verbatim
@smallformat
@example
Ptr<Node> n0 = CreateObject<Node> ();
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
@@ -349,7 +362,8 @@ default values.
Ptr<Queue> q = CreateObject<DropTailQueue> ();
net0->AddQueue(q);
@end verbatim
@end example
@end smallformat
At this point, we have created a single node (Node 0) and a
single PointToPointNetDevice (NetDevice 0) and added a
@@ -358,10 +372,10 @@ DropTailQueue to it.
Now, we can manipulate the MaxPackets value of the already
instantiated DropTailQueue. Here are various ways to do that.
@subsubsection Pointer-based access
@subsection Pointer-based access
We assume that a smart pointer (Ptr) to a relevant network device is
in hand; here, it is the net0 pointer.
in hand; in the current example, it is the @code{net0} pointer.
One way to change the value is to access a pointer to the
underlying queue and modify its attribute.
@@ -369,11 +383,11 @@ underlying queue and modify its attribute.
First, we observe that we can get a pointer to the (base class)
queue via the PointToPointNetDevice attributes, where it is called
TxQueue
@verbatim
@example
PointerValue tmp;
net0->GetAttribute ("TxQueue", tmp);
Ptr<Object> txQueue = tmp.GetObject ();
@end verbatim
@end example
Using the GetObject function, we can perform a safe downcast
to a DropTailQueue, where MaxPackets is a member
@@ -409,44 +423,52 @@ Now, let's set it to another value (60 packets)
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets");
@end verbatim
@subsubsection Namespace-based access
@subsection Namespace-based access
An alternative way to get at the attribute is to use the configuration namespace.
Here, this attribute resides on a known path in this namespace; this approach
is useful if one doesn't have access to the underlying pointers and would like
to configure a specific attribute with a single statement.
@verbatim
@smallformat
@example
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25));
txQueue->GetAttribute ("MaxPackets", limit);
NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
limit.Get () << " packets");
@end verbatim
@end example
@end smallformat
We could have also used wildcards to set this value for all nodes and all net
devices (which in this simple example has the same effect as the previous Set())
@verbatim
@smallformat
@example
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15));
txQueue->GetAttribute ("MaxPackets", limit);
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
limit.Get () << " packets");
@end verbatim
@end example
@end smallformat
@subsubsection Object Name Service-based access
@subsection Object Name Service-based access
Another way to get at the attribute is to use the object name service facility.
Here, this attribute is found using a name string. This approach is useful if
one doesn't have access to the underlying pointers and it is difficult to
determine the required concrete configuration namespaced path.
@verbatim
@smallformat
@example
Names::Add ("server", serverNode);
Names::Add ("server/eth0", serverDevice);
...
Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25));
@end verbatim
@end example
@end smallformat
@xref{Object names} for a fuller treatment of the ns-3 configuration namespace.
@subsection Setting through constructors helper classes
@@ -466,7 +488,8 @@ or from the higher-level helper APIs, such as:
"LayoutType", StringValue ("RowFirst"));
@end verbatim
@subsection Value classes
@subsection Implementation details
@subsubsection Value classes
Readers will note the new FooValue classes which are subclasses of the
AttributeValue base class. These can be thought of as
an intermediate class that can be used to convert from raw types to the
@@ -489,14 +512,14 @@ the attribute system:
@item ATTRIBUTE_HELPER_CPP
@end itemize
@subsection Initialization order
@subsubsection Initialization order
In general, the attribute code to assign values to the underlying
class member variables is executed after an object is constructed.
But what if you need the values assigned before the constructor
body executes, because you need them in the logic of the constructor?
There is a way to do this, used for example in the class
@code{ns3::ConfigStore}: call @code{ObjectBase::ConstructSelf()}
@code{ns3::ConfigStore}: call @code{ObjectBase::ConstructSelf ()}
as follows:
@verbatim
@@ -546,7 +569,8 @@ Here, we discuss the impact on a user who wants to add a new class to
ns-3; what additional things must be done to hook it into this system.
We've already introduced what a TypeId definition looks like:
@verbatim
@smallformat
@example
TypeId
RandomWalk2dMobilityModel::GetTypeId (void)
{
@@ -568,7 +592,8 @@ RandomWalk2dMobilityModel::GetTypeId (void)
;
return tid;
}
@end verbatim
@end example
@end smallformat
The declaration for this in the class declaration is one-line public
member method:
@@ -599,7 +624,9 @@ the conversions to/from strings and attribute values. Most of this can be
copy/pasted with macro-ized code. For instance, consider class
declaration for Rectangle in the @code{src/mobility/} directory:
@verbatim
@subsection Header file
@smallformat
@example
/**
* \brief a 2d rectangle
*/
@@ -612,35 +639,42 @@ class Rectangle
double yMin;
double yMax;
};
@end verbatim
@end example
@end smallformat
One macro call and two operators, must be added below the class declaration
in order to turn a Rectangle into a value usable by the @code{Attribute}
system:
@verbatim
@smallformat
@example
std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
std::istream &operator >> (std::istream &is, Rectangle &rectangle);
ATTRIBUTE_HELPER_HEADER (Rectangle);
@end verbatim
@end example
@end smallformat
@subsection Implementation file
In the class definition (@code{.cc} file), the code looks like this:
@verbatim
@smallformat
@example
ATTRIBUTE_HELPER_CPP (Rectangle);
std::ostream &
operator << (std::ostream &os, const Rectangle &rectangle)
{
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax;
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|"
<< rectangle.yMax;
return os;
}
std::istream &
operator >> (std::istream &is, Rectangle &rectangle)
{
char c1, c2, c3;
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax;
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3
>> rectangle.yMax;
if (c1 != '|' ||
c2 != '|' ||
c3 != '|')
@@ -649,7 +683,8 @@ operator >> (std::istream &is, Rectangle &rectangle)
}
return is;
}
@end verbatim
@end example
@end smallformat
These stream operators simply convert from a string representation of the
Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the
@@ -679,7 +714,8 @@ file to the scratch directory:
Let's edit it to add the ConfigStore feature. First, add an include statement
to include the contrib module, and then add these lines:
@verbatim
@smallformat
@example
#include "contrib-module.h"
...
int main (...)
@@ -693,7 +729,8 @@ int main (...)
Simulator::Run ();
}
@end verbatim
@end example
@end smallformat
There are three attributes that govern the behavior of the ConfigStore:
"Mode", "Filename", and "FileFormat". The Mode (default "None") configures
@@ -705,12 +742,16 @@ the ConfigStore format is Xml or RawText format.
So, using the above modified program, try executing the following
waf command and
@verbatim
./waf --command-template="%s --ns3::ConfigStore::Filename=csma-bridge-config.xml --ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=Xml" --run scratch/csma-bridge
@end verbatim
@smallformat
@example
./waf --command-template="%s --ns3::ConfigStore::Filename=csma-bridge-config.xml
--ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=Xml" --run scratch/csma-bridge
@end example
@end smallformat
After running, you can open the csma-bridge-config.xml file and it will
display the configuration that was applied to your simulation; e.g.
@verbatim
@smallformat
@example
<?xml version="1.0" encoding="UTF-8"?>
<ns3>
<default name="ns3::V4Ping::Remote" value="102.102.102.102"/>
@@ -723,7 +764,9 @@ display the configuration that was applied to your simulation; e.g.
<default name="ns3::QstaWifiMac::MaxMissedBeacons" value="10"/>
<default name="ns3::QstaWifiMac::ActiveProbing" value="false"/>
...
@end verbatim
@end example
@end smallformat
This file can be archived with your simulation script and output data.
While it is possible to generate a sample config file and lightly
@@ -749,7 +792,8 @@ separate file called "output-attributes.xml". (Note-- to get this
input xml file to begin with, it is sometimes helpful to run the
program to generate an output xml file first, then hand-edit that
file and re-input it for the next simulation run).
@verbatim
@smallformat
@example
#include "contrib-module.h"
...
int main (...)
@@ -778,7 +822,8 @@ int main (...)
outputConfig.ConfigureAttributes ();
Simulator::Run ();
}
@end verbatim
@end example
@end smallformat
@subsection GTK-based ConfigStore
@@ -794,24 +839,28 @@ 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
@smallformat
@example
---- 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
@end example
@end smallformat
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, but there
are no ConfigStore attributes involved:
@verbatim
@smallformat
@example
// Invoke just before entering Simulator::Run ()
GtkConfigStore config;
config.ConfigureDefaults ();
config.ConfigureAttributes ();
@end verbatim
@end example
@end smallformat
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
+9
View File
@@ -0,0 +1,9 @@
@node Bridge NetDevice
@chapter Bridge NetDevice
@cartouche
Placeholder chapter
@end cartouche
Some examples of the use of Bridge NetDevice can be found in
@code{examples/csma/} directory.
+32 -16
View File
@@ -7,15 +7,16 @@ chapter provides some motivation on the callback, guidance on how to use
it, and details on its implementation.
@menu
* Motivation::
* Background::
* Callbacks Motivation::
* Callbacks Background::
* Using the Callback API::
* Bound Callbacks::
* Callback locations in ns-3::
* Traced Callbacks::
* Implementation details::
@end menu
@node Motivation
@node Callbacks Motivation
@section Motivation
Consider that you have two simulation models A and B, and you wish
@@ -35,7 +36,6 @@ public:
class B {
public:
void ReceiveInput ( // parameters);
void DoSomething (void);
...
@@ -91,9 +91,13 @@ to a transport protocol above, the user may be forced to hack the
system to get the desired interconnections, This is clearly not an
optimal way to design a generic simulator.
@node Background
@node Callbacks Background
@section Background
@cartouche
Readers familiar with programming callbacks may skip this tutorial section.
@end cartouche
The basic mechanism that allows one to address the problem above is known as
a @emph{callback}. The ultimate goal is to allow one piece of code to call
a function (or method in C++) without any specific inter-module dependency.
@@ -358,16 +362,19 @@ Consider also the following main program snippet:
@end verbatim
This is an example of a C-style callback -- one which does not include or need
a @code{this} pointer. The funtion template @code{Callback} is esentially the
a @code{this} pointer. The function template @code{Callback} is esentially the
declaration of the variable containing the pointer-to-function. In the example
above, we explicitly showed a pointer to a function that returned an integer and
took a single integer as a parameter, The @code{Callback} template function is
a generic version of that -- it is used to declare the type of a callback.
@strong{Note1:} Readers unfamiliar with C++ templates may consult
@uref{http://www.cplusplus.com/doc/tutorial/templates/,,this reference}.
The @code{Callback} template requires one mandatory argument (the return type
of the function to be assigned to this callback) and up to five optional
arguments, which each specify the type of the arguments (if your particular
callback function has more than five arguments, then this can be easily handled
callback function has more than five arguments, then this can be handled
by extending the callback implementation).
So in the above example, we have a declared a callback named "one" that will
@@ -451,7 +458,7 @@ invoked. Consider this example, also from main-callback.cc:
@end verbatim
Here, we pass an additional object pointer to the @code{MakeCallback<>} function.
Recall from the example above that @code{Operator()} will use the pointer to
Recall from the background section above that @code{Operator()} will use the pointer to
member syntax when it executes on an object:
@verbatim
@@ -505,7 +512,7 @@ later -- when the @code{Callback} is called via @code{operator()}. All of
the parameters are provided by the calling function.
What if it is desired to allow the client function (the one that provides the
callback) to provide some of the parameters? Alexandrescu calls the process of
callback) to provide some of the parameters? @uref{http://erdani.com/book/main.html,,Alexandrescu} calls the process of
allowing a client to specify one of the parameters @emph{binding}. One of the
parameters of @code{operator()} has been bound (fixed) by the client.
@@ -539,7 +546,7 @@ takes the parameters to be bound. In the case of the example above,
MakeBoundCallback (&CsmaHelper::SniffEvent, pcap));
@end verbatim
Will create a specific callback implementation that knows to add in the extra
will create a specific callback implementation that knows to add in the extra
bound arguments. Conceptually, it extends the specific functor described above
with one or more bound arguments
@@ -581,16 +588,24 @@ function call:
(*m_p.*m_pmi)(m_boundArg, arg);
@end verbatim
@node Traced Callbacks
@section Traced Callbacks
@cartouche
Placeholder subsection
@end cartouche
@section Callback locations in @command{ns-3}
@node Callback locations in ns-3
@section Callback locations in @command{ns-3}
Where are callbacks frequently used in @command{ns-3}? Here are some of the
more visible ones to typical users:
@subsection Socket API
@subsection Layer-2/Layer-3 API
@subsection Tracing subsystem
@subsection Routing
@itemize @bullet
@item Socket API
@item Layer-2/Layer-3 API
@item Tracing subsystem
@item API between IP and routing subsystems
@end itemize
@node Implementation details
@section Implementation details
@@ -600,8 +615,9 @@ itself. The actual Callback code is quite complicated and very template-intense
a deep understanding of the code is not required. If interested, expert users may
find the following useful:
The code was originally written based on the techniques described
@uref{http://www.codeproject.com/cpp/TTLFunction.asp,,here}.
The code was originally written based on the techniques described in
@uref{http://www.codeproject.com/cpp/TTLFunction.asp,,
http://www.codeproject.com/cpp/TTLFunction.asp}.
It was subsequently rewritten to follow the architecture outlined in
@uref{http://www.amazon.com/Modern-C\%2B\%2B-Design-Programming-Patterns/dp/0201704315/ref=pd_bbs_sr_1/102-0157303-1900156?ie=UTF8\&s=books\&qid=1187982662\&sr=1-1,,Modern C++ Design: Generic Programming and Design Patterns Applied-- Alexandrescu}, chapter 5, "Generalized Functors".
+244 -139
View File
@@ -1,183 +1,288 @@
@node Emu NetDevice
@chapter Emu NetDevice
This is the introduction to Emu NetDevice chapter, to complement the
Emu model doxygen.
@section Behavior
@menu
* Overview of the model::
* Using the EmuNetDevice::
* Emu Tracing::
@end menu
The @code{Emu} net device allows a simulation node to send and receive packets
over a real network. The emulated net device relies on a specified interface
being in promiscuous mode. It opens a raw socket and binds to that interface.
We perform MAC spoofing to separate simulation network traffic from other
network traffic that may be flowing to and from the host.
@node Overview of the model
@section Overview of the model
One can use the @code{Emu} net device in a testbed situation where the
host on which the simulation is running has a specific interface of interest
which drives the testbed hardware. You would also need to set this specific
interface into promiscuous mode and provide an appropriate device name to the
ns-3 emulated net device. An example of this environment is the ORBIT testbed
as described above.
The emulated net device allows a simulation node to send and receive packets
a real network.
The Emu net device is not a complete net device and channel combination as is
typical in ns-3. The Emu device can be thought of as a proxy for a real
device that resides in an ns-3 simulation. The Emu net device talks to that
real device using raw sockets and binds to the device via the Linux interface.
There is no related Emu channel since other devices will most likely reside on
different computers running entirely separate simulations.
The Emu net device relies on a specified interface (``eth1, for example) being
in promiscuous mode. It opens a raw socket and binds to that interface. We
perform MAC spoofing to separate simulation network traffic from other network
traffic that may be flowing to and from the host.
Normally, the use case for emulated net devices is in collections of
small simulations that connect to the outside world through specific
interfaces. For example, one could construct a number of virtual
machines and connect them via a host-only network. To use the emulated
net device, you would need to set all of the host-only interfaces in
promiscuous mode and provide an appropriate device name, "eth1" for example.
One could also use the emulated net device in a testbed situation
where the host on which the simulation is running has a specific interface
of interest which drives the testbed hardware. You would also need to set
this specific interface into promiscuous mode and provide an appropriate
device name to the ns-3 emulated net device.
The emulated net device only works if the underlying interface is up in
promiscuous mode. We could just turn it on, but the situation is that we
expect the other considerations listed above to have been dealt with.
To verify that these issues are dealt with, we just make sure that the end
result of that process has taken place and that the specified interface is
in promiscuous mode.
@subsection Address Concerns
Packets will be sent out over the device, but as mentioned, we use MAC spoofing.
By default in the simulation, the MAC addresses will be generated using the
The @code{Emu} net device only works if the underlying interface is up and in
promiscuous mode. Packets will be sent out over the device, but we use MAC
spoofing. The MAC addresses will be generated (by default) using the
Organizationally Unique Identifier (OUI) 00:00:00 as a base. This vendor code
is not assigned to any organization and so should not conflict with any real
hardware.
It is always up to you to determine that using these MAC addresses is
It is always up to the user to determine that using these MAC addresses is
okay on your network and won't conflict with anything else (including another
simulation using emu devices) on your network. If you are using the
simulation using @code{Emu} devices) on your network. If you are using the
emulated net device in separate simulations you must consider global MAC
address assignment issues and ensure that MAC addresses are unique across
all simulations. The emulated net device respects the MAC address provided
in the SetAddress method so you can do this manually. For larger simulations,
you may want to set the OUI in the MAC address allocation function.
in the @code{SetAddress} method so you can do this manually. For larger
simulations, you may want to set the OUI in the MAC address allocation function.
IP addresses corresponding to the emulated net devices are the addresses
generated in the simulation, which are generated in the usual way via helper
functions.
@subsection Attributes
The Emu network device appears to the ns-3 system just as any other device and
can be controlled through the attribute system, and traced through conventional
trace hooks. The EmuNetDevice provides following Attributes:
@itemize @bullet
@item Address: The Mac48Address of the device;
@item DeviceName: The name of the underlying real device (e.g., ``eth1'');
@item Start: The simulation time at which to enable the underlying socket;
@item Stop: The simulation time at which to stop receiving from the underlying socket;
@item TxQueue: The transmit queue used by the device;
@item InterframeGap: The optional time to wait between "frames";
@item Rx: A trace source for received packets;
@end itemize
Packets sent over the EmuNetDevice are always routed through the
transmit queue to provide a trace hook for packets sent out over the
network. This transmit queue can be set (via attribute) to model different
queuing strategies.
@node Using the EmuNetDevice
@section Using the EmuNetDevice
functions. Since we are using MAC spoofing, there will not be a conflict
between ns-3 network stacks and any native network stacks.
The emulated net device comes with a helper function as all ns-3 devices do.
One unique aspect is that there is no channel associated with the underlying
medium. We really have no idea what this medium is, and so have not made an
effort to model it abstractly. The primary thing to be aware of is the
implication this has for static global routing. The global router module
medium. We really have no idea what this external medium is, and so have not
made an effort to model it abstractly. The primary thing to be aware of is the
implication this has for IPv4 global routing. The global router module
attempts to walk the channels looking for adjacent networks. Since there
is no channel, the global router will be unable to do this.
is no channel, the global router will be unable to do this and you must then
use a dynamic routing protocol such as OLSR to include routing in
@code{Emu}-based networks.
The Emu net devices are typically created and configured using the associated
@code{EmuHelper} object. The various ns3 device helpers generally work in a
similar way, and their use is seen in many of our example programs.
The conceptual model of interest is that of a bare computer ``husk'' into which
you plug net devices. The bare computers are created using a @code{NodeContainer}
helper. You just ask this helper to create as many computers (we call them
@code{Nodes}) as you need on your network:
@section Usage
Any mixing of ns-3 objects with real objects will typically require that
ns-3 compute checksums in its protocols. By default, checksums are not
computed by ns-3. To enable checksums (e.g. UDP, TCP, IP), users must set
the attribute @code{ChecksumEnabled} to true, such as follows:
@verbatim
NodeContainer nodes;
nodes.Create (nEmuNodes);
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
@end verbatim
Once you have your nodes, you need to instantiate a @code{EmuHelper} and set
any attributes you may want to change.
The usage of the @code{Emu} net device is straightforward once the network of
simulations has been configured. Since most of the work involved in working
with this device is in network configuration before even starting a simulation,
you may want to take a moment to review a couple of HOWTO pages on the ns-3 wiki
that describe how to set up a virtual test network using VMware and how to run
a set of example (client server) simulations that use @code{Emu} net devices.
@itemize @bullet
@item @uref{http://www.nsnam.org/wiki/index.php/HOWTO_use_VMware_to_set_up_virtual_networks_(Windows)}
@item @uref{http://www.nsnam.org/wiki/index.php/HOWTO_use_ns-3_scripts_to_drive_real_hardware_(experimental)}
@end itemize
Once you are over the configuration hurdle, the script changes required to use
an @code{Emu} device are trivial. The main structural difference is that you
will need to create an ns-3 simulation script for each node. In the case of
the HOWTOs above, there is one client script and one server script. The only
``challenge'' is to get the addresses set correctly.
Just as with all other ns-3 net devices, we provide a helper class for the
@code{Emu} net device. The following code snippet illustrates how one would
declare an EmuHelper and use it to set the ``DeviceName'' attribute to ``eth1''
and install @code{Emu} devices on a group of nodes. You would do this on both
the client and server side in the case of the HOWTO seen above.
@verbatim
EmuHelper emu;
csma.SetAttribute ("DeviceName", StringValue ("eth1"));
emu.SetAttribute ("DeviceName", StringValue ("eth1"));
NetDeviceContainer d = emu.Install (n);
@end verbatim
Once the attributes are set, all that remains is to create the devices
and install them on the required nodes. When we create the net devices,
we add them to a container to allow you to use them in the future. This
all takes just one line of code.
The only other change that may be required is to make sure that the address
spaces (MAC and IP) on the client and server simulations are compatible. First
the MAC address is set to a unique well-known value in both places (illustrated
here for one side).
@verbatim
NetDeviceContainer emuDevices = emu.Install (nodes);
//
// We've got the devices in place. Since we're using MAC address
// spoofing under the sheets, we need to make sure that the MAC addresses
// we have assigned to our devices are unique. Ns-3 will happily
// automatically assign the same MAC address to the devices in both halves
// of our two-script pair, so let's go ahead and just manually change them
// to something we ensure is unique.
//
Ptr<NetDevice> nd = d.Get (0);
Ptr<EmuNetDevice> ed = nd->GetObject<EmuNetDevice> ();
ed->SetAddress ("00:00:00:00:00:02");
@end verbatim
@node Emu Tracing
@section Emu Tracing
And then the IP address of the client or server is set in the usual way using
helpers.
Like all ns-3 devices, the Emu Model provides a number of trace sources.
These trace sources can be hooked using your own custom trace code, or you
can use our helper functions to arrange for tracing to be enabled on devices
you specify.
@verbatim
//
// We've got the "hardware" in place. Now we need to add IP addresses.
// This is the server half of a two-script pair. We need to make sure
// that the addressing in both of these applications is consistent, so
// we use provide an initial address in both cases. Here, the client
// will reside on one machine running ns-3 with one node having ns-3
// with IP address "10.1.1.2" and talk to a server script running in
// another ns-3 on another computer that has an ns-3 node with IP
// address "10.1.1.3"
//
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0", "0.0.0.2");
Ipv4InterfaceContainer i = ipv4.Assign (d);
@end verbatim
@subsection Upper-Level (MAC) Hooks
You will use application helpers to generate traffic exactly as you do in any
ns-3 simulation script. Note that the server address shown below in a snippet
from the client, must correspond to the IP address assigned to the server node
similarly to the snippet above.
From the point of view of tracing in the net device, there are several
interesting points to insert trace hooks. A convention inherited from other
simulators is that packets destined for transmission onto attached networks
pass through a single "transmit queue" in the net device. We provide trace
hooks at this point in packet flow, which corresponds (abstractly) only to a
transition from the network to data link layer, and call them collectively
the device MAC hooks.
@verbatim
uint32_t packetSize = 1024;
uint32_t maxPacketCount = 2000;
Time interPacketInterval = Seconds (0.001);
UdpEchoClientHelper client ("10.1.1.3", 9);
client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
client.SetAttribute ("PacketSize", UintegerValue (packetSize));
ApplicationContainer apps = client.Install (n.Get (0));
apps.Start (Seconds (1.0));
apps.Stop (Seconds (2.0));
@end verbatim
When a packet is sent to the Emu net device for transmission it always
passes through the transmit queue. The transmit queue in the
EmuNetDevice inherits from Queue, and therefore inherits three
trace sources:
The @code{Emu} net device and helper provide access to ASCII and pcap tracing
functionality just as other ns-3 net devices to. You enable tracing similarly
to these other net devices:
@itemize @bullet
@item An Enqueue operation source (see Queue::m_traceEnqueue);
@item A Dequeue operation source (see Queue::m_traceDequeue);
@item A Drop operation source (see Queue::m_traceDrop).
@end itemize
@verbatim
EmuHelper::EnablePcapAll ("emu-udp-echo-client");
@end verbatim
The upper-level (MAC) trace hooks for the EmuNetDevice are, in fact,
exactly these three trace sources on the single transmit queue of the device.
To see an example of a client script using the @code{Emu} net device, see
@code{examples/emu-udp-echo-client.cc} and @code{examples/emu-udp-echo-server.cc}
in the repository @uref{http://code.nsnam.org/craigdo/ns-3-emu/}.
The m_traceEnqueue event is triggered when a packet is placed on the transmit
queue. This happens at the time that EmuNetDevice::Send or
EmuNetDevice::SendFrom is called by a higher layer to queue a packet for
transmission.
@section Implementation
The m_traceDequeue event is triggered when a packet is removed from the
transmit queue. Dequeues from the transmit queue happen immediately after
the Enqueue event and just prior to the packet being sent to the underlying
socket. This means that the transmit queue really only exists to fire on
enqueue and dequeue operations so the Emu device behaves like other ns-3
devices in this respect.
Perhaps the most unusual part of the @code{Emu} and @code{Tap} device
implementation relates to the requirement for executing some of the code
with super-user permissions. Rather than force the user to execute the entire
simulation as root, we provide a small ``creator'' program that runs as root
and does any required high-permission sockets work.
@subsection Lower-Level (PHY) Hooks
We do a similar thing for both the @code{Emu} and the @code{Tap} devices.
The high-level view is that the @code{CreateSocket} method creates a local
interprocess (Unix) socket, forks, and executes the small creation program.
The small program, which runs as suid root, creates a raw socket and sends
back the raw socket file descriptor over the Unix socket that is passed to
it as a parameter. The raw socket is passed as a control message (sometimes
called ancillary data) of type SCM_RIGHTS.
The @code{Emu} net device uses the ns-3 threading and multithreaded real-time
scheduler extensions. The interesting work in the @code{Emu} device is done
when the net device is started (@code{EmuNetDevice::StartDevice ()}). An
attribute (``Start'') provides a simulation time at which to spin up the
net device. At this specified time (which defaults to t=0), the socket
creation function is called and executes as described above. You may also
specify a time at which to stop the device using the ``Stop'' attribute.
Once the (promiscuous mode) socket is created, we bind it to an interface name
also provided as an attribute (``DeviceName'') that is stored internally as
@code{m_deviceName}:
@verbatim
struct ifreq ifr;
bzero (&ifr, sizeof(ifr));
strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
struct sockaddr_ll ll;
bzero (&ll, sizeof(ll));
ll.sll_family = AF_PACKET;
ll.sll_ifindex = m_sll_ifindex;
ll.sll_protocol = htons(ETH_P_ALL);
rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
@end verbatim
After the promiscuous raw socket is set up, a separate thread is spawned to do
reads from that socket and the link state is set to @code{Up}.
@verbatim
m_readThread = Create<SystemThread> (
MakeCallback (&EmuNetDevice::ReadThread, this));
m_readThread->Start ();
NotifyLinkUp ();
@end verbatim
The @code{EmuNetDevice::ReadThread} function basically just sits in an infinite
loop reading from the promiscuous mode raw socket and scheduling packet
receptions using the real-time simulator extensions.
@verbatim
for (;;)
{
...
len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr,
&addrSize);
...
DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->
ScheduleRealtimeNow (
MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
...
}
@end verbatim
The line starting with our templated DynamicCast function probably deserves a
comment. It gains access to the simulator implementation object using
the @code{Simulator::GetImplementation} method and then casts to the real-time
simulator implementation to use the real-time schedule method
@code{ScheduleRealtimeNow}. This function will cause a handler for the newly
received packet to be scheduled for execution at the current real time clock
value. This will, in turn cause the simulation clock to be advanced to that
real time value when the scheduled event (@code{EmuNetDevice::ForwardUp}) is
fired.
The @code{ForwardUp} function operates as most other similar ns-3 net device
methods do. The packet is first filtered based on the destination address. In
the case of the @code{Emu} device, the MAC destination address will be the
address of the @code{Emu} device and not the hardware address of the real
device. Headers are then stripped off and the trace hooks are hit. Finally,
the packet is passed up the ns-3 protocol stack using the receive callback
function of the net device.
Sending a packet is equally straightforward as shown below. The first thing
we do is to add the ethernet header and trailer to the ns-3 @code{Packet} we
are sending. The source address corresponds to the address of the @code{Emu}
device and not the underlying native device MAC address. This is where the
MAC address spoofing is done. The trailer is added and we enqueue and dequeue
the packet from the net device queue to hit the trace hooks.
@verbatim
header.SetSource (source);
header.SetDestination (destination);
header.SetLengthType (packet->GetSize ());
packet->AddHeader (header);
EthernetTrailer trailer;
trailer.CalcFcs (packet);
packet->AddTrailer (trailer);
m_queue->Enqueue (packet);
packet = m_queue->Dequeue ();
struct sockaddr_ll ll;
bzero (&ll, sizeof (ll));
ll.sll_family = AF_PACKET;
ll.sll_ifindex = m_sll_ifindex;
ll.sll_protocol = htons(ETH_P_ALL);
rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0,
reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
@end verbatim
Finally, we simply send the packet to the raw socket which puts it out on the
real network.
There are no lower level trace hooks implemented in the Emu net device since
we rely on the underlying OS implementation of the raw socket to perform
the low level operations required to send and receive packets.
+2 -317
View File
@@ -1,6 +1,5 @@
@node Emulation
@chapter Emulation
@anchor{chap:Emulation}
ns-3 has been designed for integration into testbed and virtual machine
environments. We have addressed this need by providing two kinds of
@@ -24,7 +23,7 @@ for details on the ORBIT testbed.
A simulation of this kind is shown in the following figure:
@float Figure,fig:testbed
@center @caption{Example Implementation of Testbed Emulation.}
@caption{Example Implementation of Testbed Emulation.}
@center @image{figures/testbed, 5in}
@end float
@@ -45,7 +44,7 @@ is shown in the following figure:
@float Figure,fig:emulated-channel
@caption{Implementation overview of emulated channel.}
@image{figures/emulated-channel, 5in}
@image{figures/emulated-channel, 6in}
@end float
Here, you will see that there is a single host with a number of virtual machines
@@ -68,317 +67,3 @@ We expect the typical use case for this environment will be to analyze the
behavior of native applications and protocol suites in the presence of large
simulated ns-3 networks.
@section Behavior
@subsection Emu Net Device
The @code{Emu} net device allows a simulation node to send and receive packets
over a real network. The emulated net device relies on a specified interface
being in promiscuous mode. It opens a raw socket and binds to that interface.
We perform MAC spoofing to separate simulation network traffic from other
network traffic that may be flowing to and from the host.
Normally, the use case for emulated net devices is in collections of small
simulations that connect to the outside world through specific interfaces.
For example, one could construct a number of virtual machines and connect them
via a host-only network. To use the emulated net device, you would need to
set all of the host-only interfaces in promiscuous mode and provide an
appropriate device name, "eth1" for example.
One could also use the @code{Emu} net device in a testbed situation where the
host on which the simulation is running has a specific interface of interest
which drives the testbed hardware. You would also need to set this specific
interface into promiscuous mode and provide an appropriate device name to the
ns-3 emulated net device. An example of this environment is the ORBIT testbed
as described above.
The @code{Emu} net device only works if the underlying interface is up and in
promiscuous mode. Packets will be sent out over the device, but we use MAC
spoofing. The MAC addresses will be generated (by default) using the
Organizationally Unique Identifier (OUI) 00:00:00 as a base. This vendor code
is not assigned to any organization and so should not conflict with any real
hardware.
It is always up to the user to determine that using these MAC addresses is
okay on your network and won't conflict with anything else (including another
simulation using @code{Emu} devices) on your network. If you are using the
emulated net device in separate simulations you must consider global MAC
address assignment issues and ensure that MAC addresses are unique across
all simulations. The emulated net device respects the MAC address provided
in the @code{SetAddress} method so you can do this manually. For larger
simulations, you may want to set the OUI in the MAC address allocation function.
IP addresses corresponding to the emulated net devices are the addresses
generated in the simulation, which are generated in the usual way via helper
functions. Since we are using MAC spoofing, there will not be a conflict
between ns-3 network stacks and any native network stacks.
The emulated net device comes with a helper function as all ns-3 devices do.
One unique aspect is that there is no channel associated with the underlying
medium. We really have no idea what this external medium is, and so have not
made an effort to model it abstractly. The primary thing to be aware of is the
implication this has for static global routing. The global router module
attempts to walk the channels looking for adjacent networks. Since there
is no channel, the global router will be unable to do this and you must then
use a dynamic routing protocol such as OLSR to include routing in
@code{Emu}-based networks.
@subsection Tap Net Device
The @code{Tap} Net Device is scheduled for inclusion in ns-3.4 at the writing
of this section. We will include details as soon as the @code{Tap} device is
merged.
@section Usage
Any mixing of ns-3 objects with real objects will typically require that
ns-3 compute checksums in its protocols. By default, checksums are not
computed by ns-3. To enable checksums (e.g. UDP, TCP, IP), users must set
the attribute @code{ChecksumEnabled} to true, such as follows:
@verbatim
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
@end verbatim
@subsection Emu Net Device
The usage of the @code{Emu} net device is straightforward once the network of
simulations has been configured. Since most of the work involved in working
with this device is in network configuration before even starting a simulation,
you may want to take a moment to review a couple of HOWTO pages on the ns-3 wiki
that describe how to set up a virtual test network using VMware and how to run
a set of example (client server) simulations that use @code{Emu} net devices.
@uref{http://www.nsnam.org/wiki/index.php/HOWTO_use_VMware_to_set_up_virtual_networks_(Windows)}
@uref{http://www.nsnam.org/wiki/index.php/HOWTO_use_ns-3_scripts_to_drive_real_hardware_(experimental)}
Once you are over the configuration hurdle, the script changes required to use
an @code{Emu} device are trivial. The main structural difference is that you
will need to create an ns-3 simulation script for each node. In the case of
the HOWTOs above, there is one client script and one server script. The only
``challenge'' is to get the addresses set correctly.
Just as with all other ns-3 net devices, we provide a helper class for the
@code{Emu} net device. The following code snippet illustrates how one would
declare an EmuHelper and use it to set the ``DeviceName'' attribute to ``eth1''
and install @code{Emu} devices on a group of nodes. You would do this on both
the client and server side in the case of the HOWTO seen above.
@verbatim
EmuHelper emu;
emu.SetAttribute ("DeviceName", StringValue ("eth1"));
NetDeviceContainer d = emu.Install (n);
@end verbatim
The only other change that may be required is to make sure that the address
spaces (MAC and IP) on the client and server simulations are compatible. First
the MAC address is set to a unique well-known value in both places (illustrated
here for one side).
@verbatim
//
// We've got the devices in place. Since we're using MAC address
// spoofing under the sheets, we need to make sure that the MAC addresses
// we have assigned to our devices are unique. Ns-3 will happily
// automatically assign the same MAC addresses to the devices in both halves
// of our two-script pair, so let's go ahead and just manually change them
// to something we ensure is unique.
//
Ptr<NetDevice> nd = d.Get (0);
Ptr<EmuNetDevice> ed = nd->GetObject<EmuNetDevice> ();
ed->SetAddress ("00:00:00:00:00:02");
@end verbatim
And then the IP address of the client or server is set in the usual way using
helpers.
@verbatim
//
// We've got the "hardware" in place. Now we need to add IP addresses.
// This is the server half of a two-script pair. We need to make sure
// that the addressing in both of these applications is consistent, so
// we use provide an initial address in both cases. Here, the client
// will reside on one machine running ns-3 with one node having ns-3
// with IP address "10.1.1.2" and talk to a server script running in
// another ns-3 on another computer that has an ns-3 node with IP
// address "10.1.1.3"
//
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0", "0.0.0.2");
Ipv4InterfaceContainer i = ipv4.Assign (d);
@end verbatim
You will use application helpers to generate traffic exactly as you do in any
ns-3 simulation script. Note that the server address shown below in a snippet
from the client, must correspond to the IP address assigned to the server node
similarly to the snippet above.
@verbatim
uint32_t packetSize = 1024;
uint32_t maxPacketCount = 2000;
Time interPacketInterval = Seconds (0.001);
UdpEchoClientHelper client ("10.1.1.3", 9);
client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
client.SetAttribute ("PacketSize", UintegerValue (packetSize));
ApplicationContainer apps = client.Install (n.Get (0));
apps.Start (Seconds (1.0));
apps.Stop (Seconds (2.0));
@end verbatim
The @code{Emu} net device and helper provide access to ASCII and pcap tracing
functionality just as other ns-3 net devices to. You enable tracing similarly
to these other net devices:
@verbatim
EmuHelper::EnablePcapAll ("emu-udp-echo-client");
@end verbatim
To see an example of a client script using the @code{Emu} net device, see
@code{examples/emu-udp-echo-client.cc} and @code{examples/emu-udp-echo-server.cc}
in the repository @uref{http://code.nsnam.org/craigdo/ns-3-emu/}.
@subsection Tap Net Device
The @code{Tap} Net Device is scheduled for inclusion in ns-3.4 at the writing
of this section. We will include details as soon as the @code{Tap} device is
merged.
@section Implementation
Perhaps the most unusual part of the @code{Emu} and @code{Tap} device
implementation relates to the requirement for executing some of the code
with super-user permissions. Rather than force the user to execute the entire
simulation as root, we provide a small ``creator'' program that runs as root
and does any required high-permission sockets work.
We do a similar thing for both the @code{Emu} and the @code{Tap} devices.
The high-level view is that the @code{CreateSocket} method creates a local
interprocess (Unix) socket, forks, and executes the small creation program.
The small program, which runs as suid root, creates a raw socket and sends
back the raw socket file descriptor over the Unix socket that is passed to
it as a parameter. The raw socket is passed as a control message (sometimes
called ancillary data) of type SCM_RIGHTS.
@subsection Emu Net Device
The @code{Emu} net device uses the ns-3 threading and multithreaded real-time
scheduler extensions. The interesting work in the @code{Emu} device is done
when the net device is started (@code{EmuNetDevice::StartDevice ()}). An
attribute (``Start'') provides a simulation time at which to spin up the
net device. At this specified time (which defaults to t=0), the socket
creation function is called and executes as described above. You may also
specify a time at which to stop the device using the ``Stop'' attribute.
Once the (promiscuous mode) socket is created, we bind it to an interface name
also provided as an attribute (``DeviceName'') that is stored internally as
@code{m_deviceName}:
@verbatim
struct ifreq ifr;
bzero (&ifr, sizeof(ifr));
strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
struct sockaddr_ll ll;
bzero (&ll, sizeof(ll));
ll.sll_family = AF_PACKET;
ll.sll_ifindex = m_sll_ifindex;
ll.sll_protocol = htons(ETH_P_ALL);
rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
@end verbatim
After the promiscuous raw socket is set up, a separate thread is spawned to do
reads from that socket and the link state is set to @code{Up}.
@verbatim
m_readThread = Create<SystemThread> (
MakeCallback (&EmuNetDevice::ReadThread, this));
m_readThread->Start ();
NotifyLinkUp ();
@end verbatim
The @code{EmuNetDevice::ReadThread} function basically just sits in an infinite
loop reading from the promiscuous mode raw socket and scheduling packet
receptions using the real-time simulator extensions.
@verbatim
for (;;)
{
...
len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr,
&addrSize);
...
DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->
ScheduleRealtimeNow (
MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
...
}
@end verbatim
The line starting with our templated DynamicCast function probably deserves a
comment. It gains access to the simulator implementation object using
the @code{Simulator::GetImplementation} method and then casts to the real-time
simulator implementation to use the real-time schedule method
@code{ScheduleRealtimeNow}. This function will cause a handler for the newly
received packet to be scheduled for execution at the current real time clock
value. This will, in turn cause the simulation clock to be advanced to that
real time value when the scheduled event (@code{EmuNetDevice::ForwardUp}) is
fired.
The @code{ForwardUp} function operates as most other similar ns-3 net device
methods do. The packet is first filtered based on the destination address. In
the case of the @code{Emu} device, the MAC destination address will be the
address of the @code{Emu} device and not the hardware address of the real
device. Headers are then stripped off and the trace hooks are hit. Finally,
the packet is passed up the ns-3 protocol stack using the receive callback
function of the net device.
Sending a packet is equally straightforward as shown below. The first thing
we do is to add the ethernet header and trailer to the ns-3 @code{Packet} we
are sending. The source address corresponds to the address of the @code{Emu}
device and not the underlying native device MAC address. This is where the
MAC address spoofing is done. The trailer is added and we enqueue and dequeue
the packet from the net device queue to hit the trace hooks.
@verbatim
header.SetSource (source);
header.SetDestination (destination);
header.SetLengthType (packet->GetSize ());
packet->AddHeader (header);
EthernetTrailer trailer;
trailer.CalcFcs (packet);
packet->AddTrailer (trailer);
m_queue->Enqueue (packet);
packet = m_queue->Dequeue ();
struct sockaddr_ll ll;
bzero (&ll, sizeof (ll));
ll.sll_family = AF_PACKET;
ll.sll_ifindex = m_sll_ifindex;
ll.sll_protocol = htons(ETH_P_ALL);
rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0,
reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
@end verbatim
Finally, we simply send the packet to the raw socket which puts it out on the
real network.
@subsection Tap Net Device
The @code{Tap} Net Device is scheduled for inclusion in ns-3.4 at the writing
of this section. We will include details as soon as the @code{Tap} device is
merged.
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
@node Flow Monitor
@chapter Flow Monitor
@cartouche
Placeholder chapter
@end cartouche
This feature was added as contributed code (@code{src/contrib}) in ns-3.6.
A paper on this feature is published in the proceedings of NSTools: @*
@uref{http://www.nstools.org/techprog.shtml,,http://www.nstools.org/techprog.shtml}
+42
View File
@@ -0,0 +1,42 @@
@node Helpers
@chapter Helpers
The above chapters introduced you to various ns-3 programming concepts
such as smart pointers for reference-counted memory management, attributes,
namespaces, callbacks, etc. Users who work at this low-level API
can interconnect ns-3 objects with fine granulariy. However, a
simulation program written entirely using the low-level API would
be quite long and tedious to code. For this reason, a separate so-called
``helper API'' has been overlaid on the core ns-3 API. If you have read
the ns-3 tutorial, you will already be familiar with the helper API,
since it is the API that new users are typically introduced to first.
In this chapter, we introduce the design philosophy of the helper
API and contrast it to the low-level API. If you become a heavy
user of ns-3, you will likely move back and forth between these
APIs even in the same program.
The helper API has a few goals:
@enumerate
@item the rest of @code{src/} has no dependencies on the helper API;
anything that can be done with the helper API can be coded also at
the low-level API
@item @strong{Containers:} Often simulations will need to do
a number of identical actions to groups of objects. The helper
API makes heavy use of containers of similar objects to which similar
or identical operations can be performed.
@item The helper API is not generic; it does not strive to maximize
code reuse. So, programming constructs such as polymorphism and
templates that achieve code reuse are not as prevalent. For instance,
there are separate CsmaNetDevice helpers and PointToPointNetDevice
helpers but they do not derive from a common NetDevice base class.
@item The helper API typically works with stack-allocated (vs.
heap-allocated) objects. For some programs, ns-3 users may not
need to worry about any low level Object Create or Ptr handling;
they can make do with containers of objects and stack-allocated helpers
that operate on them.
@end enumerate
The helper API is really all about making ns-3 programs easier to
write and read, without taking away the power of the low-level
interface. The rest of this chapter provides some examples of
the programming conventions of the helper API.
+243
View File
@@ -0,0 +1,243 @@
@node Internet Stack
@chapter Internet Stack
@section Internet stack aggregation
A bare @code{class Node} is not very useful as-is; other objects
must be aggregated to it to provide useful node functionality.
The ns-3 source code directory @code{src/internet-stack} provides
implementation of TCP/IPv4- and IPv6-related components. These include IPv4,
ARP, UDP, TCP, IPv6, Neighbor Discovery, and other related protocols.
Internet Nodes are not subclasses of class Node; they are simply Nodes
that have had a bunch of IPv4-related
objects aggregated to them. They can be put together by hand, or
via a helper function @code{InternetStackHelper::Install ()} which does the
following to all nodes passed in as arguments:
@smallformat
@example
void
InternetStackHelper::Install (Ptr<Node> node) const
{
if (node->GetObject<Ipv4> () != 0)
{
NS_FATAL_ERROR ("InternetStackHelper::Install(): Aggregating "
"an InternetStack to a node with an existing Ipv4 object");
return;
}
CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol");
CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3Protocol");
CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol");
CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol");
node->AggregateObject (m_tcpFactory.Create<Object> ());
Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> ();
node->AggregateObject (factory);
// Set routing
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
Ptr<Ipv4RoutingProtocol> ipv4Routing = m_routing->Create (node);
ipv4->SetRoutingProtocol (ipv4Routing);
}
@end example
@end smallformat
Where multiple implementations exist in ns-3 (TCP, IP routing), these
objects are added by a factory object (TCP) or by a routing helper
(m_routing).
Note that the routing protocol is configured and set outside this
function. By default, the following protocols are added to Ipv4:
@verbatim
InternetStackHelper::InternetStackHelper ()
{
SetTcp ("ns3::TcpL4Protocol");
static Ipv4StaticRoutingHelper staticRouting;
static Ipv4GlobalRoutingHelper globalRouting;
static Ipv4ListRoutingHelper listRouting;
listRouting.Add (staticRouting, 0);
listRouting.Add (globalRouting, -10);
SetRoutingHelper (listRouting);
}
@end verbatim
By default, IPv4 and IPv6 are enabled.
@subsection Internet Node structure
An IPv4-capable Node (an ns-3 Node augmented by aggregation to have one or more
IP stacks) has the following internal structure.
@subsubsection Layer-3 protocols
At the lowest layer, sitting above the NetDevices, are the "layer 3"
protocols, including IPv4, IPv6 (in the future), and ARP. The
@code{class Ipv4L3Protocol} is an
implementation class whose public interface is
typically @code{class Ipv4} (found in src/node directory), but the
Ipv4L3Protocol public API is also used internally in the
src/internet-stack directory at present.
In class Ipv4L3Protocol, one method described below is @code{Receive ()}:
@smallformat
@example
/**
* Lower layer calls this method after calling L3Demux::Lookup
* The ARP subclass needs to know from which NetDevice this
* packet is coming to:
* - implement a per-NetDevice ARP cache
* - send back arp replies on the right device
*/
void Receive( Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol,
const Address &from, const Address &to, NetDevice::PacketType packetType);
@end example
@end smallformat
First, note that the @code{Receive ()} function has a matching signature
to the ReceiveCallback in the @code{class Node}. This function pointer
is inserted into the Node's protocol handler when
@code{AddInterface ()} is called. The actual registration is done
with a statement such as:
follows:
@verbatim
RegisterProtocolHandler ( MakeCallback (&Ipv4Protocol::Receive, ipv4),
Ipv4L3Protocol::PROT_NUMBER, 0);
@end verbatim
The Ipv4L3Protocol object is aggregated to the Node; there is only one
such Ipv4L3Protocol object. Higher-layer protocols that have a packet
to send down to the Ipv4L3Protocol object can call
@code{GetObject<Ipv4L3Protocol> ()} to obtain a pointer, as follows:
@verbatim
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
if (ipv4 != 0)
{
ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
}
@end verbatim
This class nicely demonstrates two techniques we exploit in
ns-3 to bind objects together: callbacks, and object aggregation.
Once IPv4 routing has determined that a packet is for the local node, it
forwards it up the stack. This is done with the following function:
@smallformat
@example
void
Ipv4L3Protocol::LocalDeliver (Ptr<const Packet> packet, Ipv4Header const&ip, uint32_t iif)
@end example
@end smallformat
The first step is to find the right Ipv4L4Protocol object , based on IP protocol
number. For instance, TCP is registered in the demux as protocol number 6.
Finally, the @code{Receive()} function on the Ipv4L4Protocol (such as
@code{TcpL4Protocol::Receive} is called.
We have not yet introduced the class Ipv4Interface. Basically,
each NetDevice is paired with an IPv4 representation of such device.
In Linux, this @code{class Ipv4Interface} roughly corresponds to
the @code{struct in_device}; the main purpose is to provide
address-family specific information (addresses) about an interface.
The IPv6 implementation follows a similar architecture.
@subsubsection Layer-4 protocols and sockets
We next describe how the transport protocols, sockets, and applications
tie together. In summary, each transport protocol implementation is
a socket factory. An application that needs a new socket
For instance, to create a UDP socket, an application would use a code
snippet such as the following:
@verbatim
Ptr<Udp> udpSocketFactory = GetNode ()->GetObject<Udp> ();
Ptr<Socket> m_socket = socketFactory->CreateSocket ();
m_socket->Bind (m_local_address);
...
@end verbatim
The above will query the node to get a pointer to its UDP socket
factory, will create one such socket, and will use the socket with
an API similar to the C-based sockets API, such as @code{Connect ()}
and @code{Send ()}. See the chapter on ns-3 sockets for more information.
We have described so far a socket factory (e.g. @code{class Udp}) and
a socket, which may be specialized (e.g., @code{class UdpSocket}).
There are a few more key objects that relate to the specialized
task of demultiplexing a packet to one or more receiving sockets.
The key object in this task is @code{class Ipv4EndPointDemux}.
This demultiplexer stores objects of @code{class Ipv4EndPoint}.
This class holds the addressing/port tuple (local port, local address,
destination port, destination address) associated with the socket,
and a receive callback. This receive callback has a receive
function registered by the socket. The @code{Lookup ()} function to
Ipv4EndPointDemux returns a list of Ipv4EndPoint objects (there may
be a list since more than one socket may match the packet). The
layer-4 protocol copies the packet to each Ipv4EndPoint and calls
its @code{ForwardUp ()} method, which then calls the @code{Receive ()}
function registered by the socket.
An issue that arises when working with the sockets API on real
systems is the need to manage the reading from a socket, using
some type of I/O (e.g., blocking, non-blocking, asynchronous, ...).
ns-3 implements an asynchronous model for socket I/O; the application
sets a callback to be notified of received data ready to be read, and the
callback is invoked by the transport protocol when data is available.
This callback is specified as follows:
@verbatim
void Socket::SetRecvCallback (Callback<void, Ptr<Socket>,
Ptr<Packet>, const Address&> receivedData);
@end verbatim
The data being received is conveyed in the Packet data buffer. An example
usage is in @code{class PacketSink}:
@verbatim
m_socket->SetRecvCallback (MakeCallback(&PacketSink::HandleRead, this));
@end verbatim
To summarize, internally, the UDP implementation is organized as follows:
@itemize @bullet
@item a @code{UdpImpl} class that implements the UDP socket factory
functionality
@item a @code{UdpL4Protocol} class that implements the protocol logic
that is socket-independent
@item a @code{UdpSocketImpl} class that implements socket-specific aspects
of UDP
@item a class called @code{Ipv4EndPoint} that stores the
addressing tuple (local port, local address, destination port, destination
address) associated with the socket, and a receive callback for the socket.
@end itemize
@subsection Ipv4-capable node interfaces
Many of the implementation details, or internal objects themselves,
of Ipv4-capable Node objects are not exposed at the simulator public
API. This allows for different implementations; for instance,
replacing the native ns-3 models with ported TCP/IP stack code.
The C++ public APIs of all of these objects is found in the
@code{src/node} directory, including principally:
@itemize @bullet
@item @code{socket.h}
@item @code{tcp.h}
@item @code{udp.h}
@item @code{ipv4.h}
@end itemize
These are typically base class objects that implement the default
values used in the implementation, implement access methods to get/set
state variables, host attributes, and implement publicly-available methods
exposed to clients such as @code{CreateSocket}.
@subsection Example path of a packet
These two figures show an example stack trace of how packets flow
through the Internet Node objects.
@float Figure,fig:internet-node-send
@caption{Send path of a packet.}
@image{figures/internet-node-send,5in}
@end float
@float Figure,fig:internet-node-recv
@caption{Receive path of a packet.}
@image{figures/internet-node-recv,5in}
@end float
+6
View File
@@ -0,0 +1,6 @@
@node IPv4
@chapter IPv4
@cartouche
Placeholder chapter
@end cartouche
+10
View File
@@ -0,0 +1,10 @@
@node IPv6
@chapter IPv6
@cartouche
Placeholder chapter
@end cartouche
IPv6 models are being added to ns-3. A paper on the IPv6 models was
published in WNS2 2008: @*
@uref{http://lsiit.u-strasbg.fr/Publications/2008/VMM08/,,http://lsiit.u-strasbg.fr/Publications/2008/VMM08/}
+4 -21
View File
@@ -1,24 +1,7 @@
@node Logging
@chapter Logging
@anchor{chap:Logging}
This chapter is the first in a series of chapters discussing things that
one can do to modify the input or output of existing ns-3 scripts.
Examples:
@itemize @bullet
@item Enable or disable the generation of log messages, with fine granularity
@item Set default values for configuration values in the system
@item Generate a report of all configuration values used during a simulation
run (not yet implemented)
@item Set or get values of member variables on objects already instantiated
@item Customizing the tracing output of the script
@item Generate statistics on (not yet implemented)
@item Perform a large number of independent runs of the same simulation
@end itemize
@node Logging Basics
@section Logging Basics
@node Enabling Log Output
@section Enabling Log Output
@cartouche
This chapter not yet written. For now, the ns-3 tutorial contains logging
information.
@end cartouche
+79 -18
View File
@@ -2,7 +2,6 @@
@c %**start of header
@setfilename ns-3.info
@settitle ns-3 manual
@c @setchapternewpage odd
@c %**end of header
@ifinfo
@@ -25,11 +24,12 @@ the document should be discussed on the ns-developers@@isi.edu mailing list.
This is an @command{ns-3} reference manual.
Primary documentation for the @command{ns-3} project is available in
four forms:
five forms:
@itemize @bullet
@item @uref{http://www.nsnam.org/docs/tutorial/tutorial.html,,ns-3 Tutorial}
@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen}: Documentation of the public APIs of the simulator
@item Reference Manual (this document)
@item @uref{http://www.nsnam.org/tutorials.html,, ns-3 Testing and Validation manual}
@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki}
@end itemize
@@ -61,9 +61,10 @@ along with this program. If not, see @uref{http://www.gnu.org/licenses/}.
@include VERSION
@today{}
@c @page
@vskip 0pt plus 1filll
@insertcopying
@page
@center This page is intentionally blank.
@end titlepage
@c So the toc is printed at the start.
@@ -86,42 +87,102 @@ Simulator version:
@end ifnottex
@menu
* Organization::
* Random variables::
* Callbacks::
* Object model::
* Attributes::
* Object names::
* Logging::
* Tracing::
* RealTime::
* Emulation::
* Packets::
* Sockets APIs::
* Node and Internet Stack::
* TCP::
* Routing overview::
* Wifi NetDevice::
* CSMA NetDevice::
* Helpers::
* Python::
* Node and NetDevices::
* Simple NetDevice::
* PointToPoint NetDevice::
* CSMA NetDevice::
* Wifi NetDevice::
* Mesh NetDevice::
* Bridge NetDevice::
* Emulation::
* Emu NetDevice::
* Tap NetDevice::
* Sockets APIs::
* Internet Stack::
* IPv4::
* IPv6::
* Routing overview::
* TCP::
* Applications::
* Flow Monitor::
* Animation::
* Statistics::
* Creating a new ns-3 model::
* Troubleshooting::
@end menu
@setchapternewpage odd
@headings off
@everyheading @thischapter @| @| ns-3 manual
@everyfooting ns-3.6 @| @thispage @| @today
@include organization.texi
@unnumbered Part 1: ns-3 core
@setchapternewpage off
@include random.texi
@setchapternewpage odd
@include callbacks.texi
@include objects.texi
@include attributes.texi
@include names.texi
@include log.texi
@include tracing.texi
@include realtime.texi
@include emulation.texi
@include packets.texi
@include sockets.texi
@include helpers.texi
@include python.texi
@unnumbered Part 2: Nodes and NetDevices
@setchapternewpage off
@include node.texi
@c @include output.texi
@include tcp.texi
@include routing.texi
@include wifi.texi
@include csma.texi
@setchapternewpage odd
@include simple.texi
@include point-to-point.texi
@c @include other.texi
@include csma.texi
@include wifi.texi
@include mesh.texi
@include bridge.texi
@unnumbered Part 3: Emulation
@setchapternewpage off
@include emulation.texi
@setchapternewpage odd
@include emu.texi
@include tap.texi
@unnumbered Part 4: Internet Models
@setchapternewpage off
@include sockets.texi
@setchapternewpage odd
@include internet.texi
@include ipv4.texi
@include ipv6.texi
@include routing.texi
@include tcp.texi
@unnumbered Part 5: Applications
@setchapternewpage off
@include applications.texi
@setchapternewpage odd
@unnumbered Part 6: Support
@setchapternewpage off
@include flow-monitor.texi
@setchapternewpage odd
@include animation.texi
@include statistics.texi
@include new-models.texi
@include troubleshoot.texi
+11
View File
@@ -0,0 +1,11 @@
@node Mesh NetDevice
@chapter Mesh NetDevice
@cartouche
Placeholder chapter
@end cartouche
The Mesh NetDevice based on 802.11s was added in ns-3.6.
An overview presentation by Kirill Andreev was published at the wns-3 workshop
in 2009: @*
@uref{http://www.nsnam.org/wiki/index.php/Wns3-2009,,http://www.nsnam.org/wiki/index.php/Wns3-2009}
+6
View File
@@ -0,0 +1,6 @@
@node Object names
@chapter Object names
@cartouche
Placeholder chapter
@end cartouche
+29 -16
View File
@@ -395,8 +395,10 @@ The @ref{Object model} chapter discusses this in more detail.
@subsection how to include files from elsewhere
@subsection log component
Here, write a bit about adding ns-3 logging macros. Note that
@cartouche
Here, write a bit about adding ns-3 logging macros. Note that @*
LOG_COMPONENT_DEFINE is done outside the namespace ns3
@end cartouche
@subsection constructor, empty function prototypes
@@ -407,7 +409,8 @@ LOG_COMPONENT_DEFINE is done outside the namespace ns3
@subsection Object Framework
@verbatim
@smallformat
@example
static const ClassId cid;
@@ -416,8 +419,8 @@ const InterfaceId ErrorModel::iid =
const ClassId ErrorModel::cid =
MakeClassId<ErrorModel> ("ErrorModel", ErrorModel::iid);
@end verbatim
@end example
@end smallformat
@node Adding-a-sample-script
@section Adding a sample script
@@ -431,7 +434,8 @@ of the ErrorModels themselves.
@subsection Add basic support in the class
@verbatim
@smallformat
@example
point-to-point-net-device.h
class ErrorModel;
@@ -440,12 +444,13 @@ point-to-point-net-device.h
*/
Ptr<ErrorModel> m_receiveErrorModel;
@end verbatim
@end example
@end smallformat
@subsection Add Accessor
@verbatim
@smallformat
@example
void
PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
{
@@ -458,11 +463,13 @@ PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
PointerValue (),
MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
MakePointerChecker<ErrorModel> ())
@end verbatim
@end example
@end smallformat
@subsection Plumb into the system
@verbatim
@smallformat
@example
void PointToPointNetDevice::Receive (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this << packet);
@@ -486,15 +493,18 @@ void PointToPointNetDevice::Receive (Ptr<Packet> packet)
ProcessHeader(packet, protocol);
m_rxCallback (this, packet, protocol, GetRemote ());
if (!m_promiscCallback.IsNull ())
{ m_promiscCallback (this, packet, protocol, GetRemote (), GetAddress (), NetDevice::PACKET_HOST);
{ m_promiscCallback (this, packet, protocol, GetRemote (),
GetAddress (), NetDevice::PACKET_HOST);
}
}
}
@end verbatim
@end example
@end smallformat
@subsection Create null functional script
@verbatim
@smallformat
@example
simple-error-model.cc
// Error model
@@ -514,7 +524,8 @@ ErrorModel::DoCorrupt (Packet& p)
NS_LOG_UNCOND("Corrupt!");
return false;
}
@end verbatim
@end example
@end smallformat
At this point, we can run the program with our trivial ErrorModel
plumbed into the receive path of the PointToPointNetDevice. It
@@ -550,7 +561,8 @@ the above unit of granularity.
We declare BasicErrorModel to be a subclass of ErrorModel as follows,
@verbatim
@smallformat
@example
class BasicErrorModel : public ErrorModel
{
public:
@@ -562,7 +574,8 @@ private:
virtual bool DoReset (void);
...
}
@end verbatim
@end example
@end smallformat
and configure the subclass GetTypeId function by setting a unique
TypeId string and setting the Parent to ErrorModel:
+6 -229
View File
@@ -1,5 +1,5 @@
@node Node and Internet Stack
@chapter Node and Internet Stack
@node Node and NetDevices
@chapter Node and NetDevices
@anchor{chap:Node}
This chapter describes how ns-3 nodes are put together, and provides
@@ -20,8 +20,8 @@ to which one may add NetDevices (cards) and other innards including
the protocols and applications. @ref{fig:node} illustrates
that Node objects contain a list of Applications (initially,
the list is empty), a list of NetDevices (initially, the list
is empty), a unique integer ID, and a system ID (for
distributed simulation).
is empty), a list of ProtocolHandlers, a unique integer ID, and
a system ID (for distributed simulation).
The design tries to avoid putting too many dependencies on the
base class Node, Application, or NetDevice for the following:
@@ -109,229 +109,6 @@ The NodeList class provides an @code{Add()} method and C++ iterators
to allow one to walk the node list or fetch a Node pointer by
its integer identifier.
@section Internet stack aggregation
The above @code{class Node} is not very useful as-is; other objects
must be aggregated to it to provide useful node functionality.
The ns-3 source code directory @code{src/internet-stack} provides
implementation of TCP/IPv4-related components. These include IPv4,
ARP, UDP, TCP, and other related protocols.
Internet Nodes are not subclasses of class Node; they are simply Nodes
that have had a bunch of IPv4-related
objects aggregated to them. They can be put together by hand, or
via a helper function @code{InternetStackHelper::Install ()} which does the
following to all nodes passed in as arguments:
@verbatim
void
InternetStackHelper::Install (Ptr<Node> node) const
{
if (node->GetObject<Ipv4> () != 0)
{
NS_FATAL_ERROR ("InternetStackHelper::Install(): Aggregating "
"an InternetStack to a node with an existing Ipv4 object");
return;
}
CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol");
CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3Protocol");
CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol");
CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol");
node->AggregateObject (m_tcpFactory.Create<Object> ());
Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> ();
node->AggregateObject (factory);
// Set routing
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
Ptr<Ipv4RoutingProtocol> ipv4Routing = m_routing->Create (node);
ipv4->SetRoutingProtocol (ipv4Routing);
}
@end verbatim
Note that the Ipv4 routing protocol is configured and set outside this
function. By default, the following protocols are added to Ipv4:
@verbatim
InternetStackHelper::InternetStackHelper ()
{
SetTcp ("ns3::TcpL4Protocol");
static Ipv4StaticRoutingHelper staticRouting;
static Ipv4GlobalRoutingHelper globalRouting;
static Ipv4ListRoutingHelper listRouting;
listRouting.Add (staticRouting, 0);
listRouting.Add (globalRouting, -10);
SetRoutingHelper (listRouting);
}
@end verbatim
@subsection Internet Node structure
An IPv4-capable Node (an ns-3 Node augmented by aggregation to have one or more
IP stacks) has the following internal structure.
@subsubsection Layer-3 protocols
At the lowest layer, sitting above the NetDevices, are the "layer 3"
protocols, including IPv4, IPv6 (in the future), and ARP. The
@code{class Ipv4L3Protocol} is an
implementation class whose public interface is
typically @code{class Ipv4} (found in src/node directory), but the
Ipv4L3Protocol public API is also used internally in the
src/internet-stack directory at present.
In class Ipv4L3Protocol, one method described below is @code{Receive ()}:
@verbatim
/**
* Lower layer calls this method after calling L3Demux::Lookup
* The ARP subclass needs to know from which NetDevice this
* packet is coming to:
* - implement a per-NetDevice ARP cache
* - send back arp replies on the right device
*/
void Receive( Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
const Address &to, NetDevice::PacketType packetType);
@end verbatim
First, note that the @code{Receive ()} function has a matching signature
to the ReceiveCallback in the @code{class Node}. This function pointer
is inserted into the Node's protocol handler when
@code{AddInterface ()} is called. The actual registration is done
with a statement such as:
follows:
@verbatim
RegisterProtocolHandler ( MakeCallback (&Ipv4Protocol::Receive, ipv4),
Ipv4L3Protocol::PROT_NUMBER, 0);
@end verbatim
The Ipv4L3Protocol object is aggregated to the Node; there is only one
such Ipv4L3Protocol object. Higher-layer protocols that have a packet
to send down to the Ipv4L3Protocol object can call
@code{GetObject<Ipv4L3Protocol> ()} to obtain a pointer, as follows:
@verbatim
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
if (ipv4 != 0)
{
ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
}
@end verbatim
This class nicely demonstrates two techniques we exploit in
ns-3 to bind objects together: callbacks, and object aggregation.
Once IPv4 routing has determined that a packet is for the local node, it
forwards it up the stack. This is done with the following function:
@verbatim
void
Ipv4L3Protocol::LocalDeliver (Ptr<const Packet> packet, Ipv4Header const&ip, uint32_t iif)
@end verbatim
The first step is to find the right Ipv4L4Protocol object , based on IP protocol
number. For instance, TCP is registered in the demux as protocol number 6.
Finally, the @code{Receive()} function on the Ipv4L4Protocol (such as
@code{TcpL4Protocol::Receive} is called.
We have not yet introduced the class Ipv4Interface. Basically,
each NetDevice is paired with an IPv4 representation of such device.
In Linux, this @code{class Ipv4Interface} roughly corresponds to
the @code{struct in_device}; the main purpose is to provide
address-family specific information (addresses) about an interface.
@subsubsection Layer-4 protocols and sockets
We next describe how the transport protocols, sockets, and applications
tie together. In summary, each transport protocol implementation is
a socket factory. An application that needs a new socket
For instance, to create a UDP socket, an application would use a code
snippet such as the following:
@verbatim
Ptr<Udp> udpSocketFactory = GetNode ()->GetObject<Udp> ();
Ptr<Socket> m_socket = socketFactory->CreateSocket ();
m_socket->Bind (m_local_address);
...
@end verbatim
The above will query the node to get a pointer to its UDP socket
factory, will create one such socket, and will use the socket with
an API similar to the C-based sockets API, such as @code{Connect ()}
and @code{Send ()}. See the chapter on ns-3 sockets for more information.
We have described so far a socket factory (e.g. @code{class Udp}) and
a socket, which may be specialized (e.g., @code{class UdpSocket}).
There are a few more key objects that relate to the specialized
task of demultiplexing a packet to one or more receiving sockets.
The key object in this task is @code{class Ipv4EndPointDemux}.
This demultiplexer stores objects of @code{class Ipv4EndPoint}.
This class holds the addressing/port tuple (local port, local address,
destination port, destination address) associated with the socket,
and a receive callback. This receive callback has a receive
function registered by the socket. The @code{Lookup ()} function to
Ipv4EndPointDemux returns a list of Ipv4EndPoint objects (there may
be a list since more than one socket may match the packet). The
layer-4 protocol copies the packet to each Ipv4EndPoint and calls
its @code{ForwardUp ()} method, which then calls the @code{Receive ()}
function registered by the socket.
An issue that arises when working with the sockets API on real
systems is the need to manage the reading from a socket, using
some type of I/O (e.g., blocking, non-blocking, asynchronous, ...).
ns-3 implements an asynchronous model for socket I/O; the application
sets a callback to be notified of received data ready to be read, and the
callback is invoked by the transport protocol when data is available.
This callback is specified as follows:
@verbatim
void Socket::SetRecvCallback (Callback<void, Ptr<Socket>,
Ptr<Packet>, const Address&> receivedData);
@end verbatim
The data being received is conveyed in the Packet data buffer. An example
usage is in @code{class PacketSink}:
@verbatim
m_socket->SetRecvCallback (MakeCallback(&PacketSink::HandleRead, this));
@end verbatim
To summarize, internally, the UDP implementation is organized as follows:
@itemize @bullet
@item a @code{UdpImpl} class that implements the UDP socket factory
functionality
@item a @code{UdpL4Protocol} class that implements the protocol logic
that is socket-independent
@item a @code{UdpSocketImpl} class that implements socket-specific aspects
of UDP
@item a class called @code{Ipv4EndPoint} that stores the
addressing tuple (local port, local address, destination port, destination
address) associated with the socket, and a receive callback for the socket.
@end itemize
@subsection Ipv4-capable node interfaces
Many of the implementation details, or internal objects themselves,
of Ipv4-capable Node objects are not exposed at the simulator public
API. This allows for different implementations; for instance,
replacing the native ns-3 models with ported TCP/IP stack code.
The C++ public APIs of all of these objects is found in the
@code{src/node} directory, including principally:
@itemize @bullet
@item @code{socket.h}
@item @code{tcp.h}
@item @code{udp.h}
@item @code{ipv4.h}
@end itemize
These are typically base class objects that implement the default
values used in the implementation, implement access methods to get/set
state variables, host attributes, and implement publicly-available methods
exposed to clients such as @code{CreateSocket}.
@subsection Example path of a packet
These two figures show an example stack trace of how packets flow
through the Internet Node objects.
@float Figure,fig:internet-node-send
@caption{Send path of a packet.}
@image{figures/internet-node-send,5in}
@end float
@float Figure,fig:internet-node-recv
@caption{Receive path of a packet.}
@image{figures/internet-node-recv,5in}
@end float
The following chapters provide reference information on the available
NetDevices in ns-3.
+5 -3
View File
@@ -98,7 +98,7 @@ When the reference count falls to zero, the object is deleted.
@itemize @bullet
@item When the client code obtains a pointer from the object itself
through object creation, or via QueryInterface, it does not have
through object creation, or via GetObject, it does not have
to increment the reference count.
@item When client code obtains a pointer from another source (e.g.,
copying a pointer) it must call @code{Ref()} to increment the
@@ -154,7 +154,9 @@ using @code{CreateObject()} instead.
For objects deriving from @code{class RefCountBase}, or other
objects that support usage of the smart pointer class
(in particular, the ns-3 Packet class),
(in particular, the ns-3 Packet class does not derive from RefCountBase
in order to avoid a vtable, but separately implements @code{Ref ()} and
@code{Unref ()}),
a templated helper function is available and recommended to be used:
@verbatim
Ptr<B> b = Create<B> ();
@@ -241,7 +243,7 @@ now use the Ptr to the Ipv4 object that was previously aggregated to
the node.
Another example of how one might use aggregation is to add optional
models to objects. For in
models to objects.
For instance, an existing Node object may have an ``Energy Model''
object aggregated to it at run time (without modifying
and recompiling the node class). An existing model (such as a wireless
+55
View File
@@ -0,0 +1,55 @@
@node Organization
@chapter Organization
This manual is organized into several parts with several chapters per part.
This chapter describes the overall software organization and the
corresponding organization of this manual.
ns-3 is a discrete-event network simulator in which the simulation core
and models are implemented in C++. ns-3 is built as a library which
may be statically or dynamically linked to a C++ main program that
defines the simulation topology and starts the simulator. ns-3 also
exports nearly all of its API to Python, allowing Python programs to
import an "ns3" module in much the same way as in C++.
@float Figure,fig:organization
@caption{Software organization of ns-3}
@center @image{figures/software-organization, 5in}
@end float
The source code for ns-3 is mostly organized in the @code{src/}
directory and can be described by the diagram in @ref{fig:organization}.
We will work our way from the bottom up; in general, modules
only have dependencies on modules beneath them in the figure.
We first describe Part 1 of the manual.
The simulation core is implemented in @code{src/core}, and the core is
used to build the simulation engine @code{src/simulator}. Packets are
fundamental objects in a network simulator and are implemented in
@code{src/packet}. These three simulation modules by themselves
are intended to comprise a generic simulation core that can be used
by different kinds of networks, not just Internet-based networks.
The above modules of ns-3 are independent of specific network and
device models, which are covered in later parts of this manual.
In addition to the above ns-3 core, we describe also in Part 1 two
other modules that supplement the core C++-based API. ns-3 programs
may access all of the API directly or may make use of a so-called
``helper API'' that provides convenient wrappers or encapsulation of
low-level API calls. The fact that ns-3 programs can be written to
two APIs (or a combination thereof) is a fundamental aspect of the
simulator and is also covered in Part 1. We also describe how
Python is supported in ns-3 as the last chapter of Part 1.
The remainder of the manual is focused on documenting the models
and supporting capabilities. Part 2 focuses on two fundamental
objects in ns-3: the @code{Node} and @code{NetDevice}. Two
special NetDevice types are designed to support network emulation
use cases, and emulation is described in Part 3.
Part 4 is devoted to Internet-related models, including the sockets
API used by Internet applications. Part 5 covers applications, and
Part 6 describes additional support for simulation, such as animators.
The project maintains a separate manual devoted to testing and
validation of ns-3 code (see the
@uref{http://www.nsnam.org/tutorials.html,, ns-3 Testing and Validation manual}).
+21 -11
View File
@@ -99,7 +99,7 @@ things that you wouldn't find in the bits on the wire).
@float Figure,fig:packets
@caption{Implementation overview of Packet class.}
@image{figures/packet}
@image{figures/packet, 4in}
@end float
Figure @ref{fig:packets} is a high-level overview of the Packet
@@ -222,9 +222,11 @@ applied is:
Packet (uint8_t const *buffer, uint32_t size);
@end verbatim
Here is an example:
@verbatim
@smallformat
@example
Ptr<Packet> pkt1 = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello"), 5);
@end verbatim
@end example
@end smallformat
Packets are freed when there are no more references to them, as with
all ns-3 objects referenced by the Ptr class.
@@ -258,7 +260,8 @@ examples within the source code.
Once you have a header (or you have a preexisting header), the following
Packet API can be used to add or remove such headers.
@verbatim
@smallformat
@example
/**
* Add header to this packet. This method invokes the
* Header::GetSerializedSize and Header::Serialize
@@ -284,11 +287,13 @@ Packet API can be used to add or remove such headers.
* \returns the number of bytes read from the packet.
*/
uint32_t PeekHeader (Header &header) const;
@end verbatim
@end example
@end smallformat
For instance, here are the typical operations to add and remove a UDP header.
@verbatim
@smallformat
@example
// add header
Ptr<Packet> packet = Create<Packet> ();
UdpHeader udpHeader;
@@ -299,7 +304,8 @@ For instance, here are the typical operations to add and remove a UDP header.
UdpHeader udpHeader;
packet->RemoveHeader (udpHeader);
// Read udpHeader fields as needed
@end verbatim
@end example
@end smallformat
@subsection Adding and removing Tags
@@ -355,7 +361,8 @@ An example is the UdpEchoServer class, which takes the received packet
and "turns it around" to send back to the echo client.
The Packet API for byte tags is given below.
@verbatim
@smallformat
@example
/**
* \param tag the new tag to add to this packet
*
@@ -399,10 +406,12 @@ The Packet API for byte tags is given below.
* invoke the Print method of each tag stored in the packet.
*/
void PrintByteTags (std::ostream &os) const;
@end verbatim
@end example
@end smallformat
The Packet API for packet tags is given below.
@verbatim
@smallformat
@example
/**
* \param tag the tag to store in this packet
*
@@ -451,7 +460,8 @@ The Packet API for packet tags is given below.
* packet tags.
*/
PacketTagIterator GetPacketTagIterator (void) const;
@end verbatim
@end example
@end smallformat
Here is a simple example illustrating the use of tags from the
code in @code{src/internet-stack/udp-socket-impl.cc}:
+9
View File
@@ -0,0 +1,9 @@
@node Python
@chapter Python
@cartouche
Placeholder chapter
@end cartouche
For now, please see the Python wiki page at @*
@uref{http://www.nsnam.org/wiki/index.php/NS-3_Python_Bindings,,http://www.nsnam.org/wiki/index.php/NS-3_Python_Bindings}.
+28 -43
View File
@@ -35,7 +35,7 @@ default; this marks a change in policy starting with ns-3.4}
@end itemize
@item to obtain randomness across multiple simulation runs, you must either
set the seed differently or set the run number differently. To set a seed, call
@code{SeedManager::SetSeed(uint32_t)} at the beginning of the program;
@code{SeedManager::SetSeed (uint32_t)} at the beginning of the program;
to set a run number with the same seed, call
@code{SeedManager::SetRun (uint32_t)} at the beginning of the program;
@xref{Seeding and independent replications}
@@ -53,7 +53,7 @@ ns-3.
@node Background
@section Background
Simulations use a lot of random numbers; the study in [cite]
Simulations use a lot of random numbers; one study
found that most network simulations spend as much as 50%
of the CPU generating random numbers. Simulation users need
to be concerned with the quality of the (pseudo) random numbers and
@@ -62,7 +62,7 @@ the independence between different streams of random numbers.
Users need to be concerned with a few issues, such as:
@itemize @bullet
@item the seeding of the random number generator and whether a
simulation run is deterministic or not,
simulation outcome is deterministic or not,
@item how to acquire different streams of random numbers that are
independent from one another, and
@item how long it takes for streams to cycle
@@ -96,8 +96,7 @@ streams of random numbers, each of which consists of
2.3x10^15 substreams. Each substream has a period
(@emph{i.e.}, the number of random numbers before overlap) of
7.6x10^22. The period of the entire generator is
3.1x10^57. Figure ref-streams provides a graphical idea of
how the streams and substreams fit together.
3.1x10^57.
Class @code{ns3::RandomVariable} is the public interface to this
underlying random number generator. When users create new
@@ -167,7 +166,7 @@ from within the program; the user can set the
@end verbatim
Another way to control this is by passing a command-line argument; since
this is an ns3 GlobalValue instance, it is equivalently done such as follows:
this is an ns-3 GlobalValue instance, it is equivalently done such as follows:
@verbatim
./waf --command-template="%s --RngRun=3" --run program-name
@end verbatim
@@ -198,42 +197,25 @@ numbers before overlapping.
@section Base class public API
Below are excerpted a few public methods of @code{class RandomVariable}
that deal with the global configuration and state of the RNG.
@verbatim
that access the next value in the substream.
@smallformat
@example
/**
* \brief Set seeding behavior
*
* Specify whether the POSIX device /dev/random is to
* be used for seeding. When this is used, the underlying
* generator is seeded with data from /dev/random instead of
* being seeded based upon the time of day. Defaults to true.
* \brief Returns a random double from the underlying distribution
* \return A floating point random value
*/
static void UseDevRandom(bool udr = true);
/**
* \brief Use the global seed to force precisely reproducible results.
*/
static void UseGlobalSeed(uint32_t s0, uint32_t s1, uint32_t s2,
uint32_t s3, uint32_t s4, uint32_t s5);
double GetValue (void) const;
/**
* \brief Set the run number of this simulation
* \brief Returns a random integer integer from the underlying distribution
* \return Integer cast of ::GetValue()
*/
static void SetRunNumber(uint32_t n);
uint32_t GetInteger (void) const;
@end example
@end smallformat
/**
* \brief Get the internal state of the RNG
*
* This function is for power users who understand the inner workings
* of the underlying RngStream method used. It returns the internal
* state of the RNG via the input parameter.
* \param seed Output parameter; gets overwritten with the internal state
* of the RNG.
*/
void GetSeed(uint32_t seed[6]) const;
@end verbatim
We have already described the seeding configuration above.
We have already described the seeding configuration above. Different
RandomVariable subclasses may have additional API.
@node Types of RandomVariables
@section Types of RandomVariables
@@ -255,6 +237,9 @@ class RandomVariable.
@item @code{class DeterministicVariable }
@item @code{class LogNormalVariable }
@item @code{class TriangularVariable }
@item @code{class GammaVariable }
@item @code{class ErlangVariable }
@item @code{class ZipfVariable }
@end itemize
@node Semantics of RandomVariable objects
@@ -270,7 +255,8 @@ any heap-allocated RandomVariables.
RandomVariable objects can also be used in ns-3 attributes, which means
that values can be set for them through the ns-3 attribute system.
An example is in the propagation models for WifiNetDevice:
@verbatim
@smallformat
@example
TypeId
RandomPropagationDelayModel::GetTypeId (void)
{
@@ -285,7 +271,8 @@ RandomPropagationDelayModel::GetTypeId (void)
;
return tid;
}
@end verbatim
@end example
@end smallformat
Here, the ns-3 user can change the default random variable for this
delay model (which is a UniformVariable ranging from 0 to 1) through
the attribute system.
@@ -328,14 +315,12 @@ Let's review what things you should do when creating a simulation.
@itemize @bullet
@item Decide whether you are running with a fixed seed or random seed;
a random seed is the default,
a fixed seed is the default,
@item Decide how you are going to manage independent replications, if
applicable,
@item Convince yourself that you are not drawing more random values
than the cycle length, if you are running a long simulation, and
than the cycle length, if you are running a very long simulation, and
@item When you publish, follow the guidelines above about documenting your
use of the random number generator.
@end itemize
The program @emph{samples/main-random.cc} has some examples of usage.
+11 -4
View File
@@ -25,7 +25,7 @@ are described in @ref{Unicast routing}. Multicast routing is documented in
@image{figures/routing, 6in}
@end float
Figure 11-1 shows the overall routing architecture for Ipv4. The key objects
@ref{fig:routing} shows the overall routing architecture for Ipv4. The key objects
are Ipv4L3Protocol, Ipv4RoutingProtocol(s) (a class to which all
routing/forwarding has been delegated from Ipv4L3Protocol), and Ipv4Route(s).
@@ -143,7 +143,8 @@ and rebuilds the routes.
For instance, this scheduling call will cause the tables to be rebuilt
at time 5 seconds:
@verbatim
Simulator::Schedule (Seconds (5),&Ipv4GlobalRoutingHelper::RecomputeRoutingTables);
Simulator::Schedule (Seconds (5),
&Ipv4GlobalRoutingHelper::RecomputeRoutingTables);
@end verbatim
@subsection Global Routing Implementation
@@ -199,15 +200,21 @@ is finally used to populate the routes themselves.
@node Unicast routing
@section Unicast routing
There are presently four routing protocols defined:
There are presently five unicast routing protocols defined for IPv4 and
two for IPv6:
@itemize @bullet
@item class Ipv4StaticRouting (covering both unicast and multicast)
@item Optimized Link State Routing (a MANET protocol defined in
@item IPv4 Optimized Link State Routing (a MANET protocol defined in
@uref{http://www.ietf.org/rfc/rfc3626.txt,,RFC 3626})
@item class Ipv4ListRouting (used to store a prioritized list of routing
protocols)
@item class Ipv4GlobalRouting (used to store routes computed by the global
route manager, if that is used)
@item class Ipv4NixVectorRouting (a more efficient version of global routing
that stores source routes in a packet header field)
@item class Ipv6ListRouting (used to store a prioritized list of routing
protocols)
@item class Ipv6StaticRouting
@end itemize
In the future, this architecture should also allow someone to implement
+6
View File
@@ -0,0 +1,6 @@
@node Simple NetDevice
@chapter Simple NetDevice
@cartouche
Placeholder chapter
@end cartouche
+12 -55
View File
@@ -42,8 +42,8 @@ one of asynchronous I/O, which is not typically found in real systems
@item the API is not a complete sockets API, such as supporting
all socket options or all function variants;
@item many calls use @code{ns3::Packet} class to transfer data
between application and socket. This may seem a little funny to
people to pass ``Packets'' across a stream socket API, but think
between application and socket. This may seem peculiar to
pass ``Packets'' across a stream socket API, but think
of these packets as just fancy byte buffers at this level (more
on this also below).
@end itemize
@@ -58,7 +58,7 @@ on this also below).
@subsubsection Creating sockets
An application that wants to use sockets must first create one.
On real systems, this is accomplished by calling socket():
On real systems using a C-based API, this is accomplished by calling socket():
@verbatim
int
socket(int domain, int type, int protocol);
@@ -79,11 +79,13 @@ Examples of TypeIds to pass to this method are @code{TcpSocketFactory},
This method returns a smart pointer to a Socket object. Here is an
example:
@verbatim
@smallformat
@example
Ptr<Node> n0;
// Do some stuff to build up the Node's internet stack
Ptr<Socket> localSocket = Socket::CreateSocket (n0, TcpSocketFactory::GetTypeId ());
@end verbatim
@end example
@end smallformat
In some ns-3 code, sockets will not be explicitly created by user's
main programs, if an ns-3 application does it. For instance, for
@@ -149,7 +151,7 @@ There are two basic variants of @code{Send()} and @code{Recv()} supported:
int Recv (uint8_t* buf, uint32_t size);
@end verbatim
The non-Packet variants are left for legacy API reasons. When calling
The non-Packet variants are provided for legacy API reasons. When calling
the raw buffer variant of @code{Send()}, the buffer is immediately
written into a Packet and the @code{Send (Ptr<Packet> p)} is invoked.
@@ -160,7 +162,7 @@ the Packet variants are more likely to be preferred in ns-3:
@itemize @bullet
@item Users can use the Tags facility of packets to, for example, encode
a flow ID or other helper data.
a flow ID or other helper data at the application layer.
@item Users can exploit the copy-on-write implementation to avoid
memory copies (on the receive side, the conversion back to a
@code{uint8_t* buf} may sometimes incur an additional copy).
@@ -193,51 +195,6 @@ a real (zeroed) buffer on the spot, and the efficiency will be lost there.
@section POSIX-like sockets API
@emph{this capability is under development and is scheduled for
inclusion in the ns-3.5 releasetimeframe; see the repository
http://code.nsnam.org/mathieu/ns-3-simu for details}
The below is excerpted from Mathieu's post to ns-developers list
on April 4, 2008.
"To summarize, the goal is that the full posix/socket API is defined in
src/process/simu.h: each posix type and function is re-defined there
with a simu_ or SIMU_ prefix to avoid ugly name clashes and collisions
(feel free to come up with a better prefix).
Each process is created with a call to ProcessManager::Create and is
attached to that ProcessManager instance. So, if the ProcessManager
(which is aggregated to a Node in src/helper/process-helper.cc) is
killed when the simulation ends, the system will automatically reclaim
all the resources of each process associated to each manager. The same
happens when an application "exits" from its main function.
The example application defines two posix "processes": the function
ClientProgram creates a udp socket on the localhost port 2000 and the
function ServerProgram creates a udp socket on the localhost port 2000.
The code does not work right now because I did not get the details of
simu_read right yet but, I do plan to make this work at some point.
I really think that this approach is worthwhile for many reasons, a few
of which are outlined below:
@itemize @bullet
@item makes porting real world application code _much_ easier
@item makes write applications for new users much easier because they can
read the bsd socket api reference and documentation and write code
directly.
@item can be used to write applications which work in both simulation and
in the real world at the same time. To do this, all you have to do is
write your application to use the simu_ API, and, then, you can chose at
compile-time which implementation of that API you want to use: you can
pick one implementation which forwards all calls to the system BSD
socket API or another one which forwards all calls to the attached
ProcessManager. Arguably, I did not implement the version which forwards
to system BSD sockets but, that should be pretty trivial.
@end itemize
So, anyway, comments about the overall API would be welcome. Students
interested in the gsoc project for real-world code integration should
consider looking at this also."
@cartouche
Under development in the http://code.nsnam.org/mathieu/ns-3-simu repository.
@end cartouche
+7 -6
View File
@@ -1,9 +1,10 @@
@node Statistics
@chapter Statistics
@anchor{chap:Statistics}
ns-3 does not presently have support for statistics (automatically generated
statistical output). This is planned
for development later in 2008. If you are interested in contributing,
please see @uref{http://www.nsnam.org/wiki/index.php/Suggested_Projects,,our suggested projects page} or contact the ns-developers
list.
@cartouche
Placeholder chapter
@end cartouche
This wiki page: @*
@uref{http://www.nsnam.org/wiki/index.php/Statistical_Framework_for_Network_Simulation,,http://www.nsnam.org/wiki/index.php/Statistical_Framework_for_Network_Simulation}
contains information about the proposed statistical framework that is
located in @code{src/contrib} directory.
+11
View File
@@ -0,0 +1,11 @@
@node Tap NetDevice
@chapter Tap NetDevice
@cartouche
Placeholder chapter
@end cartouche
The Tap NetDevice can be used to allow a host system or virtual machines
to interact with a simulation. See @*
@code{examples/tap/tap-wifi-dumbbell.cc} for an example.
+23 -47
View File
@@ -105,10 +105,7 @@ 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.
@item Only IPv4 is supported (IPv6 support will start to be added after ns-3.6).
@end itemize
@section Network Simulation Cradle
@@ -132,43 +129,17 @@ 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.
Linux i386 and Linux x86-64. NSC does not support powerpc.
NSC requires the packages mercurial, flex, and bison.
Building NSC requires the packages flex and bison.
@subsection Configuring and Downloading
NSC is disabled by default and must be explicitly configured in. To try
this, type
Using the @code{build.py} script in ns-3-allinone directory, NSC will be
enabled by default unless the platform does not support it. To disable
it when building ns-3, 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
./waf configure --disable-nsc
@end verbatim
@subsection Building and validating
@@ -233,12 +204,18 @@ 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
@smallformat
@example
// 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 example
@end smallformat
These additional configuration variables are not available to native ns-3
TCP.
@@ -331,11 +308,10 @@ nsc-tcp-sockets of a node when its wakeup callback is invoked by nsc.
@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.
be fixed by ns-3.7.
@item Cygwin and OS X PPC are not supported
@item The non-Linux stacks of NSC are not supported in ns-3
@item Not all socket API callbacks are supported
@end itemize
For more information, see
+42 -27
View File
@@ -1,25 +1,25 @@
@node Tracing
@chapter Tracing
The tracing subsystem is one of the most important mechansisms to understand in
The tracing subsystem is one of the most important mechanisms to understand in
@command{ns-3}. In most cases, @command{ns-3} users will have a brilliant idea
for some new and improved networking feature. In order to verify that this
idea works, the researcher will make changes to an existing system and then run
experiments to see how the new feature behaves by gathering some form of statistic
that captures the behavior of the feature.
experiments to see how the new feature behaves by gathering statistics
that capture the behavior of the feature.
In other words, the whole point of running a simulation is to generate output for
further study. In @command{ns-3}, the subsystem that enables a researcher to do
this is the tracing subsystem.
@menu
* Motivation::
* Tracing Motivation::
* Overview::
* Using the Tracing API::
* Implementation details::
* Tracing implementation details::
@end menu
@node Motivation
@node Tracing Motivation
@section Motivation
There are many ways to get information out of a program. The most straightforward
@@ -37,7 +37,7 @@ way is to just directly print the information to the standard output, as in,
@end verbatim
This is workable in small environments, but as your simulations get more and more
compliated, you end up with more and more prints and the task of parsing and
complicated, you end up with more and more prints and the task of parsing and
performing computations on the output begins to get harder and harder.
Another thing to consider is that every time a new tidbit is needed, the software
@@ -74,7 +74,7 @@ Trace sources are entities that can signal events that happen in a simulation an
provide access to interesting underlying data. For example, a trace source could
indicate when a packet is received by a net device and provide access to the
packet contents for interested trace sinks. A trace source might also indicate
when an iteresting state change happens in a model. For example, the congestion
when an interesting state change happens in a model. For example, the congestion
window of a TCP model is a prime candidate for a trace source.
Trace sources are not useful by themselves; they must be connected to other pieces
@@ -92,7 +92,7 @@ or models of the simulator.
There can be zero or more consumers of trace events generated by a trace source.
One can think of a trace source as a kind of point-to-multipoint information link.
The ``transport protocol'' for this conceptual point-to-multipoint link as an
The ``transport protocol'' for this conceptual point-to-multipoint link is an
@code{ns-3} @code{Callback}.
Recall from the Callback Section that callback facility is a way to allow two
@@ -100,7 +100,8 @@ modules in the system to communicate via function calls while at the same time
decoupling the calling function from the called class completely. This is the
same requirement as outlined above for the tracing system.
Basically, a trace source @emph{is} a callback. When a trace sink expresses
Basically, a trace source @emph{is} a callback to which multiple
functions may be registered. When a trace sink expresses
interest in receiving trace events, it adds a callback to a list of callbacks
held by the trace source. When an interesting event happens, the trace source
invokes its @code{operator()} providing zero or more parameters. This tells
@@ -112,7 +113,8 @@ functions.
It will be useful to go walk a quick example just to reinforce what we've said.
@verbatim
@smallformat
@example
#include ``ns3/object.h''
#include ``ns3/uinteger.h''
#include ``ns3/traced-value.h''
@@ -121,7 +123,8 @@ It will be useful to go walk a quick example just to reinforce what we've said.
#include <iostream>
using namespace ns3;
@end verbatim
@end example
@end smallformat
The first thing to do is include the required files. As mentioned above, the
trace system makes heavy use of the Object and Attribute systems. The first
@@ -139,7 +142,8 @@ operator--, operator+, operator==, etc.
What this all means is that you will be able to trace changes to an object
made using those operators.
@verbatim
@smallformat
@example
class MyObject : public Object
{
public:
@@ -158,7 +162,8 @@ made using those operators.
MyObject () {}
TracedValue<uint32_t> m_myInt;
};
@end verbatim
@end example
@end smallformat
Since the tracing system is integrated with Attributes, and Attributes work
with Objects, there must be an @command{ns-3} @code{Object} for the trace source
@@ -170,29 +175,33 @@ source to the outside world. The @code{TracedValue} declaration provides the
infrastructure that overloads the operators mentioned above and drives the callback
process.
@verbatim
@smallformat
@example
void
IntTrace (Int oldValue, Int newValue)
{
std::cout << ``Traced `` << oldValue << `` to `` << newValue << std::endl;
}
@end verbatim
@end example
@end smallformat
This is the definition of the trace sink. It corresponds directly to a callback
function. This function will be called whenever one of the operators of the
@code{TracedValue} is executed.
@verbatim
@smallformat
@example
int
main (int argc, char *argv[])
{
Ptr<MyObject> myObject = CreateObject<MyObject> ();
myObject->TraceConnectWithoutContext ("MyInt", MakeCallback(&IntTrace));
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));
myObject->m_myInt = 1234;
}
@end verbatim
@end example
@end smallformat
In this snippet, the first thing that needs to be done is to create the object
in which the trace source lives.
@@ -238,7 +247,8 @@ called a @emph{config path}.
For example, one might find something that looks like the following in the system
(taken from @code{examples/tcp-large-transfer.cc})
@verbatim
@smallformat
@example
void CwndTracer (uint32_t oldval, uint32_t newval) {}
...
@@ -246,7 +256,8 @@ For example, one might find something that looks like the following in the syste
Config::ConnectWithoutContext (
"/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
MakeCallback (&CwndTracer));
@end verbatim
@end example
@end smallformat
This should look very familiar. It is the same thing as the previous example,
except that a static member function of class @code{Config} is being called instead
@@ -258,13 +269,15 @@ must be an @code{Attribute} of an @code{Object}. In fact, if you had a pointer
the @code{Object} that has the ``CongestionWindow'' @code{Attribute} handy (call it
@code{theObject}), you could write this just like the previous example:
@verbatim
@smallformat
@example
void CwndTracer (uint32_t oldval, uint32_t newval) {}
...
theObject->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
@end verbatim
@end example
@end smallformat
It turns out that the code for @code{Config::ConnectWithoutContext} does exactly that.
This function takes a path that represents a chain of @code{Object} pointers and follows
@@ -297,16 +310,18 @@ This socket, the type of which turns out to be an @code{ns3::TcpSocketImpl} defi
an attribute called ``CongestionWindow'' which is a @code{TracedValue<uint32_t>}.
The @code{Config::ConnectWithoutContext} now does a,
@verbatim
@smallformat
@example
object->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
@end verbatim
@end example
@end smallformat
using the object pointer from ``SocketList/0'' which makes the connection between
the trace source defined in the socket to the callback -- @code{CwndTracer}.
Now, whenever a change is made to the @code{TracedValue<uint32_t>} representing the
congestion window in the TCP socket, the registered callback will be executed and
the function @code{Cwndtracer} will be called printing out the old and new values
the function @code{CwndTracer} will be called printing out the old and new values
of the TCP congestion window.
@node Using the Tracing API
@@ -324,5 +339,5 @@ core of the simulator;
sinks.
@end itemize
@node Implementation details
@node Tracing implementation details
@section Implementation details
+21 -10
View File
@@ -9,7 +9,9 @@ or running ns-3 programs.
* Run-time errors::
@end menu
Please note that the wiki (@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting}) may have contributed items.
Please note that the wiki @*
(@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting})
may have contributed items.
@node Build errors
@section Build errors
@@ -23,18 +25,21 @@ pointer values are unexpectedly null.
Here is an example of what might occur:
@verbatim
@smallformat
@example
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point
Entering directory `/home/tomh/ns-3-nsc/build'
Compilation finished successfully
Command ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] exited with code -11
@end verbatim
@end example
@end smallformat
The error message says that the program terminated unsuccessfully, but it is
not clear from this information what might be wrong. To examine more
closely, try running it under the @uref{http://sources.redhat.com/gdb/,,gdb debugger}:
@verbatim
@smallformat
@example
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="gdb %s"
Entering directory `/home/tomh/ns-3-nsc/build'
Compilation finished successfully
@@ -44,7 +49,8 @@ GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db
library "/lib/libthread_db.so.1".
(gdb) run
Starting program: /home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point
@@ -61,7 +67,8 @@ $1 = {m_ptr = 0x3c5d65}
$2 = {m_ptr = 0x0}
(gdb) quit
The program is running. Exit anyway? (y or n) y
@end verbatim
@end example
@end smallformat
Note first the way the program was invoked-- pass the command to run as
an argument to the command template "gdb %s".
@@ -70,11 +77,13 @@ This tells us that there was an attempt to dereference a null pointer
socketFactory.
Let's look around line 136 of tcp-point-to-point, as gdb suggests:
@verbatim
@smallformat
@example
Ptr<SocketFactory> socketFactory = n2->GetObject<SocketFactory> (Tcp::iid);
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
localSocket->Bind ();
@end verbatim
@end example
@end smallformat
The culprit here is that the return value of GetObject is not being
checked and may be null.
@@ -82,6 +91,8 @@ checked and may be null.
Sometimes you may need to use the @uref{http://valgrind.org,,valgrind memory
checker} for more subtle errors. Again, you invoke the use of valgrind
similarly:
@verbatim
@smallformat
@example
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="valgrind %s"
@end verbatim
@end example
@end smallformat
+40 -23
View File
@@ -28,9 +28,8 @@ ns-3 provides models for these aspects of 802.11:
@item QoS-based EDCA and queueing extensions of @strong{802.11e}
@item various propagation loss models including @strong{Nakagami, Rayleigh, Friis, LogDistance, FixedRss, Random}
@item two propagation delay models, a distance-based and random model
@item various rate control algorithms including @strong{Aarf, Arf, Cara, Onoe, Rraa, and ConstantRate}
@item @emph{(under development)} 802.11s (mesh)
@item @emph{(under development)} Minstrel rate control
@item various rate control algorithms including @strong{Aarf, Arf, Cara, Onoe, Rraa, ConstantRate, and Minstrel}
@item 802.11s (mesh), described in another chapter
@end itemize
The set of 802.11 models provided in ns-3 attempts to provide
@@ -159,10 +158,12 @@ and a propagation loss based on a log distance model with a reference
loss of 46.6777 dB at reference distance of 1m.
Users will typically type code such as:
@verbatim
@smallformat
@example
YansWifiChannelHelper wifiChannelHelper = YansWifiChannelHelper::Default ();
Ptr<WifiChannel> wifiChannel = wifiChannelHelper.Create ();
@end verbatim
@end example
@end smallformat
to get the defaults. Note the distinction above in creating a helper
object vs. an actual simulation object.
In ns-3, helper objects (used at the helper API only) are created on the
@@ -203,35 +204,45 @@ configure MAC parameters like type of MAC, values of contention windows and so o
Setting up a non-QoS MAC layers the object we use is @code{ns3::NqosWifiMacHelper}.
For example the following user code configures a non-QoS MAC sta and changes its default
values for contention window and Aifsn:
@verbatim
@smallformat
@example
NqosWifiMacHelper wifiMacHelper = NqosWifiMacHelper::Default ();
Ssid ssid = Ssid ("ns-3-ssid");
wifiMacHelper.SetType ("ns3::NqstaWifiMac", "Ssid", SsidValue (ssid), "ActiveProbing", BooleanValue (false));
wifiMacHelper.SetDcaParameters ("MinCw", UintegerValue (20), "Aifsn", UintegerValue (3));
@end verbatim
wifiMacHelper.SetType ("ns3::NqstaWifiMac", "Ssid", SsidValue (ssid),
"ActiveProbing", BooleanValue (false));
wifiMacHelper.SetDcaParameters ("MinCw", UintegerValue (20), "Aifsn",
UintegerValue (3));
@end example
@end smallformat
Setting up a QoS MACs we use a @code{ns3::QosWifiMacHelper} instead.
This object could be also used to change default EDCA parameters, and to set a possible MSDU aggregator
for a particular access class in order to use 802.11n MSDU aggregation feature.
A possible user code:
@verbatim
@smallformat
@example
QosWifiMacHelper wifiMacHelper = QosWifiMacHelper::Default ();
wifiMacHelper.SetType ("ns3::QapWifiMac", "Ssid", SsidValue (ssid), "BeaconGeneration", BooleanValue (true),
wifiMacHelper.SetType ("ns3::QapWifiMac", "Ssid", SsidValue (ssid),
"BeaconGeneration", BooleanValue (true),
"BeaconInterval", TimeValue (Seconds (2.5)));
wifiMacHelper.SetEdcaParametersForAc (AC_VO, "MinCw", UintegerValue (2));
wifiMacHelper.SetMsduAggregatorForAc (AC_VO, "ns3::MsduStandardAggregator", "MaxAmsduSize", UintegerValue (3839));
@end verbatim
wifiMacHelper.SetMsduAggregatorForAc (AC_VO, "ns3::MsduStandardAggregator",
"MaxAmsduSize", UintegerValue (3839));
@end example
@end smallformat
Call to QosWifiMacHelper::Default () is needed in order to set default EDCA parameters properly for all
access classes. Otherwise we should set them one by one:
@verbatim
@smallformat
@example
QosWifiMacHelper wifiMacHelper;
wifiMacHelper.SetEdcaParametersForAc (AC_VO, "MinCw", UintegerValue (2), "MaxCw", UintegerValue (7),
"Aifsn", UintegerValue (2));
wifiMacHelper.SetEdcaParametersForAc (AC_VI, "MinCw", UintegerValue (7), "MaxCw", UintegerValue (15),
"Aifsn", UintegerValue (2));
wifiMacHelper.SetEdcaParametersForAc (AC_VO, "MinCw", UintegerValue (2),
"MaxCw", UintegerValue (7), "Aifsn", UintegerValue (2));
wifiMacHelper.SetEdcaParametersForAc (AC_VI, "MinCw", UintegerValue (7),
"MaxCw", UintegerValue (15), "Aifsn", UintegerValue (2));
...
@end verbatim
@end example
@end smallformat
@subsection WifiHelper
@@ -244,9 +255,11 @@ What does this do? It sets the RemoteStationManager to
@code{ns3::ArfWifiManager}.
Now, let's use the wifiPhyHelper and wifiMacHelper created above to install WifiNetDevices
on a set of nodes in a NodeContainer "c":
@verbatim
@smallformat
@example
NetDeviceContainer wifiContainer = WifiHelper::Install (wifiPhyHelper, wifiMacHelper, c);
@end verbatim
@end example
@end smallformat
This creates the WifiNetDevice which includes also a WifiRemoteStationManager,
a WifiMac, and a WifiPhy (connected to the matching WifiChannel).
@@ -257,12 +270,16 @@ show how to do some of this reconfiguration.
@subsection AdHoc WifiNetDevice configuration
This is a typical example of how a user might configure an adhoc network.
@emph{Write me}
@cartouche
To be completed
@end cartouche
@subsection Infrastructure (Access Point and clients) WifiNetDevice configuration
This is a typical example of how a user might configure an access point and a set of clients.
@emph{Write me}
@cartouche
To be completed
@end cartouche
@node The WifiChannel and WifiPhy models
@section The WifiChannel and WifiPhy models
+29 -22
View File
@@ -1,10 +1,11 @@
Steps in doing an ns-3 release
1. check out a clean ns-3-dev somewhere
1. check out a clean ns-3-dev somewhere using ns-3-allinone (you will need it)
- hg clone http://code.nsnam.org/ns-3-allinone
- ./download.py
- ./build.py
- confirm that the release builds cleanly.
- cd ns-3-dev
- ensure that tests pass (./test.py)
- ensure no regressions (./waf --regression)
2. prepare the source files
@@ -13,19 +14,23 @@ Steps in doing an ns-3 release
- DO NOT change VERSION at this time
- confirm that Doxygen builds cleanly and without warnings
(./waf doxygen), and check in any necessary changes
3. ./waf configure; ./waf dist
- this will create an ns-3-dev.tar.bz2 tarball
- this will also create a ns-3-dev-ref-traces.tar.bz2 tarball
4. test dev tarball on release platforms (waf --check and maybe some other
scripts)
3. build an ns-3-allinone distribution
- change back into the allinone directory
- ./dist.py
- this will create an ns-allinone-dev.tar.bz2 tarball
4. test dev tarball on release platforms
- ./test.py
- ./waf --regression
- other scripts you can think of
5. once you are happy with the tarball, tag ns-3-dev and ns-3-dev-ref-traces
- cd into ns-3-dev
- hg tag "ns-3.x"
- hg push
- cd into regression/ns-3-dev-ref-traces
- cd into ns-3-dev-ref-traces
- hg tag "ns-3.x"
- hg push
6. clone the tagged ns-3-dev and place it on the repository
- ssh code.nsnam.org; sudo tcsh; su code;
- ssh code.nsnam.org; sudo bash; su code;
- cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.1x
- cd /home/code/repos/ns-3.x/.hg and edit the hgrc appropriately:
"description = ns-3.x release
@@ -33,20 +38,21 @@ Steps in doing an ns-3 release
- clone the ns-3-dev-ref-traces and place it on the repository as above
but use the name ns-3.x-ref-traces and edit the hgrc appropriately
7. check out a clean version of the new release (ns-3.x) somewhere
- hg clone http://code.nsnam.org/ns-3.x
8. Update the VERSION for this new release
- change the string 3-dev in the VERSION file to the real version
(e.g. 3.7 or 3.7-RC1) This must agree with the version name you chose in the clone
for the regression tests to work.
- hg commit
- hg push
- hg commit -m "update VERSION to ns-3.x"
- hg push ssh://code@code.nsnam.org//home/code/repos/ns-3.x
9. Run the tests on the new release (debug and optimized) like a user would
You need to use ns-3-allinone since you will use that to make the distro
- hg clone http://code.nsnam.org/ns-3-allinone-ns-3.x
- hg clone http://code.nsnam.org/ns-3-allinone ns-3-allinone-3.x
- cd !$
- ./download.py -n ns-3.x -r ns-3.x-ref-traces
- ./build.py
- cd ns-3.x
- ./waf -d debug configure
- ./waf
- ./test.py
- ./test.py -g
- ./waf --regression
@@ -59,9 +65,8 @@ Steps in doing an ns-3 release
- ./waf --valgrind --regression (for valgrind version)
- There should be no regression errors at this time
10. Create final tarballs
- cd ..
- cd into ns-3-allinone level
- ./dist.py
- ./waf configure; ./waf dist
- this will create an ns-allinone-3.x.tar.bz2 tarball
11. upload "ns-allinone-3.x.tar.bz2" to the /var/www/html/releases/ directory on
the www.nsnam.org server
@@ -74,23 +79,25 @@ Steps in doing an ns-3 release
- sudo chmod 644 ns-allinone-3.x.tar.bz2
13. update web pages on www.nsnam.org (source is in the www/ module)
- clone the source repo (hg clone http://code.nsnam.org/www)
- update index.html
- add link to news.html
- update getting_started.html
- update documents.html
- update references to releases in html_src
(consider "grep 'ns-3\.' *.html" for a new release)
(consider "grep 'RCx' *.html" for a new RC)
- update references to releases in scripts/
- update roadmap on wiki
- commit and push changes
14. update the server
- build and update HTML directory on the server
-- ssh www.nsnam.org; sudo tcsh; su nsnam;
-- ssh www.nsnam.org; sudo bash; su nsnam;
-- run ~/bin/update-html
- build and update Doxygen directory on the server
-- edit ~/bin/update-doxygen-release file and change RELEASE variable
to the right version number
-- run ~/bin/update-doxygen-release
14. Final checks
15. Final checks
- download tarball from web, build and run regression tests for as many
targets as you can
- download release from mercurial, build and run regression tests for as
many targets as you can
- test and verify until you're confident the release is solid.
15. announce to ns-developers, with summary of release notes
16. announce to ns-developers, with summary of release notes
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

+805 -6
View File
@@ -1,4 +1,3 @@
@c ============================================================================
@c Begin document body here
@c ============================================================================
@@ -17,6 +16,7 @@
@menu
* Background::
* Overview::
@end menu
@c ============================================================================
@@ -1096,10 +1096,809 @@ Callbacks, feel free to take a look at the @code{ns-3} manual. They are one
of the most frequently used constructs in the low-level parts of @code{ns-3}.
It is, in my opinion, a quite elegant thing.
@subsection What About TracedValue?
Earlier in this section, we presented a simple piece of code that used a
@code{TracedValue<int32_t>} to demonstrate the basics of the tracing code.
We just glossed over the way to find the return type and formal arguments
for the @code{TracedValue}. Rather than go through the whole exercise, we
will just point you at the correct file, @code{src/core/traced-value.h} and
to the important piece of code:
@verbatim
template <typename T>
class TracedValue
{
public:
...
void Set (const T &v) {
if (m_v != v)
{
m_cb (m_v, v);
m_v = v;
}
}
...
private:
T m_v;
TracedCallback<T,T> m_cb;
};
@end verbatim
Here you see that the @code{TracedValue} is templated, of course. In the simple
example case at the start of the section, the typename is int32_t. This means
that the member variable being traced (@code>m_v} in the private section of the
class) will be an @code{int32_t m_v}. The @code{Set} method will take a
@code{const uint32_t &v} as a parameter. You should now be able to understand
that the @code{Set} code will fire the @code{m_cb} callback with two parameters:
the first being the current value of the @code{TracedValue}; and the second
being the new value being set.
The callback, @code{m_cb} is declared as a @code{TracedCallback<T, T>} which
will correspond to a @code{TracedCallback<int32_t, int32_t>} when the class is
instantiated.
Recall that the callback target of a TracedCallback always returns @code{void}.
Further recall that there is a one-to-one correspondence between the template
parameter list in the declaration and the formal arguments of the callback
function. Therefore the callback will need to have a function signature that
looks like:
@verbatim
void
MyCallback (uint32_t oldValue, uint32_t newValue)
{
...
}
@end verbatim
It probably won't surprise you that this is exactly what we provided in that
simple example we covered so long ago:
@verbatim
void
IntTrace (int32_t oldValue, int32_t newValue)
{
std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
}
@end verbatim
@c ============================================================================
@c A Real Example
@c ============================================================================
@node A Real Example
@section A Real Example
Let's do an example taken from one of the best-known books on TCP around.
``TCP/IP Illustrated, Volume 1: The Protocols,'' by W. Richard Stevens is a
classic. I just flipped the book open and ran across a nice plot of both the
congestion window and sequence numbers versus time on page 366. Stevens calls
this, ``Figure 21.10. Value of cwnd and send sequence number while data is being
transmitted.'' Let's just recreate the cwnd part of that plot in @command{ns-3}
using the tracing system and @code{gnuplot}.
@subsection Are There Trace Sources Available?
The first thing to think about is how we want to get the data out. What is it
that we need to trace? The first thing to do is to consult ``The list of all
trace sources'' to see what we have to work with. Recall that this is found
in the @command{ns-3} Doxygen in the ``Core'' Module section. If you scroll
through the list, you will eventually find:
@verbatim
ns3::TcpSocketImpl
CongestionWindow: The TCP connection's congestion window
@end verbatim
It turns out that the @command{ns-3} TCP implementation lives (mostly) in the
file @code{src/internet-stack/tcp-socket-impl.cc}. If you don't know this a
priori, you can use the recursive grep trick:
@verbatim
find . -name '*.cc' | xargs grep -i tcp
@end verbatim
You will find page after page of instances of tcp pointing you to that file.
If you open @code{src/internet-stack/tcp-socket-impl.cc} in your favorite
editor, you will see right up at the top of the file, the following declarations:
@verbatim
TypeId
TcpSocketImpl::GetTypeId ()
{
static TypeId tid = TypeId(``ns3::TcpSocketImpl'')
.SetParent<TcpSocket> ()
.AddTraceSource (``CongestionWindow'',
``The TCP connection's congestion window'',
MakeTraceSourceAccessor (&TcpSocketImpl::m_cWnd))
;
return tid;
}
@end verbatim
This should tell you to look for the declaration of @code{m_cWnd} in the header
file @code{src/internet-stack/tcp-socket-impl.h}. If you open this file in your
favorite editor, you will find:
@verbatim
TracedValue<uint32_t> m_cWnd; //Congestion window
@end verbatim
You should now understand this code completely. If we have a pointer to the
@code{TcpSocketImpl}, we can @code{TraceConnect} to the ``CongestionWindow'' trace
source if we provide an appropriate callback target. This is the same kind of
trace source that we saw in the simple example at the start of this section,
except that we are talking about @code{uint32_t} instead of @code{int32_t}.
We now know that we need to provide a callback that returns void and takes
two @code{uint32_t} parameters, the first being the old value and the second
being the new value:
@verbatim
void
CwndTrace (uint32_t oldValue, uint32_t newValue)
{
...
}
@end verbatim
@subsection What Script to Use?
It's always best to try and find working code laying around that you can
modify, rather than starting from scratch. So the fist order of business now
is to find some code that already hooks the ``CongestionWindow'' trace source
and see if we can modify it. As usual, grep is your friend:
@verbatim
find . -name '*.cc' | xargs grep CongestionWindow
@end verbatim
This will point out a couple of promising candidates:
@code{examples/tcp/tcp-large-transfer.cc} and
@code{src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc}.
We haven't visited any of the test code yet, so let's take a look there. You
will typically find that test code is fairly minimal, so this is probably a
very good bet. Open @code{src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc} in your
favorite editor and search for ``CongestionWindow.'' You will find,
@verbatim
ns3TcpSocket->TraceConnectWithoutContext (``CongestionWindow'',
MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, this));
@end verbatim
This should look very familiar to you. We mentioned above that if we had a
pointer to the @code{TcpSocketImpl}, we could @code{TraceConnect} to the
``CongestionWindow'' trace source. That's exactly what we have here; so it
turns out that this line of code does exactly what we want. Let's go ahead
and extract the code we need from this function
(@code{Ns3TcpCwndTestCase1::DoRun (void)}). If you look at this function,
you will find that it looks just like an @code{ns-3} script. It turns out that
is exactly what it is. It is a script run by the test framework, so we can just
pull it out and wrap it in @code{main} instead of in @code{DoRun}. Rather than
walk through this step, by step, we have provided the file that results from
porting this test back to a native @code{ns-3} script --
@code{examples/tutorial/fifth.cc}.
@subsection A Common Problem and Solution
The @code{fifth.cc} example demonstrates an extremely important rule that you
must understand before using any kind of @code{Attribute}: you must ensure
that the target of a @code{Config} command exists before trying to use it.
This is no different than saying an object must be instantiated before trying
to call it, Although this may seem obvious when stated this way, it does
trip up many people trying to use the system for the first time.
Let's return to basics for a moment. There are three basic time periods that
exist in any @command{ns-3} script. The first time period is sometimes called
``Configuration Time'' or ``Setup Time,'' and is in force during the period
when the @code{main} function of your script is running, but before
@code{Simulator::Run} is called. The second time period is sometimes called
``Simulation Time'' and is in force during the time period when
@code{Simulator::Run} is actively executing its events. After it completes
executing the simulation, @code{Simulator::Run} will return control back to
the @code{main} function. When this happens, the script enters what can be
called ``Teardown Time,'' which is when the structures and objects created
during setup and taken apart and released,
Perhaps the most common mistake made in trying to use the tracing system is
assuming that entities constructed dynamically during simulation time are
available during configuration time. In particular, an @command{ns-3}
@code{Socket} is a dynamic object often created by @code{Applications} to
communicate between @code{Nodes}. An @command{ns-3} @code{Application}
always has a ``Start Time'' and a ``Stop Time'' associated with it. In the
vast majority of cases, an @code{Application} will not attempt to create
a dynamic object until its @code{StartApplication} method is called. This
is to ensure that the simulation is completely configured before the app
tries to do anything (what would happen if it tried to connect to a node
that didn't exist yet during configuration time). The answer to this
issue is to 1) create a simulator event that is run after the dynamic object
is created and hook the trace when that event is executedl or 2) create the
dynamic object at configuration time, hook it then, and give the object to
the system to use during simulation time. We took the second approach in
the @code{fifth.cc} example. This decision required us to create the
@code{MyApp} @code{Application}, the entire purpose of which is to
take a @code{Socket} as a parameter.
@subsection A fifth.cc Walkthrough
Now, let's take a look at the example program we constructed by disecting
the congestion window test. Open @code{examples/tutorial/fifth.cc} in your
favorite editor. You should see some familiar looking code:
@verbatim
/* -*- 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, Include., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <fstream>
#include "ns3/core-module.h"
#include "ns3/common-module.h"
#include "ns3/simulator-module.h"
#include "ns3/node-module.h"
#include "ns3/helper-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
@end verbatim
This has all been covered, so we won't rehash it. The next lines of source are
the network illustration and a comment addressing the problem described above
with @code{Socket}.
@verbatim
// ===========================================================================
//
// node 0 node 1
// +----------------+ +----------------+
// | ns-3 TCP | | ns-3 TCP |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ +----------------+
// | point-to-point | | point-to-point |
// +----------------+ +----------------+
// | |
// +---------------------+
// 5 Mbps, 2 ms
//
//
// We want to look at changes in the ns-3 TCP congestion window. We need
// to crank up a flow and hook the CongestionWindow attribute on the socket
// of the sender. Normally one would use an on-off application to generate a
// flow, but this has a couple of problems. First, the socket of the on-off
// application is not created until Application Start time, so we wouldn't be
// able to hook the socket (now) at configuration time. Second, even if we
// could arrange a call after start time, the socket is not public so we
// couldn't get at it.
//
// So, we can cook up a simple version of the on-off application that does what
// we want. On the plus side we don't need all of the complexity of the on-off
// application. On the minus side, we don't have a helper, so we have to get
// a little more involved in the details, but this is trivial.
//
// 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 source node.
// ===========================================================================
//
@end verbatim
This should also be self-explanatory.
The next part is the declaration of the @code{MyApp} @code{Application} that
we put together to allow the @code{Socket} to be created at configuration time.
@verbatim
class MyApp : public Application
{
public:
MyApp ();
virtual ~MyApp();
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;
};
@end verbatim
You can see that this class inherits from the @command{ns-3} @code{Application}
class. Take a look at @code{src/node/application.h} if you are interested in
what is inherited. The @code{MyApp} class is obligated to override the
@code{StartApplication} and @code{StopApplication} methods. These methods are
called when the corresponding base class @code{Start} and @code{Stop} methods are
called during simulation time.
@subsubsection How Applications are Started and Stopped
It is worthwhile to spend a bit of time explaining how events actually get
started in the system. The most common way to start pumping events is to start
an @code{Application}. This is done as the result of the following (hopefully)
familar lines of an @command{ns-3} script:
@verbatim
ApplicationContainer apps = ...
apps.Start (Seconds (1.0));
apps.Stop (Seconds (10.0));
@end verbatim
The application container code (see @code{src/helper/application-container.h} if
you are interested) loops through its contained applications and calls,
@verbatim
app->Start (startTime);
app->Stop (stopTime);
@end verbatim
on each of them. The @code{Start} method of an @code{Application} calls
@code{Application::ScheduleStart} (see @code{src/helper/application-container.cc})
which, in turn, schedules an event to start the @code{Application}:
@verbatim
Simulator::Schedule (startTime, &Application::StartApplication, this);
@end verbatim
Since @code{MyApp} inherits from @code{Application} and overrides
@code{StartApplication}, this bit of code causes the simulator to execute
something that is effectively like,
@verbatim
this->StartApplication (startTime);
@end verbatim
where the @code{this} pointer, if you have kept it all straight, is the pointer
to the @code{Application} in the container. It is then expected that another
event will be scheduled in the overridden @code{StartApplication} that will
begin doing some application-specific function, like sending packets.
@code{StopApplication} operates in a similar manner and tells the @code{Application}
to stop generating events.
@subsubsection The MyApp Application
The @code{MyApp} @code{Application} needs a constructor and a destructor,
of course:
@verbatim
MyApp::MyApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPackets (0),
m_dataRate (0),
m_sendEvent (),
m_running (false),
m_packetsSent (0)
{
}
MyApp::~MyApp()
{
m_socket = 0;
}
@end verbatim
The existence of the next bit of code is the whole reason why we wrote this
@code{Application} in the first place.
@verbatim
void
MyApp::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;
}
@end verbatim
This code should be pretty self-explanatory. We are just initializing member
variables. The important one from the perspective of tracing is the
@code{Ptr<Socket> socket} which we needed to provide to the application
during configuration time. Recall that we are going to create the @code{Socket}
as a @code{TcpSocket} (which is implemented by @code{TcpSocketImpl}) and hook
its ``CongestionWindow'' trace source before passing it to the @code{Setup}
method.
@verbatim
void
MyApp::StartApplication (void)
{
m_running = true;
m_packetsSent = 0;
m_socket->Bind ();
m_socket->Connect (m_peer);
SendPacket ();
}
@end verbatim
The above code is the overridden implementation @code{Application::StartApplication}
that will be automatically called by the simulator to start our @code{Application}
running. You can see that it does a @code{Socket} @code{Bind} operation. If
you are familiar with Berkeley Sockets this shouldn't be a surprise. It performs
the required work on the local side of the connection just as you might expect.
The following @code{Connect} will do what is required to establish a connection
with the TCP at @code{Address} m_peer. It should now be clear why we need to defer
a lot of this to simulation time, since the @code{Connect} is going to need a fully
functioning network to comlete. After the @code{Connect}, the @code{Application}
then starts creating simulation events by calling @code{SendPacket}.
The next bit of code explains to the @code{Application} how to stop creating
simulation events.
@verbatim
void
MyApp::StopApplication (void)
{
m_running = false;
if (m_sendEvent.IsRunning ())
{
Simulator::Cancel (m_sendEvent);
}
if (m_socket)
{
m_socket->Close ();
}
}
@end verbatim
Every time a simulation event is scheduled, an @code{Event} is created. If the
@code{Event} is pending execution or executing, its method @code{IsRunning} will
return @code{true}. In this code, if @code{IsRunning()} returns true, we
@code{Cancel} the event which removes it from the simulator event queue. By
doing this, we break the chain of events that the @code{Application} is using to
keep sending its @code{Packets} and the @code{Application} goes quiet. After we
quiet the @code{Application} we @code{Close} the socket which tears down the TCP
connection.
The socket is actually deleted in the destructor when the @code{m_socket = 0} is
executed. This removes the last reference to the underlying Ptr<Socket> which
causes the destructor of that Object to be called.
Recall that @code{StartApplication} called @code{SendPacket} to start the
chain of events that describes the @code{Application} behavior.
@verbatim
void
MyApp::SendPacket (void)
{
Ptr<Packet> packet = Create<Packet> (m_packetSize);
m_socket->Send (packet);
if (++m_packetsSent < m_nPackets)
{
ScheduleTx ();
}
}
@end verbatim
Here, you see that @code{SendPacket} does just that. It creates a @code{Packet}
and then does a @code{Send} which, if you know Berkeley Sockets, is probably
just what you expected to see.
It is the responsibility of the @code{Application} to keep scheduling the
chain of events, so the next lines call @code{ScheduleTx} to schedule another
transmit event (a @code{SendPacket}) until the @code{Application} decides it
has sent enough.
@verbatim
void
MyApp::ScheduleTx (void)
{
if (m_running)
{
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}
@end verbatim
Here, you see that @code{ScheduleTx} does exactly that. If the @code{Applciation}
is running (if @code{StopApplication}) has not been called) it will schedule a
new event, which calls @code{SendPacket} again. The alert reader will spot
something that also trips up new users. The data rate of an @code{Application} is
just that. It has nothing to do with the data rate of an underlying @code{Channel}.
This is the rate at which the @code{Application} produces bits. It does not take
into account any overhead for the various protocols or channels that it uses to
transport the data. If you set the data rate of an @code{Application} to the same
data rate as your underlying @code{Channel} you will eventually get a buffer overflow.
@subsubsection The Trace Sinks
The whole point of this exercise is to get trace callbacks from TCP indicating the
congestion window has been updated. The next piece of code implements the
corresponding trace sink:
@verbatim
static void
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << ``\t'' << newCwnd);
}
@end verbatim
This should be very familiar to you now, so we won't dwell on the details. This
function just logs the current simulation time and the new value of the
congestion window every time it is changed. You can probably imagine that you
could load the resulting output into a graphics program (gnuplot or Excel) and
immediately see a nice graph of the congestion window behavior over time.
We added a new trace sink to show where are dropped. We are going to add an
error model to this code also, so we wanted to demonstrate this working.
@verbatim
static void
RxDrop (Ptr<const Packet> p)
{
NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
}
@end verbatim
This trace sink will be connected to the ``PhyRxDrop'' trace source of the
point-to-point NetDevice. This trace source fires when a packet is dropped
by the physical layer of a @code{NetDevice}. If you take a small detour to the
source (@code{src/devices/point-to-point/point-to-point-net-device.cc}) you will
see that this trace source refers to @code{PointToPointNetDevice::m_phyRxDropTrace}.
If you then look in @code{src/devices/point-to-point/point-to-point-net-device.h}
for this member variable, you will find that it is declared as a
@code{TracedCallback<Ptr<const Packet> >}. This should tell you that the
callback target should be a function that returns void and takes a single
parameter which is a @code{Ptr<const Packet>} -- just what we have above.
@subsubsection The Main Program
The following code should be very familiar to you by now:
@verbatim
int
main (int argc, char *argv[])
{
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
@end verbatim
This creates two nodes with a point-to-point channel between them, just as
shown in the illustration at the start of the file.
The next few lines of code show somthing new. If we trace a connection that
behaves perfectly, we will end up with a monotonically increasing congestion
window. To see any interesting behavior, we really want to introduce link
errors which will drop packets, cause duplicate ACKs and trigger the more
interesting behaviors of the congestion window.
@command{ns-3} provides @code{ErrorModel} objects which can be attached to
@code{Channels}. We are using the @code{RateErrorModel} which allows us
to introduce errors into a @code{Channel} at a given @emph{rate}.
@verbatim
Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> (
"RanVar", RandomVariableValue (UniformVariable (0., 1.)),
"ErrorRate", DoubleValue (0.00001));
devices.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
@end verbatim
The above code instantiates a @code{RateErrorModel} Object. Rather than
using the two-step process of instantiating it and then setting Attributes,
we use the convenience function @code{CreateObjectWithAttributes} which
allows us to do both at the same time. We set the ``RanVar''
@code{Attribute} to a random variable that generates a uniform distribution
from 0 to 1. We also set the ``ErrorRate'' @code{Attribute}.
We then set the resulting instantiated @code{RateErrorModel} as the error
model used by the point-to-point @code{NetDevice}. This will give us some
retransmissions and make our plot a little more interesting.
@verbatim
InternetStackHelper stack;
stack.Install (nodes);
Ipv4AddressHelper address;
address.SetBase (``10.1.1.0'', ``255.255.255.252'');
Ipv4InterfaceContainer interfaces = address.Assign (devices);
@end verbatim
The above code should be familiar. It installs internet stacks on our two
nodes and creates interfaces and assigns IP addresses for the point-to-point
devices.
Since we are using TCP, we need something on the destination node to receive
TCP connections and data. The @code{PacketSink} @code{Application} is commonly
used in @command{ns-3} for that purpose.
@verbatim
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 (20.));
@end verbatim
This should all be familiar, with the exception of,
@verbatim
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
@end verbatim
This code instantiates a @code{PacketSinkHelper} and tells it to create sockets
using the class @code{ns3::TcpSocketFactory}. This class implements a design
pattern called ``object factory'' which is a commonly used mechanism for
specifying a class used to create objects in an abstract way. Here, instead of
having to create the objects themselves, you provide the @code{ PacketSinkHelper}
a string that specifies a @code{TypeId} string used to create an object which
can then be used, in turn, to create instances of the Objects created by the
factory.
The remaining parameter tells the @code{Application} which address and port it
should @code{Bind} to.
The next two lines of code will create the socket and connect the trace source.
@verbatim
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0),
TcpSocketFactory::GetTypeId ());
ns3TcpSocket->TraceConnectWithoutContext (``CongestionWindow'',
MakeCallback (&CwndChange));
@end verbatim
The first statement calls the static member function @code{Socket::CreateSocket}
and provides a @code{Node} and an explicit @code{TypeId} for the object factory
used to create the socket. This is a slightly lower level call than the
@code{PacketSinkHelper} call above, and uses an explicit C++ type instead of
one referred to by a string. Otherwise, it is conceptually the same thing.
Once the @code{TcpSocket} is created and attached to the @code{Node}, we can
use @code{TraceConnectWithoutContext} to connect the CongestionWindow trace
source to our trace sink.
Recall that we coded an @code{Application} so we could take that @code{Socket}
we just made (during configuration time) and use it in simulation time. We now
have to instantiate that @code{Application}. We didn't go to any trouble to
create a helper to manage the @code{Application} so we are going to have to
create and install it ``manually.'' This is actually quite easy:
@verbatim
Ptr<MyApp> app = CreateObject<MyApp> ();
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
nodes.Get (0)->AddApplication (app);
app->Start (Seconds (1.));
app->Stop (Seconds (20.));
@end verbatim
The first line creates an @code{Object} of type @code{MyApp} -- our
@code{Application}. The second line tells the @code{Application} what
@code{Socket} to use, what address to connect to, how much data to send
at each send event, how many send events to generate and the rate at which
to produce data from those events.
Next, we manually add the @code{MyApp Application} to the source node
and explicitly call the @code{Start} and @code{Stop} methods on the
@code{Application} to tell it when to start and stop doing its thing.
We need to actually do the connect from the receiver point-to-point @code{NetDevice}
to our callback now.
@verbatim
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));
@end verbatim
It should now be obvious that we are getting a reference to the receiving
@code{Node NetDevice} from its container and connecting the trace source defined
by the attribute ``PhyRxDrop'' on that device to the trace sink @code{RxDrop}.
Finally, we tell the simulator to override any @code{Applications} and just
stop processing events at 20 seconds into the simulation.
@verbatim
Simulator::Stop (Seconds(20));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
@end verbatim
Recall that as soon as @code{Simulator::Run} is called, configuration time
ends, and simulation time begins. All of the work we orchestrated by
creating the @code{Application} and teaching it how to connect and send
data actually happens during this function call.
As soon as @code{Simulator::Run} returns, the simulation is complete and
we enter the teardown phase. In this case, @code{Simulator::Destroy} takes
care of the gory details and we just return a success code after it completes.
@subsection Running fifth.cc
Since we have provided the file @code{fifth.cc} for you, if you have built
your distribution (in debug mode since it uses NS_LOG -- recall that optimized
builds optimize out NS_LOGs) it will be waiting for you to run.
@verbatim
./waf --run fifth
Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
'build' finished successfully (0.525s)
1.21397 1072
1.22755 1608
1.24114 2144
...
1.35211 8576
1.36136 9112
1.37061 9648
RxDrop at 1.3729
...
@end verbatim
You can probably see immediately a downside of using prints of any kind in your
traces. We get those extraneous waf messages printed all over our interesting
information along with those RxDrop messages. We will remedy that soon, but I'm
sure you can't wait to see the results of all of this work. Let's redirect that
output to a file called @code{cwnd.dat}:
@verbatim
./waf --run fifth > cwnd.dat 2>&1
@end verbatim
Now edit up ``cwnd.dat'' in your favorite editor and remove the waf build status
and drop lines, leaving only the traced data (you could also comment out the
@code{TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));} in the
script to get rid of the drop prints just as easily.
You can now run gnuplot (if you have it installed) and tell it to generate some
pretty pictures:
@verbatim
gnuplot> set terminal png size 1024,768
gnuplot> set output "cwnd.png"
gnuplot> plot "cwnd.dat" using 1:2 title 'Congestion Window' with linespoints
gnuplot> exit
@end verbatim
You should now have a graph of the congestion window versus time sitting in the
file ``cwnd.png'' in all of its glory, that looks like:
@sp 1
@center @image{figures/cwnd,,,,png}
+224
View File
@@ -0,0 +1,224 @@
/* -*- 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 <fstream>
#include "ns3/core-module.h"
#include "ns3/common-module.h"
#include "ns3/simulator-module.h"
#include "ns3/node-module.h"
#include "ns3/helper-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
// ===========================================================================
//
// node 0 node 1
// +----------------+ +----------------+
// | ns-3 TCP | | ns-3 TCP |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ +----------------+
// | point-to-point | | point-to-point |
// +----------------+ +----------------+
// | |
// +---------------------+
// 5 Mbps, 2 ms
//
//
// We want to look at changes in the ns-3 TCP congestion window. We need
// to crank up a flow and hook the CongestionWindow attribute on the socket
// of the sender. Normally one would use an on-off application to generate a
// flow, but this has a couple of problems. First, the socket of the on-off
// application is not created until Application Start time, so we wouldn't be
// able to hook the socket (now) at configuration time. Second, even if we
// could arrange a call after start time, the socket is not public so we
// couldn't get at it.
//
// So, we can cook up a simple version of the on-off application that does what
// we want. On the plus side we don't need all of the complexity of the on-off
// application. On the minus side, we don't have a helper, so we have to get
// a little more involved in the details, but this is trivial.
//
// 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 source node.
// ===========================================================================
//
class MyApp : public Application
{
public:
MyApp ();
virtual ~MyApp();
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;
};
MyApp::MyApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPackets (0),
m_dataRate (0),
m_sendEvent (),
m_running (false),
m_packetsSent (0)
{
}
MyApp::~MyApp()
{
m_socket = 0;
}
void
MyApp::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
MyApp::StartApplication (void)
{
m_running = true;
m_packetsSent = 0;
m_socket->Bind ();
m_socket->Connect (m_peer);
SendPacket ();
}
void
MyApp::StopApplication (void)
{
m_running = false;
if (m_sendEvent.IsRunning ())
{
Simulator::Cancel (m_sendEvent);
}
if (m_socket)
{
m_socket->Close ();
}
}
void
MyApp::SendPacket (void)
{
Ptr<Packet> packet = Create<Packet> (m_packetSize);
m_socket->Send (packet);
if (++m_packetsSent < m_nPackets)
{
ScheduleTx ();
}
}
void
MyApp::ScheduleTx (void)
{
if (m_running)
{
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}
static void
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
}
static void
RxDrop (Ptr<const Packet> p)
{
NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
}
int
main (int argc, char *argv[])
{
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("1Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> (
"RanVar", RandomVariableValue (UniformVariable (0., 1.)),
"ErrorRate", DoubleValue (0.00001));
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
InternetStackHelper stack;
stack.Install (nodes);
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer interfaces = address.Assign (devices);
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 (20.));
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndChange));
Ptr<MyApp> app = CreateObject<MyApp> ();
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("5Mbps"));
nodes.Get (0)->AddApplication (app);
app->Start (Seconds (1.));
app->Stop (Seconds (20.));
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));
Simulator::Stop (Seconds(20));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
+3
View File
@@ -15,3 +15,6 @@ def build(bld):
obj = bld.create_ns3_program('fourth', ['core'])
obj.source = 'fourth.cc'
obj = bld.create_ns3_program('fifth', ['core', 'simulator', 'point-to-point', 'internet-stack'])
obj.source = 'fifth.cc'
+5
View File
@@ -184,6 +184,7 @@ HwmpProtocol::HwmpProtocol ():
m_doFlag (false),
m_rfFlag (false)
{
NS_LOG_FUNCTION_NOARGS ();
if (m_isRoot)
{
@@ -193,11 +194,13 @@ HwmpProtocol::HwmpProtocol ():
HwmpProtocol::~HwmpProtocol ()
{
NS_LOG_FUNCTION_NOARGS ();
}
void
HwmpProtocol::DoDispose ()
{
NS_LOG_FUNCTION_NOARGS ();
for (std::map<Mac48Address, EventId>::iterator i = m_preqTimeouts.begin (); i != m_preqTimeouts.end (); i ++)
{
i->second.Cancel ();
@@ -206,8 +209,10 @@ HwmpProtocol::DoDispose ()
m_preqTimeouts.clear ();
m_lastDataSeqno.clear ();
m_lastHwmpSeqno.clear ();
m_interfaces.clear ();
m_rqueue.clear ();
m_rtable = 0;
m_mp = 0;
}
bool
@@ -118,19 +118,11 @@ IeBeaconTiming::DelNeighboursTimingElementUnit (uint16_t aid, Time last_beacon,
void
IeBeaconTiming::ClearTimingElement ()
{
uint16_t to_delete = 0;
uint16_t i;
for (NeighboursTimingUnitsList::iterator j = m_neighbours.begin (); j != m_neighbours.end (); j++)
{
to_delete++;
(*j) = 0;
}
for (i = 0; i < to_delete; i++)
{
m_neighbours.pop_back ();
}
m_neighbours.clear ();
}
uint8_t
IeBeaconTiming::GetInformationSize () const
@@ -373,16 +373,11 @@ IePreq::DelDestinationAddressElement (Mac48Address dest_address)
void
IePreq::ClearDestinationAddressElements ()
{
int i;
for (std::vector<Ptr<DestinationAddressUnit> >::iterator j = m_destinations.begin (); j
!= m_destinations.end (); j++)
{
(*j) = 0;
}
for (i = 0; i < m_destCount; i++)
{
m_destinations.pop_back ();
}
m_destinations.clear ();
m_destCount = 0;
}
@@ -93,6 +93,8 @@ PeerManagementProtocol::DoDispose ()
i->second.clear ();
}
m_neighbourBeacons.clear ();
m_plugins.clear ();
}
bool
+3
View File
@@ -73,6 +73,9 @@ MeshPointDevice::DoDispose ()
*iter = 0;
}
m_ifaces.clear ();
m_node = 0;
m_channel = 0;
m_routingProtocol = 0;
NetDevice::DoDispose ();
}
-2
View File
@@ -27,8 +27,6 @@
#include "ns3/wifi-mac-header.h"
#include "ns3/wifi-information-element-vector.h"
#include <vector>
namespace ns3 {
/**
@@ -282,8 +282,10 @@ MeshWifiInterfaceMac::DoDispose ()
m_rxMiddle = 0;
m_low = 0;
m_dcfManager = 0;
m_stationManager = 0;
m_phy = 0;
m_queues.clear ();
m_plugins.clear ();
m_beaconSendEvent.Cancel ();
m_beaconDca = 0;
@@ -74,7 +74,7 @@ WifiInformationElementVector::GetSerializedSize () const
void
WifiInformationElementVector::Serialize (Buffer::Iterator start) const
{
for(std::vector<Ptr<WifiInformationElement> >::const_iterator i = m_elements.begin (); i != m_elements.end (); i ++)
for(IE_VECTOR::const_iterator i = m_elements.begin (); i != m_elements.end (); i ++)
{
start.WriteU8((*i)->ElementId ());
start.WriteU8 ((*i)->GetInformationSize ());
+1 -1
View File
@@ -611,7 +611,7 @@ InterferenceHelper::EraseEvents (void)
{
*i = 0;
}
m_events.erase (m_events.begin (), m_events.end ());
m_events.clear ();
}
void
+10 -2
View File
@@ -28,6 +28,9 @@
#include "ns3/pointer.h"
#include "ns3/node.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/log.h"
NS_LOG_COMPONENT_DEFINE ("WifiNetDevice");
namespace ns3 {
@@ -65,13 +68,18 @@ WifiNetDevice::GetTypeId (void)
WifiNetDevice::WifiNetDevice ()
: m_mtu (0),
m_configComplete (false)
{}
{
NS_LOG_FUNCTION_NOARGS ();
}
WifiNetDevice::~WifiNetDevice ()
{}
{
NS_LOG_FUNCTION_NOARGS ();
}
void
WifiNetDevice::DoDispose (void)
{
NS_LOG_FUNCTION_NOARGS ();
m_node = 0;
m_mac->Dispose ();
m_phy->Dispose ();
+1
View File
@@ -56,6 +56,7 @@ YansWifiChannel::YansWifiChannel ()
{}
YansWifiChannel::~YansWifiChannel ()
{
NS_LOG_FUNCTION_NOARGS ();
m_phyList.clear ();
}
+2
View File
@@ -139,6 +139,8 @@ YansWifiPhy::DoDispose (void)
m_channel = 0;
m_modes.clear ();
m_device = 0;
m_mobility = 0;
m_state = 0;
}
void
+3 -2
View File
@@ -73,8 +73,9 @@ Dot11sStack::InstallStack (Ptr<MeshPointDevice> mp)
hwmp->SetRoot ();
}
//Install interaction between HWMP and Peer management protocol:
pmp->SetPeerLinkStatusCallback (MakeCallback (&HwmpProtocol::PeerLinkStatus, hwmp));
hwmp->SetNeighboursCallback (MakeCallback (&PeerManagementProtocol::GetActiveLinks, pmp));
//PeekPointer()'s to avoid circular Ptr references
pmp->SetPeerLinkStatusCallback (MakeCallback (&HwmpProtocol::PeerLinkStatus, PeekPointer (hwmp)));
hwmp->SetNeighboursCallback (MakeCallback (&PeerManagementProtocol::GetActiveLinks, PeekPointer (pmp)));
return true;
}
void
+3 -1
View File
@@ -45,6 +45,8 @@ TypeId NetDevice::GetTypeId (void)
}
NetDevice::~NetDevice ()
{}
{
NS_LOG_FUNCTION_NOARGS ();
}
} // namespace ns3
+1
View File
@@ -148,6 +148,7 @@ Node::GetNApplications (void) const
void
Node::DoDispose()
{
m_handlers.clear ();
for (std::vector<Ptr<NetDevice> >::iterator i = m_devices.begin ();
i != m_devices.end (); i++)
{