merge with ns3-dev
This commit is contained in:
@@ -479,34 +479,34 @@ def register_Ns3Names_methods(root_module, cls):
|
||||
cls.add_constructor([param('ns3::Names const &', 'arg0')])
|
||||
## names.h: ns3::Names::Names() [constructor]
|
||||
cls.add_constructor([])
|
||||
## names.h: static bool ns3::Names::Add(std::string name, ns3::Ptr<ns3::Object> obj) [member function]
|
||||
## names.h: static void ns3::Names::Add(std::string name, ns3::Ptr<ns3::Object> obj) [member function]
|
||||
cls.add_method('Add',
|
||||
'bool',
|
||||
'void',
|
||||
[param('std::string', 'name'), param('ns3::Ptr< ns3::Object >', 'obj')],
|
||||
is_static=True)
|
||||
## names.h: static bool ns3::Names::Add(std::string path, std::string name, ns3::Ptr<ns3::Object> object) [member function]
|
||||
## names.h: static void ns3::Names::Add(std::string path, std::string name, ns3::Ptr<ns3::Object> object) [member function]
|
||||
cls.add_method('Add',
|
||||
'bool',
|
||||
'void',
|
||||
[param('std::string', 'path'), param('std::string', 'name'), param('ns3::Ptr< ns3::Object >', 'object')],
|
||||
is_static=True)
|
||||
## names.h: static bool ns3::Names::Add(ns3::Ptr<ns3::Object> context, std::string name, ns3::Ptr<ns3::Object> object) [member function]
|
||||
## names.h: static void ns3::Names::Add(ns3::Ptr<ns3::Object> context, std::string name, ns3::Ptr<ns3::Object> object) [member function]
|
||||
cls.add_method('Add',
|
||||
'bool',
|
||||
'void',
|
||||
[param('ns3::Ptr< ns3::Object >', 'context'), param('std::string', 'name'), param('ns3::Ptr< ns3::Object >', 'object')],
|
||||
is_static=True)
|
||||
## names.h: static bool ns3::Names::Rename(std::string oldpath, std::string newname) [member function]
|
||||
## names.h: static void ns3::Names::Rename(std::string oldpath, std::string newname) [member function]
|
||||
cls.add_method('Rename',
|
||||
'bool',
|
||||
'void',
|
||||
[param('std::string', 'oldpath'), param('std::string', 'newname')],
|
||||
is_static=True)
|
||||
## names.h: static bool ns3::Names::Rename(std::string path, std::string oldname, std::string newname) [member function]
|
||||
## names.h: static void ns3::Names::Rename(std::string path, std::string oldname, std::string newname) [member function]
|
||||
cls.add_method('Rename',
|
||||
'bool',
|
||||
'void',
|
||||
[param('std::string', 'path'), param('std::string', 'oldname'), param('std::string', 'newname')],
|
||||
is_static=True)
|
||||
## names.h: static bool ns3::Names::Rename(ns3::Ptr<ns3::Object> context, std::string oldname, std::string newname) [member function]
|
||||
## names.h: static void ns3::Names::Rename(ns3::Ptr<ns3::Object> context, std::string oldname, std::string newname) [member function]
|
||||
cls.add_method('Rename',
|
||||
'bool',
|
||||
'void',
|
||||
[param('ns3::Ptr< ns3::Object >', 'context'), param('std::string', 'oldname'), param('std::string', 'newname')],
|
||||
is_static=True)
|
||||
## names.h: static std::string ns3::Names::FindName(ns3::Ptr<ns3::Object> object) [member function]
|
||||
|
||||
@@ -946,6 +946,8 @@ def register_Ns3StaticMulticastRouteHelper_methods(root_module, cls):
|
||||
def register_Ns3TapBridgeHelper_methods(root_module, cls):
|
||||
## tap-bridge-helper.h: ns3::TapBridgeHelper::TapBridgeHelper(ns3::TapBridgeHelper const & arg0) [copy constructor]
|
||||
cls.add_constructor([param('ns3::TapBridgeHelper const &', 'arg0')])
|
||||
## tap-bridge-helper.h: ns3::TapBridgeHelper::TapBridgeHelper() [constructor]
|
||||
cls.add_constructor([])
|
||||
## tap-bridge-helper.h: ns3::TapBridgeHelper::TapBridgeHelper(ns3::Ipv4Address gateway) [constructor]
|
||||
cls.add_constructor([param('ns3::Ipv4Address', 'gateway')])
|
||||
## tap-bridge-helper.h: void ns3::TapBridgeHelper::SetAttribute(std::string n1, ns3::AttributeValue const & v1) [member function]
|
||||
@@ -968,6 +970,10 @@ def register_Ns3TapBridgeHelper_methods(root_module, cls):
|
||||
cls.add_method('Install',
|
||||
'ns3::Ptr< ns3::NetDevice >',
|
||||
[param('std::string', 'nodeName'), param('std::string', 'ndName')])
|
||||
## tap-bridge-helper.h: ns3::Ptr<ns3::NetDevice> ns3::TapBridgeHelper::Install(ns3::Ptr<ns3::Node> node, ns3::Ptr<ns3::NetDevice> nd, ns3::AttributeValue const & v1) [member function]
|
||||
cls.add_method('Install',
|
||||
'ns3::Ptr< ns3::NetDevice >',
|
||||
[param('ns3::Ptr< ns3::Node >', 'node'), param('ns3::Ptr< ns3::NetDevice >', 'nd'), param('ns3::AttributeValue const &', 'v1')])
|
||||
return
|
||||
|
||||
def register_Ns3UdpEchoClientHelper_methods(root_module, cls):
|
||||
|
||||
@@ -5,6 +5,8 @@ def register_types(module):
|
||||
|
||||
## tap-bridge.h: ns3::TapBridge [class]
|
||||
module.add_class('TapBridge', parent=root_module['ns3::NetDevice'])
|
||||
## tap-bridge.h: ns3::TapBridge::Mode [enumeration]
|
||||
module.add_enum('Mode', ['ILLEGAL', 'CONFIGURE_LOCAL', 'USE_LOCAL', 'USE_BRIDGE'], outer_class=root_module['ns3::TapBridge'])
|
||||
|
||||
## Register a nested module for the namespace Config
|
||||
|
||||
@@ -76,6 +78,14 @@ def register_Ns3TapBridge_methods(root_module, cls):
|
||||
cls.add_method('Stop',
|
||||
'void',
|
||||
[param('ns3::Time', 'tStop')])
|
||||
## tap-bridge.h: void ns3::TapBridge::SetMode(ns3::TapBridge::Mode mode) [member function]
|
||||
cls.add_method('SetMode',
|
||||
'void',
|
||||
[param('ns3::TapBridge::Mode', 'mode')])
|
||||
## tap-bridge.h: ns3::TapBridge::Mode ns3::TapBridge::GetMode() [member function]
|
||||
cls.add_method('GetMode',
|
||||
'ns3::TapBridge::Mode',
|
||||
[])
|
||||
## tap-bridge.h: void ns3::TapBridge::SetName(std::string const name) [member function]
|
||||
cls.add_method('SetName',
|
||||
'void',
|
||||
|
||||
@@ -145,6 +145,7 @@ def main():
|
||||
if 'TapBridge' not in enabled_features:
|
||||
for clsname in ['TapBridge', 'TapBridgeHelper']:
|
||||
root_module.classes.remove(root_module['ns3::%s' % clsname])
|
||||
root_module.enums.remove(root_module['ns3::TapBridge::Mode'])
|
||||
|
||||
root_module.generate(out, '_ns3')
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -362,21 +362,6 @@ enable on each component. These two lines of code enable debug logging at the
|
||||
INFO level for echo clients and servers. This will result in the application
|
||||
printing out messages as packets are sent and received during the simulation.
|
||||
|
||||
The next line of code is used to give a fixed seed to the random number
|
||||
generators so that they will generate repeatable results. In the example
|
||||
programs, it allows us to thouroughly document the output of the trace files
|
||||
in a consistent way. Having a fixed seed also allows us to use the examples
|
||||
in our regression testing framework.
|
||||
|
||||
@verbatim
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
@end verbatim
|
||||
|
||||
Random variables are very important in understanding how to get repeatable
|
||||
results, so you are encouraged to read the Doxygen and manual sections to
|
||||
understand what is going on there. For us, the main concern is in making
|
||||
random backoff algorithms consistent across runs.
|
||||
|
||||
Now we will get directly to the business of creating a topology and running
|
||||
a simulation. We use the topology helper objects to make this job as
|
||||
easy as possible.
|
||||
@@ -439,7 +424,7 @@ The next three lines in the script are,
|
||||
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
|
||||
@end verbatim
|
||||
|
||||
The first line
|
||||
The first line,
|
||||
|
||||
@verbatim
|
||||
PointToPointHelper pointToPoint;
|
||||
@@ -461,12 +446,12 @@ to what we call an @code{Attribute} of the @code{PointToPointNetDevice}.
|
||||
If you look at the Doxygen for class @code{ns3::PointToPointNetDevice} and
|
||||
find the documentation for the @code{GetTypeId} method, you will find a list
|
||||
of @code{Attributes} defined for the device. Among these is the ``DataRate''
|
||||
attribute. Most user-visible @command{ns-3} objects have similar lists of
|
||||
attributes. We use this mechanism to easily configure simulations without
|
||||
@code{Attribute}. Most user-visible @command{ns-3} objects have similar lists of
|
||||
@code{Attributes}. We use this mechanism to easily configure simulations without
|
||||
recompiling as you will see in a following section.
|
||||
|
||||
Similar to the ``DataRate'' on the @code{PointToPointNetDevice} you will find a
|
||||
``Delay'' attribute associated with the @code{PointToPointChannel}. The
|
||||
``Delay'' @code{Attribute} associated with the @code{PointToPointChannel}. The
|
||||
final line,
|
||||
|
||||
@verbatim
|
||||
@@ -502,8 +487,9 @@ is created. For each node in the @code{NodeContainer} (there must be exactly
|
||||
two for a point-to-point link) a @code{PointToPointNetDevice} is created and
|
||||
saved in the device container. A @code{PointToPointChannel} is created and
|
||||
the two @code{PointToPointNetDevices} are attached. When objects are created
|
||||
by the @code{PointToPointHelper}, the attributes previously set in the helper
|
||||
are used to initialize the corresponding attributes in the created objects.
|
||||
by the @code{PointToPointHelper}, the @code{Attributes} previously set in the
|
||||
helper are used to initialize the corresponding @code{Attributes} in the
|
||||
created objects.
|
||||
|
||||
After executing the @code{pointToPoint.Install (nodes)} call we will have
|
||||
two nodes, each with an installed point-to-point net device and a
|
||||
@@ -590,13 +576,13 @@ created.
|
||||
The first line of code in the above snippet declares the
|
||||
@code{UdpEchoServerHelper}. As usual, this isn't the application itself, it
|
||||
is an object used to help us create the actual applications. One of our
|
||||
conventions is to place required attributes in the helper constructor. In this
|
||||
case, the helper can't do anything useful unless it is provided with a port
|
||||
number that the client also knows about. Rather than just picking one and
|
||||
hoping it all works out, we require the port number as a parameter to the
|
||||
conventions is to place required @code{Attributes} in the helper constructor.
|
||||
In this case, the helper can't do anything useful unless it is provided with
|
||||
a port number that the client also knows about. Rather than just picking one
|
||||
and hoping it all works out, we require the port number as a parameter to the
|
||||
constructor. The constructor, in turn, simply does a @code{SetAttribute}
|
||||
with the passed value. You can, if desired, set the ``Port'' attribute to
|
||||
another value later.
|
||||
with the passed value. You can, if desired, set the ``Port'' @code{Attribute}
|
||||
to another value later.
|
||||
|
||||
Similar to many other helper objects, the @code{UdpEchoServerHelper} object
|
||||
has an @code{Install} method. It is the execution of this method that actually
|
||||
@@ -649,12 +635,12 @@ that is managed by an @code{UdpEchoClientHelper}.
|
||||
clientApps.Stop (Seconds (10.0));
|
||||
@end verbatim
|
||||
|
||||
For the echo client, however, we need to set five different attributes. The
|
||||
first two attributes are set during construction of the
|
||||
For the echo client, however, we need to set five different @code{Attributes}.
|
||||
The first two @code{Attributes} are set during construction of the
|
||||
@code{UdpEchoClientHelper}. We pass parameters that are used (internally to
|
||||
the helper) to set the ``RemoteAddress'' and ``RemotePort'' attributes in
|
||||
accordance with our convention to make required attributes parameters in the
|
||||
helper constructors.
|
||||
the helper) to set the ``RemoteAddress'' and ``RemotePort'' @code{Attributes}
|
||||
in accordance with our convention to make required @code{Attributes} parameters
|
||||
in the helper constructors.
|
||||
|
||||
Recall that we used an @code{Ipv4InterfaceContainer} to keep track of the IP
|
||||
addresses we assigned to our devices. The zeroth interface in the
|
||||
@@ -666,12 +652,12 @@ are creating the helper and telling it so set the remote address of the client
|
||||
to be the IP address assigned to the node on which the server resides. We
|
||||
also tell it to arrange to send packets to port nine.
|
||||
|
||||
The ``MaxPackets'' attribute tells the client the maximum number of packets
|
||||
we allow it to send during the simulation. The ``Interval'' attribute tells
|
||||
the client how long to wait between packets, and the ``PacketSize'' attribute
|
||||
tells the client how large its packet payloads should be. With this
|
||||
particular combination of attributes, we are telling the client to send one
|
||||
1024-byte packet.
|
||||
The ``MaxPackets'' @code{Attribute} tells the client the maximum number of
|
||||
packets we allow it to send during the simulation. The ``Interval''
|
||||
@code{Attribute} tells the client how long to wait between packets, and the
|
||||
``PacketSize'' @code{Attribute} tells the client how large its packet payloads
|
||||
should be. With this particular combination of @code{Attributes}, we are
|
||||
telling the client to send one 1024-byte packet.
|
||||
|
||||
Just as in the case of the echo server, we tell the echo client to @code{Start}
|
||||
and @code{Stop}, but here we start the client one second after the server is
|
||||
@@ -738,34 +724,40 @@ built if you run Waf. Let's try it. Copy @code{examples/first.cc} into
|
||||
the @code{scratch} directory.
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > cp examples/first.cc scratch/
|
||||
~/repos/ns-3-dev > cp examples/first.cc scratch/myfirst.cc
|
||||
@end verbatim
|
||||
|
||||
and then build it using waf,
|
||||
Now build your first example script using waf:
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
[467/511] cxx: scratch/first.cc -> build/debug/scratch/first_1.o
|
||||
[468/511] cxx: scratch/multiple-sources/simple-main.cc -> build/debug/scratch/multiple-sources/simple-main_2.o
|
||||
[469/511] cxx: scratch/multiple-sources/simple-simulation.cc -> build/debug/scratch/multiple-sources/simple-simulation_2.o
|
||||
[470/511] cxx: scratch/simple.cc -> build/debug/scratch/simple_3.o
|
||||
[508/511] cxx_link: build/debug/scratch/first_1.o -> build/debug/scratch/first
|
||||
Compilation finished successfully
|
||||
~/repos/ns-3-dev >
|
||||
./waf
|
||||
@end verbatim
|
||||
|
||||
You should see messages reporting that your @code{myfirst} example was built
|
||||
successfully.
|
||||
|
||||
@verbatim
|
||||
Entering directory `repos/ns-3-allinone-dev/ns-3-dev/build'
|
||||
[563/648] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o
|
||||
[646/648] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst
|
||||
Build finished successfully (00:00:02)
|
||||
@end verbatim
|
||||
|
||||
You can now run the example (note that if you build your program in the scratch
|
||||
directory you must run it out of the scratch directory):
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
./waf --run scratch/myfirst
|
||||
@end verbatim
|
||||
|
||||
You should see some output:
|
||||
|
||||
@verbatim
|
||||
Entering directory `repos/ns-3-allinone-dev/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
Sent 1024 bytes to 10.1.1.2
|
||||
Received 1024 bytes from 10.1.1.1
|
||||
Received 1024 bytes from 10.1.1.2
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
Here you see that the build system checks to make sure that the file has been
|
||||
@@ -793,38 +785,42 @@ links, one can browse the source tree.
|
||||
|
||||
The top-level directory for one of our @emph{repositories} will look
|
||||
something like:
|
||||
|
||||
@verbatim
|
||||
drwxr-xr-x [up]
|
||||
drwxr-xr-x doc manifest
|
||||
drwxr-xr-x examples manifest
|
||||
drwxr-xr-x ns3 manifest
|
||||
drwxr-xr-x regression manifest
|
||||
drwxr-xr-x samples manifest
|
||||
drwxr-xr-x scratch manifest
|
||||
drwxr-xr-x src manifest
|
||||
drwxr-xr-x tutorial manifest
|
||||
drwxr-xr-x utils manifest
|
||||
-rw-r--r-- 135 .hgignore file | revisions | annotate
|
||||
-rw-r--r-- 891 .hgtags file | revisions | annotate
|
||||
-rw-r--r-- 441 AUTHORS file | revisions | annotate
|
||||
-rw-r--r-- 17987 LICENSE file | revisions | annotate
|
||||
-rw-r--r-- 4948 README file | revisions | annotate
|
||||
-rw-r--r-- 4917 RELEASE_NOTES file | revisions | annotate
|
||||
-rw-r--r-- 7 VERSION file | revisions | annotate
|
||||
-rwxr-xr-x 99143 waf file | revisions | annotate
|
||||
-rwxr-xr-x 28 waf.bat file | revisions | annotate
|
||||
-rw-r--r-- 30584 wscript file | revisions | annotate
|
||||
drwxr-xr-x [up]
|
||||
drwxr-xr-x bindings python files
|
||||
drwxr-xr-x doc files
|
||||
drwxr-xr-x examples files
|
||||
drwxr-xr-x ns3 files
|
||||
drwxr-xr-x regression files
|
||||
drwxr-xr-x samples files
|
||||
drwxr-xr-x scratch files
|
||||
drwxr-xr-x src files
|
||||
drwxr-xr-x utils files
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 505 .hgignore file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 1682 .hgtags file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 686 AUTHORS file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 14893 CHANGES.html file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 17987 LICENSE file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 3742 README file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 13505 RELEASE_NOTES file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 6 VERSION file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 9257 regression.py file | revisions | annotate
|
||||
-rwxr-xr-x 2009-03-24 00:51 -0700 81285 waf file | revisions | annotate
|
||||
-rwxr-xr-x 2009-03-24 00:51 -0700 28 waf.bat file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 26270 wscript file | revisions | annotate
|
||||
-rw-r--r-- 2009-03-24 00:51 -0700 6636 wutils.py file | revisions | annotate
|
||||
@end verbatim
|
||||
|
||||
The source code is mainly in the @code{src} directory. You can view source
|
||||
code by clicking on the @code{manifest} link to the right of the directory
|
||||
name. If you click on the @code{manifest} link to the right of the src
|
||||
directory you will find a subdirectory. If you click on the @code{manifest}
|
||||
link next to the @code{core} subdirectory in under @code{src}, you will find
|
||||
a list of files. The first file you will find is @code{assert.h}. If you
|
||||
click on the @code{file} link, you will be sent to the source file for
|
||||
@code{assert.h}.
|
||||
code either by clicking on the directory name or by clicking on the @code{files}
|
||||
link to the right of the directory name. If you click on the @code{src}
|
||||
directory you be taken to the lising of the @code{src} subdirectories. If you
|
||||
click on @code{core} subdirectory, you will find a list of files. The first file
|
||||
you will find (as of this writing) is @code{abort.h}. If you
|
||||
click on @code{abort.h} link, you will be sent to the source file for @code{abort.h}.
|
||||
|
||||
Our example scripts are in the @code{examples} directory. The source code for
|
||||
the helpers we have used in this chapter can be found in the
|
||||
@code{src/helpers} directory.
|
||||
@code{src/helpers} directory. Feel free to poke around in the directory tree to
|
||||
get a feel for what is there and the style of @command{ns-3} programs.
|
||||
|
||||
@@ -44,78 +44,229 @@ the Getting Started section of the @command{ns-3} web site:
|
||||
|
||||
@cindex tarball
|
||||
The @command{ns-3} code is available in Mercurial repositories on the server
|
||||
code.nsnam.org. You can download a tarball release at
|
||||
code.nsnam.org. You can also download a tarball release at
|
||||
@uref{http://www.nsnam.org/releases/}, or you can work with repositories
|
||||
using Mercurial.
|
||||
using Mercurial. We recommend using Mercurial unless there's a good reason
|
||||
not to. See the end of this section for instructions on how to get a tarball
|
||||
release.
|
||||
|
||||
@cindex repository
|
||||
If you go to the following link: @uref{http://code.nsnam.org/},
|
||||
you will see a number of repositories. Many are the private repositories of
|
||||
the @command{ns-3} development team. The repositories of interest to you will
|
||||
be prefixed with ``ns-3''. The current development snapshot (unreleased)
|
||||
of @command{ns-3} may be found at: @uref{http://code.nsnam.org/ns-3-dev/}.
|
||||
Official releases of @command{ns-3} will be numbered as @code{ns-3.<release>}
|
||||
with any required hotfixes added as minor release numbers. For example, a
|
||||
second hotfix to a hypothetical release nine of @command{ns-3} would be
|
||||
numbered @code{ns-3.9.2}.
|
||||
|
||||
The current development snapshot (unreleased) of @command{ns-3} may be found
|
||||
at: @uref{http://code.nsnam.org/ns-3-dev/}. The developers attempt to keep
|
||||
this repository in a consistent, working state but it is a development area
|
||||
with unreleased code present, so you may want to consider staying with an
|
||||
official release if you do not need newly-introduced features.
|
||||
|
||||
Since the release numbers are going to be changing, I will stick with
|
||||
the more constant ns-3-dev here in the tutorial, but you can replace the
|
||||
string ``ns-3-dev'' with your choice of release (e.g., ns-3.2) in the text
|
||||
below. You can find the latest version of the code either by inspection of
|
||||
the repository list or by going to the ``Getting Started'' web page and
|
||||
looking for the latest release identifier.
|
||||
The simplest way to get started using Mercurial repositories is to use the
|
||||
@code{ns-3-allinone} environment. This is a set of scripts that manages the
|
||||
downloading and building of various subystems of @command{ns-3} for you. We
|
||||
recommend that you begin your @command{ns-3} adventures in this environment
|
||||
as it can really simplify your life at this point.
|
||||
|
||||
@subsection Downloading ns-3 Using Mercurial
|
||||
One practice is to create a directory called @code{repos} in one's home
|
||||
directory under which one can keep local Mercurial repositories.
|
||||
@emph{Hint: we will assume you do this later in the tutorial.} If you adopt
|
||||
that approach, you can get a copy of the development version of
|
||||
@command{ns-3} by typing the following into your Linux shell (assuming you
|
||||
have installed Mercurial):
|
||||
that approach, you can get a copy of @code{ns-3-allinone} by typing the
|
||||
following into your Linux shell (assuming you have installed Mercurial):
|
||||
|
||||
@verbatim
|
||||
cd
|
||||
mkdir repos
|
||||
cd repos
|
||||
hg clone http://code.nanam.org/ns-3-dev
|
||||
hg clone http://code.nsnam.org/ns-3-allinone
|
||||
@end verbatim
|
||||
|
||||
As the hg (Mercurial) command executes, you should see something like the
|
||||
following displayed,
|
||||
|
||||
@verbatim
|
||||
destination directory: ns-3-allinone
|
||||
requesting all changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 26 changesets with 40 changes to 7 files
|
||||
7 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
@end verbatim
|
||||
|
||||
After the clone command completes, you should have a directory called
|
||||
@code{ns-3-allinone} under your @code{~/repos} directory, the contents of which should
|
||||
look something like the following:
|
||||
|
||||
@verbatim
|
||||
build.py* constants.py dist.py* download.py* README util.py
|
||||
@end verbatim
|
||||
|
||||
Notice that you really just downloaded some Python scripts. The next step
|
||||
will be to use those scripts to download and build the @command{ns-3}
|
||||
distribution of your choice.
|
||||
|
||||
@cindex repository
|
||||
If you go to the following link: @uref{http://code.nsnam.org/},
|
||||
you will see a number of repositories. Many are the private repositories of
|
||||
the @command{ns-3} development team. The repositories of interest to you will
|
||||
be prefixed with ``ns-3''. Official releases of @command{ns-3} will be
|
||||
numbered as @code{ns-3.<release>.<hotfix>}. For example, a second hotfix to a
|
||||
still hypothetical release nine of @command{ns-3} would be numbered as
|
||||
@code{ns-3.9.2}.
|
||||
|
||||
We have had a regression testing framework in place since the first release.
|
||||
For each release, a set of output files that define ``good behavior'' are saved.
|
||||
These known good output files are called reference traces and are associated
|
||||
with a given release by name. For example, in @uref{http://code.nsnam.org/}
|
||||
you will find a repository named @code{ns-3.1} which is the first stable release
|
||||
of @command{ns-3}. You will also find a separate repository named
|
||||
@code{ns-3.1-ref-traces} that holds the reference traces for the @code{ns-3.1}
|
||||
release. It is crucial to keep these files consistent if you want to do any
|
||||
regression testing of your repository. This is a good idea to do at least once
|
||||
to verify everything has built correctly.
|
||||
|
||||
The current development snapshot (unreleased) of @command{ns-3} may be found
|
||||
at @uref{http://code.nsnam.org/ns-3-dev/} and the associated reference traces
|
||||
may be found at @uref{http://code.nsnam.org/ns-3-dev-ref-traces/}. The
|
||||
developers attempt to keep these repository in consistent, working states but
|
||||
they are in a development area with unreleased code present, so you may want
|
||||
to consider staying with an official release if you do not need newly-
|
||||
introduced features.
|
||||
|
||||
Since the release numbers are going to be changing, I will stick with
|
||||
the more constant ns-3-dev here in the tutorial, but you can replace the
|
||||
string ``ns-3-dev'' with your choice of release (e.g., ns-3.4 and
|
||||
ns-3.4-ref-traces) in the text below. You can find the latest version of the
|
||||
code either by inspection of the repository list or by going to the ``Getting
|
||||
Started'' web page and looking for the latest release identifier.
|
||||
|
||||
Go ahead and change into the @code{ns-3-allinone} directory you created when
|
||||
you cloned that repository. We are now going to use the @code{download.py}
|
||||
script to pull down the various pieces of @command{ns-3} you will be using/
|
||||
|
||||
Go ahead and type the following into your shell (remember you can substitute
|
||||
the name of your chosen release number instead of @code{ns-3-dev} -- like
|
||||
@code{"ns-3.4"} and @code{"ns-3.4-ref-traces"} if you want to work with a
|
||||
stable release).
|
||||
|
||||
@verbatim
|
||||
./download.py -n ns-3-dev -r ns-3-dev-ref-traces
|
||||
@end verbatim
|
||||
|
||||
As the hg (Mercurial) command executes, you should see something like the
|
||||
following,
|
||||
|
||||
@verbatim
|
||||
destination directory: ns-3-dev
|
||||
#
|
||||
# Get NS-3
|
||||
#
|
||||
|
||||
Cloning ns-3 branch
|
||||
=> hg clone http://code.nsnam.org/ns-3-dev ns-3-dev
|
||||
requesting all changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 3276 changesets with 12301 changes to 1353 files
|
||||
594 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
added 4292 changesets with 15368 changes to 1671 files
|
||||
823 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
@end verbatim
|
||||
|
||||
After the clone command completes, you should have a directory called
|
||||
ns-3-dev under your @code{~/repos} directory, the contents of which should
|
||||
look something like the following:
|
||||
This is output by the download script as it fetches the actual @code{ns-3}
|
||||
code from the repository. Next, you should see something like,
|
||||
|
||||
@verbatim
|
||||
AUTHORS examples/ README samples/ utils/ waf.bat*
|
||||
build/ LICENSE regression/ scratch/ VERSION wscript
|
||||
doc/ ns3/ RELEASE_NOTES src/ waf*
|
||||
#
|
||||
# Get the regression traces
|
||||
#
|
||||
|
||||
Synchronizing reference traces using Mercurial.
|
||||
=> hg clone http://code.nsnam.org/ns-3-dev-ref-traces ns-3-dev-ref-traces
|
||||
requesting all changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 79 changesets with 1102 changes to 222 files
|
||||
206 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
@end verbatim
|
||||
|
||||
Similarly, if working from a released version instead, you can simply
|
||||
This is the download script fetching the reference trace files for you.
|
||||
The download script is smart enough to know that on some platforms various
|
||||
pieces of ns-3 are not supported. On your platform you may not see some
|
||||
of these pieces come down. However, on most platforms, the process should
|
||||
continue with something like,
|
||||
|
||||
@verbatim
|
||||
#
|
||||
# Get PyBindGen
|
||||
#
|
||||
|
||||
Required pybindgen version: 0.10.0.630
|
||||
Trying to fetch pybindgen; this will fail if no network connection is available. Hit Ctrl-C to skip.
|
||||
=> bzr checkout -rrevno:630 https://launchpad.net/pybindgen pybindgen
|
||||
Fetch was successful.
|
||||
@end verbatim
|
||||
|
||||
This was the download script getting the Python bindings generator for you.
|
||||
Next you should see (modulo platform variations) something along the lines of,
|
||||
|
||||
@verbatim
|
||||
#
|
||||
# Get NSC
|
||||
#
|
||||
|
||||
Required NSC version: nsc-0.5.0
|
||||
Retrieving nsc from https://secure.wand.net.nz/mercurial/nsc
|
||||
=> hg clone https://secure.wand.net.nz/mercurial/nsc nsc
|
||||
requesting all changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 270 changesets with 17375 changes to 14991 files
|
||||
10614 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
@end verbatim
|
||||
|
||||
This part of the process is the script downloading the Network Simulation
|
||||
Cradle for you.
|
||||
|
||||
After the clone command completes, you should have several new directories
|
||||
under @code{~/repos/ns-3-allinone}:
|
||||
|
||||
@verbatim
|
||||
build.py* constants.pyc download.py* ns-3-dev-ref-traces/ pybindgen/ util.py
|
||||
constants.py dist.py* ns-3-dev/ nsc/ README util.pyc
|
||||
@end verbatim
|
||||
|
||||
Go ahead and change into @code{ns-3-dev} under your @code{~/repos/ns-3-allinone}
|
||||
directory. You should see something like the following there:
|
||||
|
||||
@verbatim
|
||||
AUTHORS examples/ regression/ scratch/ waf*
|
||||
bindings/ LICENSE regression.py src/ waf.bat*
|
||||
CHANGES.html ns3/ RELEASE_NOTES utils/ wscript
|
||||
doc/ README samples/ VERSION wutils.py
|
||||
@end verbatim
|
||||
|
||||
You are now ready to build the @command{ns-3} distribution.
|
||||
|
||||
@subsection Downloading ns-3 Using a Tarball
|
||||
The process for downloading @command{ns-3} via tarball is simpler than the
|
||||
Mercurial process since all of the pieces are pre-packaged for you. You just
|
||||
have to pick a release, download it and decompress it.
|
||||
|
||||
As mentioned above, one practice is to create a directory called @code{repos}
|
||||
in one's home directory under which one can keep local Mercurial repositories.
|
||||
One could also keep a @code{tarballs} directory. @emph{Hint: the tutorial
|
||||
will assume you downloaded into a @code{repos} directory, so remember the
|
||||
placekeeper.} If you adopt the @code{tarballs} directory approach, you can
|
||||
get a copy of a release by typing the following into your Linux shell
|
||||
(substitute the appropriate version numbers, of course):
|
||||
|
||||
@verbatim
|
||||
cd
|
||||
mkdir repos
|
||||
wget http://www.nsnam.org/releases/ns-3.2.tar.bz2
|
||||
bunzip2 ns-3.2.tar.bz2
|
||||
tar xvf ns-3.2.tar
|
||||
mkdir tarballs
|
||||
cd tarballs
|
||||
wget http://www.nsnam.org/releases/ns-allinone-3.4.tar.bz2
|
||||
bunzip2 ns-allinone-3.4.tar.bz2
|
||||
tar xf ns-3.4.tar
|
||||
@end verbatim
|
||||
|
||||
If you change into the directory @code{ns-allinone-3.4} you should see a
|
||||
number of files:
|
||||
|
||||
@verbatim
|
||||
build.py* ns-3.4-RC2/ nsc-0.5.0/ util.py
|
||||
constants.py ns-3.4-RC2-ref-traces/ pybindgen-0.10.0.630/
|
||||
@end verbatim
|
||||
|
||||
You are now ready to build the @command{ns-3} distribution.
|
||||
@@ -127,19 +278,61 @@ You are now ready to build the @command{ns-3} distribution.
|
||||
@node Building ns-3
|
||||
@section Building ns-3
|
||||
|
||||
@subsection Building with build.py
|
||||
@cindex building with build.py
|
||||
The first time you build the @command{ns-3} project you should build using the
|
||||
@command{allinone} environment. This will get the project configured for you
|
||||
in the most commonly useful way.
|
||||
|
||||
Change into the directory you created in the download section above. If you
|
||||
downloaded using Mercurial you should have a directory called
|
||||
@code{ns-3-allinone} under your @code{~/repos} directory. If you downloaded
|
||||
using a tarball you should have a directory called something like
|
||||
@code{ns-3-allinone-3.4} under your @code{~/tarballs} directory. Take a deep
|
||||
breath and type the following:
|
||||
|
||||
@verbatim
|
||||
./build.py
|
||||
@end verbatim
|
||||
|
||||
You will see lots of typical compiler output messages displayed as the build
|
||||
script builds the various pieces you downloaded. Eventually you should see the
|
||||
following magic words:
|
||||
|
||||
@verbatim
|
||||
Build finished successfully (00:02:37)
|
||||
Leaving directory `./ns-3-dev'
|
||||
@end verbatim
|
||||
|
||||
Once the project has built you can say goodbye to your old friends, the
|
||||
@code{ns-3-allinone} scripts. You got what you needed from them and will now
|
||||
interact directly with Waf and we do it in the @code{ns-3-dev} directory and
|
||||
not in the @code{ns-3-allinone} directory. Go ahead and change into the
|
||||
@code{ns-3-dev} directory (or the directory for the appropriate release you
|
||||
downloaded.
|
||||
|
||||
@verbatim
|
||||
cd ns-3-dev
|
||||
@end verbatim
|
||||
|
||||
@subsection Building with Waf
|
||||
@cindex building with Waf
|
||||
@cindex configuring Waf
|
||||
@cindex building debug version with Waf
|
||||
@cindex compiling with Waf
|
||||
@cindex unit tests with Waf
|
||||
@cindex regression tests with Waf
|
||||
We use Waf to build the @command{ns-3} project. The first thing you will need
|
||||
to do is to configure the build. For reasons that will become clear later,
|
||||
we are going to work with debug builds in the tutorial. To explain to Waf
|
||||
that it should do debug builds you will need to execute the following command,
|
||||
We use Waf to configure and build the @command{ns-3} project. It's not
|
||||
strictly required at this point, but it will be valuable to take a slight
|
||||
detour and look at how to make changes to the configuration of the project.
|
||||
Probably the most useful configuration change you can make will be to
|
||||
build the optimized version of the code. By default you have configured
|
||||
your project to build the debug version. Let's tell the project to do
|
||||
make an optimized build. To explain to Waf that it should do optimized
|
||||
builds you will need to execute the following command,
|
||||
|
||||
@verbatim
|
||||
./waf -d debug configure
|
||||
./waf -d optimized configure
|
||||
@end verbatim
|
||||
|
||||
This runs Waf out of the local directory (which is provided as a convenience
|
||||
@@ -147,57 +340,82 @@ for you). As the build system checks for various dependencies you should see
|
||||
output that looks similar to the following,
|
||||
|
||||
@verbatim
|
||||
Checking for program g++ : ok /usr/bin/g++
|
||||
Checking for compiler version : ok Version 4.0.1
|
||||
Checking for program cpp : ok /usr/bin/cpp
|
||||
Checking for program ar : ok /usr/bin/ar
|
||||
Checking for program ranlib : ok /usr/bin/ranlib
|
||||
Checking for compiler could create programs : ok
|
||||
Checking for compiler could create shared libs : ok
|
||||
Checking for compiler could create static libs : ok
|
||||
Checking for flags -O2 -DNDEBUG : ok
|
||||
Checking for flags -g -DDEBUG : ok
|
||||
Checking for flags -g3 -O0 -DDEBUG : ok
|
||||
Checking for flags -Wall : ok
|
||||
Checking for g++ : ok
|
||||
Checking for -Wno-error=deprecated-declarations compilation flag support : no
|
||||
Checking for header stdlib.h : ok
|
||||
Checking for header stdlib.h : ok
|
||||
Checking for header signal.h : ok
|
||||
Checking for library rt : not found
|
||||
Checking for header pthread.h : ok
|
||||
Checking for high precision time implementation: 128-bit integer
|
||||
Checking for header stdint.h : ok
|
||||
Checking for header inttypes.h : ok
|
||||
Checking for header sys/inttypes.h : not found
|
||||
Checking for package gtk+-2.0 >= 2.12 : not found
|
||||
Checking for library sqlite3 : ok
|
||||
Checking for package goocanvas gthread-2.0 : not found
|
||||
Checking for program python : ok /usr/local/bin/python
|
||||
Checking for Python version >= 2.3 : ok 2.4.3
|
||||
Checking for library python2.4 : not found
|
||||
Checking for library python2.4 : not found
|
||||
Checking for library python24 : not found
|
||||
Checking for program python2.4-config : not found
|
||||
Checking for header Python.h : not found
|
||||
Checking for program diff : ok /usr/bin/diff
|
||||
Checking for program hg : ok /opt/local/bin/hg
|
||||
Checking for program g++ : ok /usr/bin/g++
|
||||
Checking for program cpp : ok /usr/bin/cpp
|
||||
Checking for program ar : ok /usr/bin/ar
|
||||
Checking for program ranlib : ok /usr/bin/ranlib
|
||||
Checking for g++ : ok
|
||||
Checking for program pkg-config : ok /usr/bin/pkg-config
|
||||
Checking for regression reference traces : ok ../ns-3-dev-ref-traces (guessed)
|
||||
Checking for -Wno-error=deprecated-declarations support : yes
|
||||
Checking for header stdlib.h : ok
|
||||
Checking for header signal.h : ok
|
||||
Checking for header pthread.h : ok
|
||||
Checking for high precision time implementation : 128-bit integer
|
||||
Checking for header stdint.h : ok
|
||||
Checking for header inttypes.h : ok
|
||||
Checking for header sys/inttypes.h : not found
|
||||
Checking for library rt : ok
|
||||
Checking for header netpacket/packet.h : ok
|
||||
Checking for header linux/if_tun.h : ok
|
||||
Checking for pkg-config flags for GTK_CONFIG_STORE : ok
|
||||
Package libxml-2.0 was not found in the pkg-config search path.
|
||||
Perhaps you should add the directory containing `libxml-2.0.pc'
|
||||
to the PKG_CONFIG_PATH environment variable
|
||||
No package 'libxml-2.0' found
|
||||
Checking for pkg-config flags for LIBXML2 : not found
|
||||
Checking for library sqlite3 : ok
|
||||
Checking for NSC location : ok ../nsc (guessed)
|
||||
Checking for library dl : ok
|
||||
Checking for NSC supported architecture x86_64 : ok
|
||||
Package goocanvas was not found in the pkg-config search path.
|
||||
Perhaps you should add the directory containing `goocanvas.pc'
|
||||
to the PKG_CONFIG_PATH environment variable
|
||||
No package 'goocanvas' found
|
||||
Checking for pkg-config flags for MOBILITY_VISUALIZER : not found
|
||||
Checking for program python : ok /usr/bin/python
|
||||
Checking for Python version >= 2.3 : ok 2.5.2
|
||||
Checking for library python2.5 : ok
|
||||
Checking for program python2.5-config : ok /usr/bin/python2.5-config
|
||||
Checking for header Python.h : ok
|
||||
Checking for -fvisibility=hidden support : yes
|
||||
Checking for pybindgen location : ok ../pybindgen (guessed)
|
||||
Checking for Python module pybindgen : ok
|
||||
Checking for pybindgen version : ok 0.10.0.630
|
||||
Checking for Python module pygccxml : ok
|
||||
Checking for pygccxml version : ok 0.9.5
|
||||
Checking for program gccxml : ok /usr/local/bin/gccxml
|
||||
Checking for gccxml version : ok 0.9.0
|
||||
Checking for program sudo : ok /usr/bin/sudo
|
||||
Checking for program hg : ok /usr/bin/hg
|
||||
Checking for program valgrind : ok /usr/bin/valgrind
|
||||
---- Summary of optional NS-3 features:
|
||||
Threading Primitives : enabled
|
||||
Real Time Simulator : enabled
|
||||
GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found)
|
||||
SQlite stats data output : enabled
|
||||
Network Simulation Cradle : not enabled (--enable-nsc configure option not given)
|
||||
Python Bindings : not enabled (Python development headers not found.)
|
||||
Configuration finished successfully; project is now ready to build.
|
||||
Threading Primitives : enabled
|
||||
Real Time Simulator : enabled
|
||||
Emulated Net Device : enabled
|
||||
Tap Bridge : enabled
|
||||
GtkConfigStore : enabled
|
||||
XmlIo : not enabled (library 'libxml-2.0 >= 2.7' not found)
|
||||
SQlite stats data output : enabled
|
||||
Network Simulation Cradle : enabled
|
||||
Python Bindings : enabled
|
||||
Python API Scanning Support : enabled
|
||||
Use sudo to set suid bit : not enabled (option --enable-sudo not selected)
|
||||
Configuration finished successfully (00:00:02); project is now ready to build.
|
||||
@end verbatim
|
||||
|
||||
Note the trailing portion of the above output. Some ns-3 options are
|
||||
not enabled by default or require support from the underlying system.
|
||||
For instance, to enable Python bindings, Python development headers must
|
||||
be installed on the host machine, and they were not found in the above
|
||||
example, so Python scripting will not be supported in the resulting build.
|
||||
For this tutorial, we will focus on the non-optional pieces of ns-3.
|
||||
Note the last part of the above output. Some ns-3 options are not enabled by
|
||||
default or require support from the underlying system to work properly
|
||||
For instance, to enable XmlTo, the library libxml-2.0 must be found on the
|
||||
system. in the example above, this library was not found and the corresponding
|
||||
feature was not enabled. There is a feature to use sudo to set the suid bit of
|
||||
certain programs. This was not enabled by default.
|
||||
|
||||
Now go ahead and switch back to the debug build.
|
||||
|
||||
@verbatim
|
||||
./waf -d debug configure
|
||||
@end verbatim
|
||||
|
||||
The build system is now configured and you can build the debug versions of
|
||||
the @command{ns-3} programs by simply typing,
|
||||
@@ -206,15 +424,29 @@ the @command{ns-3} programs by simply typing,
|
||||
./waf
|
||||
@end verbatim
|
||||
|
||||
(Hint: if you have a multicore machine, use the "-j JOBS" option to speed
|
||||
up your build, where JOBS is the number of cores)
|
||||
You will see many Waf status messages displayed as the system compiles. The
|
||||
most important is the last one:
|
||||
Some waf commands are meaningful during the build phase and some commands are valid
|
||||
in the configuration phase. For example, if you wanted to use the emulation
|
||||
features of @command{ns-3} you might want to enable setting the suid bit using
|
||||
sudo. This is a configuration command, and so you could have run the following
|
||||
command
|
||||
|
||||
@verbatim
|
||||
Compilation finished successfully
|
||||
./waf -d debug --enable-sudo configure
|
||||
@end verbatim
|
||||
|
||||
If you had done this, waf would have run sudo to change the socket creator
|
||||
programs to run as root. There are many other configure- and build-time options
|
||||
available in waf. To explore these options, type:
|
||||
|
||||
@verbatim
|
||||
./waf -- help
|
||||
@end verbatim
|
||||
|
||||
We'll use some of the testing-related commands in the next section.
|
||||
|
||||
Okay, sorry, I made you build the @command{ns-3} part of the system twice,
|
||||
but now you know how to change the configuration and build optimized code.
|
||||
|
||||
@c ========================================================================
|
||||
@c Testing ns-3
|
||||
@c ========================================================================
|
||||
@@ -234,19 +466,22 @@ You should see a report from each unit test that executes indicating that the
|
||||
test has passed.
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf check
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
-- Running NS-3 C++ core unit tests...
|
||||
PASS AddressHelper
|
||||
PASS Wifi
|
||||
PASS DcfManager
|
||||
|
||||
...
|
||||
|
||||
PASS Object
|
||||
PASS Ptr
|
||||
PASS Callback
|
||||
~/repos/ns-3-dev >
|
||||
-- Running NS-3 Python bindings unit tests...
|
||||
...........
|
||||
----------------------------------------------------------------------
|
||||
Ran 11 tests in 0.003s
|
||||
|
||||
OK
|
||||
@end verbatim
|
||||
|
||||
This command is typically run by @code{users} to quickly verify that an
|
||||
@@ -255,60 +490,66 @@ This command is typically run by @code{users} to quickly verify that an
|
||||
@cindex regression tests
|
||||
You can also run our regression test suite to ensure that your distribution and
|
||||
tool chain have produced binaries that generate output that is identical to
|
||||
reference output files stored in a central location. To run the regression
|
||||
tests, you provide Waf with the regression flag.
|
||||
known-good reference output files. You downloaded these reference traces to
|
||||
your machine during the download process above. (Warning: The @code{ns-3.2}
|
||||
and @code{ns-3.3} releases do not use the @code{ns-3-allinone} environment
|
||||
and require you to be online when you run regression tests because they
|
||||
dynamically synchronize the reference traces directory with an online
|
||||
repository immediately prior to the run).
|
||||
|
||||
During regression testing Waf will run a number of tests that generate what we
|
||||
call trace files. The content of these trace files are compared with the
|
||||
reference traces. If they are identical, the regression tests report a PASS
|
||||
status. If a regression test fails you will see a FAIL indication along with a
|
||||
pointer to the offending trace file and its associated reference trace file
|
||||
along with a suggestion on diff parameters and options in order to see what
|
||||
has gone awry. If the error was discovered in a pcap file, it will be useful
|
||||
to convert the pcap files to text using tcpdump prior to comparison.
|
||||
|
||||
Some regression tests wmay be SKIPped if the required support
|
||||
is not present.
|
||||
|
||||
To run the regression tests, you provide Waf with the regression flag.
|
||||
|
||||
@verbatim
|
||||
./waf --regression
|
||||
@end verbatim
|
||||
|
||||
Waf will verify that the current files in the @command{ns-3} distribution are
|
||||
built and will then look for trace files in the aforementioned centralized
|
||||
location. If your tool chain includes Mercurial, the regression tests will
|
||||
be downloaded from a repository at @code{code.nsnam.org}. If you do not have
|
||||
Mercurial installed, the reference traces will be downloaded from a tarball
|
||||
located in the releases section of @code{www.nsnam.org}. The particular name
|
||||
of the reference trace location is built from the @command{ns-3} version
|
||||
located in the VERSION file, so don't change that string yourself unless you
|
||||
know what you are doing. (Warning: The ns-3.2 release requires you
|
||||
to be online when you run regression tests because it synchronizes the
|
||||
trace directory with an online repository).
|
||||
|
||||
Once the reference traces are downloaded to your local machine, Waf will run
|
||||
a number of tests that generate what we call trace files. The content of
|
||||
these trace files are compared with the reference traces just downloaded. If
|
||||
they are identical, the regression tests report a PASS status. If the
|
||||
regression tests pass, you should see something like,
|
||||
You should see messages indicating that many tests are being run and are
|
||||
passing.
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --regression
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
========== Running Regression Tests ==========
|
||||
Synchronizing reference traces using Mercurial.
|
||||
Pulling http://code.nsnam.org/ns-3-dev-ref-traces from repo.
|
||||
Skipping csma-bridge: Python bindings not available.
|
||||
SKIP test-csma-bridge
|
||||
PASS test-csma-broadcast
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
[647/669] regression-test (test-csma-bridge)
|
||||
[648/669] regression-test (test-csma-broadcast)
|
||||
[649/669] regression-test (test-csma-multicast)
|
||||
[650/669] regression-test (test-csma-one-subnet)
|
||||
PASS test-csma-multicast
|
||||
PASS test-csma-one-subnet
|
||||
PASS test-csma-packet-socket
|
||||
PASS test-realtime-udp-echo
|
||||
PASS test-simple-error-model
|
||||
PASS test-simple-global-routing
|
||||
PASS test-simple-point-to-point-olsr
|
||||
PASS test-tcp-large-transfer
|
||||
PASS test-udp-echo
|
||||
PASS test-wifi-wired-bridging
|
||||
|
||||
~/repos/ns-3-dev >
|
||||
[651/669] regression-test (test-csma-packet-socket)
|
||||
PASS test-csma-bridge
|
||||
...
|
||||
Regression testing summary:
|
||||
PASS: 22 of 22 tests passed
|
||||
Build finished successfully (00:00:23)
|
||||
@end verbatim
|
||||
|
||||
If a regression tests fails you will see a FAIL indication along with a
|
||||
pointer to the offending trace file and its associated reference trace file
|
||||
along with a suggestion on diff parameters and options in order to see what
|
||||
has gone awry. Python regression tests will be SKIPped if Python bindings
|
||||
are not built.
|
||||
If you want to take a look at an example of what might be checked during
|
||||
a regression test, you can do the following:
|
||||
|
||||
@verbatim
|
||||
cd build/debug/regression/traces/second.ref
|
||||
tcpdump -nn -tt -r second-2-0.pcap
|
||||
@end verbatim
|
||||
|
||||
The output should be clear to anyone who is familiar with tcpdump or net
|
||||
sniffers. We'll have much more to say on pcap files later in this tutorial.
|
||||
|
||||
Remember to cd back into the top-level @command{ns-3} directory
|
||||
after you are done:
|
||||
|
||||
@verbatim
|
||||
cd ../../../../..
|
||||
@end verbatim
|
||||
|
||||
@c ========================================================================
|
||||
@c Running a Script
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
The @command{ns-3} simulator is a discrete-event network simulator targeted
|
||||
primarily for research and educational use. The
|
||||
@uref{http://www.nsnam.org,,ns-3 project},
|
||||
started in 2006, is an open-source project developing ns-3.
|
||||
started in 2006, is an open-source project developing @command{ns-3}.
|
||||
|
||||
Primary documentation for the @command{ns-3} project is available in four
|
||||
forms:
|
||||
@@ -43,7 +43,7 @@ information into working simulations. In this tutorial, we will build
|
||||
several example simulations, introducing and explaining key concepts and
|
||||
features as we go.
|
||||
|
||||
As the tutorial unfolds, we will introduce the full ns-3 documentation
|
||||
As the tutorial unfolds, we will introduce the full @command{ns-3} documentation
|
||||
and provide pointers to source code for those interested in delving deeper
|
||||
into the workings of the system.
|
||||
|
||||
@@ -52,9 +52,9 @@ A few key points are worth noting at the onset:
|
||||
@item Ns-3 is not an extension of @uref{http://www.isi.edu/nsnam/ns,,ns-2};
|
||||
it is a new simulator. The two simulators are both written in C++ but
|
||||
@command{ns-3} is a new simulator that does not support the ns-2 APIs. Some
|
||||
models from ns-2 have already been ported from ns-2 to ns-3. The project will
|
||||
continue to maintain ns-2 while ns-3 is being built, and will study transition
|
||||
and integration mechanisms.
|
||||
models from ns-2 have already been ported from ns-2 to @command{ns-3}. The
|
||||
project will continue to maintain ns-2 while @command{ns-3} is being built,
|
||||
and will study transition and integration mechanisms.
|
||||
@item @command{Ns-3} is open-source, and the project strives to maintain an
|
||||
open environment for researchers to contribute and share their software.
|
||||
@end itemize
|
||||
@@ -63,36 +63,36 @@ open environment for researchers to contribute and share their software.
|
||||
@section For ns-2 Users
|
||||
|
||||
For those familiar with ns-2, the most visible outward change when moving to
|
||||
ns-3 is the choice of scripting language. Ns-2 is
|
||||
@command{ns-3} is the choice of scripting language. Ns-2 is
|
||||
scripted in OTcl and results of simulations can be visualized using the
|
||||
Network Animator @command{nam}. It is not possible to run a simulation
|
||||
in ns-2 purely from C++ (i.e., as a main() program without any OTcl).
|
||||
Moreover, some components of ns-2 are written in C++ and others in OTcl.
|
||||
In ns-3, the simulator is written entirely in C++, with optional
|
||||
In @command{ns-3}, the simulator is written entirely in C++, with optional
|
||||
Python bindings. Simulation scripts can therefore be written in C++
|
||||
or in Python. The results of some simulations can be visualized by
|
||||
@command{nam}, but new animators are under development. Since ns-3
|
||||
@command{nam}, but new animators are under development. Since @command{ns-3}
|
||||
generates pcap packet trace files, other utilities can be used to
|
||||
analyze traces as well.
|
||||
In this tutorial, we will first concentrate on scripting
|
||||
directly in C++ and interpreting results via ascii trace files.
|
||||
|
||||
But there are similarities as well (both, for example, are based on C++
|
||||
objects, and some code from ns-2 has already been ported to ns-3).
|
||||
We will try to highlight differences between ns-2 and ns-3
|
||||
objects, and some code from ns-2 has already been ported to @command{ns-3}).
|
||||
We will try to highlight differences between ns-2 and @command{ns-3}
|
||||
as we proceed in this tutorial.
|
||||
|
||||
A question that we often hear is "Should I still use ns-2 or move to
|
||||
ns-3?" The answer is that it depends. ns-3 does not have all of the
|
||||
models that ns-2 currently has, but on the other hand, ns-3 does have
|
||||
new capabilities (such as handling multiple interfaces on nodes
|
||||
@command{ns-3}?" The answer is that it depends. @command{ns-3} does not have
|
||||
all of the models that ns-2 currently has, but on the other hand, @command{ns-3}
|
||||
does have new capabilities (such as handling multiple interfaces on nodes
|
||||
correctly, use of IP addressing and more alignment with Internet
|
||||
protocols and designs, more detailed 802.11 models, etc.). ns-2
|
||||
models can usually be ported to ns-3 (a porting guide is under
|
||||
development). There is active development on multiple fronts for ns-3.
|
||||
The ns-3 developers believe (and certain early users have proven) that
|
||||
ns-3 is ready for active use, and should be an attractive alternative
|
||||
for users looking to start new simulation projects.
|
||||
models can usually be ported to @command{ns-3} (a porting guide is under
|
||||
development). There is active development on multiple fronts for
|
||||
@command{ns-3}. The @command{ns-3} developers believe (and certain early users
|
||||
have proven) that @command{ns-3} is ready for active use, and should be an
|
||||
attractive alternative for users looking to start new simulation projects.
|
||||
|
||||
@node Contributing
|
||||
@section Contributing
|
||||
@@ -119,7 +119,7 @@ We realize that if you are reading this document, contributing back to
|
||||
the project is probably not your foremost concern at this point, but
|
||||
we want you to be aware that contributing is in the spirit of the project and
|
||||
that even the act of dropping us a note about your early experience
|
||||
with ns-3 (e.g. "this tutorial section was not clear..."),
|
||||
with @command{ns-3} (e.g. "this tutorial section was not clear..."),
|
||||
reports of stale documentation, etc. are much appreciated.
|
||||
|
||||
@node Tutorial Organization
|
||||
@@ -160,14 +160,14 @@ broad sequences of events.
|
||||
@cindex architecture
|
||||
There are several important resources of which any @command{ns-3} user must be
|
||||
aware. The main web site is located at @uref{http://www.nsnam.org} and
|
||||
provides access to basic information about the ns-3 system. Detailed
|
||||
provides access to basic information about the @command{ns-3} system. Detailed
|
||||
documentation is available through the main web site at
|
||||
@uref{http://www.nsnam.org/documents.html}. You can also find documents
|
||||
relating to the system architecture from this page.
|
||||
|
||||
There is a Wiki that complements the main ns-3 web site which you will find at
|
||||
@uref{http://www.nsnam.org/wiki/}. You will find user and developer FAQs
|
||||
there, as well as troubleshooting guides, third-party contributed code,
|
||||
There is a Wiki that complements the main @command{ns-3} web site which you will
|
||||
find at @uref{http://www.nsnam.org/wiki/}. You will find user and developer
|
||||
FAQs there, as well as troubleshooting guides, third-party contributed code,
|
||||
papers, etc.
|
||||
|
||||
@cindex mercurial repository
|
||||
@@ -221,7 +221,7 @@ using the Python language.
|
||||
|
||||
The build system @code{Waf} is used on the @command{ns-3} project. It is one
|
||||
of the new generation of Python-based build systems. You will not need to
|
||||
understand any Python to build the existing ns-3 system, and will
|
||||
understand any Python to build the existing @command{ns-3} system, and will
|
||||
only have to understand a tiny and intuitively obvious subset of Python in
|
||||
order to extend the system in most cases.
|
||||
|
||||
@@ -233,9 +233,9 @@ found at @uref{http://freehackers.org/~tnagy/waf.html}.
|
||||
|
||||
@cindex C++
|
||||
@cindex Python
|
||||
As mentioned above, scripting in ns-3 is done in C++ or Python.
|
||||
As of ns-3.2, most of the ns-3 API is available in Python, but the models
|
||||
are written in C++ in either case. A working
|
||||
As mentioned above, scripting in @command{ns-3} is done in C++ or Python.
|
||||
As of ns-3.2, most of the @command{ns-3} API is available in Python, but the
|
||||
models are written in C++ in either case. A working
|
||||
knowledge of C++ and object-oriented concepts is assumed in this document.
|
||||
We will take some time to review some of the more advanced concepts or
|
||||
possibly unfamiliar language features, idioms and design patterns as they
|
||||
@@ -255,7 +255,7 @@ The @command{ns-3} system uses several components of the GNU ``toolchain''
|
||||
for development. A
|
||||
software toolchain is the set of programming tools available in the given
|
||||
environment. For a quick review of what is included in the GNU toolchain see,
|
||||
@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. ns-3 uses gcc,
|
||||
@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. @command{ns-3} uses gcc,
|
||||
GNU binutils, and gdb. However, we do not use the GNU build system,
|
||||
either make or autotools, using Waf instead.
|
||||
|
||||
|
||||
@@ -82,8 +82,8 @@ documentation and now would be a good time to peruse the Logging Module
|
||||
documentation if you have not done so.
|
||||
|
||||
Now that you have read the documentation in great detail, let's use some of
|
||||
that knowledge to get some interesting information out of the @code{first.cc}
|
||||
example script you have already built.
|
||||
that knowledge to get some interesting information out of the
|
||||
@code{scratch/myfirst.cc} example script you have already built.
|
||||
|
||||
@node Enabling Logging
|
||||
@subsection Enabling Logging
|
||||
@@ -92,17 +92,22 @@ Let's use the NS_LOG environment variable to turn on some more logging, but
|
||||
to get our bearings, go ahead and run the script just as you did previously,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
./waf --run scratch/myfirst
|
||||
@end verbatim
|
||||
|
||||
You should see the now familiar output of the first @command{ns-3} example
|
||||
program
|
||||
|
||||
@verbatim
|
||||
Entering directory `repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
Sent 1024 bytes to 10.1.1.2
|
||||
Received 1024 bytes from 10.1.1.1
|
||||
Received 1024 bytes from 10.1.1.2
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
It turns out that the ``Sent'' and ``Received'' messages are actually logging
|
||||
messages from the @code{UdpEchoClientApplication} and
|
||||
It turns out that the ``Sent'' and ``Received'' messages you see above are
|
||||
actually logging messages from the @code{UdpEchoClientApplication} and
|
||||
@code{UdpEchoServerApplication}. We can ask the client application, for
|
||||
example, to print more information by setting its logging level via the
|
||||
NS_LOG environment variable.
|
||||
@@ -113,7 +118,7 @@ will have to convert my examples to the ``setenv VARIABLE value'' syntax
|
||||
required by those shells.
|
||||
|
||||
Right now, the UDP echo client application is responding to the following line
|
||||
of code in @code{first.cc},
|
||||
of code in @code{scratch/myfirst.cc},
|
||||
|
||||
@verbatim
|
||||
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
|
||||
@@ -127,7 +132,7 @@ increase the logging level and get more information without changing the
|
||||
script and recompiling by setting the NS_LOG environment variable like this:
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > export NS_LOG=UdpEchoClientApplication=level_all
|
||||
export NS_LOG=UdpEchoClientApplication=level_all
|
||||
@end verbatim
|
||||
|
||||
This sets the shell environment variable @code{NS_LOG} to the string,
|
||||
@@ -143,21 +148,19 @@ you run the script with NS_LOG set this way, the @command{ns-3} logging
|
||||
system will pick up the change and you should see the following output:
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
UdpEchoClientApplication:UdpEchoClient()
|
||||
UdpEchoClientApplication:StartApplication()
|
||||
UdpEchoClientApplication:ScheduleTransmit()
|
||||
UdpEchoClientApplication:Send()
|
||||
Sent 1024 bytes to 10.1.1.2
|
||||
Received 1024 bytes from 10.1.1.1
|
||||
UdpEchoClientApplication:HandleRead(0x62c640, 0x62cd70)
|
||||
UdpEchoClientApplication:HandleRead(0x638180, 0x6389b0)
|
||||
Received 1024 bytes from 10.1.1.2
|
||||
UdpEchoClientApplication:StopApplication()
|
||||
UdpEchoClientApplication:DoDispose()
|
||||
UdpEchoClientApplication:~UdpEchoClient()
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
The additional debug information provided by the application is from
|
||||
@@ -198,21 +201,19 @@ that every message from the given log component is prefixed with the component
|
||||
name.
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
UdpEchoClientApplication:UdpEchoClient()
|
||||
UdpEchoClientApplication:StartApplication()
|
||||
UdpEchoClientApplication:ScheduleTransmit()
|
||||
UdpEchoClientApplication:Send()
|
||||
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
|
||||
Received 1024 bytes from 10.1.1.1
|
||||
UdpEchoClientApplication:HandleRead(0x62c710, 0x62ce40)
|
||||
UdpEchoClientApplication:HandleRead(0x638180, 0x6389b0)
|
||||
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
|
||||
UdpEchoClientApplication:StopApplication()
|
||||
UdpEchoClientApplication:DoDispose()
|
||||
UdpEchoClientApplication:~UdpEchoClient()
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
You can now see all of the messages coming from the UDP echo client application
|
||||
@@ -227,17 +228,16 @@ the NS_LOG environment variable.
|
||||
UdpEchoServerApplication=level_all|prefix_func'
|
||||
@end verbatim
|
||||
|
||||
Note that you will need to remove the newline after the @code{:} in the
|
||||
example text above.
|
||||
Warning: You will need to remove the newline after the @code{:} in the
|
||||
example text above which is only there for document formatting purposes.
|
||||
|
||||
Now, if you run the script you will see all of the log messages from both the
|
||||
echo client and server applications. You may see that this can be very useful
|
||||
in debugging problems.
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
UdpEchoServerApplication:UdpEchoServer()
|
||||
UdpEchoClientApplication:UdpEchoClient()
|
||||
UdpEchoServerApplication:StartApplication()
|
||||
@@ -247,7 +247,7 @@ in debugging problems.
|
||||
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
|
||||
UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
|
||||
UdpEchoServerApplication:HandleRead(): Echoing packet
|
||||
UdpEchoClientApplication:HandleRead(0x62c760, 0x62ce90)
|
||||
UdpEchoClientApplication:HandleRead(0x638320, 0x638b50)
|
||||
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
|
||||
UdpEchoServerApplication:StopApplication()
|
||||
UdpEchoClientApplication:StopApplication()
|
||||
@@ -255,7 +255,6 @@ in debugging problems.
|
||||
UdpEchoServerApplication:DoDispose()
|
||||
UdpEchoClientApplication:~UdpEchoClient()
|
||||
UdpEchoServerApplication:~UdpEchoServer()
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
It is also sometimes useful to be able to see the simulation time at which a
|
||||
@@ -266,12 +265,12 @@ log message is generated. You can do this by ORing in the prefix_time bit.
|
||||
UdpEchoServerApplication=level_all|prefix_func|prefix_time'
|
||||
@end verbatim
|
||||
|
||||
If you run the script now, you should see the following output:
|
||||
Again, you will have to remove the newline above. If you run the script now,
|
||||
you should see the following output:
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
0s UdpEchoServerApplication:UdpEchoServer()
|
||||
0s UdpEchoClientApplication:UdpEchoClient()
|
||||
1s UdpEchoServerApplication:StartApplication()
|
||||
@@ -281,7 +280,7 @@ If you run the script now, you should see the following output:
|
||||
2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
|
||||
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
|
||||
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
|
||||
2.00737s UdpEchoClientApplication:HandleRead(0x62c8c0, 0x62d020)
|
||||
2.00737s UdpEchoClientApplication:HandleRead(0x638490, 0x638cc0)
|
||||
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
|
||||
10s UdpEchoServerApplication:StopApplication()
|
||||
10s UdpEchoClientApplication:StopApplication()
|
||||
@@ -289,15 +288,14 @@ If you run the script now, you should see the following output:
|
||||
UdpEchoServerApplication:DoDispose()
|
||||
UdpEchoClientApplication:~UdpEchoClient()
|
||||
UdpEchoServerApplication:~UdpEchoServer()
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
You can see that the constructor for the UdpEchoServer was called at a
|
||||
simulation time of 0 seconds. This is actually happening before the
|
||||
simulation starts. The same for the UdpEchoClient constructor.
|
||||
|
||||
Recall that the @code{first.cc} script started the echo server application at
|
||||
one second into the simulation. You can now see that the
|
||||
Recall that the @code{scratch/first.cc} script started the echo server
|
||||
application at one second into the simulation. You can now see that the
|
||||
@code{StartApplication} method of the server is, in fact, called at one second
|
||||
(or one billion nanoseconds). You can also see that the echo client
|
||||
application is started at a simulation time of two seconds as we requested in
|
||||
@@ -322,29 +320,29 @@ turning on all of the logging components in the system. Try setting the
|
||||
|
||||
The asterisk above is the logging component wildcard. This will turn on all
|
||||
of the logging in all of the components used in the simulation. I won't
|
||||
reproduce the output here (as of this writing it produces 772 lines of output
|
||||
reproduce the output here (as of this writing it produces 974 lines of output
|
||||
for the single packet echo) but you can redirect this information into a file
|
||||
and look through it with your favorite editor if you like,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first >& log.out
|
||||
./waf --run scratch/myfirst > log.out 2>&1
|
||||
@end verbatim
|
||||
|
||||
I personally use this quite a bit when I am presented with a problem and I
|
||||
have no idea where things are going wrong. I can follow the progress of the
|
||||
code quite easily without having to set breakpoints and step through code
|
||||
in a debugger. When I have a general idea about what is going wrong, I
|
||||
transition into a debugger for fine-grained examination of the problem. This
|
||||
kind of output can be especially useful when your script does something
|
||||
completely unexpected. If you are stepping using a debugger you may miss an
|
||||
unexpected excursion completely. Logging the excursion makes it quickly
|
||||
visible.
|
||||
I personally use this volume of logging quite a bit when I am presented with
|
||||
a problem and I have no idea where things are going wrong. I can follow the
|
||||
progress of the code quite easily without having to set breakpoints and step
|
||||
through code in a debugger. When I have a general idea about what is going
|
||||
wrong, I transition into a debugger for fine-grained examination of the
|
||||
problem. This kind of output can be especially useful when your script does
|
||||
something completely unexpected. If you are stepping using a debugger you
|
||||
may miss an unexpected excursion completely. Logging the excursion makes it
|
||||
quickly visible.
|
||||
|
||||
@node Adding Logging to your Code
|
||||
@subsection Adding Logging to your Code
|
||||
@cindex NS_LOG
|
||||
You can add new logging to your simulations by making calls to the log
|
||||
component via several macros. Let's do so in the @code{first.cc} script we
|
||||
component via several macros. Let's do so in the @code{myfirst.cc} script we
|
||||
have in the @code{scratch} directory.
|
||||
|
||||
Recall that we have defined a logging component in that script:
|
||||
@@ -357,43 +355,56 @@ You now know that you can enable all of the logging for this component by
|
||||
setting the @code{NS_LOG} environment variable to the various levels. Let's
|
||||
go ahead add some logging to the script. The macro used to add an
|
||||
informational level log message is @code{NS_LOG_INFO}. Go ahead and add one
|
||||
just before we start creating the nodes that tells you that the script is
|
||||
(just before we start creating the nodes) that tells you that the script is
|
||||
``Creating Topology.'' This is done as in this code snippet,
|
||||
|
||||
Open @code{scratch/myfirst.cc} in your favorite editor and add the line,
|
||||
|
||||
@verbatim
|
||||
NS_LOG_INFO ("Creating Topology");
|
||||
@end verbatim
|
||||
|
||||
right before the lines,
|
||||
|
||||
@verbatim
|
||||
NodeContainer nodes;
|
||||
nodes.Create (2);
|
||||
@end verbatim
|
||||
|
||||
Now build the script using waf and clear the @code{NS_LOG} variable to turn
|
||||
off the torrent of logging we previously enabled:
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > export NS_LOG=
|
||||
./waf
|
||||
export NS_LOG=
|
||||
@end verbatim
|
||||
|
||||
Now, if you run the script, you will not see your new message since its
|
||||
associated logging component (@code{FirstScriptExample}) has not been enabled.
|
||||
In order to see your message you will have to enable the
|
||||
@code{FirstScriptExample} logging component with a level greater than or equal
|
||||
to @code{NS_LOG_INFO}. If you just want to see this particular level of
|
||||
logging, you can enable it by,
|
||||
Now, if you run the script,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > export NS_LOG=FirstScriptExample=info
|
||||
./waf --run scratch/myfirst
|
||||
@end verbatim
|
||||
|
||||
you will @emph{not} see your new message since its associated logging
|
||||
component (@code{FirstScriptExample}) has not been enabled. In order to see your
|
||||
message you will have to enable the @code{FirstScriptExample} logging component
|
||||
with a level greater than or equal to @code{NS_LOG_INFO}. If you just want to
|
||||
see this particular level of logging, you can enable it by,
|
||||
|
||||
@verbatim
|
||||
export NS_LOG=FirstScriptExample=info
|
||||
@end verbatim
|
||||
|
||||
If you now run the script you will see your new ``Creating Topology'' log
|
||||
message,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
Creating Topology
|
||||
Sent 1024 bytes to 10.1.1.2
|
||||
Received 1024 bytes from 10.1.1.1
|
||||
Received 1024 bytes from 10.1.1.2
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
@c ========================================================================
|
||||
@@ -427,35 +438,33 @@ in the following code,
|
||||
@end verbatim
|
||||
|
||||
This simple two line snippet is actually very useful by itself. It opens the
|
||||
door to the @command{ns-3} global variable and attribute systems. Go ahead
|
||||
and add that two lines of code to the @code{first.cc} script at the start of
|
||||
@code{main}. Go ahead and build the script and run it, but ask the script
|
||||
for help in the following way,
|
||||
door to the @command{ns-3} global variable and @code{Attribute} systems. Go
|
||||
ahead and add that two lines of code to the @code{scratch/first.cc} script at
|
||||
the start of @code{main}. Go ahead and build the script and run it, but ask
|
||||
the script for help in the following way,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run "scratch/first --PrintHelp"
|
||||
./waf --run "scratch/myfirst --PrintHelp"
|
||||
@end verbatim
|
||||
|
||||
This will ask Waf to run the @code{scratch/first} script and pass the command
|
||||
This will ask Waf to run the @code{scratch/myfirst} script and pass the command
|
||||
line argument @code{--PrintHelp} to the script. The quotes are required to
|
||||
sort out which program gets which argument. The command line parser will
|
||||
now see the @code{--PrintHelp} argument and respond with,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run ``scratch/first --PrintHelp''
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
--PrintHelp: Print this help message.
|
||||
--PrintGroups: Print the list of groups.
|
||||
--PrintTypeIds: Print all TypeIds.
|
||||
--PrintGroup=[group]: Print all TypeIds of group.
|
||||
--PrintAttributes=[typeid]: Print all attributes of typeid.
|
||||
--PrintGlobals: Print the list of globals.
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
Let's focus on the @code{--PrintAttributes} option. We have already hinted
|
||||
at the @command{ns-3} attribute system while walking through the
|
||||
at the @command{ns-3} @code{Attribute} system while walking through the
|
||||
@code{first.cc} script. We looked at the following lines of code,
|
||||
|
||||
@verbatim
|
||||
@@ -466,17 +475,17 @@ at the @command{ns-3} attribute system while walking through the
|
||||
|
||||
and mentioned that @code{DataRate} was actually an @code{Attribute} of the
|
||||
@code{PointToPointNetDevice}. Let's use the command line argument parser
|
||||
to take a look at the attributes of the PointToPointNetDevice. The help
|
||||
to take a look at the @code{Attributes} of the PointToPointNetDevice. The help
|
||||
listing says that we should provide a @code{TypeId}. This corresponds to the
|
||||
class name of the class to which the attributes belong. In this case it will
|
||||
be @code{ns3::PointToPointNetDevice}. Let's go ahead and type in,
|
||||
class name of the class to which the @code{Attributes} belong. In this case it
|
||||
will be @code{ns3::PointToPointNetDevice}. Let's go ahead and type in,
|
||||
|
||||
@verbatim
|
||||
./waf --run "scratch/first --PrintAttributes=ns3::PointToPointNetDevice"
|
||||
./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"
|
||||
@end verbatim
|
||||
|
||||
The system will print out all of the attributes of this kind of net device.
|
||||
Among the attributes you will see listed is,
|
||||
The system will print out all of the @code{Attributes} of this kind of net device.
|
||||
Among the @code{Attributes} you will see listed is,
|
||||
|
||||
@verbatim
|
||||
--ns3::PointToPointNetDevice::DataRate=[32768bps]:
|
||||
@@ -484,7 +493,7 @@ Among the attributes you will see listed is,
|
||||
@end verbatim
|
||||
|
||||
This is the default value that will be used when a @code{PointToPointNetDevice}
|
||||
is created in the system. We overrode this default with the attribute
|
||||
is created in the system. We overrode this default with the @code{Attribute}
|
||||
setting in the @code{PointToPointHelper} above. Let's use the default values
|
||||
for the point-to-point devices and channels by deleting the
|
||||
@code{SetDeviceAttribute} call and the @code{SetChannelAttribute} call from
|
||||
@@ -518,24 +527,26 @@ time prefix.
|
||||
If you run the script, you should now see the following output,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run scratch/first
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
0ns UdpEchoServerApplication:UdpEchoServer()
|
||||
1000000000ns UdpEchoServerApplication:StartApplication()
|
||||
Build finished successfully (00:00:00)
|
||||
0s UdpEchoServerApplication:UdpEchoServer()
|
||||
1s UdpEchoServerApplication:StartApplication()
|
||||
Sent 1024 bytes to 10.1.1.2
|
||||
2257324218ns Received 1024 bytes from 10.1.1.1
|
||||
2257324218ns Echoing packet
|
||||
2.25732s Received 1024 bytes from 10.1.1.1
|
||||
2.25732s Echoing packet
|
||||
Received 1024 bytes from 10.1.1.2
|
||||
10000000000ns UdpEchoServerApplication:StopApplication()
|
||||
10s UdpEchoServerApplication:StopApplication()
|
||||
UdpEchoServerApplication:DoDispose()
|
||||
UdpEchoServerApplication:~UdpEchoServer()
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
Recall that the last time we looked at the simulation time at which the packet
|
||||
was received by the echo server, it was at 2.0036864 seconds. Now it is
|
||||
receiving the packet at about 2.257 seconds. This is because we just dropped
|
||||
was received by the echo server, it was at 2.00369 seconds.
|
||||
|
||||
@verbatim
|
||||
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
|
||||
@end verbatim
|
||||
|
||||
Now it is receiving the packet at 2.25732 seconds. This is because we just dropped
|
||||
the data rate of the @code{PointToPointNetDevice} down to its default of
|
||||
32768 bits per second from five megabits per second.
|
||||
|
||||
@@ -544,20 +555,21 @@ speed our simulation up again. We do this in the following way, according to
|
||||
the formula implied by the help item:
|
||||
|
||||
@verbatim
|
||||
./waf --run "scratch/first --ns3::PointToPointNetDevice::DataRate=5Mbps"
|
||||
./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"
|
||||
@end verbatim
|
||||
|
||||
This will set the default value of the @code{DataRate} attribute back to
|
||||
five megabits per second. To get the original behavior of the script back,
|
||||
we will have to set the speed-of-light delay of the channel. We can ask the
|
||||
command line system to print out the @code{Attributes} of the channel just
|
||||
like we did the net device:
|
||||
This will set the default value of the @code{DataRate} @code{Attribute} back to
|
||||
five megabits per second. Are you surprised by the result? It turns out that
|
||||
in order to get the original behavior of the script back, we will have to set
|
||||
the speed-of-light delay of the channel as well. We can ask the command line
|
||||
system to print out the @code{Attributes} of the channel just like we did for
|
||||
the net device:
|
||||
|
||||
@verbatim
|
||||
./waf --run "scratch/first --PrintAttributes=ns3::PointToPointChannel"
|
||||
./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel"
|
||||
@end verbatim
|
||||
|
||||
We discover the @code{Delay} attribute of the channel is set in the following
|
||||
We discover the @code{Delay} @code{Attribute} of the channel is set in the following
|
||||
way:
|
||||
|
||||
@verbatim
|
||||
@@ -568,7 +580,7 @@ way:
|
||||
We can then set both of these default values through the command line system,
|
||||
|
||||
@verbatim
|
||||
./waf --run "scratch/first
|
||||
./waf --run "scratch/myfirst
|
||||
--ns3::PointToPointNetDevice::DataRate=5Mbps
|
||||
--ns3::PointToPointChannel::Delay=2ms"
|
||||
@end verbatim
|
||||
@@ -577,25 +589,26 @@ in which case we recover the timing we had when we explicitly set the
|
||||
@code{DataRate} and @code{Delay} in the script:
|
||||
|
||||
@verbatim
|
||||
Compilation finished successfully
|
||||
0ns UdpEchoServerApplication:UdpEchoServer()
|
||||
1000000000ns UdpEchoServerApplication:StartApplication()
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
0s UdpEchoServerApplication:UdpEchoServer()
|
||||
1s UdpEchoServerApplication:StartApplication()
|
||||
Sent 1024 bytes to 10.1.1.2
|
||||
2003686400ns Received 1024 bytes from 10.1.1.1
|
||||
2003686400ns Echoing packet
|
||||
2.00369s Received 1024 bytes from 10.1.1.1
|
||||
2.00369s Echoing packet
|
||||
Received 1024 bytes from 10.1.1.2
|
||||
10000000000ns UdpEchoServerApplication:StopApplication()
|
||||
10s UdpEchoServerApplication:StopApplication()
|
||||
UdpEchoServerApplication:DoDispose()
|
||||
UdpEchoServerApplication:~UdpEchoServer()
|
||||
@end verbatim
|
||||
|
||||
Note that the packet is again received by the server at 2.0036864 seconds. We
|
||||
could actually set any of the attributes used in the script in this way. In
|
||||
particular we could set the @code{UdpEchoClient} attribute @code{MaxPackets}
|
||||
Note that the packet is again received by the server at 2.00369 seconds. We
|
||||
could actually set any of the @code{Attributes} used in the script in this way.
|
||||
In particular we could set the @code{UdpEchoClient Attribute MaxPackets}
|
||||
to some other value than one.
|
||||
|
||||
How would you go about that? Give it a try. Remember you have to comment
|
||||
out the place we override the default attribute in the script. Then you
|
||||
out the place we override the default @code{Attribute} in the script. Then you
|
||||
have to rebuild the script using the default. You will also have to find the
|
||||
syntax for actually setting the new default atribute value using the command
|
||||
line help facility. Once you have this figured out you should be able to
|
||||
@@ -604,7 +617,7 @@ folks, we'll tell you that your command line should end up looking something
|
||||
like,
|
||||
|
||||
@verbatim
|
||||
./waf --run "scratch/first
|
||||
./waf --run "scratch/myfirst
|
||||
--ns3::PointToPointNetDevice::DataRate=5Mbps
|
||||
--ns3::PointToPointChannel::Delay=2ms
|
||||
--ns3::UdpEchoClient::MaxPackets=2"
|
||||
@@ -619,7 +632,7 @@ completely different way. Let's add a local variable called @code{nPackets}
|
||||
to the @code{main} function. We'll initialize it to one to match our previous
|
||||
default behavior. To allow the command line parser to change this value, we
|
||||
need to hook the value into the parser. We do this by adding a call to
|
||||
@code{AddValue}. Go ahead and change the @code{scratch/first.cc} script to
|
||||
@code{AddValue}. Go ahead and change the @code{scratch/myfirst.cc} script to
|
||||
start with the following code,
|
||||
|
||||
@verbatim
|
||||
@@ -636,20 +649,25 @@ start with the following code,
|
||||
@end verbatim
|
||||
|
||||
Scroll down to the point in the script where we set the @code{MaxPackets}
|
||||
attribute and change it so that it is set to the variable @code{nPackets}
|
||||
@code{Attribute} and change it so that it is set to the variable @code{nPackets}
|
||||
instead of the constant @code{1} as is shown below.
|
||||
|
||||
@verbatim
|
||||
echoClient.SetAppAttribute ("MaxPackets", UintegerValue (nPackets));
|
||||
echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));
|
||||
@end verbatim
|
||||
|
||||
Now if you run the script and provide the @code{--PrintHelp} argument, you
|
||||
should see your new @code{User Argument} listed in the help display.
|
||||
|
||||
Try,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run "scratch/first --PrintHelp"
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
./waf --run "scratch/myfirst --PrintHelp"
|
||||
@end verbatim
|
||||
|
||||
@verbatim
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
--PrintHelp: Print this help message.
|
||||
--PrintGroups: Print the list of groups.
|
||||
--PrintTypeIds: Print all TypeIds.
|
||||
@@ -658,33 +676,43 @@ should see your new @code{User Argument} listed in the help display.
|
||||
--PrintGlobals: Print the list of globals.
|
||||
User Arguments:
|
||||
--nPackets: Number of packets to echo
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
If you want to specify the number of packets to echo, you can now do so by
|
||||
setting the @code{--nPackets} argument in the command line,
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > ./waf --run "scratch/first --nPackets=2"
|
||||
Entering directory `/home/craigdo/repos/ns-3-dev/build'
|
||||
Compilation finished successfully
|
||||
./waf --run "scratch/myfirst --nPackets=2"
|
||||
@end verbatim
|
||||
|
||||
You should now see
|
||||
|
||||
@verbatim
|
||||
Entering directory `repos/ns-3-allinone/ns-3-dev/build'
|
||||
Build finished successfully (00:00:00)
|
||||
0s UdpEchoServerApplication:UdpEchoServer()
|
||||
1s UdpEchoServerApplication:StartApplication()
|
||||
Sent 1024 bytes to 10.1.1.2
|
||||
Received 1024 bytes from 10.1.1.1
|
||||
2.25732s Received 1024 bytes from 10.1.1.1
|
||||
2.25732s Echoing packet
|
||||
Received 1024 bytes from 10.1.1.2
|
||||
Sent 1024 bytes to 10.1.1.2
|
||||
Received 1024 bytes from 10.1.1.1
|
||||
3.25732s Received 1024 bytes from 10.1.1.1
|
||||
3.25732s Echoing packet
|
||||
Received 1024 bytes from 10.1.1.2
|
||||
~/repos/ns-3-dev >
|
||||
10s UdpEchoServerApplication:StopApplication()
|
||||
UdpEchoServerApplication:DoDispose()
|
||||
UdpEchoServerApplication:~UdpEchoServer()
|
||||
@end verbatim
|
||||
|
||||
You have now echoed two packets.
|
||||
|
||||
You can see that if you are an @command{ns-3} user, you can use the command
|
||||
line argument system to control global values and attributes. If you are a
|
||||
model author, you can add new attributes to your Objects and they will
|
||||
automatically be available for setting by your users through the command line
|
||||
system. If you are a script author, you can add new variables to your scripts
|
||||
and hook them into the command line system quite painlessly.
|
||||
line argument system to control global values and @code{Attributes}. If you are
|
||||
a model author, you can add new @code{Attributes} to your @code{Objects} and
|
||||
they will automatically be available for setting by your users through the
|
||||
command line system. If you are a script author, you can add new variables to
|
||||
your scripts and hook them into the command line system quite painlessly.
|
||||
|
||||
@c ========================================================================
|
||||
@c Using the Tracing System
|
||||
@@ -764,17 +792,26 @@ generated by many scripts.
|
||||
|
||||
@cindex tracing packets
|
||||
Let's just jump right in and add some ASCII tracing output to our
|
||||
@code{first.cc} script. The first thing you need to do is to add the
|
||||
following code to the script just before the call to @code{Simulator::Run ()}.
|
||||
@code{scratch/myfirst.cc} script.
|
||||
|
||||
The first thing you need to do is to add the following include to the top of
|
||||
the script just after the GNU GPL comment:
|
||||
|
||||
@verbatim
|
||||
#include <fstream>
|
||||
@end verbatim
|
||||
|
||||
Then, right before the before the call to @code{Simulator::Run ()}, add the
|
||||
following lines of code.
|
||||
|
||||
@verbatim
|
||||
std::ofstream ascii;
|
||||
ascii.open ("first.tr");
|
||||
ascii.open ("myfirst.tr");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
@end verbatim
|
||||
|
||||
The first two lines are just vanilla C++ code to open a stream that will be
|
||||
written to a file named ``first.tr.'' See your favorite C++ tutorial if you
|
||||
written to a file named ``myfirst.tr.'' See your favorite C++ tutorial if you
|
||||
are unfamiliar with this code. The last line of code in the snippet above
|
||||
tells @command{ns-3} that you want to enable ASCII tracing on all
|
||||
point-to-point devices in your simulation; and you want the (provided) trace
|
||||
@@ -782,32 +819,24 @@ sinks to write out information about packet movement in ASCII format to the
|
||||
stream provided. For those familiar with @command{ns-2}, the traced events are
|
||||
equivalent to the popular trace points that log "+", "-", "d", and "r" events.
|
||||
|
||||
Since we have used a @code{std::ofstream} object, we also need to include the
|
||||
appropriate header. Add the following line to the script (I typically add it
|
||||
above the ns-3 includes):
|
||||
|
||||
@verbatim
|
||||
#include <fstream>
|
||||
@end verbatim
|
||||
|
||||
You can now build the script and run it from the command line:
|
||||
|
||||
@verbatim
|
||||
./waf --run scratch/first
|
||||
./waf --run scratch/myfirst
|
||||
@end verbatim
|
||||
|
||||
@cindex first.tr
|
||||
Just as you have seen previously, you may see some messages from Waf and then
|
||||
the ``Compilation finished successfully'' with some number of messages from
|
||||
@cindex myfirst.tr
|
||||
Just as you have seen many times before, you will see some messages from Waf and then
|
||||
the ``Build finished successfully'' with some number of messages from
|
||||
the running program.
|
||||
|
||||
When it ran, the program will have created a file named @code{first.tr}.
|
||||
When it ran, the program will have created a file named @code{myfirst.tr}.
|
||||
Because of the way that Waf works, the file is not created in the local
|
||||
directory, it is created at the top-level directory of the repository by
|
||||
default. If you want to control where the traces are saved you can use the
|
||||
@code{--cwd} option of Waf to specify this. We have not done so, thus we
|
||||
need to change into the top level directory of our repo and take a look at
|
||||
the ASCII trace file @code{first.tr} in your favorite editor.
|
||||
the ASCII trace file @code{myfirst.tr} in your favorite editor.
|
||||
|
||||
@subsubsection Parsing Ascii Traces
|
||||
@cindex parsing ascii traces
|
||||
@@ -844,7 +873,7 @@ number on the left side:
|
||||
03 ns3::PppHeader (
|
||||
04 Point-to-Point Protocol: IP (0x0021))
|
||||
05 ns3::Ipv4Header (
|
||||
06 tos 0x0 ttl 64 id 0 offset 0 flags [none]
|
||||
06 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
|
||||
07 length: 1052 10.1.1.1 > 10.1.1.2)
|
||||
08 ns3::UdpHeader (
|
||||
09 length: 1032 49153 > 9)
|
||||
@@ -898,7 +927,7 @@ device on the node with the echo server. I have reproduced that event below.
|
||||
@verbatim
|
||||
00 r
|
||||
01 2.25732
|
||||
02 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/Rx
|
||||
02 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
|
||||
03 ns3::PppHeader (
|
||||
04 Point-to-Point Protocol: IP (0x0021))
|
||||
05 ns3::Ipv4Header (
|
||||
@@ -917,7 +946,7 @@ be familiar as you have seen it before in a previous section.
|
||||
|
||||
The trace source namespace entry (reference 02) has changed to reflect that
|
||||
this event is coming from node 1 (@code{/NodeList/1}) and the packet reception
|
||||
trace source (@code{/Rx}). It should be quite easy for you to follow the
|
||||
trace source (@code{/MacRx}). It should be quite easy for you to follow the
|
||||
progress of the packet through the topology by looking at the rest of the
|
||||
traces in the file.
|
||||
|
||||
@@ -937,54 +966,54 @@ traces. In this tutorial, we concentrate on viewing pcap traces with tcpdump.
|
||||
The code used to enable pcap tracing is a one-liner.
|
||||
|
||||
@verbatim
|
||||
PointToPointHelper::EnablePcapAll ("first");
|
||||
PointToPointHelper::EnablePcapAll ("myfirst");
|
||||
@end verbatim
|
||||
|
||||
Go ahead and insert this line of code after the ASCII tracing code we just
|
||||
added to @code{scratch/first.cc}. Notice that we only passed the string
|
||||
``first,'' and not ``first.pcap'' or something similar. This is because the
|
||||
added to @code{scratch/myfirst.cc}. Notice that we only passed the string
|
||||
``myfirst,'' and not ``myfirst.pcap'' or something similar. This is because the
|
||||
parameter is a prefix, not a complete file name. The helper will actually
|
||||
create a trace file for every point-to-point device in the simulation. The
|
||||
file names will be built using the prefix, the node number, the device number
|
||||
and a ``.pcap'' suffix.
|
||||
|
||||
In our example script, we will eventually see files named ``first-0-0.pcap''
|
||||
and ``first.1-0.pcap'' which are the pcap traces for node 0-device 0 and
|
||||
In our example script, we will eventually see files named ``myfirst-0-0.pcap''
|
||||
and ``myfirst.1-0.pcap'' which are the pcap traces for node 0-device 0 and
|
||||
node 1-device 0, respectively.
|
||||
|
||||
Once you have added the line of code to enable pcap tracing, you can run the
|
||||
script in the usual way:
|
||||
|
||||
@verbatim
|
||||
./waf --run scratch/first
|
||||
./waf --run scratch/myfirst
|
||||
@end verbatim
|
||||
|
||||
If you look at the top level directory of your distribution, you should now
|
||||
see three log files: @code{first.tr} is the ASCII trace file we have
|
||||
previously examined. @code{first-0-0.pcap} and @code{first-1-0.pcap}
|
||||
see three log files: @code{myfirst.tr} is the ASCII trace file we have
|
||||
previously examined. @code{myfirst-0-0.pcap} and @code{myfirst-1-0.pcap}
|
||||
are the new pcap files we just generated.
|
||||
|
||||
@subsubsection Reading output with tcpdump
|
||||
@cindex tcpdump
|
||||
The easiest thing to do at this point will be to use @code{tcpdump} to look
|
||||
at the @code{pcap} files. Output from dumping both files is shown below:
|
||||
at the @code{pcap} files.
|
||||
|
||||
@verbatim
|
||||
~/repos/ns-3-dev > /usr/sbin/tcpdump -r first-0-0.pcap -nn -tt
|
||||
reading from file first-0-0.pcap, link-type PPP (PPP)
|
||||
tcpdump -nn -tt -r myfirst-0-0.pcap
|
||||
reading from file myfirst-0-0.pcap, link-type PPP (PPP)
|
||||
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
|
||||
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
|
||||
~/repos/ns-3-dev > /usr/sbin/tcpdump -r first-1-0.pcap -nn -tt
|
||||
reading from file first-1-0.pcap, link-type PPP (PPP)
|
||||
|
||||
tcpdump -nn -tt -r myfirst-1-0.pcap
|
||||
reading from file myfirst-1-0.pcap, link-type PPP (PPP)
|
||||
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
|
||||
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
|
||||
~/repos/ns-3-dev >
|
||||
@end verbatim
|
||||
|
||||
You can see in the dump of ``first-0.0.pcap'' (the client device) that the
|
||||
You can see in the dump of @code{myfirst-0.0.pcap} (the client device) that the
|
||||
echo packet is sent at 2 seconds into the simulation. If you look at the
|
||||
second dump (of ``first-1-0.pcap'') you can see that packet being received
|
||||
at 2.257324 seconds. You see the packet being echoed at 2.257324 seconds
|
||||
second dump (@code{first-1-0.pcap}) you can see that packet being received
|
||||
at 2.257324 seconds. You see the packet being echoed back at 2.257324 seconds
|
||||
in the second dump, and finally, you see the packet being received back at
|
||||
the client in the first dump at 2.514648 seconds.
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
bool verbose = true;
|
||||
|
||||
uint32_t nCsma = 3;
|
||||
|
||||
CommandLine cmd;
|
||||
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
|
||||
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
|
||||
@@ -51,6 +51,8 @@ main (int argc, char *argv[])
|
||||
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
|
||||
}
|
||||
|
||||
nCsma = nCsma == 0 ? 1 : nCsma;
|
||||
|
||||
NodeContainer p2pNodes;
|
||||
p2pNodes.Create (2);
|
||||
|
||||
@@ -102,8 +104,8 @@ main (int argc, char *argv[])
|
||||
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
|
||||
PointToPointHelper::EnablePcap ("second", p2pDevices.Get (1));
|
||||
CsmaHelper::EnablePcap ("second", csmaDevices.Get (0), true);
|
||||
PointToPointHelper::EnablePcapAll ("second");
|
||||
CsmaHelper::EnablePcap ("second", csmaDevices.Get (1), true);
|
||||
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
// | external |
|
||||
// | Linux |
|
||||
// | Host |
|
||||
// | "left" |
|
||||
// | |
|
||||
// | "mytap" |
|
||||
// +----------+
|
||||
// | n0 n3 n4
|
||||
// | +--------+ +------------+ +------------+
|
||||
@@ -61,7 +62,7 @@
|
||||
// item).
|
||||
//
|
||||
// ./waf --run tap-wifi-dumbbell&
|
||||
// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev left gw 10.1.1.2
|
||||
// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev thetap gw 10.1.1.2
|
||||
// ping 10.1.3.4
|
||||
//
|
||||
// Take a look at the pcap traces and note that the timing reflects the
|
||||
@@ -77,9 +78,33 @@
|
||||
// traffic data rate and watch the ping timing change dramatically.
|
||||
//
|
||||
// ./waf --run "tap-wifi-dumbbell --ns3::OnOffApplication::DataRate=100kb/s"&
|
||||
// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev left gw 10.1.1.2
|
||||
// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev thetap gw 10.1.1.2
|
||||
// ping 10.1.3.4
|
||||
//
|
||||
// 4) Try to run this in UseLocal mode. This allows you to provide an existing
|
||||
// pre-configured tap device to the simulation. The IP address and MAC
|
||||
// address in this mode do not have to match those of the ns-3 device.
|
||||
//
|
||||
// sudo tunctl -t mytap
|
||||
// sudo ifconfig mytap hw ether 08:00:2e:00:00:01
|
||||
// sudo ifconfig mytap 10.1.1.1 netmask 255.255.255.0 up
|
||||
// ./waf --run "tap-wifi-dumbbell --mode=UseLocal --tapName=mytap"&
|
||||
// ping 10.1.1.3
|
||||
//
|
||||
// 5) Try to run this in UseBridge mode. This allows you to bridge an ns-3
|
||||
// simulation to an existing pre-configured bridge. This uses tap devices
|
||||
// just for illustration, you can create your own bridge if you want.
|
||||
//
|
||||
// sudo tunctl -t mytap1
|
||||
// sudo ifconfig mytap1 0.0.0.0 promisc up
|
||||
// sudo tunctl -t mytap2
|
||||
// sudo ifconfig mytap2 0.0.0.0 promisc up
|
||||
// sudo brctl addbr mybridge
|
||||
// sudo brctl addif mybridge mytap1
|
||||
// sudo brctl addif mybridge mytap2
|
||||
// sudo ifconfig mybridge 10.1.1.5 netmask 255.255.255.0 up
|
||||
// ./waf --run "tap-wifi-dumbbell --mode=UseBridge --tapName=mytap2"&
|
||||
// ping 10.1.1.3
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@@ -98,7 +123,12 @@ NS_LOG_COMPONENT_DEFINE ("TapDumbbellExample");
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
std::string mode = "ConfigureLocal";
|
||||
std::string tapName = "thetap";
|
||||
|
||||
CommandLine cmd;
|
||||
cmd.AddValue("mode", "Mode setting of TapBridge", mode);
|
||||
cmd.AddValue("tapName", "Name of the OS tap device", tapName);
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl"));
|
||||
@@ -145,9 +175,10 @@ main (int argc, char *argv[])
|
||||
ipv4Left.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer interfacesLeft = ipv4Left.Assign (devicesLeft);
|
||||
|
||||
TapBridgeHelper bridgeLeft (interfacesLeft.GetAddress (1));
|
||||
bridgeLeft.SetAttribute ("DeviceName", StringValue ("left"));
|
||||
bridgeLeft.Install (nodesLeft.Get (0), devicesLeft.Get (0));
|
||||
TapBridgeHelper tapBridge (interfacesLeft.GetAddress (1));
|
||||
tapBridge.SetAttribute ("Mode", StringValue (mode));
|
||||
tapBridge.SetAttribute ("DeviceName", StringValue (tapName));
|
||||
tapBridge.Install (nodesLeft.Get (0), devicesLeft.Get (0));
|
||||
|
||||
//
|
||||
// Now, create the right side.
|
||||
|
||||
@@ -57,9 +57,14 @@ static uint32_t txBytes = 2000000;
|
||||
void StartFlow(Ptr<Socket>, Ipv4Address, uint16_t);
|
||||
void WriteUntilBufferFull (Ptr<Socket>, uint32_t);
|
||||
|
||||
static void
|
||||
CwndTracer (uint32_t oldval, uint32_t newval)
|
||||
{
|
||||
NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
|
||||
@@ -67,9 +72,6 @@ int main (int argc, char *argv[])
|
||||
// LogComponentEnable("PacketSink", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpLargeTransfer", LOG_LEVEL_ALL);
|
||||
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
@@ -140,6 +142,9 @@ int main (int argc, char *argv[])
|
||||
Socket::CreateSocket (n0n1.Get (0), TcpSocketFactory::GetTypeId ());
|
||||
localSocket->Bind ();
|
||||
|
||||
// Trace changes to the congestion window
|
||||
Config::ConnectWithoutContext ("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow", MakeCallback (&CwndTracer));
|
||||
|
||||
// ...and schedule the sending "Application"; This is similar to what an
|
||||
// ns3::Application subclass would do internally.
|
||||
Simulator::ScheduleNow (&StartFlow, localSocket,
|
||||
|
||||
@@ -43,6 +43,11 @@ using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpNscLfn");
|
||||
|
||||
static void
|
||||
CwndTracer (uint32_t oldval, uint32_t newval)
|
||||
{
|
||||
NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
@@ -133,6 +138,10 @@ int main (int argc, char *argv[])
|
||||
clientApp.Stop (Seconds (runtime + 1.0 + i));
|
||||
}
|
||||
|
||||
// Trace changes to the congestion window
|
||||
Config::ConnectWithoutContext ("/NodeList/1/$ns3::NscTcpL4Protocol/SocketList/0/CongestionWindow",
|
||||
MakeCallback (&CwndTracer));
|
||||
|
||||
// This tells ns-3 to generate pcap traces.
|
||||
PointToPointHelper::EnablePcapAll ("tcp-nsc-lfn");
|
||||
|
||||
|
||||
@@ -40,11 +40,10 @@ NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
bool verbose = true;
|
||||
|
||||
uint32_t nCsma = 3;
|
||||
uint32_t nWifi = 3;
|
||||
|
||||
CommandLine cmd;
|
||||
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
|
||||
cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi);
|
||||
@@ -162,7 +161,7 @@ main (int argc, char *argv[])
|
||||
|
||||
Simulator::Stop (Seconds (10.0));
|
||||
|
||||
PointToPointHelper::EnablePcap ("third", p2pDevices.Get (0));
|
||||
PointToPointHelper::EnablePcapAll ("third");
|
||||
YansWifiPhyHelper::EnablePcap ("third", apDevices.Get (0));
|
||||
CsmaHelper::EnablePcap ("third", csmaDevices.Get (0), true);
|
||||
|
||||
|
||||
@@ -157,8 +157,6 @@ int main (int argc, char *argv[])
|
||||
wifiX += 20.0;
|
||||
}
|
||||
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
|
||||
Address dest;
|
||||
std::string protocol;
|
||||
if (sendIp)
|
||||
|
||||
@@ -623,40 +623,47 @@ Names::Delete (void)
|
||||
NamesPriv::Delete ();
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Names::Add (std::string name, Ptr<Object> object)
|
||||
{
|
||||
return NamesPriv::Get ()->Add (name, object);
|
||||
bool result = NamesPriv::Get ()->Add (name, object);
|
||||
NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Names::Rename (std::string oldpath, std::string newname)
|
||||
{
|
||||
return NamesPriv::Get ()->Rename (oldpath, newname);
|
||||
bool result = NamesPriv::Get ()->Rename (oldpath, newname);
|
||||
NS_ABORT_MSG_UNLESS (result, "Names::Rename(): Error renaming " << oldpath << " to " << newname);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Names::Add (std::string path, std::string name, Ptr<Object> object)
|
||||
{
|
||||
return NamesPriv::Get ()->Add (path, name, object);
|
||||
bool result = NamesPriv::Get ()->Add (path, name, object);
|
||||
NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding " << path << " " << name);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Names::Rename (std::string path, std::string oldname, std::string newname)
|
||||
{
|
||||
return NamesPriv::Get ()->Rename (path, oldname, newname);
|
||||
bool result = NamesPriv::Get ()->Rename (path, oldname, newname);
|
||||
NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << path << " " << oldname << " to " << newname);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
|
||||
{
|
||||
return NamesPriv::Get ()->Add (context, name, object);
|
||||
bool result = NamesPriv::Get ()->Add (context, name, object);
|
||||
NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name << " under context " << &context);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Names::Rename (Ptr<Object> context, std::string oldname, std::string newname)
|
||||
{
|
||||
return NamesPriv::Get ()->Rename (context, oldname, newname);
|
||||
bool result = NamesPriv::Get ()->Rename (context, oldname, newname);
|
||||
NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << oldname << " to " << newname << " under context " <<
|
||||
&context);
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -730,50 +737,53 @@ NamesTest::RunTests (void)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
//
|
||||
// Names::Add and Names::Rename return void to align with the Config API.
|
||||
// The private versions of these functions do return error codes so we
|
||||
// can test to make sure errors are detected. Names::Add and
|
||||
// Names::Rename check for these error codes and abort if an error was
|
||||
// detected. So when we expect that an error should be detected, we
|
||||
// have to call the private routine to avoid a fatal error popping.
|
||||
//
|
||||
// Name a couple of objects at the root level
|
||||
//
|
||||
Ptr<TestObject> client = CreateObject<TestObject> ();
|
||||
result = Names::Add ("Client", client);
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Add ("Client", client);
|
||||
|
||||
Ptr<TestObject> server = CreateObject<TestObject> ();
|
||||
result = Names::Add ("Server", server);
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Add ("Server", server);
|
||||
|
||||
//
|
||||
// We shouldn't be able to add another name to a previously named object
|
||||
//
|
||||
result = Names::Add ("Not Client", client);
|
||||
result = NamesPriv::Get ()->Add ("Not Client", client);
|
||||
NS_TEST_ASSERT_EQUAL (result, false);
|
||||
|
||||
//
|
||||
// We shouldn't be able to duplicate a name at the root level.
|
||||
//
|
||||
Ptr<TestObject> secondClient = CreateObject<TestObject> ();
|
||||
result = Names::Add ("Client", secondClient);
|
||||
result = NamesPriv::Get ()->Add ("Client", secondClient);
|
||||
NS_TEST_ASSERT_EQUAL (result, false);
|
||||
|
||||
//
|
||||
// We should be able to add a new name in the first object's context
|
||||
//
|
||||
Ptr<TestObject> clientEth0 = CreateObject<TestObject> ();
|
||||
result = Names::Add (client, "eth0", clientEth0);
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Add (client, "eth0", clientEth0);
|
||||
|
||||
//
|
||||
// We shouldn't be able to duplicate a name in that context.
|
||||
//
|
||||
Ptr<TestObject> secondClientEth0 = CreateObject<TestObject> ();
|
||||
result = Names::Add (client, "eth0", secondClientEth0);
|
||||
result = NamesPriv::Get ()->Add (client, "eth0", secondClientEth0);
|
||||
NS_TEST_ASSERT_EQUAL (result, false);
|
||||
|
||||
//
|
||||
// We should be able to add the same name in the second object's context
|
||||
//
|
||||
Ptr<TestObject> serverEth0 = CreateObject<TestObject> ();
|
||||
result = Names::Add (server, "eth0", serverEth0);
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Add (server, "eth0", serverEth0);
|
||||
|
||||
//
|
||||
// We should be able to find the short names for the objects we created
|
||||
@@ -879,32 +889,28 @@ NamesTest::RunTests (void)
|
||||
// in the name.
|
||||
//
|
||||
Ptr<TestObject> router1 = CreateObject<TestObject> ();
|
||||
result = Names::Add ("/Names/Router1", router1);
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Add ("/Names/Router1", router1);
|
||||
|
||||
//
|
||||
// We should be able to add objects while not including the root of the namespace
|
||||
// in the name.
|
||||
//
|
||||
Ptr<TestObject> router2 = CreateObject<TestObject> ();
|
||||
result = Names::Add ("Router2", router2);
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Add ("Router2", router2);
|
||||
|
||||
//
|
||||
// We should be able to add sub-objects while including the root of the namespace
|
||||
// in the name.
|
||||
//
|
||||
Ptr<TestObject> router1Eth0 = CreateObject<TestObject> ();
|
||||
result = Names::Add ("/Names/Router1/eth0", router1Eth0);
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Add ("/Names/Router1/eth0", router1Eth0);
|
||||
|
||||
//
|
||||
// We should be able to add sub-objects while not including the root of the namespace
|
||||
// in the name.
|
||||
//
|
||||
Ptr<TestObject> router2Eth0 = CreateObject<TestObject> ();
|
||||
result = Names::Add ("Router2/eth0", router2Eth0);
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Add ("Router2/eth0", router2Eth0);
|
||||
|
||||
//
|
||||
// We should be able to find these objects in the same two ways
|
||||
@@ -937,20 +943,17 @@ NamesTest::RunTests (void)
|
||||
// We have a pile of names defined. We should be able to rename them in the
|
||||
// usual ways.
|
||||
//
|
||||
result = Names::Rename ("/Names/Router1", "RouterX");
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Rename ("/Names/Router1", "RouterX");
|
||||
|
||||
foundObject = Names::Find<TestObject> ("/Names/RouterX");
|
||||
NS_TEST_ASSERT_EQUAL (foundObject, router1);
|
||||
|
||||
result = Names::Rename ("Router2", "RouterY");
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Rename ("Router2", "RouterY");
|
||||
|
||||
foundObject = Names::Find<TestObject> ("RouterY");
|
||||
NS_TEST_ASSERT_EQUAL (foundObject, router2);
|
||||
|
||||
result = Names::Rename ("/Names/RouterX/eth0", "ath0");
|
||||
NS_TEST_ASSERT_EQUAL (result, true);
|
||||
Names::Rename ("/Names/RouterX/eth0", "ath0");
|
||||
|
||||
foundObject = Names::Find<TestObject> ("/Names/RouterX/ath0");
|
||||
NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
|
||||
@@ -963,7 +966,7 @@ NamesTest::RunTests (void)
|
||||
// object.
|
||||
//
|
||||
|
||||
result = Names::Rename ("/Names/RouterX", "RouterY");
|
||||
result = NamesPriv::Get ()->Rename ("/Names/RouterX", "RouterY");
|
||||
NS_TEST_ASSERT_EQUAL (result, false);
|
||||
|
||||
Names::Delete ();
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
* prepended with a path to that object.
|
||||
* \param obj A smart pointer to the object itself.
|
||||
*/
|
||||
static bool Add (std::string name, Ptr<Object> obj);
|
||||
static void Add (std::string name, Ptr<Object> obj);
|
||||
|
||||
/**
|
||||
* \brief An intermediate form of Names::Add allowing you to provide a path to
|
||||
@@ -96,11 +96,9 @@ public:
|
||||
* \param name The name of the object you want to associate.
|
||||
* \param obj A smart pointer to the object itself.
|
||||
*
|
||||
* \returns true if the association was successfully completed, false otherwise
|
||||
*
|
||||
* \see Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object);
|
||||
*/
|
||||
static bool Add (std::string path, std::string name, Ptr<Object> object);
|
||||
static void Add (std::string path, std::string name, Ptr<Object> object);
|
||||
|
||||
/**
|
||||
* \brief A low-level form of Names::Add allowing you to specify the path to
|
||||
@@ -148,10 +146,8 @@ public:
|
||||
* under which you want this new name to be defined.
|
||||
* \param name The name of the object you want to associate.
|
||||
* \param obj A smart pointer to the object itself.
|
||||
*
|
||||
* \returns true if the association was successfully completed, false otherwise
|
||||
*/
|
||||
static bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
|
||||
static void Add (Ptr<Object> context, std::string name, Ptr<Object> object);
|
||||
|
||||
/**
|
||||
* \brief Rename a previously associated name.
|
||||
@@ -178,11 +174,9 @@ public:
|
||||
* \param oldpath The current path name to the object you want to change.
|
||||
* \param newname The new name of the object you want to change.
|
||||
*
|
||||
* \returns true if the name change was successfully completed, false otherwise
|
||||
*
|
||||
* \see Names::Add (std::string name, Ptr<Object> obj)
|
||||
*/
|
||||
static bool Rename (std::string oldpath, std::string newname);
|
||||
static void Rename (std::string oldpath, std::string newname);
|
||||
|
||||
/**
|
||||
* \brief An intermediate form of Names::Rename allowing you to provide a path to
|
||||
@@ -203,10 +197,8 @@ public:
|
||||
* you want this name change to occur (cf. directory).
|
||||
* \param oldname The currently defined name of the object.
|
||||
* \param newname The new name you want the object to have.
|
||||
*
|
||||
* \returns true if the name change was successfully completed, false otherwise
|
||||
*/
|
||||
static bool Rename (std::string path, std::string oldname, std::string newname);
|
||||
static void Rename (std::string path, std::string oldname, std::string newname);
|
||||
|
||||
/**
|
||||
* \brief A low-level form of Names::Rename allowing you to specify the path to
|
||||
@@ -244,10 +236,8 @@ public:
|
||||
* under which you want this new name to be defined.
|
||||
* \param oldname The current shortname of the object you want to change.
|
||||
* \param newname The new shortname of the object you want to change.
|
||||
*
|
||||
* \returns true if the name change was successfully completed, false otherwise
|
||||
*/
|
||||
static bool Rename (Ptr<Object> context, std::string oldname, std::string newname);
|
||||
static void Rename (Ptr<Object> context, std::string oldname, std::string newname);
|
||||
|
||||
/**
|
||||
* Given a pointer to an object, look to see if that object has a name
|
||||
|
||||
@@ -11,7 +11,7 @@ def configure(conf):
|
||||
|
||||
# Check for POSIX threads
|
||||
test_env = conf.env.copy()
|
||||
if Options.platform != 'darwin':
|
||||
if Options.platform != 'darwin' and Options.platform != 'cygwin':
|
||||
test_env.append_value('LINKFLAGS', '-pthread')
|
||||
test_env.append_value('CXXFLAGS', '-pthread')
|
||||
test_env.append_value('CCFLAGS', '-pthread')
|
||||
@@ -30,7 +30,7 @@ int main ()
|
||||
mandatory=False)
|
||||
if have_pthread:
|
||||
# darwin accepts -pthread but prints a warning saying it is ignored
|
||||
if Options.platform != 'darwin':
|
||||
if Options.platform != 'darwin' and Options.platform != 'cygwin':
|
||||
conf.env['CXXFLAGS_PTHREAD'] = '-pthread'
|
||||
conf.env['CCFLAGS_PTHREAD'] = '-pthread'
|
||||
conf.env['LINKFLAGS_PTHREAD'] = '-pthread'
|
||||
|
||||
@@ -61,7 +61,6 @@ public:
|
||||
|
||||
/**
|
||||
* Enumeration of the types of packets supported in the class.
|
||||
*
|
||||
*/
|
||||
enum EncapsulationMode {
|
||||
ILLEGAL, /**< Encapsulation mode not set */
|
||||
|
||||
@@ -167,6 +167,7 @@ PointToPointNetDevice::PointToPointNetDevice ()
|
||||
|
||||
PointToPointNetDevice::~PointToPointNetDevice ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -226,8 +227,8 @@ PointToPointNetDevice::TransmitStart (Ptr<Packet> p)
|
||||
//
|
||||
NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
|
||||
m_txMachineState = BUSY;
|
||||
m_phyTxBeginTrace (m_currentPkt);
|
||||
m_currentPkt = p;
|
||||
m_phyTxBeginTrace (m_currentPkt);
|
||||
|
||||
Time txTime = Seconds (m_bps.CalculateTxTime(p->GetSize()));
|
||||
Time txCompleteTime = txTime + m_tInterframeGap;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/enum.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/realtime-simulator-impl.h"
|
||||
@@ -48,10 +49,7 @@
|
||||
// if you are running in an environment where you have got to run as root,
|
||||
// such as ORBIT or CORE.
|
||||
//
|
||||
// sudo tunctl -t tap0
|
||||
// sudo ifconfig tap0 hw ether 00:00:00:00:00:01
|
||||
// sudo ifconfig tap0 10.1.1.1 netmask 255.255.255.0 up
|
||||
//
|
||||
|
||||
|
||||
// #define NO_CREATOR
|
||||
|
||||
@@ -82,22 +80,25 @@ TapBridge::GetTypeId (void)
|
||||
MakeStringAccessor (&TapBridge::m_tapDeviceName),
|
||||
MakeStringChecker ())
|
||||
.AddAttribute ("Gateway",
|
||||
"The IP address of the default gateway to assign to the tap device.",
|
||||
"The IP address of the default gateway to assign to the host machine, when in ConfigureLocal mode.",
|
||||
Ipv4AddressValue ("255.255.255.255"),
|
||||
MakeIpv4AddressAccessor (&TapBridge::m_tapGateway),
|
||||
MakeIpv4AddressChecker ())
|
||||
.AddAttribute ("IpAddress",
|
||||
"The IP address to assign to the tap device.",
|
||||
"The IP address to assign to the tap device, when in ConfigureLocal mode. "
|
||||
"This address will override the discovered IP address of the simulated device.",
|
||||
Ipv4AddressValue ("255.255.255.255"),
|
||||
MakeIpv4AddressAccessor (&TapBridge::m_tapIp),
|
||||
MakeIpv4AddressChecker ())
|
||||
.AddAttribute ("MacAddress",
|
||||
"The MAC address to assign to the tap device.",
|
||||
"The MAC address to assign to the tap device, when in ConfigureLocal mode. "
|
||||
"This address will override the discovered MAC address of the simulated device.",
|
||||
Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
|
||||
MakeMac48AddressAccessor (&TapBridge::m_tapMac),
|
||||
MakeMac48AddressChecker ())
|
||||
.AddAttribute ("Netmask",
|
||||
"The network mask to assign to the tap device.",
|
||||
"The network mask to assign to the tap device, when in ConfigureLocal mode. "
|
||||
"This address will override the discovered MAC address of the simulated device.",
|
||||
Ipv4MaskValue ("255.255.255.255"),
|
||||
MakeIpv4MaskAccessor (&TapBridge::m_tapNetmask),
|
||||
MakeIpv4MaskChecker ())
|
||||
@@ -111,6 +112,13 @@ TapBridge::GetTypeId (void)
|
||||
TimeValue (Seconds (0.)),
|
||||
MakeTimeAccessor (&TapBridge::m_tStop),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("Mode",
|
||||
"The operating and configuration mode to use.",
|
||||
EnumValue (USE_LOCAL),
|
||||
MakeEnumAccessor (&TapBridge::SetMode),
|
||||
MakeEnumChecker (CONFIGURE_LOCAL, "ConfigureLocal",
|
||||
USE_LOCAL, "UseLocal",
|
||||
USE_BRIDGE, "UseBridge"))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -122,7 +130,8 @@ TapBridge::TapBridge ()
|
||||
m_sock (-1),
|
||||
m_startEvent (),
|
||||
m_stopEvent (),
|
||||
m_readThread (0)
|
||||
m_readThread (0),
|
||||
m_learnedMac (Mac48Address ("ff:ff:ff:ff:ff:ff"))
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
Start (m_tStart);
|
||||
@@ -215,38 +224,53 @@ TapBridge::CreateTap (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
#ifdef NO_CREATOR
|
||||
//
|
||||
// The TapBridge has three distinct operating modes. At this point, the
|
||||
// differences revolve around who is responsible for creating and configuring
|
||||
// the underlying network tap that we use. In ConfigureLocal mode, the
|
||||
// TapBridge has the responsibility for creating and configuring the TAP.
|
||||
//
|
||||
// In come cases, can you say FreeBSD, the tap-creator just gets in the way.
|
||||
// in this case, just define NO_CREATOR, manually set up your tap device and
|
||||
// just open and use it.
|
||||
// In UseBridge or UseLocal modes, the user will provide us a configuration
|
||||
// and we have to adapt to it. For example, in UseLocal mode, the user will
|
||||
// be configuring a tap device outside the scope of the ns-3 simulation and
|
||||
// will be expecting us to work with it. The user will do something like:
|
||||
//
|
||||
// sudo tunctl -t tap0
|
||||
// sudo ifconfig tap0 hw ether 00:00:00:00:00:01
|
||||
// sudo ifconfig tap0 10.1.1.1 netmask 255.255.255.0 up
|
||||
//
|
||||
// Creation and management of Tap devices is done via the tun device
|
||||
// The user will then set the "Mode" Attribute of the TapBridge to "UseLocal"
|
||||
// and the "DeviceName" Attribute to "tap0" in this case.
|
||||
//
|
||||
m_sock = open ("/dev/net/tun", O_RDWR);
|
||||
NS_ABORT_MSG_IF (m_sock == -1, "TapBridge::CreateTap(): could not open /dev/net/tun: " << strerror (errno));
|
||||
|
||||
// In ConfigureLocal mode, the user is asking the TapBridge to do the
|
||||
// configuration and create a TAP with the provided "DeviceName" with which
|
||||
// the user can later do what she wants. We need to extract values for the
|
||||
// MAC address, IP address, net mask, etc, from the simualtion itself and
|
||||
// use them to initialize corresponding values on the created tap device.
|
||||
//
|
||||
// Allocate a tap device, making sure that it will not send the tun_pi header.
|
||||
// If we provide a null name to the ifr.ifr_name, we tell the kernel to pick
|
||||
// a name for us (i.e., tapn where n = 0..255
|
||||
// In UseBridge mode, the user is asking us to use an existing tap device
|
||||
// has been included in an OS bridge. She is asking us to take the simulated
|
||||
// net device and logically add it to the existing bridge. We expect that
|
||||
// the user has done something like:
|
||||
//
|
||||
struct ifreq ifr;
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strcpy (ifr.ifr_name, m_tapDeviceName.c_str ());
|
||||
int status = ioctl (m_sock, TUNSETIFF, (void *) &ifr);
|
||||
NS_ABORT_MSG_IF (status == -1, "TapBridge::CreateTap(): could not open device " << m_tapDeviceName <<
|
||||
": " << strerror (errno));
|
||||
|
||||
#else // use the tap-creator
|
||||
|
||||
// sudo brctl addbr mybridge
|
||||
// sudo tunctl -t mytap
|
||||
// sudo ifconfig mytap hw ether 00:00:00:00:00:01
|
||||
// sudo ifconfig mytap 0.0.0.0 up
|
||||
// sudo brctl addif mybridge mytap
|
||||
// sudo brctl addif mybridge ...
|
||||
// sudo ifconfig mybridge 10.1.1.1 netmask 255.255.255.0 up
|
||||
//
|
||||
// We want to create a tap device on the host. Unfortunately for us
|
||||
// you have to have root privileges to do that. Instead of running the
|
||||
// entire simulation as root, we decided to make a small program who's whole
|
||||
// reason for being is to run as suid root and do what it takes to create the
|
||||
// tap. We're going to fork and exec that program soon, but we need to have
|
||||
// The bottom line at this point is that we want to either create or use a
|
||||
// tap device on the host based on the verb part "Use" or "Configure" of the
|
||||
// operating mode. Unfortunately for us you have to have root privileges to
|
||||
// do either. Instead of running the entire simulation as root, we decided
|
||||
// to make a small program who's whole reason for being is to run as suid
|
||||
// root and do what it takes to create the tap. We're just going to pass
|
||||
// off the configuration information to that program and let it deal with
|
||||
// the situation.
|
||||
//
|
||||
// We're going to fork and exec that program soon, but first we need to have
|
||||
// a socket to talk to it with. So we create a local interprocess (Unix)
|
||||
// socket for that purpose.
|
||||
//
|
||||
@@ -282,7 +306,8 @@ TapBridge::CreateTap (void)
|
||||
NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
|
||||
//
|
||||
// Fork and exec the process to create our socket. If we're us (the parent)
|
||||
// we wait for the child (the creator) to complete and read the socket it created using the ancillary data mechanism.
|
||||
// we wait for the child (the creator) to complete and read the socket it
|
||||
// created and passed back using the ancillary data mechanism.
|
||||
//
|
||||
pid_t pid = ::fork ();
|
||||
if (pid == 0)
|
||||
@@ -300,9 +325,10 @@ TapBridge::CreateTap (void)
|
||||
// -i<IP-address> The IP address to assign to the new tap device;
|
||||
// -m<MAC-address> The MAC-48 address to assign to the new tap device;
|
||||
// -n<network-mask> The network mask to assign to the new tap device;
|
||||
// -o<operating mode> The operating mode of the bridge (1=ConfigureLocal, 2=UseLocal, 3=UseBridge)
|
||||
// -p<path> the path to the unix socket described above.
|
||||
//
|
||||
// Example tap-creator -dnewdev -g1.2.3.2 -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -pblah
|
||||
// Example tap-creator -dnewdev -g1.2.3.2 -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -o1 -pblah
|
||||
//
|
||||
// We want to get as much of this stuff automagically as possible.
|
||||
//
|
||||
@@ -382,6 +408,21 @@ TapBridge::CreateTap (void)
|
||||
ossNetmask << "-n" << m_tapNetmask;
|
||||
}
|
||||
|
||||
std::ostringstream ossMode;
|
||||
ossMode << "-o";
|
||||
if (m_mode == CONFIGURE_LOCAL)
|
||||
{
|
||||
ossMode << "1";
|
||||
}
|
||||
else if (m_mode == USE_LOCAL)
|
||||
{
|
||||
ossMode << "2";
|
||||
}
|
||||
else
|
||||
{
|
||||
ossMode << "3";
|
||||
}
|
||||
|
||||
std::ostringstream ossPath;
|
||||
ossPath << "-p" << path;
|
||||
//
|
||||
@@ -394,7 +435,8 @@ TapBridge::CreateTap (void)
|
||||
ossIp.str ().c_str (), // argv[3] (-i<IP address>)
|
||||
ossMac.str ().c_str (), // argv[4] (-m<MAC address>)
|
||||
ossNetmask.str ().c_str (), // argv[5] (-n<net mask>)
|
||||
ossPath.str ().c_str (), // argv[6] (-p<path>)
|
||||
ossMode.str ().c_str (), // argv[6] (-o<operating mode>)
|
||||
ossPath.str ().c_str (), // argv[7] (-p<path>)
|
||||
(char *)NULL);
|
||||
|
||||
//
|
||||
@@ -484,14 +526,14 @@ TapBridge::CreateTap (void)
|
||||
|
||||
//
|
||||
// Now we can actually receive the interesting bits from the tap
|
||||
// creator process.
|
||||
// creator process. Lots of pain to get four bytes.
|
||||
//
|
||||
ssize_t bytesRead = recvmsg (sock, &msg, 0);
|
||||
NS_ABORT_MSG_IF (bytesRead != sizeof(int), "TapBridge::CreateTap(): Wrong byte count from socket creator");
|
||||
|
||||
//
|
||||
// There may be a number of message headers/ancillary data arrays coming in.
|
||||
// Let's look for the one with a type SCM_RIGHTS which indicates it' the
|
||||
// Let's look for the one with a type SCM_RIGHTS which indicates it's the
|
||||
// one we're interested in.
|
||||
//
|
||||
struct cmsghdr *cmsg;
|
||||
@@ -521,7 +563,6 @@ TapBridge::CreateTap (void)
|
||||
}
|
||||
NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
|
||||
}
|
||||
#endif // use the tap-creator
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -531,19 +572,19 @@ TapBridge::FindCreator (std::string creatorName)
|
||||
|
||||
std::list<std::string> locations;
|
||||
|
||||
// in repo
|
||||
// The path to the bits if we're sitting in the root of the repo
|
||||
locations.push_back ("./build/optimized/src/devices/tap-bridge/");
|
||||
locations.push_back ("./build/debug/src/devices/tap-bridge/");
|
||||
|
||||
// in src
|
||||
// if in src
|
||||
locations.push_back ("../build/optimized/src/devices/tap-bridge/");
|
||||
locations.push_back ("../build/debug/src/devices/tap-bridge/");
|
||||
|
||||
// in src/devices
|
||||
// if in src/devices
|
||||
locations.push_back ("../../build/optimized/src/devices/tap-bridge/");
|
||||
locations.push_back ("../../build/debug/src/devices/tap-bridge/");
|
||||
|
||||
// in src/devices/tap-bridge
|
||||
// if in src/devices/tap-bridge
|
||||
locations.push_back ("../../../build/optimized/src/devices/tap-bridge/");
|
||||
locations.push_back ("../../../build/debug/src/devices/tap-bridge/");
|
||||
|
||||
@@ -568,12 +609,15 @@ TapBridge::ReadThread (void)
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
//
|
||||
// It's important to remember that we're in a completely different thread than the simulator is running in. We
|
||||
// need to synchronize with that other thread to get the packet up into ns-3. What we will need to do is to schedule
|
||||
// a method to deal with the packet using the multithreaded simulator we are most certainly running. However, I just
|
||||
// said it -- we are talking about two threads here, so it is very, very dangerous to do any kind of reference couning
|
||||
// on a shared object. Just don't do it. So what we're going to do is to allocate a buffer on the heap and pass that
|
||||
// buffer into the ns-3 context thread where it will create the packet.
|
||||
// It's important to remember that we're in a completely different thread
|
||||
// than the simulator is running in. We need to synchronize with that
|
||||
// other thread to get the packet up into ns-3. What we will need to do
|
||||
// is to schedule a method to deal with the packet using the multithreaded
|
||||
// simulator we are most certainly running. However, I just said it -- we
|
||||
// are talking about two threads here, so it is very, very dangerous to do
|
||||
// any kind of reference counting on a shared object. Just don't do it.
|
||||
// So what we're going to do is to allocate a buffer on the heap and pass
|
||||
// that buffer into the ns-3 context thread where it will create the packet.
|
||||
//
|
||||
int32_t len = -1;
|
||||
|
||||
@@ -582,11 +626,12 @@ TapBridge::ReadThread (void)
|
||||
uint32_t bufferSize = 65536;
|
||||
uint8_t *buf = (uint8_t *)malloc (bufferSize);
|
||||
NS_ABORT_MSG_IF (buf == 0, "TapBridge::ReadThread(): malloc packet buffer failed");
|
||||
NS_LOG_LOGIC ("Calling read on tap device socket fd");
|
||||
NS_LOG_LOGIC ("Calling read on tap device socket fd " << m_sock);
|
||||
len = read (m_sock, buf, bufferSize);
|
||||
|
||||
if (len == -1)
|
||||
{
|
||||
NS_LOG_INFO ("TapBridge::ReadThread(): Returning");
|
||||
free (buf);
|
||||
buf = 0;
|
||||
return;
|
||||
@@ -606,7 +651,31 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len)
|
||||
NS_LOG_FUNCTION (buf << len);
|
||||
|
||||
//
|
||||
// Create a packet out of the buffer we received and free that buffer.
|
||||
// There are three operating modes for the TapBridge
|
||||
//
|
||||
// CONFIGURE_LOCAL means that ns-3 will create and configure a tap device
|
||||
// and we are expected to use it. The tap device and the ns-3 net device
|
||||
// will have the same MAC address by definition. Thus Send and SendFrom
|
||||
// are equivalent in this case. We use Send to allow all ns-3 devices to
|
||||
// participate in this mode.
|
||||
//
|
||||
// USE_LOCAL mode tells us that we have got to USE a pre-created tap device
|
||||
// that will have a different MAC address from the ns-3 net device. We
|
||||
// also enforce the requirement that there will only be one MAC address
|
||||
// bridged on the Linux side so we can use Send (instead of SendFrom) in
|
||||
// the linux to ns-3 direction. Again, all ns-3 devices can participate
|
||||
// in this mode.
|
||||
//
|
||||
// USE_BRIDGE mode tells us that we are logically extending a Linux bridge
|
||||
// on which lies our tap device. In this case there may be many linux
|
||||
// net devices on the other side of the bridge and so we must use SendFrom
|
||||
// to preserve the possibly many source addresses. Thus, ns-3 devices
|
||||
// must support SendFrom in order to be considered for USE_BRIDGE mode.
|
||||
//
|
||||
|
||||
//
|
||||
// First, create a packet out of the byte buffer we received and free that
|
||||
// buffer.
|
||||
//
|
||||
Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
|
||||
free (buf);
|
||||
@@ -633,9 +702,74 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len)
|
||||
NS_LOG_LOGIC ("Pkt source is " << src);
|
||||
NS_LOG_LOGIC ("Pkt destination is " << dst);
|
||||
NS_LOG_LOGIC ("Pkt LengthType is " << type);
|
||||
if (m_mode == USE_LOCAL)
|
||||
{
|
||||
//
|
||||
// Packets we are going to forward should not be from a broadcast src
|
||||
//
|
||||
NS_ASSERT_MSG (Mac48Address::ConvertFrom (src) != Mac48Address ("ff:ff:ff:ff:ff:ff"),
|
||||
"TapBridge::ForwardToBridgedDevice: Source addr is broadcast");
|
||||
//
|
||||
// Remember the Mac address since we are going to spoof it when we go
|
||||
// the other way.
|
||||
//
|
||||
m_learnedMac = Mac48Address::ConvertFrom (src);
|
||||
NS_LOG_LOGIC ("Learned MacAddr is " << m_learnedMac);
|
||||
|
||||
//
|
||||
// If we are operating in USE_LOCAL mode, we may be attached to an ns-3
|
||||
// device that does not support bridging (SupportsSendFrom returns false).
|
||||
// The whole point of this mode is really to support this case. We allow
|
||||
// only packets from one source MAC to flow across the TapBridge in this
|
||||
// mode and will spoof that address when packets flow the other way.
|
||||
// Since we will be doing this spoofing, we can relax the normal bridged
|
||||
// device requirement to support SendFrom and use Send.
|
||||
//
|
||||
NS_LOG_LOGIC ("Forwarding packet to ns-3 device via Send()");
|
||||
m_bridgedDevice->Send (packet, dst, type);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// If we are operating in USE_BRIDGE mode, we have the
|
||||
// situation described below:
|
||||
//
|
||||
// Other Device <-bridge-> Tap Device <-bridge-> ns3 device
|
||||
// Mac Addr A Mac Addr B Mac Addr C
|
||||
//
|
||||
// In Linux, "Other Device" and "Tap Device" are bridged together. By this
|
||||
// we mean that a user has sone something in Linux like:
|
||||
//
|
||||
// brctl addbr mybridge
|
||||
// brctl addif other-device
|
||||
// brctl addif tap-device
|
||||
//
|
||||
// In USE_BRIDGE mode, we want to logically extend this Linux behavior to the
|
||||
// simulated ns3 device and make it appear as if it is connected to the Linux
|
||||
// subnet. As you may expect, this means that we need to act like a real
|
||||
// Linux bridge and take all packets that come from "Tap Device" and ask
|
||||
// "ns3 Device" to send them down its directly connected network. Just like
|
||||
// in a normal everyday bridge we need to call SendFrom in order to preserve
|
||||
//the original packet's from address.
|
||||
//
|
||||
// If we are operating in CONFIGURE_LOCAL mode, we simply simply take all packets
|
||||
// that come from "Tap Device" and ask "ns3 Device" to send them down its
|
||||
// directly connected network. A normal bridge would need to call SendFrom
|
||||
// in order to preserve the original from address, but in CONFIGURE_LOCAL mode
|
||||
// the tap device and the ns-3 device have the same MAC address by definition so
|
||||
// we can call Send.
|
||||
//
|
||||
NS_LOG_LOGIC ("Forwarding packet");
|
||||
m_bridgedDevice->Send (packet, dst, type);
|
||||
|
||||
if (m_mode == USE_BRIDGE)
|
||||
{
|
||||
m_bridgedDevice->SendFrom (packet, src, dst, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERT_MSG (m_mode == CONFIGURE_LOCAL, "TapBridge::ForwardToBridgedDevice(): Internal error");
|
||||
m_bridgedDevice->Send (packet, dst, type);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Packet>
|
||||
@@ -646,7 +780,7 @@ TapBridge::Filter (Ptr<Packet> p, Address *src, Address *dst, uint16_t *type)
|
||||
|
||||
//
|
||||
// We have a candidate packet for injection into ns-3. We expect that since
|
||||
// it came over a socket that provides Ethernet packets, it sould be big
|
||||
// it came over a socket that provides Ethernet packets, it should be big
|
||||
// enough to hold an EthernetHeader. If it can't, we signify the packet
|
||||
// should be filtered out by returning 0.
|
||||
//
|
||||
@@ -720,7 +854,7 @@ TapBridge::SetBridgedNetDevice (Ptr<NetDevice> bridgedDevice)
|
||||
NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support eui 48 addresses: cannot be added to bridge.");
|
||||
}
|
||||
|
||||
if (!bridgedDevice->SupportsSendFrom ())
|
||||
if (m_mode == USE_BRIDGE && !bridgedDevice->SupportsSendFrom ())
|
||||
{
|
||||
NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support SendFrom: cannot be added to bridge.");
|
||||
}
|
||||
@@ -744,38 +878,72 @@ TapBridge::ReceiveFromBridgedDevice (
|
||||
{
|
||||
NS_LOG_FUNCTION (device << packet << protocol << src << dst << packetType);
|
||||
NS_ASSERT_MSG (device == m_bridgedDevice, "TapBridge::SetBridgedDevice: Received packet from unexpected device");
|
||||
|
||||
NS_LOG_DEBUG ("Packet UID is " << packet->GetUid ());
|
||||
|
||||
Mac48Address from = Mac48Address::ConvertFrom (src);
|
||||
Mac48Address to = Mac48Address::ConvertFrom (dst);
|
||||
//
|
||||
// There are three operating modes for the TapBridge
|
||||
//
|
||||
// CONFIGURE_LOCAL means that ns-3 will create and configure a tap device
|
||||
// and we are expected to use it. The tap device and the ns-3 net device
|
||||
// will have the same MAC address by definition.
|
||||
//
|
||||
// USE_LOCAL mode tells us that we have got to USE a pre-created tap device
|
||||
// that will have a different MAC address from the ns-3 net device. In this
|
||||
// case we will be spoofing the MAC address of a received packet to match
|
||||
// the single allowed address on the Linux side.
|
||||
//
|
||||
// USE_BRIDGE mode tells us that we are logically extending a Linux bridge
|
||||
// on which lies our tap device.
|
||||
//
|
||||
|
||||
//
|
||||
// We hooked the promiscuous mode protocol handler so we could get the
|
||||
// destination address of the actual packet. This means we will be getting
|
||||
// PACKET_OTHERHOST packets (not broadcast, not multicast, not unicast to
|
||||
// this device, but to some other address). We don't want to forward those
|
||||
// PACKET_OTHERHOST packets so just ignore them
|
||||
//
|
||||
if (packetType == PACKET_OTHERHOST)
|
||||
if (m_mode == CONFIGURE_LOCAL && packetType == PACKET_OTHERHOST)
|
||||
{
|
||||
//
|
||||
// We hooked the promiscuous mode protocol handler so we could get the
|
||||
// destination address of the actual packet. This means we will be
|
||||
// getting PACKET_OTHERHOST packets (not broadcast, not multicast, not
|
||||
// unicast to the ns-3 net device, but to some other address). In
|
||||
// CONFIGURE_LOCAL mode we are not interested in these packets since they
|
||||
// don't refer to the single MAC address shared by the ns-3 device and
|
||||
// the TAP device. If, however, we are in USE_LOCAL or USE_BRIDGE mode,
|
||||
// we want to act like a bridge and forward these PACKET_OTHERHOST
|
||||
// packets.
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// We have received a packet from the ns-3 net device that has been associated
|
||||
// with this bridge. We want to take these bits and send them off to the
|
||||
// Tap device on the Linux host. Once we do this, the bits in the packet will
|
||||
// percolate up through the stack on the Linux host.
|
||||
// with this bridge. We want to take these bits and send them off to the tap
|
||||
// device on the Linux host. The only question we have to answer is, what
|
||||
// should the destination address be?
|
||||
//
|
||||
// The ns-3 net device that is the source of these bits has removed the MAC
|
||||
// header, so we have to put one back on. This is a callback and by convention
|
||||
// uses Ptr<const Packet>, so we have to muck with a copy.
|
||||
// If we are in CONFIGURE_LOCAL mode, then the destination address is just
|
||||
// left alone since it can only be the shared single MAC address, broadcast
|
||||
// or multicast.
|
||||
//
|
||||
// If we are in USE_LOCAL mode, then we need to spoof the destination
|
||||
// address with the one we saved.
|
||||
//
|
||||
// If we are in USE_BRIDGE mode, then we need to do the equvalent of a
|
||||
// SendFrom and leave the source and destination alone.
|
||||
//
|
||||
Mac48Address from = Mac48Address::ConvertFrom (src);
|
||||
Mac48Address to;
|
||||
if (m_mode == USE_LOCAL)
|
||||
{
|
||||
to = Mac48Address::ConvertFrom (m_learnedMac);
|
||||
}
|
||||
else
|
||||
{
|
||||
to = Mac48Address::ConvertFrom (dst);
|
||||
}
|
||||
|
||||
Ptr<Packet> p = packet->Copy ();
|
||||
EthernetHeader header = EthernetHeader (false);
|
||||
header.SetSource (from);
|
||||
header.SetDestination (to);
|
||||
|
||||
header.SetLengthType (protocol);
|
||||
p->AddHeader (header);
|
||||
|
||||
@@ -831,6 +999,20 @@ TapBridge::GetAddress (void) const
|
||||
return m_address;
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::SetMode (enum Mode mode)
|
||||
{
|
||||
NS_LOG_FUNCTION (mode);
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
TapBridge::Mode
|
||||
TapBridge::GetMode (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::SetMtu (const uint16_t mtu)
|
||||
{
|
||||
|
||||
@@ -37,58 +37,79 @@ namespace ns3 {
|
||||
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* \ingroup devices
|
||||
* \defgroup tap-bridge TapBridge
|
||||
*
|
||||
* \brief A bridge to make it appear that a host is connected to an ns-3 net device.
|
||||
*
|
||||
* The Tap Bridge lives in a kind of a gray world somewhere between a Linux host and
|
||||
* an ns-3 bridge device. From the Linux perspective, this code appears as the user
|
||||
* mode handler for a Tap net device. That is, when the Linux host writes to the
|
||||
* /dev/tap device that we create for it, the write is redirected into the TapBridge
|
||||
* and from that perspective, becomes a read. The TapBridge then redirects the data
|
||||
* written (by the Linux host) to the tap device on out the ns-3 net device to which
|
||||
* we are bridged. When a packet comes in from the ns-3 world to the ns-3 net device
|
||||
* we are bridging, it appears via a callback from that net device. Our job is to
|
||||
* take those bits and write them back to the host using the user mode handler for
|
||||
* /dev/tapx. This write to the device will then appear to the Linux host as if a
|
||||
* packet has arrived on its device.
|
||||
*
|
||||
* The upshot is that the Tap Bridge appears to bridge a tap device on a Linux host
|
||||
* in the "real world" to an ns-3 net device in the simulation. In order to do this
|
||||
* we need a "ghost node" in the simulation to hold the bridged ns-3 net device and
|
||||
* this Tap Bridge. This node will not be able to actually do anything else in the
|
||||
* simulation with respect to the Tap Bridge and its bridged net device. This is
|
||||
* because:
|
||||
*
|
||||
* - Bits sent to the Tap Bridge using its Send() method are completely ignored.
|
||||
* The Tap Bridge is not, itself, connected to any network.
|
||||
* - The bridged ns-3 net device is has had its receive callback disconnected from
|
||||
* the ns-3 node and reconnected to the Tap Bridge. All data received by a
|
||||
* bridged device will be sent to the Linux host and will not be received by the
|
||||
* node. You can send but you cannot ever receive.
|
||||
*
|
||||
* You will be able to perform typical ns-3 operations on the ghost node if you so
|
||||
* desire. The internet stack, for example, must be there and functional on that
|
||||
* node in order to participate in IP address assignment and global routing.
|
||||
* However, interfaces talking any Tap Bridge or associated bridged net devices
|
||||
* will not work completely. If you understand exactly what you are doing, you
|
||||
* can set up other interfaces and devices on the ghost node and use them; but we
|
||||
* generally recommend that you treat this node as a ghost of the Linux host and
|
||||
* leave it alone.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup tap-bridge
|
||||
* \brief A bridge to make it appear that a host is connected to an ns-3 net device.
|
||||
*
|
||||
* \brief A bridge to make it appear that a real host process is connected to
|
||||
* an ns-3 net device.
|
||||
*
|
||||
* The Tap Bridge lives in a kind of a gray world somewhere between a
|
||||
* Linux host and an ns-3 bridge device. From the Linux perspective,
|
||||
* this code appears as the user mode handler for a Tap net device. That
|
||||
* is, when the Linux host writes to a /dev/tap device (that is either
|
||||
* manually or automatically created depending on basic operating mode
|
||||
* -- more on this later), the write is redirected into the TapBridge that
|
||||
* lives in the ns-3 world; and from this perspective, becomes a read.
|
||||
* In other words, a Linux process writes a packet to a tap device and
|
||||
* this packet is redirected to an ns-3 process where it is received by
|
||||
* the TapBridge as a result of a read operation there. The TapBridge
|
||||
* then sends the packet to the ns-3 net device to which it is bridged.
|
||||
* In the other direction, a packet received by an ns-3 net device is
|
||||
* bridged to the TapBridge (it appears via a callback from that net
|
||||
* device. The TapBridge then takes that packet and writes it back to
|
||||
* the host using the Linux TAP mechanism. This write to the device will
|
||||
* then appear to the Linux host as if a packet has arrived on its
|
||||
* device.
|
||||
*
|
||||
* The upshot is that the Tap Bridge appears to bridge a tap device on a
|
||||
* Linux host in the "real world" to an ns-3 net device in the simulation
|
||||
* and make is appear that a ns-3 net device is actually installed in the
|
||||
* Linux host. In order to do this on the ns-3 side, we need a "ghost
|
||||
* node" in the simulation to hold the bridged ns-3 net device and the
|
||||
* TapBridge. This node should not actually do anything else in the
|
||||
* simulation since its job is simply to make the net device appear in
|
||||
* Linux. This is not just arbitrary policy, it is because:
|
||||
*
|
||||
* - Bits sent to the Tap Bridge from higher layers in the ghost node (using
|
||||
* the TapBridge Send() method) are completely ignored. The Tap Bridge is
|
||||
* not, itself, connected to any network, neither in Linux nor in ns-3;
|
||||
* - The bridged ns-3 net device is has had its receive callback disconnected
|
||||
* from the ns-3 node and reconnected to the Tap Bridge. All data received
|
||||
* by a bridged device will be sent to the Linux host and will not be
|
||||
* received by the node. From the perspective of the ghost node, you can
|
||||
* send over this device but you cannot ever receive.
|
||||
*
|
||||
* Of course, if you understand all of the issues you can take control of
|
||||
* your own destiny and do whatever you want -- we do not actively
|
||||
* prevent you from using the ghost node for anything you decide. You
|
||||
* will be able to perform typical ns-3 operations on the ghost node if
|
||||
* you so desire. The internet stack, for example, must be there and
|
||||
* functional on that node in order to participate in IP address
|
||||
* assignment and global routing. However, as mentioned above,
|
||||
* interfaces talking any Tap Bridge or associated bridged net devices
|
||||
* will not work completely. If you understand exactly what you are
|
||||
* doing, you can set up other interfaces and devices on the ghost node
|
||||
* and use them; or take advantage of the operational send side of the
|
||||
* bridged devices to create traffic generators. We generally recommend
|
||||
* that you treat this node as a ghost of the Linux host and leave it to
|
||||
* itself, though.
|
||||
*/
|
||||
|
||||
class TapBridge : public NetDevice
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
/**
|
||||
* Enumeration of the operating modes supported in the class.
|
||||
*
|
||||
*/
|
||||
enum Mode {
|
||||
ILLEGAL, /**< mode not set */
|
||||
CONFIGURE_LOCAL, /**< ns-3 creates and configures tap device */
|
||||
USE_LOCAL, /**< ns-3 uses a pre-created tap, without configuring it */
|
||||
USE_BRIDGE, /**< ns-3 uses a pre-created tap, and bridges to a bridging net device */
|
||||
};
|
||||
|
||||
TapBridge ();
|
||||
virtual ~TapBridge ();
|
||||
|
||||
@@ -134,6 +155,20 @@ public:
|
||||
*/
|
||||
void Stop (Time tStop);
|
||||
|
||||
/**
|
||||
* Set the operating mode of this device.
|
||||
*
|
||||
* \param mode The operating mode of this device.
|
||||
*/
|
||||
void SetMode (TapBridge::Mode mode);
|
||||
|
||||
/**
|
||||
* Get the operating mode of this device.
|
||||
*
|
||||
* \returns The operating mode of this device.
|
||||
*/
|
||||
TapBridge::Mode GetMode (void);
|
||||
|
||||
//
|
||||
// The following methods are inherited from NetDevice base class and are
|
||||
// documented there.
|
||||
@@ -336,15 +371,21 @@ private:
|
||||
*/
|
||||
Ptr<SystemThread> m_readThread;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The operating mode of the bridge. Tells basically who creates and
|
||||
* configures the underlying network tap.
|
||||
*/
|
||||
Mode m_mode;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The (unused) MAC address of the TapBridge net device. Since the TapBridge
|
||||
* is implemented as a ns-3 net device, it is required to implement certain
|
||||
* functionality. In this case, the TapBridge is automatically assigned a
|
||||
* MAC address, but it is not used. The MAC address assigned to the internet
|
||||
* host actually comes from the bridged (N.B. the "ed") device and not from
|
||||
* the bridge device.
|
||||
* MAC address, but it is not used.
|
||||
*/
|
||||
Mac48Address m_address;
|
||||
|
||||
@@ -386,7 +427,11 @@ private:
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The MAC address to use as the hardware address on the host.
|
||||
* The MAC address to use as the hardware address on the host; only used
|
||||
* in UseLocal mode. This value comes from the MAC
|
||||
* address assigned to the bridged ns-3 net device and matches the MAC
|
||||
* address of the underlying network TAP which we configured to have the
|
||||
* same value.
|
||||
*/
|
||||
Mac48Address m_tapMac;
|
||||
|
||||
@@ -403,6 +448,17 @@ private:
|
||||
* The ns-3 net device to which we are bridging.
|
||||
*/
|
||||
Ptr<NetDevice> m_bridgedDevice;
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The MAC address of the local tap device is stored in this variable.
|
||||
* When in UseLocal mode, this address is added back to the destination
|
||||
* Mac address for frames destined to the tap device. It is learned from
|
||||
* the first frame sent from the host to the TapBridge device. In the
|
||||
* other modes of this device, this value is unused.
|
||||
*/
|
||||
Mac48Address m_learnedMac;
|
||||
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -29,17 +29,10 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#if 0
|
||||
#include <linux/un.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/route.h>
|
||||
#else
|
||||
#include <sys/un.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "tap-encode-decode.h"
|
||||
@@ -277,7 +270,7 @@ SendSocket (const char *path, int fd)
|
||||
}
|
||||
|
||||
static int
|
||||
CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, const char *netmask)
|
||||
CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, const char *mode, const char *netmask)
|
||||
{
|
||||
//
|
||||
// Creation and management of Tap devices is done via the tun device
|
||||
@@ -288,7 +281,9 @@ CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, con
|
||||
//
|
||||
// Allocate a tap device, making sure that it will not send the tun_pi header.
|
||||
// If we provide a null name to the ifr.ifr_name, we tell the kernel to pick
|
||||
// a name for us (i.e., tapn where n = 0..255
|
||||
// a name for us (i.e., tapn where n = 0..255.
|
||||
//
|
||||
// If the device does not already exist, the system will create one.
|
||||
//
|
||||
struct ifreq ifr;
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
@@ -299,6 +294,18 @@ CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, con
|
||||
std::string tapDeviceName = (char *)ifr.ifr_name;
|
||||
LOG ("Allocated TAP device " << tapDeviceName);
|
||||
|
||||
//
|
||||
// Operating mode "2" corresponds to USE_LOCAL and "3" to USE_BRIDGE mode.
|
||||
// This means that we expect that the user will have named, created and
|
||||
// configured a network tap that we are just going to use. So don't mess
|
||||
// up his hard work by changing anything, just return the tap fd.
|
||||
//
|
||||
if (strcmp (mode, "2") == 0 || strcmp (mode, "3") == 0)
|
||||
{
|
||||
LOG ("Returning precreated tap ");
|
||||
return tap;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the hardware (MAC) address of the new device
|
||||
//
|
||||
@@ -348,31 +355,35 @@ main (int argc, char *argv[])
|
||||
char *ip = NULL;
|
||||
char *mac = NULL;
|
||||
char *netmask = NULL;
|
||||
char *operatingMode = NULL;
|
||||
char *path = NULL;
|
||||
|
||||
opterr = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "vd:g:i:m:n:p:")) != -1)
|
||||
while ((c = getopt (argc, argv, "vd:g:i:m:n:o:p:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'd':
|
||||
dev = optarg; // name of the new tap device
|
||||
dev = optarg; // name of the new tap device
|
||||
break;
|
||||
case 'g':
|
||||
gw = optarg; // gateway address for the new device
|
||||
gw = optarg; // gateway address for the new device
|
||||
break;
|
||||
case 'i':
|
||||
ip = optarg; // ip address of the new device
|
||||
ip = optarg; // ip address of the new device
|
||||
break;
|
||||
case 'm':
|
||||
mac = optarg; // mac address of the new device
|
||||
mac = optarg; // mac address of the new device
|
||||
break;
|
||||
case 'n':
|
||||
netmask = optarg; // net mask for the new device
|
||||
netmask = optarg; // net mask for the new device
|
||||
break;
|
||||
case 'o':
|
||||
operatingMode = optarg; // operating mode of tap bridge
|
||||
break;
|
||||
case 'p':
|
||||
path = optarg; // path back to the tap bridge
|
||||
path = optarg; // path back to the tap bridge
|
||||
break;
|
||||
case 'v':
|
||||
gVerbose = true;
|
||||
@@ -421,6 +432,12 @@ main (int argc, char *argv[])
|
||||
ABORT_IF (netmask == NULL, "Net Mask is a required argument", 0);
|
||||
LOG ("Provided Net Mask is \"" << netmask << "\"");
|
||||
|
||||
//
|
||||
// We have got to know whether or not to create the TAP.
|
||||
//
|
||||
ABORT_IF (operatingMode == NULL, "Operating Mode is a required argument", 0);
|
||||
LOG ("Provided Operating Mode is \"" << operatingMode << "\"");
|
||||
|
||||
//
|
||||
// This program is spawned by a tap bridge running in a simulation. It
|
||||
// wants to create a socket as described below. We are going to do the
|
||||
@@ -444,7 +461,7 @@ main (int argc, char *argv[])
|
||||
// us to exeucte the following code:
|
||||
//
|
||||
LOG ("Creating Tap");
|
||||
int sock = CreateTap (dev, gw, ip, mac, netmask);
|
||||
int sock = CreateTap (dev, gw, ip, mac, operatingMode, netmask);
|
||||
ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1);
|
||||
|
||||
//
|
||||
|
||||
@@ -6,46 +6,281 @@
|
||||
*
|
||||
* The Tap Bridge is designed to integrate "real" internet hosts (or more
|
||||
* precisely, hosts that support Tun/Tap devices) into ns-3 simulations. The
|
||||
* goal is to make it appear to the host host node in question that it has an
|
||||
* ns-3 net device as a local device. The concept of a "real host" is a bit
|
||||
* slippery the "real host" may actually be virtualized using readily avialable
|
||||
* goal is to make it appear to a "real" host node in that it has an ns-3 net
|
||||
* device as a local device. The concept of a "real host" is a bit slippery
|
||||
* since the "real host" may actually be virtualized using readily avialable
|
||||
* technologies such as VMware or OpenVZ.
|
||||
*
|
||||
* Since we are, in essence, connecting the inputs and outputs of an ns-3 net
|
||||
* device to the inputs and outputs of a Linux Tap net device, we call this
|
||||
* arrangement a Tap Bridge.
|
||||
*
|
||||
* The TapBridge appears to the Linux host computer as a network device just
|
||||
* like any arbitrary "eth0" or "ath0" might appear. The creation and
|
||||
* configuration of the device is done by the ns-3 simulation, however. You
|
||||
* should not expect to be able to configure a net device via, for example,
|
||||
* wlanconfig. The IP addresses, MAC addresses, gateway, etc., for the given
|
||||
* Tap device are also set up by the ns-3 simulation. If you change the
|
||||
* or manipulate the configuration manually, you will almost certainly break
|
||||
* the simulation.
|
||||
* There are two basic operating modes of this device available to users.
|
||||
* Basic functionality is essentially identical, but the two modes are
|
||||
* different in details regarding how the arrangement is configured. In the
|
||||
* first mode, the configuration is ns-3 configuration-centric. Configuration
|
||||
* information is taken from the ns-3 simulation and a tap device matching
|
||||
* the ns-3 attributes is created for you. In this mode, which we call
|
||||
* LocalDevice mode, an ns-3 net device is made to appear to be directly
|
||||
* connected to a real host.
|
||||
*
|
||||
* This is illustrated below
|
||||
*
|
||||
* \verbatim
|
||||
* +--------+
|
||||
* | Linux |
|
||||
* | host | +----------+
|
||||
* | ------ | | ghost |
|
||||
* | apps | | node |
|
||||
* | ------ | | -------- |
|
||||
* | stack | | IP | +----------+
|
||||
* | ------ | | stack | | node |
|
||||
* | TAP | |==========| | -------- |
|
||||
* | device | <-- IPC Bridge --> | tap | | IP |
|
||||
* +--------+ | bridge | | stack |
|
||||
* | -------- | | -------- |
|
||||
* | ns-3 | | ns-3 |
|
||||
* | net | | net |
|
||||
* | device | | device |
|
||||
* +----------+ +----------+
|
||||
* || ||
|
||||
* +---------------------------+
|
||||
* | ns-3 channel |
|
||||
* +---------------------------+
|
||||
*\endverbatim
|
||||
*
|
||||
* In this case, the ns-3 net device in the ghost node appears as if it were
|
||||
* actually replacing the TAP device in the Linux host. The ns-3 process
|
||||
* creates the TAP device configures the IP address and MAC address of the
|
||||
* TAP device to match the values assigned to the ns-3 net device. The IPC
|
||||
* link is via the network tap mechanism in the underlying OS and acts as a
|
||||
* conventional bridge; but a bridge between devices that happen to have the
|
||||
* same shared MAC address.
|
||||
*
|
||||
* The LocalDevice mode is the default operating mode of the Tap Bridge.
|
||||
*
|
||||
* The second mode, BridgedDevice mode, is more oriented toward allowing existing
|
||||
* host configurations. This allows ns-3 net devices to appear as part of a host
|
||||
* operating system bridge (in Linux, we make the ns-3 device part of a "brctl"
|
||||
* bridge. This mode is especially useful in the case of virtualization where
|
||||
* the configuration of the virtual hosts may be dictated by another system and
|
||||
* not be changable to suit ns-3. For example, a particular VM scheme may create
|
||||
* virtual "vethx" or "vmnetx" devices that appear local to virtual hosts. In
|
||||
* order to connect to such systems, one would need to manually create TAP devices
|
||||
* on the host system and brigde these TAP devices to the existing (VM) virtual
|
||||
* devices. The job of the Tap Bridge in this case is to extend the bridge to
|
||||
* join the ns-3 net device.
|
||||
*
|
||||
* This is illustrated below:
|
||||
*
|
||||
* \verbatim
|
||||
* +---------+
|
||||
* | Linux |
|
||||
* | VM | +----------+
|
||||
* | ------- | | ghost |
|
||||
* | apps | | node |
|
||||
* | ------- | | -------- |
|
||||
* | stack | | IP | +----------+
|
||||
* | ------- | +--------+ | stack | | node |
|
||||
* | Virtual | | TAP | |==========| | -------- |
|
||||
* | Device | | Device | <-- IPC Bridge-> | tap | | IP |
|
||||
* +---------+ +--------+ | bridge | | stack |
|
||||
* || || | -------- | | -------- |
|
||||
* +--------------------+ | ns-3 | | ns-3 |
|
||||
* | OS (brctl) Bridge | | net | | net |
|
||||
* +--------------------+ | device | | device |
|
||||
* +----------+ +----------+
|
||||
* || ||
|
||||
* +---------------------------+
|
||||
* | ns-3 channel |
|
||||
* +---------------------------+
|
||||
*\endverbatim
|
||||
*
|
||||
* In this case, a collection of virtual machines with associated Virtual
|
||||
* Devices is created in the virtualization environment (for exampe, OpenVZ
|
||||
* or VMware). A TAP device (with a specific name) is then manually created
|
||||
* for each Virtual Device that will be bridged into the ns-3 simulation.
|
||||
* These created TAP devices are then bridged together with the Virtual Devices
|
||||
* using a native OS bridge mechanism shown as "OS (brctl) Bridge" in the
|
||||
* illustration above.
|
||||
*
|
||||
* In the ns-3 simulation, a Tap Bridge is created to match each TAP Device.
|
||||
* The name of the TAP Device is assigned to the Tap Bridge using the
|
||||
* "DeviceName" attribute. The Tap Bridge then opens a network tap to the TAP
|
||||
* Device and logically extends the bridge to encompass the ns-3 net device.
|
||||
* This makes it appear as if an ns-3 simulated net device is a member of the
|
||||
* "OS (brctl) Bridge" and allows the Virtual Machines to communicate with the
|
||||
* ns-3 simulation..
|
||||
*
|
||||
* \subsection TapBridgeLocalDeviceMode TapBridge LocalDevice Mode
|
||||
*
|
||||
* In LocalDevice mode, the TapBridge and therefore its associated ns-3 net
|
||||
* device appears to the Linux host computer as a network device just like any
|
||||
* arbitrary "eth0" or "ath0" might appear. The creation and configuration
|
||||
* of the TAP device is done by the ns-3 simulation and no manual configuration
|
||||
* is required by the user. The IP addresses, MAC addresses, gateways, etc.,
|
||||
* for created TAP devices are extracted from the simulation itself by querying
|
||||
* the configuration of the ns-3 device and the TapBridge Attributes.
|
||||
*
|
||||
* The TapBridge appears to an ns-3 simulation as a channel-less net device.
|
||||
* This device, however, must _not_ have an IP address associated with it.
|
||||
* Be aware that this is the inverse situation of an ns-3 BridgeNetDevice
|
||||
* which demands that its bridge ports not have IP addresses, but allows the
|
||||
* bridge to have an IP address.
|
||||
* This device must not have an IP address associated with it, but the bridged
|
||||
* (ns-3) net device must have an IP adress. Be aware that this is the inverse
|
||||
* of an ns-3 BridgeNetDevice (or a conventional bridge in general) which
|
||||
* demands that its bridge ports not have IP addresses, but allows the bridge
|
||||
* device itself to have an IP address.
|
||||
*
|
||||
* The host computer will appear in a simulation as a "ghost" node that contains
|
||||
* pairs of net devices and Tap bridges that represent the host devices. From
|
||||
* the perspective of a simulation, the only difference between a ghost node and
|
||||
* another node will be the presence of the TapBridge devices that connect to
|
||||
* the hosts. Configuration of address information and the ns-3 devices is
|
||||
* not changed in any way. A TapBridge will pick up the addressing info from
|
||||
* the ns-3 net device to which it is connected (its "bridged" net device) and
|
||||
* use that information to configure the device on the real host.
|
||||
* one TapBridge for each NetDevice that is being bridged. From the perspective
|
||||
* of a simulation, the only difference between a ghost node and any other node
|
||||
* will be the presence of the TapBridge devices. Note however, that the
|
||||
* presence of the TapBridge does affect the connectivity of the net device to
|
||||
* the IP stack of the ghost node.
|
||||
*
|
||||
* Configuration of address information and the ns-3 devices is not changed in
|
||||
* any way if a TapBridge is present. A TapBridge will pick up the addressing
|
||||
* information from the ns-3 net device to which it is connected (its "bridged"
|
||||
* net device) and use that information to create and configure the TAP device
|
||||
* on the real host.
|
||||
*
|
||||
* The end result of this is a situation where one can, for example, use the
|
||||
* standard ping utility on a real host to ping a simulated ns-3 net device. If
|
||||
* correct routes are added to the internet host, the routing systems in ns-3
|
||||
* will enable correct routing of the packets across simulated ns-3 networks.
|
||||
* For an example of this, see the example program, tap-dumbbell.cc in the
|
||||
* ns-3 distribution.
|
||||
* standard ping utility on a real host to ping a simulated ns-3 node. If
|
||||
* correct routes are added to the internet host (this is expected to be done
|
||||
* automatically in future ns-3 releases), the routing systems in ns-3 will
|
||||
* enable correct routing of the packets across simulated ns-3 networks.
|
||||
* For an example of this, see the example program, tap-wifi-dumbbell.cc in
|
||||
* the ns-3 distribution.
|
||||
*
|
||||
* \subsection TapBridgeLocalDeviceModeOperation TapBridge LocalDevice Mode Operation
|
||||
*
|
||||
* The Tap Bridge lives in a kind of a gray world somewhere between a Linux host
|
||||
* and an ns-3 bridge device. From the Linux perspective, this code appears as
|
||||
* the user mode handler for a TAP net device. In LocalDevice mode, this TAP
|
||||
* device is automatically created by the ns-3 simulation. When the Linux host
|
||||
* writes to one of these automatically created /dev/tap devices, the write is
|
||||
* redirected into the TapBridge that lives in the ns-3 world; and from this
|
||||
* perspective, the packet write on Linux becomes a packet read in the Tap Bridge.
|
||||
* In other words, a Linux process writes a packet to a tap device and this packet
|
||||
* is redirected by the network tap mechanism toan ns-3 process where it is
|
||||
* received by the TapBridge as a result of a read operation there. The TapBridge
|
||||
* then writes the packet to the ns-3 net device to which it is bridged; and
|
||||
* therefore it appears as if the Linux host sent a packet directly through an
|
||||
* ns-3 net device onto an ns-3 network.
|
||||
*
|
||||
* In the other direction, a packet received by the ns-3 net device connected to
|
||||
* the Tap Bridge is sent via promiscuous callback to the TapBridge. The
|
||||
* TapBridge then takes that packet and writes it back to the host using the
|
||||
* network tap mechanism. This write to the device will appear to the Linux
|
||||
* host as if a packet has arrived on its device; and therefore as if a packet
|
||||
* received by the ns-3 net device has appeared on a Linux net device.
|
||||
*
|
||||
* The upshot is that the Tap Bridge appears to bridge a tap device on a
|
||||
* Linux host in the "real world" to an ns-3 net device in the simulation.
|
||||
* Because the TAP device and the bridged ns-3 net device have the same MAC
|
||||
* address and the network tap IPC link is not exernalized, this particular
|
||||
* kind of bridge makes ti appear that a ns-3 net device is actually installed
|
||||
* in the Linux host.
|
||||
*
|
||||
* In order to implement this on the ns-3 side, we need a "ghost node" in the
|
||||
* simulation to hold the bridged ns-3 net device and the TapBridge. This node
|
||||
* should not actually do anything else in the simulation since its job is
|
||||
* simply to make the net device appear in Linux. This is not just arbitrary
|
||||
* policy, it is because:
|
||||
*
|
||||
* - Bits sent to the Tap Bridge from higher layers in the ghost node (using
|
||||
* the TapBridge Send method) are completely ignored. The Tap Bridge is
|
||||
* not, itself, connected to any network, neither in Linux nor in ns-3. You
|
||||
* can never send nor receive data over a Tap Bridge from the ghost node.
|
||||
*
|
||||
* - The bridged ns-3 net device has its receive callback disconnected
|
||||
* from the ns-3 node and reconnected to the Tap Bridge. All data received
|
||||
* by a bridged device will then be sent to the Linux host and will not be
|
||||
* received by the node. From the perspective of the ghost node, you can
|
||||
* send over this device but you cannot ever receive.
|
||||
*
|
||||
* Of course, if you understand all of the issues you can take control of
|
||||
* your own destiny and do whatever you want -- we do not actively
|
||||
* prevent you from using the ghost node for anything you decide. You
|
||||
* will be able to perform typical ns-3 operations on the ghost node if
|
||||
* you so desire. The internet stack, for example, must be there and
|
||||
* functional on that node in order to participate in IP address
|
||||
* assignment and global routing. However, as mentioned above,
|
||||
* interfaces talking any Tap Bridge or associated bridged net devices
|
||||
* will not work completely. If you understand exactly what you are
|
||||
* doing, you can set up other interfaces and devices on the ghost node
|
||||
* and use them; or take advantage of the operational send side of the
|
||||
* bridged devices to create traffic generators. We generally recommend
|
||||
* that you treat this node as a ghost of the Linux host and leave it to
|
||||
* itself, though.
|
||||
*
|
||||
* \subsection TapBridgeBridgedDeviceMode TapBridge BridgedDevice Mode
|
||||
*
|
||||
* In BridgedDevice mode, the TapBridge and its associated ns-3 net device are
|
||||
* arranged in a fundamentally similar was as in LocalDevice mode. The TAP
|
||||
* device is bridged to the ns-3 net device in the same way. The description
|
||||
* of LocalDevice mode applies except as noted below.
|
||||
*
|
||||
* The most user-visible difference in modes is how the creation and
|
||||
* configuration of the underlying TAP device is done. In LocalDevice mode,
|
||||
* both creation and configuration of the underlying TAP device are handled
|
||||
* completely by ns-3. In BridgedDevice mode, creation and configuration is
|
||||
* delegated (due to requirements) to the user. No configuration is done in
|
||||
* ns-3 other than settting the operating mode of the TapBridge to
|
||||
* "BridgedDevice" and specifying the name of a pre-configured TAP device
|
||||
* using ns-3 Attributes of the TapBridge.
|
||||
*
|
||||
* The primary conceptual difference between modes is due to the fact that in
|
||||
* BridgedDevice mode the MAC addresses of the user-created TAPs will be pre-
|
||||
* configured and will therefore be different than those in the bridged device.
|
||||
* As in LocalDevice mode, the Tap Bridge functions as IPC bridge between the
|
||||
* TAP device and the ns-3 net device, but in BridgedDevice configurations the
|
||||
* two devices will have different MAC addresses and the bridging functionality
|
||||
* will be fundamentally the same as in any bridge. Since this implies MAC
|
||||
* address spoofing, the only ns-3 devices which may paritcipate in a bridge
|
||||
* in BridgedDevice mode must support SendFrom (i.e., a call to the method
|
||||
* SupportsSendFrom in the bridged net device must return true).
|
||||
*
|
||||
* \subsection TapBridgeBridgedDeviceModeOperation TapBridge BridgedDevice Mode Operation
|
||||
*
|
||||
* As described in the LocalDevice mode section, when the Linux host writes to
|
||||
* one of the /dev/tap devices, the write is redirected into the TapBridge
|
||||
* that lives in the ns-3 world. In the case of the BridgedDevice mode, these
|
||||
* packets will need to be sent out on the ns-3 network as if they were sent on
|
||||
* the Linux network. This means calling the SendFrom method on the bridged
|
||||
* device and providing the source and destination MAC addresses found in the
|
||||
* packet.
|
||||
*
|
||||
* In the other direction, a packet received by an ns-3 net device is hooked
|
||||
* via callback to the TapBridge. This must be done in promiscuous mode since
|
||||
* the goal is to bridge the ns-3 net device onto the OS (brctl) bridge of
|
||||
* which the TAP device is a part.
|
||||
*
|
||||
* There is no functional difference between modes at this level, even though
|
||||
* the configuration and conceptual models regarding what is going on are quite
|
||||
* different -- the Tap Bridge is just acting like a bridge. In the LocalDevice
|
||||
* mode, the bridge is between devices having the same MAC address and in the
|
||||
* BridgedDevice model the bridge is between devices having different MAC
|
||||
* addresses.
|
||||
*
|
||||
* \subsection TapBridgeSingleSourceModeOperation TapBridge SingleSource Mode Operation
|
||||
*
|
||||
* As described in above, the Tap Bridge acts like a bridge. Just like every
|
||||
* other bridge, there is a requirement that participating devices must have
|
||||
* the ability to receive promiscuously and to spoof the source MAC addresses
|
||||
* of packets.
|
||||
*
|
||||
* We do, however, have a specific requirement to be able to bridge Virtual
|
||||
* Machines onto wireless STA nodes. Unfortunately, the 802.11 spec doesn't
|
||||
* provide a good way to implement SendFrom. So we have to work around this.
|
||||
*
|
||||
* To this end, we provice the SingleSource mode of the Tap Bridge. This
|
||||
* mode allows you to create a bridge as described in BridgedDevice mode, but
|
||||
* only allows one source of packets on the Linux side of the bridge. The
|
||||
* address on the Linux side is remembered in the Tap Bridge, and all packets
|
||||
* coming from the Linux side are repeated out the ns-3 side using the ns-3 device
|
||||
* MAC source address. All packets coming in from the ns-3 side are repeated
|
||||
* out the Linux side using the remembered MAC address. This allows us to use
|
||||
* SendFrom on the ns-3 device side which is available on all ns-3 net devices.
|
||||
*
|
||||
* \section TapBridgeChannelModel Tap Bridge Channel Model
|
||||
*
|
||||
* There is no channel model associated with the Tap Bridge. In fact, the
|
||||
|
||||
@@ -27,6 +27,7 @@ def build(bld):
|
||||
module.source.extend([
|
||||
'tap-bridge.cc',
|
||||
'tap-encode-decode.cc',
|
||||
'tap-creator.cc',
|
||||
])
|
||||
headers.source.extend([
|
||||
'tap-bridge.h',
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/enum.h"
|
||||
#include "ns3/tap-bridge.h"
|
||||
#include "ns3/names.h"
|
||||
#include "tap-bridge-helper.h"
|
||||
@@ -26,11 +27,18 @@ NS_LOG_COMPONENT_DEFINE ("TapBridgeHelper");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
TapBridgeHelper::TapBridgeHelper ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_deviceFactory.SetTypeId ("ns3::TapBridge");
|
||||
}
|
||||
|
||||
TapBridgeHelper::TapBridgeHelper (Ipv4Address gateway)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_deviceFactory.SetTypeId ("ns3::TapBridge");
|
||||
SetAttribute ("Gateway", Ipv4AddressValue (gateway));
|
||||
SetAttribute ("Mode", EnumValue(TapBridge::CONFIGURE_LOCAL));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -41,6 +49,14 @@ TapBridgeHelper::SetAttribute (std::string n1, const AttributeValue &v1)
|
||||
}
|
||||
|
||||
|
||||
Ptr<NetDevice>
|
||||
TapBridgeHelper::Install (Ptr<Node> node, Ptr<NetDevice> nd, const AttributeValue &v1)
|
||||
{
|
||||
NS_LOG_FUNCTION (node << nd << &v1);
|
||||
m_deviceFactory.Set ("DeviceName", v1);
|
||||
return Install (node, nd);
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
TapBridgeHelper::Install (Ptr<Node> node, Ptr<NetDevice> nd)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "net-device-container.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include "ns3/tap-bridge.h"
|
||||
#include <string>
|
||||
|
||||
namespace ns3 {
|
||||
@@ -31,12 +32,14 @@ class AttributeValue;
|
||||
class TapBridgeHelper
|
||||
{
|
||||
public:
|
||||
TapBridgeHelper ();
|
||||
TapBridgeHelper (Ipv4Address gateway);
|
||||
void SetAttribute (std::string n1, const AttributeValue &v1);
|
||||
Ptr<NetDevice> Install (Ptr<Node> node, Ptr<NetDevice> nd);
|
||||
Ptr<NetDevice> Install (std::string nodeName, Ptr<NetDevice> nd);
|
||||
Ptr<NetDevice> Install (Ptr<Node> node, std::string ndName);
|
||||
Ptr<NetDevice> Install (std::string nodeName, std::string ndName);
|
||||
Ptr<NetDevice> Install (Ptr<Node> node, Ptr<NetDevice> nd, const AttributeValue &v1);
|
||||
private:
|
||||
ObjectFactory m_deviceFactory;
|
||||
};
|
||||
|
||||
@@ -54,6 +54,8 @@ AddUdpStack(Ptr<Node> node)
|
||||
Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> ();
|
||||
udp->SetNode (node);
|
||||
ipv4->Insert (udp);
|
||||
node->AggregateObject (udp);
|
||||
|
||||
Ptr<UdpSocketFactoryImpl> udpFactory = CreateObject<UdpSocketFactoryImpl> ();
|
||||
udpFactory->SetUdp (udp);
|
||||
node->AggregateObject (udpFactory);
|
||||
@@ -66,6 +68,8 @@ AddIcmpStack (Ptr<Node> node)
|
||||
Ptr<Icmpv4L4Protocol> icmp = CreateObject<Icmpv4L4Protocol> ();
|
||||
icmp->SetNode (node);
|
||||
ipv4->Insert (icmp);
|
||||
node->AggregateObject (icmp);
|
||||
|
||||
Ptr<Ipv4RawSocketFactoryImpl> rawFactory = CreateObject<Ipv4RawSocketFactoryImpl> ();
|
||||
node->AggregateObject (rawFactory);
|
||||
}
|
||||
@@ -76,8 +80,8 @@ AddTcpStack(Ptr<Node> node)
|
||||
Ptr<Ipv4L3Protocol> ipv4 = node->GetObject<Ipv4L3Protocol> ();
|
||||
Ptr<TcpL4Protocol> tcp = CreateObject<TcpL4Protocol> ();
|
||||
tcp->SetNode (node);
|
||||
|
||||
ipv4->Insert (tcp);
|
||||
node->AggregateObject (tcp);
|
||||
|
||||
Ptr<TcpSocketFactoryImpl> tcpFactory = CreateObject<TcpSocketFactoryImpl> ();
|
||||
tcpFactory->SetTcp (tcp);
|
||||
@@ -114,6 +118,8 @@ AddNscStack(Ptr<Node> node, const std::string &soname)
|
||||
tcp->SetNscLibrary(soname);
|
||||
tcp->SetNode (node);
|
||||
ipv4->Insert (tcp);
|
||||
node->AggregateObject (tcp);
|
||||
|
||||
Ptr<NscTcpSocketFactoryImpl> tcpFactory = CreateObject<NscTcpSocketFactoryImpl> ();
|
||||
tcpFactory->SetTcp (tcp);
|
||||
node->AggregateObject (tcpFactory);
|
||||
|
||||
@@ -152,17 +152,16 @@ Ipv4L3Protocol::DoDispose (void)
|
||||
NS_LOG_FUNCTION (this);
|
||||
for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
|
||||
{
|
||||
(*i)->Dispose ();
|
||||
*i = 0;
|
||||
}
|
||||
m_protocols.clear ();
|
||||
|
||||
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); ++i)
|
||||
for (Ipv4InterfaceList::iterator i = m_interfaces.begin (); i != m_interfaces.end (); ++i)
|
||||
{
|
||||
Ptr<Ipv4Interface> interface = *i;
|
||||
interface->Dispose ();
|
||||
*i = 0;
|
||||
}
|
||||
m_interfaces.clear ();
|
||||
m_routingProtocols.clear ();
|
||||
m_node = 0;
|
||||
m_staticRouting->Dispose ();
|
||||
m_staticRouting = 0;
|
||||
|
||||
@@ -24,12 +24,13 @@
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/node.h"
|
||||
|
||||
#include "ns3/object-vector.h"
|
||||
|
||||
#include "tcp-header.h"
|
||||
#include "ipv4-end-point-demux.h"
|
||||
#include "ipv4-end-point.h"
|
||||
#include "ipv4-l3-protocol.h"
|
||||
#include "nsc-tcp-l4-protocol.h"
|
||||
#include "nsc-tcp-socket-impl.h"
|
||||
#include "nsc-sysctl.h"
|
||||
|
||||
#include "tcp-typedefs.h"
|
||||
@@ -70,6 +71,10 @@ NscTcpL4Protocol::GetTypeId (void)
|
||||
ObjectFactoryValue (GetDefaultRttEstimatorFactory ()),
|
||||
MakeObjectFactoryAccessor (&NscTcpL4Protocol::m_rttFactory),
|
||||
MakeObjectFactoryChecker ())
|
||||
.AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
|
||||
ObjectVectorValue (),
|
||||
MakeObjectVectorAccessor (&NscTcpL4Protocol::m_sockets),
|
||||
MakeObjectVectorChecker<NscTcpSocketImpl> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -154,6 +159,14 @@ void
|
||||
NscTcpL4Protocol::DoDispose (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
for (std::vector<Ptr<NscTcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
|
||||
{
|
||||
*i = 0;
|
||||
}
|
||||
m_sockets.clear ();
|
||||
|
||||
|
||||
if (m_endPoints != 0)
|
||||
{
|
||||
delete m_endPoints;
|
||||
@@ -173,6 +186,7 @@ NscTcpL4Protocol::CreateSocket (void)
|
||||
socket->SetNode (m_node);
|
||||
socket->SetTcp (this);
|
||||
socket->SetRtt (rtt);
|
||||
m_sockets.push_back (socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "ns3/timer.h"
|
||||
#include "sim_interface.h"
|
||||
#include "nsc-tcp-socket-impl.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -116,6 +117,7 @@ private:
|
||||
INetStack* m_nscStack;
|
||||
void *m_dlopenHandle;
|
||||
Timer m_softTimer;
|
||||
std::vector<Ptr<NscTcpSocketImpl> > m_sockets;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "nsc-tcp-socket-factory-impl.h"
|
||||
#include "nsc-tcp-l4-protocol.h"
|
||||
#include "nsc-tcp-socket-factory-impl.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/object-vector.h"
|
||||
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/node.h"
|
||||
@@ -31,7 +32,6 @@
|
||||
#include "ipv4-end-point-demux.h"
|
||||
#include "ipv4-end-point.h"
|
||||
#include "ipv4-l3-protocol.h"
|
||||
#include "tcp-socket-impl.h"
|
||||
|
||||
#include "tcp-typedefs.h"
|
||||
|
||||
@@ -334,6 +334,10 @@ TcpL4Protocol::GetTypeId (void)
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&TcpL4Protocol::m_calcChecksum),
|
||||
MakeBooleanChecker ())
|
||||
.AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
|
||||
ObjectVectorValue (),
|
||||
MakeObjectVectorAccessor (&TcpL4Protocol::m_sockets),
|
||||
MakeObjectVectorChecker<TcpSocketImpl> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -366,11 +370,18 @@ void
|
||||
TcpL4Protocol::DoDispose (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
for (std::vector<Ptr<TcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
|
||||
{
|
||||
*i = 0;
|
||||
}
|
||||
m_sockets.clear ();
|
||||
|
||||
if (m_endPoints != 0)
|
||||
{
|
||||
delete m_endPoints;
|
||||
m_endPoints = 0;
|
||||
}
|
||||
|
||||
m_node = 0;
|
||||
Ipv4L4Protocol::DoDispose ();
|
||||
}
|
||||
@@ -384,6 +395,7 @@ TcpL4Protocol::CreateSocket (void)
|
||||
socket->SetNode (m_node);
|
||||
socket->SetTcp (this);
|
||||
socket->SetRtt (rtt);
|
||||
m_sockets.push_back (socket);
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "ipv4-l4-protocol.h"
|
||||
#include "ipv4-interface.h"
|
||||
|
||||
#include "tcp-socket-impl.h"
|
||||
#include "tcp-header.h"
|
||||
#include "tcp-typedefs.h"
|
||||
|
||||
@@ -120,6 +121,7 @@ private:
|
||||
|
||||
bool m_goodChecksum;
|
||||
bool m_calcChecksum;
|
||||
std::vector<Ptr<TcpSocketImpl> > m_sockets;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
@@ -105,8 +105,6 @@ private:
|
||||
Ptr<UdpL4Protocol> m_udp;
|
||||
Ipv4Address m_defaultAddress;
|
||||
uint16_t m_defaultPort;
|
||||
Callback<void,Ptr<Socket>,uint32_t,const Address &> m_dummyRxCallback;
|
||||
Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Address &> m_rxCallback;
|
||||
TracedCallback<Ptr<const Packet> > m_dropTrace;
|
||||
|
||||
enum SocketErrno m_errno;
|
||||
|
||||
@@ -154,14 +154,14 @@ SPFVertex::GetDistanceFromRoot (void) const
|
||||
}
|
||||
|
||||
void
|
||||
SPFVertex::SetOutgoingTypeId (uint32_t id)
|
||||
SPFVertex::SetOutgoingInterfaceId (uint32_t id)
|
||||
{
|
||||
NS_LOG_FUNCTION (id);
|
||||
m_rootOif = id;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SPFVertex::GetOutgoingTypeId (void) const
|
||||
SPFVertex::GetOutgoingInterfaceId (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_rootOif;
|
||||
@@ -872,14 +872,14 @@ GlobalRouteManagerImpl::SPFNexthopCalculation (
|
||||
// from the perspective of <v> -- remember that <l> is the link "from"
|
||||
// <v> "to" <w>.
|
||||
//
|
||||
w->SetOutgoingTypeId (
|
||||
FindOutgoingTypeId (l->GetLinkData ()));
|
||||
w->SetOutgoingInterfaceId (
|
||||
FindOutgoingInterfaceId (l->GetLinkData ()));
|
||||
w->SetDistanceFromRoot (distance);
|
||||
w->SetParent (v);
|
||||
NS_LOG_LOGIC ("Next hop from " <<
|
||||
v->GetVertexId () << " to " << w->GetVertexId () <<
|
||||
" goes through next hop " << w->GetNextHop () <<
|
||||
" via outgoing interface " << w->GetOutgoingTypeId () <<
|
||||
" via outgoing interface " << w->GetOutgoingInterfaceId () <<
|
||||
" with distance " << distance);
|
||||
} // end W is a router vertes
|
||||
else
|
||||
@@ -889,14 +889,14 @@ GlobalRouteManagerImpl::SPFNexthopCalculation (
|
||||
GlobalRoutingLSA* w_lsa = w->GetLSA ();
|
||||
NS_ASSERT (w_lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA);
|
||||
// Find outgoing interface ID for this network
|
||||
w->SetOutgoingTypeId (
|
||||
FindOutgoingTypeId (w_lsa->GetLinkStateId (),
|
||||
w->SetOutgoingInterfaceId (
|
||||
FindOutgoingInterfaceId (w_lsa->GetLinkStateId (),
|
||||
w_lsa->GetNetworkLSANetworkMask () ));
|
||||
w->SetDistanceFromRoot (distance);
|
||||
w->SetParent (v);
|
||||
NS_LOG_LOGIC ("Next hop from " <<
|
||||
v->GetVertexId () << " to network " << w->GetVertexId () <<
|
||||
" via outgoing interface " << w->GetOutgoingTypeId () <<
|
||||
" via outgoing interface " << w->GetOutgoingInterfaceId () <<
|
||||
" with distance " << distance);
|
||||
return 1;
|
||||
}
|
||||
@@ -921,17 +921,17 @@ GlobalRouteManagerImpl::SPFNexthopCalculation (
|
||||
* it can be inherited from the parent network).
|
||||
*/
|
||||
w->SetNextHop (linkRemote->GetLinkData ());
|
||||
w->SetOutgoingTypeId (v->GetOutgoingTypeId ());
|
||||
w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
|
||||
NS_LOG_LOGIC ("Next hop from " <<
|
||||
v->GetVertexId () << " to " << w->GetVertexId () <<
|
||||
" goes through next hop " << w->GetNextHop () <<
|
||||
" via outgoing interface " << w->GetOutgoingTypeId ());
|
||||
" via outgoing interface " << w->GetOutgoingInterfaceId ());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
w->SetNextHop (v->GetNextHop ());
|
||||
w->SetOutgoingTypeId (v->GetOutgoingTypeId ());
|
||||
w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -950,7 +950,7 @@ GlobalRouteManagerImpl::SPFNexthopCalculation (
|
||||
// (are inherited).
|
||||
//
|
||||
w->SetNextHop (v->GetNextHop ());
|
||||
w->SetOutgoingTypeId (v->GetOutgoingTypeId ());
|
||||
w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
|
||||
}
|
||||
//
|
||||
// In all cases, we need valid values for the distance metric and a parent.
|
||||
@@ -1328,7 +1328,7 @@ GlobalRouteManagerImpl::SPFIntraAddStub (GlobalRoutingLinkRecord *l, SPFVertex*
|
||||
" add route to " << tempip <<
|
||||
" with mask " << tempmask <<
|
||||
" using next hop " << v->GetNextHop () <<
|
||||
" via interface " << v->GetOutgoingTypeId ());
|
||||
" via interface " << v->GetOutgoingInterfaceId ());
|
||||
//
|
||||
// Here's why we did all of that work. We're going to add a host route to the
|
||||
// host address found in the m_linkData field of the point-to-point link
|
||||
@@ -1344,7 +1344,7 @@ GlobalRouteManagerImpl::SPFIntraAddStub (GlobalRoutingLinkRecord *l, SPFVertex*
|
||||
//
|
||||
Ptr<Ipv4GlobalRouting> gr = GetGlobalRoutingProtocol (node->GetId ());
|
||||
NS_ASSERT (gr);
|
||||
gr->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (), v->GetOutgoingTypeId ());
|
||||
gr->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (), v->GetOutgoingInterfaceId ());
|
||||
return;
|
||||
} // if
|
||||
} // for
|
||||
@@ -1356,7 +1356,7 @@ GlobalRouteManagerImpl::SPFIntraAddStub (GlobalRoutingLinkRecord *l, SPFVertex*
|
||||
// have to find the right node pointer to pass to that function.
|
||||
//
|
||||
uint32_t
|
||||
GlobalRouteManagerImpl::FindOutgoingTypeId (Ipv4Address a, Ipv4Mask amask)
|
||||
GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask)
|
||||
{
|
||||
NS_LOG_FUNCTION (a << amask);
|
||||
//
|
||||
@@ -1399,7 +1399,7 @@ GlobalRouteManagerImpl::FindOutgoingTypeId (Ipv4Address a, Ipv4Mask amask)
|
||||
//
|
||||
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
|
||||
NS_ASSERT_MSG (ipv4,
|
||||
"GlobalRouteManagerImpl::FindOutgoingTypeId (): "
|
||||
"GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
|
||||
"QI for <Ipv4> interface failed");
|
||||
//
|
||||
// Look through the interfaces on this node for one that has the IP address
|
||||
@@ -1526,7 +1526,7 @@ GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v)
|
||||
NS_LOG_LOGIC (" Node " << node->GetId () <<
|
||||
" add route to " << lr->GetLinkData () <<
|
||||
" using next hop " << v->GetNextHop () <<
|
||||
" via interface " << v->GetOutgoingTypeId ());
|
||||
" via interface " << v->GetOutgoingInterfaceId ());
|
||||
//
|
||||
// Here's why we did all of that work. We're going to add a host route to the
|
||||
// host address found in the m_linkData field of the point-to-point link
|
||||
@@ -1543,7 +1543,7 @@ GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v)
|
||||
Ptr<Ipv4GlobalRouting> gr = GetGlobalRoutingProtocol (node->GetId ());
|
||||
NS_ASSERT (gr);
|
||||
gr->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (),
|
||||
v->GetOutgoingTypeId ());
|
||||
v->GetOutgoingInterfaceId ());
|
||||
}
|
||||
//
|
||||
// Done adding the routes for the selected node.
|
||||
@@ -1627,11 +1627,11 @@ GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v)
|
||||
Ptr<Ipv4GlobalRouting> gr = GetGlobalRoutingProtocol (node->GetId ());
|
||||
NS_ASSERT (gr);
|
||||
gr->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (),
|
||||
v->GetOutgoingTypeId ());
|
||||
v->GetOutgoingInterfaceId ());
|
||||
NS_LOG_LOGIC ("Node " << node->GetId () <<
|
||||
" add network route to " << tempip <<
|
||||
" using next hop " << v->GetNextHop () <<
|
||||
" via interface " << v->GetOutgoingTypeId ());
|
||||
" via interface " << v->GetOutgoingInterfaceId ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ public:
|
||||
* @returns The interface index to use when forwarding packets to the host
|
||||
* or network represented by "this" SPFVertex.
|
||||
*/
|
||||
uint32_t GetOutgoingTypeId (void) const;
|
||||
uint32_t GetOutgoingInterfaceId (void) const;
|
||||
|
||||
/**
|
||||
* @brief Set the interface ID that should be used to begin forwarding packets
|
||||
@@ -337,7 +337,7 @@ public:
|
||||
* @param id The interface index to use when forwarding packets to the host or
|
||||
* network represented by "this" SPFVertex.
|
||||
*/
|
||||
void SetOutgoingTypeId (uint32_t id);
|
||||
void SetOutgoingInterfaceId (uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief Get the IP address that should be used to begin forwarding packets
|
||||
@@ -799,7 +799,7 @@ private:
|
||||
void SPFIntraAddRouter (SPFVertex* v);
|
||||
void SPFIntraAddTransit (SPFVertex* v);
|
||||
void SPFIntraAddStub (GlobalRoutingLinkRecord *l, SPFVertex* v);
|
||||
uint32_t FindOutgoingTypeId (Ipv4Address a,
|
||||
uint32_t FindOutgoingInterfaceId (Ipv4Address a,
|
||||
Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
|
||||
|
||||
// Local cache of the Ipv4GlobalRouting objects, indexed by nodeId
|
||||
|
||||
Reference in New Issue
Block a user