trace.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8 -*- */
00002 /*
00003  * Copyright (c) 1990-1997 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *  This product includes software developed by the Computer Systems
00017  *  Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * @(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/trace/trace.cc,v 1.81 2005/07/13 03:51:33 tomh Exp $ (LBL)
00035  */
00036 
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include "packet.h"
00040 #include "ip.h"
00041 #include "tcp.h"
00042 #include "sctp.h"
00043 #include "rtp.h"
00044 #include "srm.h"
00045 #include "tfrc.h"
00046 #include "flags.h"
00047 #include "address.h"
00048 #include "trace.h"
00049 #include "rap/rap.h"
00050 
00051 
00052 //const double Trace::PRECISION = 1.0e+6; 
00053 
00054 class TraceClass : public TclClass {
00055 public:
00056     TraceClass() : TclClass("Trace") { }
00057     TclObject* create(int argc, const char*const* argv) {
00058         if (argc >= 5)
00059             return (new Trace(*argv[4]));
00060         return 0;
00061     }
00062 } trace_class;
00063 
00064 
00065 Trace::Trace(int type)
00066     : Connector(), callback_(0), pt_(0), type_(type)
00067 {
00068     bind("src_", (int*)&src_);
00069     bind("dst_", (int*)&dst_);
00070     bind("callback_", &callback_);
00071     bind("show_tcphdr_", &show_tcphdr_);
00072     bind("show_sctphdr_", &show_sctphdr_);
00073     pt_ = new BaseTrace;
00074 }
00075 
00076 Trace::~Trace()
00077 {
00078 }
00079 
00080 /*
00081  * $trace detach
00082  * $trace flush
00083  * $trace attach $fileID
00084  */
00085 int Trace::command(int argc, const char*const* argv)
00086 {
00087     Tcl& tcl = Tcl::instance();
00088     if (argc == 2) {
00089         if (strcmp(argv[1], "detach") == 0) {
00090             pt_->channel(0) ;
00091             pt_->namchannel(0) ;
00092             return (TCL_OK);
00093         }
00094         if (strcmp(argv[1], "flush") == 0) {
00095             Tcl_Channel ch = pt_->channel();
00096             Tcl_Channel namch = pt_->namchannel();
00097             if (ch != 0) 
00098                 pt_->flush(ch);
00099                 //Tcl_Flush(pt_.channel());
00100             if (namch != 0)
00101                 //Tcl_Flush(pt_->namchannel());
00102                 pt_->flush(namch);
00103             return (TCL_OK);
00104         }
00105                 if (strcmp(argv[1], "tagged") == 0) {
00106             tcl.resultf("%d", pt_->tagged());
00107                         return (TCL_OK);
00108                 }
00109     } else if (argc == 3) {
00110         if (strcmp(argv[1], "annotate") == 0) {
00111             if (pt_->channel() != 0)
00112                 annotate(argv[2]);
00113             return (TCL_OK);
00114         }
00115         if (strcmp(argv[1], "attach") == 0) {
00116             int mode;
00117             const char* id = argv[2];
00118             Tcl_Channel ch = Tcl_GetChannel(tcl.interp(), (char*)id,
00119                           &mode);
00120             pt_->channel(ch); 
00121             if (pt_->channel() == 0) {
00122                 tcl.resultf("trace: can't attach %s for writing", id);
00123                 return (TCL_ERROR);
00124             }
00125             return (TCL_OK);
00126         }
00127         if (strcmp(argv[1], "namattach") == 0) {
00128             int mode;
00129             const char* id = argv[2];
00130             Tcl_Channel namch = Tcl_GetChannel(tcl.interp(), 
00131                                (char*)id, &mode);
00132             pt_->namchannel(namch); 
00133             if (pt_->namchannel() == 0) {
00134                 tcl.resultf("trace: can't attach %s for writing", id);
00135                 return (TCL_ERROR);
00136             }
00137             return (TCL_OK);
00138         }
00139         if (strcmp(argv[1], "ntrace") == 0) {
00140             if (pt_->namchannel() != 0) 
00141                 write_nam_trace(argv[2]);
00142             return (TCL_OK);
00143         }
00144         if (strcmp(argv[1], "tagged") == 0) {
00145                         int tag;
00146             if (Tcl_GetBoolean(tcl.interp(),
00147                        (char*)argv[2], &tag) == TCL_OK) {
00148                 pt_->tagged(tag);
00149                 return (TCL_OK);
00150             } else return (TCL_ERROR);
00151                 }
00152     }
00153     return (Connector::command(argc, argv));
00154 }
00155 
00156 void Trace::write_nam_trace(const char *s)
00157 {
00158     sprintf(pt_->nbuffer(), "%s", s);
00159     pt_->namdump();
00160 }
00161 
00162 void Trace::annotate(const char* s)
00163 {
00164     if (pt_->tagged()) {
00165         sprintf(pt_->buffer(),
00166             "v "TIME_FORMAT" -e {sim_annotation %g %s}",
00167             Scheduler::instance().clock(), 
00168             Scheduler::instance().clock(), s);
00169     } else {
00170         sprintf(pt_->buffer(),
00171             "v "TIME_FORMAT" eval {set sim_annotation {%s}}", 
00172             pt_->round(Scheduler::instance().clock()), s);
00173     }
00174     pt_->dump();
00175     callback();
00176     sprintf(pt_->nbuffer(), "v -t "TIME_FORMAT" -e sim_annotation %g %s", 
00177         Scheduler::instance().clock(), 
00178         Scheduler::instance().clock(), s);
00179     pt_->namdump();
00180 }
00181 
00182 
00183 char* srm_names[] = {
00184         SRM_NAMES
00185 };
00186 
00187 int
00188 Trace::get_seqno(Packet* p)
00189 {
00190     hdr_cmn *th = hdr_cmn::access(p);
00191     hdr_tcp *tcph = hdr_tcp::access(p);
00192     hdr_rtp *rh = hdr_rtp::access(p);
00193         hdr_rap *raph = hdr_rap::access(p);
00194     hdr_tfrc *tfrch = hdr_tfrc::access(p);
00195     hdr_tfrc_ack *tfrch_ack = hdr_tfrc_ack::access(p);
00196     packet_t t = th->ptype();
00197     int seqno;
00198 
00199     /* UDP's now have seqno's too */
00200     if (t == PT_RTP || t == PT_CBR || t == PT_UDP || t == PT_EXP ||
00201         t == PT_PARETO)
00202         seqno = rh->seqno();
00203         else if (t == PT_RAP_DATA || t == PT_RAP_ACK)
00204                 seqno = raph->seqno();
00205     else if (t == PT_TCP || t == PT_ACK || t == PT_HTTP || t == PT_FTP ||
00206         t == PT_TELNET || t == PT_XCP)
00207         seqno = tcph->seqno();
00208     else if (t == PT_TFRC)
00209         seqno = tfrch->seqno;
00210     else if (t == PT_TFRC_ACK)
00211                 seqno = tfrch_ack->seqno;
00212     else
00213         seqno = -1;
00214     return seqno;
00215 }
00216 
00217 // this function should retain some backward-compatibility, so that
00218 // scripts don't break.
00219 void Trace::format(int tt, int s, int d, Packet* p)
00220 {
00221     hdr_cmn *th = hdr_cmn::access(p);
00222     hdr_ip *iph = hdr_ip::access(p);
00223     hdr_tcp *tcph = hdr_tcp::access(p);
00224     hdr_sctp *sctph = hdr_sctp::access(p);
00225     hdr_srm *sh = hdr_srm::access(p); 
00226 
00227     const char* sname = "null";
00228 
00229     packet_t t = th->ptype();
00230     const char* name = packet_info.name(t);
00231 
00232         /* SRM-specific */
00233     if (strcmp(name,"SRM") == 0 || strcmp(name,"cbr") == 0 || strcmp(name,"udp") == 0) {
00234             if ( sh->type() < 5 && sh->type() > 0 ) {
00235             sname = srm_names[sh->type()];
00236         }
00237     }
00238 
00239     if (name == 0)
00240         abort();
00241 
00242     int seqno = get_seqno(p);
00243         /* 
00244          * When new flags are added, make sure to change NUMFLAGS
00245          * in trace.h
00246          */
00247         char flags[NUMFLAGS+1];
00248         for (int i = 0; i < NUMFLAGS; i++)
00249         flags[i] = '-';
00250         flags[NUMFLAGS] = 0;
00251 
00252     hdr_flags* hf = hdr_flags::access(p);
00253     flags[0] = hf->ecn_ ? 'C' : '-';          // Ecn Echo
00254     flags[1] = hf->pri_ ? 'P' : '-'; 
00255     flags[2] = '-';
00256     flags[3] = hf->cong_action_ ? 'A' : '-';   // Congestion Action
00257     flags[4] = hf->ecn_to_echo_ ? 'E' : '-';   // Congestion Experienced
00258     flags[5] = hf->fs_ ? 'F' : '-';        // Fast start: see tcp-fs and tcp-int
00259     flags[6] = hf->ecn_capable_ ? 'N' : '-';
00260     flags[7] = 0; // only for SCTP  
00261 
00262 #ifdef notdef
00263     flags[1] = (iph->flags() & PF_PRI) ? 'P' : '-';
00264     flags[2] = (iph->flags() & PF_USR1) ? '1' : '-';
00265     flags[3] = (iph->flags() & PF_USR2) ? '2' : '-';
00266     flags[5] = 0;
00267 #endif
00268     char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr());
00269     char *src_portaddr = Address::instance().print_portaddr(iph->sport());
00270     char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr());
00271     char *dst_portaddr = Address::instance().print_portaddr(iph->dport());
00272 
00273     if (pt_->tagged()) {
00274         sprintf(pt_->buffer(), 
00275             "%c "TIME_FORMAT" -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
00276             tt,
00277             Scheduler::instance().clock(),
00278             s,
00279             d,
00280             name,
00281             th->size(),
00282             iph->flowid(),
00283             th->uid(),
00284             iph->flowid(),
00285             src_nodeaddr,
00286             src_portaddr,
00287             dst_nodeaddr,
00288             dst_portaddr,
00289             seqno,flags,sname);
00290     } else if (show_sctphdr_ && t == PT_SCTP) {
00291         double timestamp;
00292         timestamp = Scheduler::instance().clock();
00293         
00294         for(unsigned int i = 0; i < sctph->NumChunks(); i++) {
00295             switch(sctph->SctpTrace()[i].eType) {
00296             case SCTP_CHUNK_INIT:
00297             case SCTP_CHUNK_INIT_ACK:
00298             case SCTP_CHUNK_COOKIE_ECHO:
00299             case SCTP_CHUNK_COOKIE_ACK:
00300                 flags[7] = 'I';     // connection initialization
00301                 break;
00302                 
00303             case SCTP_CHUNK_DATA:
00304                 flags[7] = 'D';
00305                 break;
00306 
00307             case SCTP_CHUNK_SACK:
00308                 flags[7] = 'S';
00309                 break;
00310                 
00311             case SCTP_CHUNK_FORWARD_TSN:
00312                 flags[7] = 'R';
00313                 break;
00314                 
00315             case SCTP_CHUNK_HB:
00316                 flags[7] = 'H';
00317                 break;
00318 
00319             case SCTP_CHUNK_HB_ACK:
00320                 flags[7] = 'B';
00321                 break;
00322             default:
00323                 assert (false);
00324             }
00325             sprintf(pt_->buffer(),
00326                 "%c "TIME_FORMAT" %d %d %s %d %s %d %s.%s %s.%s %d %d %d %d %d",
00327                 tt,
00328                 pt_->round(timestamp),
00329                 s,
00330                 d,
00331                 name,
00332                 th->size(),
00333                 flags,
00334                 iph->flowid(), /* was p->class_ */
00335                 src_nodeaddr,
00336                 src_portaddr,
00337                 dst_nodeaddr,
00338                 dst_portaddr,
00339                 sctph->NumChunks(),
00340                 sctph->SctpTrace()[i].uiTsn,
00341                 th->uid(), /* was p->uid_ */
00342                 sctph->SctpTrace()[i].usStreamId,
00343                 sctph->SctpTrace()[i].usStreamSeqNum);       
00344 
00345             /* The caller already calls pt_->dump() for us,
00346              * but since SCTP needs to dump once per chunk, we
00347              * call dump ourselves for all but the last chunk.
00348              */
00349             assert (sctph->NumChunks() >= 1);
00350             if(i < sctph->NumChunks() - 1)
00351                 pt_->dump();
00352         }
00353     } else if (!show_tcphdr_) {
00354         sprintf(pt_->buffer(), "%c "TIME_FORMAT" %d %d %s %d %s %d %s.%s %s.%s %d %d",
00355             tt,
00356             pt_->round(Scheduler::instance().clock()),
00357             s,
00358             d,
00359             name,
00360             th->size(),
00361             flags,
00362             iph->flowid() /* was p->class_ */,
00363             // iph->src() >> (Address::instance().NodeShift_[1]), 
00364                         // iph->src() & (Address::instance().PortMask_), 
00365                         // iph->dst() >> (Address::instance().NodeShift_[1]), 
00366                         // iph->dst() & (Address::instance().PortMask_),
00367             src_nodeaddr,
00368             src_portaddr,
00369             dst_nodeaddr,
00370             dst_portaddr,
00371             seqno,
00372             th->uid() /* was p->uid_ */);
00373     } else {
00374         sprintf(pt_->buffer(), 
00375             "%c "TIME_FORMAT" %d %d %s %d %s %d %s.%s %s.%s %d %d %d 0x%x %d %d",
00376             tt,
00377             pt_->round(Scheduler::instance().clock()),
00378             s,
00379             d,
00380             name,
00381             th->size(),
00382             flags,
00383             iph->flowid(), /* was p->class_ */
00384                 // iph->src() >> (Address::instance().NodeShift_[1]), 
00385             // iph->src() & (Address::instance().PortMask_), 
00386                 // iph->dst() >> (Address::instance().NodeShift_[1]), 
00387                 // iph->dst() & (Address::instance().PortMask_),
00388             src_nodeaddr,
00389             src_portaddr,
00390             dst_nodeaddr,
00391             dst_portaddr,
00392             seqno,
00393             th->uid(), /* was p->uid_ */
00394             tcph->ackno(),
00395             tcph->flags(),
00396             tcph->hlen(),
00397             tcph->sa_length());
00398     }
00399     if (pt_->namchannel() != 0)
00400         sprintf(pt_->nbuffer(), 
00401             "%c -t "TIME_FORMAT" -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
00402             tt,
00403             Scheduler::instance().clock(),
00404             s,
00405             d,
00406             name,
00407             th->size(),
00408             iph->flowid(),
00409             th->uid(),
00410             iph->flowid(),
00411             src_nodeaddr,
00412             src_portaddr,
00413             dst_nodeaddr,
00414             dst_portaddr,
00415             seqno,flags,sname);
00416     delete [] src_nodeaddr;
00417     delete [] src_portaddr;
00418     delete [] dst_nodeaddr;
00419     delete [] dst_portaddr;
00420 }
00421 
00422 void Trace::recv(Packet* p, Handler* h)
00423 {
00424     format(type_, src_, dst_, p);
00425     pt_->dump();
00426     callback();
00427     pt_->namdump();
00428     /* hack: if trace object not attached to anything free packet */
00429     if (target_ == 0)
00430         Packet::free(p);
00431     else
00432         send(p, h);
00433 }
00434 
00435 void Trace::recvOnly(Packet *p)
00436 {
00437     format(type_, src_, dst_, p);
00438     pt_->dump();
00439     callback();
00440     pt_->namdump(); 
00441     target_->recvOnly(p);
00442 }
00443 
00444 void Trace::trace(TracedVar* var)
00445 {
00446     char tmp[256] = "";
00447     Scheduler& s = Scheduler::instance();
00448     if (&s == 0)
00449         return;
00450 
00451     if (pt_->tagged()) {
00452         sprintf(pt_->buffer(), "%c "TIME_FORMAT" -a %s -n %s -v %s",
00453             type_,
00454             pt_->round(s.clock()),
00455             var->owner()->name(),
00456             var->name(),
00457             var->value(tmp, 256));
00458     } else {
00459         // format: use Mark's nam feature code without the '-' prefix
00460         sprintf(pt_->buffer(), "%c t"TIME_FORMAT" a%s n%s v%s",
00461             type_,
00462             pt_->round(s.clock()),
00463             var->owner()->name(),
00464             var->name(),
00465             var->value(tmp, 256));
00466     }
00467     pt_->dump();
00468     callback();
00469 }
00470 
00471 void Trace::callback() 
00472 {
00473     if (callback_) {
00474         Tcl& tcl = Tcl::instance();
00475         tcl.evalf("%s handle { %s }", name(), pt_->buffer());
00476     }
00477 }
00478 
00479 //
00480 // we need a DequeTraceClass here because a 'h' event need to go together
00481 // with the '-' event. It's possible to use a postprocessing script, but 
00482 // seems that's inconvient.
00483 //
00484 static class DequeTraceClass : public TclClass {
00485 public:
00486     DequeTraceClass() : TclClass("Trace/Deque") { }
00487     TclObject* create(int args, const char*const* argv) {
00488         if (args >= 5)
00489             return (new DequeTrace(*argv[4]));
00490         return NULL;
00491     }
00492 } dequetrace_class;
00493 
00494 
00495 DequeTrace::~DequeTrace()
00496 {
00497 }
00498 
00499 void 
00500 DequeTrace::recv(Packet* p, Handler* h)
00501 {
00502     // write the '-' event first
00503     format(type_, src_, dst_, p);
00504     pt_->dump();
00505     callback();
00506     pt_->namdump();
00507 
00508     if (pt_->namchannel() != 0 ||
00509         (pt_->tagged() && pt_->channel() !=0)) {
00510         hdr_cmn *th = hdr_cmn::access(p);
00511         hdr_ip *iph = hdr_ip::access(p);
00512         hdr_srm *sh = hdr_srm::access(p);
00513         const char* sname = "null";   
00514 
00515         packet_t t = th->ptype();
00516         const char* name = packet_info.name(t);
00517         
00518         if (strcmp(name,"SRM") == 0 || strcmp(name,"cbr") == 0 || strcmp(name,"udp") == 0) {
00519             if ( sh->type() < 5 && sh->type() > 0  ) {
00520                 sname = srm_names[sh->type()];
00521             }
00522         }   
00523 
00524         char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr());
00525         char *src_portaddr = Address::instance().print_portaddr(iph->sport());
00526         char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr());
00527         char *dst_portaddr = Address::instance().print_portaddr(iph->dport());
00528 
00529         char flags[NUMFLAGS+1];
00530         for (int i = 0; i < NUMFLAGS; i++)
00531             flags[i] = '-';
00532         flags[NUMFLAGS] = 0;
00533 
00534         hdr_flags* hf = hdr_flags::access(p);
00535         flags[0] = hf->ecn_ ? 'C' : '-';          // Ecn Echo
00536         flags[1] = hf->pri_ ? 'P' : '-'; 
00537         flags[2] = '-';
00538         flags[3] = hf->cong_action_ ? 'A' : '-';   // Congestion Action
00539         flags[4] = hf->ecn_to_echo_ ? 'E' : '-';   // Congestion Experienced
00540         flags[5] = hf->fs_ ? 'F' : '-';
00541         flags[6] = hf->ecn_capable_ ? 'N' : '-';
00542         flags[7] = 0; // only for SCTP
00543     
00544 #ifdef notdef
00545         flags[1] = (iph->flags() & PF_PRI) ? 'P' : '-';
00546         flags[2] = (iph->flags() & PF_USR1) ? '1' : '-';
00547         flags[3] = (iph->flags() & PF_USR2) ? '2' : '-';
00548         flags[5] = 0;
00549 #endif
00550         
00551         if (pt_->nbuffer() != 0) {
00552             sprintf(pt_->nbuffer(), 
00553                 "%c -t "TIME_FORMAT" -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
00554                 'h',
00555                 Scheduler::instance().clock(),
00556                 src_,
00557                 dst_,
00558                 name,
00559                 th->size(),
00560                 iph->flowid(),
00561                 th->uid(),
00562                 iph->flowid(),
00563                 src_nodeaddr,
00564                 src_portaddr,
00565                 dst_nodeaddr,
00566                 dst_portaddr,
00567                 -1, flags, sname);
00568             pt_->namdump();
00569         }
00570         if (pt_->tagged() && pt_->buffer() != 0) {
00571             sprintf(pt_->buffer(), 
00572                 "%c "TIME_FORMAT" -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
00573                 'h',
00574                 Scheduler::instance().clock(),
00575                 src_,
00576                 dst_,
00577                 name,
00578                 th->size(),
00579                 iph->flowid(),
00580                 th->uid(),
00581                 iph->flowid(),
00582                 src_nodeaddr,
00583                 src_portaddr,
00584                 dst_nodeaddr,
00585                 dst_portaddr,
00586                 -1, flags, sname);
00587             pt_->dump();
00588         }
00589 
00590         delete [] src_nodeaddr;
00591         delete [] src_portaddr;
00592         delete [] dst_nodeaddr;
00593         delete [] dst_portaddr;
00594     }
00595 
00596     /* hack: if trace object not attached to anything free packet */
00597     if (target_ == 0)
00598         Packet::free(p);
00599     else
00600         send(p, h);
00601 }
00602 

Generated on Tue Mar 6 16:47:53 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6