📄 red.cpp
字号:
int victim; if (drop_front_) victim = min(1, q_->length()-1); else if (drop_rand_) victim = Random::integer(q_->length()); else /* default is drop_tail_ */ victim = q_->length() - 1; return(q_->lookup(victim)); }/* * Receive a new packet arriving at the queue. * The average queue size is computed. If the average size * exceeds the threshold, then the dropping probability is computed, * and the newly-arriving packet is dropped with that probability. * The packet is also dropped if the maximum queue size is exceeded. * * "Forced" drops mean a packet arrived when the underlying queue was * full or when the average q size exceeded maxthresh. * "Unforced" means a RED random drop. * * For forced drops, either the arriving packet is dropped or one in the * queue is dropped, depending on the setting of drop_tail_. * For unforced drops, the arriving packet is always the victim. */#define DTYPE_NONE 0 /* ok, no drop */#define DTYPE_FORCED 1 /* a "forced" drop */#define DTYPE_UNFORCED 2 /* an "unforced" (random) drop */void REDQueue::enque(Packet* pkt){ /* * if we were idle, we pretend that m packets arrived during * the idle period. m is set to be the ptc times the amount * of time we've been idle for */ int m = 0; if (idle_) { //add //初始化令牌桶 tokens_=bucket_; lastupdatetime_ = Scheduler::instance().clock(); //add over // A packet that arrives to an idle queue will never // be dropped. double now = Scheduler::instance().clock(); /* To account for the period when the queue was empty. */ idle_ = 0; m = int(edp_.ptc * (now - idletime_)); } /* * Run the estimator with either 1 new packet arrival, or with * the scaled version above [scaled by m due to idle time] * (bcount_ maintains the byte count in the underlying queue). * If the underlying queue is able to delete packets without * us knowing, then bcount_ will not be maintained properly! */ edv_.v_ave = estimator(qib_ ? bcount_ : q_->length(), m + 1, edv_.v_ave, edp_.q_w); //printf("v_ave: %6.4f (%13.12f) q: %d)\n", // double(edv_.v_ave), double(edv_.v_ave), q_->length()); //run_estimator(qib_ ? bcount_ : q_->length(), m + 1); /* * count and count_bytes keeps a tally of arriving traffic * that has not been dropped (i.e. how long, in terms of traffic, * it has been since the last early drop) */ hdr_cmn* ch = hdr_cmn::access(pkt); //进行令牌计数 double tok; tok = getupdatedtokens(); int pktsize = ch->size(); if (tokens_ >=pktsize) { cou_grn ++; } else { cou_red ++; }; if (cou_red = 0) { para_modi = 0 ; reset_cou(); } else { if (cou_grn=1) { para_modi = 1- 1/cou_red; reset_cou(); } } //计数结束 ++edv_.count; edv_.count_bytes += ch->size(); /* * DROP LOGIC: * q = current q size, ~q = averaged q size * 1> if ~q > maxthresh, this is a FORCED drop * 2> if minthresh < ~q < maxthresh, this may be an UNFORCED drop * 3> if (q+1) > hard q limit, this is a FORCED drop */ register double qavg = edv_.v_ave; int droptype = DTYPE_NONE; int qlen = qib_ ? bcount_ : q_->length(); int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_; curq_ = qlen; // helps to trace queue during arrival, if enabled if (qavg >= edp_.th_min && qlen > 1) { if ((!edp_.gentle && qavg >= edp_.th_max) || (edp_.gentle && qavg >= 2 * edp_.th_max)) { droptype = DTYPE_FORCED; } else if (edv_.old == 0) { /* * The average queue size has just crossed the * threshold from below to above "minthresh", or * from above "minthresh" with an empty queue to * above "minthresh" with a nonempty queue. */ edv_.count = 1; edv_.count_bytes = ch->size(); edv_.old = 1; } else if (drop_early(pkt)) { droptype = DTYPE_UNFORCED; } } else { /* No packets are being dropped. */ edv_.v_prob = 0.0; edv_.old = 0; } if (qlen >= qlim) { // see if we've exceeded the queue size droptype = DTYPE_FORCED; } if (droptype == DTYPE_UNFORCED) { /* pick packet for ECN, which is dropping in this case */ Packet *pkt_to_drop = pickPacketForECN(pkt); /* * If the packet picked is different that the one that just arrived, * add it to the queue and remove the chosen packet. */ if (pkt_to_drop != pkt) { q_->enque(pkt); bcount_ += ch->size(); q_->remove(pkt_to_drop); bcount_ -= hdr_cmn::access(pkt_to_drop)->size(); pkt = pkt_to_drop; /* XXX okay because pkt is not needed anymore */ } // deliver to special "edrop" target, if defined if (de_drop_ != NULL) { //trace first if asked // if no snoop object (de_drop_) is defined, // this packet will not be traced as a special case. if (EDTrace != NULL) ((Trace *)EDTrace)->recvOnly(pkt); reportDrop(pkt); de_drop_->recv(pkt); } else { reportDrop(pkt); drop(pkt); } } else { /* forced drop, or not a drop: first enqueue pkt */ q_->enque(pkt); bcount_ += ch->size(); /* drop a packet if we were told to */ if (droptype == DTYPE_FORCED) { /* drop random victim or last one */ pkt = pickPacketToDrop(); q_->remove(pkt); bcount_ -= hdr_cmn::access(pkt)->size(); reportDrop(pkt); drop(pkt); if (!ns1_compat_) { // bug-fix from Philip Liu, <phill@ece.ubc.ca> edv_.count = 0; edv_.count_bytes = 0; } } } return;}int REDQueue::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "reset") == 0) { reset(); return (TCL_OK); } if (strcmp(argv[1], "early-drop-target") == 0) { if (de_drop_ != NULL) tcl.resultf("%s", de_drop_->name()); return (TCL_OK); } if (strcmp(argv[1], "edrop-trace") == 0) { if (EDTrace != NULL) { tcl.resultf("%s", EDTrace->name()); if (debug_) printf("edrop trace exists according to RED\n"); } else { if (debug_) printf("edrop trace doesn't exist according to RED\n"); tcl.resultf("0"); } return (TCL_OK); } if (strcmp(argv[1], "trace-type") == 0) { tcl.resultf("%s", traceType); return (TCL_OK); } } else if (argc == 3) { // attach a file for variable tracing if (strcmp(argv[1], "attach") == 0) { int mode; const char* id = argv[2]; tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); if (tchan_ == 0) { tcl.resultf("RED: trace: can't attach %s for writing", id); return (TCL_ERROR); } return (TCL_OK); } // tell RED about link stats if (strcmp(argv[1], "link") == 0) { LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]); if (del == 0) { tcl.resultf("RED: no LinkDelay object %s", argv[2]); return(TCL_ERROR); } // set ptc now link_ = del; edp_.ptc = link_->bandwidth() / (8. * edp_.mean_pktsize); return (TCL_OK); } if (strcmp(argv[1], "early-drop-target") == 0) { NsObject* p = (NsObject*)TclObject::lookup(argv[2]); if (p == 0) { tcl.resultf("no object %s", argv[2]); return (TCL_ERROR); } de_drop_ = p; return (TCL_OK); } if (strcmp(argv[1], "edrop-trace") == 0) { if (debug_) printf("Ok, Here\n"); NsObject * t = (NsObject *)TclObject::lookup(argv[2]); if (debug_) printf("Ok, Here too\n"); if (t == 0) { tcl.resultf("no object %s", argv[2]); return (TCL_ERROR); } EDTrace = t; if (debug_) printf("Ok, Here too too too %d\n", ((Trace *)EDTrace)->type_); return (TCL_OK); } if (!strcmp(argv[1], "packetqueue-attach")) { delete q_; if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2]))) return (TCL_ERROR); else { pq_ = q_; return (TCL_OK); } } } return (Queue::command(argc, argv));}/* * Routine called by TracedVar facility when variables change values. * Currently used to trace values of avg queue size, drop probability, * and the instantaneous queue size seen by arriving packets. * Note that the tracing of each var must be enabled in tcl to work. */voidREDQueue::trace(TracedVar* v){ char wrk[500], *p; if (((p = strstr(v->name(), "ave")) == NULL) && ((p = strstr(v->name(), "prob")) == NULL) && ((p = strstr(v->name(), "curq")) == NULL)) { fprintf(stderr, "RED:unknown trace var %s\n", v->name()); return; } if (tchan_) { int n; double t = Scheduler::instance().clock(); // XXX: be compatible with nsv1 RED trace entries if (*p == 'c') { sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v))); } else { sprintf(wrk, "%c %g %g", *p, t, double(*((TracedDouble*) v))); } n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; (void)Tcl_Write(tchan_, wrk, n+1); } return; }/* for debugging help */void REDQueue::print_edp(){ printf("mean_pktsz: %d\n", edp_.mean_pktsize); printf("bytes: %d, wait: %d, setbit: %d\n", edp_.bytes, edp_.wait, edp_.setbit); printf("minth: %f, maxth: %f\n", edp_.th_min, edp_.th_max); printf("max_p_inv: %f, qw: %f, ptc: %f\n", edp_.max_p_inv, edp_.q_w, edp_.ptc); printf("qlim: %d, idletime: %f\n", qlim_, idletime_); printf("=========\n");}void REDQueue::print_edv(){ printf("v_a: %f, v_b: %f\n", edv_.v_a, edv_.v_b);}/************************************************************//* * This procedure is obsolete, and only included for backward compatibility. * The new procedure is REDQueue::estimator */ /* * Compute the average queue size. * The code contains two alternate methods for this, the plain EWMA * and the Holt-Winters method. * nqueued can be bytes or packets */void REDQueue::run_estimator(int nqueued, int m){ double f, f_sl, f_old; f = edv_.v_ave; f_sl = edv_.v_slope;#define RED_EWMA#ifdef RED_EWMA while (--m >= 1) { f_old = f; f *= 1.0 - edp_.q_w; } f_old = f; f *= 1.0 - edp_.q_w; f += edp_.q_w * nqueued;#endif#ifdef RED_HOLT_WINTERS while (--m >= 1) { f_old = f; f += f_sl; f *= 1.0 - edp_.q_w; f_sl *= 1.0 - 0.5 * edp_.q_w; f_sl += 0.5 * edp_.q_w * (f - f_old); } f_old = f; f += f_sl; f *= 1.0 - edp_.q_w; f += edp_.q_w * nqueued; f_sl *= 1.0 - 0.5 * edp_.q_w; f_sl += 0.5 * edp_.q_w * (f - f_old);#endif edv_.v_ave = f; edv_.v_slope = f_sl;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -