2010-12-30 23:39:27 +01:00
.. include :: replace.txt
2013-07-17 17:09:36 -07:00
.. highlight :: python
2010-12-30 23:39:27 +01:00
2017-11-13 14:39:51 -08:00
.. heading hierarchy:
------------- Chapter
***** ***** *** Section (#.#)
============= Subsection (#.#.#)
############# Paragraph (no number)
2011-06-17 13:36:07 -07:00
Using Python to Run |ns3|
-------------------------
2010-12-30 23:39:27 +01:00
2011-06-17 13:36:07 -07:00
Python bindings allow the C++ code in |ns3| to be called from Python.
2010-12-30 23:39:27 +01:00
2011-06-17 13:36:07 -07:00
This chapter shows you how to create a Python script that can run |ns3| and also the process of creating Python bindings for a C++ |ns3| module.
Introduction
***** ***** **
2016-10-03 15:51:13 -07:00
Python bindings provide support for importing |ns3| model libraries as Python
modules. Coverage of most of the |ns3| C++ API is provided. The intent
has been to allow the programmer to write complete simulation scripts in
Python, to allow integration of |ns3| with other Python tools and workflows.
The intent is not to provide a different language choice to author new
|ns3| models implemented in Python.
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
Python bindings for |ns3| use a tool called Cppyy (https://cppyy.readthedocs.io/en/latest/)
to create a Python module from the C++ libraries built by CMake. The Python bindings that Cppyy
uses are built at runtime, by importing the C++ libraries and headers for each ns-3 module.
This means that even if the C++ API changes, the Python bindings will adapt to them
without requiring any preprocessing or scanning.
If a user is not interested in Python, no action is needed; the Python bindings
are only built on-demand by Cppyy.
As of ns-3.37, the previous Python bindings framework based on Pybindgen has been
removed due to a lack of active maintainers. The Cppyy frameword that replaced
it may also be removed from future ns-3 releases if new maintainers are not found.
2022-04-17 15:46:35 -07:00
2011-06-17 13:36:07 -07:00
An Example Python Script that Runs |ns3|
***** ***** ***** ***** ***** ***** ***** *****
Here is some example code that is written in Python and that runs |ns3|, which is written in C++. This Python example can be found in `` examples/tutorial/first.py `` :
::
2022-08-01 17:34:51 -03:00
from ns import ns
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
nodes = ns.network.NodeContainer()
nodes.Create(2)
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
pointToPoint = ns.point_to_point.PointToPointHelper()
pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
devices = pointToPoint.Install(nodes)
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
stack = ns.internet.InternetStackHelper()
stack.Install(nodes)
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
address = ns.internet.Ipv4AddressHelper()
2022-08-01 17:34:51 -03:00
address.SetBase(ns.network.Ipv4Address("10.1.1.0"),
ns.network.Ipv4Mask("255.255.255.0"))
2022-06-05 21:01:11 -07:00
2022-08-01 17:34:51 -03:00
interfaces = address.Assign(devices)
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
echoServer = ns.applications.UdpEchoServerHelper(9)
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
serverApps = echoServer.Install(nodes.Get(1))
serverApps.Start(ns.core.Seconds(1.0))
serverApps.Stop(ns.core.Seconds(10.0))
2022-06-05 21:01:11 -07:00
2022-08-01 17:34:51 -03:00
address = ns.addressFromIpv4Address(interfaces.GetAddress(1))
echoClient = ns.applications.UdpEchoClientHelper(address, 9)
2011-06-17 13:36:07 -07:00
echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
2022-08-01 17:34:51 -03:00
echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
2011-06-17 13:36:07 -07:00
echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
clientApps = echoClient.Install(nodes.Get(0))
clientApps.Start(ns.core.Seconds(2.0))
clientApps.Stop(ns.core.Seconds(10.0))
2022-06-05 21:01:11 -07:00
2011-06-17 13:36:07 -07:00
ns.core.Simulator.Run()
ns.core.Simulator.Destroy()
2022-08-01 17:34:51 -03:00
2011-06-17 13:36:07 -07:00
Running Python Scripts
***** ***** ***** ***** **
2022-04-17 15:46:35 -07:00
First, we need to enable the build of Python bindings:
2022-01-31 20:02:10 -03:00
.. sourcecode :: bash
2022-08-01 17:34:51 -03:00
$ ./ns3 configure
2022-01-31 20:02:10 -03:00
2022-04-17 15:46:35 -07:00
Other options such as `` --enable-examples `` may be passed to the above command.
2022-08-01 17:34:51 -03:00
ns3 contains some options that automatically update the python path to find the ns3 module.
To run example programs, there are two ways to use ns3 to take care of this. One is to run a ns3 shell; e.g.:
2011-06-17 13:36:07 -07:00
2013-07-17 17:09:36 -07:00
.. sourcecode :: bash
2011-06-17 13:36:07 -07:00
2021-11-29 21:58:30 -03:00
$ ./ns3 shell
2022-04-17 15:46:35 -07:00
$ python3 examples/wireless/mixed-wireless.py
2011-06-17 13:36:07 -07:00
2022-01-31 20:02:10 -03:00
and the other is to use the 'run' option to ns3:
2011-06-17 13:36:07 -07:00
2013-07-17 17:09:36 -07:00
.. sourcecode :: bash
2011-06-17 13:36:07 -07:00
2022-01-13 23:59:59 -03:00
$ ./ns3 run examples/wireless/mixed-wireless.py
2011-06-17 13:36:07 -07:00
2022-01-31 20:02:10 -03:00
Use the `` --no-build `` option to run the program without invoking a project rebuild.
This option may be useful to improve execution time when running the same program
repeatedly but with different arguments, such as from scripts.
2019-04-03 15:34:32 -07:00
.. sourcecode :: bash
2022-04-17 15:46:35 -07:00
$ ./ns3 run --no-build examples/wireless/mixed-wireless.py
2019-04-03 15:34:32 -07:00
2011-06-17 13:36:07 -07:00
To run a python script under the C debugger:
2013-07-17 17:09:36 -07:00
.. sourcecode :: bash
2011-06-17 13:36:07 -07:00
2021-11-29 21:58:30 -03:00
$ ./ns3 shell
2022-04-17 15:46:35 -07:00
$ gdb --args python3 examples/wireless/mixed-wireless.py
2011-06-17 13:36:07 -07:00
To run your own Python script that calls |ns3| and that has this path, `` /path/to/your/example/my-script.py `` , do the following:
2013-07-17 17:09:36 -07:00
.. sourcecode :: bash
2011-06-17 13:36:07 -07:00
2021-11-29 21:58:30 -03:00
$ ./ns3 shell
2022-04-17 15:46:35 -07:00
$ python3 /path/to/your/example/my-script.py
2011-06-17 13:36:07 -07:00
Caveats
***** **
2022-08-01 17:34:51 -03:00
Some of the limitations of the Cppyy-based byindings are listed here.
2011-06-17 13:36:07 -07:00
Incomplete Coverage
2017-11-13 14:39:51 -08:00
===================
2011-06-17 13:36:07 -07:00
First of all, keep in mind that not 100% of the API is supported in Python. Some of the reasons are:
2022-08-01 17:34:51 -03:00
Memory-management issues
########################
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
Some of the APIs involve pointers, which require knowledge of what kind of memory passing semantics (who owns what memory).
Such knowledge is not part of the function signatures, and is either documented or sometimes not even documented.
You may need to workaround these issues by instantiating variables on the C++ side with a Just-In-Time (JIT) compiled function.
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
For example, when handling command-line arguments, we could set additional parameters like in the following code:
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
.. sourcecode :: python
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
# Import the ns-3 C++ modules with Cppyy
from ns import ns
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
# ns.cppyy.cppdef compiles the code defined in the block
# The defined types, values and functions are available in ns.cppyy.gbl
ns.cppyy.cppdef("""
using namespace ns3;
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
CommandLine& GetCommandLine(std::string filename, int& nCsma, bool& verbose)
{
static CommandLine cmd = CommandLine(filename);
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma);
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose);
return cmd;
}
""")
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
# To pass the addresses of the Python variables to c++, we need to use ctypes
from ctypes import c_int, c_bool
nCsma = c_int(3)
verbose = c_bool(True)
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
# Pass the addresses of Python variables to C++
cmd = ns.cppyy.gbl.GetCommandLine(__file__, nCsma, verbose)
cmd.Parse(sys.argv)
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
If you find a segmentation violation, be sure to wait for the stacktrace provided by Cppyy
and try to find the root cause of the issue. If you have multiple cores, the number of
stacktraces will correspond to the number of threads being executed by Cppyy. To limit them,
define the environment variable `OPENBLAS_NUM_THREADS=1` .
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
Operators
#########
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
Cppyy may fail to map C++ operators due to the implementation style used by ns-3.
This happens for the fundamental type `Time` . To provide the expected behavior, we
redefine these operators from the Python side during the setup of the ns-3 bindings
module (`ns-3-dev/bindings/python/ns__init__.py` ).
.. sourcecode :: python
# Redefine Time operators
cppyy.cppdef("""
using namespace ns3;
bool Time_ge(Time& a, Time& b){ return a >= b;}
bool Time_eq(Time& a, Time& b){ return a == b;}
bool Time_ne(Time& a, Time& b){ return a != b;}
bool Time_le(Time& a, Time& b){ return a <= b;}
bool Time_gt(Time& a, Time& b){ return a > b;}
bool Time_lt(Time& a, Time& b){ return a < b;}
""")
cppyy.gbl.ns3.Time.__ge__ = cppyy.gbl.Time_ge
cppyy.gbl.ns3.Time.__eq__ = cppyy.gbl.Time_eq
cppyy.gbl.ns3.Time.__ne__ = cppyy.gbl.Time_ne
cppyy.gbl.ns3.Time.__le__ = cppyy.gbl.Time_le
cppyy.gbl.ns3.Time.__gt__ = cppyy.gbl.Time_gt
cppyy.gbl.ns3.Time.__lt__ = cppyy.gbl.Time_lt
A different operator used by ns-3 is `operator Address()` , used to
convert different types of Addresses into the generic type Address.
This is not supported by Cppyy and requires explicit conversion.
Some helpers have been added to handle the common cases.
.. sourcecode :: python
# Define ns.cppyy.gbl.addressFromIpv4Address and others
cppyy.cppdef("""using namespace ns3;
Address addressFromIpv4Address(Ipv4Address ip){ return Address(ip); };
Address addressFromInetSocketAddress(InetSocketAddress addr){ return Address(addr); };
Address addressFromPacketSocketAddress(PacketSocketAddress addr){ return Address(addr); };
""")
# Expose addressFromIpv4Address as a member of the ns3 namespace (equivalent to ns)
setattr(cppyy.gbl.ns3, "addressFromIpv4Address", cppyy.gbl.addressFromIpv4Address)
setattr(cppyy.gbl.ns3, "addressFromInetSocketAddress", cppyy.gbl.addressFromInetSocketAddress)
setattr(cppyy.gbl.ns3, "addressFromPacketSocketAddress", cppyy.gbl.addressFromPacketSocketAddress)
Most of the missing APIs can be wrapped, given enough time, patience, and expertise, and will likely be wrapped if bug reports are submitted.
However, don't file a bug report saying "bindings are incomplete", because the project does not have maintainers to maintain every API.
2011-06-17 13:36:07 -07:00
Tracing
2017-11-13 14:39:51 -08:00
=======
2011-06-17 13:36:07 -07:00
Callback based tracing is not yet properly supported for Python, as new |ns3| API needs to be provided for this to be supported.
Pcap file writing is supported via the normal API.
2022-08-01 17:34:51 -03:00
ASCII tracing is supported via the normal C++ API translated to Python.
However, ASCII tracing requires the creation of an ostream object to pass into the ASCII tracing methods.
In Python, the C++ std::ofstream has been minimally wrapped to allow this. For example:
2011-06-17 13:36:07 -07:00
::
2022-08-01 17:34:51 -03:00
ascii = ns.ofstream("wifi-ap.tr") # create the file
ns.YansWifiPhyHelper.EnableAsciiAll(ascii)
ns.Simulator.Run()
ns.Simulator.Destroy()
2011-06-17 13:36:07 -07:00
ascii.close() # close the file
2022-08-01 17:34:51 -03:00
There is one caveat: you must not allow the file object to be garbage collected while |ns3| is still using it.
That means that the 'ascii' variable above must not be allowed to go out of scope or else the program will crash.
2011-06-17 13:36:07 -07:00
Working with Python Bindings
***** ***** ***** ***** ***** ***
2022-06-05 21:01:11 -07:00
Python bindings are built on a module-by-module basis, and can be found in each module's `` bindings `` directory.
2011-06-17 13:36:07 -07:00
2016-10-03 15:51:13 -07:00
Overview
2017-11-13 14:39:51 -08:00
========
2011-06-17 13:36:07 -07:00
2016-10-03 15:51:13 -07:00
The python bindings are generated into an 'ns' namespace. Examples:
2011-06-17 13:36:07 -07:00
2016-10-03 15:51:13 -07:00
::
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
from ns import ns
n1 = ns.network.Node()
2011-06-17 13:36:07 -07:00
2016-10-03 15:51:13 -07:00
or
2011-06-17 13:36:07 -07:00
2016-10-03 15:51:13 -07:00
::
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
from ns import*
2016-10-03 15:51:13 -07:00
n1 = ns.network.Node()
2011-06-17 13:36:07 -07:00
2016-10-03 15:51:13 -07:00
The best way to explore the bindings is to look at the various example
programs provided in |ns3|; some C++ examples have a corresponding Python
example. There is no structured documentation for the Python bindings
like there is Doxygen for the C++ API, but the Doxygen can be consulted
to understand how the C++ API works.
2011-06-17 13:36:07 -07:00
2021-03-19 07:42:45 -07:00
Historical Information
***** ***** ***** ***** **
2011-06-17 13:36:07 -07:00
2022-08-01 17:34:51 -03:00
If you are a developer and need more background information on |ns3|'s Python bindings,
please see the `Python Bindings wiki page <http://www.nsnam.org/wiki/NS-3_Python_Bindings> `_ .
Please note, however, that some information on that page is stale.