You are on page 1of 84


An introduction to ns-2
What is ns-2 Fundamentals writing ns-2 codes Wireless support Traces support and visualization Emulation Related work

Writing ns-2 codes

Extending ns
In OTcl In C++


ns Directory Structure
ns-allinone Tcl8.3 TK8.3 OTcl tcl ex

tclcl ... lib



C++ code

validation tests

OTcl code


ensure new changes do not break the old codes

Validation test
old ns-2 test.tcl Standard output

new ns-2 That contains Your changes


new output

If standard output new output THEN something is broken

Extending ns in OTcl
If you dont want to compile
source your changes in your simulation scripts

Modifying code; recompile Adding new files
Change Makefile (NS_TCL_LIB), tcl/lib/ns-lib.tcl Recompile

Example: Agent/Message

cross traffic

n2 n0 n3
128Kb, 50ms

n4 n1
10Mb, 1ms

10Mb, 1ms

message agent


pkt: 64 bytes of arbitrary string Receiver-side processing

An UDP agent (without UDP header) Up to 64 bytes user message Good for fast prototyping a simple idea Usage requires extending ns functionality

A protocol endpoint/enity Provide
a local and destination address (like an IP-layer sender) Functions to generate or fill in packet fields

To create a new agent

Decide its inheritance structure Create recv function (and timeout if necessary) to process the packets Define OTcl linkage if necessary Create new header if necessary

Define a new class Sender and a new class Receiver which are based on class Agent/Message Sender
Send a message to the Receiver every 0.1 sec Message contains its address and a sequence number

Receive message from the Sender Acknowledge the receive message to the sender The acknowledgement contains its address and the sequence number of received message

How would you implement Ping with Agent/Message?

Agent/Message: Step 1
Define sender
class Sender superclass Agent/Message
# Message format: Addr Op SeqNo Sender instproc send-next {} { $self instvar seq_ agent_addr_ $self send $agent_addr_ send $seq_ incr seq_ global ns $ns at [expr [$ns now]+0.1] "$self send-next" }

Agent/Message: Step 2
Define sender packet processing
Sender instproc recv msg { $self instvar agent_addr_ set sdr [lindex $msg 0] set seq [lindex $msg 2] puts "Sender gets ack $seq from $sdr" }

Agent/Message: Step 3
Define receiver packet processing
Class Receiver superclass Agent/Message Receiver instproc recv msg { $self instvar agent_addr_ set sdr [lindex $msg 0] set seq [lindex $msg 2] puts Receiver gets seq $seq from $sdr $self send $addr_ ack $seq }

Agent/Message: Step 4
Scheduler and tracing
# Create scheduler set ns [new Simulator] # Turn on Tracing set fd [new w] $ns trace-all $fd

Agent/Message: Step 5
for {set i 0} {$i < 6} {incr i} { set n($i) [$ns node] } $ns duplex-link $n(0) $n(1) 128kb 50ms DropTail $ns duplex-link $n(1) $n(4) 10Mb 1ms DropTail $ns duplex-link $n(1) $n(5) 10Mb 1ms DropTail $ns duplex-link $n(0) $n(2) 10Mb 1ms DropTail $ns duplex-link $n(0) $n(3) 10Mb 1ms DropTail $ns queue-limit $n(0) $n(1) 5 $ns queue-limit $n(1) $n(0) 5

Agent/Message: Step 6
# Packet loss produced by queueing # Routing protocol: lets run distance vector $ns rtproto DV

Agent/Message: Step 7
Cross traffic
set $ns set $ns $ns udp0 [new Agent/UDP] attach-agent $n(2) $udp0 null0 [new Agent/NULL] attach-agent $n(4) $null0 connect $udp0 $null0

set exp0 [new Application/Traffic/Exponential] $exp0 set rate_ 128k $exp0 attach-agent $udp0 $ns at 1.0 $exp0 start

Agent/Message: Step 8
Message agents
set sdr [new Sender] $sdr set seq_ 0 $sdr set packetSize_ 1000 set rcvr [new Receiver] $rcvr set packetSize_ 40 $ns $ns $ns $ns attach-agent attach-agent connect $sdr at 1.1 $sdr $n(3) $sdr $n(5) $rcvr $rcvr send-next

