Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

rate-limit-strategy.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 2000  International Computer Science Institute
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by ACIRI, the AT&T 
00017  *      Center for Internet Research at ICSI (the International Computer
00018  *      Science Institute).
00019  * 4. Neither the name of ACIRI nor of ICSI may be used
00020  *    to endorse or promote products derived from this software without
00021  *    specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  *
00035  */
00036 
00037 #include "rate-limit-strategy.h"
00038 
00039 RateLimitStrategy::RateLimitStrategy(double rate, int ptype, double share, double estimate) {
00040   
00041   target_rate_ = rate;
00042   reset_time_ = Scheduler::instance().clock();
00043   
00044   ptype_ = ptype;
00045   ptype_share_ = share;
00046   
00047 //  if (debug_)
00048 //    printf("TB: Starting a token bucket at %g with rate %g bps\n", Scheduler::instance().clock(), rate);
00049   rateEstimator_ = new RateEstimator(estimate);
00050   rateLimiter_ = new TokenBucketRateLimiter();
00051   
00052   ptypeRateEstimator_ = new RateEstimator();
00053   ptypeRateLimiter_ = new TokenBucketRateLimiter();
00054   
00055   ptypeLog_ = new PacketTypeLog(this);
00056 }
00057 
00058 double
00059 RateLimitStrategy::process(Packet *p, int mine, int lowDemand) {
00060   
00061   rateEstimator_->estimateRate(p);
00062   ptypeLog_->log(p);
00063   
00064   hdr_cmn* hdr = HDR_CMN(p);
00065     
00066   int dropped = 0;
00067   if (hdr->ptype() == ptype_) {
00068     ptypeRateEstimator_->estimateRate(p);
00069     dropped = ptypeRateLimiter_->rateLimit(p, ptypeRateEstimator_->estRate_, 
00070                                            target_rate_*ptype_share_, mine, lowDemand);
00071   }
00072 
00073   if (dropped) return 1;
00074   
00075   dropped = rateLimiter_->rateLimit(p, rateEstimator_->estRate_, target_rate_, mine, lowDemand);
00076   return dropped;
00077 }
00078 
00079 void
00080 RateLimitStrategy::restrictPacketType(int type, double share, double actual) {
00081   
00082   if (type == ptype_) {
00083     return;
00084   }
00085   
00086   printf("RLSt: Restricting type %d to %g hogging=%g at %g \n",  type, share, actual, 
00087          Scheduler::instance().clock());
00088   ptype_ = type;
00089   ptype_share_ = share;
00090   ptypeRateEstimator_->estRate_ = rateEstimator_->estRate_*actual;
00091 }
00092 
00093 double 
00094 RateLimitStrategy::getDropRate() {
00095   double inRate = rateEstimator_->estRate_;
00096   double dropRate = (inRate - target_rate_)/inRate;
00097   if (dropRate < 0) dropRate=0;
00098   return dropRate;
00099 }
00100 
00101 double 
00102 RateLimitStrategy::getArrivalRate() {
00103   return rateEstimator_->estRate_;
00104 }
00105 
00106 void
00107 RateLimitStrategy::reset() {
00108   rateLimiter_->reset();
00109   ptypeRateLimiter_->reset();
00110   rateEstimator_->reset(); 
00111   ptypeRateEstimator_->reset();
00112 }
00113 
00114 RateLimitStrategy::~RateLimitStrategy() {
00115   delete(rateLimiter_);
00116   delete(ptypeRateLimiter_);
00117   delete(rateEstimator_);
00118   delete(ptypeRateEstimator_);
00119   delete(ptypeLog_);
00120 }
00121 
00122 //########################### PacketTypeLog Methods #####################
00123 
00124 PacketTypeLog::PacketTypeLog(RateLimitStrategy * rlst) {
00125   count_=0;
00126   for (int i=0; i<MAX_PACKET_TYPES; i++) {
00127     typeCount_[i]=0;
00128   }
00129   rlStrategy_ = rlst;
00130   
00131   resched(PACKET_TYPE_TIMER);
00132 }
00133 
00134 void
00135 PacketTypeLog::log(Packet *p) {
00136   hdr_cmn* hdr = HDR_CMN(p);
00137   int type = hdr->ptype();
00138   
00139   int index = mapTypeToIndex(type);
00140   //count packets instead of bytes
00141   typeCount_[index]++;
00142   count_++;
00143 }
00144 
00145 void
00146 PacketTypeLog::expire(Event * e) {
00147 
00148   //printf("PTTimer Expiry at %g\n", Scheduler::instance().clock());
00149 
00150   if (!count_) {
00151     resched(PACKET_TYPE_TIMER);
00152     return;
00153   }
00154     
00155   for (int i=0; i<MAX_PACKET_TYPES; i++) {
00156     if (typeCount_[i]!=0) {
00157       double actualShare = ((double)typeCount_[i])/count_;
00158       int type = mapIndexToType(i);
00159       double maxShare = mapTypeToShare(type);
00160       if (actualShare>maxShare) {
00161         //right now only one type can be restricted.
00162         rlStrategy_->restrictPacketType(type, maxShare, actualShare);
00163         resched(PACKET_TYPE_TIMER);
00164         return;
00165       }
00166     }
00167   }
00168   
00169   //stop restricting if you were.
00170   rlStrategy_->restrictPacketType(-1, 1, 1);
00171   resched(PACKET_TYPE_TIMER);
00172   return;
00173 }
00174   
00175 int 
00176 PacketTypeLog::mapTypeToIndex(int type) {
00177   
00178   switch (type) {
00179   case PT_PING: return 0;
00180   case PT_UDP: return 1;
00181   case PT_CBR: return 2;
00182   default: return MAX_PACKET_TYPES-1;
00183   }
00184 }
00185 
00186 int 
00187 PacketTypeLog::mapIndexToType(int index) {
00188   switch (index) {
00189   case 0: return PT_PING;
00190   case 1: return PT_UDP;
00191   case 2: return PT_CBR;
00192   case MAX_PACKET_TYPES-1: return -1;
00193   default: printf("PTLog: invalid index\n"); exit(-1);
00194   }
00195 }
00196 
00197 //returning 1.0 means don't limit traffic of that type.
00198 double
00199 PacketTypeLog::mapTypeToShare(int type) {
00200   switch (type) {
00201   case PT_PING: return 1.0;
00202   case PT_UDP: return 1.0;
00203   case PT_CBR: return 1.0;
00204   default: return 1;
00205   }
00206 }
00207 
00208 PacketTypeLog::~PacketTypeLog() {
00209   cancel();
00210 }
00211 
00212 //########################### TokenBucketRateLimiter Methods ###################
00213 
00214 TokenBucketRateLimiter::TokenBucketRateLimiter() {
00215   
00216   bucket_depth_ = DEFAULT_BUCKET_DEPTH;
00217   tbucket_ = bucket_depth_;
00218   total_passed_ = 0.0;
00219   total_dropped_ = 0.0;
00220   time_last_token_ = Scheduler::instance().clock();
00221 }
00222 
00223 int 
00224 TokenBucketRateLimiter::rateLimit(Packet * p, double arrRate, double targetRate, int mine, int lowDemand) {
00225 
00226   hdr_cmn* hdr = HDR_CMN(p);
00227   double now = Scheduler::instance().clock();
00228   double time_elapsed = now - time_last_token_;
00229   
00230   //printf("TB: now = %g last_sent = %g elapsed = %g\n", now, time_last_token_, time_elapsed);
00231   tbucket_ += (time_elapsed * targetRate)/8.0;
00232   time_last_token_ = now;
00233 
00234   if (tbucket_ > bucket_depth_)
00235     tbucket_ = bucket_depth_;      /* never overflow */
00236 
00237   //printf("TB: tbucket_ = %g pktSize = %g\n", tbucket_, (double)hdr->size_);
00238   //printf("TB: in = %g out = %g\n", total_passed_, total_dropped_);
00239 
00240   if ((double)hdr->size_ < tbucket_ || (mine && lowDemand) ) {
00241     tbucket_ -= hdr->size_;
00242     total_passed_ += (double) hdr->size_;
00243     //printf("Passed Packet in Rate Limiter\n");
00244     return 0;
00245   } 
00246   else {
00247     total_dropped_ += (double) hdr->size_;
00248     //    printf("Dropped Packet in Rate Limiter\n");
00249     return 1;
00250   }
00251 }
00252 
00253 // double 
00254 // TokenBucketRateLimiter::getDropRate() { 
00255 //   if (getArrivals() == 0) 
00256 //     return 0; 
00257 //   else 
00258 //     return total_dropped_/(total_passed_+total_dropped_);
00259 // }
00260   
00261 void
00262 TokenBucketRateLimiter::reset() {
00263   total_dropped_ = 0;
00264   total_passed_ = 0;
00265   tbucket_ = 0;
00266   time_last_token_ = Scheduler::instance().clock();
00267 }
00268 

Generated on Tue Apr 20 12:14:28 2004 for NS2.26SourcesOriginal by doxygen 1.3.3