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

red-pd.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:4; 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 #ifndef lint
00037 static const char rcsid[] =
00038     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/red-pd.cc,v 1.7 2002/01/01 00:05:54 sfloyd Exp $ (ACIRI)";
00039 #endif
00040 
00041 #include "red-pd.h"
00042 #include "red.h"
00043 #include "flowmon.h"
00044 
00045 static class ReDPDClass : public TclClass {
00046 public:
00047         ReDPDClass() : TclClass("Queue/RED/PD") {}
00048         TclObject* create(int argc, const char*const* argv) {
00049                 //              printf("creating REDPD %d\n", argc);
00050                 if (argc==4) {
00051                         return (new RedPDQueue("Drop", "Drop"));
00052                 }
00053                 else  {
00054                         char args[100];
00055                         strcpy(args, argv[4]);
00056                         //strtok used for compatibility reasons
00057                         char * arg1 = strtok(args," ");
00058                         char * arg2 = strtok(NULL," ");
00059                         //printf("got arguements :%s:  :%s:\n",arg1, arg2);
00060                         if (arg2 == NULL) {
00061                                 printf("calling null arg2\n");
00062                                 return (new RedPDQueue(arg1, "Drop"));
00063                         }
00064                         else {
00065                                 return (new RedPDQueue(arg1, arg2));
00066                         }
00067                 }
00068                 
00069         }
00070 } red_pd_class;
00071 
00072 static class RedPDFlowClass : public TclClass {
00073  public:
00074         RedPDFlowClass() : TclClass("QueueMonitor/ED/Flow/RedPD") {}
00075         TclObject* create(int, const char*const*) {
00076                 return (new RedPDFlow);
00077         }
00078 } red_pd_flow_class;
00079 
00080 RedPDQueue::RedPDQueue(const char * medtype, const char * edtype): REDQueue(edtype),
00081         auto_(0), global_target_(0), targetBW_(0), noMonitored_(0), 
00082         unresponsive_penalty_(1), P_testFRp_(-1), noidle_(0),
00083         flowMonitor_(NULL), MEDTrace(NULL) {
00084 
00085         //printf("In RedPD constructor with %s %s\n", medtype, edtype);
00086         if (strlen(medtype) >=20) {
00087                 printf("RedPD : Too Long a trace type. Change the field length in red-pd.h and recompile\n");
00088                 exit(0);
00089         }
00090         strcpy(medTraceType, medtype);
00091         
00092         off_ip_ = hdr_ip::offset();
00093         
00094         bind_bool("auto_", &auto_);
00095         bind_bool("global_target_", &global_target_);
00096         bind_bool("noidle_", &noidle_);
00097         bind_bw("targetBW_", &targetBW_);
00098         bind("noMonitored_", &noMonitored_);
00099         bind("unresponsive_penalty_", &unresponsive_penalty_);
00100         bind("P_testFRp_", &P_testFRp_);
00101 }
00102 
00103 
00104 void RedPDQueue::reset() {
00105 
00106         REDQueue::reset();
00107         
00108         //probably should also reset the attached flow monitor and all the flows in it.
00109 }
00110 
00111 /*
00112  * Receive a new packet arriving at the queue.
00113  *    Check if the incoming flow belongs to a flow being monitored
00114  *    If YES, 
00115  *         drop the packet with probability associated with this flow.
00116  *         if the packet survives, put it in the regular RED queue
00117  *    if NO,
00118  *        put it in the regular RED queue 
00119  */
00120 
00121 void RedPDQueue::enque(Packet* pkt) {
00122         
00123         double P_monFlow=0;
00124 
00125         //      hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_);    
00126         //      int fid = iph->flowid();
00127         //      int src_ = iph->saddr();
00128         
00129         if (flowMonitor_ == NULL) {
00130                 printf("RedPD: ERROR: FlowMonitor Not Found --\n");
00131                 abort();
00132         }       
00133         
00134         RedPDFlow * flow = (RedPDFlow *) flowMonitor_->find(pkt);
00135         
00136         if (flow == NULL) {
00137                 printf("RedPD: ERROR: Flow Not Found\n");
00138                 abort();
00139         }
00140         
00141 //      if (debug_) {
00142 //              printf("flow - %s %d", flow->name(), flow->monitored_);
00143 //              if (flow->monitored()) 
00144 //                      printf("RedPD: Got a monitored flow :)\n");
00145 //              else
00146 //                      printf("RedPD: Unmonitored flow :(\n");
00147 //      }
00148 
00149         if (flow->monitored()) {
00150 
00151                 //update the current estimate 
00152                 //if automatic arrival rate estimation is taking place.
00153                 if (flow->auto_) {
00154                         flow->currentBW_ = flow->estRate_;
00155                 }
00156                 
00157                 //calculate drop probability - use the global target if global_target_ is set
00158                 if (global_target_) { 
00159                         P_monFlow = getP_monFlow(flow->currentBW_, targetBW_);
00160                 } 
00161                 else { 
00162                         P_monFlow = getP_monFlow(flow->currentBW_, flow->targetBW_);
00163                 }
00164                 
00165                 if (flow->unresponsive_) {
00166                         //printf("unresponsive penalty = %g\n", unresponsive_penalty_);
00167                         P_monFlow *= unresponsive_penalty_;
00168                 }
00169                 
00170                 if (P_monFlow != 0) {
00171                         flow->lastDropTime_ = Scheduler::instance().clock();
00172                         double mod_p = modify_p(P_monFlow, flow->count, 0, 0, 0, 0, 0);
00173 
00174                         P_monFlow = mod_p;
00175                         double u = Random::uniform();
00176                         
00177                         int drop=0;
00178                         
00179                         //don't apply link utilization optimization in testFRp mode
00180                         if (P_testFRp_ != -1 && u <= P_monFlow) {
00181                             drop =1;
00182                         }
00183 
00184                         // drop a packet 
00185                         // 1. flow is responsive & (ave_q > min_th) & queue is not empty
00186                         // 2  flow is unresponsive & (noidle is not set or queue is not empty) 
00187                         int qlen = qib_ ? q_->byteLength() : q_->length();
00188                         if ( P_testFRp_ == -1 && u<= P_monFlow &&
00189                              (
00190                               (!flow->unresponsive_ && edv_.v_ave >= edp_.th_min && qlen > 1) ||
00191                               (flow->unresponsive_ && ( qlen > 1 || !noidle_))
00192                               )
00193                              ) {
00194                             drop = 1;
00195                         }
00196 
00197                         if (drop) {
00198                             //first trace the monitored early drop
00199                             if (MEDTrace!= NULL) 
00200                                 ((Trace *)MEDTrace)->recvOnly(pkt);
00201                             
00202                             flowMonitor_->mon_edrop(pkt);
00203                             
00204                             //there is a bug here, this packet drop does not go to
00205                             // any other flow monitor attached to the link. 
00206                             //departures and arrivals still go there if you wanna calculate.
00207                             Packet::free(pkt);
00208                             
00209                             flow->count = 0;
00210                             return;
00211                         }
00212                         else {
00213                             flow->count++;
00214                         }
00215                 }
00216         }
00217         
00218         //if not dropped or a non-monitored packet - send it to the RED queue 
00219         // - but before see if testFRp mode is on
00220         if (P_testFRp_ != -1) {
00221             double p = P_testFRp_;
00222             int size =  (hdr_cmn::access(pkt))->size();
00223             if (edp_.bytes) {
00224                 p = (p * size) / edp_.mean_pktsize;
00225             }
00226             if (debug_) 
00227                 printf("FRp_ mode ON with %g\n",P_testFRp_); 
00228             double u = Random::uniform();
00229             if (u <= p) {
00230                 drop(pkt);
00231                 return;
00232             }
00233         }
00234         
00235         REDQueue::enque(pkt);
00236 }
00237 
00238 
00239 int RedPDQueue::command(int argc, const char*const* argv) {
00240 
00241         Tcl& tcl = Tcl::instance();
00242         if (argc==2) {
00243                 if (strcmp(argv[1], "mon-edrop-trace") == 0) {
00244                         if (MEDTrace != NULL) {
00245                                 tcl.resultf("%s", MEDTrace->name());
00246                                 //printf("Exists according to RedPD\n");
00247                         }
00248                         else {
00249                                 //printf("Doesn't exist according to RedPD\n");
00250                                 tcl.resultf("0");
00251                         }
00252                         return (TCL_OK);
00253                 }
00254                 if (strcmp(argv[1], "mon-trace-type") == 0) {
00255                         tcl.resultf("%s",medTraceType);
00256                         return (TCL_OK);
00257                 }
00258         }
00259         else if (argc == 3) {
00260                 //$queue attach-flowmon $flowMon
00261                 if (strcmp(argv[1], "attach-flowmon") == 0) {
00262                         
00263                         flowMonitor_ = (FlowMon *) TclObject::lookup(argv[2]);
00264                         if (flowMonitor_ == NULL) {
00265                                 if (debug_) printf("Error Creating Flowmonitor\n");
00266                                 return (TCL_ERROR);
00267                         }
00268                         if (debug_) 
00269                                 printf("RedPD: Flow Monitor Set to %s\n", flowMonitor_->name());
00270         
00271                         de_drop_ = (NsObject *) flowMonitor_;
00272                         return (TCL_OK);
00273                 }
00274                 //$queue showme $flow
00275                 //prints the monitoring status of the flow
00276                 else if (strcmp(argv[1], "showme") == 0) {
00277 
00278                         RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
00279                         printf("showing now : %s = %d\n", flow->name(), flow->monitored_);
00280                         return (TCL_OK);
00281                 }
00282                 //$queue mon-edrop-trace $trace
00283                 //attaches the trace object to the queue
00284                 else if (strcmp(argv[1], "mon-edrop-trace") == 0) {
00285                         
00286                         MEDTrace = (NsObject *) TclObject::lookup(argv[2]);
00287                         if (MEDTrace == NULL) {
00288                                 if (debug_) printf("Error Attaching Trace\n");
00289                                 return (TCL_ERROR);
00290                         }
00291                         if (debug_) 
00292                                 printf("RedPD: MEDTrace Set to %s\n", flowMonitor_->name());
00293                         return (TCL_OK);
00294                 }
00295                 //$queue unmonitor-flow $flow
00296                 else if (strcmp(argv[1], "unmonitor-flow") == 0) {
00297                         RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
00298                         
00299                         if (flow->monitored_ != 1) {
00300                                 tcl.resultf("Cannot unmonitor an unmonitored flow: %d\n", flow->flowid());
00301                                 return(TCL_ERROR);
00302                         }
00303 
00304                         flow->monitored_ = 0;
00305                         flow->unresponsive_ = 0;
00306                         flow->monitorStartTime_ = 0;
00307                         flow->lastDropTime_ = 0;
00308                         flow->unresponsiveStartTime_ = 0;
00309 
00310                         noMonitored_--;
00311 
00312                         if ( noMonitored_ < 0 ) {
00313                                 tcl.resultf("noMonitored gone below ZERO\n");
00314                                 return TCL_ERROR;
00315                         }
00316                         return TCL_OK;
00317                 }
00318                 //$queue unresponsive-flow $flow
00319                 //declare a flow unresponsive
00320                 else if (strcmp(argv[1], "unresponsive-flow") == 0) {
00321                         RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
00322                         
00323                         if (flow->monitored_ != 1) {
00324                                 tcl.resultf("Cannot make an unmonitored flow unresponsive: %d\n", 
00325                                             flow->flowid());
00326                                 return(TCL_ERROR);
00327                         }
00328 
00329                         if (flow->unresponsive_ != 1) {
00330                                 flow->unresponsive_ = 1;
00331                                 flow->unresponsiveStartTime_ = Scheduler::instance().clock();
00332                         }
00333 
00334                         if (flow->auto_) {
00335                                 flow->estimate_rate_=1;
00336                         }
00337                         
00338                         return TCL_OK;
00339                 }
00340                 //$queue responsive-flow $flow
00341                 else if (strcmp(argv[1], "responsive-flow") == 0) {
00342                         RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
00343                         
00344                         if (flow->unresponsive_ != 1) {
00345                                 tcl.resultf("Cannot make a responsive flow responsive: %d\n", 
00346                                             flow->flowid());
00347                                 return(TCL_ERROR);
00348                         }
00349                         flow->unresponsive_ = 0;
00350                         flow->unresponsiveStartTime_ = 0;
00351                         
00352                         return TCL_OK;
00353                 }
00354         }
00355         else if (argc == 4) {
00356                 //$queue monitor-flow $flow $prob
00357                 //monitor a flow with probability $prob
00358                 if (strcmp(argv[1], "monitor-flow") == 0) {
00359                         //this is a round about way of doing things, but ... historical
00360                         //monitoring a flow with probability p, is same as 
00361                         //monitoring it with targetBW 1-p and currentBW 1. 
00362                         tcl.evalf("%s monitor-flow %s %g 1",name(), argv[2], 1 - atof(argv[3]));
00363                         return(TCL_OK);
00364                 }
00365         }
00366         else if (argc == 5) {
00367                 //$queue monitor-flow $flow $targetBW $currentBW 
00368                 if (strcmp(argv[1], "monitor-flow") == 0) {
00369                         RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
00370                         
00371                         tcl.evalf("%s set targetBW_ %s", flow->name(), argv[3]);
00372                         tcl.evalf("%s set currentBW_ %s", flow->name(), argv[4]);
00373                         
00374                         if (flow->monitored_ != 1) {
00375                                 flow->monitored_=1;
00376                                 noMonitored_ ++;
00377                                 flow->monitorStartTime_ = Scheduler::instance().clock();
00378                         }
00379                         
00380                         //if auto_ is ON initialize the rate estimation with the current bandwidth
00381                         if (auto_) {
00382                                 flow->estimate_rate_=1;
00383                                 flow->estRate_ = flow->currentBW_;
00384                         }
00385                         
00386                         return (TCL_OK);
00387                 }
00388         }
00389         
00390         return (REDQueue::command(argc, argv));
00391 }
00392 

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