red-pd.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* -*-  Mode:C++; c-basic-offset:4; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 2000  International Computer Science Institute
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  * This product includes software developed by ACIRI, the AT&T 
  17.  *      Center for Internet Research at ICSI (the International Computer
  18.  *      Science Institute).
  19.  * 4. Neither the name of ACIRI nor of ICSI may be used
  20.  *    to endorse or promote products derived from this software without
  21.  *    specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  */
  35. #ifndef lint
  36. static const char rcsid[] =
  37.     "@(#) $Header: /cvsroot/nsnam/ns-2/queue/red-pd.cc,v 1.7 2002/01/01 00:05:54 sfloyd Exp $ (ACIRI)";
  38. #endif
  39. #include "red-pd.h"
  40. #include "red.h"
  41. #include "flowmon.h"
  42. static class ReDPDClass : public TclClass {
  43. public:
  44. ReDPDClass() : TclClass("Queue/RED/PD") {}
  45. TclObject* create(int argc, const char*const* argv) {
  46. // printf("creating REDPD %dn", argc);
  47. if (argc==4) {
  48. return (new RedPDQueue("Drop", "Drop"));
  49. }
  50. else  {
  51. char args[100];
  52. strcpy(args, argv[4]);
  53. //strtok used for compatibility reasons
  54. char * arg1 = strtok(args," ");
  55. char * arg2 = strtok(NULL," ");
  56. //printf("got arguements :%s:  :%s:n",arg1, arg2);
  57. if (arg2 == NULL) {
  58. printf("calling null arg2n");
  59. return (new RedPDQueue(arg1, "Drop"));
  60. }
  61. else {
  62. return (new RedPDQueue(arg1, arg2));
  63. }
  64. }
  65. }
  66. } red_pd_class;
  67. static class RedPDFlowClass : public TclClass {
  68.  public:
  69. RedPDFlowClass() : TclClass("QueueMonitor/ED/Flow/RedPD") {}
  70. TclObject* create(int, const char*const*) {
  71. return (new RedPDFlow);
  72. }
  73. } red_pd_flow_class;
  74. RedPDQueue::RedPDQueue(const char * medtype, const char * edtype): REDQueue(edtype),
  75. auto_(0), global_target_(0), targetBW_(0), noMonitored_(0), 
  76. unresponsive_penalty_(1), P_testFRp_(-1), noidle_(0),
  77. flowMonitor_(NULL), MEDTrace(NULL) {
  78. //printf("In RedPD constructor with %s %sn", medtype, edtype);
  79. if (strlen(medtype) >=20) {
  80. printf("RedPD : Too Long a trace type. Change the field length in red-pd.h and recompilen");
  81. exit(0);
  82. }
  83. strcpy(medTraceType, medtype);
  84. off_ip_ = hdr_ip::offset();
  85. bind_bool("auto_", &auto_);
  86. bind_bool("global_target_", &global_target_);
  87. bind_bool("noidle_", &noidle_);
  88. bind_bw("targetBW_", &targetBW_);
  89. bind("noMonitored_", &noMonitored_);
  90. bind("unresponsive_penalty_", &unresponsive_penalty_);
  91. bind("P_testFRp_", &P_testFRp_);
  92. }
  93. void RedPDQueue::reset() {
  94. REDQueue::reset();
  95. //probably should also reset the attached flow monitor and all the flows in it.
  96. }
  97. /*
  98.  * Receive a new packet arriving at the queue.
  99.  *    Check if the incoming flow belongs to a flow being monitored
  100.  *    If YES, 
  101.  *         drop the packet with probability associated with this flow.
  102.  *         if the packet survives, put it in the regular RED queue
  103.  *    if NO,
  104.  *        put it in the regular RED queue 
  105.  */
  106. void RedPDQueue::enque(Packet* pkt) {
  107. double P_monFlow=0;
  108. // hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_);    
  109. // int fid = iph->flowid();
  110. // int src_ = iph->saddr();
  111. if (flowMonitor_ == NULL) {
  112. printf("RedPD: ERROR: FlowMonitor Not Found --n");
  113. abort();
  114. }
  115. RedPDFlow * flow = (RedPDFlow *) flowMonitor_->find(pkt);
  116. if (flow == NULL) {
  117. printf("RedPD: ERROR: Flow Not Foundn");
  118. abort();
  119. }
  120. //  if (debug_) {
  121. //  printf("flow - %s %d", flow->name(), flow->monitored_);
  122. //  if (flow->monitored()) 
  123. //  printf("RedPD: Got a monitored flow :)n");
  124. //  else
  125. //  printf("RedPD: Unmonitored flow :(n");
  126. //  }
  127. if (flow->monitored()) {
  128. //update the current estimate 
  129. //if automatic arrival rate estimation is taking place.
  130. if (flow->auto_) {
  131. flow->currentBW_ = flow->estRate_;
  132. }
  133. //calculate drop probability - use the global target if global_target_ is set
  134. if (global_target_) { 
  135. P_monFlow = getP_monFlow(flow->currentBW_, targetBW_);
  136. else { 
  137. P_monFlow = getP_monFlow(flow->currentBW_, flow->targetBW_);
  138. }
  139. if (flow->unresponsive_) {
  140. //printf("unresponsive penalty = %gn", unresponsive_penalty_);
  141. P_monFlow *= unresponsive_penalty_;
  142. }
  143. if (P_monFlow != 0) {
  144. flow->lastDropTime_ = Scheduler::instance().clock();
  145. double mod_p = modify_p(P_monFlow, flow->count, 0, 0, 0, 0, 0);
  146. P_monFlow = mod_p;
  147. double u = Random::uniform();
  148. int drop=0;
  149. //don't apply link utilization optimization in testFRp mode
  150. if (P_testFRp_ != -1 && u <= P_monFlow) {
  151.     drop =1;
  152. }
  153. // drop a packet 
  154. // 1. flow is responsive & (ave_q > min_th) & queue is not empty
  155. // 2  flow is unresponsive & (noidle is not set or queue is not empty) 
  156. int qlen = qib_ ? q_->byteLength() : q_->length();
  157. if ( P_testFRp_ == -1 && u<= P_monFlow &&
  158.      (
  159.       (!flow->unresponsive_ && edv_.v_ave >= edp_.th_min && qlen > 1) ||
  160.       (flow->unresponsive_ && ( qlen > 1 || !noidle_))
  161.       )
  162.      ) {
  163.     drop = 1;
  164. }
  165. if (drop) {
  166.     //first trace the monitored early drop
  167.     if (MEDTrace!= NULL) 
  168. ((Trace *)MEDTrace)->recvOnly(pkt);
  169.     
  170.     flowMonitor_->mon_edrop(pkt);
  171.     
  172.     //there is a bug here, this packet drop does not go to
  173.     // any other flow monitor attached to the link. 
  174.     //departures and arrivals still go there if you wanna calculate.
  175.     Packet::free(pkt);
  176.     
  177.     flow->count = 0;
  178.     return;
  179. }
  180. else {
  181.     flow->count++;
  182. }
  183. }
  184. }
  185. //if not dropped or a non-monitored packet - send it to the RED queue 
  186. // - but before see if testFRp mode is on
  187. if (P_testFRp_ != -1) {
  188.     double p = P_testFRp_;
  189.     int size =  (hdr_cmn::access(pkt))->size();
  190.     if (edp_.bytes) {
  191. p = (p * size) / edp_.mean_pktsize;
  192.     }
  193.     if (debug_) 
  194. printf("FRp_ mode ON with %gn",P_testFRp_); 
  195.     double u = Random::uniform();
  196.     if (u <= p) {
  197. drop(pkt);
  198. return;
  199.     }
  200. }
  201. REDQueue::enque(pkt);
  202. }
  203. int RedPDQueue::command(int argc, const char*const* argv) {
  204. Tcl& tcl = Tcl::instance();
  205. if (argc==2) {
  206. if (strcmp(argv[1], "mon-edrop-trace") == 0) {
  207. if (MEDTrace != NULL) {
  208. tcl.resultf("%s", MEDTrace->name());
  209. //printf("Exists according to RedPDn");
  210. }
  211. else {
  212. //printf("Doesn't exist according to RedPDn");
  213. tcl.resultf("0");
  214. }
  215. return (TCL_OK);
  216. }
  217. if (strcmp(argv[1], "mon-trace-type") == 0) {
  218. tcl.resultf("%s",medTraceType);
  219. return (TCL_OK);
  220. }
  221. }
  222. else if (argc == 3) {
  223. //$queue attach-flowmon $flowMon
  224. if (strcmp(argv[1], "attach-flowmon") == 0) {
  225. flowMonitor_ = (FlowMon *) TclObject::lookup(argv[2]);
  226. if (flowMonitor_ == NULL) {
  227. if (debug_) printf("Error Creating Flowmonitorn");
  228.                                 return (TCL_ERROR);
  229. }
  230. if (debug_) 
  231. printf("RedPD: Flow Monitor Set to %sn", flowMonitor_->name());
  232. de_drop_ = (NsObject *) flowMonitor_;
  233.                         return (TCL_OK);
  234. }
  235. //$queue showme $flow
  236. //prints the monitoring status of the flow
  237. else if (strcmp(argv[1], "showme") == 0) {
  238. RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
  239. printf("showing now : %s = %dn", flow->name(), flow->monitored_);
  240. return (TCL_OK);
  241. }
  242. //$queue mon-edrop-trace $trace
  243. //attaches the trace object to the queue
  244. else if (strcmp(argv[1], "mon-edrop-trace") == 0) {
  245. MEDTrace = (NsObject *) TclObject::lookup(argv[2]);
  246. if (MEDTrace == NULL) {
  247. if (debug_) printf("Error Attaching Tracen");
  248.                                 return (TCL_ERROR);
  249. }
  250. if (debug_) 
  251. printf("RedPD: MEDTrace Set to %sn", flowMonitor_->name());
  252. return (TCL_OK);
  253. }
  254. //$queue unmonitor-flow $flow
  255. else if (strcmp(argv[1], "unmonitor-flow") == 0) {
  256. RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
  257. if (flow->monitored_ != 1) {
  258. tcl.resultf("Cannot unmonitor an unmonitored flow: %dn", flow->flowid());
  259. return(TCL_ERROR);
  260. }
  261. flow->monitored_ = 0;
  262. flow->unresponsive_ = 0;
  263. flow->monitorStartTime_ = 0;
  264. flow->lastDropTime_ = 0;
  265. flow->unresponsiveStartTime_ = 0;
  266. noMonitored_--;
  267. if ( noMonitored_ < 0 ) {
  268. tcl.resultf("noMonitored gone below ZEROn");
  269. return TCL_ERROR;
  270. }
  271. return TCL_OK;
  272. }
  273. //$queue unresponsive-flow $flow
  274. //declare a flow unresponsive
  275. else if (strcmp(argv[1], "unresponsive-flow") == 0) {
  276. RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
  277. if (flow->monitored_ != 1) {
  278. tcl.resultf("Cannot make an unmonitored flow unresponsive: %dn", 
  279.     flow->flowid());
  280. return(TCL_ERROR);
  281. }
  282. if (flow->unresponsive_ != 1) {
  283. flow->unresponsive_ = 1;
  284. flow->unresponsiveStartTime_ = Scheduler::instance().clock();
  285. }
  286. if (flow->auto_) {
  287. flow->estimate_rate_=1;
  288. }
  289. return TCL_OK;
  290. }
  291. //$queue responsive-flow $flow
  292. else if (strcmp(argv[1], "responsive-flow") == 0) {
  293. RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
  294. if (flow->unresponsive_ != 1) {
  295. tcl.resultf("Cannot make a responsive flow responsive: %dn", 
  296.     flow->flowid());
  297. return(TCL_ERROR);
  298. }
  299. flow->unresponsive_ = 0;
  300. flow->unresponsiveStartTime_ = 0;
  301. return TCL_OK;
  302. }
  303. }
  304. else if (argc == 4) {
  305. //$queue monitor-flow $flow $prob
  306. //monitor a flow with probability $prob
  307. if (strcmp(argv[1], "monitor-flow") == 0) {
  308. //this is a round about way of doing things, but ... historical
  309. //monitoring a flow with probability p, is same as 
  310. //monitoring it with targetBW 1-p and currentBW 1. 
  311. tcl.evalf("%s monitor-flow %s %g 1",name(), argv[2], 1 - atof(argv[3]));
  312. return(TCL_OK);
  313. }
  314. }
  315. else if (argc == 5) {
  316. //$queue monitor-flow $flow $targetBW $currentBW 
  317. if (strcmp(argv[1], "monitor-flow") == 0) {
  318. RedPDFlow * flow = (RedPDFlow *) TclObject::lookup(argv[2]);
  319. tcl.evalf("%s set targetBW_ %s", flow->name(), argv[3]);
  320. tcl.evalf("%s set currentBW_ %s", flow->name(), argv[4]);
  321. if (flow->monitored_ != 1) {
  322. flow->monitored_=1;
  323. noMonitored_ ++;
  324. flow->monitorStartTime_ = Scheduler::instance().clock();
  325. }
  326. //if auto_ is ON initialize the rate estimation with the current bandwidth
  327. if (auto_) {
  328. flow->estimate_rate_=1;
  329. flow->estRate_ = flow->currentBW_;
  330. }
  331. return (TCL_OK);
  332. }
  333. }
  334. return (REDQueue::command(argc, argv));
  335. }