Agent/Message: Step 9
End-of-simulation wrapper (as usual)
$ns at 2.0 finish proc finish {} { global ns fd $ns flush-trace close $fd exit 0 } $ns run

Agent/Message: Result
Example output
> ./ns msg.tcl Receiver gets seq Sender gets ack 0 Receiver gets seq Sender gets ack 1 Receiver gets seq Sender gets ack 2 Receiver gets seq Sender gets ack 3 Receiver gets seq Sender gets ack 4 Receiver gets seq 0 from from 5 1 from from 5 2 from from 5 3 from from 5 4 from from 5 5 from 3 3 3 3 3 3

Add Your Changes into ns

ns-allinone Tcl8.3 TK8.3 OTcl tcl ex

tclcl ... lib



C++ code

validation tests

mysrc msg.tcl

OTcl code


Add Your Change into ns

Class Simulator source ../mysrc/msg.tcl

NS_TCL_LIB = \ tcl/mysrc/msg.tcl \ Or: change, make distclean, then ./configure --enable-debug , make depend and make

Writing ns-2 codes

Extending ns
In OTcl In C++
New components

Extending ns in C++
Modifying code
make depend Recompile

Adding code in new files

Change Makefile make depend recompile

Creating New Components

Guidelines Two styles
New agent based on existing packet headers Add new packet header

Decide position in class hierarchy
I.e., which class to derive from?

Create new packet header (if necessary) Create C++ class, fill in methods Define OTcl linkage (if any) Write OTcl code (if any) Build (and debug)

New Agent, Old Header

Exercise: TCP jump start
Wide-open transmission window at the beginning From cwnd_ += 1 To cwnd_ = MAXWIN_
Useful for deep space communication

TCP Jump Start Decide position in class hierarchy

TclObject NsObject Connector Queue Delay Agent TCP SACK Trace Classifier AddrClassifier McastClasifier Drop Handler

DropTail RED

Enq Deq JS


TCP Jump Start Create C++ class

New file: tcp-js.h
class JSTCPAgent : public TcpAgent { public: virtual void set_initial_window() { cwnd_ = MAXWIN_; } private: int MAXWIN_; };

TCP Jump Start Define OTcl linkage

New file:
static JSTcpClass : public TclClass { public: JSTcpClass() : TclClass("Agent/TCP/JS") {} TclObject* create(int, const char*const*) { return (new JSTcpAgent()); } }; JSTcpAgent::JSTcpAgent() { bind(MAXWIN_, MAXWIN_); }

TCP Jump Start Build

Create an instance of jump-start TCP in your tcl script tcp-js.tcl Set MAXWIN_ value in tcl Add tcp-js.o in Re-configure, make depend and recompile Run yr tcl script tcp-js.tcl

Packet Format
cmn header header data ip header tcp header rtp header trace header ... ts_ ptype_ uid_ size_ iface_

remove-all-packet-headers ;# removes all except common add-packet-header IP Message ;# hdrs reqd for cbr traffic

New Packet Header

