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 Mar 6 16:47:49 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6