📄 red.cpp
字号:
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- *//* * Copyright (c) 1990-1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Here is one set of parameters from one of Sally's simulations * (this is from tcpsim, the older simulator): * * ed [ q_weight=0.002 thresh=5 linterm=30 maxthresh=15 * mean_pktsize=500 dropmech=random-drop queue-size=60 * plot-file=none bytes=false doubleq=false dqthresh=50 * wait=true ] * * 1/"linterm" is the max probability of dropping a packet. * There are different options that make the code * more messy that it would otherwise be. For example, * "doubleq" and "dqthresh" are for a queue that gives priority to * small (control) packets, * "bytes" indicates whether the queue should be measured in bytes * or in packets, * "dropmech" indicates whether the drop function should be random-drop * or drop-tail when/if the queue overflows, and * the commented-out Holt-Winters method for computing the average queue * size can be ignored. * "wait" indicates whether the gateway should wait between dropping * packets. */#ifndef lintstatic const char rcsid[] = "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/red.cc,v 1.55 2000/11/17 22:10:33 ratul Exp $ (LBL)";#endif#include <math.h>#include <sys/types.h>#include "config.h"#include "template.h"#include "random.h"#include "flags.h"#include "delay.h"#include "red.h"#include "connector.h" //add header #include "packet.h"#include "tbf.h"static class REDClass : public TclClass {public: REDClass() : TclClass("Queue/RED") {} TclObject* create(int argc, const char*const* argv) { //printf("creating RED Queue. argc = %d\n", argc); //mod to enable RED to take arguments if (argc==5) return (new REDQueue(argv[4])); else return (new REDQueue("Drop")); }} class_red;/* Strangely this didn't work. * Seg faulted for child classes.REDQueue::REDQueue() { REDQueue("Drop");}*//* * modified to enable instantiation with special Trace objects - ratul */REDQueue::REDQueue(const char * trace) : link_(NULL), bcount_(0), de_drop_(NULL), EDTrace(NULL), tchan_(0), idle_(1), first_reset_(1){ // printf("Making trace type %s\n", trace); if (strlen(trace) >=20) { printf("trace type too long - allocate more space to traceType in red.h and recompile\n"); exit(0); } strcpy(traceType, trace); bind_bool("bytes_", &edp_.bytes); // boolean: use bytes? bind_bool("queue_in_bytes_", &qib_); // boolean: q in bytes? // _RENAMED("queue-in-bytes_", "queue_in_bytes_"); bind("thresh_", &edp_.th_min); // minthresh bind("maxthresh_", &edp_.th_max); // maxthresh bind("mean_pktsize_", &edp_.mean_pktsize); // avg pkt size bind("q_weight_", &edp_.q_w); // for EWMA bind_bool("wait_", &edp_.wait); bind("linterm_", &edp_.max_p_inv); bind_bool("setbit_", &edp_.setbit); // mark instead of drop bind_bool("gentle_", &edp_.gentle); // increase the packet // drop prob. slowly // when ave queue // exceeds maxthresh bind_bool("drop_tail_", &drop_tail_); // drop last pkt // _RENAMED("drop-tail_", "drop_tail_"); bind_bool("drop_front_", &drop_front_); // drop first pkt // _RENAMED("drop-front_", "drop_front_"); bind_bool("drop_rand_", &drop_rand_); // drop pkt at random // _RENAMED("drop-rand_", "drop_rand_"); bind_bool("ns1_compat_", &ns1_compat_); // ns-1 compatibility // _RENAMED("ns1-compat_", "ns1_compat_"); bind("ave_", &edv_.v_ave); // average queue sie bind("prob1_", &edv_.v_prob1); // dropping probability bind("curq_", &curq_); // current queue size q_ = new PacketQueue(); // underlying queue pq_ = q_; reset();#ifdef notdef print_edp(); print_edv();#endif }void REDQueue::reset(){ /* * If queue is measured in bytes, scale min/max thresh * by the size of an average packet (which is specified by user). */ if (qib_ && first_reset_ == 1) { //printf ("edp_.th_min: %5.3f \n", edp_.th_min); edp_.th_min *= edp_.mean_pktsize; edp_.th_max *= edp_.mean_pktsize; //printf ("edp_.th_min: %5.3f \n", edp_.th_min); first_reset_ = 0; } /* * Compute the "packet time constant" if we know the * link bandwidth. The ptc is the max number of (avg sized) * pkts per second which can be placed on the link. * The link bw is given in bits/sec, so scale mean psize * accordingly. */ if (link_) edp_.ptc = link_->bandwidth() / (8. * edp_.mean_pktsize); edv_.v_ave = 0.0; edv_.v_slope = 0.0; edv_.count = 0; edv_.count_bytes = 0; edv_.old = 0; edv_.v_a = 1 / (edp_.th_max - edp_.th_min); edv_.v_b = - edp_.th_min / (edp_.th_max - edp_.th_min); if (edp_.gentle) { edv_.v_c = ( 1.0 - 1 / edp_.max_p_inv ) / edp_.th_max; edv_.v_d = 2 / edp_.max_p_inv - 1.0; } idle_ = 1; if (&Scheduler::instance() != NULL) idletime_ = Scheduler::instance().clock(); else idletime_ = 0.0; /* sched not instantiated yet */ if (debug_) printf("Doing a queue reset\n"); Queue::reset(); if (debug_) printf("Done queue reset\n"); bcount_ = 0;}/* * Compute the average queue size. * Nqueued can be bytes or packets. */double REDQueue::estimator(int nqueued, int m, double ave, double q_w){ double new_ave, old_ave; new_ave = ave; while (--m >= 1) { old_ave = new_ave; new_ave *= 1.0 - q_w; } old_ave = new_ave; new_ave *= 1.0 - q_w; new_ave += q_w * nqueued; return new_ave;}void REDQueue::reset_cou(){ cou_grn = 0; cou_red = 0;}/* * Return the next packet in the queue for transmission. */Packet* REDQueue::deque(){ Packet *p; p = q_->deque(); if (p != 0) { idle_ = 0; bcount_ -= hdr_cmn::access(p)->size(); } else { idle_ = 1; // deque() may invoked by Queue::reset at init // time (before the scheduler is instantiated). // deal with this case if (&Scheduler::instance() != NULL) idletime_ = Scheduler::instance().clock(); else idletime_ = 0.0; } return (p);}//modify discard cursor positon double REDQueue::calculate_pos(double th_max, double th_min, double para_modi) { double position; position = th_max - para_modi*(th_max - th_min); return position ; }///* * Calculate the drop probability.*/doubleREDQueue::calculate_p(double v_ave, double th_max, int gentle, double v_a, double v_b, double v_c, double v_d, double max_p_inv){ double p; if (gentle && v_ave >= th_max) { // p ranges from max_p to 1 as the average queue // size ranges from th_max to twice th_max p = v_c * v_ave + v_d; } else { // p ranges from 0 to max_p as the average queue // size ranges from th_min to th_max p = v_a * v_ave + v_b; p /= max_p_inv; } if (p > 1.0) p = 1.0; return p;} // Make uniform instead of geometric interdrop periods.doubleREDQueue::modify_p(double p, int count, int count_bytes, int bytes, int mean_pktsize, int wait, int size){ double count1 = (double) count; if (bytes) count1 = (double) (count_bytes/mean_pktsize); if (wait) { if (count1 * p < 1.0) p = 0.0; else if (count1 * p < 2.0) p /= (2 - count1 * p); else p = 1.0; } else { if (count1 * p < 1.0) p /= (1.0 - count1 * p); else p = 1.0; } if (bytes && p < 1.0) { p = p * size / mean_pktsize; } if (p > 1.0) p = 1.0; return p;} /* * should the packet be dropped/marked due to a probabilistic drop? */intREDQueue::drop_early(Packet* pkt){ hdr_cmn* ch = hdr_cmn::access(pkt); /* edv_.v_prob1 = calculate_p(edv_.v_ave, edp_.th_max, edp_.gentle, edv_.v_a, edv_.v_b, edv_.v_c, edv_.v_d, edp_.max_p_inv); edv_.v_prob = modify_p(edv_.v_prob1, edv_.count, edv_.count_bytes, edp_.bytes, edp_.mean_pktsize, edp_.wait, ch->size()); */ pos_dis = calculate_pos(edp_.th_max, edp_.th_min, para_modi); if (pos_dis < edv_.v_ave) { edv_.count = 0; edv_.count_bytes = 0; hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt)); if (edp_.setbit && hf->ect() && edv_.v_ave < edp_.th_max) { hf->ce() = 1; // mark Congestion Experienced bit return (0); // no drop } else { return (1); // drop } } return (0); // no DROP/mark} // drop probability is computed, pick random number and act /*double u = Random::uniform(); if (u <= edv_.v_prob) { // DROP or MARK edv_.count = 0; edv_.count_bytes = 0; hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt)); if (edp_.setbit && hf->ect() && edv_.v_ave < edp_.th_max) { hf->ce() = 1; // mark Congestion Experienced bit return (0); // no drop } else { return (1); // drop } } return (0); // no DROP/mark}*/double REDQueue::getupdatedtokens(void){ double now=Scheduler::instance().clock(); tokens_ += (now-lastupdatetime_)*rate_; if (tokens_ > bucket_) tokens_=bucket_; lastupdatetime_ = Scheduler::instance().clock(); return tokens_;}/* * Pick packet for early congestion notification (ECN). This packet is then * marked or dropped. Having a separate function do this is convenient for * supporting derived classes that use the standard RED algorithm to compute * average queue size but use a different algorithm for choosing the packet for * ECN notification. */Packet*REDQueue::pickPacketForECN(Packet* pkt){ return pkt; /* pick the packet that just arrived */}/* * Pick packet to drop. Having a separate function do this is convenient for * supporting derived classes that use the standard RED algorithm to compute * average queue size but use a different algorithm for choosing the victim. */Packet*REDQueue::pickPacketToDrop() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -