Elmurod A. Talipov
20Jan/10Off

How to Add New Routing Protocol in NS2

Writing routing protocol is fairly easy in NS2, but for beginners it seems very difficult.  Therefore, if you are new to NS2 and want to write your own routing protocol, I would strongly recommend to revise AODV source code. Because, I believe AODV source code is straightforward and fairly easy to understand due to the simplicity of the AODV protocol.

Before you begin reading this post, I assume that you have already installed NS2 on Linux.  I have used version 2.34, which is current release.  If you have not installed yet, DOWNLOAD HERE and INSTALL. Okey, simple requirements to write your own routing protocol

  • NS2 installed
  • You should know how to program in C/C++.
  • Optionally, shell scripting and perl.

Let's start with creating directory of routing protocol. Goto the "$NS_ROOT/ ns-2.34/". Create directory named as wfrp, we call it WSN Flooding-based Routing Protocol in which sink nodes periodically send a beacon message and other nodes construct route towards the sink nodes. Then nodes report to sink node every certain period using UDP protocol. Direct Diffusion may be an example of such protocol, but what we are writing is simpler and has more functionalities.

 mkdir wfrp 

In the directory we create three files : wrfp.cc, wrfp.h, wrfp_packet.h. Download and put these files in wfrp directory. I will not explain the code here, and if you don't understand just leave comment I will try to answer.

Now, we are going to modify following files. Therefore it is better you backup these files before you start adding new protocol, so that you can easily go back.

  • $NS_ROOT/Makefile
  • $NS_ROOT/queue/priqueue.cc
  • $NS_ROOT/common/packet.h
  • $NS_ROOT/trace/cmu-trace.h
  • $NS_ROOT/trace/cmu-trace.cc
  • $NS_ROOT/tcl/lib/ns-packet.tcl
  • $NS_ROOT/tcl/lib/ns-lib.tcl
  • $NS_ROOT/tcl/lib/ns-agent.tcl
  • $NS_ROOT/tcl/lib/ns-mobilenode.tcl

Let's start with ~/ns-allinone-2.34/ns-2.34/Makefile just add following lien at 269

 wfrp/wfrp.o \  

Add following lines to ~/ns-allinone-2.34/ns-2.34/queue/priqueue.cc from line 93.

  // WFRP patch
  case PT_WFRP:

To define new routing protocol packet type we have to modify  ~/ns-allinone-2.34/ns-2.34/common/packet.h file. We change PT_NTYPE to 63, and for our protocol PT_WFRP = 62. If you have already installed another routing protocol. Just make sure PT_NTYPE is last, and protocol number is ordered sequentially. From line 85 changes would  be :

  // WFRP packet
  static const packet_t PT_WFRP = 62;

  // insert new packet types here
  static packet_t       PT_NTYPE = 63; // This MUST be the LAST one

We make following code change at line 254 of ~/ns-allinone-2.34/ns-2.34/common/packet.h. The code is used that the packet is routing protocol packet and has high priority.

  type == PT_AODV ||
  type == PT_WFRP)

And at line 390 of the same file

  // WFRP patch
  name_[PT_WFRP] = "WFRP";

Now we will make NS2 trace our simulation and write it to *something*.tr, in order to do that we have to modify cmu-trace.h and cmu-trace.cc.

To add trace function we add following line to ~/ns-allinone-2.34/ns-2.34/trace/cmu-trace.h at line 163:

  void    format_wfrp(Packet *p, int offset);

~/ns-allinone-2.34/ns-2.34/trace/cmu-trace.cc must be added following code at line 1071

// WFRP patch
void
CMUTrace::format_wfrp(Packet *p, int offset)
{
	struct hdr_wfrp *wh = HDR_WFRP(p);
	struct hdr_wfrp_beacon *wb = HDR_WFRP_BEACON(p);
	struct hdr_wfrp_error  *we = HDR_WFRP_ERROR(p);

	switch(wh->pkt_type) {
		case WFRP_BEACON:

			if (pt_->tagged()) {
				sprintf(pt_->buffer() + offset,
						  "-wfrp:t %x -wfrp:h %d -wfrp:b %d -wfrp:s %d "
						  "-wfrp:px %d -wfrp:py %d -wfrp:ts %f "
						  "-wfrp:c BEACON ",
						  wb->pkt_type,
						  wb->beacon_hops,
						  wb->beacon_id,
						  wb->beacon_src,
						  wb->beacon_posx,
						  wb->beacon_posy,
						  wb->timestamp);
			} else if (newtrace_) {

				sprintf(pt_->buffer() + offset,
						  "-P wfrp -Pt 0x%x -Ph %d -Pb %d -Ps %d -Ppx %d -Ppy %d -Pts %f -Pc BEACON ",
						  wb->pkt_type,
						  wb->beacon_hops,
						  wb->beacon_id,
						  wb->beacon_src,
						  wb->beacon_posx,
						  wb->beacon_posy,
						  wb->timestamp);

			} else {

				sprintf(pt_->buffer() + offset,
						  "[0x%x %d %d [%d %d] [%d %f]] (BEACON)",
						  wb->pkt_type,
						  wb->beacon_hops,
						  wb->beacon_id,
						  wb->beacon_src,
						  wb->beacon_posx,
						  wb->beacon_posy,
						  wb->timestamp);
			}
			break;

		case WFRP_ERROR:
			// TODO: need to add code
			break;

		default:
#ifdef WIN32
			fprintf(stderr,
					  "CMUTrace::format_wfrp: invalid WFRP packet type\n");
#else
			fprintf(stderr,
					  "%s: invalid WFRP packet type\n", __FUNCTION__);
#endif
			abort();
	}
}

Now we will modify tcl files to create routing agent. First we define protocol name to use in tcl file. It would done by modifying ~/ns-allinone-2.34/ns-2.34/tcl/lib/ns-packet.tcl @ line 172

  # WFRP patch
  WFRP

Now we set routing agent by modifying ~/ns-allinone-2.34/ns-2.34/tcl/lib/ns-lib.tcl @ line 633

  WFRP {
	set ragent [$self create-wfrp-agent $node]
  }

From line 860 of the same file following code should be added.

 Simulator instproc create-wfrp-agent { node } {
 	#  Create WFRP routing agent
	set ragent [new Agent/WFRP [$node node-addr]]
	$self at 0.0 "$ragent start"
	$node set ragent_ $ragent
	return $ragent
 }

Now we will set port numbers of routing agent. sport is source port, dport is destination port. Modify ~/ns-allinone-2.34/ns-2.34/tcl/lib/ns-agent.tcl line 202

  Agent/WFRP instproc init args {
	$self next $args
  }

  Agent/WFRP set sport_   0
  Agent/WFRP set dport_   0

Frankly speaking I have no idea why I have to add following things. But I believe it should be done according to some tutorial : ~/ns-allinone-2.34/ns-2.34/tcl/lib/ns-mobilenode.tcl line 201

  # Special processing for WFRP
  set wfrponly [string first "WFRP" [$agent info class]]
  if {$wfrponly != -1 } {
	$agent if-queue [$self set ifq_(0)]   ;# ifq between LL and MAC
  }

We are done. got to ~/ns-allinone-2.34/ns-2.34/ directory and do

make clean
make

When the compile is finished, you can test using wfrp_802_15_4.tcl file as :

ns wfrp_802_15_4.tcl

In this test the NODE 0 is sink node, starts sending beacon 1 second after simulation i started, and NODE 10 is reporting node. It starts sending report over CBR/UDP at 5.0 seconds (after simulation is started). Report interval is 2 seconds.

To remove debugging WFRP, uncomment #define DEBUG (line 36 of wfrp.cc & re-make it).

14Apr/09Off

Sensor Network 802.15.4 AODV Simulation

The reason to write this topic is many people asked me how to simulate sensor networks. Obviously, authors of 802.15.4/Zigbee protocol developers on NS2 have given a sample examples. But, these examples do not run correctly, and give some kind of unknown error (at least I don't know what errors mean). Therefore, I have decided to test AODV using 802.15.4 MAC/PHY. Thus, if my tests work, I hope you can test your own routing protocols using this source code.

Alright, the TCL file is fairly simple. I briefly explain what means what. We first set simulation environment. We are going to deploy 500 nodes, in 1000x500 sqm area, simulation time is 500 seconds. And we are using 802.15.4 MAC/PHY and interface queue is 100. We also set simulator and files to trace the simulation.

# Generated by Topology Generator for Network Simulator (c) Elmurod Talipov
set val(chan)          Channel/WirelessChannel      ;# channel type
set val(prop)          Propagation/TwoRayGround     ;# radio-propagation model
set val(netif)         Phy/WirelessPhy/802_15_4     ;# network interface type
set val(mac)           Mac/802_15_4                 ;# MAC type
set val(ifq)           Queue/DropTail/PriQueue      ;# interface queue type
set val(ll)            LL                           ;# link layer type
set val(ant)           Antenna/OmniAntenna          ;# antenna model
set val(ifqlen)        100	         	    ;# max packet in ifq
set val(nn)            500			    ;# number of mobilenodes
set val(rp)            AODV			    ;# protocol tye
set val(x)             1000			    ;# X dimension of topography
set val(y)             500			    ;# Y dimension of topography
set val(stop)          500			    ;# simulation period
set val(energymodel)   EnergyModel		    ;# Energy Model
set val(initialenergy) 100			    ;# value

set ns        		[new Simulator]
set tracefd       	[open trace-aodv-802-15-4.tr w]
set namtrace      	[open nam-aodv-802-15-4.nam w]

$ns trace-all $tracefd
$ns namtrace-all-wireless $namtrace $val(x) $val(y)

Let's set radio transmission range to 40 meters, but this does not mean exactly 40 meters. The code below filters packet with receiving signal strength above "40 meters".

set dist(5m)  7.69113e-06
set dist(9m)  2.37381e-06
set dist(10m) 1.92278e-06
set dist(11m) 1.58908e-06
set dist(12m) 1.33527e-06
set dist(13m) 1.13774e-06
set dist(14m) 9.81011e-07
set dist(15m) 8.54570e-07
set dist(16m) 7.51087e-07
set dist(20m) 4.80696e-07
set dist(25m) 3.07645e-07
set dist(30m) 2.13643e-07
set dist(35m) 1.56962e-07
set dist(40m) 1.20174e-07
Phy/WirelessPhy set CSThresh_ $dist(40m)
Phy/WirelessPhy set RXThresh_ $dist(40m)

And lets set topography as flat, deploy nodes randomly in an area of 1000 x 500 sqm.

# set up topography object
set topo       [new Topography]
$topo load_flatgrid $val(x) $val(y)

create-god $val(nn)

# configure the nodes
$ns node-config -adhocRouting $val(rp) \
            -llType $val(ll) \
             -macType $val(mac) \
             -ifqType $val(ifq) \
             -ifqLen $val(ifqlen) \
             -antType $val(ant) \
             -propType $val(prop) \
             -phyType $val(netif) \
             -channel [new $val(chan)] \
             -topoInstance $topo \
             -agentTrace ON \
             -routerTrace ON \
             -macTrace  OFF \
             -movementTrace OFF \
             -energyModel $val(energymodel) \
             -initialEnergy $val(initialenergy) \
             -rxPower 35.28e-3 \
             -txPower 31.32e-3 \
	     -idlePower 712e-6 \
	     -sleepPower 144e-9

             #-IncomingErrProc MultistateErrorProc \
             #-OutgoingErrProc MultistateErrorProc

for {set i 0} {$i < $val(nn) } { incr i } {
        set mnode_($i) [$ns node]
}

for {set i 1} {$i < $val(nn) } { incr i } {
	$mnode_($i) set X_ [ expr {$val(x) * rand()} ]
	$mnode_($i) set Y_ [ expr {$val(y) * rand()} ]
	$mnode_($i) set Z_ 0
}

And we are goig to deploy sink node in the center of area, i.e. at [500, 250].

# Position of Sink
$mnode_(0) set X_ [ expr {$val(x)/2} ]
$mnode_(0) set Y_ [ expr {$val(y)/2} ]
$mnode_(0) set Z_ 0.0
$mnode_(0) label "Sink"

The code below is useful how big the nodes are going to be shown in NAM (network animator), thus it does not have meaning in real simulation.

for {set i 0} {$i < $val(nn)} { incr i } {
	$ns initial_node_pos $mnode_($i) 10
}

Finally, we have deployed nodes, and remained important thing is establish connection. We are going to use UDP protocol with CBR (constant bit rate, interval (interval_) is set to 2 seconds)

#Setup a UDP connection
set udp [new Agent/UDP]
$ns attach-agent $mnode_(10) $udp

set sink [new Agent/Null]
$ns attach-agent $mnode_(0) $sink

$ns connect $udp $sink
$udp set fid_ 2

#Setup a CBR over UDP connection
set cbr [new Application/Traffic/CBR]
$cbr attach-agent $udp
$cbr set type_ CBR
$cbr set packet_size_ 50
$cbr set rate_ 0.1Mb
$cbr set interval_ 2
#$cbr set random_ false

$ns at 5.0 "$cbr start"
$ns at [expr $val(stop) - 5] "$cbr stop"

# Telling nodes when the simulation ends
for {set i 0} {$i < $val(nn) } { incr i } {
    $ns at $val(stop) "$mnode_($i) reset;"
}

# ending nam and the simulation
$ns at $val(stop) "$ns nam-end-wireless $val(stop)"
$ns at $val(stop) "stop"
$ns at [expr $val(stop) + 0.01] "puts \"end simulation\"; $ns halt"
proc stop {} {
    global ns tracefd namtrace
    $ns flush-trace
    close $tracefd
    close $namtrace
}

$ns run

We have finished writing sample AODV TCL script, we can run it

 ns aodv_802_15_4.tcl 

NAM gives me following deployment result.

nam-aodv-802-15-4nam

Download whole source code here : aodv_802_15_4.tcl . If you find any problem with that, leave comment here. If you want to test your own routing protocol simply change $val(rp) AODV with your own.