460 lines
14 KiB
ReStructuredText
460 lines
14 KiB
ReStructuredText
.. include:: replace.txt
|
|
.. highlight:: cpp
|
|
|
|
|
|
.. _Adding a New Module to ns3:
|
|
|
|
Adding a New Module to |ns3|
|
|
----------------------------
|
|
|
|
When you have created a group of related classes, examples, and tests,
|
|
they can be combined together into an |ns3| module so that they can be
|
|
used with existing |ns3| modules and by other researchers.
|
|
|
|
This chapter walks you through the steps necessary to add a new module
|
|
to |ns3|.
|
|
|
|
.. _Step-0:
|
|
|
|
Step 0 - Module Layout
|
|
**********************
|
|
|
|
All modules can be found in the ``src`` directory. Each module can be
|
|
found in a directory that has the same name as the module. For
|
|
example, the ``spectrum`` module can be found here: ``src/spectrum``.
|
|
We'll be quoting from the ``spectrum`` module for illustration.
|
|
|
|
A prototypical module has the following directory structure and
|
|
required files:
|
|
|
|
.. sourcecode:: text
|
|
|
|
src/
|
|
module-name/
|
|
bindings/
|
|
doc/
|
|
examples/
|
|
CMakeLists.txt
|
|
helper/
|
|
model/
|
|
test/
|
|
examples-to-run.py
|
|
CMakeLists.txt
|
|
|
|
Not all directories will be present in each module.
|
|
|
|
Step 1 - Create a Module Skeleton
|
|
*********************************
|
|
|
|
A python program is provided in the ``utils`` directory that
|
|
will create a skeleton for a new module. For the purposes
|
|
of this discussion we will assume that your new module
|
|
is called ``new-module``. From the top directory, do the following
|
|
to create the new module:
|
|
|
|
.. sourcecode:: bash
|
|
|
|
$ ./utils/create-module.py new-module
|
|
|
|
By default ``create-module.py`` creates the module skeleton in the
|
|
``src`` directory. However, it can also create modules in ``contrib``:
|
|
|
|
.. sourcecode:: bash
|
|
|
|
$ ./utils/create-module.py contrib/new-contrib
|
|
|
|
Let's assume we've created our new module in ``src``.
|
|
``cd`` into ``src/new-module``; you will find this directory layout:
|
|
|
|
.. sourcecode:: text
|
|
|
|
$ cd new-module
|
|
$ ls
|
|
doc examples helper model test CMakeLists.txt
|
|
|
|
In more detail, the ``create-module.py`` script will create the
|
|
directories as well as initial skeleton ``CMakeLists.txt``, ``.h``, ``.cc``
|
|
and ``.rst`` files. The complete module with skeleton files looks like this:
|
|
|
|
.. sourcecode:: text
|
|
|
|
src/
|
|
new-module/
|
|
doc/
|
|
new-module.rst
|
|
examples/
|
|
new-module-example.cc
|
|
CMakeLists.txt
|
|
helper/
|
|
new-module-helper.cc
|
|
new-module-helper.h
|
|
model/
|
|
new-module.cc
|
|
new-module.h
|
|
test/
|
|
new-module-test-suite.cc
|
|
CMakeLists.txt
|
|
|
|
(If required the ``bindings/`` directory listed in
|
|
:ref:`Step-0 <Step-0>` will be created automatically during
|
|
the build.)
|
|
|
|
We next walk through how to customize this module. Informing ``ns3``
|
|
about the files which make up your module is done by editing the two
|
|
``CMakeLists.txt`` files. We will walk through the main steps in this chapter.
|
|
|
|
All |ns3| modules depend on the ``core`` module and usually on
|
|
other modules. This dependency is specified in the ``CMakeLists.txt`` file
|
|
(at the top level of the module, not the separate ``CMakeLists.txt`` file
|
|
in the ``examples`` directory!). In the skeleton ``CMakeLists.txt``
|
|
the call that will declare your new module to ``ns3`` will look
|
|
like this (before editing):
|
|
|
|
.. sourcecode:: cmake
|
|
|
|
build_lib(
|
|
LIBNAME new-module
|
|
SOURCE_FILES helper/new-module-helper.cc
|
|
model/new-module.cc
|
|
HEADER_FILES helper/new-module-helper.h
|
|
model/new-module.h
|
|
LIBRARIES_TO_LINK ${libcore}
|
|
TEST_SOURCES test/new-module-test-suite.cc
|
|
)
|
|
|
|
Let's assume that ``new-module`` depends on the ``internet``,
|
|
``mobility``, and ``aodv`` modules. After editing it the ``CMakeLists.txt`` file
|
|
should look like:
|
|
|
|
.. sourcecode:: cmake
|
|
|
|
build_lib(
|
|
LIBNAME new-module
|
|
SOURCE_FILES helper/new-module-helper.cc
|
|
model/new-module.cc
|
|
HEADER_FILES helper/new-module-helper.h
|
|
model/new-module.h
|
|
LIBRARIES_TO_LINK
|
|
${libinternet}
|
|
${libmobility}
|
|
${libaodv}
|
|
TEST_SOURCES test/new-module-test-suite.cc
|
|
)
|
|
|
|
Note that only first level module dependencies should be listed, which
|
|
is why we removed ``core``; the ``internet`` module in turn depends on
|
|
``core``.
|
|
|
|
Your module will most likely have model source files. Initial skeletons
|
|
(which will compile successfully) are created in ``model/new-module.cc``
|
|
and ``model/new-module.h``.
|
|
|
|
If your module will have helper source files, then they will go into
|
|
the ``helper/`` directory; again, initial skeletons are created
|
|
in that directory.
|
|
|
|
Finally, it is good practice to write tests and examples. These will
|
|
almost certainly be required for new modules to be accepted into
|
|
the official |ns3| source tree. A skeleton
|
|
test suite and test case is created in the ``test/`` directory.
|
|
The skeleton test suite will contain the below constructor,
|
|
which declares a new unit test named ``new-module``,
|
|
with a single test case consisting of the class ``NewModuleTestCase1``::
|
|
|
|
NewModuleTestSuite::NewModuleTestSuite()
|
|
: TestSuite("new-module", Type::UNIT)
|
|
{
|
|
AddTestCase(new NewModuleTestCase1);
|
|
}
|
|
|
|
Step 3 - Declare Source Files
|
|
*****************************
|
|
|
|
The public header and source code files for your new module
|
|
should be specified in the ``CMakeLists.txt`` file by modifying it with
|
|
your text editor.
|
|
|
|
As an example, after declaring the ``spectrum`` module,
|
|
the ``src/spectrum/CMakeLists.txt`` specifies the source code files
|
|
with the following:
|
|
|
|
.. sourcecode:: cmake
|
|
|
|
set(source_files
|
|
helper/adhoc-aloha-noack-ideal-phy-helper.cc
|
|
helper/spectrum-analyzer-helper.cc
|
|
helper/spectrum-helper.cc
|
|
...
|
|
)
|
|
|
|
set(header_files
|
|
helper/adhoc-aloha-noack-ideal-phy-helper.h
|
|
helper/spectrum-analyzer-helper.h
|
|
helper/spectrum-helper.h
|
|
...
|
|
)
|
|
|
|
build_lib(
|
|
LIBNAME spectrum
|
|
SOURCE_FILES ${source_files}
|
|
HEADER_FILES ${header_files}
|
|
LIBRARIES_TO_LINK ${libpropagation}
|
|
${libantenna}
|
|
TEST_SOURCES
|
|
test/spectrum-ideal-phy-test.cc
|
|
test/spectrum-interference-test.cc
|
|
test/spectrum-value-test.cc
|
|
test/spectrum-waveform-generator-test.cc
|
|
test/three-gpp-channel-test-suite.cc
|
|
test/tv-helper-distribution-test.cc
|
|
test/tv-spectrum-transmitter-test.cc
|
|
)
|
|
|
|
|
|
Note: the ``source_files`` and ``header_files`` lists are not necessary.
|
|
They are used keep the ``build_lib`` macro readable for modules with many
|
|
source files.
|
|
|
|
The objects resulting from compiling these sources will be assembled
|
|
into a link library, which will be linked to any programs relying on this
|
|
module.
|
|
|
|
But how do such programs learn the public API of our new module? Read on!
|
|
|
|
Step 4 - Declare Public Header Files
|
|
************************************
|
|
|
|
The header files defining the public API of your model and helpers
|
|
also should be specified in the ``CMakeLists.txt`` file.
|
|
|
|
Continuing with the ``spectrum`` model illustration,
|
|
the public header files are specified with the following stanza.
|
|
(Note that the variable ``header_files`` tells
|
|
``CMake`` to install this module's headers with the other |ns3| headers):
|
|
|
|
.. sourcecode:: cmake
|
|
|
|
set(header_files
|
|
helper/adhoc-aloha-noack-ideal-phy-helper.h
|
|
helper/spectrum-analyzer-helper.h
|
|
...
|
|
model/tv-spectrum-transmitter.h
|
|
model/waveform-generator.h
|
|
model/wifi-spectrum-value-helper.h
|
|
)
|
|
|
|
build_lib(
|
|
LIBNAME spectrum
|
|
...
|
|
HEADER_FILES ${header_files}
|
|
...
|
|
)
|
|
|
|
If the list of headers is short, use the following instead:
|
|
|
|
.. sourcecode:: cmake
|
|
|
|
build_lib(
|
|
LIBNAME spectrum
|
|
...
|
|
HEADER_FILES
|
|
helper/adhoc-aloha-noack-ideal-phy-helper.h
|
|
helper/spectrum-analyzer-helper.h
|
|
...
|
|
model/tv-spectrum-transmitter.h
|
|
model/waveform-generator.h
|
|
model/wifi-spectrum-value-helper.h
|
|
...
|
|
)
|
|
|
|
|
|
Headers made public in this way will be accessible to users of your model
|
|
with include statements like
|
|
|
|
.. sourcecode:: cpp
|
|
|
|
#include "ns3/spectrum-model.h"
|
|
|
|
Headers used strictly internally in your implementation should not
|
|
be included here. They are still accessible to your implementation by
|
|
include statements like
|
|
|
|
.. sourcecode:: cpp
|
|
|
|
#include "my-module-implementation.h"
|
|
|
|
|
|
Step 5 - Declare Tests
|
|
**********************
|
|
|
|
If your new module has tests, then they must be specified in your
|
|
``CMakeLists.txt`` file by modifying it with your text editor.
|
|
|
|
The ``spectrum`` model tests are specified with the following stanza:
|
|
|
|
.. sourcecode:: cmake
|
|
|
|
build_lib(
|
|
LIBNAME spectrum
|
|
...
|
|
TEST_SOURCES
|
|
test/spectrum-ideal-phy-test.cc
|
|
test/spectrum-interference-test.cc
|
|
test/spectrum-value-test.cc
|
|
test/spectrum-waveform-generator-test.cc
|
|
test/three-gpp-channel-test-suite.cc
|
|
test/tv-helper-distribution-test.cc
|
|
test/tv-spectrum-transmitter-test.cc
|
|
)
|
|
|
|
See :doc:`Tests <tests>` for more information on how to write test cases.
|
|
|
|
Step 6 - Declare Examples
|
|
*************************
|
|
|
|
If your new module has examples, then they must be specified in your
|
|
``examples/CMakeLists.txt`` file. (The skeleton top-level ``CMakeLists.txt`` will
|
|
recursively include ``examples/CMakeLists.txt`` only if the examples were
|
|
enabled at configure time.)
|
|
|
|
The ``spectrum`` model defines it's first example in
|
|
``src/spectrum/examples/CMakeLists.txt`` with
|
|
|
|
.. sourcecode:: cmake
|
|
|
|
build_lib_example(
|
|
NAME adhoc-aloha-ideal-phy
|
|
SOURCE_FILES adhoc-aloha-ideal-phy.cc
|
|
LIBRARIES_TO_LINK
|
|
${libspectrum}
|
|
${libmobility}
|
|
${libinternet}
|
|
${libapplications}
|
|
)
|
|
|
|
|
|
Note that the variable ``libraries_to_link`` is the list of modules that
|
|
the program being created depends on; again, don't forget to include
|
|
``new-module`` in the list. It's best practice to list only the direct
|
|
module dependencies, and let ``CMake`` deduce the full dependency tree.
|
|
|
|
Occasionally, for clarity, you may want to split the implementation
|
|
for your example among several source files. In this case, just
|
|
include those files as additional explicit sources of the example:
|
|
|
|
.. sourcecode:: cmake
|
|
|
|
build_lib_example(
|
|
NAME new-module-example
|
|
SOURCE_FILES new-module-example.cc
|
|
LIBRARIES_TO_LINK
|
|
${libspectrum}
|
|
${libmobility}
|
|
${libinternet}
|
|
${libapplications}
|
|
)
|
|
|
|
Step 7 - Examples Run as Tests
|
|
******************************
|
|
|
|
In addition to running explicit test code, the test framework
|
|
can also be instrumented to run full example programs to
|
|
try to catch regressions in the examples. However, not all examples
|
|
are suitable for regression tests. The file ``test/examples-to-run.py``
|
|
controls the invocation of the examples when the test framework runs.
|
|
|
|
The ``spectrum`` model examples run by ``test.py`` are specified in
|
|
``src/spectrum/test/examples-to-run.py`` using the following
|
|
two lists of C++ and Python examples:
|
|
|
|
.. sourcecode:: python
|
|
|
|
# A list of C++ examples to run in order to ensure that they remain
|
|
# buildable and runnable over time. Each tuple in the list contains
|
|
#
|
|
# (example_name, do_run, do_valgrind_run, fullness).
|
|
#
|
|
# See test.py for more information.
|
|
cpp_examples = [
|
|
("adhoc-aloha-ideal-phy", "True", "True", "QUICK"),
|
|
("adhoc-aloha-ideal-phy-with-microwave-oven", "True", "True", "QUICK"),
|
|
("adhoc-aloha-ideal-phy-matrix-propagation-loss-model", "True", "True", "QUICK"),
|
|
]
|
|
|
|
# A list of Python examples to run in order to ensure that they remain
|
|
# runnable over time. Each tuple in the list contains
|
|
#
|
|
# (example_name, do_run, fullness).
|
|
#
|
|
# See test.py for more information.
|
|
python_examples = [
|
|
("sample-simulator.py", "True", "QUICK"),
|
|
]
|
|
|
|
As indicated in the comment, each entry in the C++ list of examples to run
|
|
contains the tuple ``(example_name, do_run, do_valgrind_run, fullness)``, where
|
|
|
|
* ``example_name`` is the executable to be run,
|
|
* ``do_run`` is a condition under which to run the example, and
|
|
* ``do_valgrind_run`` is a condition under which to run the example
|
|
under valgrind. (This is needed because NSC causes illegal instruction
|
|
crashes with some tests when they are run under valgrind.)
|
|
* ``fullness`` is the optional classification of how long the example takes to
|
|
run, like the :doc:`Tests <tests>` fullness specifier. from
|
|
fastest to slowest the possible options are: ``"QUICK"``,
|
|
``"EXTENSIVE"``, and ``"TAKES_FOREVER"``. If no value is
|
|
provided, ``"QUICK"`` is used.
|
|
|
|
Note that the two conditions are Python statements that
|
|
can depend on ``ns3`` configuration variables. For example, using the
|
|
NSC_ENABLED variable that was defined up until ns-3.35:
|
|
|
|
.. sourcecode:: python
|
|
|
|
("tcp-nsc-lfn", "NSC_ENABLED == True", "NSC_ENABLED == False", "QUICK"),
|
|
|
|
Each entry in the Python list of examples to run contains the tuple
|
|
``(example_name, do_run, fullness)``, where, as for the C++ examples,
|
|
|
|
* ``example_name`` is the Python script to be run, and
|
|
* ``do_run`` is a condition under which to run the example.
|
|
* ``fullness`` is the same as ``fullness`` for C++ examples.
|
|
If no value is provided, ``"QUICK"`` is used
|
|
|
|
Again, the condition is a Python statement that can
|
|
depend on ``ns3`` configuration variables. For example,
|
|
|
|
.. sourcecode:: python
|
|
|
|
("brite-generic-example.py", "ENABLE_BRITE == True", "QUICK"),
|
|
|
|
|
|
Step 8 - Configure and Build
|
|
****************************
|
|
|
|
You can now configure, build and test your module as normal.
|
|
You must reconfigure the project as a first step so that ``ns3``
|
|
caches the new information in your ``CMakeLists.txt`` files,
|
|
or else your new module will not be included in the build.
|
|
|
|
.. sourcecode:: bash
|
|
|
|
$ ./ns3 configure --enable-examples --enable-tests
|
|
$ ./ns3 build
|
|
$ ./test.py
|
|
|
|
Look for your new module's test suite (and example programs,
|
|
if your module has any enabled) in the test output.
|
|
|
|
|
|
Step 9 - Python Bindings
|
|
************************
|
|
|
|
Adding Python bindings to your module is optional.
|
|
|
|
If you want to include Python bindings (needed only if you want
|
|
to write Python ns-3 programs instead of C++ ns-3 programs), you
|
|
should scan your module to generate new bindings for the Python
|
|
API (covered elsewhere in this manual), and they will be used
|
|
if NS3_PYTHON_BINDINGS is set to ON.
|