[Ns-developers] Cooperative ns-3 simulation with third party software via JSON-RPC

Sébastien Vincent vincent at clarinet.u-strasbg.fr
Fri Jan 9 09:09:40 PST 2009

Hello all,

Last summer at the University of Strasbourg, we began a new extension 
for ns-3 which allows external applications to
interact with ns-3. Initially those functionalities were needed to 
interconnect a mobility simulator with ns-3. The
goal is that a mobility simulator do all mobility stuff while ns-3 
realizes network (L2, L3, transport and application)

We decided that this ns-3 extension should be as generic as possible and 
that any external applications could "connect" to ns-3 via
the network. So we decided to use JSON format [1] and its remote 
procedure call version JSON-RPC [2]. We chose JSON
because it is more lightweight compared to XML (which is a very verbose 
format). During our preliminary stuff on the
implementation, we tried to find libraries for JSON and JSON-RPC. We 
focused our choice on json-cpp [3] for encoding
and decoding format but we couldn't find a C++ implementation for 
JSON-RPC. So we have contributed to the OpenSource
community by releasing on sourceforge JsonRpc-Cpp [4], a low-level 
easy-to-use implementation of JSON-RPC in C++.

The functionalities of our ns-3 extension are:
- Synchronization between external applications and ns-3;
- Get / Set properties (depending on the application);
- Request ns-3 application to send a packet;
- Notify external application when a node receives a packet.

The first external application which work with our augmented ns-3 
version is LEMMA (Layered Mobility Model Architecture)
[6], a mobility simulator developed by Alexander Pelov at the University 
of Strasbourg. There is a simple example that
can be run. See LEMMA README. We hope that the discussions following 
this announcement would lead to a rapidly growing
list of such examples.

Our JSON-RPC ns-3 implementation is available at our mercurial 
repository: https://svnet.u-strasbg.fr/hg/ns-3-jsonrpc/
Note that it lacks a few features and needs some polishing.

Let's talk about a little bit of these features and design.

1) JSON-RPC in ns-3

We use libjson-cpp and libjsonrpc-cpp to have JSON and JSON-RPC support 
in ns-3.

In order to receive JSON-RPC request, ns-3 scenarios have to have an 
JSON-RPC server instance. We retrieve JsonRpc-Cpp
server examples and adapt them in order to (for the moment) have only 
one external application connected to ns-3 at a
time. These classes are Ns3RpcServer (abstract), Ns3TcpServer and 
Ns3UdpServer. Note that these servers could be configured
to encode / decode messages with netstring format [5].

2) Synchronization

This is an important part for a collaborative work between ns-3 and 
external applications. First of all, special ns-3
scenarios wait a connection from the external application. At this point 
we can initialize some attributes, request that
ns-3 callback the external application at a certain time or even 
dynamically build simple topology. When this phase is done,
the external applications can ask ns-3 to start the simulation by 
sending a "run" RPC command. The external
application could be notified upon some events, at which point  the 
simulation is paused.
To deblock the simulation state, the external application has to send 
the "run" command.

2) RPC agent

RPC agent registers RPC methods to the native RPC server. Thus these 
methods can be called remotely. We provide two agents,
SynchronisationAgent and UpdateAgent. The first is dedicated to time and 
synchronization management and the second is used
to get / set attributes in ns-3 object.

 a) SynchronisationAgent

 SynchronisationAgent is responsible for the synchronization of the 
simulation engines (ns-3 and external application). Here is the list of 
its RPC methods:
 - run: run (or re-run after a pause) the simulation;
 - callmeat: ask ns-3 to callback the external application at specified 
time (absolute time);
 - callmeafter: ask ns-3 to callback the external application after 
specified time (relative time);
 - stopat: ask ns-3 to stop the simulation (absolute time);
 - stopafter: ask ns-3 to stop the simulation (relative time).

 List of indications that could be sent to external applications (other 
than response to RPC methods):
 - endofsimulation: notification that ns-3 simulation is done;
 - icallyou: callback the external application and put ns-3 in pause.

 b) UpdateAgent

 UpdateAgent takes care of get / set attributes in the simulation. It 
