00001 /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ 00002 /* 00003 * Copyright (c) Xerox Corporation 1997. All rights reserved. 00004 * 00005 * This program is free software; you can redistribute it and/or modify it 00006 * under the terms of the GNU General Public License as published by the 00007 * Free Software Foundation; either version 2 of the License, or (at your 00008 * option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, but 00011 * WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along 00016 * with this program; if not, write to the Free Software Foundation, Inc., 00017 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 * 00019 * Linking this file statically or dynamically with other modules is making 00020 * a combined work based on this file. Thus, the terms and conditions of 00021 * the GNU General Public License cover the whole combination. 00022 * 00023 * In addition, as a special exception, the copyright holders of this file 00024 * give you permission to combine this file with free software programs or 00025 * libraries that are released under the GNU LGPL and with code included in 00026 * the standard release of ns-2 under the Apache 2.0 license or under 00027 * otherwise-compatible licenses with advertising requirements (or modified 00028 * versions of such code, with unchanged license). You may copy and 00029 * distribute such a system following the terms of the GNU GPL for this 00030 * file and the licenses of the other code concerned, provided that you 00031 * include the source code of that other code when and as the GNU GPL 00032 * requires distribution of source code. 00033 * 00034 * Note that people who make modified versions of this file are not 00035 * obligated to grant this special exception for their modified versions; 00036 * it is their choice whether to do so. The GNU General Public License 00037 * gives permission to release a modified version without this exception; 00038 * this exception also makes it possible to release a modified version 00039 * which carries forward this exception. 00040 */ 00041 00042 /* Token Bucket filter which has 3 parameters : 00043 a. Token Generation rate 00044 b. Token bucket depth 00045 c. Max. Queue Length (a finite length would allow this to be used as policer as packets are dropped after queue gets full) 00046 */ 00047 00048 #include "connector.h" 00049 #include "packet.h" 00050 #include "queue.h" 00051 #include "tbf.h" 00052 00053 TBF::TBF() :tokens_(0),tbf_timer_(this), init_(1) 00054 { 00055 q_=new PacketQueue(); 00056 bind_bw("rate_",&rate_); 00057 bind("bucket_",&bucket_); 00058 bind("qlen_",&qlen_); 00059 } 00060 00061 TBF::~TBF() 00062 { 00063 if (q_->length() != 0) { 00064 //Clear all pending timers 00065 tbf_timer_.cancel(); 00066 //Free up the packetqueue 00067 for (Packet *p=q_->head();p!=0;p=p->next_) 00068 Packet::free(p); 00069 } 00070 delete q_; 00071 } 00072 00073 00074 void TBF::recv(Packet *p, Handler *) 00075 { 00076 //start with a full bucket 00077 if (init_) { 00078 tokens_=bucket_; 00079 lastupdatetime_ = Scheduler::instance().clock(); 00080 init_=0; 00081 } 00082 00083 00084 hdr_cmn *ch=hdr_cmn::access(p); 00085 00086 //enque packets appropriately if a non-zero q already exists 00087 if (q_->length() !=0) { 00088 if (q_->length() < qlen_) { 00089 q_->enque(p); 00090 return; 00091 } 00092 00093 drop(p); 00094 return; 00095 } 00096 00097 double tok; 00098 tok = getupdatedtokens(); 00099 00100 int pktsize = ch->size()<<3; 00101 if (tokens_ >=pktsize) { 00102 target_->recv(p); 00103 tokens_-=pktsize; 00104 } 00105 else { 00106 00107 if (qlen_!=0) { 00108 q_->enque(p); 00109 tbf_timer_.resched((pktsize-tokens_)/rate_); 00110 } 00111 else { 00112 drop(p); 00113 } 00114 } 00115 } 00116 00117 double TBF::getupdatedtokens(void) 00118 { 00119 double now=Scheduler::instance().clock(); 00120 00121 tokens_ += (now-lastupdatetime_)*rate_; 00122 if (tokens_ > bucket_) 00123 tokens_=bucket_; 00124 lastupdatetime_ = Scheduler::instance().clock(); 00125 return tokens_; 00126 } 00127 00128 void TBF::timeout(int) 00129 { 00130 if (q_->length() == 0) { 00131 fprintf (stderr,"ERROR in tbf\n"); 00132 abort(); 00133 } 00134 00135 Packet *p=q_->deque(); 00136 double tok; 00137 tok = getupdatedtokens(); 00138 hdr_cmn *ch=hdr_cmn::access(p); 00139 int pktsize = ch->size()<<3; 00140 00141 //We simply send the packet here without checking if we have enough tokens 00142 //because the timer is supposed to fire at the right time 00143 target_->recv(p); 00144 tokens_-=pktsize; 00145 00146 if (q_->length() !=0 ) { 00147 p=q_->head(); 00148 hdr_cmn *ch=hdr_cmn::access(p); 00149 pktsize = ch->size()<<3; 00150 tbf_timer_.resched((pktsize-tokens_)/rate_); 00151 } 00152 } 00153 00154 void TBF_Timer::expire(Event* /*e*/) 00155 { 00156 tbf_->timeout(0); 00157 } 00158 00159 00160 static class TBFClass : public TclClass { 00161 public: 00162 TBFClass() : TclClass ("TBF") {} 00163 TclObject* create(int,const char*const*) { 00164 return (new TBF()); 00165 } 00166 }class_tbf;
1.4.6