00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
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"
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_);
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
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
00176
00177
00178
00179
00180 hdr_cmn* ch = hdr_cmn::access(p);
00181 int error = corrupt(p);
00182
00183
00184
00185 if (!markecn_ && !delay_pkt_ && (h && ((error && drop_) || !target_))) {
00186
00187 double delay = Random::uniform(8.0 * ch->size() / bandwidth_);
00188 if (intr_.uid_ <= 0 )
00189
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
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
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
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
00261 for (i = 0; i < FECstrength_ ; i++)
00262 dptr[i + 1] += dptr[i];
00263
00264 dptr[FECstrength_ + 1] = 1.0;
00265
00266
00267
00268
00269
00270 return dptr;
00271
00272 }
00273
00274 int ErrorModel::CorruptPkt(Packet*)
00275 {
00276
00277 double u = ranvar_ ? ranvar_->value() : Random::uniform();
00278 return (u < rate_);
00279 }
00280
00281 int ErrorModel::CorruptByte(Packet* p)
00282 {
00283
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
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
00318
00319
00320
00321
00322
00323
00324 int ErrorModel::CorruptTime(Packet *p)
00325 {
00326
00327
00328
00329
00330
00331
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) {
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()),
00361 this,
00362 eventtype
00363 );
00364
00365 if (nwrk != 0)
00366 sprintf(nwrk,
00367 "E -t "TIME_FORMAT" ErrModelTimer %p %s",
00368 et_->round(Scheduler::instance().clock()),
00369 this,
00370 eventtype
00371 );
00372 et_->trace();
00373 }
00374
00375
00376
00377
00378
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
00419 error = state_ && (remainLen_ > ZERO);
00420 remainLen_ -= PktLength(p);
00421
00422
00423 while (remainLen_ <= ZERO) {
00424 state_ ^= 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
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
00555
00556
00557
00558
00559
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
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
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
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
00732
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
00745 int rval = 0;
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
00760
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
00784
00785
00786
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
00809
00810
00811
00812
00813
00814 int
00815 ListErrorModel::nextval(const char*& p)
00816 {
00817 while (*p && isspace(*p))
00818 ++p;
00819
00820 if (!*p) {
00821
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;
00835 int spaces = 0;
00836 int total = 0;
00837 int n;
00838 const char *p;
00839
00840
00841
00842
00843
00844 while (cnt < argc) {
00845 p = argv[cnt];
00846 spaces = 0;
00847 while ((n = nextval(p))) {
00848 if (!isdigit(*p)) {
00849
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
00863
00864
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
00890
00891
00892 droplist_[idx++] = atoi(p);
00893 p += n;
00894 }
00895 cnt++;
00896 }
00897 qsort(droplist_, dropcnt_, sizeof(int), intcomp);
00898
00899
00900
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;
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
00966 if (ch->ptype() == PT_UDP && pkt_type_ == PT_CBR)
00967 pkt_type_ = PT_UDP;
00968 if (ch->ptype() == pkt_type_ && ch->uid() % drop_cycle_
00969 == drop_offset_) {
00970
00971
00972 return 1;
00973 }
00974 }
00975 return 0;
00976 }
00977
00978
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
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
01017 if (ch->ptype()==PT_UDP && pkt_type_==PT_CBR && sh->type() == SRM_DATA)
01018 pkt_type_ = PT_UDP;
01019 if ((ch->ptype() == pkt_type_) && (sh->type() == SRM_DATA) &&
01020 (sh->seqnum() % drop_cycle_ == drop_offset_)) {
01021
01022
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
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
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