can also be used to create a simple topology so
 that external applications can build topology they want without 
redefining the same topology in ns-3 scenarios.

 List of RPC methods of UpdateAgent:
 - getposition: Get position of a node (given in parameters);
 - setposition: Set position of a node (given in parameters);
 - buildsimulation: Build a simulation (create nodes, ...).

 "buildsimulation" command should not be called after the simulation has 
been started.

3) RPC application

RPC application is special application that can notify external program 
that something happened (like packet reception).
It can also react to external application request, for example "send a 
packet to someone" which will trigger a packet

For the first capability, it registers an RPC method to the native RPC 
server. Method names depend on the application
name and the node ID (on which the application is installed). For 
example an RPC application called RpcUdpEcho installed on
node ID 3 could have the following name to receive request to send a 
packet: "udpecho.3.send". When receiving a packet, RPC
application sends a JSON-RPC indication to external application and 
pauses the simulation.

With these features, RPC application must have a reference to 
SynchronisationAgent (to pause the simulation) and to Ns3RpcServer
(to send the notification).

Such RPC application should have following RPC methods:
- nameofapp.<nodeid>.send: Trigger a packet emit.

list of of indications that such application should declare:
- packetreceived (with some extra information like source and 
destination address, packet data, ...).

Like "packetreceived" event pause the simulation, every RPC application 
must have a reference to the SynchronisationAgent.

We defined an abstract RpcApplication class which contains reference to 
SynchronisationAgent and Ns3RpcServer. The abstract
method to implement is ::RpcSend().

To quickly have an application to test, we choosed to take the existing 
rpc-udp application. We duplicated and adapted the code to make
it work. We all know that duplicating code is bad but we hope to find a 
clean solution to reuse existing apps and add our
extension methods in a generic way.

Note: for the moment data attribute of JSON-RPC indication is not set 
(it is replaced by "XXX"), see next section.

4) How it works

You can use the "scenario builder server" example (launch it via ./waf 
--run rpc-simulation). With this program you can
create your scenario topology and nodes remotely! For the moment just 
simple topology build is available, i.e. topology
without nodes between two distinct network (like a router).

All you have to do is to send JSON-RPC request to ns-3 to build your 
topology and nodes (see example of such request in
the next section). After that, you can request ns-3 to call back your 
application when a certain time is reached by using
the CallMeAt requests. When this time arrives, the ns-3 simulation is 
paused and you can for example get/set some parameters
(position, direction, ...).

You can use a specific RpcApplication (like RpcUdpEchoServer or 
RpcUdpEchoClient) which can provide application specific RPC
calls and notification mechanisms (like notify packets reception, 
trigger packets emission).

Upon simulation termination, the rpc-simulation program does not exit. 
In fact you can setup a new RPC simulation immediately.
Note that the program does not allow multiple client connection at the 
same time, so a RPC simulation is owned by its remote

Here are a complete and commented JSON-RPC exchanges of a collaborative 
simulation. You can execute this example yourself
by launching ./waf --run rpc-simulation, connect via telnet or netcat 
and type every "-->" commands (one by one) to see
progression of the simulation.

# Example of JSON-RPC interactions between ns-3 and external application.
# --> message sent from external application to ns-3
# <-- message sent from ns-3 to external application

