4. Submitting new models

We actively encourage submission of new features to ns-3. Independent submissions are essential for open source projects, and if accepted into the mainline, you will also be credited as an author of future versions of ns-3. However, please keep in mind that there is already a large burden on the ns-3 maintainers to manage the flow of incoming contributions and maintain new and existing code. The goal of this chapter is to outline the options for new models in ns-3, and how you can help to minimize the burden on maintainers and thus minimize the average time-to-merge of your code.

4.1. Options for new models

ns-3 is organized into modules, each of which is compiled and linked into a separate library. Users can selectively enable and disable the inclusion of modules (via the –enable-modules argument to ns3 configure, or via the selective inclusion of contributed modules).

When proposing new models to ns-3, please keep in mind that not all models will be accepted into the mainline. However, we aim to provide at least one or more options for any code contribution.

Because of the long-term maintenance burden, ns-3 is no longer accepting all new proposals into the mainline. Features that are of general interest are more likely to be approved for the mainline, but features that are more specialized may be recommended for the ns-3 App Store. Some modules that have been in the mainline for a long time, but fall out of use (or lose their maintainers) may also be moved out of the mainline into the App Store in the future.

The options for publishing new models are:

  1. Propose a Merge Request for the ns-3 mainline and follow the guidelines below.
  2. Organize your code as a “contributed module” or modules and maintain them in your own public Git repository. A page on the App Store can be made to advertise this to users, and other tooling can be used to ensure that the module stays compatible with the mainline.
  3. Organize your code as a “public fork” that evolves separately from the ns-3 mainline. This option is sometimes chosen for models that require significant intrusive changes to the ns-3 mainline to support. Some recent examples include the Public Safety models and the millimeter-wave extensions to ns-3. This has the benefit of being self-contained, but the drawback of losing compatibility with the mainline over time. A page on the App Store can be made for these forks as well. For maintenance reasons and improved user experience, we prefer to upstream mainline changes so that public forks can be avoided.
  4. Archive your code somewhere, or publish in a Git repository, and link to it from the ns-3 Contributed Code wiki page. This option requires the least amount of work from the contributor, but visibility of the code to new ns-3 users will likely be reduced. To follow this route, obtain a wiki account from the webmaster, and make edits as appropriate to link your code.

The remainder of the chapter concerns option 1 (upstreaming to ns-3-dev); the other options are described in the next chapter (Submitting externally maintained code).

4.2. Upstreaming new models

The term “upstreaming” refers to the process whereby new code is contributed back to an upstream source (the main open source project) whereby that project takes responsibility for further enhancement and maintenance.

Making sure that each code submission fulfills as many items as possible in the following checklist is the best way to ensure quick merging of your code.

In brief, we can summarize the guidelines as follows:

  1. Be licensed appropriately (see General)
  2. Understand how and why ns-3 conducts code reviews before merging
  3. Follow the ns-3 coding style (Coding style) and software engineering and consistency feedback that maintainers may provide
  4. Write associated documentation, tests, and example programs

If you do not have the time to follow through the process to include your code in the main tree, please see the next chapter (Submitting externally maintained code) about contributing ns-3 code that is not maintained in the main tree.

The process can take a long time when submissions are large or when contributors skip some of these steps. Therefore, best results are found when the following guidelines are followed:

  • Ask for review of small chunks of code, rather than large patches. Split large submissions into several more manageable pieces.
  • Make sure that the code follows the guidelines (coding style, documentation, tests, examples) or you may be asked to fix these things before maintainers look at it again.

4.3. Code reviews

Code submissions to ns-3-dev are expected to go through a review process where one or more maintainers comment on the code. The basic purpose of the code reviews is to ensure the long-term maintenance and overall system integrity of ns-3. Contributors may be asked to revise their code or rewrite portions during this process. New features are also typically only merged during the early stages of a new release cycle, to avoid destabilizing code before release.

ns-3 code reviews are conducted using GitLab.com merge requests, possibly supported by discussion on the ns-developers mailing list for reviews that involve code that cuts across maintainer boundaries or is otherwise controversial. Many examples of ongoing reviews can be browsed on our GitLab.com site.

4.4. Submission structure

For each code submission, include a description of what your code is doing, and why. Ideally, you should be able to provide a summary description in a short paragraph at the top of the Merge Request. If you want to flag to maintainers that your submission is known to be incomplete (e.g., you are looking for early feedback), preface the title of the Merge Request with Draft:.

4.4.1. Coherent and multi-part submissions

Large code submissions should be split into smaller submissions where possible. The likelihood of getting maintainers to review your submission is inversely proportional to its size, because large code reviews require a large block of time for a maintainer. For instance, if you are submitting two routing protocol models and each protocol model can stand on its own, submit two Merge Requests rather than a single one containing both models.

