Vous êtes sur la page 1sur 10

NS example: Ping application

Overview (see wan1-0.tcl) N2 ----------- n0 ------------ N1


Ping p1 (server) Ping p0 (client)

Wan1-0.tcl setup: set p0 [new Agent/Ping] $ns attach-agent $n1 $p0 set p1 [new Agent/Ping] $ns attach-agent $n2 $p1 #Connect the two agents $ns connect $p0 $p1 #get the ping process going ... #$ns at 2 "$p0 send #can call startPingProcess which does a ping every interval #or have the recv schedule doPing .... startPingProcess $ns $p0 .5 Output: ping1.out and a single summary stat sent to standard out Standout out message: Ping: total sent: 397; total dropped: 11; loss rate: 2.770780856423174 This is created by the doPingStats tcl method that is called at the end of the simulation The main tcl script should do the following: $ns at $printtime "doPingStats" Ping1.out (format: timestamp RTT sequence#) 0.052683690666666672 52.7 1 Use getAvgPingRTT.script to obtain the mean RTT

Copyright 2010 Jim Martin

Packet Flow
N2 ----------- n0 ------------ N1
Ping p1 (server) Ping p0 (client)

Tcl code

C++ Code recv ---if (hdr->ret == 0) send --

C++ Code ---send

Tcl code <--- send

