--- a/.hgignore Thu Oct 22 17:17:40 2009 +0400
+++ b/.hgignore Mon Oct 26 09:21:20 2009 +0300
@@ -4,6 +4,7 @@
~$
^build-dir
^build
+^testpy-output
^doc/html
^doc/latex
^\.lock-wscript
--- a/.hgtags Thu Oct 22 17:17:40 2009 +0400
+++ b/.hgtags Mon Oct 26 09:21:20 2009 +0300
@@ -36,3 +36,8 @@
8562a42accf6f715d312c037326ec7da48095e13 ns-3.5-rc2
a600c11ff8d40a40e88c2d692acad6512dde70c8 ns-3.5-rc3
c975274c9707b1f07d94cc51f205c351122131a5 ns-3.5
+549243b47311211975b388cd64fcb9111caa2fc2 ns-3.6-RC1
+8996042990466b1eda718a848e1c02923c0add74 ns-3.6-RC2
+79ff6ad1adbb7b4677759ddf52028b68b0515168 ns-3.6-RC3
+39a82d7a0d661febe42e75f26ada79424258e330 ns-3.6-RC4
+d55c479666ac6be0575fac695ddf355c0530e0dd ns-3.6
--- a/CHANGES.html Thu Oct 22 17:17:40 2009 +0400
+++ b/CHANGES.html Mon Oct 26 09:21:20 2009 +0300
@@ -48,6 +48,13 @@
<h2>Changes to build system:</h2>
<ul>
+<li><b>A new test framework is provided with ns-3.6 that primarilay runs outside waf</b>
+<p>"./waf check" now runs the new unit tests of the core part of ns-3.6.
+In order to run the complete test package, use "./test.py" which is
+documented in a new manual -- find it in ./doc/testing. "./waf check"
+no longer generates the introspected Doxygen. Now use "./waf doxygen"
+to do this and generate the Doxygen documentation in one step.
+</p>
</ul>
<h2>New API:</h2>
@@ -124,6 +131,14 @@
</p>
</li>
+<li><b>New Test Framework</b>
+<p> Add TestCase, TestSuite classes
+<ul>
+<li> examples: src/core/names-test-suite.cc, src/core/random-number-test-suite.cc, src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc
+</ul>
+</p>
+</li>
+
</ul>
<h2>Changes to existing API:</h2>
--- a/RELEASE_NOTES Thu Oct 22 17:17:40 2009 +0400
+++ b/RELEASE_NOTES Mon Oct 26 09:21:20 2009 +0300
@@ -17,7 +17,7 @@
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)
@@ -63,10 +63,18 @@
- Ipv4NixVectorHelper
- Examples (nix-simple, nms-p2p-nix)
+ e) New Test Framework
+ - Use test.py instead of ./waf check or ./waf --regression
+ - 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
------------
@@ -75,10 +83,6 @@
- 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
===========
--- a/bindings/python/wscript Thu Oct 22 17:17:40 2009 +0400
+++ b/bindings/python/wscript Mon Oct 26 09:21:20 2009 +0300
@@ -15,7 +15,7 @@
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)
--- a/doc/build.txt Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/build.txt Mon Oct 26 09:21:20 2009 +0300
@@ -7,10 +7,10 @@
=== Installing Waf ===
-The top-level ns-3 directory should contain a current waf script.
-
-Note: we're using a WAF version based on WAF 1.5.x. The source code
-can be retrieved from the followin URL:
+The top-level ns-3 directory should contain a current waf script, so
+there is no need to have WAF installed in the system. We are using
+some extensions to WAF, which can be found in the 'waf-tools'
+directory. The upstream location for these WAF extensions is:
https://code.launchpad.net/~gjc/waf/cmd
--- a/doc/main.h Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/main.h Mon Oct 26 09:21:20 2009 +0300
@@ -27,9 +27,7 @@
* ns-3 requires Doxygen version 1.5.4 or greater to fully build all items,
* although earlier versions of Doxygen will mostly work.
*
- * Type "./waf --check" followed by "./waf --doxygen" to build the documentation.
- * There is a program that runs during "./waf --check" that builds pieces of
- * the documentation through introspection. The doc/ directory contains
+ * Type "./waf doxygen" to build the documentation. The doc/ directory contains
* configuration for Doxygen (doxygen.conf and main.txt). The Doxygen
* build process puts html files into the doc/html/ directory, and latex
* filex into the doc/latex/ directory.
--- a/doc/manual/Makefile Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/Makefile Mon Oct 26 09:21:20 2009 +0300
@@ -17,6 +17,7 @@
$(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 @@
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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/animation.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/applications.texi Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,6 @@
+@node Applications
+@chapter Applications
+
+@cartouche
+Placeholder chapter
+@end cartouche
--- a/doc/manual/attributes.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/attributes.texi Mon Oct 26 09:21:20 2009 +0300
@@ -125,7 +125,8 @@
This is defined in the node.cc file as follows:
-@verbatim
+@smallformat
+@example
TypeId
Node::GetTypeId (void)
{
@@ -148,15 +149,16 @@
;
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 @@
@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 @@
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 @@
return tid;
}
-@end verbatim
+@end example
+@end smallformat
The AddAttribute() method is performing a number of things with this
value:
@@ -295,11 +299,19 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
"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 @@
@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 @@
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 @@
;
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
<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 @@
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 @@
outputConfig.ConfigureAttributes ();
Simulator::Run ();
}
-@end verbatim
+@end example
+@end smallformat
@subsection GTK-based ConfigStore
@@ -794,24 +839,28 @@
@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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/bridge.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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.
--- a/doc/manual/callbacks.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/callbacks.texi Mon Oct 26 09:21:20 2009 +0300
@@ -7,15 +7,16 @@
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 @@
class B {
public:
- void ReceiveInput ( // parameters);
void DoSomething (void);
...
@@ -91,9 +91,13 @@
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 @@
@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 @@
@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 @@
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 @@
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 @@
(*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 @@
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".
--- a/doc/manual/emu.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/emu.texi Mon Oct 26 09:21:20 2009 +0300
@@ -1,183 +1,288 @@
@node Emu NetDevice
@chapter Emu NetDevice
-This is the introduction to Emu NetDevice chapter, to complement the
-Emu model doxygen.
-
-@menu
-* Overview of the model::
-* Using the EmuNetDevice::
-* Emu Tracing::
-@end menu
+@section Behavior
-@node Overview of the model
-@section Overview of the model
-
-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 @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.
-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 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.
-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.
+@section Usage
-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:
-
+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
+ //
+ // 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
+
+And then the IP address of the client or server is set in the usual way using
+helpers.
@verbatim
- NetDeviceContainer emuDevices = emu.Install (nodes);
+ //
+ // 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
-@node Emu Tracing
-@section Emu Tracing
+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/}.
+
+@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.
-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.
+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 Upper-Level (MAC) Hooks
+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}:
-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
+ 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);
-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:
+ 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.
-@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
+ 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 upper-level (MAC) trace hooks for the EmuNetDevice are, in fact,
-exactly these three trace sources on the single transmit queue of the device.
+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.
-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.
+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);
-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.
+ m_queue->Enqueue (packet);
+ packet = m_queue->Dequeue ();
+
+ struct sockaddr_ll ll;
+ bzero (&ll, sizeof (ll));
-@subsection Lower-Level (PHY) Hooks
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = m_sll_ifindex;
+ ll.sll_protocol = htons(ETH_P_ALL);
-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.
+ 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.
+
--- a/doc/manual/emulation.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/emulation.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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 @@
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 @@
@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 @@
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 doc/manual/figures/software-organization.dia has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/flow-monitor.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/helpers.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/internet.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/ipv4.texi Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,6 @@
+@node IPv4
+@chapter IPv4
+
+@cartouche
+Placeholder chapter
+@end cartouche
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/ipv6.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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/}
+
--- a/doc/manual/log.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/log.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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
--- a/doc/manual/manual.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/manual.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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 @@
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 @@
@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 @@
@end ifnottex
@menu
+* Organization::
* Random variables::
* Callbacks::
* Object model::
* Attributes::
+* Object names::
+* Logging::
* Tracing::
* RealTime::
+* Packets::
+* Helpers::
+* Python::
+* Node and NetDevices::
+* Simple NetDevice::
+* PointToPoint NetDevice::
+* CSMA NetDevice::
+* Wifi NetDevice::
+* Mesh NetDevice::
+* Bridge NetDevice::
* Emulation::
-* Packets::
+* Emu NetDevice::
+* Tap NetDevice::
* Sockets APIs::
-* Node and Internet Stack::
+* Internet Stack::
+* IPv4::
+* IPv6::
+* Routing overview::
* TCP::
-* Routing overview::
-* Wifi NetDevice::
-* CSMA NetDevice::
-* PointToPoint NetDevice::
+* 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 packets.texi
+@include helpers.texi
+@include python.texi
+
+@unnumbered Part 2: Nodes and NetDevices
+@setchapternewpage off
+@include node.texi
+@setchapternewpage odd
+@include simple.texi
+@include point-to-point.texi
+@include csma.texi
+@include wifi.texi
+@include mesh.texi
+@include bridge.texi
+
+@unnumbered Part 3: Emulation
+@setchapternewpage off
@include emulation.texi
-@include packets.texi
+@setchapternewpage odd
+@include emu.texi
+@include tap.texi
+
+@unnumbered Part 4: Internet Models
+@setchapternewpage off
@include sockets.texi
-@include node.texi
-@c @include output.texi
+@setchapternewpage odd
+@include internet.texi
+@include ipv4.texi
+@include ipv6.texi
+@include routing.texi
@include tcp.texi
-@include routing.texi
-@include wifi.texi
-@include csma.texi
-@include point-to-point.texi
-@c @include other.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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/mesh.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/names.texi Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,6 @@
+@node Object names
+@chapter Object names
+
+@cartouche
+Placeholder chapter
+@end cartouche
--- a/doc/manual/new-models.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/new-models.texi Mon Oct 26 09:21:20 2009 +0300
@@ -395,8 +395,10 @@
@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 @@
@subsection Object Framework
-@verbatim
+@smallformat
+@example
static const ClassId cid;
@@ -416,8 +419,8 @@
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 @@
@subsection Add basic support in the class
-@verbatim
+@smallformat
+@example
point-to-point-net-device.h
class ErrorModel;
@@ -440,12 +444,13 @@
*/
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 @@
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 @@
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 @@
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 @@
We declare BasicErrorModel to be a subclass of ErrorModel as follows,
-@verbatim
+@smallformat
+@example
class BasicErrorModel : public ErrorModel
{
public:
@@ -562,7 +574,8 @@
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:
--- a/doc/manual/node.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/node.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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 @@
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 @@
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:
+The following chapters provide reference information on the available
+NetDevices in ns-3.
-@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
-
--- a/doc/manual/objects.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/objects.texi Mon Oct 26 09:21:20 2009 +0300
@@ -98,7 +98,7 @@
@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 @@
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 @@
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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/organization.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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}).
--- a/doc/manual/packets.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/packets.texi Mon Oct 26 09:21:20 2009 +0300
@@ -99,7 +99,7 @@
@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 @@
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 @@
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 @@
* \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 @@
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 @@
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 @@
* 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 @@
* 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}:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/python.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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}.
--- a/doc/manual/random.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/random.texi Mon Oct 26 09:21:20 2009 +0300
@@ -35,7 +35,7 @@
@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 @@
@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 @@
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 @@
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 @@
@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 @@
@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 Returns a random integer integer from the underlying distribution
+ * \return Integer cast of ::GetValue()
+ */
+ uint32_t GetInteger (void) const;
+@end example
+@end smallformat
- /**
- * \brief Set the run number of this simulation
- */
- static void SetRunNumber(uint32_t n);
-
- /**
- * \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 @@
@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 @@
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 @@
;
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 @@
@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.
-
--- a/doc/manual/routing.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/routing.texi Mon Oct 26 09:21:20 2009 +0300
@@ -25,7 +25,7 @@
@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 @@
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 @@
@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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/simple.texi Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,6 @@
+@node Simple NetDevice
+@chapter Simple NetDevice
+
+@cartouche
+Placeholder chapter
+@end cartouche
--- a/doc/manual/sockets.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/sockets.texi Mon Oct 26 09:21:20 2009 +0300
@@ -42,8 +42,8 @@
@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 @@
@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 @@
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 @@
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 @@
@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 @@
@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
--- a/doc/manual/statistics.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/statistics.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/tap.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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.
+
--- a/doc/manual/tcp.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/tcp.texi Mon Oct 26 09:21:20 2009 +0300
@@ -105,10 +105,7 @@
@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 @@
@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
-@verbatim
-./waf configure --enable-nsc
-@end verbatim
-the output of the configuration will show something like:
+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
-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 @@
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 @@
@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
--- a/doc/manual/tracing.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/tracing.texi Mon Oct 26 09:21:20 2009 +0300
@@ -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 @@
@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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
sinks.
@end itemize
-@node Implementation details
+@node Tracing implementation details
@section Implementation details
--- a/doc/manual/troubleshoot.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/troubleshoot.texi Mon Oct 26 09:21:20 2009 +0300
@@ -9,7 +9,9 @@
* 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 @@
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 @@
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 @@
$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 @@
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 @@
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
--- a/doc/manual/wifi.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/manual/wifi.texi Mon Oct 26 09:21:20 2009 +0300
@@ -28,9 +28,8 @@
@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 @@
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,35 @@
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),
- "BeaconInterval", TimeValue (Seconds (2.5)));
- wifiMacHelper.SetEdcaParametersForAc (AC_VO, "MinCw", UintegerValue (2));
- wifiMacHelper.SetMsduAggregatorForAc (AC_VO, "ns3::MsduStandardAggregator", "MaxAmsduSize", UintegerValue (3839));
-@end verbatim
+ wifiMacHelper.SetType ("ns3::QapWifiMac",
+ "Ssid", SsidValue (ssid),
+ "BeaconGeneration", BooleanValue (true),
+ "BeaconInterval", TimeValue (Seconds (2.5)));
+ 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
- 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));
- ...
-@end verbatim
+access classes; otherwise we should set them one by one.
@subsection WifiHelper
@@ -244,9 +245,11 @@
@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 +260,16 @@
@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
--- a/doc/release_steps.txt Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/release_steps.txt Mon Oct 26 09:21:20 2009 +0300
@@ -1,26 +1,36 @@
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
- revise and check in AUTHORS, if needed
- revise and check in RELEASE_NOTES
- DO NOT change VERSION at this time
- confirm that Doxygen builds cleanly and without warnings
- (./waf --check; ./waf --doxygen), and check in any necessary changes
- - ensure no regressions (./waf --regression)
-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)
+ (./waf doxygen), and check in any necessary changes
+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
@@ -28,51 +38,66 @@
- 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.2) This must agree with the version name you chose in the clone
+ (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
-9. Run the regression tests on the new release (debug and optimized)
- - ./waf -d debug configure
- - ./waf
+ - 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-allinone-3.x
+ - cd !$
+ - ./download.py -n ns-3.x -r ns-3.x-ref-traces
+ - ./build.py
+ - cd ns-3.x
+ - ./test.py
+ - ./test.py -g
- ./waf --regression
- ./waf --valgrind --regression (for valgrind version)
- ./waf -d optimized configure
- ./waf
+ - ./test.py
+ - ./test.py -g
- ./waf --regression
- ./waf --valgrind --regression (for valgrind version)
- There should be no regression errors at this time
10. Create final tarballs
- - ./waf configure; ./waf dist
- - this will create an ns-3.x.tar.bz2 tarball
- - this will also create a ns-3.x-ref-traces.tar.bz2 tarball
-11. upload "ns-3.x.tar.bz2" to the /var/www/html/releases/ directory on
+ - cd into ns-3-allinone level
+ - ./dist.py
+ - 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
- - give it 644 file permissions, and user/group = apache
-12. upload "ns-3.x-ref-traces.tar.bz2" to the /var/www/html/releases/
- directory on the www.nsnam.org server
- - give it 644 file permissions, and user/group = apache
+ - scp ns-allinone-3.x.tar.bz2 www.nsnam.org:~
+ - ssh www.nsnam.org
+ - sudo cp ns-allinone-3.x.tar.bz2 /var/www/html/releases
+ - cd !$
+12. give it 644 file permissions, and user/group = apache if it is not already
+ - sudo chown apache:apache ns-allinone-3.x.tar.bz2
+ - 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
--- a/doc/testing/testing-framework.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/testing/testing-framework.texi Mon Oct 26 09:21:20 2009 +0300
@@ -107,6 +107,37 @@
their distribution is working correctly, and by developers who are interested
in determining if changes they have made have caused any regressions.
+There are a number of options available to control the behavir of @code{test.py}.
+if you run @code{test.py --help} you should see a command summary like:
+
+@verbatim
+ Usage: test.py [options]
+
+ Options:
+ -h, --help show this help message and exit
+ -c KIND, --constrain=KIND
+ constrain the test-runner by kind of test
+ -e EXAMPLE, --example=EXAMPLE
+ specify a single example to run
+ -g, --grind run the test suites and examples using valgrind
+ -k, --kinds print the kinds of tests available
+ -l, --list print the list of known tests
+ -m, --multiple report multiple failures from test suites and test
+ cases
+ -n, --nowaf do not run waf before starting testing
+ -s TEST-SUITE, --suite=TEST-SUITE
+ specify a single test suite to run
+ -v, --verbose print progress and informational messages
+ -w HTML-FILE, --web=HTML-FILE, --html=HTML-FILE
+ write detailed test results into HTML-FILE.html
+ -r, --retain retain all temporary files (which are normally
+ deleted)
+ -t TEXT-FILE, --text=TEXT-FILE
+ write detailed test results into TEXT-FILE.txt
+ -x XML-FILE, --xml=XML-FILE
+ write detailed test results into XML-FILE.xml
+@end verbatim
+
If one specifies an optional output style, one can generate detailed descriptions
of the tests and status. Available styles are @command{text} and @command{HTML}.
The buildbots will select the HTML option to generate HTML test reports for the
@@ -324,6 +355,18 @@
./test.py --grind
@end verbatim
+As it runs, @code{test.py} and the programs that it runs indirectly, generate large
+numbers of temporary files. Usually, the content of these files is not interesting,
+however in some cases it can be useful (for debugging purposes) to view these files.
+@code{test.py} provides a @command{--retain} option which will cause these temporary
+files to be kept after the run is completed. The files are saved in a directory
+named @code{testpy} under a subdirectory named according to the current Coordinated
+Universal Time (also known as Greenwich Mean Time).
+
+@verbatim
+ ./test.py --retain
+@end verbatim
+
Finally, @code{test.py} provides a @command{--verbose} option which will print
large amounts of information about its progress. It is not expected that this
will be terribly useful unless there is an error. In this case, you can get
--- a/doc/tutorial/building-topologies.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/tutorial/building-topologies.texi Mon Oct 26 09:21:20 2009 +0300
@@ -43,10 +43,10 @@
this section. The appearance and operation of these helpers should look
quite familiar to you.
-We provide an example script in our @code{examples} directory. This script
+We provide an example script in our @code{examples/tutorial} directory. This script
builds on the @code{first.cc} script and adds a CSMA network to the
point-to-point simulation we've already considered. Go ahead and open
-@code{examples/second.cc} in your favorite editor. You will have already seen
+@code{examples/tutorial/second.cc} in your favorite editor. You will have already seen
enough @command{ns-3} code to understand most of what is going on in this
example, but we will go over the entire script and examine some of the output.
@@ -356,7 +356,7 @@
repository you just type,
@verbatim
- cp examples/second.cc scratch/mysecond.cc
+ cp examples/tutorial/second.cc scratch/mysecond.cc
./waf
@end verbatim
@@ -380,8 +380,8 @@
@code{first.cc}, you will see similar output when you run the script.
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.415s)
Sent 1024 bytes to 10.1.2.4
Received 1024 bytes from 10.1.1.1
@@ -560,8 +560,8 @@
You should now see,
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.405s)
Sent 1024 bytes to 10.1.2.5
Received 1024 bytes from 10.1.1.1
@@ -634,8 +634,8 @@
you will see the following output:
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.407s)
Sent 1024 bytes to 10.1.2.101
Received 1024 bytes from 10.1.1.1
@@ -712,9 +712,9 @@
topology helpers in this section. The appearance and operation of these
helpers should look quite familiar to you.
-We provide an example script in our @code{examples} directory. This script
+We provide an example script in our @code{examples/tutorial} directory. This script
builds on the @code{second.cc} script and adds a Wifi network. Go ahead and
-open @code{examples/third.cc} in your favorite editor. You will have already
+open @code{examples/tutorial/third.cc} in your favorite editor. You will have already
seen enough @command{ns-3} code to understand most of what is going on in
this example, but there are a few new things, so we will go over the entire
script and examine some of the output.
@@ -1117,8 +1117,8 @@
@code{second.cc} script, you will see similar output.
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.407s)
Sent 1024 bytes to 10.1.2.4
Received 1024 bytes from 10.1.3.3
--- a/doc/tutorial/conceptual-overview.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/tutorial/conceptual-overview.texi Mon Oct 26 09:21:20 2009 +0300
@@ -181,7 +181,7 @@
@end verbatim
@cindex first.cc
-Change into the examples directory. You should see a file named
+Change into the @code{examples/tutorial} directory. You should see a file named
@code{first.cc} located there. This is a script that will create a simple
point-to-point link between two nodes and echo a single packet between the
nodes. Let's take a look at that script line by line, so go ahead and open
@@ -277,7 +277,7 @@
@end verbatim
to build the project. So now if you look in the directory
-@code{../build/debug/ns3} you will find the four module include files shown
+@code{../../build/debug/ns3} you will find the four module include files shown
above. You can take a look at the contents of these files and find that they
do include all of the public include files in their respective modules.
@@ -732,12 +732,12 @@
@subsection Building Your Script
We have made it trivial to build your simple scripts. All you have to do is
to drop your script into the scratch directory and it will automatically be
-built if you run Waf. Let's try it. Copy @code{examples/first.cc} into
+built if you run Waf. Let's try it. Copy @code{examples/tutorial/first.cc} into
the @code{scratch} directory after changing back into the top level directory.
@verbatim
cd ..
- cp examples/first.cc scratch/myfirst.cc
+ cp examples/tutorial/first.cc scratch/myfirst.cc
@end verbatim
Now build your first example script using waf:
@@ -750,10 +750,10 @@
successfully.
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
[614/708] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o
[706/708] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (2.357s)
@end verbatim
@@ -767,8 +767,8 @@
You should see some output:
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.418s)
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial/conclusion.texi Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,60 @@
+@c ============================================================================
+@c Begin document body here
+@c ============================================================================
+
+@c ============================================================================
+@c PART: Closing Remarks
+@c ============================================================================
+@c The below chapters are under the major heading "Closing Remarks"
+@c This is similar to the Latex \part command
+@c
+@c ============================================================================
+@c Closing Remarks
+@c ============================================================================
+@node Closing Remarks
+@chapter Closing Remarks
+
+@menu
+* Futures::
+* Closing::
+@end menu
+
+@c ============================================================================
+@c Futures
+@c ============================================================================
+@node
+@section Futures
+
+This document is a work in process. We hope and expect it to grow over time
+to cover more and more of the nuts and bolts of @command{ns-3}.
+
+We hope to add the following chapters over the next few releases:
+
+@itemize @bullet
+@item The Callback System
+@item The Object System and Memory Management
+@item The Routing System
+@item Adding a New NetDevice and Channel
+@item Adding a New Protocol
+@item Working with Real Networks and Hosts
+@end itemize
+
+Writing manual and tutorial chapters is not something we all get excited about,
+but it is very important to the project. If you are an expert in one of these
+areas, please consider contributing to @command{ns-3} by providing one of these
+chapters; or any other chapter you may think is important.
+
+@c ============================================================================
+@c Closing
+@c ============================================================================
+@node
+@section Closing
+
+@code{ns-3} is a large and complicated system. It is impossible to cover all
+of the things you will need to know in one small tutorial.
+
+We have really just scratched the surface of @command{ns-3} in this tutorial,
+but we hope to have covered enough to get you started doing useful networking
+research using our favorite simulator.
+
+-- The @command{ns-3} development team.
Binary file doc/tutorial/figures/cwnd.png has changed
--- a/doc/tutorial/getting-started.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/tutorial/getting-started.texi Mon Oct 26 09:21:20 2009 +0300
@@ -126,8 +126,8 @@
Since the release numbers are going to be changing, I will stick with
the more constant ns-3-dev here in the tutorial, but you can replace the
-string ``ns-3-dev'' with your choice of release (e.g., ns-3.5 and
-ns-3.5-ref-traces) in the text below. You can find the latest version of the
+string ``ns-3-dev'' with your choice of release (e.g., ns-3.6 and
+ns-3.6-ref-traces) in the text below. You can find the latest version of the
code either by inspection of the repository list or by going to the
@uref{http://www.nsnam.org/getting_started.html,,``Getting Started''}
web page and looking for the latest release identifier.
@@ -138,7 +138,7 @@
Go ahead and type the following into your shell (remember you can substitute
the name of your chosen release number instead of @code{ns-3-dev} -- like
-@code{"ns-3.5"} and @code{"ns-3.5-ref-traces"} if you want to work with a
+@code{"ns-3.6"} and @code{"ns-3.6-ref-traces"} if you want to work with a
stable release).
@verbatim
@@ -267,16 +267,16 @@
cd
mkdir tarballs
cd tarballs
- wget http://www.nsnam.org/releases/ns-allinone-3.5.tar.bz2
- tar xjf ns-allinone-3.5.tar.bz2
+ wget http://www.nsnam.org/releases/ns-allinone-3.6.tar.bz2
+ tar xjf ns-allinone-3.6.tar.bz2
@end verbatim
-If you change into the directory @code{ns-allinone-3.5} you should see a
+If you change into the directory @code{ns-allinone-3.6} you should see a
number of files:
@verbatim
-build.py* ns-3.5/ nsc-0.5.0/ README
-constants.py ns-3.5-ref-traces/ pybindgen-0.10.0.640/ util.py
+build.py* ns-3.6/ nsc-0.5.1/ README
+constants.py ns-3.6-ref-traces/ pybindgen-0.12.0.700/ util.py
@end verbatim
You are now ready to build the @command{ns-3} distribution.
@@ -298,7 +298,7 @@
downloaded using Mercurial you should have a directory called
@code{ns-3-allinone} under your @code{~/repos} directory. If you downloaded
using a tarball you should have a directory called something like
-@code{ns-allinone-3.5} under your @code{~/tarballs} directory. Take a deep
+@code{ns-allinone-3.6} under your @code{~/tarballs} directory. Take a deep
breath and type the following:
@verbatim
@@ -310,7 +310,7 @@
following magic words:
@verbatim
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (2m30.586s)
@end verbatim
@@ -405,6 +405,7 @@
Python Bindings : enabled
Python API Scanning Support : enabled
Use sudo to set suid bit : not enabled (option --enable-sudo not selected)
+ Build examples and samples : enabled
Static build : not enabled (option --enable-static not selected)
'configure' finished successfully (2.870s)
@end verbatim
@@ -462,51 +463,44 @@
@cindex unit tests
You can run the unit tests of the @command{ns-3} distribution by running the
-``--check'' option,
+``./test.py -c core'' script,
@verbatim
- ./waf --check
+ ./test.py -c core
@end verbatim
-These tests are run in parallel by waf, so the summary, ``Ran n tests'' will
-appear as soon as all of the tasks are launched, but you should eventually
+These tests are run in parallel by waf. You should eventually
see a report saying that,
@verbatim
- C++ UNIT TESTS: all 33 tests passed.
+ 47 of 47 tests passed (47 passed, 0 failed, 0 crashed, 0 valgrind errors)
@end verbatim
This is the important message.
-You will also see output from the test runner and waf task sequence numbers
-the output will actually look something like,
+You will also see output from the test runner and the output will actually look something like,
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- [707/709] get-unit-tests-list
- [708/709] run-python-unit-tests
- [709/709] print-introspected-doxygen
- [710/743] run-unit-test(AddressHelper)
- [711/743] run-unit-test(Wifi)
- ...........
- ----------------------------------------------------------------------
- Ran 11 tests in 0.003s
-
- OK
- [712/743] run-unit-test(DcfManager)
- [713/743] run-unit-test(MacRxMiddle)
- [714/743] run-unit-test(Ipv4ListRouting)
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ 'build' finished successfully (1.799s)
+ PASS: TestSuite ns3-wifi-interference
+ PASS: TestSuite histogram
+ PASS: TestSuite sample
+ PASS: TestSuite ipv4-address-helper
+ PASS: TestSuite devices-wifi
+ PASS: TestSuite propagation-loss-model
...
- [739/743] run-unit-test(RandomVariable)
- [740/743] run-unit-test(Object)
- [741/743] run-unit-test(Ptr)
- [742/743] run-unit-test(Callback)
- [743/743] collect-unit-tests-results
- C++ UNIT TESTS: all 33 tests passed.
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- 'build' finished successfully (1.799s)
+ PASS: TestSuite attributes
+ PASS: TestSuite config
+ PASS: TestSuite global-value
+ PASS: TestSuite command-line
+ PASS: TestSuite basic-random-number
+ PASS: TestSuite object
+ PASS: TestSuite random-number-generators
+ 47 of 47 tests passed (47 passed, 0 failed, 0 crashed, 0 valgrind errors)
@end verbatim
This command is typically run by @code{users} to quickly verify that an
@@ -519,7 +513,7 @@
your machine during the @code{./download.py} process above. (Warning: The
@code{ns-3.2} and @code{ns-3.3} releases do not use the @code{ns-3-allinone}
environment and require you to be online when you run regression tests because
-hey dynamically synchronize the reference traces directory with an online
+they dynamically synchronize the reference traces directory with an online
repository immediately prior to the run).
During regression testing Waf will run a number of tests that generate what we
@@ -547,7 +541,7 @@
passing.
@verbatim
- Entering directory `repos/ns-3-allinone/ns-3-dev/build'
+ Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
[647/669] regression-test (test-csma-bridge)
[648/669] regression-test (test-csma-broadcast)
[649/669] regression-test (test-csma-multicast)
@@ -558,7 +552,7 @@
...
Regression testing summary:
PASS: 22 of 22 tests passed
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (25.826s)
@end verbatim
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial/tracing.texi Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,1904 @@
+@c ============================================================================
+@c Begin document body here
+@c ============================================================================
+
+@c ============================================================================
+@c PART: The Tracing System
+@c ============================================================================
+@c The below chapters are under the major heading "The Tracing System"
+@c This is similar to the Latex \part command
+@c
+@c ============================================================================
+@c The Tracing System
+@c ============================================================================
+@node The Tracing System
+@chapter The Tracing System
+
+@menu
+* Background::
+* Overview::
+@end menu
+
+@c ============================================================================
+@c Background
+@c ============================================================================
+@node Background
+@section Background
+
+As mentioned in the Using the Tracing System section, the whole point of running
+an @code{ns-3} simulation is to generate output for study. You have two basic
+strategies to work with in @code{ns-3}: using generic pre-defined bulk output
+mechanisms and parsing their content to extract interesting information; or
+somehow developing an output mechanism that conveys exactly (and perhaps only)
+the information wanted.
+
+Using pre-defined bulk output mechansims has the advantage of not requiring any
+changes to @code{ns-3}, but it does require programming. Often, pcap or NS_LOG
+output messages are gathered during simulation runs and separately run through
+scripts that use grep, sed or awk to parse the messages and reduce and transform
+the data to a manageable form. Programs must be written to do the
+transformation, so this does not come for free. Of course, if the information
+of interest in does not exist in any of the pre-defined output mechanisms,
+this approach fails.
+
+If you need to add some tidbit of information to the pre-defined bulk mechanisms,
+this can certainly be done; and if you use one of the @code{ns-3} mechanisms,
+you may get your code added as a contribution.
+
+@code{ns-3} provides another mechanism, called Tracing, that avoids some of the
+problems inherent in the bulk output mechanisms. It has several important
+advantages. First, you can reduce the amount of data you have to manage by only
+tracing the events of interest to you. Second, if you use this method, you can
+control the format of the output directly so you avoid the postprocessing step
+with sed or awk script. If you desire, your output can be formatted directly into
+a form acceptable by gnuplot, for example. You can add hooks in the core which
+can then be accessed by other users, but which will produce no information unless
+explicitly asked to do so. For these reasons, we believe that the @code{ns-3}
+Tracing system is the best way to get information out of a simulation and is also
+therefore one of the most important mechanisms to understand in @command{ns-3}.
+
+@subsection Blunt Instruments
+There are many ways to get information out of a program. The most
+straightforward way is to just directly print the information to the standard
+output, as in,
+
+@verbatim
+ #include <iostream>
+ ...
+ void
+ SomeFunction (void)
+ {
+ uint32_t x = SOME_INTERESTING_VALUE;
+ ...
+ std::cout << "The value of x is " << x << std::endl;
+ ...
+ }
+@end verbatim
+
+Nobody is going to prevent you from going deep into the core of @code{ns-3} and
+adding print statements. This is insanely easy to do and, after all, you have
+complete control of your own @code{ns-3} branch. This will probably not turn
+out to be very satisfactory in the long term, though.
+
+As the number of print statements increases in your programs, the task of
+dealing with the large number of outputs will become more and more complicated.
+Eventually, you may feel the need to control what information is being printed
+in some way; perhaps by turning on and off certain categories of prints, or
+increasing or decreasing the amount of information you want. If you continue
+down this path you may discover that you have re-implemented the @code{NS_LOG}
+mechanism. In order to avoid that, one of the first things you might consider
+is using @code{NS_LOG} itself.
+
+We mentioned above that one way to get information out of @code{ns-3} is to
+parse existing NS_LOG output for interesting information. If you discover that
+some tidbit of information you need is not present in existing log output, you
+could edit the core of @code{ns-3} and simply add your interesting information
+to the output stream. Now, this is certainly better than adding your own
+print statements since it follows @code{ns-3} coding conventions and could
+potentially be useful to other people as a patch to the existing core.
+
+Let's pick a random example. If you wanted to add more logging to the
+@code{ns-3} TCP socket (@code{tcp-socket-impl.cc}) you could just add a new
+message down in the implementation. Notice that in TcpSocketImpl::ProcessAction()
+there is no log message for the @code{ACK_TX} case. You could simply add one,
+changing the code from:
+
+@verbatim
+ bool TcpSocketImpl::ProcessAction (Actions_t a)
+ { // These actions do not require a packet or any TCP Headers
+ NS_LOG_FUNCTION (this << a);
+ switch (a)
+ {
+ case NO_ACT:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action: NO_ACT");
+ break;
+ case ACK_TX:
+ SendEmptyPacket (TcpHeader::ACK);
+ break;
+ ...
+@end verbatim
+
+to add a new @code{NS_LOG_LOGIC} in the appropriate @code{case} statement:
+
+@verbatim
+ bool TcpSocketImpl::ProcessAction (Actions_t a)
+ { // These actions do not require a packet or any TCP Headers
+ NS_LOG_FUNCTION (this << a);
+ switch (a)
+ {
+ case NO_ACT:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " Action: NO_ACT");
+ break;
+ case ACK_TX:
+ NS_LOG_LOGIC ("TcpSocketImpl " << this << " Action: ACK_TX");
+ SendEmptyPacket (TcpHeader::ACK);
+ break;
+ ...
+@end verbatim
+
+This may seem fairly simple and satisfying at first glance, but something to
+consider is that you will be writing code to add the @code{NS_LOG} statement
+and you will also have to write code (as in grep, sed or awk scripts) to parse
+the log output in order to isolate your information. This is because even
+though you have some control over what is output by the logging system, you
+only have control down to the log component level.
+
+If you are adding code to an existing module, you will also have to live with the
+output that every other developer has found interesting. You may find that in
+order to get the small amount of information you need, you may have to wade
+through huge amounts of extraneous messages that are of no interest to you. You
+may be forced to save huge log files to disk and process them down to a few lines
+whenever you want to do anything.
+
+Since there are no guarantees in @code{ns-3} about the stability of @code{NS_LOG}
+messages, you may also discover that pieces of log output on which you depend
+disappear or change between releases. If you depend on the structure of the
+output, you may find other messages being added or deleted which may affect your
+parsing code.
+
+For these reasons, we consider prints to @code{std::cout} and NS_LOG messages
+simple ways to get more information out of @code{ns-3}, but they are really
+unstable and quite blunt instruments.
+
+It is desirable to have a stable facility using stable APIs that allow one to
+reach into the core system and only get the information required. It is
+desirable to be able to do this without having to change and recompile the
+core system. Even better would be a system that notified the user when an item
+of interest changed or an interesting event happened so the user doesn't have
+to actively go poke around in the system looking for things.
+
+The @command{ns-3} tracing system is designed to work along those lines and is
+well-integrated with the Attribute and Config subsystems allowing for relatively
+simple use scenarios.
+
+@node Overview
+@section Overview
+
+The ns-3 tracing system is built on the concepts of independent tracing sources
+and tracing sinks; along with a uniform mechanism for connecting sources to sinks.
+
+Trace sources are entities that can signal events that happen in a simulation and
+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
+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
+of code that actually do something useful with the information provided by the source.
+The entities that consume trace information are called trace sinks. Trace sources
+are generators of events and trace sinks are consumers. This explicit division
+allows for large numbers of trace sources to be scattered around the system in
+places which model authors believe might be useful.
+
+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.
+Your code looking for trace events from a particular piece of core code could
+happily coexist with other code doing something entirely different from the same
+information.
+
+Unless a user connects a trace sink to one of these sources, nothing is output. By
+using the tracing system, both you and other people at the same trace source are
+getting exactly what they want and only what they want out of the system. Neither
+of you are impacting any other user by changing what information is output by the
+system. If you happen to add a trace source, your work as a good open-source
+citizen may allow other users to provide new utilities that are perhaps very useful
+overall, without making any changes to the @code{ns-3} core.
+
+@node A Simple Low-Level Example
+@subsection A Simple Low-Level Example
+
+Let's take a few minutes and walk through a simple tracing example. We are going
+to need a little background on Callbacks to understand what is happening in the
+example, so we have to take a small detour right away.
+
+@node Callbacks
+@subsubsection Callbacks
+
+The goal of the Callback system in @code{ns-3} is to allow one piece of code to
+call a function (or method in C++) without any specific inter-module dependency.
+This ultimately means you need some kind of indirection -- you treat the address
+of the called function as a variable. This variable is called a pointer-to-function
+variable. The relationship between function and pointer-to-function pointer is
+really no different that that of object and pointer-to-object.
+
+In C the canonical example of a pointer-to-function is a
+pointer-to-function-returning-integer (PFI). For a PFI taking one int parameter,
+this could be declared like,
+
+@verbatim
+ int (*pfi)(int arg) = 0;
+@end verbatim
+
+What you get from this is a variable named simply ``pfi'' that is initialized
+to the value 0. If you want to initialize this pointer to something meaningful,
+you have to have a function with a matching signature. In this case, you could
+provide a function that looks like,
+
+@verbatim
+ int MyFunction (int arg) {}
+@end verbatim
+
+If you have this target, you can initialize the variable to point to your
+function:
+
+@verbatim
+ pfi = MyFunction;
+@end verbatim
+
+You can then call MyFunction indirectly using the more suggestive form of
+the call,
+
+@verbatim
+ int result = (*pfi) (1234);
+@end verbatim
+
+This is suggestive since it looks like you are dereferencing the function
+pointer just like you would dereference any pointer. Typically, however,
+people take advantage of the fact that the compiler knows what is going on
+and will just use a shorter form,
+
+@verbatim
+ int result = pfi (1234);
+@end verbatim
+
+This looks like you are calling a function named ``pfi,'' but the compiler is
+smart enough to know to call through the variable @code{pfi} indirectly to
+the function @code{MyFunction}.
+
+Conceptually, this is almost exactly how the tracing system will work.
+Basically, a trace source @emph{is} a callback. When a trace sink expresses
+interest in receiving trace events, it adds a Callback to a list of Callbacks
+internally held by the trace source. When an interesting event happens, the
+trace source invokes its @code{operator()} providing zero or more parameters.
+The @code{operator()} eventually wanders down into the system and does something
+remarkably like the indirect call you just saw. It provides zero or more
+parameters (the call to ``pfi'' above passed one parameter to the target function
+@code{MyFunction}.
+
+The important difference that the tracing system adds is that for each trace
+source there is an internal list of Callbacks. Instead of just making one
+indirect call, a trace source may invoke any number of Callbacks. When a trace
+sink expresses interest in notifications from a trace source, it basically just
+arranges to add its own function to the callback list.
+
+If you are interested in more details about how this is actually arranged in
+@code{ns-3}, feel free to peruse the Callback section of the manual.
+
+@node Example Code
+@subsubsection Example Code
+
+We have provided some code to implement what is really the simplest example
+of tracing that can be assembled. You can find this code in the tutorial
+directory as @code{fourth.cc}. Let's walk through it.
+
+@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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ #include "ns3/object.h"
+ #include "ns3/uinteger.h"
+ #include "ns3/traced-value.h"
+ #include "ns3/trace-source-accessor.h"
+
+ #include <iostream>
+
+ using namespace ns3;
+@end verbatim
+
+Most of this code should be quite familiar to you. As mentioned above, the
+trace system makes heavy use of the Object and Attribute systems, so you will
+need to include them. The first two includes above bring in the declarations
+for those systems explicitly. You could use the core module header, but this
+illustrates how simple this all really is.
+
+The file, @code{traced-value.h} brings in the required declarations for tracing
+of data that obeys value semantics. In general, value semantics just means that
+you can pass the object around, not an address. In order to use value semantics
+at all you have to have an object with an associated copy constructor and
+assignment operator available. We extend the requirements to talk about the set
+of operators that are pre-defined for plain-old-data (POD) types. Operator=,
+operator++, operator---, operator+, operator==, etc.
+
+What this all really means is that you will be able to trace changes to a C++
+object made using those operators.
+
+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
+to live in. The next code snippet declares and defines a simple Object we can
+work with.
+
+@verbatim
+ class MyObject : public Object
+ {
+ public:
+ static TypeId GetTypeId (void)
+ {
+ static TypeId tid = TypeId ("MyObject")
+ .SetParent (Object::GetTypeId ())
+ .AddConstructor<MyObject> ()
+ .AddTraceSource ("MyInteger",
+ "An integer value to trace.",
+ MakeTraceSourceAccessor (&MyObject::m_myInt))
+ ;
+ return tid;
+ }
+
+ MyObject () {}
+ TracedValue<int32_t> m_myInt;
+ };
+@end verbatim
+
+The two important lines of code, above, with respect to tracing are the
+@code{.AddTraceSource} and the @code{TracedValue} declaration of @code{m_myInt}.
+
+The @code{.AddTraceSource} provides the ``hooks'' used for connecting the trace
+source to the outside world through the config system. The @code{TracedValue}
+declaration provides the infrastructure that overloads the operators mentioned
+above and drives the callback process.
+
+@verbatim
+ void
+ IntTrace (int32_t oldValue, int32_t newValue)
+ {
+ std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
+ }
+@end verbatim
+
+This is the definition of the trace sink. It corresponds directly to a callback
+function. Once it is connected, this function will be called whenever one of the
+overloaded operators of the @code{TracedValue} is executed.
+
+We have now seen the trace source and the trace sink. What remains is code to
+connect the source to the sink.
+
+@verbatim
+ int
+ main (int argc, char *argv[])
+ {
+ Ptr<MyObject> myObject = CreateObject<MyObject> ();
+ myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));
+
+ myObject->m_myInt = 1234;
+ }
+@end verbatim
+
+Here we first create the Object in which the trace source lives.
+
+The next step, the @code{TraceConnectWithoutContext}, forms the connection
+between the trace source and the trace sink. Notice the @code{MakeCallback}
+template function. This function does the magic required to create the
+underlying @code{ns-3} Callback object and associate it with the function
+@code{IntTrace}. TraceConnect makes the association between your provided
+function and the overloaded @code{operator()} in the traced variable referred
+to by the ``MyInteger'' Attribute. After this association is made, the trace
+source will ``fire'' your provided callback function.
+
+The code to make all of this happen is, of course, non-trivial, but the essence
+is that you are arranging for something that looks just like the @code{pfi()}
+example above to be called by the trace source. The declaration of the
+@code{TracedValue<int32_t> m_myInt;} in the Object itself performs the magic
+needed to provide the overloaded operators (++, ---, etc.) that will use the
+@code{operator()} to actually invoke the Callback with the desired parameters.
+The @code{.AddTraceSource} performs the magic to connect the Callback to the
+Config system, and @code{TraceConnectWithoutContext} performs the magic to
+connect your function to the trace source, which is specified by Attribute
+name.
+
+Let's ignore the bit about context for now.
+
+Finally, the line,
+
+@verbatim
+ myObject->m_myInt = 1234;
+@end verbatim
+
+should be interpreted as an invocation of @code{operator=} on the member
+variable @code{m_myInt} with the integer @code{1234} passed as a parameter.
+
+It turns out that this operator is defined (by @code{TracedValue}) to execute
+a callback that returns void and takes two integer values as parameters ---
+an old value and a new value for the integer in question. That is exactly
+the function signature for the callback function we provided --- @code{IntTrace}.
+
+To summarize, a trace source is, in essence, a variable that holds a list of
+callbacks. A trace sink is a function used as the target of a callback. The
+Attribute and object type information systems are used to provide a way to
+connect trace sources to trace sinks. The act of ``hitting'' a trace source
+is executing an operator on the trace source which fires callbacks. This
+results in the trace sink callbacks registering interest in the source being
+called with the parameters provided by the source.
+
+If you now build and run this example,
+
+@verbatim
+ ./waf --run fourth
+@end verbatim
+
+you will see the output from the @code{IntTrace} function execute as soon as the
+trace source is hit:
+
+@verbatim
+ Traced 0 to 1234
+@end verbatim
+
+When we executed the code, @code{myObject->m_myInt = 1234;}, the trace source
+fired and automatically provided the before and after values to the trace sink.
+The function @code{IntTrace} then printed this to the standard output. No
+problem.
+
+@subsection Using the Config Subsystem to Connect to Trace Sources
+
+The @code{TraceConnectWithoutContext} call shown above in the simple example is
+actually very rarely used in the system. More typically, the @code{Config}
+subsystem is used to allow selecting a trace source in the system using what is
+called a @emph{config path}. We saw an example of this in the previous section
+where we hooked the ``CourseChange'' event when we were playing with
+@code{third.cc}.
+
+Recall that we defined a trace sink to print course change information from the
+mobility models of our simulation. It should now be a lot more clear to you
+what this function is doing.
+
+@verbatim
+ void
+ CourseChange (std::string context, Ptr<const MobilityModel> model)
+ {
+ Vector position = model->GetPosition ();
+ NS_LOG_UNCOND (context <<
+ " x = " << position.x << ", y = " << position.y);
+ }
+@end verbatim
+
+When we connected the ``CourseChange'' trace source to the above trace sink,
+we used what is called a ``Config Path'' to specify the source when we
+arranged a connection between the pre-defined trace source and the new trace
+sink:
+
+@verbatim
+ std::ostringstream oss;
+ oss <<
+ "/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () <<
+ "/$ns3::MobilityModel/CourseChange";
+
+ Config::Connect (oss.str (), MakeCallback (&CourseChange));
+@end verbatim
+
+Let's try and make some sense of what is sometimes considered relatively
+mysterious code. For the purposes of discussion, assume that the node
+number returned by the @code{GetId()} is ``7''. In this case, the path
+above turns out to be,
+
+@verbatim
+ "/NodeList/7/$ns3::MobilityModel/CourseChange"
+@end verbatim
+
+The last segment of a config path must be an @code{Attribute} of an
+@code{Object}. In fact, if you had a pointer to the @code{Object} that has the
+``CourseChange'' @code{Attribute} handy, you could write this just like we did
+in the previous example. You know by now that we typically store pointers to
+our nodes in a NodeContainer. In the @code{third.cc} example, the Nodes of
+interest are stored in the @code{wifiStaNodes} NodeContainer. In fact, while
+putting the path together, we used this container to get a Ptr<Node> which we
+used to call GetId() on. We could have used this Ptr<Node> directly to call
+a connect method directly:
+
+@verbatim
+ Ptr<Object> theObject = wifiStaNodes.Get (nWifi - 1);
+ theObject->TraceConnectWithoutContext ("CourseChange", MakeCallback (&CourseChange));
+@end verbatim
+
+In the @code{third.cc} example, we actually want an additional ``context'' to
+be delivered along with the Callback parameters (which will be explained below) so we
+could actually use the following equivalent code,
+
+@verbatim
+ Ptr<Object> theObject = wifiStaNodes.Get (nWifi - 1);
+ theObject->TraceConnect ("CourseChange", MakeCallback (&CourseChange));
+@end verbatim
+
+It turns out that the internal code for @code{Config::ConnectWithoutContext} and
+@code{Config::Connect} actually do find a Ptr<Object> and call the appropriate
+TraceConnect method at the lowest level.
+
+The @code{Config} functions take a path that represents a chain of @code{Object}
+pointers. Each segment of a path corresponds to an Object Attribute. The last
+segment is the Attribute of interest, and prior segments must be typed to contain
+or find Objects. The @code{Config} code parses and ``walks'' this path until it
+gets to the final segment of the path. It then interprets the last segment as
+an @code{Attribute} on the last Object it found while walking the path. The
+@code{Config} functions then call the appropriate @code{TraceConnect} or
+@code{TraceConnectWithoutContext} method on the final Object. Let's see what
+happens in a bit more detail when the above path is walked.
+
+The leading ``/'' character in the path refers to a so-called namespace. One
+of the predefined namespaces in the config system is ``NodeList'' which is a
+list of all of the nodes in the simulation. Items in the list are referred to
+by indices into the list, so ``/NodeList/7'' refers to the eighth node in the
+list of nodes created during the simulation. This reference is actually a
+@code{Ptr<Node>} and so is a subclass of an @code{ns3::Object}.
+
+As described in the Object Model section of the @code{ns-3} manual, we support
+Object Aggregation. This allows us to form an association between different
+Objects without any programming. Each Object in an Aggregation can be reached
+from the other Objects.
+
+The next path segment being walked begins with the ``$'' character. This
+indicates to the config system that a @code{GetObject} call should be made
+looking for the type that follows. It turns out that the MobilityHelper used in
+@code{third.cc} arranges to Aggregate, or associate, a mobility model to each of
+the wireless Nodes. When you add the ``$'' you are asking for another Object that
+has presumably been previously aggregated. You can think of this as switching
+pointers from the original Ptr<Node> as specified by ``/NodeList/7'' to its
+associated mobility model --- which is of type ``$ns3::MobilityModel''. If you
+are familiar with @code{GetObject}, we have asked the system to do the following:
+
+@verbatim
+ Ptr<MobilityModel> mobilityModel = node->GetObject<MobilityModel> ()
+@end verbatim
+
+We are now at the last Object in the path, so we turn our attention to the
+Attributes of that Object. The @code{MobilityModel} class defines an Attribute
+called ``CourseChange.'' You can see this by looking at the source code in
+@code{src/mobility/mobility-model.cc} and searching for ``CourseChange'' in your
+favorite editor. You should find,
+
+@verbatim
+ .AddTraceSource (``CourseChange'',
+ ``The value of the position and/or velocity vector changed'',
+ MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace))
+@end verbatim
+
+which should look very familiar at this point.
+
+If you look for the corresponding declaration of the underlying traced variable
+in @code{mobility-model.h} you will find
+
+@verbatim
+ TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
+@end verbatim
+
+The type declaration @code{TracedCallback} identifies @code{m_courseChangeTrace}
+as a special list of Callbacks that can be hooked using the Config functions
+described above.
+
+The @code{MobilityModel} class is designed to be a base class providing a common
+interface for all of the specific subclasses. If you search down to the end of
+the file, you will see a method defined called @code{NotifyCourseChange()}:
+
+@verbatim
+ void
+ MobilityModel::NotifyCourseChange (void) const
+ {
+ m_courseChangeTrace(this);
+ }
+@end verbatim
+
+Derived classes will call into this method whenever they do a course change to
+support tracing. This method invokes @code{operator()} on the underlying
+@code{m_courseChangeTrace}, which will, in turn, invoke all of the registered
+Callbacks, calling all of the trace sinks that have registered interest in the
+trace source by calling a Config function.
+
+So, in the @code{third.cc} example we looked at, whenever a course change is
+made in one of the @code{RandomWalk2dMobilityModel} instances installed, there
+will be a @code{NotifyCourseChange()} call which calls up into the
+@code{MobilityModel} base class. As seen above, this invokes @code{operator()}
+on @code{m_courseChangeTrace}, which in turn, calls any registered trace sinks.
+In the example, the only code registering an interest was the code that provided
+the config path. Therefore, the @code{CourseChange} function that was hooked
+from Node number seven will be the only Callback called.
+
+The final piece of the puzzle is the ``context.'' Recall that we saw an output
+looking something like the following from @code{third.cc}:
+
+@verbatim
+ /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y = 2.22677
+@end verbatim
+
+The first part of the output is the context. It is simply the path through
+which the config code located the trace source. In the case we have been looking at
+there can be any number of trace sources in the system corresponding to any number
+of nodes with mobility models. There needs to be some way to identify which trace
+source is actually the one that fired the Callback. An easy way is to request a
+trace context when you @code{Config::Connect}.
+
+@subsection How to Find and Connect Trace Sources, and Discover Callback Signatures
+
+The first question that inevitably comes up for new users of the Tracing system is,
+``okay, I know that there must be trace sources in the simulation core, but how do
+I find out what trace sources are available to me''?
+
+The second question is, ``okay, I found a trace source, how do I figure out the
+config path to use when I connect to it''?
+
+The third question is, ``okay, I found a trace source, how do I figure out what
+the return type and formal arguments of my callback function need to be''?
+
+The fourth question is, ``okay, I typed that all in and got this incredibly bizarre
+error message, what in the world does it mean''?
+
+@subsection What Trace Sources are Available?
+
+The answer to this question is found in the @code{ns-3} Doxygen. Go to the
+@code{ns-3} web site @uref{http://www.nsnam.org/getting_started.html,,``here''}
+and select the ``Doxygen (stable)'' link ``Documentation'' on the navigation
+bar to the left side of the page. Expand the ``Modules'' book in the NS-3
+documentation tree a the upper left by clicking the ``+'' box. Now, expand
+the ``Core'' book in the tree by clicking its ``+'' box. You should now
+see three extremely useful links:
+
+@itemize @bullet
+@item The list of all trace sources
+@item The list of all attributes
+@item The list of all global values
+@end itemize
+
+The list of interest to us here is ``the list of all trace sources.'' Go
+ahead and select that link. You will see, perhaps not too surprisingly, a
+list of all of the trace sources available in the @code{ns-3} core.
+
+As an example, scroll down to @code{ns3::MobilityModel}. You will find
+an entry for
+
+@verbatim
+ CourseChange: The value of the position and/or velocity vector changed
+@end verbatim
+
+You should recognize this as the trace source we used in the @code{third.cc}
+example. Perusing this list will be helpful.
+
+@subsection What String do I use to Connect?
+
+The easiest way to do this is to grep around in the @code{ns-3} codebase for someone
+who has already figured it out, You should always try to copy someone else's
+working code before you start to write your own. Try something like:
+
+@verbatim
+ find . -name '*.cc' | xargs grep CourseChange | grep Connect
+@end verbatim
+
+and you may find your answer along with working code. For example, in this
+case, @code{./ns-3-dev/examples/wireless/mixed-wireless.cc} has something
+just waiting for you to use:
+
+@verbatim
+ Config::Connect (``/NodeList/*/$ns3::MobilityModel/CourseChange'',
+ MakeCallback (&CourseChangeCallback));
+@end verbatim
+
+If you cannot find any examples in the distribution, you can find this out
+from the @code{ns-3} Doxygen. It will probably be simplest just to walk
+through the ``CourseChanged'' example.
+
+Let's assume that you have just found the ``CourseChanged'' trace source in
+``The list of all trace sources'' and you want to figure out how to connect to
+it. You know that you are using (again, from the @code{third.cc} example) an
+@code{ns3::RandomWalk2dMobilityModel}. So open the ``Class List'' book in
+the NS-3 documentation tree by clicking its ``+'' box. You will now see a
+list of all of the classes in @code{ns-3}. Scroll down until you see the
+entry for @code{ns3::RandomWalk2dMobilityModel} and follow that link.
+You should now be looking at the ``ns3::RandomWalk2dMobilityModel Class
+Reference.''
+
+If you now scroll down to the ``Member Function Documentation'' section, you
+will see documentation for the @code{GetTypeId} function. You constructed one
+of these in the simple tracing example above:
+
+@verbatim
+ static TypeId GetTypeId (void)
+ {
+ static TypeId tid = TypeId ("MyObject")
+ .SetParent (Object::GetTypeId ())
+ .AddConstructor<MyObject> ()
+ .AddTraceSource ("MyInteger",
+ "An integer value to trace.",
+ MakeTraceSourceAccessor (&MyObject::m_myInt))
+ ;
+ return tid;
+ }
+@end verbatim
+
+As mentioned above, this is the bit of code that connected the Config
+and Attribute systems to the underlying trace source. This is also the
+place where you should start looking for information about the way to
+connect.
+
+You are looking at the same information for the RandomWalk2dMobilityModel; and
+the information you want is now right there in front of you in the Doxygen:
+
+@verbatim
+ This object is accessible through the following paths with Config::Set and Config::Connect:
+
+ /NodeList/[i]/$ns3::MobilityModel/$ns3::RandomWalk2dMobilityModel
+@end verbatim
+
+The documentation tells you how to get to the @code{RandomWalk2dMobilityModel}
+Object. Compare the string above with the string we actually used in the
+example code:
+
+@verbatim
+ "/NodeList/7/$ns3::MobilityModel"
+@end verbatim
+
+The difference is due to the fact that two @code{GetObject} calls are implied
+in the string found in the documentation. The first, for @code{$ns3::MobilityModel}
+will query the aggregation for the base class. The second implied
+@code{GetObject} call, for @code{$ns3::RandomWalk2dMobilityModel}, is used to ``cast''
+the base class to the concrete imlementation class. The documentation shows
+both of these operations for you. It turns out that the actual Attribute you are
+going to be looking for is found in the base class as we have seen.
+
+Look further down in the @code{GetTypeId} doxygen. You will find,
+
+@verbatim
+ No TraceSources defined for this type.
+ TraceSources defined in parent class ns3::MobilityModel:
+
+ CourseChange: The value of the position and/or velocity vector changed
+ Reimplemented from ns3::MobilityModel
+@end verbatim
+
+This is exactly what you need to know. The trace source of interest is found in
+@code{ns3::MobilityModel} (which you knew anyway). The interesting thing this
+bit of Doxygen tells you is that you don't need that extra cast in the config
+path above to get to the concrete class, since the trace source is actually in
+the base class. Therefore the additional @code{GetObject} is not required and
+you simply use the path:
+
+@verbatim
+ /NodeList/[i]/$ns3::MobilityModel
+@end verbatim
+
+which perfectly matches the example path:
+
+@verbatim
+ /NodeList/7/$ns3::MobilityModel
+@end verbatim
+
+@subsection What Return Value and Formal Arguments?
+
+The easiest way to do this is to grep around in the @code{ns-3} codebase for someone
+who has already figured it out, You should always try to copy someone else's
+working code. Try something like:
+
+@verbatim
+ find . -name '*.cc' | xargs grep CourseChange | grep Connect
+@end verbatim
+
+and you may find your answer along with working code. For example, in this
+case, @code{./ns-3-dev/examples/wireless/mixed-wireless.cc} has something
+just waiting for you to use. You will find
+
+@verbatim
+ Config::Connect (``/NodeList/*/$ns3::MobilityModel/CourseChange'',
+ MakeCallback (&CourseChangeCallback));
+@end verbatim
+
+as a result of your grep. The @code{MakeCallback} should indicate to you that
+there is a callback function there which you can use. Sure enough, there is:
+
+@verbatim
+ static void
+ CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
+ {
+ ...
+ }
+@end verbatim
+
+@subsubsection Take my Word for It
+
+If there are no examples to work from, this can be, well, challenging to
+actually figure out from the source code.
+
+Before embarking on a walkthrough of the code, I'll be kind and just tell you
+a simple way to figure this out: The return value of your callback will always
+be void. The formal parameter list for a @code{TracedCallback} can be found
+from the template parameter list in the declaration. Recall that for our
+current example, this is in @code{mobility-model.h}, where we have previously
+found:
+
+@verbatim
+ TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
+@end verbatim
+
+There is a one-to-one correspondence between the template parameter list in
+the declaration and the formal arguments of the callback function. Here,
+there is one template parameter, which is a @code{Ptr<const MobilityModel>}.
+This tells you that you need a function that returns void and takes a
+a @code{Ptr<const MobilityModel>}. For example,
+
+@verbatim
+ void
+ CourseChangeCallback (Ptr<const MobilityModel> model)
+ {
+ ...
+ }
+@end verbatim
+
+That's all you need if you want to @code{Config::ConnectWithoutContext}. If
+you want a context, you need to @code{Config::Connect} and use a Callback
+function that takes a string context, then the required argument.
+
+@verbatim
+ void
+ CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
+ {
+ ...
+ }
+@end verbatim
+
+If you want to ensure that your @code{CourseChangeCallback} is only visible
+in your local file, you can add the keyword @code{static} and come up with:
+
+@verbatim
+ static void
+ CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
+ {
+ ...
+ }
+@end verbatim
+
+which is exactly what we used in the @code{third.cc} example.
+
+@subsubsection The Hard Way
+
+This section is entirely optional. It is going to be a bumpy ride, especially
+for those unfamiliar with the details of templates. However, if you get through
+this, you will have a very good handle on a lot of the @code{ns-3} low level
+idioms.
+
+So, again, let's figure out what signature of callback function is required for
+the ``CourseChange'' Attribute. This is going to be painful, but you only need
+to do this once. After you get through this, you will be able to just look at
+a @code{TracedCallback} and understand it.
+
+The first thing we need to look at is the declaration of the trace source.
+Recall that this is in @code{mobility-model.h}, where we have previously
+found:
+
+@verbatim
+ TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
+@end verbatim
+
+This declaration is for a template. The template parameter is inside the
+angle-brackets, so we are really interested in finding out what that
+@code{TracedCallback<>} is. If you have absolutely no idea where this might
+be found, grep is your friend.
+
+We are probably going to be interested in some kind of declaration in the
+@code{ns-3} source, so first change into the @code{src} directory. Then,
+we know this declaration is going to have to be in some kind of header file,
+so just grep for it using:
+
+@verbatim
+ find . -name '*.h' | xargs grep TracedCallback
+@end verbatim
+
+You'll see 124 lines fly by (I piped this through wc to see how bad it was).
+Although that may seem like it, that's not really a lot. Just pipe the output
+through more and start scanning through it. On the first page, you will see
+some very suspiciously template-looking stuff.
+
+@verbatim
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::TracedCallback ()
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext (c ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Connect (const CallbackB ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::DisconnectWithoutContext ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Disconnect (const Callba ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (void) const ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1) const ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
+@end verbatim
+
+It turns out that all of this comes from the header file
+@code{traced-callback.h} which sounds very promising. You can then take a
+look at @code{mobility-model.h} and see that there is a line which confirms
+this hunch:
+
+@verbatim
+ #include "ns3/traced-callback.h"
+@end verbatim
+
+Of course, you could have gone at this from the other direction and started
+by looking at the includes in @code{mobility-model.h} and noticing the
+include of @code{traced-callback.h} and inferring that this must be the file
+you want.
+
+In either case, the next step is to take a look at @code{src/core/traced-callback.h}
+in your favorite editor to see what is happening.
+
+You will see a comment at the top of the file that should be comforting:
+
+@verbatim
+ An ns3::TracedCallback has almost exactly the same API as a normal ns3::Callback but
+ instead of forwarding calls to a single function (as an ns3::Callback normally does),
+ it forwards calls to a chain of ns3::Callback.
+@end verbatim
+
+This should sound very familiar and let you know you are on the right track.
+
+Just after this comment, you will find,
+
+@verbatim
+ template<typename T1 = empty, typename T2 = empty,
+ typename T3 = empty, typename T4 = empty,
+ typename T5 = empty, typename T6 = empty,
+ typename T7 = empty, typename T8 = empty>
+ class TracedCallback
+ {
+ ...
+@end verbatim
+
+This tells you that TracedCallback is a templated class. It has eight possible
+type parameters with default values. Go back and compare this with the
+declaration you are trying to understand:
+
+@verbatim
+ TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
+@end verbatim
+
+The @code{typename T1} in the templated class declaration corresponds to the
+@code{Ptr<const MobilityModel>} in the declaration above. All of the other
+type parameters are left as defaults. Looking at the constructor really
+doesn't tell you much. The one place where you have seen a connection made
+between your Callback function and the tracing system is in the @code{Connect}
+and @code{ConnectWithoutContext} functions. If you scroll down, you will see
+a @code{ConnectWithoutContext} method here:
+
+@verbatim
+ template<typename T1, typename T2,
+ typename T3, typename T4,
+ typename T5, typename T6,
+ typename T7, typename T8>
+ void
+ TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext ...
+ {
+ Callback<void,T1,T2,T3,T4,T5,T6,T7,T8> cb;
+ cb.Assign (callback);
+ m_callbackList.push_back (cb);
+ }
+@end verbatim
+
+You are now in the belly of the beast. When the template is instantiated for
+the declaration above, the compiler will replace @code{T1} with
+@code{Ptr<const MobilityModel>}.
+
+@verbatim
+ void
+ TracedCallback<Ptr<const MobilityModel>::ConnectWithoutContext ... cb
+ {
+ Callback<void, Ptr<const MobilityModel> > cb;
+ cb.Assign (callback);
+ m_callbackList.push_back (cb);
+ }
+@end verbatim
+
+You can now see the implementation of everything we've been talking about. The
+code creates a Callback of the right type and assigns your function to it. This
+is the equivalent of the @code{pfi = MyFunction} we discussed at the start of
+this section. The code then adds the Callback to the list of Callbacks for
+this source. The only thing left is to look at the definition of Callback.
+Using the same grep trick as we used to find @code{TracedCallback}, you will be
+able to find that the file @code{./core/callback.h} is the one we need to look at.
+
+If you look down through the file, you will see a lot of probably almost
+incomprehensible template code. You will eventually come to some Doxygen for
+the Callback template class, though. Fortunately, there is some English:
+
+@verbatim
+ This class template implements the Functor Design Pattern.
+ It is used to declare the type of a Callback:
+ - the first non-optional template argument represents
+ the return type of the callback.
+ - the second optional template argument represents
+ the type of the first argument to the callback.
+ - the third optional template argument represents
+ the type of the second argument to the callback.
+ - the fourth optional template argument represents
+ the type of the third argument to the callback.
+ - the fifth optional template argument represents
+ the type of the fourth argument to the callback.
+ - the sixth optional template argument represents
+ the type of the fifth argument to the callback.
+@end verbatim
+
+We are trying to figure out what the
+
+@verbatim
+ Callback<void, Ptr<const MobilityModel> > cb;
+@end verbatim
+
+declaration means. Now we are in a position to understand that the first
+(non-optional) parameter, @code{void}, represents the return type of the
+Callback. The second (non-optional) parameter, @code{Ptr<const MobilityModel>}
+represents the first argument to the callback.
+
+The Callback in question is your function to receive the trace events. From
+this you can infer that you need a function that returns @code{void} and takes
+a @code{Ptr<const MobilityModel>}. For example,
+
+@verbatim
+ void
+ CourseChangeCallback (Ptr<const MobilityModel> model)
+ {
+ ...
+ }
+@end verbatim
+
+That's all you need if you want to @code{Config::ConnectWithoutContext}. If
+you want a context, you need to @code{Config::Connect} and use a Callback
+function that takes a string context. This is because the @code{Connect}
+function will provide the context for you. You'll need:
+
+@verbatim
+ void
+ CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
+ {
+ ...
+ }
+@end verbatim
+
+If you want to ensure that your @code{CourseChangeCallback} is only visible
+in your local file, you can add the keyword @code{static} and come up with:
+
+@verbatim
+ static void
+ CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
+ {
+ ...
+ }
+@end verbatim
+
+which is exactly what we used in the @code{third.cc} example. Perhaps you
+should now go back and reread the previous section (Take My Word for It).
+
+If you are interested in more details regarding the implementation of
+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 int32_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 (int32_t oldValue, int32_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 first 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 executed; 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 dissecting
+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 complete. 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 packets 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 something 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 (1)->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.684s)
+ 1.20919 1072
+ 1.21511 1608
+ 1.22103 2144
+ ...
+ 1.2471 8040
+ 1.24895 8576
+ 1.2508 9112
+ RxDrop at 1.25151
+ ...
+@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 640,480
+ 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}
+
+
--- a/doc/tutorial/tutorial.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/tutorial/tutorial.texi Mon Oct 26 09:21:20 2009 +0300
@@ -84,6 +84,9 @@
* Conceptual Overview::
* Tweaking ns-3::
* Building Topologies::
+* The Tracing System::
+* Closing Remarks::
+* Index::
@end menu
@include introduction.texi
@@ -92,7 +95,10 @@
@include tweaking.texi
@include building-topologies.texi
@include tracing.texi
+@include conclusion.texi
+@node Index
+@unnumbered Index
@printindex cp
@bye
--- a/doc/tutorial/tweaking.texi Thu Oct 22 17:17:40 2009 +0400
+++ b/doc/tutorial/tweaking.texi Mon Oct 26 09:21:20 2009 +0300
@@ -100,8 +100,8 @@
program
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.413s)
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
@@ -150,8 +150,8 @@
system will pick up the change and you should see the following output:
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
@@ -205,8 +205,8 @@
name.
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.417s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
@@ -242,8 +242,8 @@
in debugging problems.
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.406s)
UdpEchoServerApplication:UdpEchoServer()
UdpEchoClientApplication:UdpEchoClient()
@@ -277,8 +277,8 @@
you should see the following output:
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
@@ -410,8 +410,8 @@
message,
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
Creating Topology
Sent 1024 bytes to 10.1.1.2
@@ -465,8 +465,8 @@
now see the @code{--PrintHelp} argument and respond with,
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.413s)
TcpL4Protocol:TcpStateMachine()
CommandLine:HandleArgument(): Handle arg name=PrintHelp value=
@@ -542,8 +542,8 @@
If you run the script, you should now see the following output,
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.405s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
@@ -606,8 +606,8 @@
@code{DataRate} and @code{Delay} in the script:
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/bu
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/bui
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.417s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
@@ -684,8 +684,8 @@
@end verbatim
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.403s)
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
@@ -707,8 +707,8 @@
You should now see
@verbatim
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-3.5-tutorial/ns-3-dev/build'
+ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+ Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
--- a/examples/tap/tap-wifi-dumbbell.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/examples/tap/tap-wifi-dumbbell.cc Mon Oct 26 09:21:20 2009 +0300
@@ -81,17 +81,7 @@
// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev thetap gw 10.1.1.2
// ping 10.1.3.4
//
-// 4) Try to run this in UseLocal mode. This allows you to provide an existing
-// pre-configured tap device to the simulation. The IP address and MAC
-// address in this mode do not have to match those of the ns-3 device.
-//
-// sudo tunctl -t mytap
-// sudo ifconfig mytap hw ether 08:00:2e:00:00:01
-// sudo ifconfig mytap 10.1.1.1 netmask 255.255.255.0 up
-// ./waf --run "tap-wifi-dumbbell --mode=UseLocal --tapName=mytap"&
-// ping 10.1.1.3
-//
-// 5) Try to run this in UseBridge mode. This allows you to bridge an ns-3
+// 4) Try to run this in UseBridge mode. This allows you to bridge an ns-3
// simulation to an existing pre-configured bridge. This uses tap devices
// just for illustration, you can create your own bridge if you want.
//
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/tutorial/fifth.cc Mon Oct 26 09:21:20 2009 +0300
@@ -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 ("5Mbps"));
+ 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 ("1Mbps"));
+ 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;
+}
+
--- a/examples/tutorial/wscript Thu Oct 22 17:17:40 2009 +0400
+++ b/examples/tutorial/wscript Mon Oct 26 09:21:20 2009 +0300
@@ -15,3 +15,6 @@
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'
--- a/src/common/pcap-file-test-suite.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/common/pcap-file-test-suite.cc Mon Oct 26 09:21:20 2009 +0300
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
+#include <cstring>
#include "ns3/test.h"
#include "ns3/pcap-file.h"
@@ -175,6 +176,7 @@
// data.
//
uint8_t buffer[128];
+ memset(buffer, 0, sizeof(buffer));
err = f.Write (0, 0, buffer, 128);
NS_TEST_ASSERT_MSG_EQ (err, false, "Write (write-only-file " << m_testFilename << ") returns error");
@@ -370,6 +372,7 @@
// We should be able to write to it since it was opened in "a" mode.
//
uint8_t buffer[128];
+ memset(buffer, 0, sizeof(buffer));
err = f.Write (0, 0, buffer, 128);
NS_TEST_ASSERT_MSG_EQ (err, false, "Write (append-mode-file " << m_testFilename << ") returns error");
--- a/src/devices/bridge/bridge-channel.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/bridge/bridge-channel.cc Mon Oct 26 09:21:20 2009 +0300
@@ -44,8 +44,16 @@
BridgeChannel::~BridgeChannel ()
{
NS_LOG_FUNCTION_NOARGS ();
+
+ for (std::vector< Ptr<Channel> >::iterator iter = m_bridgedChannels.begin ();
+ iter != m_bridgedChannels.end (); iter++)
+ {
+ *iter = 0;
+ }
+ m_bridgedChannels.clear ();
}
+
void
BridgeChannel::AddChannel (Ptr<Channel> bridgedChannel)
{
--- a/src/devices/mesh/dot11s/airtime-metric.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/airtime-metric.cc Mon Oct 26 09:21:20 2009 +0300
@@ -31,7 +31,7 @@
.SetParent<Object> ()
.AddConstructor<AirtimeLinkMetricCalculator> ()
.AddAttribute ( "OverheadNanosec",
- "Overhead expressed in nanoseconds:DIFS+ 2* SIFS + 2* PREAMBLE + 2* ACK",
+ "Overhead expressed in nanoseconds:DIFS+ SIFS + 2 * PREAMBLE + ACK",
UintegerValue (108000),
MakeUintegerAccessor (&AirtimeLinkMetricCalculator::m_overheadNanosec),
MakeUintegerChecker<uint32_t> (1)
@@ -80,9 +80,9 @@
WifiRemoteStation * station = mac->GetStationManager ()->Lookup (peerAddress);
NS_ASSERT (station != 0);
- Ptr<Packet> test_frame = Create<Packet> (m_testLength + m_headerLength + m_meshHeaderLength);
+ Ptr<Packet> test_frame = Create<Packet> (m_testLength + m_meshHeaderLength);
uint32_t rate =
- station->GetDataMode (test_frame, m_testLength + m_headerLength + m_meshHeaderLength).GetDataRate ();
+ station->GetDataMode (test_frame, m_testLength + m_meshHeaderLength).GetDataRate ();
uint32_t payload_nanosec = (uint32_t) (
(double) ((m_testLength + m_meshHeaderLength) * 8 /*octets -> bits*/) * sec2ns / ((double) rate));
uint32_t header_nanosec = (uint32_t) ((double) (m_headerLength * 8 /*octets -> bits*/* sec2ns)
--- a/src/devices/mesh/dot11s/airtime-metric.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/airtime-metric.h Mon Oct 26 09:21:20 2009 +0300
@@ -45,13 +45,13 @@
static TypeId GetTypeId ();
uint32_t CalculateMetric (Mac48Address peerAddress, Ptr<MeshWifiInterfaceMac> mac);
private:
- //\brief Overhead expressed in nanoseconds:DIFS+ 2* SIFS + 2*PREAMBLE + 2* ACK
+ /// Overhead expressed in nanoseconds:DIFS + SIFS + 2 * PREAMBLE + ACK
uint32_t m_overheadNanosec;
- ///\brief Bt value
+ /// Bt value
uint32_t m_testLength;
- ///\brief header length (used in overhead)
+ /// header length (used in overhead)
uint16_t m_headerLength;
- ///\brief meshHeader length (6 octets usually)
+ /// meshHeader length (minimum 6 octets)
uint16_t m_meshHeaderLength;
};
} //namespace dot11s
--- a/src/devices/mesh/dot11s/hwmp-protocol-mac.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/hwmp-protocol-mac.cc Mon Oct 26 09:21:20 2009 +0300
@@ -357,7 +357,12 @@
//Send Management frame
for (std::vector<Mac48Address>::const_iterator i = receivers.begin (); i != receivers.end (); i++)
{
- hdr.SetAddr1 (*i);
+ //
+ // 64-bit Intel valgrind complains about hdr.SetAddr1 (*i). It likes this
+ // just fine.
+ //
+ Mac48Address address = *i;
+ hdr.SetAddr1 (address);
m_stats.txPerr++;
m_stats.txMgt++;
m_stats.txMgtBytes += packet->GetSize ();
--- a/src/devices/mesh/dot11s/hwmp-protocol.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/hwmp-protocol.cc Mon Oct 26 09:21:20 2009 +0300
@@ -33,6 +33,7 @@
#include "airtime-metric.h"
#include "ie-dot11s-preq.h"
#include "ie-dot11s-prep.h"
+#include "ns3/trace-source-accessor.h"
#include "ie-dot11s-perr.h"
NS_LOG_COMPONENT_DEFINE ("HwmpProtocol");
@@ -157,7 +158,13 @@
MakeBooleanAccessor (
&HwmpProtocol::m_rfFlag),
MakeBooleanChecker ()
- );
+ )
+ .AddTraceSource ( "RouteDiscoveryTime",
+ "The time of route discovery procedure",
+ MakeTraceSourceAccessor (
+ &HwmpProtocol::m_routeDiscoveryTimeCallback)
+ )
+ ;
return tid;
}
@@ -184,6 +191,7 @@
m_doFlag (false),
m_rfFlag (false)
{
+ NS_LOG_FUNCTION_NOARGS ();
if (m_isRoot)
{
@@ -193,21 +201,25 @@
HwmpProtocol::~HwmpProtocol ()
{
+ NS_LOG_FUNCTION_NOARGS ();
}
void
HwmpProtocol::DoDispose ()
{
- for (std::map<Mac48Address, EventId>::iterator i = m_preqTimeouts.begin (); i != m_preqTimeouts.end (); i ++)
+ NS_LOG_FUNCTION_NOARGS ();
+ for (std::map<Mac48Address, PreqEvent>::iterator i = m_preqTimeouts.begin (); i != m_preqTimeouts.end (); i ++)
{
- i->second.Cancel ();
+ i->second.preqTimeout.Cancel ();
}
m_proactivePreqTimer.Cancel();
m_preqTimeouts.clear ();
m_lastDataSeqno.clear ();
- m_lastHwmpSeqno.clear ();
+ m_hwmpSeqnoMetricDatabase.clear ();
+ m_interfaces.clear ();
m_rqueue.clear ();
m_rtable = 0;
+ m_mp = 0;
}
bool
@@ -274,7 +286,12 @@
for (std::vector<Mac48Address>::const_iterator i = receivers.begin (); i != receivers.end (); i ++)
{
Ptr<Packet> packetCopy = packet->Copy();
- tag.SetAddress (*i);
+ //
+ // 64-bit Intel valgrind complains about tag.SetAddress (*i). It
+ // likes this just fine.
+ //
+ Mac48Address address = *i;
+ tag.SetAddress (address);
packetCopy->AddPacketTag (tag);
routeReply (true, packetCopy, source, destination, protocolType, plugin->first);
}
@@ -382,31 +399,24 @@
{
preq.IncrementMetric (metric);
//acceptance cretirea:
- std::map<Mac48Address, uint32_t>::const_iterator i = m_lastHwmpSeqno.find (preq.GetOriginatorAddress());
- if (i == m_lastHwmpSeqno.end ())
+ std::map<Mac48Address, std::pair<uint32_t, uint32_t> >::const_iterator i = m_hwmpSeqnoMetricDatabase.find (
+ preq.GetOriginatorAddress ());
+ if (i != m_hwmpSeqnoMetricDatabase.end ())
{
- m_lastHwmpSeqno[preq.GetOriginatorAddress ()] = preq.GetOriginatorSeqNumber ();
- m_lastHwmpMetric[preq.GetOriginatorAddress ()] = preq.GetMetric ();
- }
- else
- {
- if ((int32_t)(i->second - preq.GetOriginatorSeqNumber ()) > 0)
+ if ((int32_t)(i->second.first - preq.GetOriginatorSeqNumber ()) > 0)
{
return;
}
- if (i->second == preq.GetOriginatorSeqNumber ())
+ if (i->second.first == preq.GetOriginatorSeqNumber ())
{
- //find metric
- std::map<Mac48Address, uint32_t>::const_iterator j = m_lastHwmpMetric.find (preq.GetOriginatorAddress());
- NS_ASSERT (j != m_lastHwmpSeqno.end ());
- if (j->second <= preq.GetMetric ())
+ if (i->second.second <= preq.GetMetric ())
{
return;
}
}
- m_lastHwmpSeqno[preq.GetOriginatorAddress ()] = preq.GetOriginatorSeqNumber ();
- m_lastHwmpMetric[preq.GetOriginatorAddress ()] = preq.GetMetric ();
}
+ m_hwmpSeqnoMetricDatabase[preq.GetOriginatorAddress ()] = std::make_pair (preq.GetOriginatorSeqNumber (), preq.GetMetric ());
+
NS_LOG_DEBUG("I am " << GetAddress () << "Accepted preq from address" << from << ", preq:" << preq);
std::vector<Ptr<DestinationAddressUnit> > destinations = preq.GetDestinationList ();
//Add reactive path to originator:
@@ -549,25 +559,16 @@
{
prep.IncrementMetric (metric);
//acceptance cretirea:
- std::map<Mac48Address, uint32_t>::const_iterator i = m_lastHwmpSeqno.find (prep.GetOriginatorAddress ());
- if (i == m_lastHwmpSeqno.end ())
+ std::map<Mac48Address, std::pair<uint32_t, uint32_t> >::const_iterator i = m_hwmpSeqnoMetricDatabase.find (
+ prep.GetOriginatorAddress ());
+ if ((i != m_hwmpSeqnoMetricDatabase.end ()) && ((int32_t)(i->second.first - prep.GetOriginatorSeqNumber ()) > 0))
{
- m_lastHwmpSeqno[prep.GetOriginatorAddress ()] = prep.GetOriginatorSeqNumber ();
+ return;
}
- else
- {
- if ((int32_t)(i->second - prep.GetOriginatorSeqNumber ()) > 0)
- {
- return;
- }
- else
- {
- m_lastHwmpSeqno[prep.GetOriginatorAddress ()] = prep.GetOriginatorSeqNumber ();
- }
- }
+ m_hwmpSeqnoMetricDatabase[prep.GetOriginatorAddress ()] = std::make_pair (prep.GetOriginatorSeqNumber (), prep.GetMetric ());
//update routing info
//Now add a path to destination and add precursor to source
- NS_LOG_DEBUG("I am " << GetAddress () << ", received prep from " << prep.GetOriginatorAddress () << ", receiver was:" << from);
+ NS_LOG_DEBUG ("I am " << GetAddress () << ", received prep from " << prep.GetOriginatorAddress () << ", receiver was:" << from);
HwmpRtable::LookupResult result = m_rtable->LookupReactive (prep.GetDestinationAddress ());
//Add a reactive path only if it is better than existing:
if (
@@ -762,7 +763,7 @@
void
HwmpProtocol::InitiatePathError(PathError perr)
{
- for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
+ for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
{
std::vector<Mac48Address> receivers_for_interface;
for (unsigned int j = 0; j < perr.receivers.size (); j ++)
@@ -778,7 +779,7 @@
void
HwmpProtocol::ForwardPathError(PathError perr)
{
- for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
+ for (HwmpProtocolMacMap::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i ++)
{
std::vector<Mac48Address> receivers_for_interface;
for (unsigned int j = 0; j < perr.receivers.size (); j ++)
@@ -894,6 +895,12 @@
void
HwmpProtocol::ReactivePathResolved (Mac48Address dst)
{
+ std::map<Mac48Address, PreqEvent>::iterator i = m_preqTimeouts.find (dst);
+ if (i != m_preqTimeouts.end ())
+ {
+ m_routeDiscoveryTimeCallback (Simulator::Now () - i->second.whenScheduled);
+ }
+
HwmpRtable::LookupResult result = m_rtable->LookupReactive (dst);
NS_ASSERT(result.retransmitter != Mac48Address::GetBroadcast ());
//Send all packets stored for this destination
@@ -940,12 +947,13 @@
bool
HwmpProtocol::ShouldSendPreq (Mac48Address dst)
{
- std::map<Mac48Address, EventId>::const_iterator i = m_preqTimeouts.find (dst);
+ std::map<Mac48Address, PreqEvent>::const_iterator i = m_preqTimeouts.find (dst);
if (i == m_preqTimeouts.end ())
{
- m_preqTimeouts[dst] = Simulator::Schedule (
+ m_preqTimeouts[dst].preqTimeout = Simulator::Schedule (
m_dot11MeshHWMPnetDiameterTraversalTime * Scalar (2),
&HwmpProtocol::RetryPathDiscovery, this, dst, 1);
+ m_preqTimeouts[dst].whenScheduled = Simulator::Now ();
return true;
}
return false;
@@ -960,8 +968,8 @@
}
if (result.retransmitter != Mac48Address::GetBroadcast ())
{
- std::map<Mac48Address, EventId>::iterator i = m_preqTimeouts.find (dst);
- NS_ASSERT (i != m_preqTimeouts.end ());
+ std::map<Mac48Address, PreqEvent>::iterator i = m_preqTimeouts.find (dst);
+ NS_ASSERT (i != m_preqTimeouts.end ());
m_preqTimeouts.erase (i);
return;
}
@@ -976,8 +984,9 @@
packet.reply (false, packet.pkt, packet.src, packet.dst, packet.protocol, HwmpRtable::MAX_METRIC);
packet = DequeueFirstPacketByDst (dst);
}
- std::map<Mac48Address, EventId>::iterator i = m_preqTimeouts.find (dst);
- NS_ASSERT (i != m_preqTimeouts.end ());
+ std::map<Mac48Address, PreqEvent>::iterator i = m_preqTimeouts.find (dst);
+ NS_ASSERT (i != m_preqTimeouts.end ());
+ m_routeDiscoveryTimeCallback (Simulator::Now () - i->second.whenScheduled);
m_preqTimeouts.erase (i);
return;
}
@@ -987,7 +996,7 @@
{
i->second->RequestDestination (dst, originator_seqno, dst_seqno);
}
- m_preqTimeouts[dst] = Simulator::Schedule (
+ m_preqTimeouts[dst].preqTimeout = Simulator::Schedule (
Scalar (2 * (numOfRetry + 1)) * m_dot11MeshHWMPnetDiameterTraversalTime,
&HwmpProtocol::RetryPathDiscovery, this, dst, numOfRetry);
}
@@ -1102,7 +1111,7 @@
"totalDropped=\"" << totalDropped << "\" "
"initiatedPreq=\"" << initiatedPreq << "\" "
"initiatedPrep=\"" << initiatedPrep << "\" "
- "initiatedPerr=\"" << initiatedPerr << "\"" << std::endl;
+ "initiatedPerr=\"" << initiatedPerr << "\"/>" << std::endl;
}
void
HwmpProtocol::Report (std::ostream & os) const
--- a/src/devices/mesh/dot11s/hwmp-protocol.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/hwmp-protocol.h Mon Oct 26 09:21:20 2009 +0300
@@ -24,6 +24,7 @@
#include "ns3/mesh-l2-routing-protocol.h"
#include "ns3/nstime.h"
#include "ns3/event-id.h"
+#include "ns3/traced-value.h"
#include <vector>
#include <map>
@@ -156,6 +157,8 @@
*/
bool DropDataFrame (uint32_t seqno, Mac48Address source);
//\}
+ /// Route discovery time:
+ TracedCallback<Time> m_routeDiscoveryTimeCallback;
///\name Methods related to Queue/Dequeue procedures
///\{
bool QueuePacket (QueuedPacket packet);
@@ -225,18 +228,20 @@
///\{
/// Data sequence number database
std::map<Mac48Address, uint32_t> m_lastDataSeqno;
- /// DSN databse
- std::map<Mac48Address, uint32_t> m_lastHwmpSeqno;
- /// Metric database
- std::map<Mac48Address, uint32_t> m_lastHwmpMetric;
+ /// keeps HWMP seqno (first in pair) and HWMP metric (second in pair) for each address
+ std::map<Mac48Address, std::pair<uint32_t, uint32_t> > m_hwmpSeqnoMetricDatabase;
///\}
/// Routing table
Ptr<HwmpRtable> m_rtable;
///\name Timers:
- ///\{
- std::map<Mac48Address, EventId> m_preqTimeouts;
+ //\{
+ struct PreqEvent {
+ EventId preqTimeout;
+ Time whenScheduled;
+ };
+ std::map<Mac48Address, PreqEvent> m_preqTimeouts;
EventId m_proactivePreqTimer;
/// Random start in Proactive PREQ propagation
Time m_randomStart;
--- a/src/devices/mesh/dot11s/ie-dot11s-beacon-timing.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/ie-dot11s-beacon-timing.cc Mon Oct 26 09:21:20 2009 +0300
@@ -77,9 +77,7 @@
return m_neighbours;
}
void
-IeBeaconTiming::AddNeighboursTimingElementUnit (uint16_t aid, Time last_beacon, //MicroSeconds!
- Time beacon_interval //MicroSeconds!
-)
+IeBeaconTiming::AddNeighboursTimingElementUnit (uint16_t aid, Time last_beacon, Time beacon_interval)
{
if (m_numOfUnits == 50)
{
@@ -118,19 +116,11 @@
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
--- a/src/devices/mesh/dot11s/ie-dot11s-preq.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/ie-dot11s-preq.cc Mon Oct 26 09:21:20 2009 +0300
@@ -373,16 +373,11 @@
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;
}
--- a/src/devices/mesh/dot11s/peer-link.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/peer-link.cc Mon Oct 26 09:21:20 2009 +0300
@@ -94,6 +94,10 @@
m_peerMeshPointAddress (Mac48Address::GetBroadcast ()),
m_localLinkId (0),
m_peerLinkId (0),
+ m_assocId (0),
+ m_peerAssocId (0),
+ m_lastBeacon (Seconds (0)),
+ m_beaconInterval (Seconds (0)),
m_packetFail (0),
m_state (IDLE),
m_retryCounter (0),
@@ -188,6 +192,12 @@
{
return m_assocId;
}
+uint16_t
+PeerLink::GetPeerAid () const
+{
+ return m_peerAssocId;
+}
+
Time
PeerLink::GetLastBeacon () const
{
--- a/src/devices/mesh/dot11s/peer-link.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/peer-link.h Mon Oct 26 09:21:20 2009 +0300
@@ -74,11 +74,9 @@
void SetPeerMeshPointAddress (Mac48Address macaddr);
void SetInterface (uint32_t interface);
void SetLocalLinkId (uint16_t id);
- //void SetPeerLinkId (uint16_t id);
void SetLocalAid (uint16_t aid);
- //void SetPeerAid (uint16_t aid);
+ uint16_t GetPeerAid () const;
void SetBeaconTimingElement (IeBeaconTiming beaconTiming);
- //void SetPeerLinkDescriptorElement (IePeerManagement peerLinkElement);
Mac48Address GetPeerAddress () const;
uint16_t GetLocalAid () const;
Time GetLastBeacon () const;
--- a/src/devices/mesh/dot11s/peer-management-protocol-mac.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/peer-management-protocol-mac.cc Mon Oct 26 09:21:20 2009 +0300
@@ -69,22 +69,16 @@
{
MgtBeaconHeader beacon_hdr;
packet->RemoveHeader (beacon_hdr);
- //meshId.FindFirst (myBeacon);
- bool meshBeacon = false;
WifiInformationElementVector elements;
packet->RemoveHeader(elements);
Ptr<IeBeaconTiming> beaconTiming = DynamicCast<IeBeaconTiming> (elements.FindFirst (IE11S_BEACON_TIMING));
Ptr<IeMeshId> meshId = DynamicCast<IeMeshId> (elements.FindFirst (IE11S_MESH_ID));
- if ((beaconTiming != 0) && (meshId != 0))
+ if ((meshId != 0) && (m_protocol->GetMeshId ()->IsEqual (*meshId)))
{
- if (m_protocol->GetMeshId ()->IsEqual (*meshId))
- {
- meshBeacon = true;
- }
+ m_protocol->ReceiveBeacon (m_ifIndex, header.GetAddr2 (), MicroSeconds (
+ beacon_hdr.GetBeaconIntervalUs ()), beaconTiming);
}
- m_protocol->UpdatePeerBeaconTiming (m_ifIndex, meshBeacon, *beaconTiming, header.GetAddr2 (),
- Simulator::Now (), MicroSeconds (beacon_hdr.GetBeaconIntervalUs ()));
// Beacon shall not be dropeed. May be needed to another plugins
return true;
}
@@ -190,9 +184,13 @@
void
PeerManagementProtocolMac::UpdateBeacon (MeshWifiBeacon & beacon) const
{
- Ptr<IeBeaconTiming> beaconTiming = m_protocol->GetBeaconTimingElement (m_ifIndex);
- beacon.AddInformationElement (beaconTiming);
+ if (m_protocol->GetBeaconCollisionAvoidance ())
+ {
+ Ptr<IeBeaconTiming> beaconTiming = m_protocol->GetBeaconTimingElement (m_ifIndex);
+ beacon.AddInformationElement (beaconTiming);
+ }
beacon.AddInformationElement (m_protocol->GetMeshId ());
+ m_protocol->NotifyBeaconSent (m_ifIndex, beacon.GetBeaconInterval ());
}
void
@@ -269,14 +267,6 @@
return Mac48Address::Mac48Address ();
}
}
-std::pair<Time, Time>
-PeerManagementProtocolMac::GetBeaconInfo () const
-{
- std::pair<Time, Time> retval;
- retval.first = m_parent->GetTbtt ();
- retval.second = m_parent->GetBeaconInterval ();
- return retval;
-}
void
PeerManagementProtocolMac::SetBeaconShift (Time shift)
{
--- a/src/devices/mesh/dot11s/peer-management-protocol-mac.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/peer-management-protocol-mac.h Mon Oct 26 09:21:20 2009 +0300
@@ -86,15 +86,8 @@
///// Closes link when a proper number of successive transmissions have failed
void TxError (WifiMacHeader const &hdr);
void TxOk (WifiMacHeader const &hdr);
- ///\name BCA functionallity:
- ///\{
- ///\brief Fills TBTT and beacon interval. Needed by BCA
- ///functionallity
- ///\param first in retval is TBTT
- ///\param second in retval is beacon interval
- std::pair<Time, Time> GetBeaconInfo () const;
+ ///BCA functionallity:
void SetBeaconShift (Time shift);
- ///\}
void SetPeerManagerProtcol (Ptr<PeerManagementProtocol> protocol);
void SendPeerLinkManagementFrame (
Mac48Address peerAddress,
--- a/src/devices/mesh/dot11s/peer-management-protocol.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/peer-management-protocol.cc Mon Oct 26 09:21:20 2009 +0300
@@ -55,22 +55,30 @@
&PeerManagementProtocol::m_maxNumberOfPeerLinks),
MakeUintegerChecker<uint8_t> ()
)
- .AddAttribute ( "MaxBeaconLossForBeaconTiming",
- "If maximum number of beacons were lost, station will not included in beacon timing element",
- UintegerValue (3),
+ .AddAttribute ( "MaxBeaconShiftValue",
+ "Maximum number of TUs for beacon shifting",
+ UintegerValue (15),
MakeUintegerAccessor (
- &PeerManagementProtocol::m_maxBeaconLostForBeaconTiming),
- MakeUintegerChecker<uint8_t> ()
+ &PeerManagementProtocol::m_maxBeaconShift),
+ MakeUintegerChecker<uint16_t> ()
)
+ .AddAttribute ( "EnableBeaconCollisionAvoidance",
+ "Enable/Disable Beacon collision avoidance.",
+ BooleanValue (true),
+ MakeBooleanAccessor (
+ &PeerManagementProtocol::SetBeaconCollisionAvoidance, &PeerManagementProtocol::GetBeaconCollisionAvoidance),
+ MakeBooleanChecker ()
+ )
;
return tid;
}
PeerManagementProtocol::PeerManagementProtocol () :
- m_lastAssocId (0), m_lastLocalLinkId (1), m_maxBeaconLostForBeaconTiming (3)
+ m_lastAssocId (0), m_lastLocalLinkId (1), m_enableBca (true), m_maxBeaconShift (15)
{
}
PeerManagementProtocol::~PeerManagementProtocol ()
{
+ m_meshId = 0;
}
void
PeerManagementProtocol::DoDispose ()
@@ -86,12 +94,7 @@
j->second.clear ();
}
m_peerLinks.clear ();
- //cleaning beacon structures:
- for (BeaconInfoMap::iterator i = m_neighbourBeacons.begin (); i != m_neighbourBeacons.end (); i++)
- {
- i->second.clear ();
- }
- m_neighbourBeacons.clear ();
+ m_plugins.clear ();
}
bool
@@ -125,89 +128,33 @@
Ptr<IeBeaconTiming>
PeerManagementProtocol::GetBeaconTimingElement (uint32_t interface)
{
- Ptr<IeBeaconTiming> retval = Create<IeBeaconTiming> ();
- BeaconInfoMap::iterator i = m_neighbourBeacons.find (interface);
- if (i == m_neighbourBeacons.end ())
+ if (!GetBeaconCollisionAvoidance ())
{
- return retval;
+ return 0;
}
- bool cleaned = false;
- while (!cleaned)
+ Ptr<IeBeaconTiming> retval = Create<IeBeaconTiming> ();
+ PeerLinksMap::iterator iface = m_peerLinks.find (interface);
+ NS_ASSERT (iface != m_peerLinks.end ());
+ for (PeerLinksOnInterface::iterator i = iface->second.begin (); i != iface->second.end (); i++)
{
- BeaconsOnInterface::iterator start = i->second.begin ();
- for (BeaconsOnInterface::iterator j = start; j != i->second.end (); j++)
+ //If we do not know peer Assoc Id, we shall not add any info
+ //to a beacon timing element
+ if ((*i)->GetBeaconInterval () == Seconds (0))
{
- //check beacon loss and make a timing element
- //if last beacon was m_maxBeaconLostForBeaconTiming beacons ago - we do not put it to the
- //timing element
- if ((j->second.referenceTbtt + j->second.beaconInterval * Scalar (m_maxBeaconLostForBeaconTiming))
- < Simulator::Now ())
- {
- start = j;
- i->second.erase (j);
- break;
- }
+ //No beacon was received, do not include to the beacon timing element
+ continue;
}
- cleaned = true;
- }
- for (BeaconsOnInterface::const_iterator j = i->second.begin (); j != i->second.end (); j++)
- {
- retval->AddNeighboursTimingElementUnit (j->second.aid, j->second.referenceTbtt,
- j->second.beaconInterval);
+ retval->AddNeighboursTimingElementUnit ((*i)->GetLocalAid (), (*i)->GetLastBeacon (),
+ (*i)->GetBeaconInterval ());
}
return retval;
}
-
void
-PeerManagementProtocol::FillBeaconInfo (uint32_t interface, Mac48Address peerAddress, Time receivingTime,
- Time beaconInterval)
+PeerManagementProtocol::ReceiveBeacon (uint32_t interface, Mac48Address peerAddress, Time beaconInterval, Ptr<IeBeaconTiming> timingElement)
{
- BeaconInfoMap::iterator i = m_neighbourBeacons.find (interface);
- if (i == m_neighbourBeacons.end ())
- {
- BeaconsOnInterface newMap;
- m_neighbourBeacons[interface] = newMap;
- }
- i = m_neighbourBeacons.find (interface);
- BeaconsOnInterface::iterator j = i->second.find (peerAddress);
- if (j == i->second.end ())
- {
- BeaconInfo newInfo;
- newInfo.referenceTbtt = receivingTime;
- newInfo.beaconInterval = beaconInterval;
- newInfo.aid = m_lastAssocId++;
- if (m_lastAssocId == 0xff)
- {
- m_lastAssocId = 0;
- }
- i->second[peerAddress] = newInfo;
- }
- else
- {
- j->second.referenceTbtt = receivingTime;
- j->second.beaconInterval = beaconInterval;
- }
-}
-
-void
-PeerManagementProtocol::UpdatePeerBeaconTiming (uint32_t interface, bool meshBeacon,
- IeBeaconTiming timingElement, Mac48Address peerAddress, Time receivingTime, Time beaconInterval)
-{
- FillBeaconInfo (interface, peerAddress, receivingTime, beaconInterval);
- if (!meshBeacon)
- {
- return;
- }
- //BCA:
- PeerManagementProtocolMacMap::iterator plugin = m_plugins.find (interface);
- NS_ASSERT (plugin != m_plugins.end ());
- Time shift = GetNextBeaconShift (interface);
- if (TimeToTu (shift) != 0)
- {
- plugin->second->SetBeaconShift (shift);
- }
//PM STATE Machine
//Check that a given beacon is not from our interface
+ Simulator::Schedule (beaconInterval - TuToTime (m_maxBeaconShift + 1), &PeerManagementProtocol::DoShiftBeacon, this, interface);
for (PeerManagementProtocolMacMap::const_iterator i = m_plugins.begin (); i != m_plugins.end (); i++)
{
if (i->second->GetAddress () == peerAddress)
@@ -216,21 +163,19 @@
}
}
Ptr<PeerLink> peerLink = FindPeerLink (interface, peerAddress);
- if (peerLink != 0)
- {
- peerLink->SetBeaconTimingElement (timingElement);
- peerLink->SetBeaconInformation (receivingTime, beaconInterval);
- }
- else
+ if (peerLink == 0)
{
if (ShouldSendOpen (interface, peerAddress))
{
- peerLink = InitiateLink (interface, peerAddress, Mac48Address::GetBroadcast (), receivingTime,
- beaconInterval);
- peerLink->SetBeaconTimingElement (timingElement);
+ peerLink = InitiateLink (interface, peerAddress, Mac48Address::GetBroadcast ());
peerLink->MLMEActivePeerLinkOpen ();
}
}
+ peerLink->SetBeaconInformation (Simulator::Now (), beaconInterval);
+ if (GetBeaconCollisionAvoidance ())
+ {
+ peerLink->SetBeaconTimingElement (*PeekPointer (timingElement));
+ }
}
void
@@ -245,8 +190,7 @@
bool reject = !(ShouldAcceptOpen (interface, peerAddress, reasonCode));
if (peerLink == 0)
{
- peerLink = InitiateLink (interface, peerAddress, peerMeshPointAddress, Simulator::Now (), Seconds (
- 1.0));
+ peerLink = InitiateLink (interface, peerAddress, peerMeshPointAddress);
}
if (!reject)
{
@@ -304,26 +248,9 @@
}
Ptr<PeerLink>
PeerManagementProtocol::InitiateLink (uint32_t interface, Mac48Address peerAddress,
- Mac48Address peerMeshPointAddress, Time lastBeacon, Time beaconInterval)
+ Mac48Address peerMeshPointAddress)
{
Ptr<PeerLink> new_link = CreateObject<PeerLink> ();
- if (m_lastLocalLinkId == 0xff)
- {
- m_lastLocalLinkId = 0;
- }
- //find a beacon entry
- BeaconInfoMap::iterator beaconsOnInterface = m_neighbourBeacons.find (interface);
- if (beaconsOnInterface == m_neighbourBeacons.end ())
- {
- FillBeaconInfo (interface, peerAddress, lastBeacon, beaconInterval);
- }
- beaconsOnInterface = m_neighbourBeacons.find (interface);
- BeaconsOnInterface::iterator beacon = beaconsOnInterface->second.find (peerAddress);
- if (beacon == beaconsOnInterface->second.end ())
- {
- FillBeaconInfo (interface, peerAddress, lastBeacon, beaconInterval);
- }
- beacon = beaconsOnInterface->second.find (peerAddress);
//find a peer link - it must not exist
if (FindPeerLink (interface, peerAddress) != 0)
{
@@ -334,17 +261,17 @@
NS_ASSERT (plugin != m_plugins.end ());
PeerLinksMap::iterator iface = m_peerLinks.find (interface);
NS_ASSERT (iface != m_peerLinks.end ());
- new_link->SetLocalAid (beacon->second.aid);
+ new_link->SetLocalAid (m_lastAssocId++);
new_link->SetInterface (interface);
new_link->SetLocalLinkId (m_lastLocalLinkId++);
new_link->SetPeerAddress (peerAddress);
new_link->SetPeerMeshPointAddress (peerMeshPointAddress);
- new_link->SetBeaconInformation (lastBeacon, beaconInterval);
new_link->SetMacPlugin (plugin->second);
new_link->MLMESetSignalStatusCallback (MakeCallback (&PeerManagementProtocol::PeerLinkStatus, this));
iface->second.push_back (new_link);
return new_link;
}
+
Ptr<PeerLink>
PeerManagementProtocol::FindPeerLink (uint32_t interface, Mac48Address peerAddress)
{
@@ -374,13 +301,14 @@
{
m_peerStatusCallback = cb;
}
+
std::vector<Mac48Address>
-PeerManagementProtocol::GetActiveLinks (uint32_t interface)
+PeerManagementProtocol::GetPeers (uint32_t interface) const
{
std::vector<Mac48Address> retval;
- PeerLinksMap::iterator iface = m_peerLinks.find (interface);
+ PeerLinksMap::const_iterator iface = m_peerLinks.find (interface);
NS_ASSERT (iface != m_peerLinks.end ());
- for (PeerLinksOnInterface::iterator i = iface->second.begin (); i != iface->second.end (); i++)
+ for (PeerLinksOnInterface::const_iterator i = iface->second.begin (); i != iface->second.end (); i++)
{
if ((*i)->LinkIsEstab ())
{
@@ -389,6 +317,21 @@
}
return retval;
}
+
+std::vector< Ptr<PeerLink> >
+PeerManagementProtocol::GetPeerLinks () const
+{
+ std::vector< Ptr<PeerLink> > links;
+
+ for (PeerLinksMap::const_iterator iface = m_peerLinks.begin (); iface != m_peerLinks.end (); ++iface)
+ {
+ for (PeerLinksOnInterface::const_iterator i = iface->second.begin ();
+ i != iface->second.end (); i++)
+ if ((*i)->LinkIsEstab ())
+ links.push_back (*i);
+ }
+ return links;
+}
bool
PeerManagementProtocol::IsActiveLink (uint32_t interface, Mac48Address peerAddress)
{
@@ -404,6 +347,7 @@
{
return (m_stats.linksTotal <= m_maxNumberOfPeerLinks);
}
+
bool
PeerManagementProtocol::ShouldAcceptOpen (uint32_t interface, Mac48Address peerAddress,
PmpReasonCode & reasonCode)
@@ -415,56 +359,70 @@
}
return true;
}
-Time
-PeerManagementProtocol::GetNextBeaconShift (uint32_t interface)
+
+void
+PeerManagementProtocol::DoShiftBeacon (uint32_t interface)
{
- //REMINDER:: in timing element 1) last beacon reception time is measured in units of 256 microseconds
- // 2) beacon interval is mesured in units of 1024 microseconds
- // 3) hereafter TU = 1024 microseconds
- //So, the shift is a random integer variable uniformly distributed in [-15;-1] U [1;15]
- static int maxShift = 15;
- static int minShift = 1;
- UniformVariable randomSign (-1, 1);
- UniformVariable randomShift (minShift, maxShift);
+ if (!GetBeaconCollisionAvoidance ())
+ {
+ return;
+ }
+ // If beacon interval is equal to the neighbor's one and one o more beacons received
+ // by my neighbor coincide with my beacon - apply random uniformly distributed shift from
+ // [-m_maxBeaconShift, m_maxBeaconShift] except 0.
+ UniformVariable beaconShift (-m_maxBeaconShift, m_maxBeaconShift);
PeerLinksMap::iterator iface = m_peerLinks.find (interface);
NS_ASSERT (iface != m_peerLinks.end ());
- PeerManagementProtocolMacMap::iterator plugin = m_plugins.find (interface);
+ PeerManagementProtocolMacMap::const_iterator plugin = m_plugins.find (interface);
NS_ASSERT (plugin != m_plugins.end ());
- std::pair<Time, Time> myBeacon = plugin->second->GetBeaconInfo ();
- if (Simulator::Now () + TuToTime (maxShift) > myBeacon.first + myBeacon.second)
+ std::map<uint32_t, Time>::const_iterator lastBeacon = m_lastBeacon.find (interface);
+ std::map<uint32_t, Time>::const_iterator beaconInterval = m_beaconInterval.find (interface);
+ if ((lastBeacon == m_lastBeacon.end ()) || (beaconInterval == m_beaconInterval.end ()))
{
- return MicroSeconds (0);
+ return;
+ }
+ if (TuToTime (m_maxBeaconShift) > m_beaconInterval[interface])
+ {
+ NS_FATAL_ERROR ("Wrong beacon shift parameters");
+ return;
}
for (PeerLinksOnInterface::iterator i = iface->second.begin (); i != iface->second.end (); i++)
{
IeBeaconTiming::NeighboursTimingUnitsList neighbours;
- if ((*i)->LinkIsIdle ())
- {
- continue;
- }
neighbours = (*i)->GetBeaconTimingElement ().GetNeighboursTimingElementsList ();
//Going through all my timing elements and detecting future beacon collisions
for (IeBeaconTiming::NeighboursTimingUnitsList::const_iterator j = neighbours.begin (); j
!= neighbours.end (); j++)
{
- //We apply MBAC only if beacon Intervals are equal
- if ((*j)->GetBeaconInterval () == TimeToTu (myBeacon.second))
+ if ((*i)->GetPeerAid () == (*j)->GetAid ())
+ {
+ // I am present at neighbour's list of neighbors
+ continue;
+ }
+ //Beacon interval is stored in TU's
+ if (((*j)->GetBeaconInterval ()) != TimeToTu (beaconInterval->second))
{
- //Apply MBCA if future beacons may coinside
- if ((TimeToTu (myBeacon.first) - ((*j)->GetLastBeacon () / 4)) % ((*j)->GetBeaconInterval ())
- == 0)
+ continue;
+ }
+ //Timing element keeps beacon receiving times in 256us units, TU=1024us
+ if ((int) ((int)(*j)->GetLastBeacon () / 4 - (int)TimeToTu (lastBeacon->second)) % TimeToTu (
+ beaconInterval->second)
+ != 0)
+ {
+ continue;
+ }
+ int shift = 0;
+ do
{
- int beaconShift = randomShift.GetInteger (minShift, maxShift) * ((randomSign.GetValue ()
- >= 0) ? 1 : -1);
- NS_LOG_DEBUG ("Apply MBCA: Shift value = " << beaconShift << " beacon TUs");
- //Do not shift to the past!
- return (TuToTime (beaconShift) + Simulator::Now () < myBeacon.first) ? TuToTime (
- beaconShift) : TuToTime (0);
+ shift = (int) beaconShift.GetValue ();
}
- }
+ while (shift == 0);
+ PeerManagementProtocolMacMap::iterator plugin = m_plugins.find (interface);
+ NS_ASSERT (plugin != m_plugins.end ());
+ plugin->second->SetBeaconShift (TuToTime (shift));
+ return;
}
}
- return MicroSeconds (0);
}
Time
PeerManagementProtocol::TuToTime (uint32_t x)
@@ -530,6 +488,12 @@
{
return m_address;
}
+void
+PeerManagementProtocol::NotifyBeaconSent (uint32_t interface, Time beaconInterval)
+{
+ m_lastBeacon[interface] = Simulator::Now ();
+ m_beaconInterval[interface] = beaconInterval;
+}
PeerManagementProtocol::Statistics::Statistics (uint16_t t) :
linksTotal (t), linksOpened (0), linksClosed (0)
{
@@ -571,6 +535,16 @@
}
}
+void
+PeerManagementProtocol::SetBeaconCollisionAvoidance (bool enable)
+{
+ m_enableBca = enable;
+}
+bool
+PeerManagementProtocol::GetBeaconCollisionAvoidance () const
+{
+ return m_enableBca;
+}
} // namespace dot11s
} //namespace ns3
--- a/src/devices/mesh/dot11s/peer-management-protocol.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/dot11s/peer-management-protocol.h Mon Oct 26 09:21:20 2009 +0300
@@ -74,25 +74,12 @@
*/
Ptr<IeBeaconTiming> GetBeaconTimingElement (uint32_t interface);
/**
- * \brief When we receive a beacon from peer-station, we remember
- * its beacon timing element (needed for peer choosing mechanism),
- * and remember beacon timers - last beacon and beacon interval to
- * detect beacon loss and cancel links
- * \param interface is a interface on which beacon was received
- * \param meshBeacon indicates whether the beacon is mesh beacon or not.
- * \param timingElement is a timing element of remote beacon
- * \param peerAddress is an address where a beacon was received from
- * \param receivingTime is a time when beacon was received
- * \param beaconInterval is a beacon interval of received beacon
+ * \brief To initiate peer link we must notify about received beacon
+ * \param interface the interface where a beacon was received from
+ * \param peerAddress address of station, which sent a beacon
+ * \param beaconInterval beacon interval (needed by beacon loss counter)
*/
- void UpdatePeerBeaconTiming (
- uint32_t interface,
- bool meshBeacon,
- IeBeaconTiming timingElement,
- Mac48Address peerAddress,
- Time receivingTime,
- Time beaconInterval
- );
+ void ReceiveBeacon (uint32_t interface, Mac48Address peerAddress, Time beaconInterval, Ptr<IeBeaconTiming> beaconTiming);
//\}
/**
* \brief Methods that handle Peer link management frames
@@ -137,16 +124,26 @@
*/
bool IsActiveLink (uint32_t interface, Mac48Address peerAddress);
//\}
- ///\brief Needed by external module to do MLME
- Ptr<PeerLink> FindPeerLink (uint32_t interface, Mac48Address peerAddress);
+ ///\name Interface to other protocols (MLME)
+ //\{
+ /// Set peer link status change callback
void SetPeerLinkStatusCallback (Callback<void, Mac48Address, Mac48Address, uint32_t, bool> cb);
- std::vector<Mac48Address> GetActiveLinks (uint32_t interface);
- ///\brief needed by plugins to set global source address
+ /// Find active peer link by my interface and peer interface MAC
+ Ptr<PeerLink> FindPeerLink (uint32_t interface, Mac48Address peerAddress);
+ /// Get list of all active peer links
+ std::vector < Ptr<PeerLink> > GetPeerLinks () const;
+ /// Get list of active peers of my given interface
+ std::vector<Mac48Address> GetPeers (uint32_t interface) const;
+ /// Get mesh point address. TODO this used by plugins only. Now MAC plugins can ask MP addrress directly from main MAC
Mac48Address GetAddress ();
- ///\brief Needed to fill mesh configuration
uint8_t GetNumberOfLinks ();
void SetMeshId (std::string s);
Ptr<IeMeshId> GetMeshId () const;
+ /// Enable or disable beacon collision avoidance
+ void SetBeaconCollisionAvoidance (bool enable);
+ bool GetBeaconCollisionAvoidance () const;
+ /// Notify about beacon send event, needed to schedule BCA
+ void NotifyBeaconSent (uint32_t interface, Time beaconInterval);
///\brief: Report statistics
void Report (std::ostream &) const;
void ResetStats ();
@@ -177,16 +174,10 @@
PeerManagementProtocol& operator= (const PeerManagementProtocol &);
PeerManagementProtocol (const PeerManagementProtocol &);
- /**
- * \brief Fills information of received beacon. Needed to form own beacon timing element
- */
- void FillBeaconInfo (uint32_t interface, Mac48Address peerAddress, Time receivingTime, Time beaconInterval);
Ptr<PeerLink> InitiateLink (
uint32_t interface,
Mac48Address peerAddress,
- Mac48Address peerMeshPointAddress,
- Time lastBeacon,
- Time beaconInterval
+ Mac48Address peerMeshPointAddress
);
/**
* \name External peer-chooser
@@ -200,7 +191,7 @@
*/
void PeerLinkStatus (uint32_t interface, Mac48Address peerAddress, Mac48Address peerMeshPointAddres, PeerLink::PeerState ostate, PeerLink::PeerState nstate);
///\brief BCA
- Time GetNextBeaconShift (uint32_t interface);
+ void DoShiftBeacon (uint32_t interface);
/**
* \name Time<-->TU converters:
* \{
@@ -212,16 +203,19 @@
PeerManagementProtocolMacMap m_plugins;
Mac48Address m_address;
Ptr<IeMeshId> m_meshId;
- /**
- * \name Information related to beacons:
- * \{
- */
- BeaconInfoMap m_neighbourBeacons;
- ///\}
+
uint16_t m_lastAssocId;
uint16_t m_lastLocalLinkId;
uint8_t m_maxNumberOfPeerLinks;
- uint8_t m_maxBeaconLostForBeaconTiming;
+ /// Flag which enables BCA
+ bool m_enableBca;
+ /// Beacon can be shifted at [-m_maxBeaconShift; +m_maxBeaconShift] TUs
+ uint16_t m_maxBeaconShift;
+ ///Last beacon at each interface
+ std::map<uint32_t, Time> m_lastBeacon;
+ ///Beacon interval at each interface
+ std::map<uint32_t, Time> m_beaconInterval;
+
/**
* \name Peer Links
* \{
--- a/src/devices/mesh/mesh-l2-routing-protocol.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/mesh-l2-routing-protocol.cc Mon Oct 26 09:21:20 2009 +0300
@@ -39,6 +39,7 @@
MeshL2RoutingProtocol::~MeshL2RoutingProtocol ()
{
+ m_mp = 0;
}
void
--- a/src/devices/mesh/mesh-point-device.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/mesh-point-device.cc Mon Oct 26 09:21:20 2009 +0300
@@ -59,6 +59,9 @@
MeshPointDevice::~MeshPointDevice ()
{
NS_LOG_FUNCTION_NOARGS ();
+ m_node = 0;
+ m_channel = 0;
+ m_routingProtocol = 0;
}
void
@@ -71,6 +74,8 @@
}
m_ifaces.clear ();
m_node = 0;
+ m_channel = 0;
+ m_routingProtocol = 0;
NetDevice::DoDispose ();
}
--- a/src/devices/mesh/mesh-wifi-beacon.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/mesh-wifi-beacon.cc Mon Oct 26 09:21:20 2009 +0300
@@ -35,6 +35,11 @@
m_elements.AddInformationElement (ie);
}
+Time
+MeshWifiBeacon::GetBeaconInterval () const
+{
+ return MicroSeconds (m_header.GetBeaconIntervalUs ());
+}
Ptr<Packet>
MeshWifiBeacon::CreatePacket ()
--- a/src/devices/mesh/mesh-wifi-beacon.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/mesh-wifi-beacon.h Mon Oct 26 09:21:20 2009 +0300
@@ -27,8 +27,6 @@
#include "ns3/wifi-mac-header.h"
#include "ns3/wifi-information-element-vector.h"
-#include <vector>
-
namespace ns3 {
/**
@@ -60,6 +58,8 @@
* \param mpAddress is mesh point address
*/
WifiMacHeader CreateHeader (Mac48Address address, Mac48Address mpAddress);
+ ///Returns a beacon interval of wifi beacon
+ Time GetBeaconInterval () const;
/// Create frame = { beacon header + all information elements sorted by ElementId () }
Ptr<Packet> CreatePacket ();
--- a/src/devices/mesh/mesh-wifi-interface-mac.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/mesh-wifi-interface-mac.cc Mon Oct 26 09:21:20 2009 +0300
@@ -109,6 +109,10 @@
MeshWifiInterfaceMac::~MeshWifiInterfaceMac ()
{
NS_LOG_FUNCTION (this);
+ m_beaconDca = 0;
+ m_stationManager = 0;
+ m_phy = 0;
+ m_low = 0;
}
//-----------------------------------------------------------------------------
// WifiMac inherited
@@ -278,8 +282,10 @@
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;
--- a/src/devices/mesh/wifi-information-element-vector.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/mesh/wifi-information-element-vector.cc Mon Oct 26 09:21:20 2009 +0300
@@ -48,6 +48,11 @@
}
WifiInformationElementVector::~WifiInformationElementVector ()
{
+ for (IE_VECTOR::iterator i = m_elements.begin (); i != m_elements.end (); i++)
+ {
+ *i = 0;
+ }
+ m_elements.clear ();
}
TypeId
WifiInformationElementVector::GetTypeId ()
@@ -69,7 +74,7 @@
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 ());
--- a/src/devices/wifi/interference-helper.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/wifi/interference-helper.cc Mon Oct 26 09:21:20 2009 +0300
@@ -128,6 +128,7 @@
{}
InterferenceHelper::~InterferenceHelper ()
{
+ EraseEvents ();
m_errorRateModel = 0;
}
@@ -428,7 +429,7 @@
{
i++;
}
- m_events.erase (m_events.begin (), i);
+ EraseEvents (m_events.begin (), i);
}
m_events.push_back (event);
}
@@ -606,7 +607,21 @@
void
InterferenceHelper::EraseEvents (void)
{
- m_events.erase (m_events.begin (), m_events.end ());
+ for (Events::iterator i = m_events.begin (); i != m_events.end (); ++i)
+ {
+ *i = 0;
+ }
+ m_events.clear ();
+}
+
+void
+InterferenceHelper::EraseEvents (Events::iterator start, Events::iterator end)
+{
+ for (Events::iterator i = start; i != end; ++i)
+ {
+ *i = 0;
+ }
+ m_events.erase (start, end);
}
} // namespace ns3
--- a/src/devices/wifi/interference-helper.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/wifi/interference-helper.h Mon Oct 26 09:21:20 2009 +0300
@@ -110,6 +110,8 @@
typedef std::vector <NiChange> NiChanges;
typedef std::list<Ptr<Event> > Events;
+ void EraseEvents (Events::iterator start, Events::iterator end);
+
InterferenceHelper (const InterferenceHelper &o);
InterferenceHelper &operator = (const InterferenceHelper &o);
void AppendEvent (Ptr<Event> event);
--- a/src/devices/wifi/msdu-standard-aggregator.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/wifi/msdu-standard-aggregator.cc Mon Oct 26 09:21:20 2009 +0300
@@ -64,7 +64,8 @@
{
if (padding)
{
- aggregatedPacket->AddPaddingAtEnd (padding);
+ Ptr<Packet> pad = Create<Packet> (padding);
+ aggregatedPacket->AddAtEnd (pad);
}
currentHdr.SetDestinationAddr (dest);
currentHdr.SetSourceAddr (src);
--- a/src/devices/wifi/wifi-net-device.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/wifi/wifi-net-device.cc Mon Oct 26 09:21:20 2009 +0300
@@ -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::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 ();
--- a/src/devices/wifi/yans-wifi-channel.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/wifi/yans-wifi-channel.cc Mon Oct 26 09:21:20 2009 +0300
@@ -56,6 +56,7 @@
{}
YansWifiChannel::~YansWifiChannel ()
{
+ NS_LOG_FUNCTION_NOARGS ();
m_phyList.clear ();
}
--- a/src/devices/wifi/yans-wifi-phy.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/devices/wifi/yans-wifi-phy.cc Mon Oct 26 09:21:20 2009 +0300
@@ -139,6 +139,8 @@
m_channel = 0;
m_modes.clear ();
m_device = 0;
+ m_mobility = 0;
+ m_state = 0;
}
void
--- a/src/helper/application-container.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/application-container.h Mon Oct 26 09:21:20 2009 +0300
@@ -157,7 +157,7 @@
* \brief Append the contents of another ApplicationContainer to the end of
* this container.
*
- * \param The ApplicationContainer to append.
+ * \param other The ApplicationContainer to append.
*/
void Add (ApplicationContainer other);
@@ -202,9 +202,9 @@
* down and stop doing their thing (Stop) at a common time.
*
* This method simply iterates through the contained Applications and calls
- * their Start() methods with the provided Time.
+ * their Stop() methods with the provided Time.
*
- * \param start The Time at which each of the applications should start.
+ * \param stop The Time at which each of the applications should stop.
*/
void Stop (Time stop);
--- a/src/helper/dot11s-installer.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/dot11s-installer.cc Mon Oct 26 09:21:20 2009 +0300
@@ -73,8 +73,9 @@
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::GetPeers, PeekPointer (pmp)));
return true;
}
void
--- a/src/helper/dot11s-installer.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/dot11s-installer.h Mon Oct 26 09:21:20 2009 +0300
@@ -54,7 +54,7 @@
/**
* \brief Install an 802.11s stack.
- * \param The Ptr<MeshPointDevice> to use when setting up the PMP.
+ * \param mp The Ptr<MeshPointDevice> to use when setting up the PMP.
*/
bool InstallStack (Ptr<MeshPointDevice> mp);
--- a/src/helper/flame-installer.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/flame-installer.h Mon Oct 26 09:21:20 2009 +0300
@@ -58,7 +58,7 @@
/**
* \brief Install a flame stack on the given MeshPointDevice
- * \param The Ptr<MeshPointDevice> to use.
+ * \param mp The Ptr<MeshPointDevice> to use.
*/
bool InstallStack (Ptr<MeshPointDevice> mp);
--- a/src/helper/flow-monitor-helper.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/flow-monitor-helper.h Mon Oct 26 09:21:20 2009 +0300
@@ -46,7 +46,7 @@
/// \param nodes A NodeContainer holding the set of nodes to work with.
Ptr<FlowMonitor> Install (NodeContainer nodes);
/// \brief Enable flow monitoring on a single node
- /// \param nodes A Ptr<Node> to the node on which to enable flow monitoring.
+ /// \param node A Ptr<Node> to the node on which to enable flow monitoring.
Ptr<FlowMonitor> Install (Ptr<Node> node);
/// \brief Enable flow monitoring on all nodes
Ptr<FlowMonitor> InstallAll ();
--- a/src/helper/ipv4-interface-container.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/ipv4-interface-container.h Mon Oct 26 09:21:20 2009 +0300
@@ -79,12 +79,11 @@
* Manually add an entry to the container consisting of a previously composed
* entry std::pair.
*
- * \param ipv4 pointer to Ipv4 object
- * \param interface interface index of the Ipv4Interface to add to the container
+ * \param ipInterfacePair the pair of a pointer to Ipv4 object and interface index of the Ipv4Interface to add to the container
*
* @see Ipv4InterfaceContainer
*/
- void Add (std::pair<Ptr<Ipv4>, uint32_t>);
+ void Add (std::pair<Ptr<Ipv4>, uint32_t> ipInterfacePair);
/**
* Manually add an entry to the container consisting of the individual parts
--- a/src/helper/mesh-helper.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/mesh-helper.cc Mon Oct 26 09:21:20 2009 +0300
@@ -32,6 +32,10 @@
m_standard (WIFI_PHY_STANDARD_80211a)
{
}
+MeshHelper::~MeshHelper ()
+{
+ m_stack = 0;
+}
void
MeshHelper::SetSpreadInterfaceChannels (enum ChannelPolicy policy)
{
--- a/src/helper/mesh-helper.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/mesh-helper.h Mon Oct 26 09:21:20 2009 +0300
@@ -44,6 +44,11 @@
MeshHelper ();
/**
+ * Destroy a MeshHelper.
+ */
+ ~MeshHelper ();
+
+ /**
* \brief Set the helper to the default values for the MAC type, remote
* station manager and channel policy.
*/
--- a/src/helper/net-device-container.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/net-device-container.h Mon Oct 26 09:21:20 2009 +0300
@@ -175,14 +175,14 @@
* \brief Append the contents of another NetDeviceContainer to the end of
* this container.
*
- * \param The NetDeviceContainer to append.
+ * \param other The NetDeviceContainer to append.
*/
void Add (NetDeviceContainer other);
/**
* \brief Append a single Ptr<NetDevice> to this container.
*
- * \param application The Ptr<NetDevice> to append.
+ * \param device The Ptr<NetDevice> to append.
*/
void Add (Ptr<NetDevice> device);
@@ -190,7 +190,7 @@
* \brief Append to this container the single Ptr<NetDevice> referred to
* via its object name service registered name.
*
- * \param name The name of the NetDevice Object to add to the container.
+ * \param deviceName The name of the NetDevice Object to add to the container.
*/
void Add (std::string deviceName);
--- a/src/helper/node-container.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/node-container.h Mon Oct 26 09:21:20 2009 +0300
@@ -58,7 +58,7 @@
* instantiated and assigned a name using the Object Name Service. This
* Node is then specified by its assigned name.
*
- * \param name The name of the Node Object to add to the container.
+ * \param nodeName The name of the Node Object to add to the container.
*/
NodeContainer (std::string nodeName);
@@ -240,7 +240,7 @@
* \brief Append the contents of another NodeContainer to the end of
* this container.
*
- * \param The NodeContainer to append.
+ * \param other The NodeContainer to append.
*/
void Add (NodeContainer other);
--- a/src/helper/udp-echo-helper.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/helper/udp-echo-helper.h Mon Oct 26 09:21:20 2009 +0300
@@ -121,7 +121,7 @@
* packet (what is sent as data to the server) to the contents of the fill
* string (including the trailing zero terminator).
*
- * \warn The size of resulting echo packets will be automatically adjusted
+ * \warning The size of resulting echo packets will be automatically adjusted
* to reflect the size of the fill string -- this means that the PacketSize
* attribute may be changed as a result of this call.
*
@@ -137,7 +137,7 @@
*
* The fill byte will be used to initialize the contents of the data packet.
*
- * \warn The size of resulting echo packets will be automatically adjusted
+ * \warning The size of resulting echo packets will be automatically adjusted
* to reflect the dataLength parameter -- this means that the PacketSize
* attribute may be changed as a result of this call.
*
@@ -156,7 +156,7 @@
* by providing a complete buffer with fillLength set to your desired
* dataLength
*
- * \warn The size of resulting echo packets will be automatically adjusted
+ * \warning The size of resulting echo packets will be automatically adjusted
* to reflect the dataLength parameter -- this means that the PacketSize
* attribute of the Application may be changed as a result of this call.
*
@@ -183,7 +183,7 @@
* is provided as a string name of a Node that has been previously
* associated using the Object Name Service.
*
- * \param node The name of the node on which to create the UdpEchoClientApplication
+ * \param nodeName The name of the node on which to create the UdpEchoClientApplication
*
* \returns An ApplicationContainer that holds a Ptr<Application> to the
* application created
--- a/src/internet-stack/icmpv6-l4-protocol.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/internet-stack/icmpv6-l4-protocol.cc Mon Oct 26 09:21:20 2009 +0300
@@ -962,7 +962,8 @@
if ((redirectedPacketSize % 8) != 0)
{
- redirectedPacket->AddPaddingAtEnd (8 - (redirectedPacketSize % 8));
+ Ptr<Packet> pad = Create<Packet> (8 - (redirectedPacketSize % 8));
+ redirectedPacket->AddAtEnd (pad);
}
if (redirHardwareTarget.GetLength ())
--- a/src/internet-stack/tcp-test.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/internet-stack/tcp-test.cc Mon Oct 26 09:21:20 2009 +0300
@@ -333,9 +333,13 @@
TcpTestSuite ()
: TestSuite ("tcp", UNIT)
{
+ // Arguments to these test cases are 1) totalStreamSize,
+ // 2) source write size, 3) source read size
+ // 4) server write size, and 5) server read size
+ // with units of bytes
AddTestCase (new TcpTestCase (13, 200, 200, 200, 200));
AddTestCase (new TcpTestCase (13, 1, 1, 1, 1));
- //AddTestCase (new TcpTestCase (100000, 100, 50, 100, 20));
+ AddTestCase (new TcpTestCase (100000, 100, 50, 100, 20));
}
} g_tcpTestSuite;
--- a/src/node/net-device.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/node/net-device.cc Mon Oct 26 09:21:20 2009 +0300
@@ -45,6 +45,8 @@
}
NetDevice::~NetDevice ()
-{}
+{
+ NS_LOG_FUNCTION_NOARGS ();
+}
} // namespace ns3
--- a/src/node/node.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/node/node.cc Mon Oct 26 09:21:20 2009 +0300
@@ -148,6 +148,7 @@
void
Node::DoDispose()
{
+ m_handlers.clear ();
for (std::vector<Ptr<NetDevice> >::iterator i = m_devices.begin ();
i != m_devices.end (); i++)
{
--- a/src/simulator/cairo-wideint-private.h Thu Oct 22 17:17:40 2009 +0400
+++ b/src/simulator/cairo-wideint-private.h Mon Oct 26 09:21:20 2009 +0300
@@ -36,10 +36,12 @@
#define cairo_private
#define HAVE_UINT64_T 1
-/*for compatibility with MacOS*/
+/*for compatibility with MacOS and Cygwin*/
#ifndef HAVE_STDINT_H
#ifdef __APPLE__
#define HAVE_STDINT_H 1
+#elif defined(WIN32)
+#define HAVE_STDINT_H 1
#endif
#endif
--- a/src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc Thu Oct 22 17:17:40 2009 +0400
+++ b/src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc Mon Oct 26 09:21:20 2009 +0300
@@ -345,25 +345,20 @@
// reflecting the change from LARGEST_CWND back to MSS
//
const uint32_t MSS = 536;
- const uint32_t N_EVENTS = 21;
- const uint32_t LARGEST_CWND = MSS * N_EVENTS;
+ const uint32_t N_EVENTS = 20;
CwndEvent event;
NS_TEST_ASSERT_MSG_EQ (m_responses.GetN (), N_EVENTS, "Unexpectedly low number of cwnd change events");
- for (uint32_t i = 0, from = 536, to = 1072; i < N_EVENTS - 1; ++i, from += 536, to += 536)
+ for (uint32_t i = 0, from = MSS, to = MSS * 2; i < N_EVENTS; ++i, from += MSS, to += MSS)
{
event = m_responses.Get (i);
NS_TEST_ASSERT_MSG_EQ (event.m_oldCwnd, from, "Wrong old cwnd value in cwnd change event " << i);
NS_TEST_ASSERT_MSG_EQ (event.m_newCwnd, to, "Wrong new cwnd value in cwnd change event " << i);
}
- event = m_responses.Get (N_EVENTS - 1);
- NS_TEST_ASSERT_MSG_EQ (event.m_oldCwnd, LARGEST_CWND, "Wrong old cwnd value in cwnd change event " << N_EVENTS - 1);
- NS_TEST_ASSERT_MSG_EQ (event.m_newCwnd, MSS, "Wrong new cwnd value in cwnd change event " << N_EVENTS - 1);
-
return GetErrorStatus ();
}
@@ -523,19 +518,19 @@
NS_TEST_ASSERT_MSG_EQ (m_responses.GetN (), 31, "Unexpected number of cwnd change events");
- for (uint32_t i = 0, from = 536, to = 1072; i < 9; ++i, from += 536, to += 536)
+ for (uint32_t i = 0, from = MSS, to = MSS * 2; i < 9; ++i, from += MSS, to += MSS)
{
event = m_responses.Get (i);
NS_TEST_ASSERT_MSG_EQ (event.m_oldCwnd, from, "Wrong old cwnd value in cwnd change event " << i);
NS_TEST_ASSERT_MSG_EQ (event.m_newCwnd, to, "Wrong new cwnd value in cwnd change event " << i);
}
- // Cwnd should be back to 536
+ // Cwnd should be back to MSS
event = m_responses.Get (9);
NS_TEST_ASSERT_MSG_EQ (event.m_newCwnd, MSS, "Wrong new cwnd value in cwnd change event " << 9);
// Another round of slow start
- for (uint32_t i = 10, from = 536, to = 1072; i < 14; ++i, from += 536, to += 536)
+ for (uint32_t i = 10, from = MSS, to = MSS * 2; i < 14; ++i, from += MSS, to += MSS)
{
event = m_responses.Get (i);
NS_TEST_ASSERT_MSG_EQ (event.m_oldCwnd, from, "Wrong old cwnd value in cwnd change event " << i);
@@ -556,7 +551,7 @@
<< i);
}
- // Cwnd should be back to 536
+ // Cwnd should be back to MSS
event = m_responses.Get (29);
NS_TEST_ASSERT_MSG_EQ (event.m_newCwnd, MSS, "Wrong new cwnd value in cwnd change event " << 29);
--- a/test.py Thu Oct 22 17:17:40 2009 +0400
+++ b/test.py Mon Oct 26 09:21:20 2009 +0300
@@ -19,12 +19,12 @@
import os
import sys
+import time
import optparse
import subprocess
import threading
import Queue
import signal
-import random
import xml.dom.minidom
import shutil
@@ -53,105 +53,114 @@
#
# If the user has constrained us to run certain kinds of tests, we can tell waf
# to only build
+#
core_kinds = ["bvt", "core", "system", "unit"]
#
+# There are some special cases for test suites that kill valgrind. This is
+# because NSC causes illegal instruction crashes when run under valgrind.
+#
+core_valgrind_skip_tests = [
+ "ns3-tcp-cwnd",
+ "ns3-tcp-interoperability",
+]
+
+#
# A list of examples to run as smoke tests just to ensure that they remain
# buildable and runnable over time. Also a condition under which to run
-# the example (from the waf configuration).
+# the example (from the waf configuration), and a condition under which to
+# run the example under valgrind. This is because NSC causes illegal
+# instruction crashes when run under valgrind.
#
# XXX Should this not be read from a configuration file somewhere and not
# hardcoded.
#
example_tests = [
- ("csma/csma-bridge", "True"),
- ("csma/csma-bridge-one-hop", "True"),
- ("csma/csma-broadcast", "True"),
- ("csma/csma-multicast", "True"),
- ("csma/csma-one-subnet", "True"),
- ("csma/csma-packet-socket", "True"),
- ("csma/csma-ping", "True"),
- ("csma/csma-raw-ip-socket", "True"),
- ("csma/csma-star", "True"),
+ ("csma/csma-bridge", "True", "True"),
+ ("csma/csma-bridge-one-hop", "True", "True"),
+ ("csma/csma-broadcast", "True", "True"),
+ ("csma/csma-multicast", "True", "True"),
+ ("csma/csma-one-subnet", "True", "True"),
+ ("csma/csma-packet-socket", "True", "True"),
+ ("csma/csma-ping", "True", "True"),
+ ("csma/csma-raw-ip-socket", "True", "True"),
+ ("csma/csma-star", "True", "True"),
- ("emulation/emu-ping", "False"),
- ("emulation/emu-udp-echo", "False"),
-
- ("error-model/simple-error-model", "True"),
+ ("emulation/emu-ping", "False", "True"),
+ ("emulation/emu-udp-echo", "False", "True"),
- ("ipv6/icmpv6-redirect", "True"),
- ("ipv6/ping6", "True"),
- ("ipv6/radvd", "True"),
- ("ipv6/radvd-two-prefix", "True"),
- ("ipv6/test-ipv6", "True"),
-
- ("mesh/mesh", "True"),
-
- ("naming/object-names", "True"),
-
- ("realtime/realtime-udp-echo", "ENABLE_REAL_TIME == True"),
+ ("error-model/simple-error-model", "True", "True"),
- ("routing/dynamic-global-routing", "True"),
- ("routing/global-injection-slash32", "True"),
- ("routing/global-routing-slash32", "True"),
- ("routing/mixed-global-routing", "True"),
- ("routing/nix-simple", "True"),
- ("routing/nms-p2p-nix", "False"), # Takes too long to run
- ("routing/simple-alternate-routing", "True"),
- ("routing/simple-global-routing", "True"),
- ("routing/simple-point-to-point-olsr", "True"),
- ("routing/simple-routing-ping6", "True"),
- ("routing/static-routing-slash32", "True"),
+ ("ipv6/icmpv6-redirect", "True", "True"),
+ ("ipv6/ping6", "True", "True"),
+ ("ipv6/radvd", "True", "True"),
+ ("ipv6/radvd-two-prefix", "True", "True"),
+ ("ipv6/test-ipv6", "True", "True"),
+
+ ("mesh/mesh", "True", "True"),
+
+ ("naming/object-names", "True", "True"),
+
+ ("realtime/realtime-udp-echo", "ENABLE_REAL_TIME == True", "True"),
- ("stats/wifi-example-sim", "True"),
-
- ("tap/tap-wifi-dumbbell", "False"), # Requires manual configuration
+ ("routing/dynamic-global-routing", "True", "True"),
+ ("routing/global-injection-slash32", "True", "True"),
+ ("routing/global-routing-slash32", "True", "True"),
+ ("routing/mixed-global-routing", "True", "True"),
+ ("routing/nix-simple", "True", "True"),
+ ("routing/nms-p2p-nix", "False", "True"), # Takes too long to run
+ ("routing/simple-alternate-routing", "True", "True"),
+ ("routing/simple-global-routing", "True", "True"),
+ ("routing/simple-point-to-point-olsr", "True", "True"),
+ ("routing/simple-routing-ping6", "True", "True"),
+ ("routing/static-routing-slash32", "True", "True"),
- ("tcp/star", "True"),
- ("tcp/tcp-large-transfer", "True"),
- ("tcp/tcp-nsc-lfn", "ENABLE_NSC == True"),
- ("tcp/tcp-nsc-zoo", "ENABLE_NSC == True"),
- ("tcp/tcp-star-server", "True"),
+ ("stats/wifi-example-sim", "True", "True"),
+
+ ("tap/tap-wifi-dumbbell", "False", "True"), # Requires manual configuration
- ("tunneling/virtual-net-device", "True"),
-
- ("tutorial/first", "True"),
- ("tutorial/hello-simulator", "True"),
- ("tutorial/second", "True"),
- ("tutorial/third", "True"),
-
- ("udp/udp-echo", "True"),
+ ("tcp/star", "True", "True"),
+ ("tcp/tcp-large-transfer", "True", "True"),
+ ("tcp/tcp-nsc-lfn", "ENABLE_NSC == True", "True"),
+ ("tcp/tcp-nsc-zoo", "ENABLE_NSC == True", "True"),
+ ("tcp/tcp-star-server", "True", "True"),
- ("wireless/mixed-wireless", "True"),
- ("wireless/multirate", "False"), # Takes too long to run
- ("wireless/simple-wifi-frame-aggregation", "True"),
- ("wireless/wifi-adhoc", "False"), # Takes too long to run
- ("wireless/wifi-ap --verbose=0", "True"), # Don't let it spew to stdout
- ("wireless/wifi-clear-channel-cmu", "False"), # Requires specific hardware
- ("wireless/wifi-simple-adhoc", "True"),
- ("wireless/wifi-simple-adhoc-grid", "True"),
- ("wireless/wifi-simple-infra", "True"),
- ("wireless/wifi-simple-interference", "True"),
- ("wireless/wifi-wired-bridging", "True"),
+ ("tunneling/virtual-net-device", "True", "True"),
+
+ ("tutorial/first", "True", "True"),
+ ("tutorial/hello-simulator", "True", "True"),
+ ("tutorial/second", "True", "True"),
+ ("tutorial/third", "True", "True"),
+ ("tutorial/fourth", "True", "True"),
+
+ ("udp/udp-echo", "True", "True"),
+
+ ("wireless/mixed-wireless", "True", "True"),
+ ("wireless/multirate", "False", "True"), # Takes too long to run
+ ("wireless/simple-wifi-frame-aggregation", "True", "True"),
+ ("wireless/wifi-adhoc", "False", "True"), # Takes too long to run
+ ("wireless/wifi-ap --verbose=0", "True", "True"), # Don't let it spew to stdout
+ ("wireless/wifi-clear-channel-cmu", "False", "True"), # Requires specific hardware
+ ("wireless/wifi-simple-adhoc", "True", "True"),
+ ("wireless/wifi-simple-adhoc-grid", "True", "True"),
+ ("wireless/wifi-simple-infra", "True", "True"),
+ ("wireless/wifi-simple-interference", "True", "True"),
+ ("wireless/wifi-wired-bridging", "True", "True"),
]
#
-# Most of the examples produce gangs of trace files, so we want to find
-# somewhere to put them that won't pollute the current directory. One
-# obvious place is somewhere in /tmp.
-#
-TMP_TRACES_DIR = "/tmp/unchecked-traces"
-
-#
# The test suites are going to want to output status. They are running
# concurrently. This means that unless we are careful, the output of
# the test suites will be interleaved. Rather than introducing a lock
# file that could unintentionally start serializing execution, we ask
# the tests to write their output to a temporary directory and then
# put together the final output file when we "join" the test tasks back
-# to the main thread.
+# to the main thread. In addition to this issue, the example programs
+# often write lots and lots of trace files which we will just ignore.
+# We put all of them into the temp directory as well, so they can be
+# easily deleted.
#
-TMP_OUTPUT_DIR = "/tmp/testpy"
+TMP_OUTPUT_DIR = "testpy-output"
def get_node_text(node):
for child in node.childNodes:
@@ -229,12 +238,15 @@
time = get_node_text(suite.getElementsByTagName("SuiteTime")[0])
#
- # Print a level three header in green with the result, name and time.
- # If the test suite passed, the header is printed in green, otherwise
- # it is printed in red.
+ # Print a level three header with the result, name and time. If the
+ # test suite passed, the header is printed in green. If the suite was
+ # skipped, print it in orange, otherwise assume something bad happened
+ # and print in red.
#
if result == "PASS":
f.write("<h3 style=\"color:green\">%s: %s (%s)</h3>\n" % (result, name, time))
+ elif result == "SKIP":
+ f.write("<h3 style=\"color:#ff6600\">%s: %s (%s)</h3>\n" % (result, name, time))
else:
f.write("<h3 style=\"color:red\">%s: %s (%s)</h3>\n" % (result, name, time))
@@ -249,8 +261,8 @@
f.write("<th> Result </th>\n")
#
- # If the suite crashed, there is no further information, so just
- # delare a new table row with the result (CRASH) in it. Looks like:
+ # If the suite crashed or is skipped, there is no further information, so just
+ # delare a new table row with the result (CRASH or SKIP) in it. Looks like:
#
# +--------+
# | Result |
@@ -258,11 +270,14 @@
# | CRASH |
# +--------+
#
- # Then go on to the next test suite. Valgrind errors look the same.
+ # Then go on to the next test suite. Valgrind and skipped errors look the same.
#
- if result in ["CRASH", "VALGR"]:
+ if result in ["CRASH", "SKIP", "VALGR"]:
f.write("<tr>\n")
- f.write("<td style=\"color:red\">%s</td>\n" % result)
+ if result == "SKIP":
+ f.write("<td style=\"color:#ff6600\">%s</td>\n" % result)
+ else:
+ f.write("<td style=\"color:red\">%s</td>\n" % result)
f.write("</tr>\n")
f.write("</table>\n")
continue
@@ -422,11 +437,13 @@
#
if result == "PASS":
f.write("<td style=\"color:green\">%s</td>\n" % result)
+ elif result == "SKIP":
+ f.write("<td style=\"color:#ff6600\">%s</fd>\n" % result)
else:
f.write("<td style=\"color:red\">%s</td>\n" % result)
#
- # Write the example name as a new tagle data.
+ # Write the example name as a new tag data.
#
f.write("<td>%s</td>\n" % name)
@@ -537,7 +554,7 @@
def run_job_synchronously(shell_command, directory, valgrind):
if valgrind:
- cmd = "%s valgrind --error-exitcode=2 %s/%s/%s" % (LIBRARY_PATH, NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command)
+ cmd = "%s valgrind --leak-check=full --error-exitcode=2 %s/%s/%s" % (LIBRARY_PATH, NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command)
else:
cmd = "%s %s/%s/%s" % (LIBRARY_PATH, NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command)
@@ -552,12 +569,14 @@
# This class defines a unit of testing work. It will typically refer to
# a test suite to run using the test-runner, or an example to run directly.
#
-class Job():
+class Job:
def __init__(self):
self.is_break = False
+ self.is_skip = False
self.is_example = False
self.shell_command = ""
self.display_name = ""
+ self.basedir = ""
self.cwd = ""
self.tmp_file_name = ""
self.returncode = False
@@ -571,6 +590,13 @@
self.is_break = is_break
#
+ # If a job is to be skipped, we actually run it through the worker threads
+ # to keep the PASS, FAIL, CRASH and SKIP processing all in one place.
+ #
+ def set_is_skip(self, is_skip):
+ self.is_skip = is_skip
+
+ #
# Examples are treated differently than standard test suites. This is
# mostly because they are completely unaware that they are being run as
# tests. So we have to do some special case processing to make them look
@@ -622,10 +648,7 @@
# This is the temporary results file name that will be given to an executing
# test as it is being run. We will be running all of our tests in parallel
# so there must be multiple temporary output files. These will be collected
- # into a single XML file at the end and then be deleted. The file names are
- # just giant random numbers, for example
- #
- # "/tmp/testpy/5437925246732857"
+ # into a single XML file at the end and then be deleted.
#
def set_tmp_file_name(self, tmp_file_name):
self.tmp_file_name = tmp_file_name
@@ -665,6 +688,17 @@
job.set_is_break(True)
self.output_queue.put(job)
continue
+
+ #
+ # If we are actually supposed to skip this job, do so. Note that
+ # if is_skip is true, returncode is undefined.
+ #
+ if job.is_skip:
+ if options.verbose:
+ print "Skip %s" % job.shell_command
+ self.output_queue.put(job)
+ return
+
#
# Otherwise go about the business of running tests as normal.
#
@@ -757,8 +791,8 @@
#
# We communicate results in two ways. First, a simple message relating
- # PASS, FAIL, or SKIP is always written to the standard output. It is
- # expected that this will be one of the main use cases. A developer can
+ # PASS, FAIL, CRASH or SKIP is always written to the standard output. It
+ # is expected that this will be one of the main use cases. A developer can
# just run test.py with no options and see that all of the tests still
# pass.
#
@@ -767,26 +801,30 @@
# finds a problem, or HTML for nightly builds. In these cases, an
# XML file is written containing the status messages from the test suites.
# This file is then read and translated into text or HTML. It is expected
- # that nobody will really be interested in the XML, so we write it to
- # somewhere in /tmp with a random name to avoid collisions. Just in case
- # some strange once-in-a-lifetime error occurs, we always write the info
- # so it can be found, we just may not use it.
+ # that nobody will really be interested in the XML, so we write it somewhere
+ # with a unique name (time) to avoid collisions. In case an error happens, we
+ # provide a runtime option to retain the temporary files.
#
# When we run examples as smoke tests, they are going to want to create
# lots and lots of trace files. We aren't really interested in the contents
- # of the trace files, so we also just stash them off in /tmp somewhere.
+ # of the trace files, so we also just stash them off in the temporary dir.
+ # The retain option also causes these unchecked trace files to be kept.
#
+ date_and_time = time.strftime("%Y-%m-%d-%H-%M-%S-CUT", time.gmtime())
+
if not os.path.exists(TMP_OUTPUT_DIR):
os.makedirs(TMP_OUTPUT_DIR)
- if not os.path.exists(TMP_TRACES_DIR):
- os.makedirs(TMP_TRACES_DIR)
+ testpy_output_dir = os.path.join(TMP_OUTPUT_DIR, date_and_time);
+
+ if not os.path.exists(testpy_output_dir):
+ os.makedirs(testpy_output_dir)
#
# Create the main output file and start filling it with XML. We need to
# do this since the tests will just append individual results to this file.
#
- xml_results_file = TMP_OUTPUT_DIR + "%d.xml" % random.randint(0, sys.maxint)
+ xml_results_file = os.path.join(testpy_output_dir, "results.xml")
f = open(xml_results_file, 'w')
f.write('<?xml version="1.0"?>\n')
f.write('<TestResults>\n')
@@ -868,19 +906,27 @@
thread.start()
#
+ # Keep track of some summary statistics
+ #
+ total_tests = 0
+ skipped_tests = 0
+
+ #
# We now have worker threads spun up, and a list of work to do. So, run
# through the list of test suites and dispatch a job to run each one.
#
# Dispatching will run with unlimited speed and the worker threads will
# execute as fast as possible from the queue.
#
- total_tests = 0
+ # Note that we actually dispatch tests to be skipped, so all of the
+ # PASS, FAIL, CRASH and SKIP processing is done in the same place.
+ #
for test in suite_list:
if len(test):
job = Job()
job.set_is_example(False)
job.set_display_name(test)
- job.set_tmp_file_name(TMP_OUTPUT_DIR + "%d" % random.randint(0, sys.maxint))
+ job.set_tmp_file_name(os.path.join(testpy_output_dir, "%s.xml" % test))
job.set_cwd(os.getcwd())
job.set_basedir(os.getcwd())
if (options.multiple):
@@ -890,6 +936,9 @@
job.set_shell_command("utils/test-runner --suite='%s'%s" % (test, multiple))
+ if options.valgrind and test in core_valgrind_skip_tests:
+ job.set_is_skip(True)
+
if options.verbose:
print "Queue %s" % test
@@ -941,16 +990,19 @@
if len(options.suite) == 0 and len(options.example) == 0:
if len(options.constrain) == 0 or options.constrain == "example":
if ENABLE_EXAMPLES:
- for test, condition in example_tests:
- if eval(condition) == True:
+ for test, do_run, do_valgrind_run in example_tests:
+ if eval(do_run):
job = Job()
job.set_is_example(True)
job.set_display_name(test)
job.set_tmp_file_name("")
- job.set_cwd(TMP_TRACES_DIR)
+ job.set_cwd(testpy_output_dir)
job.set_basedir(os.getcwd())
job.set_shell_command("examples/%s" % test)
+ if options.valgrind and not eval(do_valgrind_run):
+ job.set_is_skip (True)
+
if options.verbose:
print "Queue %s" % test
@@ -967,7 +1019,7 @@
job.set_is_example(True)
job.set_display_name(options.example)
job.set_tmp_file_name("")
- job.set_cwd(TMP_TRACES_DIR)
+ job.set_cwd(testpy_output_dir)
job.set_basedir(os.getcwd())
job.set_shell_command("examples/%s" % options.example)
@@ -1011,18 +1063,22 @@
else:
kind = "TestSuite"
- if job.returncode == 0:
- status = "PASS"
- passed_tests = passed_tests + 1
- elif job.returncode == 1:
- failed_tests = failed_tests + 1
- status = "FAIL"
- elif job.returncode == 2:
- valgrind_errors = valgrind_errors + 1
- status = "VALGR"
+ if job.is_skip:
+ status = "SKIP"
+ skipped_tests = skipped_tests + 1
else:
- crashed_tests = crashed_tests + 1
- status = "CRASH"
+ if job.returncode == 0:
+ status = "PASS"
+ passed_tests = passed_tests + 1
+ elif job.returncode == 1:
+ failed_tests = failed_tests + 1
+ status = "FAIL"
+ elif job.returncode == 2:
+ valgrind_errors = valgrind_errors + 1
+ status = "VALGR"
+ else:
+ crashed_tests = crashed_tests + 1
+ status = "CRASH"
print "%s: %s %s" % (status, kind, job.display_name)
@@ -1041,12 +1097,14 @@
example_name = " <Name>%s</Name>\n" % job.display_name
f.write(example_name)
- if job.returncode == 0:
+ if status == "PASS":
f.write(' <Result>PASS</Result>\n')
- elif job.returncode == 1:
+ elif status == "FAIL":
f.write(' <Result>FAIL</Result>\n')
- elif job.returncode == 2:
+ elif status == "VALGR":
f.write(' <Result>VALGR</Result>\n')
+ elif status == "SKIP":
+ f.write(' <Result>SKIP</Result>\n')
else:
f.write(' <Result>CRASH</Result>\n')
@@ -1098,31 +1156,38 @@
# fails valgrind, we'll see the PASS entry for the working TestSuite
# followed by a VALGR failing test suite of the same name.
#
- if job.returncode == 0 or job.returncode == 1 or job.returncode == 2:
- f_to = open(xml_results_file, 'a')
- f_from = open(job.tmp_file_name, 'r')
- f_to.write(f_from.read())
- f_to.close()
- f_from.close()
- else:
+ if job.is_skip:
f = open(xml_results_file, 'a')
f.write("<TestSuite>\n")
f.write(" <SuiteName>%s</SuiteName>\n" % job.display_name)
- f.write(' <SuiteResult>CRASH</SuiteResult>\n')
+ f.write(' <SuiteResult>SKIP</SuiteResult>\n')
f.write(' <SuiteTime>Execution times not available</SuiteTime>\n')
f.write("</TestSuite>\n")
f.close()
+ else:
+ if job.returncode == 0 or job.returncode == 1 or job.returncode == 2:
+ f_to = open(xml_results_file, 'a')
+ f_from = open(job.tmp_file_name, 'r')
+ f_to.write(f_from.read())
+ f_to.close()
+ f_from.close()
+ else:
+ f = open(xml_results_file, 'a')
+ f.write("<TestSuite>\n")
+ f.write(" <SuiteName>%s</SuiteName>\n" % job.display_name)
+ f.write(' <SuiteResult>CRASH</SuiteResult>\n')
+ f.write(' <SuiteTime>Execution times not available</SuiteTime>\n')
+ f.write("</TestSuite>\n")
+ f.close()
- if job.returncode == 2:
- f = open(xml_results_file, 'a')
- f.write("<TestSuite>\n")
- f.write(" <SuiteName>%s</SuiteName>\n" % job.display_name)
- f.write(' <SuiteResult>VALGR</SuiteResult>\n')
- f.write(' <SuiteTime>Execution times not available</SuiteTime>\n')
- f.write("</TestSuite>\n")
- f.close()
-
- os.remove(job.tmp_file_name)
+ if job.returncode == 2:
+ f = open(xml_results_file, 'a')
+ f.write("<TestSuite>\n")
+ f.write(" <SuiteName>%s</SuiteName>\n" % job.display_name)
+ f.write(' <SuiteResult>VALGR</SuiteResult>\n')
+ f.write(' <SuiteTime>Execution times not available</SuiteTime>\n')
+ f.write("</TestSuite>\n")
+ f.close()
#
# We have all of the tests run and the results written out. One final
@@ -1145,8 +1210,8 @@
#
# Print a quick summary of events
#
- print "%d of %d tests passed (%d passed, %d failed, %d crashed, %d valgrind errors)" % (passed_tests, total_tests,
- passed_tests, failed_tests, crashed_tests, valgrind_errors)
+ print "%d of %d tests passed (%d passed, %d skipped, %d failed, %d crashed, %d valgrind errors)" % (passed_tests,
+ total_tests, passed_tests, skipped_tests, failed_tests, crashed_tests, valgrind_errors)
#
# The last things to do are to translate the XML results file to "human
# readable form" if the user asked for it (or make an XML file somewhere)
@@ -1160,14 +1225,21 @@
if len(options.xml):
shutil.copyfile(xml_results_file, options.xml)
- if passed_tests == total_tests:
+ #
+ # If we have been asked to retain all of the little temporary files, we
+ # don't delete tm. If we do delete the temporary files, delete only the
+ # directory we just created. We don't want to happily delete any retained
+ # directories, which will probably surprise the user.
+ #
+ if not options.retain:
+ shutil.rmtree(testpy_output_dir)
+
+ if passed_tests + skipped_tests == total_tests:
return 0 # success
else:
return 1 # catchall for general errors
def main(argv):
- random.seed()
-
parser = optparse.OptionParser()
parser.add_option("-c", "--constrain", action="store", type="string", dest="constrain", default="",
metavar="KIND",
@@ -1203,6 +1275,9 @@
metavar="HTML-FILE",
help="write detailed test results into HTML-FILE.html")
+ parser.add_option("-r", "--retain", action="store_true", dest="retain", default=False,
+ help="retain all temporary files (which are normally deleted)")
+
parser.add_option("-t", "--text", action="store", type="string", dest="text", default="",
metavar="TEXT-FILE",
help="write detailed test results into TEXT-FILE.txt")
Binary file waf has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf-tools/cflags.py Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,192 @@
+import Logs
+import Options
+import Utils
+
+
+class CompilerTraits(object):
+ def get_warnings_flags(self, level):
+ """get_warnings_flags(level) -> list of cflags"""
+ raise NotImplementedError
+
+ def get_optimization_flags(self, level):
+ """get_optimization_flags(level) -> list of cflags"""
+ raise NotImplementedError
+
+ def get_debug_flags(self, level):
+ """get_debug_flags(level) -> (list of cflags, list of cppdefines)"""
+ raise NotImplementedError
+
+
+class GccTraits(CompilerTraits):
+ def __init__(self):
+ super(GccTraits, self).__init__()
+ # cumulative list of warnings per level
+ self.warnings_flags = [['-Wall'], ['-Werror'], ['-Wextra']]
+
+ def get_warnings_flags(self, level):
+ warnings = []
+ for l in range(level):
+ if l < len(self.warnings_flags):
+ warnings.extend(self.warnings_flags[l])
+ else:
+ break
+ return warnings
+
+ def get_optimization_flags(self, level):
+ if level == 0:
+ return ['-O0']
+ elif level == 1:
+ return ['-O']
+ elif level == 2:
+ return ['-O2']
+ elif level == 3:
+ return ['-O3']
+
+ def get_debug_flags(self, level):
+ if level == 0:
+ return (['-g0'], ['NDEBUG'])
+ elif level == 1:
+ return (['-g'], [])
+ elif level >= 2:
+ return (['-ggdb', '-g3'], ['_DEBUG'])
+
+
+class IccTraits(CompilerTraits):
+ def __init__(self):
+ super(IccTraits, self).__init__()
+ # cumulative list of warnings per level
+ # icc is _very_ verbose with -Wall, -Werror is barely achievable
+ self.warnings_flags = [[], [], ['-Wall']]
+
+ def get_warnings_flags(self, level):
+ warnings = []
+ for l in range(level):
+ if l < len(self.warnings_flags):
+ warnings.extend(self.warnings_flags[l])
+ else:
+ break
+ return warnings
+
+ def get_optimization_flags(self, level):
+ if level == 0:
+ return ['-O0']
+ elif level == 1:
+ return ['-O']
+ elif level == 2:
+ return ['-O2']
+ elif level == 3:
+ return ['-O3']
+
+ def get_debug_flags(self, level):
+ if level == 0:
+ return (['-g0'], ['NDEBUG'])
+ elif level == 1:
+ return (['-g'], [])
+ elif level >= 2:
+ return (['-ggdb', '-g3'], ['_DEBUG'])
+
+
+
+class MsvcTraits(CompilerTraits):
+ def __init__(self):
+ super(MsvcTraits, self).__init__()
+ # cumulative list of warnings per level
+ self.warnings_flags = [['/W2'], ['/WX'], ['/Wall']]
+
+ def get_warnings_flags(self, level):
+ warnings = []
+ for l in range(level):
+ if l < len(self.warnings_flags):
+ warnings.extend(self.warnings_flags[l])
+ else:
+ break
+ return warnings
+
+ def get_optimization_flags(self, level):
+ if level == 0:
+ return ['/Od']
+ elif level == 1:
+ return []
+ elif level == 2:
+ return ['/O2']
+ elif level == 3:
+ return ['/Ox']
+
+ def get_debug_flags(self, level):
+ if level == 0:
+ return ([], ['NDEBUG'])
+ elif level == 1:
+ return (['/ZI', '/RTC1'], [])
+ elif level >= 2:
+ return (['/ZI', '/RTC1'], ['_DEBUG'])
+
+
+
+gcc = GccTraits()
+icc = IccTraits()
+msvc = MsvcTraits()
+
+# how to map env['COMPILER_CC'] or env['COMPILER_CXX'] into a traits object
+compiler_mapping = {
+ 'gcc': gcc,
+ 'g++': gcc,
+ 'msvc': msvc,
+ 'icc': icc,
+ 'icpc': icc,
+}
+
+profiles = {
+ # profile name: [optimization_level, warnings_level, debug_level]
+ 'default': [2, 1, 1],
+ 'debug': [0, 2, 3],
+ 'release': [3, 1, 0],
+ }
+
+default_profile = 'default'
+
+def set_options(opt):
+ assert default_profile in profiles
+ opt.add_option('-d', '--build-profile',
+ action='store',
+ default=default_profile,
+ help=("Specify the build profile. "
+ "Build profiles control the default compilation flags"
+ " used for C/C++ programs, if CCFLAGS/CXXFLAGS are not"
+ " set set in the environment. [Allowed Values: %s]"
+ % ", ".join([repr(p) for p in profiles.keys()])),
+ choices=profiles.keys(),
+ dest='build_profile')
+
+def detect(conf):
+ cc = conf.env['COMPILER_CC'] or None
+ cxx = conf.env['COMPILER_CXX'] or None
+ if not (cc or cxx):
+ raise Utils.WafError("neither COMPILER_CC nor COMPILER_CXX are defined; "
+ "maybe the compiler_cc or compiler_cxx tool has not been configured yet?")
+
+ try:
+ compiler = compiler_mapping[cc]
+ except KeyError:
+ try:
+ compiler = compiler_mapping[cxx]
+ except KeyError:
+ Logs.warn("No compiler flags support for compiler %r or %r"
+ % (cc, cxx))
+ return
+
+ opt_level, warn_level, dbg_level = profiles[Options.options.build_profile]
+
+ optimizations = compiler.get_optimization_flags(opt_level)
+ debug, debug_defs = compiler.get_debug_flags(dbg_level)
+ warnings = compiler.get_warnings_flags(warn_level)
+
+ if cc and not conf.env['CCFLAGS']:
+ conf.env.append_value('CCFLAGS', optimizations)
+ conf.env.append_value('CCFLAGS', debug)
+ conf.env.append_value('CCFLAGS', warnings)
+ conf.env.append_value('CCDEFINES', debug_defs)
+ if cxx and not conf.env['CXXFLAGS']:
+ conf.env.append_value('CXXFLAGS', optimizations)
+ conf.env.append_value('CXXFLAGS', debug)
+ conf.env.append_value('CXXFLAGS', warnings)
+ conf.env.append_value('CXXDEFINES', debug_defs)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf-tools/command.py Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,134 @@
+from TaskGen import feature, taskgen, before, task_gen
+import Node, Task, Utils, Build, pproc, Constants
+import Options
+
+import shellcmd
+shellcmd.subprocess = pproc # the WAF version of the subprocess module is supposedly less buggy
+
+from Logs import debug, error
+shellcmd.debug = debug
+
+import Task
+
+import re
+
+
+arg_rx = re.compile(r"(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})", re.M)
+
+class command_task(Task.Task):
+ color = "BLUE"
+ def __init__(self, env, generator):
+ Task.Task.__init__(self, env, normal=1, generator=generator)
+
+ def __str__(self):
+ "string to display to the user"
+ env = self.env
+ src_str = ' '.join([a.nice_path(env) for a in self.inputs])
+ tgt_str = ' '.join([a.nice_path(env) for a in self.outputs])
+ if self.outputs:
+ sep = ' -> '
+ else:
+ sep = ''
+
+ pipeline = shellcmd.Pipeline()
+ pipeline.parse(self.generator.command)
+ cmd = pipeline.get_abbreviated_command()
+
+ return 'command (%s): %s%s%s\n' % (cmd, src_str, sep, tgt_str)
+
+ def _subst_arg(self, arg, direction, namespace):
+ """
+ @param arg: the command argument (or stdin/stdout/stderr) to substitute
+ @param direction: direction of the argument: 'in', 'out', or None
+ """
+ def repl(match):
+ if match.group('dollar'):
+ return "$"
+ elif match.group('subst'):
+ var = match.group('var')
+ code = match.group('code')
+ result = eval(var+code, namespace)
+ if isinstance(result, Node.Node):
+ if var == 'TGT':
+ return result.bldpath(self.env)
+ elif var == 'SRC':
+ return result.srcpath(self.env)
+ else:
+ raise ValueError("Bad subst variable %r" % var)
+ elif result is self.inputs:
+ if len(self.inputs) == 1:
+ return result[0].srcpath(self.env)
+ else:
+ raise ValueError("${SRC} requested but have multiple sources; which one?")
+ elif result is self.outputs:
+ if len(self.outputs) == 1:
+ return result[0].bldpath(self.env)
+ else:
+ raise ValueError("${TGT} requested but have multiple targets; which one?")
+ else:
+ return result
+ return None
+
+ return arg_rx.sub(repl, arg)
+
+ def run(self):
+ pipeline = shellcmd.Pipeline()
+ pipeline.parse(self.generator.command)
+ namespace = self.env.get_merged_dict()
+ if self.generator.variables is not None:
+ namespace.update(self.generator.variables)
+ namespace.update(env=self.env, SRC=self.inputs, TGT=self.outputs)
+ for cmd in pipeline.pipeline:
+ if isinstance(cmd, shellcmd.Command):
+ if isinstance(cmd.stdin, basestring):
+ cmd.stdin = self._subst_arg(cmd.stdin, 'in', namespace)
+ if isinstance(cmd.stdout, basestring):
+ cmd.stdout = self._subst_arg(cmd.stdout, 'out', namespace)
+ if isinstance(cmd.stderr, basestring):
+ cmd.stderr = self._subst_arg(cmd.stderr, 'out', namespace)
+ for argI in xrange(len(cmd.argv)):
+ cmd.argv[argI] = self._subst_arg(cmd.argv[argI], None, namespace)
+ if cmd.env_vars is not None:
+ env_vars = dict()
+ for name, value in cmd.env_vars.iteritems():
+ env_vars[name] = self._subst_arg(value, None, namespace)
+ cmd.env_vars = env_vars
+ elif isinstance(cmd, shellcmd.Chdir):
+ cmd.dir = self._subst_arg(cmd.dir, None, namespace)
+
+ return pipeline.run(verbose=(Options.options.verbose > 0))
+
+@taskgen
+@feature('command')
+def init_command(self):
+ Utils.def_attrs(self,
+ # other variables that can be used in the command: ${VARIABLE}
+ variables = None)
+
+
+
+@taskgen
+@feature('command')
+@before('apply_core')
+def apply_command(self):
+ self.meths.remove('apply_core')
+ # create the task
+ task = self.create_task('command')
+ setattr(task, "dep_vars", getattr(self, "dep_vars", None))
+ # process the sources
+ inputs = []
+ for src in self.to_list(self.source):
+ node = self.path.find_resource(src)
+ if node is None:
+ raise Utils.WafError("source %s not found" % src)
+ inputs.append(node)
+ task.set_inputs(inputs)
+ task.set_outputs([self.path.find_or_declare(tgt) for tgt in self.to_list(self.target)])
+ #Task.file_deps = Task.extract_deps
+
+
+
+class command_taskgen(task_gen):
+ def __init__(self, *k, **kw):
+ task_gen.__init__(self, *k, **kw)
+ self.features.append('command')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf-tools/pkgconfig.py Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,71 @@
+# -*- mode: python; encoding: utf-8 -*-
+# Gustavo Carneiro (gjamc) 2008
+
+import Options
+import Configure
+import pproc as subprocess
+import config_c
+
+def detect(conf):
+ pkg_config = conf.find_program('pkg-config', var='PKG_CONFIG')
+ if not pkg_config: return
+
+@Configure.conf
+def pkg_check_modules(conf, uselib_name, expression, mandatory=True):
+ pkg_config = conf.env['PKG_CONFIG']
+ if not pkg_config:
+ if mandatory:
+ conf.fatal("pkg-config is not available")
+ else:
+ return False
+
+ argv = [pkg_config, '--cflags', '--libs', expression]
+ cmd = subprocess.Popen(argv, stdout=subprocess.PIPE)
+ out, dummy = cmd.communicate()
+ retval = cmd.wait()
+
+ msg_checking = ("pkg-config flags for %s" % (uselib_name,))
+ if Options.options.verbose:
+ if retval == 0:
+ conf.check_message_custom(msg_checking,
+ ('(%s)' % expression), out)
+ else:
+ conf.check_message(msg_checking, ('(%s)' % expression), False)
+ else:
+ conf.check_message(msg_checking, '', (retval == 0), '')
+ conf.log.write('%r: %r (exit code %i)\n' % (argv, out, retval))
+
+ if retval == 0:
+
+ config_c.parse_flags(out, uselib_name, conf.env)
+ conf.env[uselib_name] = True
+ return True
+
+ else:
+
+ conf.env[uselib_name] = False
+ if mandatory:
+ raise Configure.ConfigurationError('pkg-config check failed')
+ else:
+ return False
+
+@Configure.conf
+def pkg_check_module_variable(conf, module, variable):
+ pkg_config = conf.env['PKG_CONFIG']
+ if not pkg_config:
+ conf.fatal("pkg-config is not available")
+
+ argv = [pkg_config, '--variable', variable, module]
+ cmd = subprocess.Popen(argv, stdout=subprocess.PIPE)
+ out, dummy = cmd.communicate()
+ retval = cmd.wait()
+ out = out.rstrip() # strip the trailing newline
+
+ msg_checking = ("pkg-config variable %r in %s" % (variable, module,))
+ conf.check_message_custom(msg_checking, '', out)
+ conf.log.write('%r: %r (exit code %i)\n' % (argv, out, retval))
+
+ if retval == 0:
+ return out
+ else:
+ raise Configure.ConfigurationError('pkg-config check failed')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/waf-tools/shellcmd.py Mon Oct 26 09:21:20 2009 +0300
@@ -0,0 +1,345 @@
+# Copyright (C) 2008 Gustavo J. A. M. Carneiro <gjcarneiro@gmail.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# 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
+
+import shlex
+import subprocess
+import sys
+import re
+import os
+
+env_var_rx = re.compile(r"^([a-zA-Z0-9_]+)=(\S+)$")
+
+def debug(message):
+ print >> sys.stderr, message
+
+
+if sys.platform == 'win32':
+ dev_null = open("NUL:", "w")
+else:
+ dev_null = open("/dev/null", "w")
+
+def _open_out_file(filename):
+ if filename in ['NUL:', '/dev/null']:
+ return dev_null
+ else:
+ return open(filename, 'wb')
+
+
+class Node(object):
+ pass
+
+class Op(Node):
+ pass
+
+class Pipe(Op):
+ pass
+
+class And(Op):
+ pass
+
+class Or(Op):
+ pass
+
+class Command(Node):
+ class PIPE(object):
+ pass # PIPE is a constant
+ class STDOUT(object):
+ pass # PIPE is a constant
+
+ def __init__(self, name):
+ super(Command, self).__init__()
+ self.name = name # command name
+ self.argv = [name] # command argv
+ self.stdin = None
+ self.stdout = None
+ self.stderr = None
+ self.env_vars = None
+
+ def __repr__(self):
+ return "Command(%r, argv=%r, stdin=%r, stdout=%r, stderr=%r)" \
+ % (self.name, self.argv, self.stdin, self.stdout, self.stderr)
+
+class Chdir(Node):
+ def __init__(self):
+ super(Chdir, self).__init__()
+ self.dir = None
+
+ def __repr__(self):
+ return "Chdir(%r)" \
+ % (self.dir)
+
+class Pipeline(object):
+ def __init__(self):
+ self.current_command = None
+ self.pipeline = []
+
+ def _commit_command(self):
+ assert self.current_command is not None
+ self.pipeline.append(self.current_command)
+ self.current_command = None
+
+ def get_abbreviated_command(self):
+ l = []
+ for node in self.pipeline:
+ if isinstance(node, Command):
+ l.append(node.name)
+ if isinstance(node, Chdir):
+ l.append('cd %s' % node.dir)
+ elif isinstance(node, Pipe):
+ l.append('|')
+ elif isinstance(node, And):
+ l.append('&&')
+ elif isinstance(node, And):
+ l.append('||')
+ return ' '.join(l)
+
+ def parse(self, command):
+ self.current_command = None
+ self.pipeline = []
+
+ if isinstance(command, list):
+ tokens = list(command)
+ else:
+ tokens = shlex.split(command)
+ debug("command: shlex: %r" % (tokens,))
+
+ BEGIN, COMMAND, CHDIR, STDERR, STDOUT, STDIN = range(6)
+ state = BEGIN
+ self.current_command = None
+ env_vars = dict()
+
+ while tokens:
+ token = tokens.pop(0)
+ if state == BEGIN:
+ env_var_match = env_var_rx.match(token)
+ if env_var_match is not None:
+ env_vars[env_var_match.group(1)] = env_var_match.group(2)
+ else:
+ assert self.current_command is None
+ if token == 'cd':
+ self.current_command = Chdir()
+ assert not env_vars
+ state = CHDIR
+ else:
+ self.current_command = Command(token)
+ if env_vars:
+ self.current_command.env_vars = env_vars
+ env_vars = dict()
+ state = COMMAND
+ elif state == COMMAND:
+ if token == '>':
+ state = STDOUT
+ elif token == '2>':
+ state = STDERR
+ elif token == '2>&1':
+ assert self.current_command.stderr is None
+ self.current_command.stderr = Command.STDOUT
+ elif token == '<':
+ state = STDIN
+ elif token == '|':
+ assert self.current_command.stdout is None
+ self.current_command.stdout = Command.PIPE
+ self._commit_command()
+ self.pipeline.append(Pipe())
+ state = BEGIN
+ elif token == '&&':
+ self._commit_command()
+ self.pipeline.append(And())
+ state = BEGIN
+ elif token == '||':
+ self._commit_command()
+ self.pipeline.append(Or())
+ state = BEGIN
+ else:
+ self.current_command.argv.append(token)
+ elif state == CHDIR:
+ if token == '&&':
+ self._commit_command()
+ self.pipeline.append(And())
+ state = BEGIN
+ else:
+ assert self.current_command.dir is None
+ self.current_command.dir = token
+ elif state == STDOUT:
+ assert self.current_command.stdout is None
+ self.current_command.stdout = token
+ state = COMMAND
+ elif state == STDERR:
+ assert self.current_command.stderr is None
+ self.current_command.stderr = token
+ state = COMMAND
+ elif state == STDIN:
+ assert self.current_command.stdin is None
+ self.current_command.stdin = token
+ state = COMMAND
+ self._commit_command()
+ return self.pipeline
+
+ def _exec_piped_commands(self, commands):
+ retvals = []
+ for cmd in commands:
+ retvals.append(cmd.wait())
+ retval = 0
+ for r in retvals:
+ if r:
+ retval = retvals[-1]
+ break
+ return retval
+
+ def run(self, verbose=False):
+ pipeline = list(self.pipeline)
+ files_to_close = []
+ piped_commands = []
+ piped_commands_display = []
+ BEGIN, PIPE = range(2)
+ state = BEGIN
+ cwd = '.'
+ while pipeline:
+ node = pipeline.pop(0)
+
+ if isinstance(node, Chdir):
+ next_op = pipeline.pop(0)
+ assert isinstance(next_op, And)
+ cwd = os.path.join(cwd, node.dir)
+ if verbose:
+ piped_commands_display.append("cd %s &&" % node.dir)
+ continue
+
+ assert isinstance(node, (Command, Chdir))
+ cmd = node
+ if verbose:
+ if cmd.env_vars:
+ env_vars_str = ' '.join(['%s=%s' % (key, val) for key, val in cmd.env_vars.iteritems()])
+ piped_commands_display.append("%s %s" % (env_vars_str, ' '.join(cmd.argv)))
+ else:
+ piped_commands_display.append(' '.join(cmd.argv))
+
+ if state == PIPE:
+ stdin = piped_commands[-1].stdout
+ elif cmd.stdin is not None:
+ stdin = open(cmd.stdin, "r")
+ if verbose:
+ piped_commands_display.append('< %s' % cmd.stdin)
+ files_to_close.append(stdin)
+ else:
+ stdin = None
+
+ if cmd.stdout is None:
+ stdout = None
+ elif cmd.stdout is Command.PIPE:
+ stdout = subprocess.PIPE
+ else:
+ stdout = _open_out_file(cmd.stdout)
+ files_to_close.append(stdout)
+ if verbose:
+ piped_commands_display.append('> %s' % cmd.stdout)
+
+ if cmd.stderr is None:
+ stderr = None
+ elif cmd.stderr is Command.PIPE:
+ stderr = subprocess.PIPE
+ elif cmd.stderr is Command.STDOUT:
+ stderr = subprocess.STDOUT
+ if verbose:
+ piped_commands_display.append('2>&1')
+ else:
+ stderr = _open_out_file(cmd.stderr)
+ files_to_close.append(stderr)
+ if verbose:
+ piped_commands_display.append('2> %s' % cmd.stderr)
+
+ if cmd.env_vars:
+ env = dict(os.environ)
+ env.update(cmd.env_vars)
+ else:
+ env = None
+
+ if cwd == '.':
+ proc_cwd = None
+ else:
+ proc_cwd = cwd
+
+ debug("command: subprocess.Popen(argv=%r, stdin=%r, stdout=%r, stderr=%r, env_vars=%r, cwd=%r)"
+ % (cmd.argv, stdin, stdout, stderr, cmd.env_vars, proc_cwd))
+ proc = subprocess.Popen(cmd.argv, stdin=stdin, stdout=stdout, stderr=stderr, env=env, cwd=proc_cwd)
+ del stdin, stdout, stderr
+ piped_commands.append(proc)
+
+ try:
+ next_node = pipeline.pop(0)
+ except IndexError:
+ try:
+ retval = self._exec_piped_commands(piped_commands)
+ if verbose:
+ print "%s: exit code %i" % (' '.join(piped_commands_display), retval)
+ finally:
+ for f in files_to_close:
+ if f is not dev_null:
+ f.close()
+ files_to_close = []
+ return retval
+ else:
+
+ if isinstance(next_node, Pipe):
+ state = PIPE
+ piped_commands_display.append('|')
+
+ elif isinstance(next_node, Or):
+ try:
+ this_retval = self._exec_piped_commands(piped_commands)
+ finally:
+ for f in files_to_close:
+ if f is not dev_null:
+ f.close()
+ files_to_close = []
+ if this_retval == 0:
+ if verbose:
+ print "%s: exit code %i (|| is short-circuited)" % (' '.join(piped_commands_display), retval)
+ return this_retval
+ if verbose:
+ print "%s: exit code %i (|| proceeds)" % (' '.join(piped_commands_display), retval)
+ state = BEGIN
+ piped_commands = []
+ piped_commands_display = []
+
+ elif isinstance(next_node, And):
+ try:
+ this_retval = self._exec_piped_commands(piped_commands)
+ finally:
+ for f in files_to_close:
+ if f is not dev_null:
+ f.close()
+ files_to_close = []
+ if this_retval != 0:
+ if verbose:
+ print "%s: exit code %i (&& is short-circuited)" % (' '.join(piped_commands_display), retval)
+ return this_retval
+ if verbose:
+ print "%s: exit code %i (&& proceeds)" % (' '.join(piped_commands_display), retval)
+ state = BEGIN
+ piped_commands = []
+ piped_commands_display = []
+
+
+
+def _main():
+ pipeline = Pipeline()
+ pipeline.parse('./foo.py 2>&1 < xxx | cat && ls')
+ print pipeline.run()
+
+if __name__ == '__main__':
+ _main()
+
--- a/wscript Thu Oct 22 17:17:40 2009 +0400
+++ b/wscript Mon Oct 26 09:21:20 2009 +0300
@@ -27,11 +27,14 @@
import Configure
import Scripting
+sys.path.insert(0, os.path.abspath('waf-tools'))
+
import cflags # override the build profiles from waf
cflags.profiles = {
# profile name: [optimization_level, warnings_level, debug_level]
'debug': [0, 2, 3],
'optimized': [3, 2, 1],
+ 'release': [3, 2, 0],
}
cflags.default_profile = 'debug'
@@ -137,16 +140,6 @@
action="store_true", default=False,
dest='lcov_report')
- opt.add_option('--doxygen',
- help=('Run doxygen to generate html documentation from source comments'),
- action="store_true", default=False,
- dest='doxygen')
- opt.add_option('--doxygen-no-build',
- help=('Run doxygen to generate html documentation from source comments, '
- 'but do not wait for ns-3 to finish the full build.'),
- action="store_true", default=False,
- dest='doxygen_no_build')
-
opt.add_option('--run',
help=('Run a locally built program; argument can be a program name,'
' or a command starting with the program name.'),
@@ -289,6 +282,10 @@
env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')
env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE')
+ if Options.options.build_profile == 'release':
+ env.append_value('CXXFLAGS', '-fomit-frame-pointer')
+ env.append_value('CXXFLAGS', '-march=native')
+
env['PLATFORM'] = sys.platform
if conf.env['CXX_NAME'] in ['gcc', 'icc']:
@@ -385,6 +382,14 @@
conf.env.append_value('CXXDEFINES', "ENABLE_GSL")
conf.env.append_value('CCDEFINES', "ENABLE_GSL")
+ # append user defined flags after all our ones
+ for (confvar, envvar) in [['CCFLAGS', 'CCFLAGS_EXTRA'],
+ ['CXXFLAGS', 'CXXFLAGS_EXTRA'],
+ ['LINKFLAGS', 'LINKFLAGS_EXTRA'],
+ ['LINKFLAGS', 'LDFLAGS_EXTRA']]:
+ if envvar in os.environ:
+ conf.env.append_value(confvar, os.environ[envvar])
+
# Write a summary of optional features status
print "---- Summary of optional NS-3 features:"
for (name, caption, was_enabled, reason_not_enabled) in conf.env['NS3_OPTIONAL_FEATURES']:
@@ -590,25 +595,12 @@
raise Utils.WafError("Cannot run regression tests: building the ns-3 examples is not enabled"
" (regression tests are based on examples)")
-# if Options.options.check:
-# Options.options.compile_targets += ',run-tests'
-# if env['ENABLE_PYTHON_BINDINGS']:
-# Options.options.compile_targets += ',ns3module,pybindgen-command'
-# _run_check(bld)
-
- if Options.options.doxygen_no_build:
- doxygen()
- raise SystemExit(0)
-
def shutdown(ctx):
bld = wutils.bld
if wutils.bld is None:
return
env = bld.env
- #if Options.commands['check']:
- # _run_waf_check()
-
if Options.options.lcov_report:
lcov_report()
@@ -626,25 +618,14 @@
if Options.options.check:
raise Utils.WafError("Please run `./test.py' now, instead of `./waf --check'")
- if Options.options.doxygen:
- doxygen()
- raise SystemExit(0)
-
check_shell(bld)
- if Options.options.doxygen:
- doxygen()
- raise SystemExit(0)
-
-
check_context = Build.BuildContext
def check(bld):
"""run the equivalent of the old ns-3 unit tests using test.py"""
- bld = wutils.bld
- env = bld.env
- wutils.run_python_program("test.py -c core", env)
-
+ env = wutils.bld.env
+ wutils.run_python_program("test.py -n -c core", env)
class print_introspected_doxygen_task(Task.TaskBase):
after = 'cc cxx cc_link cxx_link'
@@ -696,111 +677,6 @@
wutils.run_argv([self.bld.env['PYTHON'], os.path.join("..", "utils", "python-unit-tests.py")],
self.bld.env, proc_env, force_no_valgrind=True)
-#class run_a_unit_test_task(Task.TaskBase):
-# after = 'cc cxx cc_link cxx_link'
-# color = 'BLUE'
-#
-# def __init__(self, bld, name_of_test):
-# self.bld = bld
-# super(run_a_unit_test_task, self).__init__(generator=self)
-# self.name_of_test = name_of_test
-# try:
-# program_obj = wutils.find_program("run-tests", self.bld.env)
-# except ValueError, ex:
-# raise Utils.WafError(str(ex))
-# program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
-# self.program_path = program_node.abspath(self.bld.env)
-#
-# def __str__(self):
-# return 'run-unit-test(%s)\n' % self.name_of_test
-#
-# def runnable_status(self):
-# return Task.RUN_ME
-#
-# def run(self):
-# #print repr([self.program_path, self.name_of_test])
-# try:
-# self.retval = wutils.run_argv([self.program_path, self.name_of_test], self.bld.env)
-# except Utils.WafError:
-# self.retval = 1
-# #print "running test %s: exit with %i" % (self.name_of_test, retval)
-# return 0
-#
-#class get_list_of_unit_tests_task(Task.TaskBase):
-# after = 'cc cxx cc_link cxx_link'
-# color = 'BLUE'
-#
-# def __init__(self, bld):
-# self.bld = bld
-# super(get_list_of_unit_tests_task, self).__init__(generator=self)
-# self.tests = []
-#
-# def __str__(self):
-# return 'get-unit-tests-list\n'
-#
-# def runnable_status(self):
-# return Task.RUN_ME
-#
-# def run(self):
-# try:
-# program_obj = wutils.find_program("run-tests", self.bld.env)
-# except ValueError, ex:
-# raise Utils.WafError(str(ex))
-# program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
-# program_path = program_node.abspath(self.bld.env)
-# proc = subprocess.Popen([program_path, "--ListTests"], stdout=subprocess.PIPE,
-# env=wutils.get_proc_env())
-# self.tests = [l.rstrip() for l in proc.stdout.readlines()]
-# retval = proc.wait()
-# if retval:
-# return retval
-# test_tasks = []
-# for name_of_test in self.tests:
-# test_tasks.append(run_a_unit_test_task(self.bld, name_of_test))
-# collector = collect_unit_test_results_task(self.bld, list(test_tasks))
-# collector.run_after = list(test_tasks)
-# self.more_tasks = [collector] + test_tasks
-#
-#
-#class collect_unit_test_results_task(Task.TaskBase):
-# after = 'run_a_unit_test_task'
-# color = 'BLUE'
-#
-# def __init__(self, bld, test_tasks):
-# self.bld = bld
-# super(collect_unit_test_results_task, self).__init__(generator=self)
-# self.test_tasks = test_tasks
-#
-# def __str__(self):
-# return 'collect-unit-tests-results\n'
-#
-# def runnable_status(self):
-# for t in self.run_after:
-# if not t.hasrun:
-# return Task.ASK_LATER
-# return Task.RUN_ME
-#
-# def run(self):
-# failed_tasks = []
-# for task in self.test_tasks:
-# if task.retval:
-# failed_tasks.append(task)
-# if failed_tasks:
-# print "C++ UNIT TESTS: %i tests passed, %i failed (%s)." % \
-# (len(self.test_tasks) - len(failed_tasks), len(failed_tasks),
-# ', '.join(t.name_of_test for t in failed_tasks))
-# return 1
-# else:
-# print "C++ UNIT TESTS: all %i tests passed." % (len(self.test_tasks),)
-# return 0
-#
-#
-#def _run_check(bld):
-# task = get_list_of_unit_tests_task(bld)
-# print_introspected_doxygen_task(bld)
-# if bld.env['ENABLE_PYTHON_BINDINGS']:
-# run_python_unit_tests_task(bld)
-
def check_shell(bld):
if 'NS3_MODULE_PATH' not in os.environ:
return
@@ -835,11 +711,26 @@
env = wutils.bld.env
wutils.run_argv([shell], env, {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH'])})
-def doxygen():
- if not os.path.exists('doc/introspected-doxygen.h'):
- Logs.warn("doc/introspected-doxygen.h does not exist; run waf check to generate it.")
+def doxygen(bld):
+ """do a full build, generate the introspected doxygen and then the doxygen"""
+ Scripting.build(bld)
+ env = wutils.bld.env
+ proc_env = wutils.get_proc_env()
- ## run doxygen
+ try:
+ program_obj = wutils.find_program('print-introspected-doxygen', env)
+ except ValueError:
+ Logs.warn("print-introspected-doxygen does not exist")
+ raise SystemExit(1)
+ return
+
+ prog = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)).abspath(env)
+ out = open(os.path.join('doc', 'introspected-doxygen.h'), 'w')
+
+ if subprocess.Popen([prog], stdout=out, env=proc_env).wait():
+ raise SystemExit(1)
+ out.close()
+
doxygen_config = os.path.join('doc', 'doxygen.conf')
if subprocess.Popen(['doxygen', doxygen_config]).wait():
raise SystemExit(1)
@@ -876,9 +767,6 @@
finally:
os.chdir("..")
-
-
-
##
## The default WAF DistDir implementation is rather slow, because it
## first copies everything and only later removes unwanted files and