Each submission should be a coherent whole: if you need to edit ten files to get a feature to work, then, the submission should contain all the changes for these ten files. Of course, if you can split the feature in sub-features, then, you should do it to decrease the size of the submission as per the previous paragraph.

For example, if you have made changes to optimize one module, and in the course of doing so, you fixed a bug in another module, make sure you separate these two sets of changes in two separate submissions.

When splitting a large submission into separate submissions, (ideally) these submissions should be prefaced (in the Merge Request description) by a detailed explanation of the overall plan such that code reviewers can review each submission separately but within a larger context. This kind of submission typically is split in multiple dependent steps where each step depends on the previous one. If this is the case, make it very clear in your initial explanation. If you can, minimize dependencies between each step such that reviewers can merge each step separately without having to consider the impact of merging one submission on other submissions.

4.4.2. History rewriting

It is good practice to rebase your feature branch onto the tip of the (evolving) ns-3-dev, so that the commits appear on top of a recent commit of ns-3-dev. For instance, you may have started with an initial Merge Request, and it has been some time to gather feedback from maintainers, and now you want to update your Merge Request with that feedback. A rebase onto the current ns-3-dev master branch is good practice for any Merge Request update.

In addition, in the course of your development, and in responding to reviewer comments, the git commit log will accumulate lots of small commits that are not helpful to future maintainers: they make it more painful to use the annotate and bisect commands. For this reason, it is good practice to “squash” and “rebase” commits into coherent groups. For example, assume that the commit history, after you have responded to a reviewer’s comment, looks like this:

commit 4938c01400fb961c37716c3f415f47ba2b04ab5f (HEAD -> master, origin/master, origin/HEAD)
Author: Some Contributor <some.contributor@example.com>
Date:   Mon Jun 15 11:19:49 2020 -0700

  Fix typo in Doxygen based on code review comment

commit 915cf65cb8f464d9398ddd8bea9af167ced64663
Author: Some Contributor <some.contributor@example.com>
Date:   Thu Jun 11 16:44:46 2020 -0400

  Add documentation, tests, and examples for clever protocol

commit a1d51db126fb3d1c7c76427473f02ee792fdfd53
Author: Some Contributor <some.contributor@example.com>
Date:   Thu Jun 11 16:35:48 2020 -0400

  Add new models for clever protocol

In the above case, it will be helpful to squash the top commit about the typo into the first commit where the Doxygen was first written, leaving you again with two commits. Git interactive rebase is a good tool for this; ask a maintainer for help in doing this if you need some help to learn this process.

4.5. Documentation, tests, and examples

Often we have observed that contributors will provide nice new classes implementing a new model, but will fail to include supporting test code, example scripts, and documentation. Therefore, we ask people submitting the code (who are in the best position to do this type of work) to provide documentation, test code, and example scripts.

Note that you may want to go through multiple phases of code reviews, and all of this supporting material may not be needed at the first stage (e.g. when you want some feedback on public API header declarations only, before starting the implementation). However, when it times come to merge your code, you should be prepared to provide these things, as fits your contribution (maintainers will provide some guidance here).

4.5.1. Including examples

For many submissions, it will be important to include at least one example that exercises the new code, so the reviewer understands how it is intended to be used. For final submission, please consider to add as many examples as you can that will help new users of your code. The <tt>samples/</tt> and <tt>examples/</tt> directories are places for these files.

4.5.2. Tests

All new models should include automated tests. These should, where appropriate, be unit tests of model correctness, validation tests of stochastic behavior, and overall system tests if the model’s interaction with other components must be tested. The test code should try to cover as much model code as possible, and should be checked as much as possible by regression tests.

The ns-3 manual provides documentation and suggestions for how to write tests.

4.5.3. Documentation

If you add a new features, or make changes to existing features, you need to update existing or write new documentation and example code. Consider the following checklist:

  • Doxygen should be added to header files for all public classes and methods, and should be checked for Doxygen errors
  • new features should be described in the RELEASE_NOTES.md
  • public API changes (if any) must be documented in CHANGES.html
  • new API or changes to existing API must update the inline doxygen documentation in header files
  • consider updating or adding a new section to the manual (doc/manual) or model library (doc/models) as appropriate
  • update the AUTHORS file for any new authors

4.5.4. Module dependencies

Since ns-3 is a modular system, each module has (typically) dependencies on other modules. These must be kept to the minimum necessary, and circular dependencies must be avoided (they will generate errors). As an example, the lr-wpan module depends on core, network, mobility, spectrum, and propagation. Tests for your new module must not add any other dependency (that was not needed for the model or helper code itself), but examples can use other modules because their module dependencies are handled independently. As an example, the lr-wpan examples also use the stats module.

This rule might pose limitations to the authoring of tests. In such a case, ask a maintainer for suggestions, or check existing tests to find solutions. Sometimes tests that involve adding additional dependencies are placed into the src/test subdirectory.