merge with ns3-dev

This commit is contained in:
Pavel Boyko
2009-03-30 14:41:30 +04:00
37 changed files with 2027 additions and 1028 deletions

View File

@@ -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]

View File

@@ -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):

View File

@@ -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',

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 ();

View File

@@ -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.

View File

@@ -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,

View File

@@ -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");

View File

@@ -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);

View File

@@ -157,8 +157,6 @@ int main (int argc, char *argv[])
wifiX += 20.0;
}
GlobalRouteManager::PopulateRoutingTables ();
Address dest;
std::string protocol;
if (sendIp)

View File

@@ -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 ();

View File

@@ -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

View File

@@ -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'

View File

@@ -61,7 +61,6 @@ public:
/**
* Enumeration of the types of packets supported in the class.
*
*/
enum EncapsulationMode {
ILLEGAL, /**< Encapsulation mode not set */

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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);
//

View File

@@ -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

View File

@@ -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',

View File

@@ -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)
{

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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 ());
}
}
}

View File

@@ -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