errmodel.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 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 Daedalus Research
00017  *  Group at the University of California Berkeley.
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  * Contributed by the Daedalus Research Group, UC Berkeley 
00035  * (http://daedalus.cs.berkeley.edu)
00036  *
00037  * Multi-state error model patches contributed by Jianping Pan 
00038  * (jpan@bbcr.uwaterloo.ca).
00039  *
00040  * @(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/errmodel.cc,v 1.81 2005/09/21 21:45:04 haldar Exp $ (UCB)
00041  */
00042 
00043 #ifndef lint
00044 static const char rcsid[] =
00045     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/errmodel.cc,v 1.81 2005/09/21 21:45:04 haldar Exp $ (UCB)";
00046 #endif
00047 
00048 #include "config.h"
00049 #include <stdio.h>
00050 #include <ctype.h>
00051 #include "packet.h"
00052 #include "flags.h"
00053 #include "mcast_ctrl.h"
00054 #include "errmodel.h"
00055 #include "srm-headers.h"        // to get the hdr_srm structure
00056 #include "classifier.h"
00057 
00058 static class ErrorModelClass : public TclClass {
00059 public:
00060     ErrorModelClass() : TclClass("ErrorModel") {}
00061     TclObject* create(int, const char*const*) {
00062         return (new ErrorModel);
00063     }
00064 } class_errormodel;
00065 
00066 static class TwoStateErrorModelClass : public TclClass {
00067 public:
00068     TwoStateErrorModelClass() : TclClass("ErrorModel/TwoState") {}
00069     TclObject* create(int, const char*const*) {
00070         return (new TwoStateErrorModel);
00071     }
00072 } class_errormodel_twostate;
00073 
00074 static class ComplexTwoStateMarkovModelClass : public TclClass {
00075 public:
00076     ComplexTwoStateMarkovModelClass() : TclClass("ErrorModel/ComplexTwoStateMarkov") {}
00077     TclObject* create(int, const char*const*) {
00078         return (new ComplexTwoStateErrorModel);
00079     }
00080 } class_errormodel_complextwostatemarkov;
00081 
00082 
00083 static class MultiStateErrorModelClass : public TclClass {
00084 public:
00085     MultiStateErrorModelClass() : TclClass("ErrorModel/MultiState") {}
00086     TclObject* create(int, const char*const*) {
00087         return (new MultiStateErrorModel);
00088     }
00089 } class_errormodel_multistate;
00090 
00091 static class TraceErrorModelClass : public TclClass {
00092 public:
00093     TraceErrorModelClass() : TclClass("ErrorModel/Trace") {}
00094     TclObject* create(int, const char*const*) {
00095         return (new TraceErrorModel);
00096     }
00097 } class_traceerrormodel;
00098 
00099 static char* eu_names[] = { EU_NAMES };
00100 
00101 inline double comb(int n, int k) {
00102     int i;
00103     double sum = 1.0;
00104 
00105     for(i = 0; i < k; i++) 
00106         sum *= (n - i)/(i + 1);
00107     return sum;
00108 }
00109 
00110 
00111 ErrorModel::ErrorModel() : et_(0), firstTime_(1), unit_(EU_PKT), ranvar_(0), FECstrength_(1)
00112 {
00113     bind("enable_", &enable_);
00114     bind("rate_", &rate_);
00115     bind("delay_", &delay_);
00116     bind_bw("bandwidth_", &bandwidth_); // required for EU_TIME
00117     bind_bool("markecn_", &markecn_);
00118     bind_bool("delay_pkt_", &delay_pkt_);
00119     
00120 }
00121 
00122 int ErrorModel::command(int argc, const char*const* argv)
00123 {
00124     Tcl& tcl = Tcl::instance();
00125     //ErrorModel *em;
00126     if (argc == 3) {
00127         if (strcmp(argv[1], "unit") == 0) {
00128             unit_ = STR2EU(argv[2]);
00129             return (TCL_OK);
00130         } 
00131         if (strcmp(argv[1], "ranvar") == 0) {
00132             ranvar_ = (RandomVariable*) TclObject::lookup(argv[2]);
00133             return (TCL_OK);
00134         }
00135         if (strcmp(argv[1], "FECstrength") == 0) {
00136             FECstrength_ = atoi(argv[2]);
00137             return (TCL_OK);
00138         }
00139         if (strcmp(argv[1], "datapktsize") == 0) {
00140             datapktsize_ = atoi(argv[2]);
00141             return (TCL_OK);
00142         }
00143         if (strcmp(argv[1], "cntrlpktsize") == 0) {
00144             cntrlpktsize_ = atoi(argv[2]);
00145             return (TCL_OK);
00146         }
00147         if (strcmp(argv[1], "eventtrace") == 0) {
00148             et_ = (EventTrace *)TclObject::lookup(argv[2]);
00149             return (TCL_OK);
00150         }
00151     } else if (argc == 2) {
00152         if (strcmp(argv[1], "unit") == 0) {
00153             tcl.resultf("%s", eu_names[unit_]);
00154             return (TCL_OK);
00155         }
00156         if (strcmp(argv[1], "ranvar") == 0) {
00157             tcl.resultf("%s", ranvar_->name());
00158             return (TCL_OK);
00159         } 
00160         if (strcmp(argv[1], "FECstrength") == 0) {
00161             tcl.resultf("%d", FECstrength_);
00162             return (TCL_OK);
00163         } 
00164     } 
00165     return Connector::command(argc, argv);
00166 }
00167 
00168 void ErrorModel::reset()
00169 {
00170     firstTime_ = 1;
00171 }
00172 
00173 void ErrorModel::recv(Packet* p, Handler* h)
00174 {
00175     // 1.  Determine the error by calling corrupt(p)
00176     // 2.  Set the packet's error flag if it is corrupted
00177     // 3.  If there is no error,  no drop_ target or markecn is true,
00178     //  let pkt continue, otherwise hand the corrupted packet to drop_
00179 
00180     hdr_cmn* ch = hdr_cmn::access(p);
00181     int error = corrupt(p);
00182 
00183     // XXX When we do ECN, the packet is marked but NOT dropped.
00184     // So we don't resume handler here. 
00185     if (!markecn_ && !delay_pkt_ && (h && ((error && drop_) || !target_))) {
00186         // if we drop or there is no target_, then resume handler
00187         double delay = Random::uniform(8.0 * ch->size() / bandwidth_);
00188         if (intr_.uid_ <= 0 ) 
00189             // schedule only if nothing scheduled already
00190             Scheduler::instance().schedule(h, &intr_, delay);
00191     } 
00192     if (error) {
00193         ch->error() |= error;
00194 
00195         if (markecn_) {
00196             hdr_flags* hf = hdr_flags::access(p);
00197             hf->ce() = 1;
00198         } else if (delay_pkt_) {
00199             // Delay the packet.
00200             Scheduler::instance().schedule(target_, p, delay_);
00201             return;
00202         } else if (drop_) {
00203             drop_->recv(p);
00204             return;
00205         }
00206     }
00207 
00208     if (target_) {
00209             target_->recv(p, h);
00210     }
00211 }
00212 
00213 int ErrorModel::corrupt(Packet* p)
00214 {
00215     hdr_cmn* ch;
00216     // a temp hack
00217 
00218     ch = HDR_CMN(p);
00219     
00220     if (enable_ == 0)
00221         return 0;
00222     switch (unit_) {
00223     case EU_TIME:
00224         return (CorruptTime(p) != 0);
00225     case EU_BYTE:
00226         return (CorruptByte(p) != 0);
00227     case EU_BIT:
00228         ch = hdr_cmn::access(p);
00229         ch->errbitcnt() = CorruptBit(p);
00230         return (ch->errbitcnt() != 0);
00231     default:
00232         return (CorruptPkt(p) != 0);
00233     }
00234     return 0;
00235 }
00236 
00237 double ErrorModel::PktLength(Packet* p)
00238 {
00239     //double now;
00240     if (unit_ == EU_PKT)
00241         return 1;
00242     int byte = hdr_cmn::access(p)->size();
00243     if (unit_ == EU_BYTE)
00244         return byte;
00245     if (unit_ == EU_BIT)
00246         return 8.0 * byte;
00247     return 8.0 * byte / bandwidth_;
00248 }
00249 
00250 double * ErrorModel::ComputeBitErrProb(int size) 
00251 {
00252     double *dptr;
00253     int i;
00254 
00255         dptr = (double *)calloc((FECstrength_ + 2), sizeof(double));
00256 
00257         for (i = 0; i < (FECstrength_ + 1) ; i++) 
00258         dptr[i] = comb(size, i) * pow(rate_, (double)i) * pow(1.0 - rate_, (double)(size - i));
00259 
00260     // Cumulative probability
00261     for (i = 0; i < FECstrength_ ; i++) 
00262         dptr[i + 1] += dptr[i];
00263     
00264     dptr[FECstrength_ + 1] = 1.0;
00265 
00266     /*  printf("Size = %d\n", size);
00267     for (i = 0; i <(FECstrength_ + 2); i++)
00268         printf("Ptr[%d] = %g\n", i, dptr[i]); */
00269 
00270     return dptr;
00271     
00272 }
00273 
00274 int ErrorModel::CorruptPkt(Packet*) 
00275 {
00276     // if no random var is specified, assume uniform random variable
00277     double u = ranvar_ ? ranvar_->value() : Random::uniform();
00278     return (u < rate_);
00279 }
00280 
00281 int ErrorModel::CorruptByte(Packet* p)
00282 {
00283     // compute pkt error rate, assume uniformly distributed byte error
00284     double per = 1 - pow(1.0 - rate_, PktLength(p));
00285     double u = ranvar_ ? ranvar_->value() : Random::uniform();
00286     return (u < per);
00287 }
00288 
00289 int ErrorModel::CorruptBit(Packet* p)
00290 {
00291     double u, *dptr;
00292     int i;
00293 
00294     if (firstTime_ && FECstrength_) {
00295         // precompute the probabilies for each bit-error cnts
00296         cntrlprb_ = ComputeBitErrProb(cntrlpktsize_);
00297         dataprb_ = ComputeBitErrProb(datapktsize_);
00298 
00299         firstTime_ = 0;
00300     }   
00301 
00302     u = ranvar_ ? ranvar_->value() : Random::uniform();
00303     dptr = (hdr_cmn::access(p)->size() >= datapktsize_) ? dataprb_ : cntrlprb_;
00304         for (i = 0; i < (FECstrength_ + 2); i++)
00305         if (dptr[i] > u) break;
00306     return(i);
00307 }
00308 
00309 int ErrorModel::CorruptTime(Packet *)
00310 {
00311     fprintf(stderr, "Warning:  uniform rate error cannot be time-based\n");
00312     return 0;
00313 }
00314 
00315 #if 0
00316 /*
00317  * Decide whether or not to corrupt this packet, for a continuous 
00318  * time-based error model.  The main parameter used is errLength,
00319  * which is the time to the next error, from the last time an error 
00320  * occured on  the channel.  It is dependent on the random variable 
00321  * being used  internally.
00322  *  rate_ is the user-specified mean
00323  */
00324 int ErrorModel::CorruptTime(Packet *p)
00325 {
00326     /* 
00327      * First get MAC header.  It has the transmission time (txtime)
00328      * of the packet in one of it's fields.  Then, get the time
00329      * interval [t-txtime, t], where t is the current time.  The
00330      * goal is to figure out whether the channel would have
00331      * corrupted the packet during that interval. 
00332      */
00333     Scheduler &s = Scheduler::instance();
00334     double now = s.clock(), rv;
00335     int numerrs = 0;
00336     double start = now - hdr_mac::access(p)->txtime();
00337 
00338     while (remainLen_ < start) {
00339         rv = ranvar_ ? ranvar_->value() : Random::uniform(rate_);
00340         remainLen_ += rv;
00341     }
00342 
00343     while (remainLen_ < now) { /* corrupt the packet */
00344         numerrs++;
00345         rv = ranvar_ ? ranvar_->value() : Random::uniform(rate_);
00346         remainLen_ += rv;
00347     }
00348     return numerrs;
00349 }
00350 #endif
00351 
00352 void ErrorModel::trace_event(char *eventtype)
00353 {
00354     if (et_ == NULL) return;
00355     char *wrk = et_->buffer();
00356     char *nwrk = et_->nbuffer();
00357     if (wrk != 0)
00358         sprintf(wrk,
00359             "E "TIME_FORMAT" ErrModelTimer %p %s",
00360             et_->round(Scheduler::instance().clock()),   // time
00361             this,
00362             eventtype                    // event type
00363             );
00364     
00365     if (nwrk != 0)
00366         sprintf(nwrk,
00367             "E -t "TIME_FORMAT" ErrModelTimer %p %s",
00368             et_->round(Scheduler::instance().clock()),   // time
00369             this,
00370             eventtype                    // event type
00371             );
00372     et_->trace();
00373 }
00374 
00375 
00376 
00377 /*
00378  * Two-State:  error-free and error
00379  */
00380 TwoStateErrorModel::TwoStateErrorModel() : remainLen_(0), twoStateTimer_(NULL)
00381 {
00382     ranvar_[0] = ranvar_[1] = 0;
00383 }
00384 
00385 int TwoStateErrorModel::command(int argc, const char*const* argv)
00386 {
00387     Tcl& tcl = Tcl::instance();
00388     if (strcmp(argv[1], "ranvar") == 0) {
00389         int i = atoi(argv[2]);
00390         if (i < 0 || i > 1) {
00391             tcl.resultf("%s does not has ranvar_[%d]", name_, i);
00392             return (TCL_ERROR);
00393         }
00394         if (argc == 3) {
00395             tcl.resultf("%s", ranvar_[i]->name());
00396             return (TCL_OK);
00397         }
00398         if (argc == 4) {
00399             ranvar_[i] = (RandomVariable*)TclObject::lookup(argv[3]);
00400             if (ranvar_[0] != 0 && ranvar_[1] != 0)
00401                 checkUnit();
00402             return (TCL_OK);
00403         } 
00404     }
00405     return ErrorModel::command(argc, argv);
00406 }
00407 
00408 int TwoStateErrorModel::corruptPkt(Packet* p)
00409 {
00410 #define ZERO 0.00000
00411     int error;
00412     if (firstTime_) {
00413         firstTime_ = 0;
00414         state_ = 0;
00415         remainLen_ = ranvar_[state_]->value();
00416     }
00417 
00418     // if remainLen_ is outside the range of 0, then error = state_
00419     error = state_ && (remainLen_ > ZERO);
00420     remainLen_ -= PktLength(p);
00421 
00422     // state transition until remainLen_ > 0 to covers the packet length
00423     while (remainLen_ <= ZERO) {
00424         state_ ^= 1;    // state transition: 0 <-> 1
00425         remainLen_ += ranvar_[state_]->value();
00426         error |= state_;
00427     }
00428     return error;
00429 }
00430 
00431 void TwoStateErrorModel::checkUnit() 
00432 {
00433     if (unit_ == EU_TIME) {
00434         // setup timer for keeping states in time
00435         twoStateTimer_ = new TwoStateErrModelTimer(this, &TwoStateErrorModel::transitionState);
00436         transitionState();
00437     }
00438     
00439 }
00440 
00441 void TwoStateErrorModel::transitionState()
00442 {
00443     char buf[SMALL_LEN];
00444     
00445     if (firstTime_) {
00446         firstTime_ = 0;
00447         state_ = 0;
00448         remainLen_ = ranvar_[state_]->value();
00449         twoStateTimer_->sched(remainLen_);
00450         sprintf (buf,"STATE %d, DURATION %f",state_,remainLen_);
00451         trace_event(buf);
00452         return;
00453     }
00454     state_ ^= 1;
00455     remainLen_ = ranvar_[state_]->value();
00456     twoStateTimer_->resched(remainLen_);
00457     sprintf (buf,"STATE %d, DURATION %f",state_,remainLen_);
00458     trace_event(buf);
00459     
00460 }
00461 
00462 
00463 
00464 int TwoStateErrorModel::corrupt(Packet* p)
00465 {
00466     if (unit_ == EU_TIME)
00467         return corruptTime(p);
00468     else
00469         return corruptPkt(p);
00470 }
00471 
00472 int TwoStateErrorModel::corruptTime(Packet* p)
00473 {
00474     int error = 0;
00475     if (state_ == 1)
00476         error = 1;
00477     return error;
00478     
00479 }
00480 
00481 ComplexTwoStateErrorModel::ComplexTwoStateErrorModel() 
00482 {
00483     em_[0] = new TwoStateErrorModel();
00484     em_[1] = new TwoStateErrorModel();
00485 }
00486 
00487 ComplexTwoStateErrorModel::~ComplexTwoStateErrorModel()
00488 {
00489     delete em_[0];
00490     delete em_[1];
00491 }
00492 
00493 int ComplexTwoStateErrorModel::command(int argc, const char*const* argv)
00494 {
00495     Tcl& tcl = Tcl::instance();
00496     if (argc == 3) {
00497         if (strcmp(argv[1], "unit") == 0) {
00498             unit_ = STR2EU(argv[2]);
00499             em_[0]->setunit(unit_); 
00500             em_[1]->setunit(unit_);
00501             return TCL_OK;
00502         }
00503         if (strcmp(argv[1], "eventtrace") == 0) {
00504             EventTrace* et = (EventTrace *)TclObject::lookup(argv[2]);
00505             em_[0]->et_ = et;
00506             em_[1]->et_ = et;
00507             return (TCL_OK);
00508         }
00509     }
00510     else if (argc == 5) {
00511         if (strcmp(argv[1], "ranvar") == 0) {
00512             int i = atoi(argv[2]);
00513             int j = atoi(argv[3]);
00514             if (i < 0 || i > 1) {
00515                 tcl.add_errorf("%s does not has em_[%d]", name_, i);
00516                 return (TCL_ERROR);
00517             }
00518             if (j < 0 || j > 1) {
00519                 tcl.add_errorf("%s does not has ranvar_[%d]", name_, i);
00520                 return (TCL_ERROR);
00521             }
00522 
00523             em_[i]->ranvar_[j] = (RandomVariable*)TclObject::lookup(argv[4]);
00524             if (em_[i]->ranvar_[0] != 0 && em_[i]->ranvar_[1] != 0)
00525                 em_[i]->checkUnit();
00526             return (TCL_OK);
00527         }
00528         
00529     }
00530     return ErrorModel::command(argc, argv);
00531 }
00532 
00533 
00534 int ComplexTwoStateErrorModel::corruptTime(Packet* p)
00535 {
00536     int error = 0;
00537     if (em_[0]->state_ == 1 && em_[1]->state_ == 1)
00538         error = 1;
00539     return error;
00540 }
00541 
00542 int ComplexTwoStateErrorModel::corruptPkt(Packet* p)
00543 {
00544     fprintf(stderr, "Error model defined in time; not in packets\n");
00545     return -1;
00546     
00547 }
00548 
00549 
00550 
00551 static char * st_names[]={ST_NAMES};
00552 
00553 /*
00554 // MultiState ErrorModel:
00555 //   corrupt(pkt) invoke Tcl method "corrupt" to do state transition
00556 //  Tcl corrupt either:
00557 //     - assign em_, the error-model to be use
00558 //     - return the status of the packet
00559 //  If em_ is assigned, then invoke em_->corrupt(p)
00560 */
00561 
00562 MultiStateErrorModel::MultiStateErrorModel() : prevTime_(0.0), em_(0)
00563 {
00564     bind("sttype_", &sttype_);
00565     bind("texpired_", &texpired_);
00566     bind("curperiod_", &curperiod_);
00567 }
00568 
00569 int MultiStateErrorModel::command(int argc, const char*const* argv)
00570 {
00571 
00572     Tcl& tcl = Tcl::instance();
00573 
00574     if (argc == 3) {
00575         if (strcmp(argv[1], "error-model") == 0) {
00576             em_ = (ErrorModel*) TclObject::lookup(argv[2]);
00577             return TCL_OK;
00578         }
00579         if (strcmp(argv[1], "sttype") == 0) {
00580             sttype_ = STR2ST(argv[2]);
00581             return TCL_OK;
00582         }
00583     } else if (argc == 2) {
00584         if (strcmp(argv[1], "sttype") == 0) {
00585             tcl.resultf("%s", st_names[sttype_]);
00586             return TCL_OK;
00587         }
00588         if (strcmp(argv[1], "error-model") == 0) {
00589             tcl.resultf("%s", (ErrorModel*) em_->name());
00590             return TCL_OK;
00591         }
00592     }
00593     return ErrorModel::command(argc, argv);
00594 }
00595 
00596 int MultiStateErrorModel::corrupt(Packet* p)
00597 {
00598     int retval;
00599     double now;
00600     // static double prevTime_ = 0.0;
00601     Scheduler & s = Scheduler::instance();
00602 
00603     now = s.clock();
00604 
00605     if (sttype_ == ST_TIME)
00606         if ((now - prevTime_) >= curperiod_)
00607             texpired_ = 1;
00608 
00609     Tcl& tcl = Tcl::instance();
00610     tcl.evalf("%s corrupt", name());
00611 
00612     retval = em_ ? em_->corrupt(p) : atoi(tcl.result());
00613 
00614     if (firstTime_) {
00615         firstTime_ = 0;
00616         prevTime_ = s.clock();
00617         texpired_ = 0;
00618     }
00619 
00620     return (retval);
00621 
00622 }
00623 
00624 
00625 TraceErrorModel::TraceErrorModel() : loss_(0), good_(123456789)
00626 {
00627     bind("good_", &good_);
00628     bind("loss_", &loss_);
00629 }
00630 
00631 /* opening and reading the trace file/info is done in OTcl */
00632 int TraceErrorModel::corrupt(Packet* p)
00633 {
00634     Tcl& tcl = Tcl::instance();
00635     if (! match(p))
00636         return 0;
00637     if ((good_ <= 0) && (loss_ <= 0)) {
00638         tcl.evalf("%s read",name());
00639         if (good_ < 0)
00640             good_ = 123456789;
00641     }
00642     if (good_-- > 0)
00643         return 0;
00644     return (loss_-- > 0);
00645 }
00646 
00647 int TraceErrorModel::match(Packet*)
00648 {
00649     return 1;
00650 }
00651 
00652 
00653 /*
00654  * Periodic ErrorModel
00655  */
00656 static class PeriodicErrorModelClass : public TclClass {
00657 public:
00658     PeriodicErrorModelClass() : TclClass("ErrorModel/Periodic") {}
00659     TclObject* create(int, const char*const*) {
00660         return (new PeriodicErrorModel);
00661     }
00662 } class_periodic_error_model;
00663 
00664 PeriodicErrorModel::PeriodicErrorModel() : cnt_(0), last_time_(0.0), first_time_(-1.0)
00665 {
00666     bind("period_", &period_);
00667     bind("offset_", &offset_);
00668     bind("burstlen_", &burstlen_);
00669     bind("default_drop_", &default_drop_);
00670 }
00671 
00672 int PeriodicErrorModel::corrupt(Packet* p)
00673 {
00674     hdr_cmn *ch = hdr_cmn::access(p);
00675     double now = Scheduler::instance().clock();
00676 
00677     if (unit_ == EU_TIME) {
00678         if (first_time_ < 0.0) {
00679             if (now >= offset_) {
00680                 first_time_ = last_time_ = now;
00681                 return 1;
00682             }
00683         } else {
00684             if ((now - last_time_) > period_) {
00685                 last_time_ = now;
00686                 return 1;
00687             }
00688             if ((now - last_time_) < burstlen_) {
00689                 return 1;
00690             }
00691         }
00692         return 0;
00693     }
00694     cnt_ += (unit_ == EU_PKT) ? 1 : ch->size();
00695     if (default_drop_) {
00696         if (int(first_time_) < 0) {
00697             if (cnt_ >= int(offset_)) {
00698                 last_time_ = first_time_ = 1.0;
00699                 cnt_ = 0;
00700                 return 0;
00701             }
00702             return 0;
00703         } else {
00704             if (cnt_ >= int(period_)) {
00705                 cnt_ = 0;
00706                 return 0;
00707             }
00708         }
00709         return 1;
00710     } else {
00711         if (int(first_time_) < 0) {
00712             if (cnt_ >= int(offset_)) {
00713                 last_time_ = first_time_ = 1.0;
00714                 cnt_ = 0;
00715                 return 1;
00716             }
00717             return 0;
00718         } else {
00719             if (cnt_ >= int(period_)) {
00720                 cnt_ = 0;
00721                 return 1;
00722             }
00723             if (cnt_ < burstlen_)
00724                 return 1;
00725         }
00726         return 0;
00727     }
00728 }
00729 
00730 /*
00731  * List ErrorModel: specify a list of packets/bytes to drop
00732  * can be specified in any order
00733  */
00734 static class ListErrorModelClass : public TclClass {
00735 public:
00736     ListErrorModelClass() : TclClass("ErrorModel/List") {}
00737     TclObject* create(int, const char*const*) {
00738         return (new ListErrorModel);
00739     }
00740 } class_list_error_model;
00741 
00742 int ListErrorModel::corrupt(Packet* p)
00743 {
00744     /* assumes droplist_ is sorted */
00745     int rval = 0;   // no drop
00746 
00747     if (unit_ == EU_TIME) {
00748         fprintf(stderr,
00749             "ListErrorModel: error, EU_TIME not supported\n");
00750         return 0;
00751     }
00752 
00753     if (droplist_ == NULL || dropcnt_ == 0) {
00754         fprintf(stderr, "warning: ListErrorModel: null drop list\n");
00755         return 0;
00756     }
00757 
00758     if (unit_ == EU_PKT) {
00759 //printf("TEST: cur_:%d, dropcnt_:%d, droplist_[cur_]:%d, cnt_:%d\n",
00760 //cur_, dropcnt_, droplist_[cur_], cnt_);
00761         if ((cur_ < dropcnt_) && droplist_[cur_] == cnt_) {
00762             rval = 1;
00763             cur_++;
00764         }
00765         cnt_++;
00766 
00767     } else if (unit_ == EU_BYTE) {
00768         int sz = hdr_cmn::access(p)->size();
00769         if ((cur_ < dropcnt_) && (cnt_ + sz) >= droplist_[cur_]) {
00770             rval = 1;
00771             cur_++;
00772         }
00773         cnt_ += sz;
00774     }
00775 
00776     return (rval);
00777 }
00778 
00779 int
00780 ListErrorModel::command(int argc, const char*const* argv)
00781 {
00782     /*
00783      * works for variable args:
00784      *  $lem droplist "1 3 4 5"
00785      * and
00786      *  $lem droplist 1 3 4 5
00787      */
00788     Tcl& tcl = Tcl::instance();
00789     if (strcmp(argv[1], "droplist") == 0) {
00790         int cnt;
00791         if ((cnt = parse_droplist(argc-2, argv + 2)) < 0)
00792             return (TCL_ERROR);
00793         tcl.resultf("%u", cnt);
00794         return(TCL_OK);
00795     }
00796     return (ErrorModel::command(argc, argv));
00797 }
00798 
00799 int
00800 ListErrorModel::intcomp(const void *p1, const void *p2)
00801 {
00802     int a = *((int*) p1);
00803     int b = *((int*) p2);
00804     return (a - b);
00805 }
00806 
00807 /*
00808  * nextval: find the next value in the string
00809  *
00810  * skip white space, update pointer to first non-white-space
00811  * character.  Return the number of characters in the next
00812  * token.
00813  */
00814 int
00815 ListErrorModel::nextval(const char*& p)
00816 {
00817     while (*p && isspace(*p))
00818         ++p;
00819 
00820     if (!*p) {
00821         /* end of string */
00822         return (0);
00823     }
00824     const char *q = p;
00825     while (*q && !isspace(*q))
00826         ++q;
00827     return (q-p);
00828 }
00829 
00830 int
00831 ListErrorModel::parse_droplist(int argc, const char *const* argv)
00832 {
00833 
00834     int cnt = 0;        // counter for argc list
00835     int spaces = 0;     // counts # of spaces in an argv entry
00836     int total = 0;      // total entries in the drop list
00837     int n;          // # of chars in the next drop number
00838     const char *p;      // ptr into current string
00839 
00840     /*
00841      * loop over argc list:  figure out how many numbers
00842      * have been specified
00843      */
00844     while (cnt < argc) {
00845         p = argv[cnt];
00846         spaces = 0;
00847         while ((n = nextval(p))) {
00848             if (!isdigit(*p)) {
00849                 /* problem... */
00850                 fprintf(stderr, "ListErrorModel(%s): parse_droplist: unknown drop specifier starting at >>>%s\n",
00851                     name(), p);
00852                 return (-1);
00853             }
00854             ++spaces;
00855             p += n;
00856         }
00857         total += spaces;
00858         cnt++;
00859     }
00860 
00861     /*
00862      * parse the numbers, put them in an array (droplist_)
00863      * set dropcnt_ to the total # of drops.  Also, free any
00864      * previous drop list.
00865      */
00866 
00867     if ((total == 0) || (dropcnt_ > 0 && droplist_ != NULL)) {
00868         delete[] droplist_;
00869         droplist_ = NULL;
00870     }
00871 
00872     if ((dropcnt_ = total) == 0)
00873         return (0);
00874 
00875     droplist_ = new int[dropcnt_];
00876     if (droplist_ == NULL) {
00877         fprintf(stderr,
00878             "ListErrorModel(%s): no memory for drop list!\n",
00879             name());
00880         return (-1);
00881     }
00882 
00883     int idx = 0;
00884     cnt = 0;
00885     while (cnt < argc) {
00886         p = argv[cnt];
00887         while ((n = nextval(p))) {
00888             /*
00889              * this depends on atoi(s) returning the
00890              * value of the first number in s
00891              */
00892             droplist_[idx++] = atoi(p);
00893             p += n;
00894         }
00895         cnt++;
00896     }
00897     qsort(droplist_, dropcnt_, sizeof(int), intcomp);
00898 
00899     /*
00900      * sanity check the array, looking for (wrong) dups
00901      */
00902     cnt = 0;
00903     while (cnt < (dropcnt_ - 1)) {
00904         if (droplist_[cnt] == droplist_[cnt+1]) {
00905             fprintf(stderr,
00906                 "ListErrorModel: error: dup %d in list\n",
00907                 droplist_[cnt]);
00908             total = -1; /* error */
00909         }
00910         ++cnt;
00911     }
00912 
00913     if (total < 0) {
00914         if (droplist_)
00915             delete[] droplist_;
00916         dropcnt_ = 0;
00917         droplist_ = NULL;
00918         return (-1);
00919     }
00920 
00921 #ifdef notdef
00922 printf("sorted list:\n");
00923 {
00924     register i;
00925     for (i =0; i < dropcnt_; i++) {
00926         printf("list[%d] = %d\n", i, droplist_[i]);
00927     }
00928 }
00929 #endif
00930     return dropcnt_;
00931 }
00932 
00933 /***** ***/
00934 
00935 static class SelectErrorModelClass : public TclClass {
00936 public:
00937     SelectErrorModelClass() : TclClass("SelectErrorModel") {}
00938     TclObject* create(int, const char*const*) {
00939         return (new SelectErrorModel);
00940     }
00941 } class_selecterrormodel;
00942 
00943 SelectErrorModel::SelectErrorModel()
00944 {
00945     bind("pkt_type_", (int*)&pkt_type_);
00946     bind("drop_cycle_", &drop_cycle_);
00947     bind("drop_offset_", &drop_offset_);
00948 }
00949 
00950 int SelectErrorModel::command(int argc, const char*const* argv)
00951 {
00952     if (strcmp(argv[1], "drop-packet") == 0) {
00953         pkt_type_ = packet_t(atoi(argv[2]));
00954         drop_cycle_ = atoi(argv[3]);
00955         drop_offset_ = atoi(argv[4]);
00956         return TCL_OK;
00957     }
00958     return ErrorModel::command(argc, argv);
00959 }
00960 
00961 int SelectErrorModel::corrupt(Packet* p)
00962 {
00963     if (unit_ == EU_PKT) {
00964         hdr_cmn *ch = hdr_cmn::access(p);
00965         // XXX Backward compatibility for cbr agents
00966         if (ch->ptype() == PT_UDP && pkt_type_ == PT_CBR)
00967             pkt_type_ = PT_UDP; // "udp" rather than "cbr"
00968         if (ch->ptype() == pkt_type_ && ch->uid() % drop_cycle_ 
00969             == drop_offset_) {
00970             //printf ("dropping packet type %d, uid %d\n", 
00971             //  ch->ptype(), ch->uid());
00972             return 1;
00973         }
00974     }
00975     return 0;
00976 }
00977 
00978 /* Error model for srm experiments */
00979 class SRMErrorModel : public SelectErrorModel {
00980 public:
00981     SRMErrorModel();
00982     virtual int corrupt(Packet*);
00983 protected:
00984     int command(int argc, const char*const* argv);
00985 };
00986 
00987 static class SRMErrorModelClass : public TclClass {
00988 public:
00989     SRMErrorModelClass() : TclClass("SRMErrorModel") {}
00990     TclObject* create(int, const char*const*) {
00991         return (new SRMErrorModel);
00992     }
00993 } class_srmerrormodel;
00994 
00995 SRMErrorModel::SRMErrorModel()
00996 {
00997 }
00998 
00999 int SRMErrorModel::command(int argc, const char*const* argv)
01000 {
01001     //int ac = 0;
01002     if (strcmp(argv[1], "drop-packet") == 0) {
01003         pkt_type_ = packet_t(atoi(argv[2]));
01004         drop_cycle_ = atoi(argv[3]);
01005         drop_offset_ = atoi(argv[4]);
01006         return TCL_OK;
01007     }
01008     return ErrorModel::command(argc, argv);
01009 }
01010 
01011 int SRMErrorModel::corrupt(Packet* p)
01012 {
01013     if (unit_ == EU_PKT) {
01014         hdr_srm *sh = hdr_srm::access(p);
01015         hdr_cmn *ch = hdr_cmn::access(p);
01016         // XXX Backward compatibility for cbr agents
01017         if (ch->ptype()==PT_UDP && pkt_type_==PT_CBR && sh->type() == SRM_DATA)
01018             pkt_type_ = PT_UDP; // "udp" rather than "cbr"
01019         if ((ch->ptype() == pkt_type_) && (sh->type() == SRM_DATA) && 
01020             (sh->seqnum() % drop_cycle_ == drop_offset_)) {
01021             //printf ("dropping packet type SRM-DATA, seqno %d\n", 
01022             //sh->seqnum());
01023             return 1;
01024         }
01025     }
01026     return 0;
01027 }
01028 
01029 
01030 static class MrouteErrorModelClass : public TclClass {
01031 public:
01032     MrouteErrorModelClass() : TclClass("ErrorModel/Trace/Mroute") {}
01033     TclObject* create(int, const char*const*) {
01034         return (new MrouteErrorModel);
01035     }
01036 } class_mrouteerrormodel;
01037  
01038 MrouteErrorModel::MrouteErrorModel() : TraceErrorModel()
01039 {
01040 }
01041 
01042 int MrouteErrorModel::command(int argc, const char*const* argv)
01043 {
01044     if (argc == 3) {
01045         if (strcmp(argv[1], "drop-packet") == 0) {
01046             const char* s = argv[2];
01047             int n = strlen(s);
01048             if (n >= this->maxtype()) {
01049                 // tcl.result("message type too big");
01050                 return (TCL_ERROR);
01051             }
01052             strcpy(msg_type,s);
01053             return(TCL_OK);
01054         }
01055     }
01056     return TraceErrorModel::command(argc, argv);
01057 }
01058 
01059 int MrouteErrorModel::match(Packet* p)
01060 {
01061     hdr_mcast_ctrl* ph = hdr_mcast_ctrl::access(p);
01062     int indx = strcspn(ph->type(),"/");
01063     if (!strncmp(ph->type(),msg_type,indx)) {
01064         return 1;
01065     }
01066     return 0;
01067 }
01068 
01069 
01070 static class ErrorModuleClass : public TclClass {
01071 public:
01072     ErrorModuleClass() : TclClass("ErrorModule") {}
01073     TclObject* create(int, const char*const*) {
01074         return (new ErrorModule);
01075     }
01076 } class_errormodule;
01077 
01078 void ErrorModule::recv(Packet *p, Handler *h)
01079 {
01080     classifier_->recv(p, h);
01081 }
01082 
01083 int ErrorModule::command(int argc, const char*const* argv)
01084 {
01085     Tcl& tcl = Tcl::instance();
01086     if (argc == 2) {
01087         if (strcmp(argv[1], "classifier") == 0) {
01088             if (classifier_)
01089                 tcl.resultf("%s", classifier_->name());
01090             else
01091                 tcl.resultf("");
01092             return (TCL_OK);
01093         }
01094     } else if (argc == 3) {
01095         if (strcmp(argv[1], "classifier") == 0) {
01096             classifier_ = (Classifier*)
01097                 TclObject::lookup(argv[2]);
01098             if (classifier_ == NULL) {
01099                 tcl.resultf("Couldn't look up classifier %s", argv[2]);
01100                 return (TCL_ERROR);
01101             }
01102             return (TCL_OK);
01103         }
01104     }
01105     return (Connector::command(argc, argv));
01106 }
01107 
01108 #include "config.h"
01109 #ifdef HAVE_STL //pgm uses STL
01110 
01111 #include "pgm/pgm.h"
01112 
01113 static class PGMErrorModelClass : public TclClass {
01114 public:
01115        PGMErrorModelClass() : TclClass("PGMErrorModel") {}
01116         TclObject* create(int, const char*const*) {
01117                 return (new PGMErrorModel);
01118         }
01119 } class_pgm_errormodel;
01120 
01121 PGMErrorModel::PGMErrorModel() : ErrorModel(), pgm_type_(-1), count_(0)
01122 {
01123         ndrops_ = 0;
01124 
01125         bind("ndrops_", &ndrops_);
01126 }
01127 
01128 int PGMErrorModel::command(int argc, const char*const* argv)
01129 {
01130         if (strcmp(argv[1], "drop-packet") == 0) {
01131         if (!strcasecmp(argv[2], "SPM")) {
01132             pgm_type_ = PGM_SPM;
01133         }
01134         else if (!strcasecmp(argv[2], "ODATA")) {
01135             pgm_type_ = PGM_ODATA;
01136         }
01137         else if (!strcasecmp(argv[2], "RDATA")) {
01138             pgm_type_ = PGM_RDATA;
01139         }
01140         else if (!strcasecmp(argv[2], "NAK")) {
01141             pgm_type_ = PGM_NAK;
01142         }
01143         else if (!strcasecmp(argv[2], "NCF")) {
01144             pgm_type_ = PGM_NCF;
01145         }
01146         else {
01147             fprintf(stderr, "PGMErrorModel: drop-packet PGM type \"%s\" unknown.\n", argv[2]);
01148             return TCL_ERROR;
01149         }
01150 
01151                 drop_cycle_ = atoi(argv[3]);
01152                 drop_offset_ = atoi(argv[4]);
01153                 return TCL_OK;
01154         }
01155         return ErrorModel::command(argc, argv);
01156 }
01157 
01158 int PGMErrorModel::corrupt(Packet* p)
01159 {
01160         if (unit_ == EU_PKT) {
01161 
01162                 hdr_cmn *ch = HDR_CMN(p);
01163                 hdr_pgm *hp = HDR_PGM(p);
01164 
01165                 if ((ch->ptype() == PT_PGM) && (hp->type_ == pgm_type_)) {
01166             count_++;
01167             if (count_ % drop_cycle_ == drop_offset_) {
01168 #ifdef PGM_DEBUG
01169                 printf ("DROPPING PGM packet type %d, seqno %d\n", pgm_type_, hp->seqno_);
01170 #endif
01171                 ++ndrops_;
01172                 return 1;
01173             }
01174         }
01175         }
01176         return 0;
01177 }
01178 
01179 #endif //HAVE_STL
01180 
01181 //
01182 // LMS Error Model
01183 //
01184 #include "rtp.h"                
01185 #include "mcast/lms.h"
01186 
01187 static class LMSErrorModelClass : public TclClass {
01188 public:
01189         LMSErrorModelClass() : TclClass("LMSErrorModel") {}
01190         TclObject* create(int, const char*const*) {
01191                 return (new LMSErrorModel);
01192         }
01193 } class_lms_errormodel;
01194  
01195  
01196 LMSErrorModel::LMSErrorModel() : ErrorModel()
01197     {
01198         ndrops_ = 0;
01199         bind("ndrops_", &ndrops_);
01200     }
01201  
01202 int LMSErrorModel::command(int argc, const char*const* argv)
01203     {
01204         if (strcmp(argv[1], "drop-packet") == 0)
01205         {
01206                 pkt_type_ = packet_t(atoi(argv[2]));
01207                 drop_cycle_ = atoi(argv[3]);
01208                 drop_offset_ = atoi(argv[4]);
01209                 return TCL_OK;
01210         }
01211         return ErrorModel::command(argc, argv);
01212     }
01213 
01214 int LMSErrorModel::corrupt(Packet* p)
01215 {
01216         if (unit_ == EU_PKT)
01217         {
01218                 hdr_cmn *ch = HDR_CMN(p);
01219                 hdr_lms *lh = HDR_LMS(p);
01220                 hdr_rtp *rh = HDR_RTP(p);
01221  
01222                 if ((ch->ptype() == pkt_type_) && (lh->type_ != LMS_DMCAST) &&
01223                     (rh->seqno() % drop_cycle_ == drop_offset_))
01224             {
01225 #ifdef LMS_DEBUG
01226 printf ("Error Model: DROPPING pkt type %d, seqno %d\n", pkt_type_, rh->seqno());
01227 #endif
01228                         ++ndrops_;
01229             return 1;
01230             }
01231             }
01232     return 0;
01233 }
01234 
01235 void TwoStateErrModelTimer::expire(Event *e) 
01236 {
01237     (*a_.*call_back_)();
01238 }
01239 

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