Create new header structure Create static class for OTcl linkage (packet.h) Enable tracing support of new header( Enable new header in OTcl (tcl/lib/ns-packet.tcl) This does not apply when you add a new field into an existing header!


foreach prot { Common Flags IP }{ add-packet-header $prot }

How Packet Header Works

Packet next_ hdrlen_ bits_

hdr_cmn size determined at compile time PacketHeader/IP size determined at compile time size determined at compile time hdr_ip

size determined at simulator startup time



Example: Agent/Message
New packet header for 64-byte message New transport agent to process this new header

New Packet Header Step 1

Create header structure
struct hdr_msg { char msg_[64]; static int offset_; inline static int& offset() { return offset_; } inline static hdr_msg* access(Packet* p) { return (hdr_msg*) p->access(offset_); } /* per-field member functions */ char* msg() { return (msg_); } int maxmsg() { return (sizeof(msg_)); } };

New Packet Header Step 2

Otcl linkage: PacketHeader/Message
static class MessageHeaderClass : public PacketHeaderClass { public: MessageHeaderClass() : PacketHeaderClass("PacketHeader/Message", sizeof(hdr_msg)) { bind_offset(&hdr_msg::offset_); } } class_msghdr;

New Packet Header Step 3

Enable tracing (packet.h):
enum packet_t { PT_TCP, , PT_MESSAGE, PT_NTYPE // This MUST be the LAST one }; class p_info { name_[PT_MESSAGE] = message; name_[PT_NTYPE]= "undefined"; };

New Packet Header Step 4

Register new header (tcl/lib/ns-packet.tcl)
foreach prot { { Common off_cmn_ } { Message off_msg_ } } add-packet-header $prot

Packet Header: Caution

Some old code, e.g.:
RtpAgent::RtpAgent() { bind(off_rtp_, &off_rtp); } hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_);

Dont follow this example!

Agent/Message Step 1
TclObject NsObject Connector Queue Delay Agent TCP Trace Classifier AddrClassifier McastClasifier Drop

DropTail RED

Message Enq Deq



Agent/Message Step 2
C++ class definition
// Standard split object declaration static class MessageAgent : public Agent { public: MessageAgent() : Agent(PT_MESSAGE) {} virtual int command(int argc, const char*const* argv); virtual void recv(Packet*, Handler*); };

Agent/Message Step 3
Packet processing: $msgAgent send data1
int MessageAgent::command(int, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (strcmp(argv[1], "send") == 0) { Packet* pkt = allocpkt(); hdr_msg* mh = hdr_msg::access(pkt); // We ignore message size check... strcpy(mh->msg(), argv[2]); send(pkt, 0); return (TCL_OK); } return (Agent::command(argc, argv)); }

Agent/Message Step 4
Packet processing: receive
void MessageAgent::recv(Packet* pkt, Handler*) { hdr_msg* mh = hdr_msg::access(pkt); // OTcl callback char wrk[128]; sprintf(wrk, "%s recv {%s}", name(), mh->msg()); Tcl& tcl = Tcl::instance(); tcl.eval(wrk); Packet::free(pkt); }

Writing ns-2 codes

Extending ns
In OTcl In C++ Debugging: OTcl/C++, memory Pitfalls

Debugging C++ in ns
C++/OTcl debugging Memory debugging (memory leak is a common bug)
purify dmalloc

C++/OTcl Debugging
Usual technique
Break inside command() Cannot examine states inside OTcl!

Execute tcl-debug inside gdb

C++/OTcl Debugging
C++ OTcl

Otcl command debug 1 Otcl command

debug 1

C++/OTcl Debugging
(gdb) call Tcl::instance().eval(debug 1) 15: lappend auto_path $dbg_library dbg15.3> w *0: application 15: lappend auto_path $dbg_library dbg15.4> Simulator info instances _o1 dbg15.5> _o1 now 0 dbg15.6> # and other fun stuff dbg15.7> c (gdb) where #0 0x102218 in write() ......

Memory Debugging in ns
Set PURIFY macro in ns Makefile Usually, put -colloctor=<ld_path>

Gray Watsons dmalloc library make distclean ./configure --with-dmalloc=<dmalloc_path> Analyze results: dmalloc_summarize

dmalloc: Usage
Turn on dmalloc
alias dmalloc eval \dmalloc C \!*` dmalloc -l log low

dmalloc_summarize ns < logfile

ns must be in current directory Itemize how much memory is allocated in each function

Run ns-2 on ples/example2.tcl Execute dmalloc Submit the memory profile to TA Due date: May 30

Scalability vs flexibility
Or, how to write scalable simulation?

Memory conservation tips Memory leaks

Scalability vs Flexibility
Its tempting to write all-OTcl simulation
Benefit: quick prototyping Cost: memory + runtime

Control the granularity of your split object by migrating methods from OTcl to C++

THE Merit of OTcl


Program size, complexity C/C++ split objects OTcl


Smoothly adjust the granularity of scripting to balance extensibility and performance With complete compatibility with existing simulation scripts

Object Granularity Tips

Per-packet processing C++ Hooks, frequently changing code OTcl

Data management
Complex/large data structure C++ One-time configuration variables OTcl

Memory usage
Simulator Unicast node Multicast node Duplex link Packet 268KB 2KB 6KB 9KB 2KB

Memory Conservation Tips

Remove unused packet headers Avoid trace-all Use arrays for a sequence of variables
Instead of n$i, say n($i)

Avoid OTcl temporary variables

temp=A; B=temp

Use dynamic binding

delay_bind() instead of bind() See object.{h,cc}

Use different routing strategies

Computing routing tables dominate the simulation setup time

Run on FreeBSD
use less memory for malloc()

Memory Leaks
Purify or dmalloc, but be careful about split objects:
for {set i 0} {$i < 500} {incr i} { set a [new RandomVariable/Constant] }

It leaks memory, but cant be detected!

Explicitly delete EVERY split object that was new-ed

Final Word
My extended ns dumps OTcl scripts!
Find the last 10-20 lines of the dump Is the error related to _o*** cmd ?
Check your command()

Otherwise, check the otcl script pointed by the error message


An introduction to ns-2
What is ns-2 Fundamentals Writing ns-2 codes Traces support and visualization Wireless support Emulation Related work

nsnam Interface
Color Node manipulation Link manipulation Topology layout Protocol state Misc

nam Interface: Color

Color mapping
$ns $ns $ns color color color 40 41 42 red blue chocolate

Color flow id association

$tcp0 set fid_ 40 ;# red packets $tcp1 set fid_ 41 ;# blue packets

nam Interface: Nodes

$node color red

Shape (cant be changed after sim starts)

$node shape box $ns $ns at at 1.0 2.0 $n0 $n0 ;# circle, box, hexagon add-mark m0 delete-mark blue box m0

Marks (concentric shapes) Label (single string)

$ns at 1.1 $n0 label \web cache 0\
$node label-at up $node label-color blue

nam Interfaces: Links

$ns duplex-link-op $n0 $n1 color "green"

$ns $ns $ns duplex-link-op duplex-link-op duplex-link-op $n0 $n1 $n1 $n1 $n2 $n2 label "abced label-color blue label-at down

Queue position
$ns duplex-link-op queuePos right

Dynamics (automatically handled)

$ns rtmodel Deterministic {2.0 0.9 0.1} $n0 $n1

Asymmetric links not allowed

nam Interface: Topology Layout

Manual layout: specify everything
$ns $ns $ns $ns duplex-link-op duplex-link-op duplex-link-op duplex-link-op $n(0) $n(1) $n(2) $n(3) $n(1) $n(2) $n(3) $n(4) orient orient orient orient right right right 60deg

If anything missing automatic layout

nam Interface: Misc

Packet color
$ns color $n blue $agent set fid_ $n

Add textual explanation to your simulation
$ns at 3.5 "$ns trace-annotate \packet drop\"

Control playback
$ns at 0.0 "$ns set-animation-rate 0.1ms"

The nam user interface

Summary of nam
Turn on nam tracing in your Tcl script
As easy as turning on normal tracing
$ns namtrace $file

Specify color/shape/label of node/link

$ns duplex-link-op $node1 $node2 orient left

Execute nam
exec nam $filename

A live demo

Display a graph showing when packets are received/dropped. Enabling namgraph
Run the namfilter script on your nam trace file:
exec tclsh /path/to/namfilter.tcl out.nam


The nam editor

Create simple scenarios graphically Good for those who dont want to learn Tcl, but only a limited subset of ns is currently available

The nam editor

Topology generator

Inet topology generator

from University of Michigan AS level Internet topology Create topologies with accurate degree distributions Conversion of Inet output to ns-2 format
inet2ns < inet.topology > ns.topology

Comes with ns-allinone Require Knuths cweb and SGB

itm <config_file>

Three graph models

Flat random: Waxman n-level hierarchy Transit-stub

GT-ITM: Transit-Stub Model

transit domains
ansit transit-tr link

stub-stub link

stub domains

Converters for GT-ITM

Convert SGB format to ns config file
sgb2ns <SGB_file> <OTcl_file>

ts2ns: output lists of transit and stub nodes

Convert transit-stub information into hierarchical addresses
sgb2hierns <SGB_file> <OTcl_file>

Tiers topology generator

3-level hierarchy Conversion of Tiers output to ns-2 format
an awk script tiers2ns.awk is included in ~ns-2/bin to convert the output of tiers into ns2 scripts.

From Boston University Supports multiple generation models
flat AS flat Router hierarchical topologies

Object-oriented design to allow the flexibility to add new topology models Can import from Inet, GT-ITM, Skitter,.. Can export to ns-2, JavaSim, SSFNET format Written in Java and C++ GUI support

Packages NTG RTG GT-ITM TIERS Graphs
n-level Flat random Flat random, nlevel, Transit-stub 3-level

Edge Method
probabilistic Waxman various spanning tree