Compare commits
19 Commits
ns-3.6-RC2
...
ns-3.6-RC4
| Author | SHA1 | Date | |
|---|---|---|---|
| d59f3b1bb4 | |||
| 6450db55f2 | |||
| 30dac288f5 | |||
| 0b559a7c8c | |||
| c381234e62 | |||
| 42ba205efd | |||
| 6a6de8bbfa | |||
| 41c62223ee | |||
| ae2b92f330 | |||
| 1a742a3c02 | |||
| c237cbe114 | |||
| 117fa7f3c2 | |||
| d0ffc407ac | |||
| c0d01261d0 | |||
| b252f68f9d | |||
| af27a1388c | |||
| ac9dc12e94 | |||
| 4eba1f033e | |||
| 4fb0057dc7 |
@@ -37,3 +37,5 @@ dfd0bc16dc991313896f351530a3dc5a25f62e15 ns-3.3-RC4
|
||||
a600c11ff8d40a40e88c2d692acad6512dde70c8 ns-3.5-rc3
|
||||
c975274c9707b1f07d94cc51f205c351122131a5 ns-3.5
|
||||
549243b47311211975b388cd64fcb9111caa2fc2 ns-3.6-RC1
|
||||
8996042990466b1eda718a848e1c02923c0add74 ns-3.6-RC2
|
||||
79ff6ad1adbb7b4677759ddf52028b68b0515168 ns-3.6-RC3
|
||||
|
||||
+5
-6
@@ -17,7 +17,7 @@ http://www.nsnam.org/releases/ns-allinone-3.6.tar.bz2
|
||||
Supported platforms
|
||||
-------------------
|
||||
ns-3.6 has been tested on the following platforms:
|
||||
- linux x86 gcc 4.2, 4.1, and, 3.4.6.
|
||||
- linux x86 gcc 4.4.1, 4.2, 4.1, and, 3.4.6.
|
||||
- linux x86_64 gcc 4.4.0, 4.3.2, 4.2.3, 4.2.1, 4.1.3, 3.4.6
|
||||
- MacOS X ppc and x86 (gcc 4.0.x and 4.2.x)
|
||||
- cygwin gcc 3.4.4 (debug only), gcc 4.3.2 (debug and optimized)
|
||||
@@ -68,10 +68,13 @@ New user-visible features
|
||||
- Previous unit tests have been ported to new framework.
|
||||
- Examples are tested for run-ability.
|
||||
|
||||
f) A new Flow Monitor module
|
||||
- To very easily measure flow metrics in a simulation
|
||||
- No need to use trace callbacks or parsing trace files
|
||||
|
||||
API changes from ns-3.5
|
||||
-----------------------
|
||||
API changes for this release are documented in the file CHANGES.html.
|
||||
XXX
|
||||
|
||||
Known issues
|
||||
------------
|
||||
@@ -80,10 +83,6 @@ ns-3 build is known to fail on the following platforms:
|
||||
- optimized builds on gcc 3.4.4 and 3.4.5
|
||||
- optimized builds on linux x86 gcc 4.0.x
|
||||
|
||||
Future releases
|
||||
---------------
|
||||
XXX
|
||||
|
||||
Release 3.5
|
||||
===========
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import Build
|
||||
import Utils
|
||||
|
||||
## https://launchpad.net/pybindgen/
|
||||
REQUIRED_PYBINDGEN_VERSION = (0, 12, 0, 700)
|
||||
REQUIRED_PYBINDGEN_VERSION = (0, 12, 0, 703)
|
||||
REQUIRED_PYGCCXML_VERSION = (0, 9, 5)
|
||||
|
||||
|
||||
|
||||
+4
-1
@@ -17,6 +17,7 @@ IMAGES_EPS = \
|
||||
$(FIGURES)/node.eps \
|
||||
$(FIGURES)/buffer.eps \
|
||||
$(FIGURES)/sockets-overview.eps \
|
||||
$(FIGURES)/software-organization.eps \
|
||||
$(FIGURES)/routing.eps \
|
||||
$(FIGURES)/routing-specialization.eps \
|
||||
$(FIGURES)/testbed.eps \
|
||||
@@ -71,6 +72,8 @@ figures-clean:
|
||||
version:
|
||||
echo -n "ns-" > VERSION-PREFIX; cat VERSION-PREFIX ../../VERSION > VERSION; rm -rf VERSION-PREFIX
|
||||
|
||||
clean: figures-clean
|
||||
texi-clean:
|
||||
rm -rf manual.aux manual.cp manual.cps manual.fn manual.ky manual.pg manual.tp
|
||||
rm -rf manual.vr manual.toc manual.log manual.pdf manual.html manual/ VERSION
|
||||
|
||||
clean: figures-clean texi-clean
|
||||
|
||||
@@ -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.
|
||||
@@ -0,0 +1,6 @@
|
||||
@node Applications
|
||||
@chapter Applications
|
||||
|
||||
@cartouche
|
||||
Placeholder chapter
|
||||
@end cartouche
|
||||
+99
-50
@@ -125,7 +125,8 @@ public:
|
||||
|
||||
This is defined in the node.cc file as follows:
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
TypeId
|
||||
Node::GetTypeId (void)
|
||||
{
|
||||
@@ -148,15 +149,16 @@ Node::GetTypeId (void)
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
Look at the TypeId of an ns-3 @code{Object} class as an extended form of run
|
||||
time type information (RTTI). The C++ language includes simple kind of RTTI
|
||||
Consider the TypeId of an ns-3 @code{Object} class as an extended form of run
|
||||
time type information (RTTI). The C++ language includes a simple kind of RTTI
|
||||
in order to support @code{dynamic_cast} and @code{typeid} operators.
|
||||
|
||||
The ``@code{.SetParent<Object> ()}'' call in the declaration above is used in
|
||||
conjunction with our object aggregation mechanisms to allow safe up- and
|
||||
down-casing in inheritance trees during @code{GetObject}.
|
||||
down-casting in inheritance trees during @code{GetObject}.
|
||||
|
||||
The ``@code{.AddConstructor<Node> ()}'' call is used in conjunction with our
|
||||
abstract object factory mechanisms to allow us to construct C++ objects without
|
||||
@@ -183,7 +185,7 @@ without even knowing the concrete C++ type
|
||||
@verbatim
|
||||
ObjectFactory factory;
|
||||
const std::string typeId = "ns3::Node'';
|
||||
factory.SetTypeId(typeId);
|
||||
factory.SetTypeId (typeId);
|
||||
Ptr<Object> node = factory.Create <Object> ();
|
||||
@end verbatim
|
||||
|
||||
@@ -259,7 +261,8 @@ and some type of global default value.
|
||||
In the ns-3 attribute system, these value definitions and accessor
|
||||
functions are moved into the TypeId class; e.g.:
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
NS_OBJECT_ENSURE_REGISTERED (DropTailQueue);
|
||||
|
||||
TypeId DropTailQueue::GetTypeId (void)
|
||||
@@ -276,7 +279,8 @@ TypeId DropTailQueue::GetTypeId (void)
|
||||
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
The AddAttribute() method is performing a number of things with this
|
||||
value:
|
||||
@@ -295,11 +299,19 @@ section, we will provide an example script that shows how users
|
||||
may manipulate these values.
|
||||
|
||||
Note that initialization of the attribute relies on the macro
|
||||
NS_OBJECT_ENSURE_REGISTERED (DropTailQueue) being called; if you leave
|
||||
@code{NS_OBJECT_ENSURE_REGISTERED} (DropTailQueue) being called; if you leave
|
||||
this out of your new class implementation, your attributes will not be
|
||||
initialized correctly.
|
||||
|
||||
@subsection Basic usage
|
||||
While we have described how to create attributes, we still haven't
|
||||
described how to access and manage these values. For instance, there is no
|
||||
@code{globals.h} header file where these are stored; attributes are
|
||||
stored with their classes. Questions that naturally arise are how
|
||||
do users easily learn about all of the attributes of their models, and
|
||||
how does a user access these attributes, or document their values
|
||||
as part of the record of their simulation?
|
||||
|
||||
@subsection Default values and command-line arguments
|
||||
|
||||
Let's look at how a user script might access these values.
|
||||
This is based on the script found at @code{samples/main-attribute-value.cc},
|
||||
@@ -341,7 +353,8 @@ Now, we will create a few objects using the low-level API; here,
|
||||
our newly created queues will not have a m_maxPackets initialized to
|
||||
100 packets but to 80 packets, because of what we did above with
|
||||
default values.
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
Ptr<Node> n0 = CreateObject<Node> ();
|
||||
|
||||
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
|
||||
@@ -349,7 +362,8 @@ default values.
|
||||
|
||||
Ptr<Queue> q = CreateObject<DropTailQueue> ();
|
||||
net0->AddQueue(q);
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
At this point, we have created a single node (Node 0) and a
|
||||
single PointToPointNetDevice (NetDevice 0) and added a
|
||||
@@ -358,10 +372,10 @@ DropTailQueue to it.
|
||||
Now, we can manipulate the MaxPackets value of the already
|
||||
instantiated DropTailQueue. Here are various ways to do that.
|
||||
|
||||
@subsubsection Pointer-based access
|
||||
@subsection Pointer-based access
|
||||
|
||||
We assume that a smart pointer (Ptr) to a relevant network device is
|
||||
in hand; here, it is the net0 pointer.
|
||||
in hand; in the current example, it is the @code{net0} pointer.
|
||||
|
||||
One way to change the value is to access a pointer to the
|
||||
underlying queue and modify its attribute.
|
||||
@@ -369,11 +383,11 @@ underlying queue and modify its attribute.
|
||||
First, we observe that we can get a pointer to the (base class)
|
||||
queue via the PointToPointNetDevice attributes, where it is called
|
||||
TxQueue
|
||||
@verbatim
|
||||
@example
|
||||
PointerValue tmp;
|
||||
net0->GetAttribute ("TxQueue", tmp);
|
||||
Ptr<Object> txQueue = tmp.GetObject ();
|
||||
@end verbatim
|
||||
@end example
|
||||
|
||||
Using the GetObject function, we can perform a safe downcast
|
||||
to a DropTailQueue, where MaxPackets is a member
|
||||
@@ -409,44 +423,52 @@ Now, let's set it to another value (60 packets)
|
||||
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
@subsubsection Namespace-based access
|
||||
@subsection Namespace-based access
|
||||
|
||||
An alternative way to get at the attribute is to use the configuration namespace.
|
||||
Here, this attribute resides on a known path in this namespace; this approach
|
||||
is useful if one doesn't have access to the underlying pointers and would like
|
||||
to configure a specific attribute with a single statement.
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25));
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
|
||||
limit.Get () << " packets");
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
We could have also used wildcards to set this value for all nodes and all net
|
||||
devices (which in this simple example has the same effect as the previous Set())
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15));
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
|
||||
limit.Get () << " packets");
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@subsubsection Object Name Service-based access
|
||||
@subsection Object Name Service-based access
|
||||
|
||||
Another way to get at the attribute is to use the object name service facility.
|
||||
Here, this attribute is found using a name string. This approach is useful if
|
||||
one doesn't have access to the underlying pointers and it is difficult to
|
||||
determine the required concrete configuration namespaced path.
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
Names::Add ("server", serverNode);
|
||||
Names::Add ("server/eth0", serverDevice);
|
||||
|
||||
...
|
||||
|
||||
Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25));
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@xref{Object names} for a fuller treatment of the ns-3 configuration namespace.
|
||||
|
||||
@subsection Setting through constructors helper classes
|
||||
|
||||
@@ -466,7 +488,8 @@ or from the higher-level helper APIs, such as:
|
||||
"LayoutType", StringValue ("RowFirst"));
|
||||
@end verbatim
|
||||
|
||||
@subsection Value classes
|
||||
@subsection Implementation details
|
||||
@subsubsection Value classes
|
||||
Readers will note the new FooValue classes which are subclasses of the
|
||||
AttributeValue base class. These can be thought of as
|
||||
an intermediate class that can be used to convert from raw types to the
|
||||
@@ -489,14 +512,14 @@ the attribute system:
|
||||
@item ATTRIBUTE_HELPER_CPP
|
||||
@end itemize
|
||||
|
||||
@subsection Initialization order
|
||||
@subsubsection Initialization order
|
||||
|
||||
In general, the attribute code to assign values to the underlying
|
||||
class member variables is executed after an object is constructed.
|
||||
But what if you need the values assigned before the constructor
|
||||
body executes, because you need them in the logic of the constructor?
|
||||
There is a way to do this, used for example in the class
|
||||
@code{ns3::ConfigStore}: call @code{ObjectBase::ConstructSelf()}
|
||||
@code{ns3::ConfigStore}: call @code{ObjectBase::ConstructSelf ()}
|
||||
as follows:
|
||||
|
||||
@verbatim
|
||||
@@ -546,7 +569,8 @@ Here, we discuss the impact on a user who wants to add a new class to
|
||||
ns-3; what additional things must be done to hook it into this system.
|
||||
|
||||
We've already introduced what a TypeId definition looks like:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
TypeId
|
||||
RandomWalk2dMobilityModel::GetTypeId (void)
|
||||
{
|
||||
@@ -568,7 +592,8 @@ RandomWalk2dMobilityModel::GetTypeId (void)
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
The declaration for this in the class declaration is one-line public
|
||||
member method:
|
||||
@@ -599,7 +624,9 @@ the conversions to/from strings and attribute values. Most of this can be
|
||||
copy/pasted with macro-ized code. For instance, consider class
|
||||
declaration for Rectangle in the @code{src/mobility/} directory:
|
||||
|
||||
@verbatim
|
||||
@subsection Header file
|
||||
@smallformat
|
||||
@example
|
||||
/**
|
||||
* \brief a 2d rectangle
|
||||
*/
|
||||
@@ -612,35 +639,42 @@ class Rectangle
|
||||
double yMin;
|
||||
double yMax;
|
||||
};
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
One macro call and two operators, must be added below the class declaration
|
||||
in order to turn a Rectangle into a value usable by the @code{Attribute}
|
||||
system:
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
|
||||
std::istream &operator >> (std::istream &is, Rectangle &rectangle);
|
||||
|
||||
ATTRIBUTE_HELPER_HEADER (Rectangle);
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@subsection Implementation file
|
||||
In the class definition (@code{.cc} file), the code looks like this:
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
ATTRIBUTE_HELPER_CPP (Rectangle);
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream &os, const Rectangle &rectangle)
|
||||
{
|
||||
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax;
|
||||
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|"
|
||||
<< rectangle.yMax;
|
||||
return os;
|
||||
}
|
||||
std::istream &
|
||||
operator >> (std::istream &is, Rectangle &rectangle)
|
||||
{
|
||||
char c1, c2, c3;
|
||||
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax;
|
||||
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3
|
||||
>> rectangle.yMax;
|
||||
if (c1 != '|' ||
|
||||
c2 != '|' ||
|
||||
c3 != '|')
|
||||
@@ -649,7 +683,8 @@ operator >> (std::istream &is, Rectangle &rectangle)
|
||||
}
|
||||
return is;
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
These stream operators simply convert from a string representation of the
|
||||
Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the
|
||||
@@ -679,7 +714,8 @@ file to the scratch directory:
|
||||
Let's edit it to add the ConfigStore feature. First, add an include statement
|
||||
to include the contrib module, and then add these lines:
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
#include "contrib-module.h"
|
||||
...
|
||||
int main (...)
|
||||
@@ -693,7 +729,8 @@ int main (...)
|
||||
|
||||
Simulator::Run ();
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
There are three attributes that govern the behavior of the ConfigStore:
|
||||
"Mode", "Filename", and "FileFormat". The Mode (default "None") configures
|
||||
@@ -705,12 +742,16 @@ the ConfigStore format is Xml or RawText format.
|
||||
|
||||
So, using the above modified program, try executing the following
|
||||
waf command and
|
||||
@verbatim
|
||||
./waf --command-template="%s --ns3::ConfigStore::Filename=csma-bridge-config.xml --ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=Xml" --run scratch/csma-bridge
|
||||
@end verbatim
|
||||
@smallformat
|
||||
@example
|
||||
./waf --command-template="%s --ns3::ConfigStore::Filename=csma-bridge-config.xml
|
||||
--ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=Xml" --run scratch/csma-bridge
|
||||
@end example
|
||||
@end smallformat
|
||||
After running, you can open the csma-bridge-config.xml file and it will
|
||||
display the configuration that was applied to your simulation; e.g.
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ns3>
|
||||
<default name="ns3::V4Ping::Remote" value="102.102.102.102"/>
|
||||
@@ -723,7 +764,9 @@ display the configuration that was applied to your simulation; e.g.
|
||||
<default name="ns3::QstaWifiMac::MaxMissedBeacons" value="10"/>
|
||||
<default name="ns3::QstaWifiMac::ActiveProbing" value="false"/>
|
||||
...
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
This file can be archived with your simulation script and output data.
|
||||
|
||||
While it is possible to generate a sample config file and lightly
|
||||
@@ -749,7 +792,8 @@ separate file called "output-attributes.xml". (Note-- to get this
|
||||
input xml file to begin with, it is sometimes helpful to run the
|
||||
program to generate an output xml file first, then hand-edit that
|
||||
file and re-input it for the next simulation run).
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
#include "contrib-module.h"
|
||||
...
|
||||
int main (...)
|
||||
@@ -778,7 +822,8 @@ int main (...)
|
||||
outputConfig.ConfigureAttributes ();
|
||||
Simulator::Run ();
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@subsection GTK-based ConfigStore
|
||||
|
||||
@@ -794,24 +839,28 @@ sudo apt-get install libgtk2.0-0 libgtk2.0-dev
|
||||
@end verbatim
|
||||
To check whether it is configured or not, check the output of the
|
||||
./waf configure step:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
---- Summary of optional NS-3 features:
|
||||
Threading Primitives : enabled
|
||||
Real Time Simulator : enabled
|
||||
GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found)
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
In the above example, it was not enabled, so it cannot be used until a
|
||||
suitable version is installed and ./waf configure; ./waf is rerun.
|
||||
|
||||
Usage is almost the same as the non-GTK-based version, but there
|
||||
are no ConfigStore attributes involved:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
// Invoke just before entering Simulator::Run ()
|
||||
GtkConfigStore config;
|
||||
config.ConfigureDefaults ();
|
||||
config.ConfigureAttributes ();
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
Now, when you run the script, a GUI should pop up, allowing you to open
|
||||
menus of attributes on different nodes/objects, and then launch the
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@node Bridge NetDevice
|
||||
@chapter Bridge NetDevice
|
||||
|
||||
@cartouche
|
||||
Placeholder chapter
|
||||
@end cartouche
|
||||
|
||||
Some examples of the use of Bridge NetDevice can be found in
|
||||
@code{examples/csma/} directory.
|
||||
+32
-16
@@ -7,15 +7,16 @@ chapter provides some motivation on the callback, guidance on how to use
|
||||
it, and details on its implementation.
|
||||
|
||||
@menu
|
||||
* Motivation::
|
||||
* Background::
|
||||
* Callbacks Motivation::
|
||||
* Callbacks Background::
|
||||
* Using the Callback API::
|
||||
* Bound Callbacks::
|
||||
* Callback locations in ns-3::
|
||||
* Traced Callbacks::
|
||||
* Implementation details::
|
||||
@end menu
|
||||
|
||||
@node Motivation
|
||||
@node Callbacks Motivation
|
||||
@section Motivation
|
||||
|
||||
Consider that you have two simulation models A and B, and you wish
|
||||
@@ -35,7 +36,6 @@ public:
|
||||
|
||||
class B {
|
||||
public:
|
||||
void ReceiveInput ( // parameters);
|
||||
void DoSomething (void);
|
||||
...
|
||||
|
||||
@@ -91,9 +91,13 @@ to a transport protocol above, the user may be forced to hack the
|
||||
system to get the desired interconnections, This is clearly not an
|
||||
optimal way to design a generic simulator.
|
||||
|
||||
@node Background
|
||||
@node Callbacks Background
|
||||
@section Background
|
||||
|
||||
@cartouche
|
||||
Readers familiar with programming callbacks may skip this tutorial section.
|
||||
@end cartouche
|
||||
|
||||
The basic mechanism that allows one to address the problem above is known as
|
||||
a @emph{callback}. The ultimate goal is to allow one piece of code to call
|
||||
a function (or method in C++) without any specific inter-module dependency.
|
||||
@@ -358,16 +362,19 @@ Consider also the following main program snippet:
|
||||
@end verbatim
|
||||
|
||||
This is an example of a C-style callback -- one which does not include or need
|
||||
a @code{this} pointer. The funtion template @code{Callback} is esentially the
|
||||
a @code{this} pointer. The function template @code{Callback} is esentially the
|
||||
declaration of the variable containing the pointer-to-function. In the example
|
||||
above, we explicitly showed a pointer to a function that returned an integer and
|
||||
took a single integer as a parameter, The @code{Callback} template function is
|
||||
a generic version of that -- it is used to declare the type of a callback.
|
||||
|
||||
@strong{Note1:} Readers unfamiliar with C++ templates may consult
|
||||
@uref{http://www.cplusplus.com/doc/tutorial/templates/,,this reference}.
|
||||
|
||||
The @code{Callback} template requires one mandatory argument (the return type
|
||||
of the function to be assigned to this callback) and up to five optional
|
||||
arguments, which each specify the type of the arguments (if your particular
|
||||
callback function has more than five arguments, then this can be easily handled
|
||||
callback function has more than five arguments, then this can be handled
|
||||
by extending the callback implementation).
|
||||
|
||||
So in the above example, we have a declared a callback named "one" that will
|
||||
@@ -451,7 +458,7 @@ invoked. Consider this example, also from main-callback.cc:
|
||||
@end verbatim
|
||||
|
||||
Here, we pass an additional object pointer to the @code{MakeCallback<>} function.
|
||||
Recall from the example above that @code{Operator()} will use the pointer to
|
||||
Recall from the background section above that @code{Operator()} will use the pointer to
|
||||
member syntax when it executes on an object:
|
||||
|
||||
@verbatim
|
||||
@@ -505,7 +512,7 @@ later -- when the @code{Callback} is called via @code{operator()}. All of
|
||||
the parameters are provided by the calling function.
|
||||
|
||||
What if it is desired to allow the client function (the one that provides the
|
||||
callback) to provide some of the parameters? Alexandrescu calls the process of
|
||||
callback) to provide some of the parameters? @uref{http://erdani.com/book/main.html,,Alexandrescu} calls the process of
|
||||
allowing a client to specify one of the parameters @emph{binding}. One of the
|
||||
parameters of @code{operator()} has been bound (fixed) by the client.
|
||||
|
||||
@@ -539,7 +546,7 @@ takes the parameters to be bound. In the case of the example above,
|
||||
MakeBoundCallback (&CsmaHelper::SniffEvent, pcap));
|
||||
@end verbatim
|
||||
|
||||
Will create a specific callback implementation that knows to add in the extra
|
||||
will create a specific callback implementation that knows to add in the extra
|
||||
bound arguments. Conceptually, it extends the specific functor described above
|
||||
with one or more bound arguments
|
||||
|
||||
@@ -581,16 +588,24 @@ function call:
|
||||
(*m_p.*m_pmi)(m_boundArg, arg);
|
||||
@end verbatim
|
||||
|
||||
@node Traced Callbacks
|
||||
@section Traced Callbacks
|
||||
@cartouche
|
||||
Placeholder subsection
|
||||
@end cartouche
|
||||
@section Callback locations in @command{ns-3}
|
||||
@node Callback locations in ns-3
|
||||
@section Callback locations in @command{ns-3}
|
||||
|
||||
Where are callbacks frequently used in @command{ns-3}? Here are some of the
|
||||
more visible ones to typical users:
|
||||
|
||||
@subsection Socket API
|
||||
@subsection Layer-2/Layer-3 API
|
||||
@subsection Tracing subsystem
|
||||
@subsection Routing
|
||||
@itemize @bullet
|
||||
@item Socket API
|
||||
@item Layer-2/Layer-3 API
|
||||
@item Tracing subsystem
|
||||
@item API between IP and routing subsystems
|
||||
@end itemize
|
||||
|
||||
@node Implementation details
|
||||
@section Implementation details
|
||||
@@ -600,8 +615,9 @@ itself. The actual Callback code is quite complicated and very template-intense
|
||||
a deep understanding of the code is not required. If interested, expert users may
|
||||
find the following useful:
|
||||
|
||||
The code was originally written based on the techniques described
|
||||
@uref{http://www.codeproject.com/cpp/TTLFunction.asp,,here}.
|
||||
The code was originally written based on the techniques described in
|
||||
@uref{http://www.codeproject.com/cpp/TTLFunction.asp,,
|
||||
http://www.codeproject.com/cpp/TTLFunction.asp}.
|
||||
It was subsequently rewritten to follow the architecture outlined in
|
||||
@uref{http://www.amazon.com/Modern-C\%2B\%2B-Design-Programming-Patterns/dp/0201704315/ref=pd_bbs_sr_1/102-0157303-1900156?ie=UTF8\&s=books\&qid=1187982662\&sr=1-1,,Modern C++ Design: Generic Programming and Design Patterns Applied-- Alexandrescu}, chapter 5, "Generalized Functors".
|
||||
|
||||
|
||||
+244
-139
@@ -1,183 +1,288 @@
|
||||
@node Emu NetDevice
|
||||
@chapter Emu NetDevice
|
||||
|
||||
This is the introduction to Emu NetDevice chapter, to complement the
|
||||
Emu model doxygen.
|
||||
@section Behavior
|
||||
|
||||
@menu
|
||||
* Overview of the model::
|
||||
* Using the EmuNetDevice::
|
||||
* Emu Tracing::
|
||||
@end menu
|
||||
The @code{Emu} net device allows a simulation node to send and receive packets
|
||||
over a real network. The emulated net device relies on a specified interface
|
||||
being in promiscuous mode. It opens a raw socket and binds to that interface.
|
||||
We perform MAC spoofing to separate simulation network traffic from other
|
||||
network traffic that may be flowing to and from the host.
|
||||
|
||||
@node Overview of the model
|
||||
@section Overview of the model
|
||||
One can use the @code{Emu} net device in a testbed situation where the
|
||||
host on which the simulation is running has a specific interface of interest
|
||||
which drives the testbed hardware. You would also need to set this specific
|
||||
interface into promiscuous mode and provide an appropriate device name to the
|
||||
ns-3 emulated net device. An example of this environment is the ORBIT testbed
|
||||
as described above.
|
||||
|
||||
The emulated net device allows a simulation node to send and receive packets
|
||||
a real network.
|
||||
|
||||
The Emu net device is not a complete net device and channel combination as is
|
||||
typical in ns-3. The Emu device can be thought of as a proxy for a real
|
||||
device that resides in an ns-3 simulation. The Emu net device talks to that
|
||||
real device using raw sockets and binds to the device via the Linux interface.
|
||||
There is no related Emu channel since other devices will most likely reside on
|
||||
different computers running entirely separate simulations.
|
||||
|
||||
The Emu net device relies on a specified interface (``eth1, for example) being
|
||||
in promiscuous mode. It opens a raw socket and binds to that interface. We
|
||||
perform MAC spoofing to separate simulation network traffic from other network
|
||||
traffic that may be flowing to and from the host.
|
||||
|
||||
Normally, the use case for emulated net devices is in collections of
|
||||
small simulations that connect to the outside world through specific
|
||||
interfaces. For example, one could construct a number of virtual
|
||||
machines and connect them via a host-only network. To use the emulated
|
||||
net device, you would need to set all of the host-only interfaces in
|
||||
promiscuous mode and provide an appropriate device name, "eth1" for example.
|
||||
|
||||
One could also use the emulated net device in a testbed situation
|
||||
where the host on which the simulation is running has a specific interface
|
||||
of interest which drives the testbed hardware. You would also need to set
|
||||
this specific interface into promiscuous mode and provide an appropriate
|
||||
device name to the ns-3 emulated net device.
|
||||
|
||||
The emulated net device only works if the underlying interface is up in
|
||||
promiscuous mode. We could just turn it on, but the situation is that we
|
||||
expect the other considerations listed above to have been dealt with.
|
||||
To verify that these issues are dealt with, we just make sure that the end
|
||||
result of that process has taken place and that the specified interface is
|
||||
in promiscuous mode.
|
||||
|
||||
@subsection Address Concerns
|
||||
|
||||
Packets will be sent out over the device, but as mentioned, we use MAC spoofing.
|
||||
By default in the simulation, the MAC addresses will be generated using the
|
||||
The @code{Emu} net device only works if the underlying interface is up and in
|
||||
promiscuous mode. Packets will be sent out over the device, but we use MAC
|
||||
spoofing. The MAC addresses will be generated (by default) using the
|
||||
Organizationally Unique Identifier (OUI) 00:00:00 as a base. This vendor code
|
||||
is not assigned to any organization and so should not conflict with any real
|
||||
hardware.
|
||||
|
||||
It is always up to you to determine that using these MAC addresses is
|
||||
It is always up to the user to determine that using these MAC addresses is
|
||||
okay on your network and won't conflict with anything else (including another
|
||||
simulation using emu devices) on your network. If you are using the
|
||||
simulation using @code{Emu} devices) on your network. If you are using the
|
||||
emulated net device in separate simulations you must consider global MAC
|
||||
address assignment issues and ensure that MAC addresses are unique across
|
||||
all simulations. The emulated net device respects the MAC address provided
|
||||
in the SetAddress method so you can do this manually. For larger simulations,
|
||||
you may want to set the OUI in the MAC address allocation function.
|
||||
in the @code{SetAddress} method so you can do this manually. For larger
|
||||
simulations, you may want to set the OUI in the MAC address allocation function.
|
||||
|
||||
IP addresses corresponding to the emulated net devices are the addresses
|
||||
generated in the simulation, which are generated in the usual way via helper
|
||||
functions.
|
||||
|
||||
@subsection Attributes
|
||||
|
||||
The Emu network device appears to the ns-3 system just as any other device and
|
||||
can be controlled through the attribute system, and traced through conventional
|
||||
trace hooks. The EmuNetDevice provides following Attributes:
|
||||
|
||||
@itemize @bullet
|
||||
@item Address: The Mac48Address of the device;
|
||||
@item DeviceName: The name of the underlying real device (e.g., ``eth1'');
|
||||
@item Start: The simulation time at which to enable the underlying socket;
|
||||
@item Stop: The simulation time at which to stop receiving from the underlying socket;
|
||||
@item TxQueue: The transmit queue used by the device;
|
||||
@item InterframeGap: The optional time to wait between "frames";
|
||||
@item Rx: A trace source for received packets;
|
||||
@end itemize
|
||||
|
||||
Packets sent over the EmuNetDevice are always routed through the
|
||||
transmit queue to provide a trace hook for packets sent out over the
|
||||
network. This transmit queue can be set (via attribute) to model different
|
||||
queuing strategies.
|
||||
|
||||
@node Using the EmuNetDevice
|
||||
@section Using the EmuNetDevice
|
||||
functions. Since we are using MAC spoofing, there will not be a conflict
|
||||
between ns-3 network stacks and any native network stacks.
|
||||
|
||||
The emulated net device comes with a helper function as all ns-3 devices do.
|
||||
One unique aspect is that there is no channel associated with the underlying
|
||||
medium. We really have no idea what this medium is, and so have not made an
|
||||
effort to model it abstractly. The primary thing to be aware of is the
|
||||
implication this has for static global routing. The global router module
|
||||
medium. We really have no idea what this external medium is, and so have not
|
||||
made an effort to model it abstractly. The primary thing to be aware of is the
|
||||
implication this has for IPv4 global routing. The global router module
|
||||
attempts to walk the channels looking for adjacent networks. Since there
|
||||
is no channel, the global router will be unable to do this.
|
||||
is no channel, the global router will be unable to do this and you must then
|
||||
use a dynamic routing protocol such as OLSR to include routing in
|
||||
@code{Emu}-based networks.
|
||||
|
||||
The Emu net devices are typically created and configured using the associated
|
||||
@code{EmuHelper} object. The various ns3 device helpers generally work in a
|
||||
similar way, and their use is seen in many of our example programs.
|
||||
|
||||
The conceptual model of interest is that of a bare computer ``husk'' into which
|
||||
you plug net devices. The bare computers are created using a @code{NodeContainer}
|
||||
helper. You just ask this helper to create as many computers (we call them
|
||||
@code{Nodes}) as you need on your network:
|
||||
@section Usage
|
||||
|
||||
Any mixing of ns-3 objects with real objects will typically require that
|
||||
ns-3 compute checksums in its protocols. By default, checksums are not
|
||||
computed by ns-3. To enable checksums (e.g. UDP, TCP, IP), users must set
|
||||
the attribute @code{ChecksumEnabled} to true, such as follows:
|
||||
@verbatim
|
||||
NodeContainer nodes;
|
||||
nodes.Create (nEmuNodes);
|
||||
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
|
||||
@end verbatim
|
||||
|
||||
Once you have your nodes, you need to instantiate a @code{EmuHelper} and set
|
||||
any attributes you may want to change.
|
||||
The usage of the @code{Emu} net device is straightforward once the network of
|
||||
simulations has been configured. Since most of the work involved in working
|
||||
with this device is in network configuration before even starting a simulation,
|
||||
you may want to take a moment to review a couple of HOWTO pages on the ns-3 wiki
|
||||
that describe how to set up a virtual test network using VMware and how to run
|
||||
a set of example (client server) simulations that use @code{Emu} net devices.
|
||||
|
||||
@itemize @bullet
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php/HOWTO_use_VMware_to_set_up_virtual_networks_(Windows)}
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php/HOWTO_use_ns-3_scripts_to_drive_real_hardware_(experimental)}
|
||||
@end itemize
|
||||
|
||||
Once you are over the configuration hurdle, the script changes required to use
|
||||
an @code{Emu} device are trivial. The main structural difference is that you
|
||||
will need to create an ns-3 simulation script for each node. In the case of
|
||||
the HOWTOs above, there is one client script and one server script. The only
|
||||
``challenge'' is to get the addresses set correctly.
|
||||
|
||||
Just as with all other ns-3 net devices, we provide a helper class for the
|
||||
@code{Emu} net device. The following code snippet illustrates how one would
|
||||
declare an EmuHelper and use it to set the ``DeviceName'' attribute to ``eth1''
|
||||
and install @code{Emu} devices on a group of nodes. You would do this on both
|
||||
the client and server side in the case of the HOWTO seen above.
|
||||
|
||||
@verbatim
|
||||
EmuHelper emu;
|
||||
csma.SetAttribute ("DeviceName", StringValue ("eth1"));
|
||||
emu.SetAttribute ("DeviceName", StringValue ("eth1"));
|
||||
NetDeviceContainer d = emu.Install (n);
|
||||
@end verbatim
|
||||
|
||||
Once the attributes are set, all that remains is to create the devices
|
||||
and install them on the required nodes. When we create the net devices,
|
||||
we add them to a container to allow you to use them in the future. This
|
||||
all takes just one line of code.
|
||||
|
||||
The only other change that may be required is to make sure that the address
|
||||
spaces (MAC and IP) on the client and server simulations are compatible. First
|
||||
the MAC address is set to a unique well-known value in both places (illustrated
|
||||
here for one side).
|
||||
|
||||
@verbatim
|
||||
NetDeviceContainer emuDevices = emu.Install (nodes);
|
||||
//
|
||||
// We've got the devices in place. Since we're using MAC address
|
||||
// spoofing under the sheets, we need to make sure that the MAC addresses
|
||||
// we have assigned to our devices are unique. Ns-3 will happily
|
||||
// automatically assign the same MAC address to the devices in both halves
|
||||
// of our two-script pair, so let's go ahead and just manually change them
|
||||
// to something we ensure is unique.
|
||||
//
|
||||
Ptr<NetDevice> nd = d.Get (0);
|
||||
Ptr<EmuNetDevice> ed = nd->GetObject<EmuNetDevice> ();
|
||||
ed->SetAddress ("00:00:00:00:00:02");
|
||||
@end verbatim
|
||||
|
||||
@node Emu Tracing
|
||||
@section Emu Tracing
|
||||
And then the IP address of the client or server is set in the usual way using
|
||||
helpers.
|
||||
|
||||
Like all ns-3 devices, the Emu Model provides a number of trace sources.
|
||||
These trace sources can be hooked using your own custom trace code, or you
|
||||
can use our helper functions to arrange for tracing to be enabled on devices
|
||||
you specify.
|
||||
@verbatim
|
||||
//
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
// This is the server half of a two-script pair. We need to make sure
|
||||
// that the addressing in both of these applications is consistent, so
|
||||
// we use provide an initial address in both cases. Here, the client
|
||||
// will reside on one machine running ns-3 with one node having ns-3
|
||||
// with IP address "10.1.1.2" and talk to a server script running in
|
||||
// another ns-3 on another computer that has an ns-3 node with IP
|
||||
// address "10.1.1.3"
|
||||
//
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0", "0.0.0.2");
|
||||
Ipv4InterfaceContainer i = ipv4.Assign (d);
|
||||
@end verbatim
|
||||
|
||||
@subsection Upper-Level (MAC) Hooks
|
||||
You will use application helpers to generate traffic exactly as you do in any
|
||||
ns-3 simulation script. Note that the server address shown below in a snippet
|
||||
from the client, must correspond to the IP address assigned to the server node
|
||||
similarly to the snippet above.
|
||||
|
||||
From the point of view of tracing in the net device, there are several
|
||||
interesting points to insert trace hooks. A convention inherited from other
|
||||
simulators is that packets destined for transmission onto attached networks
|
||||
pass through a single "transmit queue" in the net device. We provide trace
|
||||
hooks at this point in packet flow, which corresponds (abstractly) only to a
|
||||
transition from the network to data link layer, and call them collectively
|
||||
the device MAC hooks.
|
||||
@verbatim
|
||||
uint32_t packetSize = 1024;
|
||||
uint32_t maxPacketCount = 2000;
|
||||
Time interPacketInterval = Seconds (0.001);
|
||||
UdpEchoClientHelper client ("10.1.1.3", 9);
|
||||
client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
|
||||
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
|
||||
client.SetAttribute ("PacketSize", UintegerValue (packetSize));
|
||||
ApplicationContainer apps = client.Install (n.Get (0));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (2.0));
|
||||
@end verbatim
|
||||
|
||||
When a packet is sent to the Emu net device for transmission it always
|
||||
passes through the transmit queue. The transmit queue in the
|
||||
EmuNetDevice inherits from Queue, and therefore inherits three
|
||||
trace sources:
|
||||
The @code{Emu} net device and helper provide access to ASCII and pcap tracing
|
||||
functionality just as other ns-3 net devices to. You enable tracing similarly
|
||||
to these other net devices:
|
||||
|
||||
@itemize @bullet
|
||||
@item An Enqueue operation source (see Queue::m_traceEnqueue);
|
||||
@item A Dequeue operation source (see Queue::m_traceDequeue);
|
||||
@item A Drop operation source (see Queue::m_traceDrop).
|
||||
@end itemize
|
||||
@verbatim
|
||||
EmuHelper::EnablePcapAll ("emu-udp-echo-client");
|
||||
@end verbatim
|
||||
|
||||
The upper-level (MAC) trace hooks for the EmuNetDevice are, in fact,
|
||||
exactly these three trace sources on the single transmit queue of the device.
|
||||
To see an example of a client script using the @code{Emu} net device, see
|
||||
@code{examples/emu-udp-echo-client.cc} and @code{examples/emu-udp-echo-server.cc}
|
||||
in the repository @uref{http://code.nsnam.org/craigdo/ns-3-emu/}.
|
||||
|
||||
The m_traceEnqueue event is triggered when a packet is placed on the transmit
|
||||
queue. This happens at the time that EmuNetDevice::Send or
|
||||
EmuNetDevice::SendFrom is called by a higher layer to queue a packet for
|
||||
transmission.
|
||||
@section Implementation
|
||||
|
||||
The m_traceDequeue event is triggered when a packet is removed from the
|
||||
transmit queue. Dequeues from the transmit queue happen immediately after
|
||||
the Enqueue event and just prior to the packet being sent to the underlying
|
||||
socket. This means that the transmit queue really only exists to fire on
|
||||
enqueue and dequeue operations so the Emu device behaves like other ns-3
|
||||
devices in this respect.
|
||||
Perhaps the most unusual part of the @code{Emu} and @code{Tap} device
|
||||
implementation relates to the requirement for executing some of the code
|
||||
with super-user permissions. Rather than force the user to execute the entire
|
||||
simulation as root, we provide a small ``creator'' program that runs as root
|
||||
and does any required high-permission sockets work.
|
||||
|
||||
@subsection Lower-Level (PHY) Hooks
|
||||
We do a similar thing for both the @code{Emu} and the @code{Tap} devices.
|
||||
The high-level view is that the @code{CreateSocket} method creates a local
|
||||
interprocess (Unix) socket, forks, and executes the small creation program.
|
||||
The small program, which runs as suid root, creates a raw socket and sends
|
||||
back the raw socket file descriptor over the Unix socket that is passed to
|
||||
it as a parameter. The raw socket is passed as a control message (sometimes
|
||||
called ancillary data) of type SCM_RIGHTS.
|
||||
|
||||
The @code{Emu} net device uses the ns-3 threading and multithreaded real-time
|
||||
scheduler extensions. The interesting work in the @code{Emu} device is done
|
||||
when the net device is started (@code{EmuNetDevice::StartDevice ()}). An
|
||||
attribute (``Start'') provides a simulation time at which to spin up the
|
||||
net device. At this specified time (which defaults to t=0), the socket
|
||||
creation function is called and executes as described above. You may also
|
||||
specify a time at which to stop the device using the ``Stop'' attribute.
|
||||
|
||||
Once the (promiscuous mode) socket is created, we bind it to an interface name
|
||||
also provided as an attribute (``DeviceName'') that is stored internally as
|
||||
@code{m_deviceName}:
|
||||
|
||||
@verbatim
|
||||
struct ifreq ifr;
|
||||
bzero (&ifr, sizeof(ifr));
|
||||
strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
|
||||
|
||||
int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
|
||||
|
||||
struct sockaddr_ll ll;
|
||||
bzero (&ll, sizeof(ll));
|
||||
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_ifindex = m_sll_ifindex;
|
||||
ll.sll_protocol = htons(ETH_P_ALL);
|
||||
|
||||
rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
|
||||
@end verbatim
|
||||
|
||||
After the promiscuous raw socket is set up, a separate thread is spawned to do
|
||||
reads from that socket and the link state is set to @code{Up}.
|
||||
|
||||
@verbatim
|
||||
m_readThread = Create<SystemThread> (
|
||||
MakeCallback (&EmuNetDevice::ReadThread, this));
|
||||
m_readThread->Start ();
|
||||
|
||||
NotifyLinkUp ();
|
||||
@end verbatim
|
||||
|
||||
The @code{EmuNetDevice::ReadThread} function basically just sits in an infinite
|
||||
loop reading from the promiscuous mode raw socket and scheduling packet
|
||||
receptions using the real-time simulator extensions.
|
||||
|
||||
@verbatim
|
||||
for (;;)
|
||||
{
|
||||
...
|
||||
|
||||
len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr,
|
||||
&addrSize);
|
||||
|
||||
...
|
||||
|
||||
DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->
|
||||
ScheduleRealtimeNow (
|
||||
MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
|
||||
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The line starting with our templated DynamicCast function probably deserves a
|
||||
comment. It gains access to the simulator implementation object using
|
||||
the @code{Simulator::GetImplementation} method and then casts to the real-time
|
||||
simulator implementation to use the real-time schedule method
|
||||
@code{ScheduleRealtimeNow}. This function will cause a handler for the newly
|
||||
received packet to be scheduled for execution at the current real time clock
|
||||
value. This will, in turn cause the simulation clock to be advanced to that
|
||||
real time value when the scheduled event (@code{EmuNetDevice::ForwardUp}) is
|
||||
fired.
|
||||
|
||||
The @code{ForwardUp} function operates as most other similar ns-3 net device
|
||||
methods do. The packet is first filtered based on the destination address. In
|
||||
the case of the @code{Emu} device, the MAC destination address will be the
|
||||
address of the @code{Emu} device and not the hardware address of the real
|
||||
device. Headers are then stripped off and the trace hooks are hit. Finally,
|
||||
the packet is passed up the ns-3 protocol stack using the receive callback
|
||||
function of the net device.
|
||||
|
||||
Sending a packet is equally straightforward as shown below. The first thing
|
||||
we do is to add the ethernet header and trailer to the ns-3 @code{Packet} we
|
||||
are sending. The source address corresponds to the address of the @code{Emu}
|
||||
device and not the underlying native device MAC address. This is where the
|
||||
MAC address spoofing is done. The trailer is added and we enqueue and dequeue
|
||||
the packet from the net device queue to hit the trace hooks.
|
||||
|
||||
@verbatim
|
||||
header.SetSource (source);
|
||||
header.SetDestination (destination);
|
||||
header.SetLengthType (packet->GetSize ());
|
||||
packet->AddHeader (header);
|
||||
|
||||
EthernetTrailer trailer;
|
||||
trailer.CalcFcs (packet);
|
||||
packet->AddTrailer (trailer);
|
||||
|
||||
m_queue->Enqueue (packet);
|
||||
packet = m_queue->Dequeue ();
|
||||
|
||||
struct sockaddr_ll ll;
|
||||
bzero (&ll, sizeof (ll));
|
||||
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_ifindex = m_sll_ifindex;
|
||||
ll.sll_protocol = htons(ETH_P_ALL);
|
||||
|
||||
rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0,
|
||||
reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
|
||||
@end verbatim
|
||||
|
||||
|
||||
Finally, we simply send the packet to the raw socket which puts it out on the
|
||||
real network.
|
||||
|
||||
There are no lower level trace hooks implemented in the Emu net device since
|
||||
we rely on the underlying OS implementation of the raw socket to perform
|
||||
the low level operations required to send and receive packets.
|
||||
|
||||
+2
-317
@@ -1,6 +1,5 @@
|
||||
@node Emulation
|
||||
@chapter Emulation
|
||||
@anchor{chap:Emulation}
|
||||
|
||||
ns-3 has been designed for integration into testbed and virtual machine
|
||||
environments. We have addressed this need by providing two kinds of
|
||||
@@ -24,7 +23,7 @@ for details on the ORBIT testbed.
|
||||
A simulation of this kind is shown in the following figure:
|
||||
|
||||
@float Figure,fig:testbed
|
||||
@center @caption{Example Implementation of Testbed Emulation.}
|
||||
@caption{Example Implementation of Testbed Emulation.}
|
||||
@center @image{figures/testbed, 5in}
|
||||
@end float
|
||||
|
||||
@@ -45,7 +44,7 @@ is shown in the following figure:
|
||||
|
||||
@float Figure,fig:emulated-channel
|
||||
@caption{Implementation overview of emulated channel.}
|
||||
@image{figures/emulated-channel, 5in}
|
||||
@image{figures/emulated-channel, 6in}
|
||||
@end float
|
||||
|
||||
Here, you will see that there is a single host with a number of virtual machines
|
||||
@@ -68,317 +67,3 @@ We expect the typical use case for this environment will be to analyze the
|
||||
behavior of native applications and protocol suites in the presence of large
|
||||
simulated ns-3 networks.
|
||||
|
||||
@section Behavior
|
||||
|
||||
@subsection Emu Net Device
|
||||
|
||||
The @code{Emu} net device allows a simulation node to send and receive packets
|
||||
over a real network. The emulated net device relies on a specified interface
|
||||
being in promiscuous mode. It opens a raw socket and binds to that interface.
|
||||
We perform MAC spoofing to separate simulation network traffic from other
|
||||
network traffic that may be flowing to and from the host.
|
||||
|
||||
Normally, the use case for emulated net devices is in collections of small
|
||||
simulations that connect to the outside world through specific interfaces.
|
||||
For example, one could construct a number of virtual machines and connect them
|
||||
via a host-only network. To use the emulated net device, you would need to
|
||||
set all of the host-only interfaces in promiscuous mode and provide an
|
||||
appropriate device name, "eth1" for example.
|
||||
|
||||
One could also use the @code{Emu} net device in a testbed situation where the
|
||||
host on which the simulation is running has a specific interface of interest
|
||||
which drives the testbed hardware. You would also need to set this specific
|
||||
interface into promiscuous mode and provide an appropriate device name to the
|
||||
ns-3 emulated net device. An example of this environment is the ORBIT testbed
|
||||
as described above.
|
||||
|
||||
The @code{Emu} net device only works if the underlying interface is up and in
|
||||
promiscuous mode. Packets will be sent out over the device, but we use MAC
|
||||
spoofing. The MAC addresses will be generated (by default) using the
|
||||
Organizationally Unique Identifier (OUI) 00:00:00 as a base. This vendor code
|
||||
is not assigned to any organization and so should not conflict with any real
|
||||
hardware.
|
||||
|
||||
It is always up to the user to determine that using these MAC addresses is
|
||||
okay on your network and won't conflict with anything else (including another
|
||||
simulation using @code{Emu} devices) on your network. If you are using the
|
||||
emulated net device in separate simulations you must consider global MAC
|
||||
address assignment issues and ensure that MAC addresses are unique across
|
||||
all simulations. The emulated net device respects the MAC address provided
|
||||
in the @code{SetAddress} method so you can do this manually. For larger
|
||||
simulations, you may want to set the OUI in the MAC address allocation function.
|
||||
|
||||
IP addresses corresponding to the emulated net devices are the addresses
|
||||
generated in the simulation, which are generated in the usual way via helper
|
||||
functions. Since we are using MAC spoofing, there will not be a conflict
|
||||
between ns-3 network stacks and any native network stacks.
|
||||
|
||||
The emulated net device comes with a helper function as all ns-3 devices do.
|
||||
One unique aspect is that there is no channel associated with the underlying
|
||||
medium. We really have no idea what this external medium is, and so have not
|
||||
made an effort to model it abstractly. The primary thing to be aware of is the
|
||||
implication this has for static global routing. The global router module
|
||||
attempts to walk the channels looking for adjacent networks. Since there
|
||||
is no channel, the global router will be unable to do this and you must then
|
||||
use a dynamic routing protocol such as OLSR to include routing in
|
||||
@code{Emu}-based networks.
|
||||
|
||||
@subsection Tap Net Device
|
||||
|
||||
The @code{Tap} Net Device is scheduled for inclusion in ns-3.4 at the writing
|
||||
of this section. We will include details as soon as the @code{Tap} device is
|
||||
merged.
|
||||
|
||||
@section Usage
|
||||
|
||||
Any mixing of ns-3 objects with real objects will typically require that
|
||||
ns-3 compute checksums in its protocols. By default, checksums are not
|
||||
computed by ns-3. To enable checksums (e.g. UDP, TCP, IP), users must set
|
||||
the attribute @code{ChecksumEnabled} to true, such as follows:
|
||||
@verbatim
|
||||
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
|
||||
@end verbatim
|
||||
|
||||
@subsection Emu Net Device
|
||||
|
||||
The usage of the @code{Emu} net device is straightforward once the network of
|
||||
simulations has been configured. Since most of the work involved in working
|
||||
with this device is in network configuration before even starting a simulation,
|
||||
you may want to take a moment to review a couple of HOWTO pages on the ns-3 wiki
|
||||
that describe how to set up a virtual test network using VMware and how to run
|
||||
a set of example (client server) simulations that use @code{Emu} net devices.
|
||||
|
||||
@uref{http://www.nsnam.org/wiki/index.php/HOWTO_use_VMware_to_set_up_virtual_networks_(Windows)}
|
||||
@uref{http://www.nsnam.org/wiki/index.php/HOWTO_use_ns-3_scripts_to_drive_real_hardware_(experimental)}
|
||||
|
||||
Once you are over the configuration hurdle, the script changes required to use
|
||||
an @code{Emu} device are trivial. The main structural difference is that you
|
||||
will need to create an ns-3 simulation script for each node. In the case of
|
||||
the HOWTOs above, there is one client script and one server script. The only
|
||||
``challenge'' is to get the addresses set correctly.
|
||||
|
||||
Just as with all other ns-3 net devices, we provide a helper class for the
|
||||
@code{Emu} net device. The following code snippet illustrates how one would
|
||||
declare an EmuHelper and use it to set the ``DeviceName'' attribute to ``eth1''
|
||||
and install @code{Emu} devices on a group of nodes. You would do this on both
|
||||
the client and server side in the case of the HOWTO seen above.
|
||||
|
||||
@verbatim
|
||||
EmuHelper emu;
|
||||
emu.SetAttribute ("DeviceName", StringValue ("eth1"));
|
||||
NetDeviceContainer d = emu.Install (n);
|
||||
@end verbatim
|
||||
|
||||
The only other change that may be required is to make sure that the address
|
||||
spaces (MAC and IP) on the client and server simulations are compatible. First
|
||||
the MAC address is set to a unique well-known value in both places (illustrated
|
||||
here for one side).
|
||||
|
||||
@verbatim
|
||||
//
|
||||
// We've got the devices in place. Since we're using MAC address
|
||||
// spoofing under the sheets, we need to make sure that the MAC addresses
|
||||
// we have assigned to our devices are unique. Ns-3 will happily
|
||||
// automatically assign the same MAC addresses to the devices in both halves
|
||||
// of our two-script pair, so let's go ahead and just manually change them
|
||||
// to something we ensure is unique.
|
||||
//
|
||||
Ptr<NetDevice> nd = d.Get (0);
|
||||
Ptr<EmuNetDevice> ed = nd->GetObject<EmuNetDevice> ();
|
||||
ed->SetAddress ("00:00:00:00:00:02");
|
||||
@end verbatim
|
||||
|
||||
And then the IP address of the client or server is set in the usual way using
|
||||
helpers.
|
||||
|
||||
@verbatim
|
||||
//
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
// This is the server half of a two-script pair. We need to make sure
|
||||
// that the addressing in both of these applications is consistent, so
|
||||
// we use provide an initial address in both cases. Here, the client
|
||||
// will reside on one machine running ns-3 with one node having ns-3
|
||||
// with IP address "10.1.1.2" and talk to a server script running in
|
||||
// another ns-3 on another computer that has an ns-3 node with IP
|
||||
// address "10.1.1.3"
|
||||
//
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0", "0.0.0.2");
|
||||
Ipv4InterfaceContainer i = ipv4.Assign (d);
|
||||
@end verbatim
|
||||
|
||||
You will use application helpers to generate traffic exactly as you do in any
|
||||
ns-3 simulation script. Note that the server address shown below in a snippet
|
||||
from the client, must correspond to the IP address assigned to the server node
|
||||
similarly to the snippet above.
|
||||
|
||||
@verbatim
|
||||
uint32_t packetSize = 1024;
|
||||
uint32_t maxPacketCount = 2000;
|
||||
Time interPacketInterval = Seconds (0.001);
|
||||
UdpEchoClientHelper client ("10.1.1.3", 9);
|
||||
client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
|
||||
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
|
||||
client.SetAttribute ("PacketSize", UintegerValue (packetSize));
|
||||
ApplicationContainer apps = client.Install (n.Get (0));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (2.0));
|
||||
@end verbatim
|
||||
|
||||
The @code{Emu} net device and helper provide access to ASCII and pcap tracing
|
||||
functionality just as other ns-3 net devices to. You enable tracing similarly
|
||||
to these other net devices:
|
||||
|
||||
@verbatim
|
||||
EmuHelper::EnablePcapAll ("emu-udp-echo-client");
|
||||
@end verbatim
|
||||
|
||||
To see an example of a client script using the @code{Emu} net device, see
|
||||
@code{examples/emu-udp-echo-client.cc} and @code{examples/emu-udp-echo-server.cc}
|
||||
in the repository @uref{http://code.nsnam.org/craigdo/ns-3-emu/}.
|
||||
|
||||
@subsection Tap Net Device
|
||||
|
||||
The @code{Tap} Net Device is scheduled for inclusion in ns-3.4 at the writing
|
||||
of this section. We will include details as soon as the @code{Tap} device is
|
||||
merged.
|
||||
|
||||
@section Implementation
|
||||
|
||||
Perhaps the most unusual part of the @code{Emu} and @code{Tap} device
|
||||
implementation relates to the requirement for executing some of the code
|
||||
with super-user permissions. Rather than force the user to execute the entire
|
||||
simulation as root, we provide a small ``creator'' program that runs as root
|
||||
and does any required high-permission sockets work.
|
||||
|
||||
We do a similar thing for both the @code{Emu} and the @code{Tap} devices.
|
||||
The high-level view is that the @code{CreateSocket} method creates a local
|
||||
interprocess (Unix) socket, forks, and executes the small creation program.
|
||||
The small program, which runs as suid root, creates a raw socket and sends
|
||||
back the raw socket file descriptor over the Unix socket that is passed to
|
||||
it as a parameter. The raw socket is passed as a control message (sometimes
|
||||
called ancillary data) of type SCM_RIGHTS.
|
||||
|
||||
@subsection Emu Net Device
|
||||
|
||||
The @code{Emu} net device uses the ns-3 threading and multithreaded real-time
|
||||
scheduler extensions. The interesting work in the @code{Emu} device is done
|
||||
when the net device is started (@code{EmuNetDevice::StartDevice ()}). An
|
||||
attribute (``Start'') provides a simulation time at which to spin up the
|
||||
net device. At this specified time (which defaults to t=0), the socket
|
||||
creation function is called and executes as described above. You may also
|
||||
specify a time at which to stop the device using the ``Stop'' attribute.
|
||||
|
||||
Once the (promiscuous mode) socket is created, we bind it to an interface name
|
||||
also provided as an attribute (``DeviceName'') that is stored internally as
|
||||
@code{m_deviceName}:
|
||||
|
||||
@verbatim
|
||||
struct ifreq ifr;
|
||||
bzero (&ifr, sizeof(ifr));
|
||||
strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
|
||||
|
||||
int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
|
||||
|
||||
struct sockaddr_ll ll;
|
||||
bzero (&ll, sizeof(ll));
|
||||
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_ifindex = m_sll_ifindex;
|
||||
ll.sll_protocol = htons(ETH_P_ALL);
|
||||
|
||||
rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
|
||||
@end verbatim
|
||||
|
||||
After the promiscuous raw socket is set up, a separate thread is spawned to do
|
||||
reads from that socket and the link state is set to @code{Up}.
|
||||
|
||||
@verbatim
|
||||
m_readThread = Create<SystemThread> (
|
||||
MakeCallback (&EmuNetDevice::ReadThread, this));
|
||||
m_readThread->Start ();
|
||||
|
||||
NotifyLinkUp ();
|
||||
@end verbatim
|
||||
|
||||
The @code{EmuNetDevice::ReadThread} function basically just sits in an infinite
|
||||
loop reading from the promiscuous mode raw socket and scheduling packet
|
||||
receptions using the real-time simulator extensions.
|
||||
|
||||
@verbatim
|
||||
for (;;)
|
||||
{
|
||||
...
|
||||
|
||||
len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr,
|
||||
&addrSize);
|
||||
|
||||
...
|
||||
|
||||
DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->
|
||||
ScheduleRealtimeNow (
|
||||
MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
|
||||
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The line starting with our templated DynamicCast function probably deserves a
|
||||
comment. It gains access to the simulator implementation object using
|
||||
the @code{Simulator::GetImplementation} method and then casts to the real-time
|
||||
simulator implementation to use the real-time schedule method
|
||||
@code{ScheduleRealtimeNow}. This function will cause a handler for the newly
|
||||
received packet to be scheduled for execution at the current real time clock
|
||||
value. This will, in turn cause the simulation clock to be advanced to that
|
||||
real time value when the scheduled event (@code{EmuNetDevice::ForwardUp}) is
|
||||
fired.
|
||||
|
||||
The @code{ForwardUp} function operates as most other similar ns-3 net device
|
||||
methods do. The packet is first filtered based on the destination address. In
|
||||
the case of the @code{Emu} device, the MAC destination address will be the
|
||||
address of the @code{Emu} device and not the hardware address of the real
|
||||
device. Headers are then stripped off and the trace hooks are hit. Finally,
|
||||
the packet is passed up the ns-3 protocol stack using the receive callback
|
||||
function of the net device.
|
||||
|
||||
Sending a packet is equally straightforward as shown below. The first thing
|
||||
we do is to add the ethernet header and trailer to the ns-3 @code{Packet} we
|
||||
are sending. The source address corresponds to the address of the @code{Emu}
|
||||
device and not the underlying native device MAC address. This is where the
|
||||
MAC address spoofing is done. The trailer is added and we enqueue and dequeue
|
||||
the packet from the net device queue to hit the trace hooks.
|
||||
|
||||
@verbatim
|
||||
header.SetSource (source);
|
||||
header.SetDestination (destination);
|
||||
header.SetLengthType (packet->GetSize ());
|
||||
packet->AddHeader (header);
|
||||
|
||||
EthernetTrailer trailer;
|
||||
trailer.CalcFcs (packet);
|
||||
packet->AddTrailer (trailer);
|
||||
|
||||
m_queue->Enqueue (packet);
|
||||
packet = m_queue->Dequeue ();
|
||||
|
||||
struct sockaddr_ll ll;
|
||||
bzero (&ll, sizeof (ll));
|
||||
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_ifindex = m_sll_ifindex;
|
||||
ll.sll_protocol = htons(ETH_P_ALL);
|
||||
|
||||
rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0,
|
||||
reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
|
||||
@end verbatim
|
||||
|
||||
|
||||
Finally, we simply send the packet to the raw socket which puts it out on the
|
||||
real network.
|
||||
|
||||
@subsection Tap Net Device
|
||||
|
||||
The @code{Tap} Net Device is scheduled for inclusion in ns-3.4 at the writing
|
||||
of this section. We will include details as soon as the @code{Tap} device is
|
||||
merged.
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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}
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
@node IPv4
|
||||
@chapter IPv4
|
||||
|
||||
@cartouche
|
||||
Placeholder chapter
|
||||
@end cartouche
|
||||
@@ -0,0 +1,10 @@
|
||||
@node IPv6
|
||||
@chapter IPv6
|
||||
|
||||
@cartouche
|
||||
Placeholder chapter
|
||||
@end cartouche
|
||||
IPv6 models are being added to ns-3. A paper on the IPv6 models was
|
||||
published in WNS2 2008: @*
|
||||
@uref{http://lsiit.u-strasbg.fr/Publications/2008/VMM08/,,http://lsiit.u-strasbg.fr/Publications/2008/VMM08/}
|
||||
|
||||
+4
-21
@@ -1,24 +1,7 @@
|
||||
@node Logging
|
||||
@chapter Logging
|
||||
@anchor{chap:Logging}
|
||||
|
||||
This chapter is the first in a series of chapters discussing things that
|
||||
one can do to modify the input or output of existing ns-3 scripts.
|
||||
|
||||
Examples:
|
||||
@itemize @bullet
|
||||
@item Enable or disable the generation of log messages, with fine granularity
|
||||
@item Set default values for configuration values in the system
|
||||
@item Generate a report of all configuration values used during a simulation
|
||||
run (not yet implemented)
|
||||
@item Set or get values of member variables on objects already instantiated
|
||||
@item Customizing the tracing output of the script
|
||||
@item Generate statistics on (not yet implemented)
|
||||
@item Perform a large number of independent runs of the same simulation
|
||||
@end itemize
|
||||
|
||||
@node Logging Basics
|
||||
@section Logging Basics
|
||||
|
||||
@node Enabling Log Output
|
||||
@section Enabling Log Output
|
||||
@cartouche
|
||||
This chapter not yet written. For now, the ns-3 tutorial contains logging
|
||||
information.
|
||||
@end cartouche
|
||||
|
||||
+79
-18
@@ -2,7 +2,6 @@
|
||||
@c %**start of header
|
||||
@setfilename ns-3.info
|
||||
@settitle ns-3 manual
|
||||
@c @setchapternewpage odd
|
||||
@c %**end of header
|
||||
|
||||
@ifinfo
|
||||
@@ -25,11 +24,12 @@ the document should be discussed on the ns-developers@@isi.edu mailing list.
|
||||
|
||||
This is an @command{ns-3} reference manual.
|
||||
Primary documentation for the @command{ns-3} project is available in
|
||||
four forms:
|
||||
five forms:
|
||||
@itemize @bullet
|
||||
@item @uref{http://www.nsnam.org/docs/tutorial/tutorial.html,,ns-3 Tutorial}
|
||||
@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen}: Documentation of the public APIs of the simulator
|
||||
@item Reference Manual (this document)
|
||||
@item @uref{http://www.nsnam.org/tutorials.html,, ns-3 Testing and Validation manual}
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki}
|
||||
@end itemize
|
||||
|
||||
@@ -61,9 +61,10 @@ along with this program. If not, see @uref{http://www.gnu.org/licenses/}.
|
||||
@include VERSION
|
||||
@today{}
|
||||
|
||||
@c @page
|
||||
@vskip 0pt plus 1filll
|
||||
@insertcopying
|
||||
@page
|
||||
@center This page is intentionally blank.
|
||||
@end titlepage
|
||||
|
||||
@c So the toc is printed at the start.
|
||||
@@ -86,42 +87,102 @@ Simulator version:
|
||||
@end ifnottex
|
||||
|
||||
@menu
|
||||
* Organization::
|
||||
* Random variables::
|
||||
* Callbacks::
|
||||
* Object model::
|
||||
* Attributes::
|
||||
* Object names::
|
||||
* Logging::
|
||||
* Tracing::
|
||||
* RealTime::
|
||||
* Emulation::
|
||||
* Packets::
|
||||
* Sockets APIs::
|
||||
* Node and Internet Stack::
|
||||
* TCP::
|
||||
* Routing overview::
|
||||
* Wifi NetDevice::
|
||||
* CSMA NetDevice::
|
||||
* Helpers::
|
||||
* Python::
|
||||
* Node and NetDevices::
|
||||
* Simple NetDevice::
|
||||
* PointToPoint NetDevice::
|
||||
* CSMA NetDevice::
|
||||
* Wifi NetDevice::
|
||||
* Mesh NetDevice::
|
||||
* Bridge NetDevice::
|
||||
* Emulation::
|
||||
* Emu NetDevice::
|
||||
* Tap NetDevice::
|
||||
* Sockets APIs::
|
||||
* Internet Stack::
|
||||
* IPv4::
|
||||
* IPv6::
|
||||
* Routing overview::
|
||||
* TCP::
|
||||
* Applications::
|
||||
* Flow Monitor::
|
||||
* Animation::
|
||||
* Statistics::
|
||||
* Creating a new ns-3 model::
|
||||
* Troubleshooting::
|
||||
@end menu
|
||||
|
||||
@setchapternewpage odd
|
||||
@headings off
|
||||
@everyheading @thischapter @| @| ns-3 manual
|
||||
@everyfooting ns-3.6 @| @thispage @| @today
|
||||
@include organization.texi
|
||||
|
||||
@unnumbered Part 1: ns-3 core
|
||||
@setchapternewpage off
|
||||
@include random.texi
|
||||
@setchapternewpage odd
|
||||
@include callbacks.texi
|
||||
@include objects.texi
|
||||
@include attributes.texi
|
||||
@include names.texi
|
||||
@include log.texi
|
||||
@include tracing.texi
|
||||
@include realtime.texi
|
||||
@include emulation.texi
|
||||
@include packets.texi
|
||||
@include sockets.texi
|
||||
@include helpers.texi
|
||||
@include python.texi
|
||||
|
||||
@unnumbered Part 2: Nodes and NetDevices
|
||||
@setchapternewpage off
|
||||
@include node.texi
|
||||
@c @include output.texi
|
||||
@include tcp.texi
|
||||
@include routing.texi
|
||||
@include wifi.texi
|
||||
@include csma.texi
|
||||
@setchapternewpage odd
|
||||
@include simple.texi
|
||||
@include point-to-point.texi
|
||||
@c @include other.texi
|
||||
@include csma.texi
|
||||
@include wifi.texi
|
||||
@include mesh.texi
|
||||
@include bridge.texi
|
||||
|
||||
@unnumbered Part 3: Emulation
|
||||
@setchapternewpage off
|
||||
@include emulation.texi
|
||||
@setchapternewpage odd
|
||||
@include emu.texi
|
||||
@include tap.texi
|
||||
|
||||
@unnumbered Part 4: Internet Models
|
||||
@setchapternewpage off
|
||||
@include sockets.texi
|
||||
@setchapternewpage odd
|
||||
@include internet.texi
|
||||
@include ipv4.texi
|
||||
@include ipv6.texi
|
||||
@include routing.texi
|
||||
@include tcp.texi
|
||||
|
||||
@unnumbered Part 5: Applications
|
||||
@setchapternewpage off
|
||||
@include applications.texi
|
||||
@setchapternewpage odd
|
||||
|
||||
@unnumbered Part 6: Support
|
||||
@setchapternewpage off
|
||||
@include flow-monitor.texi
|
||||
@setchapternewpage odd
|
||||
@include animation.texi
|
||||
@include statistics.texi
|
||||
@include new-models.texi
|
||||
@include troubleshoot.texi
|
||||
|
||||
|
||||
@@ -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}
|
||||
@@ -0,0 +1,6 @@
|
||||
@node Object names
|
||||
@chapter Object names
|
||||
|
||||
@cartouche
|
||||
Placeholder chapter
|
||||
@end cartouche
|
||||
+29
-16
@@ -395,8 +395,10 @@ The @ref{Object model} chapter discusses this in more detail.
|
||||
@subsection how to include files from elsewhere
|
||||
@subsection log component
|
||||
|
||||
Here, write a bit about adding ns-3 logging macros. Note that
|
||||
@cartouche
|
||||
Here, write a bit about adding ns-3 logging macros. Note that @*
|
||||
LOG_COMPONENT_DEFINE is done outside the namespace ns3
|
||||
@end cartouche
|
||||
|
||||
@subsection constructor, empty function prototypes
|
||||
|
||||
@@ -407,7 +409,8 @@ LOG_COMPONENT_DEFINE is done outside the namespace ns3
|
||||
|
||||
|
||||
@subsection Object Framework
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
static const ClassId cid;
|
||||
|
||||
|
||||
@@ -416,8 +419,8 @@ const InterfaceId ErrorModel::iid =
|
||||
|
||||
const ClassId ErrorModel::cid =
|
||||
MakeClassId<ErrorModel> ("ErrorModel", ErrorModel::iid);
|
||||
@end verbatim
|
||||
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@node Adding-a-sample-script
|
||||
@section Adding a sample script
|
||||
@@ -431,7 +434,8 @@ of the ErrorModels themselves.
|
||||
|
||||
@subsection Add basic support in the class
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
point-to-point-net-device.h
|
||||
class ErrorModel;
|
||||
|
||||
@@ -440,12 +444,13 @@ point-to-point-net-device.h
|
||||
*/
|
||||
Ptr<ErrorModel> m_receiveErrorModel;
|
||||
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@subsection Add Accessor
|
||||
|
||||
@verbatim
|
||||
|
||||
@smallformat
|
||||
@example
|
||||
void
|
||||
PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
|
||||
{
|
||||
@@ -458,11 +463,13 @@ PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
|
||||
PointerValue (),
|
||||
MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
|
||||
MakePointerChecker<ErrorModel> ())
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@subsection Plumb into the system
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
void PointToPointNetDevice::Receive (Ptr<Packet> packet)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << packet);
|
||||
@@ -486,15 +493,18 @@ void PointToPointNetDevice::Receive (Ptr<Packet> packet)
|
||||
ProcessHeader(packet, protocol);
|
||||
m_rxCallback (this, packet, protocol, GetRemote ());
|
||||
if (!m_promiscCallback.IsNull ())
|
||||
{ m_promiscCallback (this, packet, protocol, GetRemote (), GetAddress (), NetDevice::PACKET_HOST);
|
||||
{ m_promiscCallback (this, packet, protocol, GetRemote (),
|
||||
GetAddress (), NetDevice::PACKET_HOST);
|
||||
}
|
||||
}
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@subsection Create null functional script
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
simple-error-model.cc
|
||||
|
||||
// Error model
|
||||
@@ -514,7 +524,8 @@ ErrorModel::DoCorrupt (Packet& p)
|
||||
NS_LOG_UNCOND("Corrupt!");
|
||||
return false;
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
At this point, we can run the program with our trivial ErrorModel
|
||||
plumbed into the receive path of the PointToPointNetDevice. It
|
||||
@@ -550,7 +561,8 @@ the above unit of granularity.
|
||||
|
||||
We declare BasicErrorModel to be a subclass of ErrorModel as follows,
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
class BasicErrorModel : public ErrorModel
|
||||
{
|
||||
public:
|
||||
@@ -562,7 +574,8 @@ private:
|
||||
virtual bool DoReset (void);
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
and configure the subclass GetTypeId function by setting a unique
|
||||
TypeId string and setting the Parent to ErrorModel:
|
||||
|
||||
+6
-229
@@ -1,5 +1,5 @@
|
||||
@node Node and Internet Stack
|
||||
@chapter Node and Internet Stack
|
||||
@node Node and NetDevices
|
||||
@chapter Node and NetDevices
|
||||
@anchor{chap:Node}
|
||||
|
||||
This chapter describes how ns-3 nodes are put together, and provides
|
||||
@@ -20,8 +20,8 @@ to which one may add NetDevices (cards) and other innards including
|
||||
the protocols and applications. @ref{fig:node} illustrates
|
||||
that Node objects contain a list of Applications (initially,
|
||||
the list is empty), a list of NetDevices (initially, the list
|
||||
is empty), a unique integer ID, and a system ID (for
|
||||
distributed simulation).
|
||||
is empty), a list of ProtocolHandlers, a unique integer ID, and
|
||||
a system ID (for distributed simulation).
|
||||
|
||||
The design tries to avoid putting too many dependencies on the
|
||||
base class Node, Application, or NetDevice for the following:
|
||||
@@ -109,229 +109,6 @@ The NodeList class provides an @code{Add()} method and C++ iterators
|
||||
to allow one to walk the node list or fetch a Node pointer by
|
||||
its integer identifier.
|
||||
|
||||
@section Internet stack aggregation
|
||||
|
||||
The above @code{class Node} is not very useful as-is; other objects
|
||||
must be aggregated to it to provide useful node functionality.
|
||||
|
||||
The ns-3 source code directory @code{src/internet-stack} provides
|
||||
implementation of TCP/IPv4-related components. These include IPv4,
|
||||
ARP, UDP, TCP, and other related protocols.
|
||||
|
||||
Internet Nodes are not subclasses of class Node; they are simply Nodes
|
||||
that have had a bunch of IPv4-related
|
||||
objects aggregated to them. They can be put together by hand, or
|
||||
via a helper function @code{InternetStackHelper::Install ()} which does the
|
||||
following to all nodes passed in as arguments:
|
||||
@verbatim
|
||||
void
|
||||
InternetStackHelper::Install (Ptr<Node> node) const
|
||||
{
|
||||
if (node->GetObject<Ipv4> () != 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("InternetStackHelper::Install(): Aggregating "
|
||||
"an InternetStack to a node with an existing Ipv4 object");
|
||||
return;
|
||||
}
|
||||
|
||||
CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol");
|
||||
CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3Protocol");
|
||||
CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol");
|
||||
CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol");
|
||||
node->AggregateObject (m_tcpFactory.Create<Object> ());
|
||||
Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> ();
|
||||
node->AggregateObject (factory);
|
||||
// Set routing
|
||||
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
|
||||
Ptr<Ipv4RoutingProtocol> ipv4Routing = m_routing->Create (node);
|
||||
ipv4->SetRoutingProtocol (ipv4Routing);
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Note that the Ipv4 routing protocol is configured and set outside this
|
||||
function. By default, the following protocols are added to Ipv4:
|
||||
@verbatim
|
||||
InternetStackHelper::InternetStackHelper ()
|
||||
{
|
||||
SetTcp ("ns3::TcpL4Protocol");
|
||||
static Ipv4StaticRoutingHelper staticRouting;
|
||||
static Ipv4GlobalRoutingHelper globalRouting;
|
||||
static Ipv4ListRoutingHelper listRouting;
|
||||
listRouting.Add (staticRouting, 0);
|
||||
listRouting.Add (globalRouting, -10);
|
||||
SetRoutingHelper (listRouting);
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
@subsection Internet Node structure
|
||||
|
||||
An IPv4-capable Node (an ns-3 Node augmented by aggregation to have one or more
|
||||
IP stacks) has the following internal structure.
|
||||
|
||||
@subsubsection Layer-3 protocols
|
||||
At the lowest layer, sitting above the NetDevices, are the "layer 3"
|
||||
protocols, including IPv4, IPv6 (in the future), and ARP. The
|
||||
@code{class Ipv4L3Protocol} is an
|
||||
implementation class whose public interface is
|
||||
typically @code{class Ipv4} (found in src/node directory), but the
|
||||
Ipv4L3Protocol public API is also used internally in the
|
||||
src/internet-stack directory at present.
|
||||
|
||||
In class Ipv4L3Protocol, one method described below is @code{Receive ()}:
|
||||
@verbatim
|
||||
/**
|
||||
* Lower layer calls this method after calling L3Demux::Lookup
|
||||
* The ARP subclass needs to know from which NetDevice this
|
||||
* packet is coming to:
|
||||
* - implement a per-NetDevice ARP cache
|
||||
* - send back arp replies on the right device
|
||||
*/
|
||||
void Receive( Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
|
||||
const Address &to, NetDevice::PacketType packetType);
|
||||
@end verbatim
|
||||
|
||||
First, note that the @code{Receive ()} function has a matching signature
|
||||
to the ReceiveCallback in the @code{class Node}. This function pointer
|
||||
is inserted into the Node's protocol handler when
|
||||
@code{AddInterface ()} is called. The actual registration is done
|
||||
with a statement such as:
|
||||
follows:
|
||||
@verbatim
|
||||
RegisterProtocolHandler ( MakeCallback (&Ipv4Protocol::Receive, ipv4),
|
||||
Ipv4L3Protocol::PROT_NUMBER, 0);
|
||||
@end verbatim
|
||||
|
||||
The Ipv4L3Protocol object is aggregated to the Node; there is only one
|
||||
such Ipv4L3Protocol object. Higher-layer protocols that have a packet
|
||||
to send down to the Ipv4L3Protocol object can call
|
||||
@code{GetObject<Ipv4L3Protocol> ()} to obtain a pointer, as follows:
|
||||
@verbatim
|
||||
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
|
||||
if (ipv4 != 0)
|
||||
{
|
||||
ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This class nicely demonstrates two techniques we exploit in
|
||||
ns-3 to bind objects together: callbacks, and object aggregation.
|
||||
|
||||
Once IPv4 routing has determined that a packet is for the local node, it
|
||||
forwards it up the stack. This is done with the following function:
|
||||
|
||||
@verbatim
|
||||
void
|
||||
Ipv4L3Protocol::LocalDeliver (Ptr<const Packet> packet, Ipv4Header const&ip, uint32_t iif)
|
||||
@end verbatim
|
||||
|
||||
The first step is to find the right Ipv4L4Protocol object , based on IP protocol
|
||||
number. For instance, TCP is registered in the demux as protocol number 6.
|
||||
Finally, the @code{Receive()} function on the Ipv4L4Protocol (such as
|
||||
@code{TcpL4Protocol::Receive} is called.
|
||||
|
||||
We have not yet introduced the class Ipv4Interface. Basically,
|
||||
each NetDevice is paired with an IPv4 representation of such device.
|
||||
In Linux, this @code{class Ipv4Interface} roughly corresponds to
|
||||
the @code{struct in_device}; the main purpose is to provide
|
||||
address-family specific information (addresses) about an interface.
|
||||
|
||||
@subsubsection Layer-4 protocols and sockets
|
||||
|
||||
We next describe how the transport protocols, sockets, and applications
|
||||
tie together. In summary, each transport protocol implementation is
|
||||
a socket factory. An application that needs a new socket
|
||||
|
||||
For instance, to create a UDP socket, an application would use a code
|
||||
snippet such as the following:
|
||||
@verbatim
|
||||
Ptr<Udp> udpSocketFactory = GetNode ()->GetObject<Udp> ();
|
||||
Ptr<Socket> m_socket = socketFactory->CreateSocket ();
|
||||
m_socket->Bind (m_local_address);
|
||||
...
|
||||
@end verbatim
|
||||
The above will query the node to get a pointer to its UDP socket
|
||||
factory, will create one such socket, and will use the socket with
|
||||
an API similar to the C-based sockets API, such as @code{Connect ()}
|
||||
and @code{Send ()}. See the chapter on ns-3 sockets for more information.
|
||||
|
||||
We have described so far a socket factory (e.g. @code{class Udp}) and
|
||||
a socket, which may be specialized (e.g., @code{class UdpSocket}).
|
||||
There are a few more key objects that relate to the specialized
|
||||
task of demultiplexing a packet to one or more receiving sockets.
|
||||
The key object in this task is @code{class Ipv4EndPointDemux}.
|
||||
This demultiplexer stores objects of @code{class Ipv4EndPoint}.
|
||||
This class holds the addressing/port tuple (local port, local address,
|
||||
destination port, destination address) associated with the socket,
|
||||
and a receive callback. This receive callback has a receive
|
||||
function registered by the socket. The @code{Lookup ()} function to
|
||||
Ipv4EndPointDemux returns a list of Ipv4EndPoint objects (there may
|
||||
be a list since more than one socket may match the packet). The
|
||||
layer-4 protocol copies the packet to each Ipv4EndPoint and calls
|
||||
its @code{ForwardUp ()} method, which then calls the @code{Receive ()}
|
||||
function registered by the socket.
|
||||
|
||||
An issue that arises when working with the sockets API on real
|
||||
systems is the need to manage the reading from a socket, using
|
||||
some type of I/O (e.g., blocking, non-blocking, asynchronous, ...).
|
||||
ns-3 implements an asynchronous model for socket I/O; the application
|
||||
sets a callback to be notified of received data ready to be read, and the
|
||||
callback is invoked by the transport protocol when data is available.
|
||||
This callback is specified as follows:
|
||||
@verbatim
|
||||
void Socket::SetRecvCallback (Callback<void, Ptr<Socket>,
|
||||
Ptr<Packet>, const Address&> receivedData);
|
||||
@end verbatim
|
||||
The data being received is conveyed in the Packet data buffer. An example
|
||||
usage is in @code{class PacketSink}:
|
||||
@verbatim
|
||||
m_socket->SetRecvCallback (MakeCallback(&PacketSink::HandleRead, this));
|
||||
@end verbatim
|
||||
|
||||
To summarize, internally, the UDP implementation is organized as follows:
|
||||
@itemize @bullet
|
||||
@item a @code{UdpImpl} class that implements the UDP socket factory
|
||||
functionality
|
||||
@item a @code{UdpL4Protocol} class that implements the protocol logic
|
||||
that is socket-independent
|
||||
@item a @code{UdpSocketImpl} class that implements socket-specific aspects
|
||||
of UDP
|
||||
@item a class called @code{Ipv4EndPoint} that stores the
|
||||
addressing tuple (local port, local address, destination port, destination
|
||||
address) associated with the socket, and a receive callback for the socket.
|
||||
@end itemize
|
||||
|
||||
@subsection Ipv4-capable node interfaces
|
||||
|
||||
Many of the implementation details, or internal objects themselves,
|
||||
of Ipv4-capable Node objects are not exposed at the simulator public
|
||||
API. This allows for different implementations; for instance,
|
||||
replacing the native ns-3 models with ported TCP/IP stack code.
|
||||
|
||||
The C++ public APIs of all of these objects is found in the
|
||||
@code{src/node} directory, including principally:
|
||||
@itemize @bullet
|
||||
@item @code{socket.h}
|
||||
@item @code{tcp.h}
|
||||
@item @code{udp.h}
|
||||
@item @code{ipv4.h}
|
||||
@end itemize
|
||||
These are typically base class objects that implement the default
|
||||
values used in the implementation, implement access methods to get/set
|
||||
state variables, host attributes, and implement publicly-available methods
|
||||
exposed to clients such as @code{CreateSocket}.
|
||||
|
||||
@subsection Example path of a packet
|
||||
|
||||
These two figures show an example stack trace of how packets flow
|
||||
through the Internet Node objects.
|
||||
|
||||
@float Figure,fig:internet-node-send
|
||||
@caption{Send path of a packet.}
|
||||
@image{figures/internet-node-send,5in}
|
||||
@end float
|
||||
|
||||
@float Figure,fig:internet-node-recv
|
||||
@caption{Receive path of a packet.}
|
||||
@image{figures/internet-node-recv,5in}
|
||||
@end float
|
||||
The following chapters provide reference information on the available
|
||||
NetDevices in ns-3.
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ When the reference count falls to zero, the object is deleted.
|
||||
|
||||
@itemize @bullet
|
||||
@item When the client code obtains a pointer from the object itself
|
||||
through object creation, or via QueryInterface, it does not have
|
||||
through object creation, or via GetObject, it does not have
|
||||
to increment the reference count.
|
||||
@item When client code obtains a pointer from another source (e.g.,
|
||||
copying a pointer) it must call @code{Ref()} to increment the
|
||||
@@ -154,7 +154,9 @@ using @code{CreateObject()} instead.
|
||||
|
||||
For objects deriving from @code{class RefCountBase}, or other
|
||||
objects that support usage of the smart pointer class
|
||||
(in particular, the ns-3 Packet class),
|
||||
(in particular, the ns-3 Packet class does not derive from RefCountBase
|
||||
in order to avoid a vtable, but separately implements @code{Ref ()} and
|
||||
@code{Unref ()}),
|
||||
a templated helper function is available and recommended to be used:
|
||||
@verbatim
|
||||
Ptr<B> b = Create<B> ();
|
||||
@@ -241,7 +243,7 @@ now use the Ptr to the Ipv4 object that was previously aggregated to
|
||||
the node.
|
||||
|
||||
Another example of how one might use aggregation is to add optional
|
||||
models to objects. For in
|
||||
models to objects.
|
||||
For instance, an existing Node object may have an ``Energy Model''
|
||||
object aggregated to it at run time (without modifying
|
||||
and recompiling the node class). An existing model (such as a wireless
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
@node Organization
|
||||
@chapter Organization
|
||||
|
||||
This manual is organized into several parts with several chapters per part.
|
||||
This chapter describes the overall software organization and the
|
||||
corresponding organization of this manual.
|
||||
|
||||
ns-3 is a discrete-event network simulator in which the simulation core
|
||||
and models are implemented in C++. ns-3 is built as a library which
|
||||
may be statically or dynamically linked to a C++ main program that
|
||||
defines the simulation topology and starts the simulator. ns-3 also
|
||||
exports nearly all of its API to Python, allowing Python programs to
|
||||
import an "ns3" module in much the same way as in C++.
|
||||
|
||||
@float Figure,fig:organization
|
||||
@caption{Software organization of ns-3}
|
||||
@center @image{figures/software-organization, 5in}
|
||||
@end float
|
||||
|
||||
The source code for ns-3 is mostly organized in the @code{src/}
|
||||
directory and can be described by the diagram in @ref{fig:organization}.
|
||||
We will work our way from the bottom up; in general, modules
|
||||
only have dependencies on modules beneath them in the figure.
|
||||
|
||||
We first describe Part 1 of the manual.
|
||||
The simulation core is implemented in @code{src/core}, and the core is
|
||||
used to build the simulation engine @code{src/simulator}. Packets are
|
||||
fundamental objects in a network simulator and are implemented in
|
||||
@code{src/packet}. These three simulation modules by themselves
|
||||
are intended to comprise a generic simulation core that can be used
|
||||
by different kinds of networks, not just Internet-based networks.
|
||||
The above modules of ns-3 are independent of specific network and
|
||||
device models, which are covered in later parts of this manual.
|
||||
|
||||
In addition to the above ns-3 core, we describe also in Part 1 two
|
||||
other modules that supplement the core C++-based API. ns-3 programs
|
||||
may access all of the API directly or may make use of a so-called
|
||||
``helper API'' that provides convenient wrappers or encapsulation of
|
||||
low-level API calls. The fact that ns-3 programs can be written to
|
||||
two APIs (or a combination thereof) is a fundamental aspect of the
|
||||
simulator and is also covered in Part 1. We also describe how
|
||||
Python is supported in ns-3 as the last chapter of Part 1.
|
||||
|
||||
The remainder of the manual is focused on documenting the models
|
||||
and supporting capabilities. Part 2 focuses on two fundamental
|
||||
objects in ns-3: the @code{Node} and @code{NetDevice}. Two
|
||||
special NetDevice types are designed to support network emulation
|
||||
use cases, and emulation is described in Part 3.
|
||||
Part 4 is devoted to Internet-related models, including the sockets
|
||||
API used by Internet applications. Part 5 covers applications, and
|
||||
Part 6 describes additional support for simulation, such as animators.
|
||||
|
||||
The project maintains a separate manual devoted to testing and
|
||||
validation of ns-3 code (see the
|
||||
@uref{http://www.nsnam.org/tutorials.html,, ns-3 Testing and Validation manual}).
|
||||
+21
-11
@@ -99,7 +99,7 @@ things that you wouldn't find in the bits on the wire).
|
||||
|
||||
@float Figure,fig:packets
|
||||
@caption{Implementation overview of Packet class.}
|
||||
@image{figures/packet}
|
||||
@image{figures/packet, 4in}
|
||||
@end float
|
||||
|
||||
Figure @ref{fig:packets} is a high-level overview of the Packet
|
||||
@@ -222,9 +222,11 @@ applied is:
|
||||
Packet (uint8_t const *buffer, uint32_t size);
|
||||
@end verbatim
|
||||
Here is an example:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
Ptr<Packet> pkt1 = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello"), 5);
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
Packets are freed when there are no more references to them, as with
|
||||
all ns-3 objects referenced by the Ptr class.
|
||||
@@ -258,7 +260,8 @@ examples within the source code.
|
||||
Once you have a header (or you have a preexisting header), the following
|
||||
Packet API can be used to add or remove such headers.
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
/**
|
||||
* Add header to this packet. This method invokes the
|
||||
* Header::GetSerializedSize and Header::Serialize
|
||||
@@ -284,11 +287,13 @@ Packet API can be used to add or remove such headers.
|
||||
* \returns the number of bytes read from the packet.
|
||||
*/
|
||||
uint32_t PeekHeader (Header &header) const;
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
For instance, here are the typical operations to add and remove a UDP header.
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
// add header
|
||||
Ptr<Packet> packet = Create<Packet> ();
|
||||
UdpHeader udpHeader;
|
||||
@@ -299,7 +304,8 @@ For instance, here are the typical operations to add and remove a UDP header.
|
||||
UdpHeader udpHeader;
|
||||
packet->RemoveHeader (udpHeader);
|
||||
// Read udpHeader fields as needed
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@subsection Adding and removing Tags
|
||||
|
||||
@@ -355,7 +361,8 @@ An example is the UdpEchoServer class, which takes the received packet
|
||||
and "turns it around" to send back to the echo client.
|
||||
|
||||
The Packet API for byte tags is given below.
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
/**
|
||||
* \param tag the new tag to add to this packet
|
||||
*
|
||||
@@ -399,10 +406,12 @@ The Packet API for byte tags is given below.
|
||||
* invoke the Print method of each tag stored in the packet.
|
||||
*/
|
||||
void PrintByteTags (std::ostream &os) const;
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
The Packet API for packet tags is given below.
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
/**
|
||||
* \param tag the tag to store in this packet
|
||||
*
|
||||
@@ -451,7 +460,8 @@ The Packet API for packet tags is given below.
|
||||
* packet tags.
|
||||
*/
|
||||
PacketTagIterator GetPacketTagIterator (void) const;
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
Here is a simple example illustrating the use of tags from the
|
||||
code in @code{src/internet-stack/udp-socket-impl.cc}:
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@node Python
|
||||
@chapter Python
|
||||
|
||||
@cartouche
|
||||
Placeholder chapter
|
||||
@end cartouche
|
||||
|
||||
For now, please see the Python wiki page at @*
|
||||
@uref{http://www.nsnam.org/wiki/index.php/NS-3_Python_Bindings,,http://www.nsnam.org/wiki/index.php/NS-3_Python_Bindings}.
|
||||
+28
-43
@@ -35,7 +35,7 @@ default; this marks a change in policy starting with ns-3.4}
|
||||
@end itemize
|
||||
@item to obtain randomness across multiple simulation runs, you must either
|
||||
set the seed differently or set the run number differently. To set a seed, call
|
||||
@code{SeedManager::SetSeed(uint32_t)} at the beginning of the program;
|
||||
@code{SeedManager::SetSeed (uint32_t)} at the beginning of the program;
|
||||
to set a run number with the same seed, call
|
||||
@code{SeedManager::SetRun (uint32_t)} at the beginning of the program;
|
||||
@xref{Seeding and independent replications}
|
||||
@@ -53,7 +53,7 @@ ns-3.
|
||||
@node Background
|
||||
@section Background
|
||||
|
||||
Simulations use a lot of random numbers; the study in [cite]
|
||||
Simulations use a lot of random numbers; one study
|
||||
found that most network simulations spend as much as 50%
|
||||
of the CPU generating random numbers. Simulation users need
|
||||
to be concerned with the quality of the (pseudo) random numbers and
|
||||
@@ -62,7 +62,7 @@ the independence between different streams of random numbers.
|
||||
Users need to be concerned with a few issues, such as:
|
||||
@itemize @bullet
|
||||
@item the seeding of the random number generator and whether a
|
||||
simulation run is deterministic or not,
|
||||
simulation outcome is deterministic or not,
|
||||
@item how to acquire different streams of random numbers that are
|
||||
independent from one another, and
|
||||
@item how long it takes for streams to cycle
|
||||
@@ -96,8 +96,7 @@ streams of random numbers, each of which consists of
|
||||
2.3x10^15 substreams. Each substream has a period
|
||||
(@emph{i.e.}, the number of random numbers before overlap) of
|
||||
7.6x10^22. The period of the entire generator is
|
||||
3.1x10^57. Figure ref-streams provides a graphical idea of
|
||||
how the streams and substreams fit together.
|
||||
3.1x10^57.
|
||||
|
||||
Class @code{ns3::RandomVariable} is the public interface to this
|
||||
underlying random number generator. When users create new
|
||||
@@ -167,7 +166,7 @@ from within the program; the user can set the
|
||||
@end verbatim
|
||||
|
||||
Another way to control this is by passing a command-line argument; since
|
||||
this is an ns3 GlobalValue instance, it is equivalently done such as follows:
|
||||
this is an ns-3 GlobalValue instance, it is equivalently done such as follows:
|
||||
@verbatim
|
||||
./waf --command-template="%s --RngRun=3" --run program-name
|
||||
@end verbatim
|
||||
@@ -198,42 +197,25 @@ numbers before overlapping.
|
||||
@section Base class public API
|
||||
|
||||
Below are excerpted a few public methods of @code{class RandomVariable}
|
||||
that deal with the global configuration and state of the RNG.
|
||||
@verbatim
|
||||
that access the next value in the substream.
|
||||
@smallformat
|
||||
@example
|
||||
/**
|
||||
* \brief Set seeding behavior
|
||||
*
|
||||
* Specify whether the POSIX device /dev/random is to
|
||||
* be used for seeding. When this is used, the underlying
|
||||
* generator is seeded with data from /dev/random instead of
|
||||
* being seeded based upon the time of day. Defaults to true.
|
||||
* \brief Returns a random double from the underlying distribution
|
||||
* \return A floating point random value
|
||||
*/
|
||||
static void UseDevRandom(bool udr = true);
|
||||
|
||||
/**
|
||||
* \brief Use the global seed to force precisely reproducible results.
|
||||
*/
|
||||
static void UseGlobalSeed(uint32_t s0, uint32_t s1, uint32_t s2,
|
||||
uint32_t s3, uint32_t s4, uint32_t s5);
|
||||
|
||||
double GetValue (void) const;
|
||||
|
||||
/**
|
||||
* \brief Set the run number of this simulation
|
||||
* \brief Returns a random integer integer from the underlying distribution
|
||||
* \return Integer cast of ::GetValue()
|
||||
*/
|
||||
static void SetRunNumber(uint32_t n);
|
||||
uint32_t GetInteger (void) const;
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
/**
|
||||
* \brief Get the internal state of the RNG
|
||||
*
|
||||
* This function is for power users who understand the inner workings
|
||||
* of the underlying RngStream method used. It returns the internal
|
||||
* state of the RNG via the input parameter.
|
||||
* \param seed Output parameter; gets overwritten with the internal state
|
||||
* of the RNG.
|
||||
*/
|
||||
void GetSeed(uint32_t seed[6]) const;
|
||||
@end verbatim
|
||||
|
||||
We have already described the seeding configuration above.
|
||||
We have already described the seeding configuration above. Different
|
||||
RandomVariable subclasses may have additional API.
|
||||
|
||||
@node Types of RandomVariables
|
||||
@section Types of RandomVariables
|
||||
@@ -255,6 +237,9 @@ class RandomVariable.
|
||||
@item @code{class DeterministicVariable }
|
||||
@item @code{class LogNormalVariable }
|
||||
@item @code{class TriangularVariable }
|
||||
@item @code{class GammaVariable }
|
||||
@item @code{class ErlangVariable }
|
||||
@item @code{class ZipfVariable }
|
||||
@end itemize
|
||||
|
||||
@node Semantics of RandomVariable objects
|
||||
@@ -270,7 +255,8 @@ any heap-allocated RandomVariables.
|
||||
RandomVariable objects can also be used in ns-3 attributes, which means
|
||||
that values can be set for them through the ns-3 attribute system.
|
||||
An example is in the propagation models for WifiNetDevice:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
TypeId
|
||||
RandomPropagationDelayModel::GetTypeId (void)
|
||||
{
|
||||
@@ -285,7 +271,8 @@ RandomPropagationDelayModel::GetTypeId (void)
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
Here, the ns-3 user can change the default random variable for this
|
||||
delay model (which is a UniformVariable ranging from 0 to 1) through
|
||||
the attribute system.
|
||||
@@ -328,14 +315,12 @@ Let's review what things you should do when creating a simulation.
|
||||
|
||||
@itemize @bullet
|
||||
@item Decide whether you are running with a fixed seed or random seed;
|
||||
a random seed is the default,
|
||||
a fixed seed is the default,
|
||||
@item Decide how you are going to manage independent replications, if
|
||||
applicable,
|
||||
@item Convince yourself that you are not drawing more random values
|
||||
than the cycle length, if you are running a long simulation, and
|
||||
than the cycle length, if you are running a very long simulation, and
|
||||
@item When you publish, follow the guidelines above about documenting your
|
||||
use of the random number generator.
|
||||
@end itemize
|
||||
|
||||
The program @emph{samples/main-random.cc} has some examples of usage.
|
||||
|
||||
|
||||
+11
-4
@@ -25,7 +25,7 @@ are described in @ref{Unicast routing}. Multicast routing is documented in
|
||||
@image{figures/routing, 6in}
|
||||
@end float
|
||||
|
||||
Figure 11-1 shows the overall routing architecture for Ipv4. The key objects
|
||||
@ref{fig:routing} shows the overall routing architecture for Ipv4. The key objects
|
||||
are Ipv4L3Protocol, Ipv4RoutingProtocol(s) (a class to which all
|
||||
routing/forwarding has been delegated from Ipv4L3Protocol), and Ipv4Route(s).
|
||||
|
||||
@@ -143,7 +143,8 @@ and rebuilds the routes.
|
||||
For instance, this scheduling call will cause the tables to be rebuilt
|
||||
at time 5 seconds:
|
||||
@verbatim
|
||||
Simulator::Schedule (Seconds (5),&Ipv4GlobalRoutingHelper::RecomputeRoutingTables);
|
||||
Simulator::Schedule (Seconds (5),
|
||||
&Ipv4GlobalRoutingHelper::RecomputeRoutingTables);
|
||||
@end verbatim
|
||||
|
||||
@subsection Global Routing Implementation
|
||||
@@ -199,15 +200,21 @@ is finally used to populate the routes themselves.
|
||||
@node Unicast routing
|
||||
@section Unicast routing
|
||||
|
||||
There are presently four routing protocols defined:
|
||||
There are presently five unicast routing protocols defined for IPv4 and
|
||||
two for IPv6:
|
||||
@itemize @bullet
|
||||
@item class Ipv4StaticRouting (covering both unicast and multicast)
|
||||
@item Optimized Link State Routing (a MANET protocol defined in
|
||||
@item IPv4 Optimized Link State Routing (a MANET protocol defined in
|
||||
@uref{http://www.ietf.org/rfc/rfc3626.txt,,RFC 3626})
|
||||
@item class Ipv4ListRouting (used to store a prioritized list of routing
|
||||
protocols)
|
||||
@item class Ipv4GlobalRouting (used to store routes computed by the global
|
||||
route manager, if that is used)
|
||||
@item class Ipv4NixVectorRouting (a more efficient version of global routing
|
||||
that stores source routes in a packet header field)
|
||||
@item class Ipv6ListRouting (used to store a prioritized list of routing
|
||||
protocols)
|
||||
@item class Ipv6StaticRouting
|
||||
@end itemize
|
||||
|
||||
In the future, this architecture should also allow someone to implement
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
@node Simple NetDevice
|
||||
@chapter Simple NetDevice
|
||||
|
||||
@cartouche
|
||||
Placeholder chapter
|
||||
@end cartouche
|
||||
+12
-55
@@ -42,8 +42,8 @@ one of asynchronous I/O, which is not typically found in real systems
|
||||
@item the API is not a complete sockets API, such as supporting
|
||||
all socket options or all function variants;
|
||||
@item many calls use @code{ns3::Packet} class to transfer data
|
||||
between application and socket. This may seem a little funny to
|
||||
people to pass ``Packets'' across a stream socket API, but think
|
||||
between application and socket. This may seem peculiar to
|
||||
pass ``Packets'' across a stream socket API, but think
|
||||
of these packets as just fancy byte buffers at this level (more
|
||||
on this also below).
|
||||
@end itemize
|
||||
@@ -58,7 +58,7 @@ on this also below).
|
||||
@subsubsection Creating sockets
|
||||
|
||||
An application that wants to use sockets must first create one.
|
||||
On real systems, this is accomplished by calling socket():
|
||||
On real systems using a C-based API, this is accomplished by calling socket():
|
||||
@verbatim
|
||||
int
|
||||
socket(int domain, int type, int protocol);
|
||||
@@ -79,11 +79,13 @@ Examples of TypeIds to pass to this method are @code{TcpSocketFactory},
|
||||
|
||||
This method returns a smart pointer to a Socket object. Here is an
|
||||
example:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
Ptr<Node> n0;
|
||||
// Do some stuff to build up the Node's internet stack
|
||||
Ptr<Socket> localSocket = Socket::CreateSocket (n0, TcpSocketFactory::GetTypeId ());
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
In some ns-3 code, sockets will not be explicitly created by user's
|
||||
main programs, if an ns-3 application does it. For instance, for
|
||||
@@ -149,7 +151,7 @@ There are two basic variants of @code{Send()} and @code{Recv()} supported:
|
||||
int Recv (uint8_t* buf, uint32_t size);
|
||||
@end verbatim
|
||||
|
||||
The non-Packet variants are left for legacy API reasons. When calling
|
||||
The non-Packet variants are provided for legacy API reasons. When calling
|
||||
the raw buffer variant of @code{Send()}, the buffer is immediately
|
||||
written into a Packet and the @code{Send (Ptr<Packet> p)} is invoked.
|
||||
|
||||
@@ -160,7 +162,7 @@ the Packet variants are more likely to be preferred in ns-3:
|
||||
|
||||
@itemize @bullet
|
||||
@item Users can use the Tags facility of packets to, for example, encode
|
||||
a flow ID or other helper data.
|
||||
a flow ID or other helper data at the application layer.
|
||||
@item Users can exploit the copy-on-write implementation to avoid
|
||||
memory copies (on the receive side, the conversion back to a
|
||||
@code{uint8_t* buf} may sometimes incur an additional copy).
|
||||
@@ -193,51 +195,6 @@ a real (zeroed) buffer on the spot, and the efficiency will be lost there.
|
||||
|
||||
@section POSIX-like sockets API
|
||||
|
||||
@emph{this capability is under development and is scheduled for
|
||||
inclusion in the ns-3.5 releasetimeframe; see the repository
|
||||
http://code.nsnam.org/mathieu/ns-3-simu for details}
|
||||
|
||||
The below is excerpted from Mathieu's post to ns-developers list
|
||||
on April 4, 2008.
|
||||
|
||||
"To summarize, the goal is that the full posix/socket API is defined in
|
||||
src/process/simu.h: each posix type and function is re-defined there
|
||||
with a simu_ or SIMU_ prefix to avoid ugly name clashes and collisions
|
||||
(feel free to come up with a better prefix).
|
||||
|
||||
Each process is created with a call to ProcessManager::Create and is
|
||||
attached to that ProcessManager instance. So, if the ProcessManager
|
||||
(which is aggregated to a Node in src/helper/process-helper.cc) is
|
||||
killed when the simulation ends, the system will automatically reclaim
|
||||
all the resources of each process associated to each manager. The same
|
||||
happens when an application "exits" from its main function.
|
||||
|
||||
The example application defines two posix "processes": the function
|
||||
ClientProgram creates a udp socket on the localhost port 2000 and the
|
||||
function ServerProgram creates a udp socket on the localhost port 2000.
|
||||
The code does not work right now because I did not get the details of
|
||||
simu_read right yet but, I do plan to make this work at some point.
|
||||
|
||||
I really think that this approach is worthwhile for many reasons, a few
|
||||
of which are outlined below:
|
||||
@itemize @bullet
|
||||
@item makes porting real world application code _much_ easier
|
||||
|
||||
@item makes write applications for new users much easier because they can
|
||||
read the bsd socket api reference and documentation and write code
|
||||
directly.
|
||||
|
||||
@item can be used to write applications which work in both simulation and
|
||||
in the real world at the same time. To do this, all you have to do is
|
||||
write your application to use the simu_ API, and, then, you can chose at
|
||||
compile-time which implementation of that API you want to use: you can
|
||||
pick one implementation which forwards all calls to the system BSD
|
||||
socket API or another one which forwards all calls to the attached
|
||||
ProcessManager. Arguably, I did not implement the version which forwards
|
||||
to system BSD sockets but, that should be pretty trivial.
|
||||
@end itemize
|
||||
|
||||
So, anyway, comments about the overall API would be welcome. Students
|
||||
interested in the gsoc project for real-world code integration should
|
||||
consider looking at this also."
|
||||
|
||||
@cartouche
|
||||
Under development in the http://code.nsnam.org/mathieu/ns-3-simu repository.
|
||||
@end cartouche
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
@node Tap NetDevice
|
||||
@chapter Tap NetDevice
|
||||
|
||||
@cartouche
|
||||
Placeholder chapter
|
||||
@end cartouche
|
||||
|
||||
The Tap NetDevice can be used to allow a host system or virtual machines
|
||||
to interact with a simulation. See @*
|
||||
@code{examples/tap/tap-wifi-dumbbell.cc} for an example.
|
||||
|
||||
+23
-47
@@ -105,10 +105,7 @@ for @code{class TcpSocket}.
|
||||
@subsection Current limitations
|
||||
@itemize @bullet
|
||||
@item Only Tahoe congestion control is presently supported.
|
||||
@item Only IPv4 is supported (IPv6 support will start to be added in ns-3.3).
|
||||
@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=198,,Bug 198}: TcpSocketImpl doesn't send acks with data packets in two-way transfers
|
||||
@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=250,,Bug 250}: Tcp breaks if you set the DelAckCount parameter to be greater than 2
|
||||
@item @uref{http://www.nsnam.org/bugzilla/show_bug.cgi?id=311,,Bug 311}: Tcp socket close returns -1 but does not set errno.
|
||||
@item Only IPv4 is supported (IPv6 support will start to be added after ns-3.6).
|
||||
@end itemize
|
||||
|
||||
@section Network Simulation Cradle
|
||||
@@ -132,43 +129,17 @@ how to use it.
|
||||
@subsection Prerequisites
|
||||
|
||||
Presently, NSC has been tested and shown to work on these platforms:
|
||||
Linux i386 and Linux x86-64. NSC does not support powerpc at the moment.
|
||||
Linux i386 and Linux x86-64. NSC does not support powerpc.
|
||||
|
||||
NSC requires the packages mercurial, flex, and bison.
|
||||
Building NSC requires the packages flex and bison.
|
||||
|
||||
@subsection Configuring and Downloading
|
||||
|
||||
NSC is disabled by default and must be explicitly configured in. To try
|
||||
this, type
|
||||
Using the @code{build.py} script in ns-3-allinone directory, NSC will be
|
||||
enabled by default unless the platform does not support it. To disable
|
||||
it when building ns-3, type:
|
||||
@verbatim
|
||||
./waf configure --enable-nsc
|
||||
@end verbatim
|
||||
the output of the configuration will show something like:
|
||||
@verbatim
|
||||
Checking for NSC supported architecture x86_64 : ok
|
||||
Pulling nsc updates from https://secure.wand.net.nz/mercurial/nsc
|
||||
pulling from https://secure.wand.net.nz/mercurial/nsc
|
||||
searching for changes
|
||||
no changes found
|
||||
---- Summary of optional NS-3 features:
|
||||
...
|
||||
Network Simulation Cradle : enabled
|
||||
...
|
||||
@end verbatim
|
||||
if successful. Note that the configure script pulls a recent copy of
|
||||
NSC from a mercurial repository. This download will not work if you are not
|
||||
online.
|
||||
|
||||
If everything went OK, you will see a directory called "nsc" in the top-level
|
||||
directory, with contents like this:
|
||||
@verbatim
|
||||
audit.sh linux-2.6/ openbsd3/ scons-time.py*
|
||||
ChangeLog linux-2.6.18/ README SConstruct
|
||||
config.log linux-2.6.26/ sconsign.py* sim/
|
||||
freebsd5/ lwip-1.3.0/ scons-LICENSE test/
|
||||
globaliser/ lwip-HEAD/ scons-local-1.0.1/
|
||||
INSTALL ns/ scons.py*
|
||||
LICENSE omnetpp/ scons-README
|
||||
./waf configure --disable-nsc
|
||||
@end verbatim
|
||||
|
||||
@subsection Building and validating
|
||||
@@ -233,12 +204,18 @@ Additionally, NSC TCP exports a lot of configuration variables into the
|
||||
ns-3 @ref{Attributes} system, via a @uref{http://en.wikipedia.org/wiki/Sysctl,,
|
||||
sysctl}-like interface. In the @code{examples/tcp-nsc-zoo} example, you
|
||||
can see the following configuration:
|
||||
@verbatim
|
||||
// this disables TCP SACK, wscale and timestamps on node 1 (the attributes represent sysctl-values).
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_sack", StringValue ("0"));
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_timestamps", StringValue ("0"));
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_window_scaling", StringValue ("0"));
|
||||
@end verbatim
|
||||
@smallformat
|
||||
@example
|
||||
// this disables TCP SACK, wscale and timestamps on node 1 (the attributes
|
||||
represent sysctl-values).
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_sack",
|
||||
StringValue ("0"));
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_timestamps",
|
||||
StringValue ("0"));
|
||||
Config::Set ("/NodeList/1/$ns3::Ns3NscStack<linux2.6.26>/net.ipv4.tcp_window_scaling",
|
||||
StringValue ("0"));
|
||||
@end example
|
||||
@end smallformat
|
||||
These additional configuration variables are not available to native ns-3
|
||||
TCP.
|
||||
|
||||
@@ -331,11 +308,10 @@ nsc-tcp-sockets of a node when its wakeup callback is invoked by nsc.
|
||||
@itemize @bullet
|
||||
@item NSC only works on single-interface nodes; attempting to run it on
|
||||
a multi-interface node will cause a program error. This limitation should
|
||||
be fixed by ns-3.3.
|
||||
@item Cygwin and OS X PPC are not presently supported
|
||||
@item The non-Linux stacks of NSC are not supported
|
||||
@item NSC's integration into the build system presently requires on-line
|
||||
access and mercurial, and is a slow download.
|
||||
be fixed by ns-3.7.
|
||||
@item Cygwin and OS X PPC are not supported
|
||||
@item The non-Linux stacks of NSC are not supported in ns-3
|
||||
@item Not all socket API callbacks are supported
|
||||
@end itemize
|
||||
|
||||
For more information, see
|
||||
|
||||
+42
-27
@@ -1,25 +1,25 @@
|
||||
@node Tracing
|
||||
@chapter Tracing
|
||||
|
||||
The tracing subsystem is one of the most important mechansisms to understand in
|
||||
The tracing subsystem is one of the most important mechanisms to understand in
|
||||
@command{ns-3}. In most cases, @command{ns-3} users will have a brilliant idea
|
||||
for some new and improved networking feature. In order to verify that this
|
||||
idea works, the researcher will make changes to an existing system and then run
|
||||
experiments to see how the new feature behaves by gathering some form of statistic
|
||||
that captures the behavior of the feature.
|
||||
experiments to see how the new feature behaves by gathering statistics
|
||||
that capture the behavior of the feature.
|
||||
|
||||
In other words, the whole point of running a simulation is to generate output for
|
||||
further study. In @command{ns-3}, the subsystem that enables a researcher to do
|
||||
this is the tracing subsystem.
|
||||
|
||||
@menu
|
||||
* Motivation::
|
||||
* Tracing Motivation::
|
||||
* Overview::
|
||||
* Using the Tracing API::
|
||||
* Implementation details::
|
||||
* Tracing implementation details::
|
||||
@end menu
|
||||
|
||||
@node Motivation
|
||||
@node Tracing Motivation
|
||||
@section Motivation
|
||||
|
||||
There are many ways to get information out of a program. The most straightforward
|
||||
@@ -37,7 +37,7 @@ way is to just directly print the information to the standard output, as in,
|
||||
@end verbatim
|
||||
|
||||
This is workable in small environments, but as your simulations get more and more
|
||||
compliated, you end up with more and more prints and the task of parsing and
|
||||
complicated, you end up with more and more prints and the task of parsing and
|
||||
performing computations on the output begins to get harder and harder.
|
||||
|
||||
Another thing to consider is that every time a new tidbit is needed, the software
|
||||
@@ -74,7 +74,7 @@ Trace sources are entities that can signal events that happen in a simulation an
|
||||
provide access to interesting underlying data. For example, a trace source could
|
||||
indicate when a packet is received by a net device and provide access to the
|
||||
packet contents for interested trace sinks. A trace source might also indicate
|
||||
when an iteresting state change happens in a model. For example, the congestion
|
||||
when an interesting state change happens in a model. For example, the congestion
|
||||
window of a TCP model is a prime candidate for a trace source.
|
||||
|
||||
Trace sources are not useful by themselves; they must be connected to other pieces
|
||||
@@ -92,7 +92,7 @@ or models of the simulator.
|
||||
There can be zero or more consumers of trace events generated by a trace source.
|
||||
One can think of a trace source as a kind of point-to-multipoint information link.
|
||||
|
||||
The ``transport protocol'' for this conceptual point-to-multipoint link as an
|
||||
The ``transport protocol'' for this conceptual point-to-multipoint link is an
|
||||
@code{ns-3} @code{Callback}.
|
||||
|
||||
Recall from the Callback Section that callback facility is a way to allow two
|
||||
@@ -100,7 +100,8 @@ modules in the system to communicate via function calls while at the same time
|
||||
decoupling the calling function from the called class completely. This is the
|
||||
same requirement as outlined above for the tracing system.
|
||||
|
||||
Basically, a trace source @emph{is} a callback. When a trace sink expresses
|
||||
Basically, a trace source @emph{is} a callback to which multiple
|
||||
functions may be registered. When a trace sink expresses
|
||||
interest in receiving trace events, it adds a callback to a list of callbacks
|
||||
held by the trace source. When an interesting event happens, the trace source
|
||||
invokes its @code{operator()} providing zero or more parameters. This tells
|
||||
@@ -112,7 +113,8 @@ functions.
|
||||
|
||||
It will be useful to go walk a quick example just to reinforce what we've said.
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
#include ``ns3/object.h''
|
||||
#include ``ns3/uinteger.h''
|
||||
#include ``ns3/traced-value.h''
|
||||
@@ -121,7 +123,8 @@ It will be useful to go walk a quick example just to reinforce what we've said.
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
The first thing to do is include the required files. As mentioned above, the
|
||||
trace system makes heavy use of the Object and Attribute systems. The first
|
||||
@@ -139,7 +142,8 @@ operator--, operator+, operator==, etc.
|
||||
What this all means is that you will be able to trace changes to an object
|
||||
made using those operators.
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
class MyObject : public Object
|
||||
{
|
||||
public:
|
||||
@@ -158,7 +162,8 @@ made using those operators.
|
||||
MyObject () {}
|
||||
TracedValue<uint32_t> m_myInt;
|
||||
};
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
Since the tracing system is integrated with Attributes, and Attributes work
|
||||
with Objects, there must be an @command{ns-3} @code{Object} for the trace source
|
||||
@@ -170,29 +175,33 @@ source to the outside world. The @code{TracedValue} declaration provides the
|
||||
infrastructure that overloads the operators mentioned above and drives the callback
|
||||
process.
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
void
|
||||
IntTrace (Int oldValue, Int newValue)
|
||||
{
|
||||
std::cout << ``Traced `` << oldValue << `` to `` << newValue << std::endl;
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
This is the definition of the trace sink. It corresponds directly to a callback
|
||||
function. This function will be called whenever one of the operators of the
|
||||
@code{TracedValue} is executed.
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
Ptr<MyObject> myObject = CreateObject<MyObject> ();
|
||||
|
||||
myObject->TraceConnectWithoutContext ("MyInt", MakeCallback(&IntTrace));
|
||||
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));
|
||||
|
||||
myObject->m_myInt = 1234;
|
||||
}
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
In this snippet, the first thing that needs to be done is to create the object
|
||||
in which the trace source lives.
|
||||
@@ -238,7 +247,8 @@ called a @emph{config path}.
|
||||
For example, one might find something that looks like the following in the system
|
||||
(taken from @code{examples/tcp-large-transfer.cc})
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
void CwndTracer (uint32_t oldval, uint32_t newval) {}
|
||||
|
||||
...
|
||||
@@ -246,7 +256,8 @@ For example, one might find something that looks like the following in the syste
|
||||
Config::ConnectWithoutContext (
|
||||
"/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
|
||||
MakeCallback (&CwndTracer));
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
This should look very familiar. It is the same thing as the previous example,
|
||||
except that a static member function of class @code{Config} is being called instead
|
||||
@@ -258,13 +269,15 @@ must be an @code{Attribute} of an @code{Object}. In fact, if you had a pointer
|
||||
the @code{Object} that has the ``CongestionWindow'' @code{Attribute} handy (call it
|
||||
@code{theObject}), you could write this just like the previous example:
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
void CwndTracer (uint32_t oldval, uint32_t newval) {}
|
||||
|
||||
...
|
||||
|
||||
theObject->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
It turns out that the code for @code{Config::ConnectWithoutContext} does exactly that.
|
||||
This function takes a path that represents a chain of @code{Object} pointers and follows
|
||||
@@ -297,16 +310,18 @@ This socket, the type of which turns out to be an @code{ns3::TcpSocketImpl} defi
|
||||
an attribute called ``CongestionWindow'' which is a @code{TracedValue<uint32_t>}.
|
||||
The @code{Config::ConnectWithoutContext} now does a,
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
object->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
using the object pointer from ``SocketList/0'' which makes the connection between
|
||||
the trace source defined in the socket to the callback -- @code{CwndTracer}.
|
||||
|
||||
Now, whenever a change is made to the @code{TracedValue<uint32_t>} representing the
|
||||
congestion window in the TCP socket, the registered callback will be executed and
|
||||
the function @code{Cwndtracer} will be called printing out the old and new values
|
||||
the function @code{CwndTracer} will be called printing out the old and new values
|
||||
of the TCP congestion window.
|
||||
|
||||
@node Using the Tracing API
|
||||
@@ -324,5 +339,5 @@ core of the simulator;
|
||||
sinks.
|
||||
@end itemize
|
||||
|
||||
@node Implementation details
|
||||
@node Tracing implementation details
|
||||
@section Implementation details
|
||||
|
||||
@@ -9,7 +9,9 @@ or running ns-3 programs.
|
||||
* Run-time errors::
|
||||
@end menu
|
||||
|
||||
Please note that the wiki (@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting}) may have contributed items.
|
||||
Please note that the wiki @*
|
||||
(@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting})
|
||||
may have contributed items.
|
||||
|
||||
@node Build errors
|
||||
@section Build errors
|
||||
@@ -23,18 +25,21 @@ pointer values are unexpectedly null.
|
||||
|
||||
Here is an example of what might occur:
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point
|
||||
Entering directory `/home/tomh/ns-3-nsc/build'
|
||||
Compilation finished successfully
|
||||
Command ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] exited with code -11
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
The error message says that the program terminated unsuccessfully, but it is
|
||||
not clear from this information what might be wrong. To examine more
|
||||
closely, try running it under the @uref{http://sources.redhat.com/gdb/,,gdb debugger}:
|
||||
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="gdb %s"
|
||||
Entering directory `/home/tomh/ns-3-nsc/build'
|
||||
Compilation finished successfully
|
||||
@@ -44,7 +49,8 @@ GDB is free software, covered by the GNU General Public License, and you are
|
||||
welcome to change it and/or distribute copies of it under certain conditions.
|
||||
Type "show copying" to see the conditions.
|
||||
There is absolutely no warranty for GDB. Type "show warranty" for details.
|
||||
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
|
||||
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db
|
||||
library "/lib/libthread_db.so.1".
|
||||
|
||||
(gdb) run
|
||||
Starting program: /home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point
|
||||
@@ -61,7 +67,8 @@ $1 = {m_ptr = 0x3c5d65}
|
||||
$2 = {m_ptr = 0x0}
|
||||
(gdb) quit
|
||||
The program is running. Exit anyway? (y or n) y
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
Note first the way the program was invoked-- pass the command to run as
|
||||
an argument to the command template "gdb %s".
|
||||
@@ -70,11 +77,13 @@ This tells us that there was an attempt to dereference a null pointer
|
||||
socketFactory.
|
||||
|
||||
Let's look around line 136 of tcp-point-to-point, as gdb suggests:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
Ptr<SocketFactory> socketFactory = n2->GetObject<SocketFactory> (Tcp::iid);
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
The culprit here is that the return value of GetObject is not being
|
||||
checked and may be null.
|
||||
@@ -82,6 +91,8 @@ checked and may be null.
|
||||
Sometimes you may need to use the @uref{http://valgrind.org,,valgrind memory
|
||||
checker} for more subtle errors. Again, you invoke the use of valgrind
|
||||
similarly:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="valgrind %s"
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
+40
-23
@@ -28,9 +28,8 @@ ns-3 provides models for these aspects of 802.11:
|
||||
@item QoS-based EDCA and queueing extensions of @strong{802.11e}
|
||||
@item various propagation loss models including @strong{Nakagami, Rayleigh, Friis, LogDistance, FixedRss, Random}
|
||||
@item two propagation delay models, a distance-based and random model
|
||||
@item various rate control algorithms including @strong{Aarf, Arf, Cara, Onoe, Rraa, and ConstantRate}
|
||||
@item @emph{(under development)} 802.11s (mesh)
|
||||
@item @emph{(under development)} Minstrel rate control
|
||||
@item various rate control algorithms including @strong{Aarf, Arf, Cara, Onoe, Rraa, ConstantRate, and Minstrel}
|
||||
@item 802.11s (mesh), described in another chapter
|
||||
@end itemize
|
||||
|
||||
The set of 802.11 models provided in ns-3 attempts to provide
|
||||
@@ -159,10 +158,12 @@ and a propagation loss based on a log distance model with a reference
|
||||
loss of 46.6777 dB at reference distance of 1m.
|
||||
|
||||
Users will typically type code such as:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
YansWifiChannelHelper wifiChannelHelper = YansWifiChannelHelper::Default ();
|
||||
Ptr<WifiChannel> wifiChannel = wifiChannelHelper.Create ();
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
to get the defaults. Note the distinction above in creating a helper
|
||||
object vs. an actual simulation object.
|
||||
In ns-3, helper objects (used at the helper API only) are created on the
|
||||
@@ -203,35 +204,45 @@ configure MAC parameters like type of MAC, values of contention windows and so o
|
||||
Setting up a non-QoS MAC layers the object we use is @code{ns3::NqosWifiMacHelper}.
|
||||
For example the following user code configures a non-QoS MAC sta and changes its default
|
||||
values for contention window and Aifsn:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
NqosWifiMacHelper wifiMacHelper = NqosWifiMacHelper::Default ();
|
||||
Ssid ssid = Ssid ("ns-3-ssid");
|
||||
wifiMacHelper.SetType ("ns3::NqstaWifiMac", "Ssid", SsidValue (ssid), "ActiveProbing", BooleanValue (false));
|
||||
wifiMacHelper.SetDcaParameters ("MinCw", UintegerValue (20), "Aifsn", UintegerValue (3));
|
||||
@end verbatim
|
||||
wifiMacHelper.SetType ("ns3::NqstaWifiMac", "Ssid", SsidValue (ssid),
|
||||
"ActiveProbing", BooleanValue (false));
|
||||
wifiMacHelper.SetDcaParameters ("MinCw", UintegerValue (20), "Aifsn",
|
||||
UintegerValue (3));
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
Setting up a QoS MACs we use a @code{ns3::QosWifiMacHelper} instead.
|
||||
This object could be also used to change default EDCA parameters, and to set a possible MSDU aggregator
|
||||
for a particular access class in order to use 802.11n MSDU aggregation feature.
|
||||
A possible user code:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
QosWifiMacHelper wifiMacHelper = QosWifiMacHelper::Default ();
|
||||
wifiMacHelper.SetType ("ns3::QapWifiMac", "Ssid", SsidValue (ssid), "BeaconGeneration", BooleanValue (true),
|
||||
wifiMacHelper.SetType ("ns3::QapWifiMac", "Ssid", SsidValue (ssid),
|
||||
"BeaconGeneration", BooleanValue (true),
|
||||
"BeaconInterval", TimeValue (Seconds (2.5)));
|
||||
wifiMacHelper.SetEdcaParametersForAc (AC_VO, "MinCw", UintegerValue (2));
|
||||
wifiMacHelper.SetMsduAggregatorForAc (AC_VO, "ns3::MsduStandardAggregator", "MaxAmsduSize", UintegerValue (3839));
|
||||
@end verbatim
|
||||
wifiMacHelper.SetMsduAggregatorForAc (AC_VO, "ns3::MsduStandardAggregator",
|
||||
"MaxAmsduSize", UintegerValue (3839));
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
Call to QosWifiMacHelper::Default () is needed in order to set default EDCA parameters properly for all
|
||||
access classes. Otherwise we should set them one by one:
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
QosWifiMacHelper wifiMacHelper;
|
||||
wifiMacHelper.SetEdcaParametersForAc (AC_VO, "MinCw", UintegerValue (2), "MaxCw", UintegerValue (7),
|
||||
"Aifsn", UintegerValue (2));
|
||||
wifiMacHelper.SetEdcaParametersForAc (AC_VI, "MinCw", UintegerValue (7), "MaxCw", UintegerValue (15),
|
||||
"Aifsn", UintegerValue (2));
|
||||
wifiMacHelper.SetEdcaParametersForAc (AC_VO, "MinCw", UintegerValue (2),
|
||||
"MaxCw", UintegerValue (7), "Aifsn", UintegerValue (2));
|
||||
wifiMacHelper.SetEdcaParametersForAc (AC_VI, "MinCw", UintegerValue (7),
|
||||
"MaxCw", UintegerValue (15), "Aifsn", UintegerValue (2));
|
||||
...
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
|
||||
@subsection WifiHelper
|
||||
|
||||
@@ -244,9 +255,11 @@ What does this do? It sets the RemoteStationManager to
|
||||
@code{ns3::ArfWifiManager}.
|
||||
Now, let's use the wifiPhyHelper and wifiMacHelper created above to install WifiNetDevices
|
||||
on a set of nodes in a NodeContainer "c":
|
||||
@verbatim
|
||||
@smallformat
|
||||
@example
|
||||
NetDeviceContainer wifiContainer = WifiHelper::Install (wifiPhyHelper, wifiMacHelper, c);
|
||||
@end verbatim
|
||||
@end example
|
||||
@end smallformat
|
||||
This creates the WifiNetDevice which includes also a WifiRemoteStationManager,
|
||||
a WifiMac, and a WifiPhy (connected to the matching WifiChannel).
|
||||
|
||||
@@ -257,12 +270,16 @@ show how to do some of this reconfiguration.
|
||||
@subsection AdHoc WifiNetDevice configuration
|
||||
This is a typical example of how a user might configure an adhoc network.
|
||||
|
||||
@emph{Write me}
|
||||
@cartouche
|
||||
To be completed
|
||||
@end cartouche
|
||||
|
||||
@subsection Infrastructure (Access Point and clients) WifiNetDevice configuration
|
||||
This is a typical example of how a user might configure an access point and a set of clients.
|
||||
|
||||
@emph{Write me}
|
||||
@cartouche
|
||||
To be completed
|
||||
@end cartouche
|
||||
|
||||
@node The WifiChannel and WifiPhy models
|
||||
@section The WifiChannel and WifiPhy models
|
||||
|
||||
+29
-22
@@ -1,10 +1,11 @@
|
||||
Steps in doing an ns-3 release
|
||||
|
||||
1. check out a clean ns-3-dev somewhere
|
||||
1. check out a clean ns-3-dev somewhere using ns-3-allinone (you will need it)
|
||||
- hg clone http://code.nsnam.org/ns-3-allinone
|
||||
- ./download.py
|
||||
- ./build.py
|
||||
- confirm that the release builds cleanly.
|
||||
- cd ns-3-dev
|
||||
- ensure that tests pass (./test.py)
|
||||
- ensure no regressions (./waf --regression)
|
||||
2. prepare the source files
|
||||
@@ -13,19 +14,23 @@ Steps in doing an ns-3 release
|
||||
- DO NOT change VERSION at this time
|
||||
- confirm that Doxygen builds cleanly and without warnings
|
||||
(./waf doxygen), and check in any necessary changes
|
||||
3. ./waf configure; ./waf dist
|
||||
- this will create an ns-3-dev.tar.bz2 tarball
|
||||
- this will also create a ns-3-dev-ref-traces.tar.bz2 tarball
|
||||
4. test dev tarball on release platforms (waf --check and maybe some other
|
||||
scripts)
|
||||
3. build an ns-3-allinone distribution
|
||||
- change back into the allinone directory
|
||||
- ./dist.py
|
||||
- this will create an ns-allinone-dev.tar.bz2 tarball
|
||||
4. test dev tarball on release platforms
|
||||
- ./test.py
|
||||
- ./waf --regression
|
||||
- other scripts you can think of
|
||||
5. once you are happy with the tarball, tag ns-3-dev and ns-3-dev-ref-traces
|
||||
- cd into ns-3-dev
|
||||
- hg tag "ns-3.x"
|
||||
- hg push
|
||||
- cd into regression/ns-3-dev-ref-traces
|
||||
- cd into ns-3-dev-ref-traces
|
||||
- hg tag "ns-3.x"
|
||||
- hg push
|
||||
6. clone the tagged ns-3-dev and place it on the repository
|
||||
- ssh code.nsnam.org; sudo tcsh; su code;
|
||||
- ssh code.nsnam.org; sudo bash; su code;
|
||||
- cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.1x
|
||||
- cd /home/code/repos/ns-3.x/.hg and edit the hgrc appropriately:
|
||||
"description = ns-3.x release
|
||||
@@ -33,20 +38,21 @@ Steps in doing an ns-3 release
|
||||
- clone the ns-3-dev-ref-traces and place it on the repository as above
|
||||
but use the name ns-3.x-ref-traces and edit the hgrc appropriately
|
||||
7. check out a clean version of the new release (ns-3.x) somewhere
|
||||
- hg clone http://code.nsnam.org/ns-3.x
|
||||
8. Update the VERSION for this new release
|
||||
- change the string 3-dev in the VERSION file to the real version
|
||||
(e.g. 3.7 or 3.7-RC1) This must agree with the version name you chose in the clone
|
||||
for the regression tests to work.
|
||||
- hg commit
|
||||
- hg push
|
||||
- hg commit -m "update VERSION to ns-3.x"
|
||||
- hg push ssh://code@code.nsnam.org//home/code/repos/ns-3.x
|
||||
|
||||
9. Run the tests on the new release (debug and optimized) like a user would
|
||||
You need to use ns-3-allinone since you will use that to make the distro
|
||||
- hg clone http://code.nsnam.org/ns-3-allinone-ns-3.x
|
||||
- hg clone http://code.nsnam.org/ns-3-allinone ns-3-allinone-3.x
|
||||
- cd !$
|
||||
- ./download.py -n ns-3.x -r ns-3.x-ref-traces
|
||||
- ./build.py
|
||||
- cd ns-3.x
|
||||
- ./waf -d debug configure
|
||||
- ./waf
|
||||
- ./test.py
|
||||
- ./test.py -g
|
||||
- ./waf --regression
|
||||
@@ -59,9 +65,8 @@ Steps in doing an ns-3 release
|
||||
- ./waf --valgrind --regression (for valgrind version)
|
||||
- There should be no regression errors at this time
|
||||
10. Create final tarballs
|
||||
- cd ..
|
||||
- cd into ns-3-allinone level
|
||||
- ./dist.py
|
||||
- ./waf configure; ./waf dist
|
||||
- this will create an ns-allinone-3.x.tar.bz2 tarball
|
||||
11. upload "ns-allinone-3.x.tar.bz2" to the /var/www/html/releases/ directory on
|
||||
the www.nsnam.org server
|
||||
@@ -74,23 +79,25 @@ Steps in doing an ns-3 release
|
||||
- sudo chmod 644 ns-allinone-3.x.tar.bz2
|
||||
13. update web pages on www.nsnam.org (source is in the www/ module)
|
||||
- clone the source repo (hg clone http://code.nsnam.org/www)
|
||||
- update index.html
|
||||
- add link to news.html
|
||||
- update getting_started.html
|
||||
- update documents.html
|
||||
- update references to releases in html_src
|
||||
(consider "grep 'ns-3\.' *.html" for a new release)
|
||||
(consider "grep 'RCx' *.html" for a new RC)
|
||||
- update references to releases in scripts/
|
||||
|
||||
- update roadmap on wiki
|
||||
- commit and push changes
|
||||
14. update the server
|
||||
- build and update HTML directory on the server
|
||||
-- ssh www.nsnam.org; sudo tcsh; su nsnam;
|
||||
-- ssh www.nsnam.org; sudo bash; su nsnam;
|
||||
-- run ~/bin/update-html
|
||||
- build and update Doxygen directory on the server
|
||||
-- edit ~/bin/update-doxygen-release file and change RELEASE variable
|
||||
to the right version number
|
||||
-- run ~/bin/update-doxygen-release
|
||||
14. Final checks
|
||||
15. Final checks
|
||||
- download tarball from web, build and run regression tests for as many
|
||||
targets as you can
|
||||
- download release from mercurial, build and run regression tests for as
|
||||
many targets as you can
|
||||
- test and verify until you're confident the release is solid.
|
||||
15. announce to ns-developers, with summary of release notes
|
||||
16. announce to ns-developers, with summary of release notes
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
+805
-6
@@ -1,4 +1,3 @@
|
||||
|
||||
@c ============================================================================
|
||||
@c Begin document body here
|
||||
@c ============================================================================
|
||||
@@ -17,6 +16,7 @@
|
||||
|
||||
@menu
|
||||
* Background::
|
||||
* Overview::
|
||||
@end menu
|
||||
|
||||
@c ============================================================================
|
||||
@@ -1096,10 +1096,809 @@ Callbacks, feel free to take a look at the @code{ns-3} manual. They are one
|
||||
of the most frequently used constructs in the low-level parts of @code{ns-3}.
|
||||
It is, in my opinion, a quite elegant thing.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@subsection What About TracedValue?
|
||||
|
||||
Earlier in this section, we presented a simple piece of code that used a
|
||||
@code{TracedValue<int32_t>} to demonstrate the basics of the tracing code.
|
||||
We just glossed over the way to find the return type and formal arguments
|
||||
for the @code{TracedValue}. Rather than go through the whole exercise, we
|
||||
will just point you at the correct file, @code{src/core/traced-value.h} and
|
||||
to the important piece of code:
|
||||
|
||||
@verbatim
|
||||
template <typename T>
|
||||
class TracedValue
|
||||
{
|
||||
public:
|
||||
...
|
||||
void Set (const T &v) {
|
||||
if (m_v != v)
|
||||
{
|
||||
m_cb (m_v, v);
|
||||
m_v = v;
|
||||
}
|
||||
}
|
||||
...
|
||||
private:
|
||||
T m_v;
|
||||
TracedCallback<T,T> m_cb;
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
Here you see that the @code{TracedValue} is templated, of course. In the simple
|
||||
example case at the start of the section, the typename is int32_t. This means
|
||||
that the member variable being traced (@code>m_v} in the private section of the
|
||||
class) will be an @code{int32_t m_v}. The @code{Set} method will take a
|
||||
@code{const uint32_t &v} as a parameter. You should now be able to understand
|
||||
that the @code{Set} code will fire the @code{m_cb} callback with two parameters:
|
||||
the first being the current value of the @code{TracedValue}; and the second
|
||||
being the new value being set.
|
||||
|
||||
The callback, @code{m_cb} is declared as a @code{TracedCallback<T, T>} which
|
||||
will correspond to a @code{TracedCallback<int32_t, int32_t>} when the class is
|
||||
instantiated.
|
||||
|
||||
Recall that the callback target of a TracedCallback always returns @code{void}.
|
||||
Further recall that there is a one-to-one correspondence between the template
|
||||
parameter list in the declaration and the formal arguments of the callback
|
||||
function. Therefore the callback will need to have a function signature that
|
||||
looks like:
|
||||
|
||||
@verbatim
|
||||
void
|
||||
MyCallback (uint32_t oldValue, uint32_t newValue)
|
||||
{
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
It probably won't surprise you that this is exactly what we provided in that
|
||||
simple example we covered so long ago:
|
||||
|
||||
@verbatim
|
||||
void
|
||||
IntTrace (int32_t oldValue, int32_t newValue)
|
||||
{
|
||||
std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
@c ============================================================================
|
||||
@c A Real Example
|
||||
@c ============================================================================
|
||||
@node A Real Example
|
||||
@section A Real Example
|
||||
|
||||
Let's do an example taken from one of the best-known books on TCP around.
|
||||
``TCP/IP Illustrated, Volume 1: The Protocols,'' by W. Richard Stevens is a
|
||||
classic. I just flipped the book open and ran across a nice plot of both the
|
||||
congestion window and sequence numbers versus time on page 366. Stevens calls
|
||||
this, ``Figure 21.10. Value of cwnd and send sequence number while data is being
|
||||
transmitted.'' Let's just recreate the cwnd part of that plot in @command{ns-3}
|
||||
using the tracing system and @code{gnuplot}.
|
||||
|
||||
@subsection Are There Trace Sources Available?
|
||||
|
||||
The first thing to think about is how we want to get the data out. What is it
|
||||
that we need to trace? The first thing to do is to consult ``The list of all
|
||||
trace sources'' to see what we have to work with. Recall that this is found
|
||||
in the @command{ns-3} Doxygen in the ``Core'' Module section. If you scroll
|
||||
through the list, you will eventually find:
|
||||
|
||||
@verbatim
|
||||
ns3::TcpSocketImpl
|
||||
CongestionWindow: The TCP connection's congestion window
|
||||
@end verbatim
|
||||
|
||||
It turns out that the @command{ns-3} TCP implementation lives (mostly) in the
|
||||
file @code{src/internet-stack/tcp-socket-impl.cc}. If you don't know this a
|
||||
priori, you can use the recursive grep trick:
|
||||
|
||||
@verbatim
|
||||
find . -name '*.cc' | xargs grep -i tcp
|
||||
@end verbatim
|
||||
|
||||
You will find page after page of instances of tcp pointing you to that file.
|
||||
|
||||
If you open @code{src/internet-stack/tcp-socket-impl.cc} in your favorite
|
||||
editor, you will see right up at the top of the file, the following declarations:
|
||||
|
||||
@verbatim
|
||||
TypeId
|
||||
TcpSocketImpl::GetTypeId ()
|
||||
{
|
||||
static TypeId tid = TypeId(``ns3::TcpSocketImpl'')
|
||||
.SetParent<TcpSocket> ()
|
||||
.AddTraceSource (``CongestionWindow'',
|
||||
``The TCP connection's congestion window'',
|
||||
MakeTraceSourceAccessor (&TcpSocketImpl::m_cWnd))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This should tell you to look for the declaration of @code{m_cWnd} in the header
|
||||
file @code{src/internet-stack/tcp-socket-impl.h}. If you open this file in your
|
||||
favorite editor, you will find:
|
||||
|
||||
@verbatim
|
||||
TracedValue<uint32_t> m_cWnd; //Congestion window
|
||||
@end verbatim
|
||||
|
||||
You should now understand this code completely. If we have a pointer to the
|
||||
@code{TcpSocketImpl}, we can @code{TraceConnect} to the ``CongestionWindow'' trace
|
||||
source if we provide an appropriate callback target. This is the same kind of
|
||||
trace source that we saw in the simple example at the start of this section,
|
||||
except that we are talking about @code{uint32_t} instead of @code{int32_t}.
|
||||
|
||||
We now know that we need to provide a callback that returns void and takes
|
||||
two @code{uint32_t} parameters, the first being the old value and the second
|
||||
being the new value:
|
||||
|
||||
@verbatim
|
||||
void
|
||||
CwndTrace (uint32_t oldValue, uint32_t newValue)
|
||||
{
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
@subsection What Script to Use?
|
||||
|
||||
It's always best to try and find working code laying around that you can
|
||||
modify, rather than starting from scratch. So the fist order of business now
|
||||
is to find some code that already hooks the ``CongestionWindow'' trace source
|
||||
and see if we can modify it. As usual, grep is your friend:
|
||||
|
||||
@verbatim
|
||||
find . -name '*.cc' | xargs grep CongestionWindow
|
||||
@end verbatim
|
||||
|
||||
This will point out a couple of promising candidates:
|
||||
@code{examples/tcp/tcp-large-transfer.cc} and
|
||||
@code{src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc}.
|
||||
|
||||
We haven't visited any of the test code yet, so let's take a look there. You
|
||||
will typically find that test code is fairly minimal, so this is probably a
|
||||
very good bet. Open @code{src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc} in your
|
||||
favorite editor and search for ``CongestionWindow.'' You will find,
|
||||
|
||||
@verbatim
|
||||
ns3TcpSocket->TraceConnectWithoutContext (``CongestionWindow'',
|
||||
MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, this));
|
||||
@end verbatim
|
||||
|
||||
This should look very familiar to you. We mentioned above that if we had a
|
||||
pointer to the @code{TcpSocketImpl}, we could @code{TraceConnect} to the
|
||||
``CongestionWindow'' trace source. That's exactly what we have here; so it
|
||||
turns out that this line of code does exactly what we want. Let's go ahead
|
||||
and extract the code we need from this function
|
||||
(@code{Ns3TcpCwndTestCase1::DoRun (void)}). If you look at this function,
|
||||
you will find that it looks just like an @code{ns-3} script. It turns out that
|
||||
is exactly what it is. It is a script run by the test framework, so we can just
|
||||
pull it out and wrap it in @code{main} instead of in @code{DoRun}. Rather than
|
||||
walk through this step, by step, we have provided the file that results from
|
||||
porting this test back to a native @code{ns-3} script --
|
||||
@code{examples/tutorial/fifth.cc}.
|
||||
|
||||
@subsection A Common Problem and Solution
|
||||
|
||||
The @code{fifth.cc} example demonstrates an extremely important rule that you
|
||||
must understand before using any kind of @code{Attribute}: you must ensure
|
||||
that the target of a @code{Config} command exists before trying to use it.
|
||||
This is no different than saying an object must be instantiated before trying
|
||||
to call it, Although this may seem obvious when stated this way, it does
|
||||
trip up many people trying to use the system for the first time.
|
||||
|
||||
Let's return to basics for a moment. There are three basic time periods that
|
||||
exist in any @command{ns-3} script. The first time period is sometimes called
|
||||
``Configuration Time'' or ``Setup Time,'' and is in force during the period
|
||||
when the @code{main} function of your script is running, but before
|
||||
@code{Simulator::Run} is called. The second time period is sometimes called
|
||||
``Simulation Time'' and is in force during the time period when
|
||||
@code{Simulator::Run} is actively executing its events. After it completes
|
||||
executing the simulation, @code{Simulator::Run} will return control back to
|
||||
the @code{main} function. When this happens, the script enters what can be
|
||||
called ``Teardown Time,'' which is when the structures and objects created
|
||||
during setup and taken apart and released,
|
||||
|
||||
Perhaps the most common mistake made in trying to use the tracing system is
|
||||
assuming that entities constructed dynamically during simulation time are
|
||||
available during configuration time. In particular, an @command{ns-3}
|
||||
@code{Socket} is a dynamic object often created by @code{Applications} to
|
||||
communicate between @code{Nodes}. An @command{ns-3} @code{Application}
|
||||
always has a ``Start Time'' and a ``Stop Time'' associated with it. In the
|
||||
vast majority of cases, an @code{Application} will not attempt to create
|
||||
a dynamic object until its @code{StartApplication} method is called. This
|
||||
is to ensure that the simulation is completely configured before the app
|
||||
tries to do anything (what would happen if it tried to connect to a node
|
||||
that didn't exist yet during configuration time). The answer to this
|
||||
issue is to 1) create a simulator event that is run after the dynamic object
|
||||
is created and hook the trace when that event is executedl or 2) create the
|
||||
dynamic object at configuration time, hook it then, and give the object to
|
||||
the system to use during simulation time. We took the second approach in
|
||||
the @code{fifth.cc} example. This decision required us to create the
|
||||
@code{MyApp} @code{Application}, the entire purpose of which is to
|
||||
take a @code{Socket} as a parameter.
|
||||
|
||||
@subsection A fifth.cc Walkthrough
|
||||
|
||||
Now, let's take a look at the example program we constructed by disecting
|
||||
the congestion window test. Open @code{examples/tutorial/fifth.cc} in your
|
||||
favorite editor. You should see some familiar looking code:
|
||||
|
||||
@verbatim
|
||||
/* -*- Mode:C++; c-file-style:''gnu''; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Include., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/common-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
|
||||
@end verbatim
|
||||
|
||||
This has all been covered, so we won't rehash it. The next lines of source are
|
||||
the network illustration and a comment addressing the problem described above
|
||||
with @code{Socket}.
|
||||
|
||||
@verbatim
|
||||
// ===========================================================================
|
||||
//
|
||||
// node 0 node 1
|
||||
// +----------------+ +----------------+
|
||||
// | ns-3 TCP | | ns-3 TCP |
|
||||
// +----------------+ +----------------+
|
||||
// | 10.1.1.1 | | 10.1.1.2 |
|
||||
// +----------------+ +----------------+
|
||||
// | point-to-point | | point-to-point |
|
||||
// +----------------+ +----------------+
|
||||
// | |
|
||||
// +---------------------+
|
||||
// 5 Mbps, 2 ms
|
||||
//
|
||||
//
|
||||
// We want to look at changes in the ns-3 TCP congestion window. We need
|
||||
// to crank up a flow and hook the CongestionWindow attribute on the socket
|
||||
// of the sender. Normally one would use an on-off application to generate a
|
||||
// flow, but this has a couple of problems. First, the socket of the on-off
|
||||
// application is not created until Application Start time, so we wouldn't be
|
||||
// able to hook the socket (now) at configuration time. Second, even if we
|
||||
// could arrange a call after start time, the socket is not public so we
|
||||
// couldn't get at it.
|
||||
//
|
||||
// So, we can cook up a simple version of the on-off application that does what
|
||||
// we want. On the plus side we don't need all of the complexity of the on-off
|
||||
// application. On the minus side, we don't have a helper, so we have to get
|
||||
// a little more involved in the details, but this is trivial.
|
||||
//
|
||||
// So first, we create a socket and do the trace connect on it; then we pass
|
||||
// this socket into the constructor of our simple application which we then
|
||||
// install in the source node.
|
||||
// ===========================================================================
|
||||
//
|
||||
@end verbatim
|
||||
|
||||
This should also be self-explanatory.
|
||||
|
||||
The next part is the declaration of the @code{MyApp} @code{Application} that
|
||||
we put together to allow the @code{Socket} to be created at configuration time.
|
||||
|
||||
@verbatim
|
||||
class MyApp : public Application
|
||||
{
|
||||
public:
|
||||
|
||||
MyApp ();
|
||||
virtual ~MyApp();
|
||||
|
||||
void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize,
|
||||
uint32_t nPackets, DataRate dataRate);
|
||||
|
||||
private:
|
||||
virtual void StartApplication (void);
|
||||
virtual void StopApplication (void);
|
||||
|
||||
void ScheduleTx (void);
|
||||
void SendPacket (void);
|
||||
|
||||
Ptr<Socket> m_socket;
|
||||
Address m_peer;
|
||||
uint32_t m_packetSize;
|
||||
uint32_t m_nPackets;
|
||||
DataRate m_dataRate;
|
||||
EventId m_sendEvent;
|
||||
bool m_running;
|
||||
uint32_t m_packetsSent;
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
You can see that this class inherits from the @command{ns-3} @code{Application}
|
||||
class. Take a look at @code{src/node/application.h} if you are interested in
|
||||
what is inherited. The @code{MyApp} class is obligated to override the
|
||||
@code{StartApplication} and @code{StopApplication} methods. These methods are
|
||||
called when the corresponding base class @code{Start} and @code{Stop} methods are
|
||||
called during simulation time.
|
||||
|
||||
@subsubsection How Applications are Started and Stopped
|
||||
|
||||
It is worthwhile to spend a bit of time explaining how events actually get
|
||||
started in the system. The most common way to start pumping events is to start
|
||||
an @code{Application}. This is done as the result of the following (hopefully)
|
||||
familar lines of an @command{ns-3} script:
|
||||
|
||||
@verbatim
|
||||
ApplicationContainer apps = ...
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
@end verbatim
|
||||
|
||||
The application container code (see @code{src/helper/application-container.h} if
|
||||
you are interested) loops through its contained applications and calls,
|
||||
|
||||
@verbatim
|
||||
app->Start (startTime);
|
||||
app->Stop (stopTime);
|
||||
@end verbatim
|
||||
|
||||
on each of them. The @code{Start} method of an @code{Application} calls
|
||||
@code{Application::ScheduleStart} (see @code{src/helper/application-container.cc})
|
||||
which, in turn, schedules an event to start the @code{Application}:
|
||||
|
||||
@verbatim
|
||||
Simulator::Schedule (startTime, &Application::StartApplication, this);
|
||||
@end verbatim
|
||||
|
||||
Since @code{MyApp} inherits from @code{Application} and overrides
|
||||
@code{StartApplication}, this bit of code causes the simulator to execute
|
||||
something that is effectively like,
|
||||
|
||||
@verbatim
|
||||
this->StartApplication (startTime);
|
||||
@end verbatim
|
||||
|
||||
where the @code{this} pointer, if you have kept it all straight, is the pointer
|
||||
to the @code{Application} in the container. It is then expected that another
|
||||
event will be scheduled in the overridden @code{StartApplication} that will
|
||||
begin doing some application-specific function, like sending packets.
|
||||
|
||||
@code{StopApplication} operates in a similar manner and tells the @code{Application}
|
||||
to stop generating events.
|
||||
|
||||
@subsubsection The MyApp Application
|
||||
|
||||
The @code{MyApp} @code{Application} needs a constructor and a destructor,
|
||||
of course:
|
||||
|
||||
@verbatim
|
||||
MyApp::MyApp ()
|
||||
: m_socket (0),
|
||||
m_peer (),
|
||||
m_packetSize (0),
|
||||
m_nPackets (0),
|
||||
m_dataRate (0),
|
||||
m_sendEvent (),
|
||||
m_running (false),
|
||||
m_packetsSent (0)
|
||||
{
|
||||
}
|
||||
|
||||
MyApp::~MyApp()
|
||||
{
|
||||
m_socket = 0;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The existence of the next bit of code is the whole reason why we wrote this
|
||||
@code{Application} in the first place.
|
||||
|
||||
@verbatim
|
||||
void
|
||||
MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize,
|
||||
uint32_t nPackets, DataRate dataRate)
|
||||
{
|
||||
m_socket = socket;
|
||||
m_peer = address;
|
||||
m_packetSize = packetSize;
|
||||
m_nPackets = nPackets;
|
||||
m_dataRate = dataRate;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This code should be pretty self-explanatory. We are just initializing member
|
||||
variables. The important one from the perspective of tracing is the
|
||||
@code{Ptr<Socket> socket} which we needed to provide to the application
|
||||
during configuration time. Recall that we are going to create the @code{Socket}
|
||||
as a @code{TcpSocket} (which is implemented by @code{TcpSocketImpl}) and hook
|
||||
its ``CongestionWindow'' trace source before passing it to the @code{Setup}
|
||||
method.
|
||||
|
||||
@verbatim
|
||||
void
|
||||
MyApp::StartApplication (void)
|
||||
{
|
||||
m_running = true;
|
||||
m_packetsSent = 0;
|
||||
m_socket->Bind ();
|
||||
m_socket->Connect (m_peer);
|
||||
SendPacket ();
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The above code is the overridden implementation @code{Application::StartApplication}
|
||||
that will be automatically called by the simulator to start our @code{Application}
|
||||
running. You can see that it does a @code{Socket} @code{Bind} operation. If
|
||||
you are familiar with Berkeley Sockets this shouldn't be a surprise. It performs
|
||||
the required work on the local side of the connection just as you might expect.
|
||||
The following @code{Connect} will do what is required to establish a connection
|
||||
with the TCP at @code{Address} m_peer. It should now be clear why we need to defer
|
||||
a lot of this to simulation time, since the @code{Connect} is going to need a fully
|
||||
functioning network to comlete. After the @code{Connect}, the @code{Application}
|
||||
then starts creating simulation events by calling @code{SendPacket}.
|
||||
|
||||
The next bit of code explains to the @code{Application} how to stop creating
|
||||
simulation events.
|
||||
|
||||
@verbatim
|
||||
void
|
||||
MyApp::StopApplication (void)
|
||||
{
|
||||
m_running = false;
|
||||
|
||||
if (m_sendEvent.IsRunning ())
|
||||
{
|
||||
Simulator::Cancel (m_sendEvent);
|
||||
}
|
||||
|
||||
if (m_socket)
|
||||
{
|
||||
m_socket->Close ();
|
||||
}
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Every time a simulation event is scheduled, an @code{Event} is created. If the
|
||||
@code{Event} is pending execution or executing, its method @code{IsRunning} will
|
||||
return @code{true}. In this code, if @code{IsRunning()} returns true, we
|
||||
@code{Cancel} the event which removes it from the simulator event queue. By
|
||||
doing this, we break the chain of events that the @code{Application} is using to
|
||||
keep sending its @code{Packets} and the @code{Application} goes quiet. After we
|
||||
quiet the @code{Application} we @code{Close} the socket which tears down the TCP
|
||||
connection.
|
||||
|
||||
The socket is actually deleted in the destructor when the @code{m_socket = 0} is
|
||||
executed. This removes the last reference to the underlying Ptr<Socket> which
|
||||
causes the destructor of that Object to be called.
|
||||
|
||||
Recall that @code{StartApplication} called @code{SendPacket} to start the
|
||||
chain of events that describes the @code{Application} behavior.
|
||||
|
||||
@verbatim
|
||||
void
|
||||
MyApp::SendPacket (void)
|
||||
{
|
||||
Ptr<Packet> packet = Create<Packet> (m_packetSize);
|
||||
m_socket->Send (packet);
|
||||
|
||||
if (++m_packetsSent < m_nPackets)
|
||||
{
|
||||
ScheduleTx ();
|
||||
}
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Here, you see that @code{SendPacket} does just that. It creates a @code{Packet}
|
||||
and then does a @code{Send} which, if you know Berkeley Sockets, is probably
|
||||
just what you expected to see.
|
||||
|
||||
It is the responsibility of the @code{Application} to keep scheduling the
|
||||
chain of events, so the next lines call @code{ScheduleTx} to schedule another
|
||||
transmit event (a @code{SendPacket}) until the @code{Application} decides it
|
||||
has sent enough.
|
||||
|
||||
@verbatim
|
||||
void
|
||||
MyApp::ScheduleTx (void)
|
||||
{
|
||||
if (m_running)
|
||||
{
|
||||
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
|
||||
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
|
||||
}
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Here, you see that @code{ScheduleTx} does exactly that. If the @code{Applciation}
|
||||
is running (if @code{StopApplication}) has not been called) it will schedule a
|
||||
new event, which calls @code{SendPacket} again. The alert reader will spot
|
||||
something that also trips up new users. The data rate of an @code{Application} is
|
||||
just that. It has nothing to do with the data rate of an underlying @code{Channel}.
|
||||
This is the rate at which the @code{Application} produces bits. It does not take
|
||||
into account any overhead for the various protocols or channels that it uses to
|
||||
transport the data. If you set the data rate of an @code{Application} to the same
|
||||
data rate as your underlying @code{Channel} you will eventually get a buffer overflow.
|
||||
|
||||
@subsubsection The Trace Sinks
|
||||
|
||||
The whole point of this exercise is to get trace callbacks from TCP indicating the
|
||||
congestion window has been updated. The next piece of code implements the
|
||||
corresponding trace sink:
|
||||
|
||||
@verbatim
|
||||
static void
|
||||
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
|
||||
{
|
||||
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << ``\t'' << newCwnd);
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This should be very familiar to you now, so we won't dwell on the details. This
|
||||
function just logs the current simulation time and the new value of the
|
||||
congestion window every time it is changed. You can probably imagine that you
|
||||
could load the resulting output into a graphics program (gnuplot or Excel) and
|
||||
immediately see a nice graph of the congestion window behavior over time.
|
||||
|
||||
We added a new trace sink to show where are dropped. We are going to add an
|
||||
error model to this code also, so we wanted to demonstrate this working.
|
||||
|
||||
@verbatim
|
||||
static void
|
||||
RxDrop (Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This trace sink will be connected to the ``PhyRxDrop'' trace source of the
|
||||
point-to-point NetDevice. This trace source fires when a packet is dropped
|
||||
by the physical layer of a @code{NetDevice}. If you take a small detour to the
|
||||
source (@code{src/devices/point-to-point/point-to-point-net-device.cc}) you will
|
||||
see that this trace source refers to @code{PointToPointNetDevice::m_phyRxDropTrace}.
|
||||
If you then look in @code{src/devices/point-to-point/point-to-point-net-device.h}
|
||||
for this member variable, you will find that it is declared as a
|
||||
@code{TracedCallback<Ptr<const Packet> >}. This should tell you that the
|
||||
callback target should be a function that returns void and takes a single
|
||||
parameter which is a @code{Ptr<const Packet>} -- just what we have above.
|
||||
|
||||
@subsubsection The Main Program
|
||||
|
||||
The following code should be very familiar to you by now:
|
||||
|
||||
@verbatim
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
NodeContainer nodes;
|
||||
nodes.Create (2);
|
||||
|
||||
PointToPointHelper pointToPoint;
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
|
||||
|
||||
NetDeviceContainer devices;
|
||||
devices = pointToPoint.Install (nodes);
|
||||
@end verbatim
|
||||
|
||||
This creates two nodes with a point-to-point channel between them, just as
|
||||
shown in the illustration at the start of the file.
|
||||
|
||||
The next few lines of code show somthing new. If we trace a connection that
|
||||
behaves perfectly, we will end up with a monotonically increasing congestion
|
||||
window. To see any interesting behavior, we really want to introduce link
|
||||
errors which will drop packets, cause duplicate ACKs and trigger the more
|
||||
interesting behaviors of the congestion window.
|
||||
|
||||
@command{ns-3} provides @code{ErrorModel} objects which can be attached to
|
||||
@code{Channels}. We are using the @code{RateErrorModel} which allows us
|
||||
to introduce errors into a @code{Channel} at a given @emph{rate}.
|
||||
|
||||
@verbatim
|
||||
Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> (
|
||||
"RanVar", RandomVariableValue (UniformVariable (0., 1.)),
|
||||
"ErrorRate", DoubleValue (0.00001));
|
||||
devices.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
|
||||
@end verbatim
|
||||
|
||||
The above code instantiates a @code{RateErrorModel} Object. Rather than
|
||||
using the two-step process of instantiating it and then setting Attributes,
|
||||
we use the convenience function @code{CreateObjectWithAttributes} which
|
||||
allows us to do both at the same time. We set the ``RanVar''
|
||||
@code{Attribute} to a random variable that generates a uniform distribution
|
||||
from 0 to 1. We also set the ``ErrorRate'' @code{Attribute}.
|
||||
We then set the resulting instantiated @code{RateErrorModel} as the error
|
||||
model used by the point-to-point @code{NetDevice}. This will give us some
|
||||
retransmissions and make our plot a little more interesting.
|
||||
|
||||
@verbatim
|
||||
InternetStackHelper stack;
|
||||
stack.Install (nodes);
|
||||
|
||||
Ipv4AddressHelper address;
|
||||
address.SetBase (``10.1.1.0'', ``255.255.255.252'');
|
||||
Ipv4InterfaceContainer interfaces = address.Assign (devices);
|
||||
@end verbatim
|
||||
|
||||
The above code should be familiar. It installs internet stacks on our two
|
||||
nodes and creates interfaces and assigns IP addresses for the point-to-point
|
||||
devices.
|
||||
|
||||
Since we are using TCP, we need something on the destination node to receive
|
||||
TCP connections and data. The @code{PacketSink} @code{Application} is commonly
|
||||
used in @command{ns-3} for that purpose.
|
||||
|
||||
@verbatim
|
||||
uint16_t sinkPort = 8080;
|
||||
Address sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
|
||||
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
|
||||
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
|
||||
sinkApps.Start (Seconds (0.));
|
||||
sinkApps.Stop (Seconds (20.));
|
||||
@end verbatim
|
||||
|
||||
This should all be familiar, with the exception of,
|
||||
|
||||
@verbatim
|
||||
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
|
||||
@end verbatim
|
||||
|
||||
This code instantiates a @code{PacketSinkHelper} and tells it to create sockets
|
||||
using the class @code{ns3::TcpSocketFactory}. This class implements a design
|
||||
pattern called ``object factory'' which is a commonly used mechanism for
|
||||
specifying a class used to create objects in an abstract way. Here, instead of
|
||||
having to create the objects themselves, you provide the @code{ PacketSinkHelper}
|
||||
a string that specifies a @code{TypeId} string used to create an object which
|
||||
can then be used, in turn, to create instances of the Objects created by the
|
||||
factory.
|
||||
|
||||
The remaining parameter tells the @code{Application} which address and port it
|
||||
should @code{Bind} to.
|
||||
|
||||
The next two lines of code will create the socket and connect the trace source.
|
||||
|
||||
@verbatim
|
||||
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0),
|
||||
TcpSocketFactory::GetTypeId ());
|
||||
ns3TcpSocket->TraceConnectWithoutContext (``CongestionWindow'',
|
||||
MakeCallback (&CwndChange));
|
||||
@end verbatim
|
||||
|
||||
The first statement calls the static member function @code{Socket::CreateSocket}
|
||||
and provides a @code{Node} and an explicit @code{TypeId} for the object factory
|
||||
used to create the socket. This is a slightly lower level call than the
|
||||
@code{PacketSinkHelper} call above, and uses an explicit C++ type instead of
|
||||
one referred to by a string. Otherwise, it is conceptually the same thing.
|
||||
|
||||
Once the @code{TcpSocket} is created and attached to the @code{Node}, we can
|
||||
use @code{TraceConnectWithoutContext} to connect the CongestionWindow trace
|
||||
source to our trace sink.
|
||||
|
||||
Recall that we coded an @code{Application} so we could take that @code{Socket}
|
||||
we just made (during configuration time) and use it in simulation time. We now
|
||||
have to instantiate that @code{Application}. We didn't go to any trouble to
|
||||
create a helper to manage the @code{Application} so we are going to have to
|
||||
create and install it ``manually.'' This is actually quite easy:
|
||||
|
||||
@verbatim
|
||||
Ptr<MyApp> app = CreateObject<MyApp> ();
|
||||
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
|
||||
nodes.Get (0)->AddApplication (app);
|
||||
app->Start (Seconds (1.));
|
||||
app->Stop (Seconds (20.));
|
||||
@end verbatim
|
||||
|
||||
The first line creates an @code{Object} of type @code{MyApp} -- our
|
||||
@code{Application}. The second line tells the @code{Application} what
|
||||
@code{Socket} to use, what address to connect to, how much data to send
|
||||
at each send event, how many send events to generate and the rate at which
|
||||
to produce data from those events.
|
||||
|
||||
Next, we manually add the @code{MyApp Application} to the source node
|
||||
and explicitly call the @code{Start} and @code{Stop} methods on the
|
||||
@code{Application} to tell it when to start and stop doing its thing.
|
||||
|
||||
We need to actually do the connect from the receiver point-to-point @code{NetDevice}
|
||||
to our callback now.
|
||||
|
||||
@verbatim
|
||||
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));
|
||||
@end verbatim
|
||||
|
||||
It should now be obvious that we are getting a reference to the receiving
|
||||
@code{Node NetDevice} from its container and connecting the trace source defined
|
||||
by the attribute ``PhyRxDrop'' on that device to the trace sink @code{RxDrop}.
|
||||
|
||||
Finally, we tell the simulator to override any @code{Applications} and just
|
||||
stop processing events at 20 seconds into the simulation.
|
||||
|
||||
@verbatim
|
||||
Simulator::Stop (Seconds(20));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Recall that as soon as @code{Simulator::Run} is called, configuration time
|
||||
ends, and simulation time begins. All of the work we orchestrated by
|
||||
creating the @code{Application} and teaching it how to connect and send
|
||||
data actually happens during this function call.
|
||||
|
||||
As soon as @code{Simulator::Run} returns, the simulation is complete and
|
||||
we enter the teardown phase. In this case, @code{Simulator::Destroy} takes
|
||||
care of the gory details and we just return a success code after it completes.
|
||||
|
||||
@subsection Running fifth.cc
|
||||
|
||||
Since we have provided the file @code{fifth.cc} for you, if you have built
|
||||
your distribution (in debug mode since it uses NS_LOG -- recall that optimized
|
||||
builds optimize out NS_LOGs) it will be waiting for you to run.
|
||||
|
||||
@verbatim
|
||||
./waf --run fifth
|
||||
Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
|
||||
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
|
||||
'build' finished successfully (0.525s)
|
||||
1.21397 1072
|
||||
1.22755 1608
|
||||
1.24114 2144
|
||||
...
|
||||
1.35211 8576
|
||||
1.36136 9112
|
||||
1.37061 9648
|
||||
RxDrop at 1.3729
|
||||
...
|
||||
@end verbatim
|
||||
|
||||
You can probably see immediately a downside of using prints of any kind in your
|
||||
traces. We get those extraneous waf messages printed all over our interesting
|
||||
information along with those RxDrop messages. We will remedy that soon, but I'm
|
||||
sure you can't wait to see the results of all of this work. Let's redirect that
|
||||
output to a file called @code{cwnd.dat}:
|
||||
|
||||
@verbatim
|
||||
./waf --run fifth > cwnd.dat 2>&1
|
||||
@end verbatim
|
||||
|
||||
Now edit up ``cwnd.dat'' in your favorite editor and remove the waf build status
|
||||
and drop lines, leaving only the traced data (you could also comment out the
|
||||
@code{TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));} in the
|
||||
script to get rid of the drop prints just as easily.
|
||||
|
||||
You can now run gnuplot (if you have it installed) and tell it to generate some
|
||||
pretty pictures:
|
||||
|
||||
@verbatim
|
||||
gnuplot> set terminal png size 1024,768
|
||||
gnuplot> set output "cwnd.png"
|
||||
gnuplot> plot "cwnd.dat" using 1:2 title 'Congestion Window' with linespoints
|
||||
gnuplot> exit
|
||||
@end verbatim
|
||||
|
||||
You should now have a graph of the congestion window versus time sitting in the
|
||||
file ``cwnd.png'' in all of its glory, that looks like:
|
||||
|
||||
@sp 1
|
||||
@center @image{figures/cwnd,,,,png}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/common-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
|
||||
|
||||
// ===========================================================================
|
||||
//
|
||||
// node 0 node 1
|
||||
// +----------------+ +----------------+
|
||||
// | ns-3 TCP | | ns-3 TCP |
|
||||
// +----------------+ +----------------+
|
||||
// | 10.1.1.1 | | 10.1.1.2 |
|
||||
// +----------------+ +----------------+
|
||||
// | point-to-point | | point-to-point |
|
||||
// +----------------+ +----------------+
|
||||
// | |
|
||||
// +---------------------+
|
||||
// 5 Mbps, 2 ms
|
||||
//
|
||||
//
|
||||
// We want to look at changes in the ns-3 TCP congestion window. We need
|
||||
// to crank up a flow and hook the CongestionWindow attribute on the socket
|
||||
// of the sender. Normally one would use an on-off application to generate a
|
||||
// flow, but this has a couple of problems. First, the socket of the on-off
|
||||
// application is not created until Application Start time, so we wouldn't be
|
||||
// able to hook the socket (now) at configuration time. Second, even if we
|
||||
// could arrange a call after start time, the socket is not public so we
|
||||
// couldn't get at it.
|
||||
//
|
||||
// So, we can cook up a simple version of the on-off application that does what
|
||||
// we want. On the plus side we don't need all of the complexity of the on-off
|
||||
// application. On the minus side, we don't have a helper, so we have to get
|
||||
// a little more involved in the details, but this is trivial.
|
||||
//
|
||||
// So first, we create a socket and do the trace connect on it; then we pass
|
||||
// this socket into the constructor of our simple application which we then
|
||||
// install in the source node.
|
||||
// ===========================================================================
|
||||
//
|
||||
class MyApp : public Application
|
||||
{
|
||||
public:
|
||||
|
||||
MyApp ();
|
||||
virtual ~MyApp();
|
||||
|
||||
void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
|
||||
|
||||
private:
|
||||
virtual void StartApplication (void);
|
||||
virtual void StopApplication (void);
|
||||
|
||||
void ScheduleTx (void);
|
||||
void SendPacket (void);
|
||||
|
||||
Ptr<Socket> m_socket;
|
||||
Address m_peer;
|
||||
uint32_t m_packetSize;
|
||||
uint32_t m_nPackets;
|
||||
DataRate m_dataRate;
|
||||
EventId m_sendEvent;
|
||||
bool m_running;
|
||||
uint32_t m_packetsSent;
|
||||
};
|
||||
|
||||
MyApp::MyApp ()
|
||||
: m_socket (0),
|
||||
m_peer (),
|
||||
m_packetSize (0),
|
||||
m_nPackets (0),
|
||||
m_dataRate (0),
|
||||
m_sendEvent (),
|
||||
m_running (false),
|
||||
m_packetsSent (0)
|
||||
{
|
||||
}
|
||||
|
||||
MyApp::~MyApp()
|
||||
{
|
||||
m_socket = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
|
||||
{
|
||||
m_socket = socket;
|
||||
m_peer = address;
|
||||
m_packetSize = packetSize;
|
||||
m_nPackets = nPackets;
|
||||
m_dataRate = dataRate;
|
||||
}
|
||||
|
||||
void
|
||||
MyApp::StartApplication (void)
|
||||
{
|
||||
m_running = true;
|
||||
m_packetsSent = 0;
|
||||
m_socket->Bind ();
|
||||
m_socket->Connect (m_peer);
|
||||
SendPacket ();
|
||||
}
|
||||
|
||||
void
|
||||
MyApp::StopApplication (void)
|
||||
{
|
||||
m_running = false;
|
||||
|
||||
if (m_sendEvent.IsRunning ())
|
||||
{
|
||||
Simulator::Cancel (m_sendEvent);
|
||||
}
|
||||
|
||||
if (m_socket)
|
||||
{
|
||||
m_socket->Close ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MyApp::SendPacket (void)
|
||||
{
|
||||
Ptr<Packet> packet = Create<Packet> (m_packetSize);
|
||||
m_socket->Send (packet);
|
||||
|
||||
if (++m_packetsSent < m_nPackets)
|
||||
{
|
||||
ScheduleTx ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MyApp::ScheduleTx (void)
|
||||
{
|
||||
if (m_running)
|
||||
{
|
||||
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
|
||||
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
|
||||
{
|
||||
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
|
||||
}
|
||||
|
||||
static void
|
||||
RxDrop (Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
NodeContainer nodes;
|
||||
nodes.Create (2);
|
||||
|
||||
PointToPointHelper pointToPoint;
|
||||
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("1Mbps"));
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
|
||||
|
||||
NetDeviceContainer devices;
|
||||
devices = pointToPoint.Install (nodes);
|
||||
|
||||
Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> (
|
||||
"RanVar", RandomVariableValue (UniformVariable (0., 1.)),
|
||||
"ErrorRate", DoubleValue (0.00001));
|
||||
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
|
||||
|
||||
InternetStackHelper stack;
|
||||
stack.Install (nodes);
|
||||
|
||||
Ipv4AddressHelper address;
|
||||
address.SetBase ("10.1.1.0", "255.255.255.252");
|
||||
Ipv4InterfaceContainer interfaces = address.Assign (devices);
|
||||
|
||||
uint16_t sinkPort = 8080;
|
||||
Address sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
|
||||
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
|
||||
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
|
||||
sinkApps.Start (Seconds (0.));
|
||||
sinkApps.Stop (Seconds (20.));
|
||||
|
||||
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ());
|
||||
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndChange));
|
||||
|
||||
Ptr<MyApp> app = CreateObject<MyApp> ();
|
||||
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("5Mbps"));
|
||||
nodes.Get (0)->AddApplication (app);
|
||||
app->Start (Seconds (1.));
|
||||
app->Stop (Seconds (20.));
|
||||
|
||||
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));
|
||||
|
||||
Simulator::Stop (Seconds(20));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -15,3 +15,6 @@ def build(bld):
|
||||
|
||||
obj = bld.create_ns3_program('fourth', ['core'])
|
||||
obj.source = 'fourth.cc'
|
||||
|
||||
obj = bld.create_ns3_program('fifth', ['core', 'simulator', 'point-to-point', 'internet-stack'])
|
||||
obj.source = 'fifth.cc'
|
||||
|
||||
@@ -184,6 +184,7 @@ HwmpProtocol::HwmpProtocol ():
|
||||
m_doFlag (false),
|
||||
m_rfFlag (false)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
if (m_isRoot)
|
||||
{
|
||||
@@ -193,11 +194,13 @@ HwmpProtocol::HwmpProtocol ():
|
||||
|
||||
HwmpProtocol::~HwmpProtocol ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
void
|
||||
HwmpProtocol::DoDispose ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
for (std::map<Mac48Address, EventId>::iterator i = m_preqTimeouts.begin (); i != m_preqTimeouts.end (); i ++)
|
||||
{
|
||||
i->second.Cancel ();
|
||||
@@ -206,8 +209,10 @@ HwmpProtocol::DoDispose ()
|
||||
m_preqTimeouts.clear ();
|
||||
m_lastDataSeqno.clear ();
|
||||
m_lastHwmpSeqno.clear ();
|
||||
m_interfaces.clear ();
|
||||
m_rqueue.clear ();
|
||||
m_rtable = 0;
|
||||
m_mp = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -118,19 +118,11 @@ IeBeaconTiming::DelNeighboursTimingElementUnit (uint16_t aid, Time last_beacon,
|
||||
void
|
||||
IeBeaconTiming::ClearTimingElement ()
|
||||
{
|
||||
uint16_t to_delete = 0;
|
||||
uint16_t i;
|
||||
for (NeighboursTimingUnitsList::iterator j = m_neighbours.begin (); j != m_neighbours.end (); j++)
|
||||
{
|
||||
to_delete++;
|
||||
(*j) = 0;
|
||||
}
|
||||
for (i = 0; i < to_delete; i++)
|
||||
{
|
||||
m_neighbours.pop_back ();
|
||||
}
|
||||
m_neighbours.clear ();
|
||||
|
||||
}
|
||||
uint8_t
|
||||
IeBeaconTiming::GetInformationSize () const
|
||||
|
||||
@@ -373,16 +373,11 @@ IePreq::DelDestinationAddressElement (Mac48Address dest_address)
|
||||
void
|
||||
IePreq::ClearDestinationAddressElements ()
|
||||
{
|
||||
int i;
|
||||
for (std::vector<Ptr<DestinationAddressUnit> >::iterator j = m_destinations.begin (); j
|
||||
!= m_destinations.end (); j++)
|
||||
{
|
||||
(*j) = 0;
|
||||
}
|
||||
for (i = 0; i < m_destCount; i++)
|
||||
{
|
||||
m_destinations.pop_back ();
|
||||
}
|
||||
m_destinations.clear ();
|
||||
m_destCount = 0;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@ PeerManagementProtocol::DoDispose ()
|
||||
i->second.clear ();
|
||||
}
|
||||
m_neighbourBeacons.clear ();
|
||||
|
||||
m_plugins.clear ();
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -73,6 +73,9 @@ MeshPointDevice::DoDispose ()
|
||||
*iter = 0;
|
||||
}
|
||||
m_ifaces.clear ();
|
||||
m_node = 0;
|
||||
m_channel = 0;
|
||||
m_routingProtocol = 0;
|
||||
NetDevice::DoDispose ();
|
||||
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
#include "ns3/wifi-mac-header.h"
|
||||
#include "ns3/wifi-information-element-vector.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
|
||||
@@ -282,8 +282,10 @@ MeshWifiInterfaceMac::DoDispose ()
|
||||
m_rxMiddle = 0;
|
||||
m_low = 0;
|
||||
m_dcfManager = 0;
|
||||
m_stationManager = 0;
|
||||
m_phy = 0;
|
||||
m_queues.clear ();
|
||||
m_plugins.clear ();
|
||||
m_beaconSendEvent.Cancel ();
|
||||
m_beaconDca = 0;
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ WifiInformationElementVector::GetSerializedSize () const
|
||||
void
|
||||
WifiInformationElementVector::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
for(std::vector<Ptr<WifiInformationElement> >::const_iterator i = m_elements.begin (); i != m_elements.end (); i ++)
|
||||
for(IE_VECTOR::const_iterator i = m_elements.begin (); i != m_elements.end (); i ++)
|
||||
{
|
||||
start.WriteU8((*i)->ElementId ());
|
||||
start.WriteU8 ((*i)->GetInformationSize ());
|
||||
|
||||
@@ -611,7 +611,7 @@ InterferenceHelper::EraseEvents (void)
|
||||
{
|
||||
*i = 0;
|
||||
}
|
||||
m_events.erase (m_events.begin (), m_events.end ());
|
||||
m_events.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("WifiNetDevice");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -65,13 +68,18 @@ WifiNetDevice::GetTypeId (void)
|
||||
WifiNetDevice::WifiNetDevice ()
|
||||
: m_mtu (0),
|
||||
m_configComplete (false)
|
||||
{}
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
WifiNetDevice::~WifiNetDevice ()
|
||||
{}
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
void
|
||||
WifiNetDevice::DoDispose (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_node = 0;
|
||||
m_mac->Dispose ();
|
||||
m_phy->Dispose ();
|
||||
|
||||
@@ -56,6 +56,7 @@ YansWifiChannel::YansWifiChannel ()
|
||||
{}
|
||||
YansWifiChannel::~YansWifiChannel ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_phyList.clear ();
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,8 @@ YansWifiPhy::DoDispose (void)
|
||||
m_channel = 0;
|
||||
m_modes.clear ();
|
||||
m_device = 0;
|
||||
m_mobility = 0;
|
||||
m_state = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -73,8 +73,9 @@ Dot11sStack::InstallStack (Ptr<MeshPointDevice> mp)
|
||||
hwmp->SetRoot ();
|
||||
}
|
||||
//Install interaction between HWMP and Peer management protocol:
|
||||
pmp->SetPeerLinkStatusCallback (MakeCallback (&HwmpProtocol::PeerLinkStatus, hwmp));
|
||||
hwmp->SetNeighboursCallback (MakeCallback (&PeerManagementProtocol::GetActiveLinks, pmp));
|
||||
//PeekPointer()'s to avoid circular Ptr references
|
||||
pmp->SetPeerLinkStatusCallback (MakeCallback (&HwmpProtocol::PeerLinkStatus, PeekPointer (hwmp)));
|
||||
hwmp->SetNeighboursCallback (MakeCallback (&PeerManagementProtocol::GetActiveLinks, PeekPointer (pmp)));
|
||||
return true;
|
||||
}
|
||||
void
|
||||
|
||||
@@ -45,6 +45,8 @@ TypeId NetDevice::GetTypeId (void)
|
||||
}
|
||||
|
||||
NetDevice::~NetDevice ()
|
||||
{}
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -148,6 +148,7 @@ Node::GetNApplications (void) const
|
||||
void
|
||||
Node::DoDispose()
|
||||
{
|
||||
m_handlers.clear ();
|
||||
for (std::vector<Ptr<NetDevice> >::iterator i = m_devices.begin ();
|
||||
i != m_devices.end (); i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user