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 * License is granted to copy, to use, and to make and to use derivative 00006 * works for research and evaluation purposes, provided that Xerox is 00007 * acknowledged in all documentation pertaining to any such copy or 00008 * derivative work. Xerox grants no other licenses expressed or 00009 * implied. The Xerox trade name should not be used in any advertising 00010 * without its written permission. 00011 * 00012 * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE 00013 * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE 00014 * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without 00015 * express or implied warranty of any kind. 00016 * 00017 * These notices must be retained in any copies of any part of this 00018 * software. 00019 */ 00020 00021 /* Token Bucket filter which has 3 parameters : 00022 a. Token Generation rate 00023 b. Token bucket depth 00024 c. Max. Queue Length (a finite length would allow this to be used as policer as packets are dropped after queue gets full) 00025 */ 00026 00027 #include "connector.h" 00028 #include "packet.h" 00029 #include "queue.h" 00030 #include "tbf.h" 00031 00032 TBF::TBF() :tokens_(0),tbf_timer_(this), init_(1) 00033 { 00034 q_=new PacketQueue(); 00035 bind_bw("rate_",&rate_); 00036 bind("bucket_",&bucket_); 00037 bind("qlen_",&qlen_); 00038 } 00039 00040 TBF::~TBF() 00041 { 00042 if (q_->length() != 0) { 00043 //Clear all pending timers 00044 tbf_timer_.cancel(); 00045 //Free up the packetqueue 00046 for (Packet *p=q_->head();p!=0;p=p->next_) 00047 Packet::free(p); 00048 } 00049 delete q_; 00050 } 00051 00052 00053 void TBF::recv(Packet *p, Handler *) 00054 { 00055 //start with a full bucket 00056 if (init_) { 00057 tokens_=bucket_; 00058 lastupdatetime_ = Scheduler::instance().clock(); 00059 init_=0; 00060 } 00061 00062 00063 hdr_cmn *ch=hdr_cmn::access(p); 00064 00065 //enque packets appropriately if a non-zero q already exists 00066 if (q_->length() !=0) { 00067 if (q_->length() < qlen_) { 00068 q_->enque(p); 00069 return; 00070 } 00071 00072 drop(p); 00073 return; 00074 } 00075 00076 double tok; 00077 tok = getupdatedtokens(); 00078 00079 int pktsize = ch->size()<<3; 00080 if (tokens_ >=pktsize) { 00081 target_->recv(p); 00082 tokens_-=pktsize; 00083 } 00084 else { 00085 00086 if (qlen_!=0) { 00087 q_->enque(p); 00088 tbf_timer_.resched((pktsize-tokens_)/rate_); 00089 } 00090 else { 00091 drop(p); 00092 } 00093 } 00094 } 00095 00096 double TBF::getupdatedtokens(void) 00097 { 00098 double now=Scheduler::instance().clock(); 00099 00100 tokens_ += (now-lastupdatetime_)*rate_; 00101 if (tokens_ > bucket_) 00102 tokens_=bucket_; 00103 lastupdatetime_ = Scheduler::instance().clock(); 00104 return tokens_; 00105 } 00106 00107 void TBF::timeout(int) 00108 { 00109 if (q_->length() == 0) { 00110 fprintf (stderr,"ERROR in tbf\n"); 00111 abort(); 00112 } 00113 00114 Packet *p=q_->deque(); 00115 double tok; 00116 tok = getupdatedtokens(); 00117 hdr_cmn *ch=hdr_cmn::access(p); 00118 int pktsize = ch->size()<<3; 00119 00120 //We simply send the packet here without checking if we have enough tokens 00121 //because the timer is supposed to fire at the right time 00122 target_->recv(p); 00123 tokens_-=pktsize; 00124 00125 if (q_->length() !=0 ) { 00126 p=q_->head(); 00127 hdr_cmn *ch=hdr_cmn::access(p); 00128 pktsize = ch->size()<<3; 00129 tbf_timer_.resched((pktsize-tokens_)/rate_); 00130 } 00131 } 00132 00133 void TBF_Timer::expire(Event* /*e*/) 00134 { 00135 tbf_->timeout(0); 00136 } 00137 00138 00139 static class TBFClass : public TclClass { 00140 public: 00141 TBFClass() : TclClass ("TBF") {} 00142 TclObject* create(int,const char*const*) { 00143 return (new TBF()); 00144 } 00145 }class_tbf;
1.3.3