500 likes | 597 Views
LAB 5. Adding New Components High level scripting in otcl Linking otcl and C++ Low level in C++. 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. C. S. C. R. cross
E N D
LAB 5 Adding New Components • High level scripting in otcl • Linking otcl and C++ • Low level in C++ NS2Work
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
C S C R cross traffic msg agent Example: Agent/Message n2 n4 128Kb, 50ms n0 n1 10Mb, 1ms 10Mb, 1ms n3 n5 http://nslab.ee.ntu.edu.tw/courses/ns-tutorial/ftw-tutorial.html NS2Work
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 Receiver-side processing string message S R NS2Work
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" } NS2Work
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" } NS2Work
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” } NS2Work
Agent/Message: Step 4 • Scheduler and tracing # Create scheduler set ns [new Simulator] # Turn on Tracing set fd [new “message.nam” w] $ns namtrace-all $fd NS2Work
Agent/Message: Step 5 • Topology 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 NS2Work
Agent/Message: Step 6 • Routing # Packet loss produced by queueing # Routing protocol: let’s run distance vector $ns rtproto DV NS2Work
Agent/Message: Step 7 • Cross traffic set udp0 [new Agent/UDP] $ns attach-agent $n(2) $udp0 set null0 [new Agent/NULL] $ns attach-agent $n(4) $null0 $ns connect $udp0 $null0 set exp0 [new Application/Traffic/Exponential] $exp0 set rate_ 128k $exp0 attach-agent $udp0 $ns at 1.0 “$exp0 start” NS2Work
Agent/Message: Step 8 • Message agents set sdr [new Sender] $sdr set packetSize_ 1000 set rcvr [new Receiver] $rcvr set packetSize_ 40 $ns attach $n(3) $sdr $ns attach $n(5) $rcvr $ns connect $sdr $rcvr $ns connect $rcvr $sdr $ns at 1.1 “$sdr send-next” NS2Work
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 } NS2Work
Agent/Message: Result • Example output > ./ns msg.tcl Receiver gets seq 0 from 0 Sender gets ack 0 from 1 Receiver gets seq 1 from 0 Sender gets ack 1 from 1 Receiver gets seq 2 from 0 Sender gets ack 2 from 1 Receiver gets seq 3 from 0 Sender gets ack 3 from 1 Receiver gets seq 4 from 0 Sender gets ack 4 from 1 Receiver gets seq 5 from 0 NS2Work
Add Your Change into ns • tcl/lib/ns-lib.tcl Class Simulator … source ../mysrc/msg.tcl • Makefile NS_TCL_LIB = \ tcl/mysrc/msg.tcl \ … • Or: change Makefile.in, make distclean, then ./configure --enable-debug NS2Work
Extending ns in C++ • Adding code in <new_stuff>.{cc,h} files • Change Makefile • make depend • recompile NS2Work
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
Class Hierarchy TclObject NsObject Connector Classifier Queue Delay Agent Trace AddrClassifier McastClasifier DropTail RED TCP Enq Deq Drop Reno SACK NS2Work
C++/otcl Linkage NS2Work
TclObject: Hierarchy and Shadowing C++ class hierarchy otcl class hierarchy TclObject TclObject Agent Agent TcpAgent Agent/TCP *tcp _o123 Agent/TCP otcl shadow object Agent/TCP C++ object NS2Work
TclObject::bind() • Link C++ member variables to otcl object variables • C++ TcpAgent::TcpAgent() { bind(“window_”, &wnd_); … … } • bind_time(), bind_bool(), bind_bw() • otcl set tcp [new Agent/TCP] $tcp set window_ 200 NS2Work
Initialization of Bound Variables • Initialization through otcl class variables Agent/TCP set window_ 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
TclObject::command() • Implement otcl methods in C++ • Trap point: otcl method cmd{} • Send all arguments after cmd{} call to TclObject::command() NS2Work
TclObject::command() OTcl space no such procedure $tcp send TclObject::unknown{} $tcp cmd send C++ space TcpAgent::command() match “send”? Yes No Invoke parent: return Agent::command() process and return NS2Work
TclObject::command() • otcl set 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
mirroring OTcl C++ TclObject TclObject NsObject ?? Agent Agent TcpAgent Agent/TCP TclClass • Static class TcpClass : public TclClass { • public: • TcpClass() : TclClass(“Agent/TCP”) {} • TclObject* create(int, const char*const*) { • return (new TcpAgent()); • } • } class_tcp; NS2Work
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
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
Creating New Components • new agent, no headers • new agent, new packet header NS2Work
DtopTail Round Robin (DTRR) – Step 1 TclObject NsObject Connector Classifier Queue Delay Agent Trace AddrClassifier McastClasifier DropTail RED TCP Enq Deq Drop Reno SACK DTRR NS2Work
Adding New Queue (DropTail Round Robin) using C++ //dtrr-queue.h class 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
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
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
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
PacketHeader/Common next_ hdrlen_ bits_ PacketHeader/TCP PacketHeader/IP How Packet Header Works Packet size determined at compile time hdr_cmn size determined at compile time size determined at simulator startup time (PacketHeaderManager) hdr_ip size determined at compile time hdr_tcp …… NS2Work
EMUR Header – Step 1 //emur_pkt.h 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
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
EMUR Header – Step 3 • Enable tracing (packet.h): enum packet_t { PT_TCP, …, PT_EMUR, PT_NTYPE // This MUST be the LAST one }; class p_info { …… name_[PT_EMUR] = “EMUR”; name_[PT_NTYPE]= "undefined"; …… }; NS2Work
EMUR Timer – Step 1 //emur.h class 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
EMUR Class – Step 2 //emur.h class 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
EMUR Binding – Step 3 //Emur/Emur.cc static 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
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
EMUR Command – Step 5 Int 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 layers if (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
Emur Packet Receive – Step 6 Void 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 header else if (ch->num_forwards() == 0) ch->size() += IP_HDR_LEN; } // If it is a Emur packet, must process it if (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
Emur Send Packet – Step - 7 Void 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
Emur Scheduling Packets – Step 8 void Emur_PktTimer::expire(Event* e) { agent_->send_emur_pkt(); resched((double)5.0); } NS2Work
Emur Tracing – Step 9 //trace/cmu-trace.h trace/cmu-trace.h class 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
Add Method to TCL library – Step 10 //tcl/lib/ns-lib.tcl Simulator instproc create-Emur-agent { node } { # Create Emur routing agent set ragent [new Agent/Emur [$node node-addr]] $self at 0.0 "$ragent start" $node set ragent_ $ragent return $ragent } NS2Work
EMUR Final Step • Change Makefile.in to add your source files • Run Configure • Run make NS2Work
Summary • Internals of NS2 • How to add new component in ns2 • Queue • Routing NS2Work