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
00044
00045
00046 #include <math.h>
00047 #include <sys/types.h>
00048 #include "config.h"
00049 #include "template.h"
00050 #include "random.h"
00051 #include "flags.h"
00052 #include "delay.h"
00053 #include "rem.h"
00054 #include <iostream>
00055
00056 static class REMClass : public TclClass {
00057 public:
00058 REMClass() : TclClass("Queue/REM") {}
00059 TclObject* create(int, const char*const*) {
00060 return (new REMQueue);
00061 }
00062 } class_rem;
00063
00064
00065 void REMQueue :: set_update_timer()
00066 {
00067 rem_timer_.resched(remp_.p_updtime);
00068 }
00069
00070 void REMQueue :: timeout()
00071 {
00072
00073 run_updaterule();
00074 set_update_timer();
00075 }
00076
00077
00078 void REMTimer :: expire (Event *e) {
00079 a_->timeout();
00080 }
00081
00082
00083
00084 REMQueue::REMQueue() : link_(NULL), tchan_(0), rem_timer_(this)
00085 {
00086 bind("gamma_", &remp_.p_gamma);
00087 bind("phi_", &remp_.p_phi);
00088 bind("inw_", &remp_.p_inw);
00089 bind("mean_pktsize_", &remp_.p_pktsize);
00090 bind("pupdtime_", &remp_.p_updtime);
00091 bind("pbo_", &remp_.p_bo);
00092 bind("prob_", &remv_.v_prob);
00093 bind("curq_", &curq_);
00094 bind("pmark_", &pmark_);
00095 bind_bool("markpkts_", &markpkts_);
00096 bind_bool("qib_", &qib_);
00097
00098 q_ = new PacketQueue();
00099 pq_ = q_;
00100 reset();
00101
00102 #ifdef notdef
00103 print_remp();
00104 print_remv();
00105 #endif
00106
00107 }
00108
00109 void REMQueue::reset()
00110 {
00111
00112
00113
00114
00115
00116
00117
00118
00119 if (link_)
00120 remp_.p_ptc = link_->bandwidth() / (8.0 * remp_.p_pktsize);
00121
00122 remv_.v_pl = 0.0;
00123 remv_.v_prob = 0.0;
00124 remv_.v_in = 0.0;
00125 remv_.v_ave = 0.0;
00126 remv_.v_count = 0.0;
00127
00128 remv_.v_pl1 = 0.0;
00129 remv_.v_pl2 = 0.0;
00130 remv_.v_in1 = 0.0;
00131 remv_.v_in2 = 0.0;
00132 pmark_ = 0.0;
00133 bcount_ = 0;
00134
00135
00136 set_update_timer();
00137 }
00138
00139
00140
00141
00142 void REMQueue::run_updaterule()
00143 {
00144
00145 double in, in_avg, nqueued, pl, pr;
00146
00147
00148
00149 pl = remv_.v_pl;
00150
00151
00152
00153
00154 in = remv_.v_count;
00155
00156
00157
00158
00159 in_avg = remv_.v_ave;
00160
00161 in_avg *= (1.0 - remp_.p_inw);
00162
00163 if (qib_) {
00164 in_avg += remp_.p_inw*in/remp_.p_pktsize;
00165 nqueued = bcount_/remp_.p_pktsize;
00166 }
00167 else {
00168 in_avg += remp_.p_inw*in;
00169 nqueued = q_ -> length();
00170 }
00171
00172
00173
00174
00175
00176 double c = remp_.p_updtime*remp_.p_ptc;
00177
00178 pl = pl + remp_.p_gamma*( in_avg + 0.1*(nqueued-remp_.p_bo) - c );
00179
00180 if ( pl < 0.0) {
00181 pl = 0.0;
00182 }
00183
00184 double pow1 = pow (remp_.p_phi, -pl);
00185 pr = 1.0-pow1;
00186
00187
00188 remv_.v_count = 0.0;
00189 remv_.v_ave = in_avg;
00190 remv_.v_pl = pl;
00191 remv_.v_prob = pr;
00192 }
00193
00194
00195
00196
00197
00198 Packet* REMQueue::deque()
00199 {
00200 Packet *p = q_->deque();
00201 hdr_cmn* ch;
00202 if (p != 0) {
00203 ch = hdr_cmn::access(p);
00204 bcount_ -= ch->size();
00205 }
00206 if (markpkts_) {
00207 double u = Random::uniform();
00208 if (p!=0) {
00209 double pro = remv_.v_prob;
00210 if (qib_) {
00211 pro = remv_.v_prob*ch->size()/remp_.p_pktsize;
00212 }
00213 if ( u <= pro ) {
00214 hdr_flags* hf = hdr_flags::access(p);
00215 if(hf->ect() == 1) {
00216 hf->ce() = 1;
00217 pmark_++;
00218 }
00219 }
00220 }
00221 }
00222 double qlen = qib_ ? bcount_ : q_->length();
00223 curq_ = (int) qlen;
00224 return (p);
00225 }
00226
00227
00228
00229
00230
00231
00232 void REMQueue::enque(Packet* pkt)
00233 {
00234 hdr_cmn* ch = hdr_cmn::access(pkt);
00235 double qlen;
00236
00237 if (qib_) {
00238 remv_.v_count += ch->size();
00239 }
00240 else {
00241 ++remv_.v_count;
00242 }
00243
00244 double qlim = qib_ ? (qlim_*remp_.p_pktsize) : qlim_ ;
00245
00246 q_ -> enque(pkt);
00247 bcount_ += ch->size();
00248
00249 qlen = qib_ ? bcount_ : q_->length();
00250
00251 if (qlen >= qlim) {
00252 q_->remove(pkt);
00253 bcount_ -= ch->size();
00254 drop(pkt);
00255 }
00256 else {
00257 if (!markpkts_) {
00258 double u = Random::uniform();
00259 double pro = remv_.v_prob;
00260 if (qib_) {
00261 pro = remv_.v_prob*ch->size()/remp_.p_pktsize;
00262 }
00263 if ( u <= pro ) {
00264 q_->remove(pkt);
00265 bcount_ -= ch->size();
00266 drop(pkt);
00267 }
00268 }
00269 }
00270 qlen = qib_ ? bcount_ : q_->length();
00271 curq_ = (int) qlen;
00272 }
00273
00274
00275 int REMQueue::command(int argc, const char*const* argv)
00276 {
00277
00278 Tcl& tcl = Tcl::instance();
00279 if (argc == 2) {
00280 if (strcmp(argv[1], "reset") == 0) {
00281 reset();
00282 return (TCL_OK);
00283 }
00284 } else if (argc == 3) {
00285
00286 if (strcmp(argv[1], "attach") == 0) {
00287 int mode;
00288 const char* id = argv[2];
00289 tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00290 if (tchan_ == 0) {
00291 tcl.resultf("REM: trace: can't attach %s for writing", id);
00292 return (TCL_ERROR);
00293 }
00294 return (TCL_OK);
00295 }
00296
00297 if (strcmp(argv[1], "link") == 0) {
00298 LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
00299 if (del == 0) {
00300 tcl.resultf("REM: no LinkDelay object %s",
00301 argv[2]);
00302 return(TCL_ERROR);
00303 }
00304
00305 link_ = del;
00306 remp_.p_ptc = link_->bandwidth() /
00307 (8. * remp_.p_pktsize);
00308
00309 return (TCL_OK);
00310 }
00311 if (!strcmp(argv[1], "packetqueue-attach")) {
00312 delete q_;
00313 if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
00314 return (TCL_ERROR);
00315 else {
00316 pq_ = q_;
00317 return (TCL_OK);
00318 }
00319 }
00320 }
00321 return (Queue::command(argc, argv));
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331 void
00332 REMQueue::trace(TracedVar* v)
00333 {
00334 char wrk[500], *p;
00335
00336 if (((p = strstr(v->name(), "ave")) == NULL) &&
00337 ((p = strstr(v->name(), "prob")) == NULL) &&
00338 ((p = strstr(v->name(), "curq")) == NULL)) {
00339 fprintf(stderr, "REM:unknown trace var %s\n",
00340 v->name());
00341 return;
00342 }
00343
00344 if (tchan_) {
00345 int n;
00346 double t = Scheduler::instance().clock();
00347 if (*p == 'c') {
00348 sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
00349 } else {
00350 sprintf(wrk, "%c %g %g", *p, t,
00351 double(*((TracedDouble*) v)));
00352 }
00353 n = strlen(wrk);
00354 wrk[n] = '\n';
00355 wrk[n+1] = 0;
00356 (void)Tcl_Write(tchan_, wrk, n+1);
00357 }
00358 return;
00359 }
00360
00361
00362 void REMQueue::print_remp()
00363 {
00364 printf("=========\n");
00365 }
00366
00367 void REMQueue::print_remv()
00368 {
00369 printf("=========\n");
00370 }