-recv if (hdr->ret == 1) sprintf(out, "%s recv %d %d %3.1f", tclobjectname recv nodeID, snum, timestamp tcl.eval(out); --recv if { [expr $lastPingReceived + 1] != $snum } { //loss, output to ping1.out: puts $pingtrace "[$ns now] 0 $lastPingReceived } if { [expr $lastPingReceived + 1] == $snum } { puts $pingtrace "[$ns now] $rtt $lastPingReceived" }

Copyright 2010 Jim Martin

C++ code: ./apps/ping.h


struct hdr_ping { char ret; double send_time; int snum; // Header access methods static int offset_; // required by PacketHeaderManager inline static int& offset() { return offset_; } inline static hdr_ping* access(const Packet* p) { return (hdr_ping*) p->access(offset_); }

}; class PingAgent : public Agent { public: PingAgent(); virtual int command(int argc, const char*const* argv); virtual void recv(Packet*, Handler*); int lastSentSnum;

Copyright 2010 Jim Martin

C++ code: ./apps/ping.cc


#include "ping.h" //#define TRACEPING 1 int hdr_ping::offset_; static class PingHeaderClass : public PacketHeaderClass { public: PingHeaderClass() : PacketHeaderClass("PacketHeader/Ping", sizeof(hdr_ping)) { bind_offset(&hdr_ping::offset_); } } class_pinghdr; static class PingClass : public TclClass { public: PingClass() : TclClass("Agent/Ping") {} TclObject* create(int, const char*const*) { return (new PingAgent()); } } class_ping; PingAgent::PingAgent() : Agent(PT_PING) { bind("packetSize_", &size_); lastSentSnum = 0; Copyright 2010 Jim Martin }

C++ code: ./apps/ping.cc


int PingAgent::command(int argc, const char*const* argv) (not complete ) { if (argc == 2) { if (strcmp(argv[1], "send") == 0) { // Create a new packet Packet* pkt = allocpkt(); // Access the Ping header for the new packet: hdr_ping* hdr = hdr_ping::access(pkt); // Set the 'ret' field to 0, so the receiving node // knows that it has to generate an echo packet hdr->ret = 0;

// Store the current time in the 'send_time' field hdr->send_time = Scheduler::instance().clock(); // Send the packet lastSentSnum++; hdr->snum = lastSentSnum; #ifdef TRACEPING printf("\nPING(%f):send snum : %d", Scheduler::instance().clock(),lastSentSnum); #endif send(pkt, 0); // return TCL_OK, so the calling function knows that // the command has been processed return (TCL_OK); Copyright 2010 Jim Martin }

C++ code: ./apps/ping.cc


void PingAgent::recv(Packet* pkt, Handler*) { // Access the IP header for the received packet: hdr_ip* hdrip = hdr_ip::access(pkt); // Access the Ping header for the received packet: hdr_ping* hdr = hdr_ping::access(pkt); // Is the 'ret' field = 0 (i.e. the receiving node is being pinged)? if (hdr->ret == 0) { // Send an 'echo'. First save the old packet's send_time double stime = hdr->send_time; int snum = hdr->snum; // Discard the packet Packet::free(pkt); // Create a new packet Packet* pktret = allocpkt(); // Access the Ping header for the new packet: hdr_ping* hdrret = hdr_ping::access(pktret); // Set the 'ret' field to 1, so the receiver won't send // another echo hdrret->ret = 1; // Set the send_time field to the correct value hdrret->send_time = stime; hdrret->snum = snum; #ifdef TRACEPING printf("\nPING(%f):return echo with snum : %d", Scheduler::instance().clock(),snum); #endif Copyright 2010 Jim Martin // Send the packet send(pktret, 0);

C++ code: ./apps/ping.cc


} else { // A packet was received. Use tcl.eval to call the Tcl // interpreter with the ping results. // Note: In the Tcl code, a procedure // 'Agent/Ping recv {from rtt}' has to be defined which // allows the user to react to the ping result. char out[100]; // Prepare the output to the Tcl interpreter. Calculate the // round trip time //JJM send the snum sprintf(out, "%s recv %d %d %3.1f", name(), hdrip->src_.addr_ >> Address::instance().NodeShift_[1], hdr->snum, (Scheduler::instance().clock()-hdr->send_time) * 1000); Tcl& tcl = Tcl::instance(); #ifdef TRACEPING printf("\nPING(%f): got echo with snum : %d", Scheduler::instance().clock(),hdr->snum); #endif tcl.eval(out); // Discard the packet Packet::free(pkt); } Copyright 2010 Jim Martin 7

Tcl code: recv method


Agent/Ping instproc recv {from snum rtt} { global ns lastPingReceived p1 totalPingDrops set pingtrace [open ping1.out a] if { [expr $lastPingReceived + 1] != $snum } { incr totalPingDrops #puts "JJM:Dropped snum: $snum" # set $totalPingDrops [expr $totalPingDrops + 1.0] set lastPingReceived [expr $lastPingReceived + 1] puts $pingtrace "[$ns now] 0 $lastPingReceived" #get here if we lost 2 consecutive ping's if { [expr $lastPingReceived + 1] != $snum } { incr totalPingDrops #puts "JJM1:Dropped snum: $snum" # set $totalPingDrops [expr $totalPingDrops + 1.0] set lastPingReceived [expr $lastPingReceived + 1] puts $pingtrace "[$ns now] 0 $lastPingReceived" #get here if we lost 3 consecutive ping's if { [expr $lastPingReceived + 1] != $snum } { set lastPingReceived [expr $lastPingReceived + 1] puts $pingtrace "[$ns now] 0 $lastPingReceived" } } }

Copyright 2010 Jim Martin

Tcl code: recv method


set lastPingReceived $snum #so do the next ping right away instead of every interval #so the ping flood mode.... #note: I need a timeout to make this work... # set pingDelay .001 # $ns at [expr [$ns now] + $pingDelay] "$p1 send" $self instvar node_ puts $pingtrace "[$ns now] $rtt $lastPingReceived" # puts "node [$node_ id] received ping answer from \ # $from with round-trip-time $rtt ms." close $pingtrace }

Copyright 2010 Jim Martin

Tcl code: tcl client send


#can call startPingProcess which does a ping every interval #or have the recv schedule doPing .... startPingProcess $ns $p0 .5 proc startPingProcess { ns pinger interval} { proc doPing {ns mypinger myinterval} { global totalPings totalPingDrops incr totalPings puts "doPing: total sent: $totalPings; total dropped: $totalPingDrops"

$mypinger send $ns at [expr [$ns now] + $myinterval + [uniform .001 .009]] "doPing $ns $mypinger $myinterval" } $ns at 0.0 "doPing $ns $pinger $interval" }

Copyright 2010 Jim Martin

10