ns2work1 lab 5 adding new components high level scripting in otcl linking otcl and c++ low level in...
TRANSCRIPT
NS2Work 1
LAB 5
Adding New Components
• High level scripting in otcl
• Linking otcl and C++
• Low level in C++
NS2Work 2
Adding New Component using otcl
• Additional <new_stuff>.tcl file
• source <new_stuff>.tcl
• Adding new files– change Makefile (NS_TCL_LIB), tcl/lib/ns-
lib.tcl– recompile
NS2Work 3
Example: Agent/Message
n0 n1
n4
n5
n2
n3
128Kb, 50ms
10Mb, 1ms 10Mb, 1ms
C Ccrosstraffic
S R
msg agent
http://nslab.ee.ntu.edu.tw/courses/ns-tutorial/ftw-tutorial.html
NS2Work 4
Agent/Message
• A UDP agent (without UDP header)• Up to 64 bytes user message• Good for fast prototyping a simple idea• Usage requires extending ns functionality
SS RR
string messageReceiver-sideprocessing
NS2Work 5
Agent/Message: Step 1
• Define senderclass Sender –superclass Agent/Messageclass Sender –superclass Agent/Message
# Message format: “Addr Op SeqNo”# Message format: “Addr Op SeqNo”
Sender instproc send-next {} {Sender instproc send-next {} {
$self instvar seq_ agent_addr_$self instvar seq_ agent_addr_
$self send “$agent_addr_ send $seq_”$self send “$agent_addr_ send $seq_”
incr seq_incr seq_
global nsglobal ns
$ns at [expr [$ns now]+0.1] "$self send-next"$ns at [expr [$ns now]+0.1] "$self send-next"
}}
NS2Work 6
Agent/Message: Step 2
• Define sender packet processing
Sender instproc Sender instproc recvrecv msg { msg {
$self instvar agent_addr_$self instvar agent_addr_
set sdr [lindex $msg 0]set sdr [lindex $msg 0]
set seq [lindex $msg 2]set seq [lindex $msg 2]
puts "Sender gets ack $seq from $sdr"puts "Sender gets ack $seq from $sdr"
}}
NS2Work 7
Agent/Message: Step 3
• Define receiver packet processing
Class Receiver –superclass Agent/MessageClass Receiver –superclass Agent/Message
Receiver instproc Receiver instproc recvrecv msg { msg {
$self instvar agent_addr_$self instvar agent_addr_
set sdr [lindex $msg 0]set sdr [lindex $msg 0]
set seq [lindex $msg 2]set seq [lindex $msg 2]
puts “Receiver gets seq $seq from $sdr”puts “Receiver gets seq $seq from $sdr”
$self send “$addr_ ack $seq”$self send “$addr_ ack $seq”
}}
NS2Work 8
Agent/Message: Step 4
• Scheduler and tracing
# Create scheduler# Create scheduler
set ns [new Simulator]set ns [new Simulator]
# Turn on Tracing# Turn on Tracing
set fd [new “message.nam” w]set fd [new “message.nam” w]
$ns namtrace-all $fd$ns namtrace-all $fd
NS2Work 9
Agent/Message: Step 5
• Topologyfor {set i 0} {$i < 6} {incr i} {for {set i 0} {$i < 6} {incr i} {
set n($i) [$ns node]set n($i) [$ns node]}}$ns duplex-link $n(0) $n(1) 128kb 50ms DropTail$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(4) 10Mb 1ms DropTail$ns duplex-link $n(1) $n(5) 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(2) 10Mb 1ms DropTail$ns duplex-link $n(0) $n(3) 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(0) $n(1) 5$ns queue-limit $n(1) $n(0) 5$ns queue-limit $n(1) $n(0) 5
NS2Work 10
Agent/Message: Step 6
• Routing
# Packet loss produced by queueing# Packet loss produced by queueing
# Routing protocol: let’s run distance vector# Routing protocol: let’s run distance vector
$ns rtproto DV$ns rtproto DV
NS2Work 11
Agent/Message: Step 7
• Cross trafficset udp0 [new Agent/UDP]set udp0 [new Agent/UDP]$ns attach-agent $n(2) $udp0$ns attach-agent $n(2) $udp0set null0 [new Agent/NULL]set null0 [new Agent/NULL]$ns attach-agent $n(4) $null0$ns attach-agent $n(4) $null0$ns connect $udp0 $null0$ns connect $udp0 $null0
set exp0 [new Application/Traffic/Exponential]set exp0 [new Application/Traffic/Exponential]$exp0 set rate_ 128k$exp0 set rate_ 128k$exp0 attach-agent $udp0$exp0 attach-agent $udp0$ns at 1.0 “$exp0 start”$ns at 1.0 “$exp0 start”
NS2Work 12
Agent/Message: Step 8
• Message agentsset sdr [new Sender]set sdr [new Sender]$sdr set packetSize_ 1000$sdr set packetSize_ 1000
set rcvr [new Receiver]set rcvr [new Receiver]$rcvr set packetSize_ 40$rcvr set packetSize_ 40
$ns attach $n(3) $sdr$ns attach $n(3) $sdr$ns attach $n(5) $rcvr$ns attach $n(5) $rcvr$ns connect $sdr $rcvr$ns connect $sdr $rcvr$ns connect $rcvr $sdr$ns connect $rcvr $sdr$ns at 1.1 “$sdr send-next”$ns at 1.1 “$sdr send-next”
NS2Work 13
Agent/Message: Step 9
• End-of-simulation wrapper (as usual)
$ns at 2.0 finish$ns at 2.0 finish
proc finish {} {proc finish {} {
global ns fdglobal ns fd
$ns flush-trace$ns flush-trace
close $fdclose $fd
exit 0exit 0
}}
NS2Work 14
Agent/Message: Result
• Example output> ./ns msg.tcl> ./ns msg.tclReceiver gets seq 0 from 0Receiver gets seq 0 from 0Sender gets ack 0 from 1Sender gets ack 0 from 1Receiver gets seq 1 from 0Receiver gets seq 1 from 0Sender gets ack 1 from 1Sender gets ack 1 from 1Receiver gets seq 2 from 0Receiver gets seq 2 from 0Sender gets ack 2 from 1Sender gets ack 2 from 1Receiver gets seq 3 from 0Receiver gets seq 3 from 0Sender gets ack 3 from 1Sender gets ack 3 from 1Receiver gets seq 4 from 0Receiver gets seq 4 from 0Sender gets ack 4 from 1Sender gets ack 4 from 1Receiver gets seq 5 from 0Receiver gets seq 5 from 0
NS2Work 15
Add Your Change into ns
• tcl/lib/ns-lib.tclClass SimulatorClass Simulator……source ../mysrc/msg.tclsource ../mysrc/msg.tcl
• MakefileNS_TCL_LIB = \NS_TCL_LIB = \tcl/mysrc/msg.tcl \tcl/mysrc/msg.tcl \……
– Or: change Makefile.in, make distcleanmake distclean, then ./configure --enable-debug./configure --enable-debug
NS2Work 16
Extending ns in C++
• Adding code in <new_stuff>.{cc,h} files– Change Makefile– make depend– recompile
NS2Work 17
Guidelines
• 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
• Write otcl code (if required)
• Build
NS2Work 18
Class Hierarchy
TclObject
NsObject
Connector Classifier
Delay AddrClassifierAgent McastClasifierQueue Trace
DropTail RED TCP Enq Deq Drop
Reno SACK
NS2Work 19
C++/otcl Linkage
Root of ns-2 object hierarchy
bind(): link variable values between C++ and OTcl TclObject
command(): link OTcl methods to C++ implementations
TclClass Create and initialize TclObject’s
Tcl C++ methods to access Tcl interpreter
TclCommand Standalone global commands
EmbeddedTcl ns script initialization
NS2Work 20
TclObject: Hierarchy and Shadowing
TclObject
Agent
Agent/TCP
Agent/TCP otcl shadow object
_o123Agent/TCP C++
object
*tcp
TclObject
Agent
TcpAgent
otcl classhierarchy
C++ classhierarchy
NS2Work 21
TclObject::bind()
• Link C++ member variables to otcl object variables
• C++TcpAgent::TcpAgent() {
bind(“window_”, &wnd_);… …
}– bind_time(), bind_bool(), bind_bw()
• otclset tcp [new Agent/TCP]set tcp [new Agent/TCP]$tcp set window_ 200$tcp set window_ 200
NS2Work 22
Initialization of Bound Variables
• Initialization through otcl class variablesAgent/TCP set Agent/TCP set window_window_ 50 50
• Do all initialization of bound variables in ~ns/lib/ns-default.tcl– Otherwise a warning will be issued when the
shadow object is created
NS2Work 23
TclObject::command()
• Implement otcl methods in C++
• Trap point: otcl method cmd{}
• Send all arguments after cmd{} call to TclObject::command()
NS2Work 24
TclObject::command()
$tcp send TclObject::unknown{} $tcp cmd sendno suchprocedure
TcpAgent::command()
match “send”?
Invoke parent: return Agent::command()
process and return
Yes No
OTcl space
C++ space
NS2Work 25
TclObject::command()
• otclset tcp [new Agent/TCP]
$tcp advance 10
• C++int TcpAgent::command(int argc,
const char*const* argv) {
if (argc == 3) { if (strcmp(argv[1], “advance”) == 0) { int newseq = atoi(argv[2]);
…… return(TCL_OK);
} }
return (Agent::command(argc, argv);}
NS2Work 26
TclClass
TclObject
Agent
Agent/TCP
TclObject
Agent
TcpAgent
NsObject ??
OTclC++ mirroringStatic class TcpClass : public TclClass {public:
TcpClass() : TclClass(“Agent/TCP”) {}TclObject* create(int, const char*const*) {
return (new TcpAgent());}
} class_tcp;
Static class TcpClass : public TclClass {public:
TcpClass() : TclClass(“Agent/TCP”) {}TclObject* create(int, const char*const*) {
return (new TcpAgent());}
} class_tcp;
NS2Work 27
Class Tcl
• Singleton class with a handle to Tcl interpreter
• Usage– Invoke otcl procedure– Obtain otcl evaluation results– Pass a result string to otcl– Return success/failure code to otcl
NS2Work 28
Class Tcl
Tcl& tcl = Tcl::instance();if (argc == 2) {
if (strcmp(argv[1], “now”) == 0) {tcl.resultf(“%g”, clock());return TCL_OK;
}tcl.error(“command not found”);return TCL_ERROR;
} else if (argc == 3) {tcl.eval(argv[2]);clock_ = atof(tcl.result());return TCL_OK;
}
NS2Work 30
DtopTail Round Robin (DTRR) – Step 1TclObject
NsObject
Connector Classifier
Delay AddrClassifierAgent McastClasifierQueue Trace
DropTail RED TCP Enq Deq Drop
Reno SACKDTRR
NS2Work 31
Adding New Queue (DropTail Round Robin) using C++
//dtrr-queue.hclass DtRrQueue : public Queue { public: DtRrQueue() {
q1_ = new PacketQueue;q2_ = new PacketQueue;pq_ = q1_;deq_turn_ = 1;
} protected: void enque(Packet*);
Packet* deque();
PacketQueue *q1_; // First FIFO queue PacketQueue *q2_; // Second FIFO queue int deq_turn_; // 1 for First queue 2 for Second
};
NS2Work 32
Creating Object//dtrr-queue.cc#include "dtrr-queue.h"static class DtRrQueueClass : public TclClass {public: DtRrQueueClass() : TclClass("Queue/DTRR") {} TclObject* create(int, const char*const*) {
return (new DtRrQueue);}
} class_dropt_tail_round_robin;
void DtRrQueue::enque(Packet* p) { …}Packet* DtRrQueue::deque(){…}
NS2Work 33
New Agent, New Header for Example MANET Unicast Routing
(EMUR)• Example: Agent/Message
– New packet header for 64-byte message– New transport agent to process this new
header
NS2Work 34
New Packet Header
• Create new header structure• Enable tracing support of new header• Create static class for otcl linkage
(packet.h)• Enable new header in otcl (tcl/lib/ns-
packet.tcl)• This does not apply when you add a new
field into an existing header!
NS2Work 35
How Packet Header Works
Packet
next_
hdrlen_
bits_ size determinedat compile time
size determinedat compile time
size determinedat compile time
……
hdr_cmn
hdr_ip
hdr_tcp
size determinedat simulatorstartup time
(PacketHeaderManager)
PacketHeader/Common
PacketHeader/IP
PacketHeader/TCP
NS2Work 36
EMUR Header – Step 1//emur_pkt.hstruct hdr_emur_pkt {struct hdr_emur_pkt {
nsaddr_t pkt_src_; // Node which originated this packet
u_int16_t pkt_len_; // Packet length (in bytes)
u_int8_t pkt_seq_num_; // Packet sequence number
inline nsaddr_t& pkt_src() { return pkt_src_; }
inline u_int16_t& pkt_len() { return pkt_len_; }
inline u_int8_t& pkt_seq_num() { return pkt_seq_num_; }
static int offset_;
inline static int& offset() { return offset_; }
inline static hdr_emur_pkt* access(const Packet* p) {
return (hdr_emur_pkt*)p->access(offset_);
}
};};
#define HDR_EMUR_PKT(p) hdr_emur_pkt::access(p)
NS2Work 37
EMUR Header – Step 2
//emur.cc
#include <emur_pkt.h>
int Emur_pkt::offset_;
static class EmurHeaderClass : public HeaderClass {
public:
EmurHeaderClass() : PacketHeaderClass("PacketHeader/EMUR",
sizeof(hdr_emur_pkt)) {
bind_offset(&hdr_emur_pkt::offset_);
}
} class_rtEMUR_hdr;
NS2Work 38
EMUR Header – Step 3
• Enable tracing (packet.h):enum packet_t {enum packet_t {
PT_TCP,PT_TCP,……,,PT_EMUR,PT_EMUR,PT_NTYPE // This MUST be the LAST onePT_NTYPE // This MUST be the LAST one
};};class p_info {class p_info {
…………name_[PT_EMUR] = “EMUR”;name_[PT_EMUR] = “EMUR”;name_[PT_NTYPE]= "undefined";name_[PT_NTYPE]= "undefined";
…………};};
NS2Work 39
EMUR Timer – Step 1//emur.hclass Emur; // forward declaration/* Timers */class Emur_PktTimer : public TimerHandler {public:Emur_PktTimer(Emur* agent) : TimerHandler() {
agent_ = agent;}protected:Emur* agent_;virtual void expire(Event* e); };
NS2Work 40
EMUR Class – Step 2//emur.hclass Emur : public Agent {/* Friends */friend class Emur_PktTimer;
/* Private members */…Emur_PktTimer pkt_timer_; // Timer for sending packets.
public:Emur(nsaddr_t);int command(int, const char*const*);void recv(Packet*, Handler*);
};
NS2Work 41
EMUR Binding – Step 3
//Emur/Emur.ccstatic class EmurClass : public TclClass {public:EmurClass() : TclClass("Agent/EMUR") {}TclObject* create(int argc, const char*const* argv) {assert(argc == 5);return (new Emur((nsaddr_t)Address::instance().str2addr(argv[4])));}
} class_rtEmur;
NS2Work 42
EMUR Constructor – Step 4
//Emur/Emur.cc
Emur::Emur(nsaddr_t id) : Agent(PT_EMUR), pkt_timer_(this) {
bind(“tcl_var_", &cc_var_);
ra_addr_ = id;
}
In Simulation script
Agent/Emur set tcl_var_ 100
NS2Work 43
EMUR Command – Step 5Int Emur::command(int argc, const char*const* argv) {
if (argc == 2) {if (strcasecmp(argv[1], "start") == 0) {Start(); //pkt_timer_.resched(0.0);return TCL_OK;}else if (strcasecmp(argv[1], “some_other_func") == 0) {…}}else if (argc == 3) {// Obtains corresponding dmux to carry packets to upper layersif (strcmp(argv[1], “some_var") == 0) {loc_var_ = atoi (strcmp(argv[2])return TCL_OK;}…
// Pass the command to the base class return Agent::command(argc, argv);}
NS2Work 44
Emur Packet Receive – Step 6Void Emur::recv(Packet* p, Handler* h) {struct hdr_cmn* ch = HDR_CMN(p);struct hdr_ip* ih = HDR_IP(p);if (ih->saddr() == ra_addr()) { // If there exists a loop, must drop the packet if (ch->num_forwards() > 0) { drop(p, DROP_RTR_ROUTE_LOOP);return;}// else if this is a packet I am originating, must add IP headerelse if (ch->num_forwards() == 0)ch->size() += IP_HDR_LEN;}// If it is a Emur packet, must process itif (ch->ptype() == PT_EMUR)recv_emur_pkt(p);// Otherwise, must forward the packet (unless TTL has reached zero)else {
ih->ttl_--;if (ih->ttl_ == 0) {drop(p, DROP_RTR_TTL);return;
}forward_data(p);}
NS2Work 45
Emur Send Packet – Step - 7Void Emur::send_emur_pkt() {
Packet* p = allocpkt();struct hdr_cmn* ch = HDR_CMN(p);struct hdr_ip* ih = HDR_IP(p);struct hdr_Emur_pkt* ph = HDR_Emur_PKT(p);ph->pkt_src() = ra_addr();ph->pkt_len() = 7;ph->pkt_seq_num() = seq_num_++;ch->ptype() = PT_Emur;ch->direction() = hdr_cmn::DOWN;ch->size() = IP_HDR_LEN + ph->pkt_len();ch->error() = 0;ch->next_hop() = IP_BROADCAST;ch->addr_type() = NS_AF_INET;ih->saddr() = ra_addr();ih->daddr() = IP_BROADCAST;ih->sport() = RT_PORT;ih->dport() = RT_PORT;ih->ttl() = IP_DEF_TTL;Scheduler::instance().schedule(target_, p, JITTER);
}
NS2Work 46
Emur Scheduling Packets – Step 8
void Emur_PktTimer::expire(Event* e) {
agent_->send_emur_pkt();
resched((double)5.0);
}
NS2Work 47
Emur Tracing – Step 9//trace/cmu-trace.htrace/cmu-trace.hclass CMUTrace : public Trace {/* ... definitions ... */private:/* ... */void format_aodv(Packet *p, int offset);void format_emur(Packet *p, int offset);};//trace/cmu-trace.cc
Void CMUTrace::format_emur(Packet *p, int offset){struct hdr_emur_pkt* ph = HDR_EMUR_PKT(p);…}
NS2Work 48
Add Method to TCL library – Step 10
//tcl/lib/ns-lib.tclSimulator instproc create-Emur-agent { node } {
# Create Emur routing agentset ragent [new Agent/Emur [$node node-addr]]
$self at 0.0 "$ragent start"$node set ragent_ $ragentreturn $ragent}