# Get the list of RPC methods
--> {"id":0, "jsonrpc":"2.0", "method":"system.describe"}
a simulation (topology, nodes, 
...).","parameters":{"application":{"description":"Install the specified 
application (may depend on a particular network stack).","type":"enum : 
udpecho | null"},"mobility":{"description":"Wheter or not install 
model.","type":"boolean"},"network_stack":{"description":"Install the 
specified network stack.","type":"enum : ipv4 | 
identifier.","type":"integer"},"number":{"description":"Number of nodes 
to create.","type":"integer"},"topology":{"description":"Topology 
type.","type":"enum : csma | wifi | point-to-point"}},"returns":"success 
| failure"},"callmeafter":{"description":"Schedule task at relative time 
that will send data to external application and block (to deblock call 
Run).","parameters":{"time":{"description":"Relative time (in 
task at absolute time that will send data to external application and 
block (to deblock call 
Run).","parameters":{"time":{"description":"Absolute time (in 
position of a node.","parameters":{"nodeid":{"description":"Node 
value (in gradients)","type":"double"},"nodeid":{"description":"Node 
value","type":"double"}}},"run":{"description":"Deblock the simulator 
(after a CallMeAt / CallMeAfter 
position of a node.","parameters":{"dir":{"description":"Direction value 
(in gradients)","type":"double"},"nodeid":{"description":"Node 
value","type":"double"}},"returns":"success | 
failure"},"stopafter":{"description":"Stop the simulation at relative 
time.","parameters":{"time":{"description":"Relative time (in 
the simulation at absolute 
time.","parameters":{"time":{"description":"Absolute time (in 
the RPC methods available","parameters":null,"returns":"Object that 
contains description of all methods registered"}}}

# Non-existent RPC => error
--> {"jsonrpc": "2.0", "id":0, "method":"rrrrun"}
<-- {"error":{"code":-32601,"message":"Procedure not 

# Build a simulation (create nodes, topology, ...)
--> {"jsonrpc":"2.0", "id":1, "method":"buildsimulation", 
"params":{"topology":"csma", "mobility":true, "network_stack":"ipv4", 
"application":"udpecho", "number":50}}
<-- {"id":1,"jsonrpc":"2.0","result":"success"}

# CallMeAt procedure
--> {"jsonrpc":"2.0", "id":2, "method":"callmeat", "params":{"time":1000}}
<-- {"id":2,"jsonrpc":"2.0","result":"success"}

# Run the simulation
--> {"jsonrpc":"2.0", "id":3, "method":"run"}

# Time has come, ns-3 callback external program
<-- {"jsonrpc":"2.0","result":{"time":1000,"type":"icallyou"}}

# Get position of node 1
--> {"jsonrpc":"2.0", "id":4, "method":"getposition", "params":{"nodeid":1}}

# Set position of node 2
--> {"jsonrpc":"2.0", "id":5, "method":"setposition", 
"params":{"nodeid":2, "x":1.0, "y":2.0, "z":3.0, "dir":4.221}}
<-- {"id":5,"jsonrpc":"2.0","result":"success"}

# Get position of node 2
--> {"jsonrpc":"2.0", "id":6, "method":"getposition", "params":{"nodeid":2}}

# Notification of order, node 1 has to send a packet to
--> {"jsonrpc":"2.0", "id":7, "method":"udpecho.1.send", 
"params":{"remote_address":"", "remote_port":9}}
<-- {"id":7,"jsonrpc":"2.0","result":"success"}

# Continue the simulation
--> {"jsonrpc":"2.0", "id":8, "method":"run"}

# A packet has been received by a  node, ns-3 callback external program

# Continue the simulation
--> {"jsonrpc":"2.0", "id":9, "method":"run"}

# The simulation is finished, ns-3 callback external program
<-- {"jsonrpc":"2.0","result":{"time":2007,"type":"endofsimulation"}}

5) Modifications in mainline code

We defined a new tag (SourceSocketAddressTag) and added it in 
UdpL4Protocol::Receive() to later retrieve source address at Application
level. We also add libraries linking in ./wscript.

To conclude we would like to know if this kind of features is 
interesting to the community. If so, we have several questions we
would like to discuss with you regarding the implementation of node 
mobility in ns-3. We would be glad to discuss and improve our
design solution.

Any feedback is very welcome.

Sebastien Vincent
Network engineer, University of Strasbourg

[1] http://tools.ietf.org/rfc/rfc4627.txt
[2] http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal
[3] http://sourceforge.net/projects/jsoncpp/
[4] http://sourceforge.net/projects/jsonrpc-cpp/
[5] http://cr.yp.to/proto/netstrings.txt
[6] http://www.mobilitymodels.org/lemma/

More information about the Ns-developers mailing list