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

通讯编程

开发平台:

Visual C++

  1.  /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1990-1997 Regents of the University of California.
  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 the Computer Systems
  17.  * Engineering Group at Lawrence Berkeley Laboratory.
  18.  * 4. Neither the name of the University nor of the Laboratory may be used
  19.  *    to endorse or promote products derived from this software without
  20.  *    specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  *
  34.  *
  35.  * Here is one set of parameters from one of Sally's simulations
  36.  * (this is from tcpsim, the older simulator):
  37.  * 
  38.  * ed [ q_weight=0.002 thresh=5 linterm=30 maxthresh=15
  39.  *         mean_pktsize=500 dropmech=random-drop queue-size=60
  40.  *         plot-file=none bytes=false doubleq=false dqthresh=50 
  41.  *    wait=true ]
  42.  * 
  43.  * 1/"linterm" is the max probability of dropping a packet. 
  44.  * There are different options that make the code
  45.  * more messy that it would otherwise be.  For example,
  46.  * "doubleq" and "dqthresh" are for a queue that gives priority to
  47.  *   small (control) packets, 
  48.  * "bytes" indicates whether the queue should be measured in bytes 
  49.  *   or in packets, 
  50.  * "dropmech" indicates whether the drop function should be random-drop 
  51.  *   or drop-tail when/if the queue overflows, and 
  52.  *   the commented-out Holt-Winters method for computing the average queue 
  53.  *   size can be ignored.
  54.  * "wait" indicates whether the gateway should wait between dropping
  55.  *   packets.
  56.  */
  57. #ifndef lint
  58. static const char rcsid[] =
  59.      "@(#) $Header: /cvsroot/nsnam/ns-2/queue/red.cc,v 1.88 2007/10/23 06:55:54 seashadow Exp $ (LBL)";
  60. #endif
  61. #include <math.h>
  62. #include <sys/types.h>
  63. #include "config.h"
  64. #include "template.h"
  65. #include "random.h"
  66. #include "flags.h"
  67. #include "delay.h"
  68. #include "red.h"
  69. static class REDClass : public TclClass {
  70. public:
  71. REDClass() : TclClass("Queue/RED") {}
  72. TclObject* create(int argc, const char*const* argv) {
  73. //printf("creating RED Queue. argc = %dn", argc);
  74. //mod to enable RED to take arguments
  75. if (argc==5) 
  76. return (new REDQueue(argv[4]));
  77. else
  78. return (new REDQueue("Drop"));
  79. }
  80. } class_red;
  81. /* Strangely this didn't work. 
  82.  * Seg faulted for child classes.
  83. REDQueue::REDQueue() { 
  84. REDQueue("Drop");
  85. }
  86. */
  87. /*
  88.  * modified to enable instantiation with special Trace objects - ratul
  89.  */
  90. REDQueue::REDQueue(const char * trace) : link_(NULL), de_drop_(NULL), EDTrace(NULL), tchan_(0), idle_(1), idletime_(0.0)
  91. {
  92. initParams();
  93. // printf("Making trace type %sn", trace);
  94. if (strlen(trace) >=20) {
  95. printf("trace type too long - allocate more space to traceType in red.h and recompilen");
  96. exit(0);
  97. }
  98. strcpy(traceType, trace);
  99. bind_bool("bytes_", &edp_.bytes);     // boolean: use bytes?
  100. bind_bool("queue_in_bytes_", &qib_);     // boolean: q in bytes?
  101. // _RENAMED("queue-in-bytes_", "queue_in_bytes_");
  102. bind("thresh_", &edp_.th_min_pkts);     // minthresh
  103. bind("thresh_queue_", &edp_.th_min);
  104. bind("maxthresh_", &edp_.th_max_pkts);     // maxthresh
  105. bind("maxthresh_queue_", &edp_.th_max);
  106. bind("mean_pktsize_", &edp_.mean_pktsize);  // avg pkt size
  107. bind("idle_pktsize_", &edp_.idle_pktsize);  // avg pkt size for idles
  108. bind("q_weight_", &edp_.q_w);     // for EWMA
  109. bind("adaptive_", &edp_.adaptive);          // 1 for adaptive red
  110. bind("cautious_", &edp_.cautious);          // 1 for cautious marking
  111. bind("alpha_", &edp_.alpha);         // adaptive red param
  112. bind("beta_", &edp_.beta);                  // adaptive red param
  113. bind("interval_", &edp_.interval);     // adaptive red param
  114. bind("feng_adaptive_",&edp_.feng_adaptive); // adaptive red variant
  115. bind("targetdelay_", &edp_.targetdelay);    // target delay
  116. bind("top_", &edp_.top);     // maximum for max_p
  117. bind("bottom_", &edp_.bottom);     // minimum for max_p
  118. bind_bool("wait_", &edp_.wait);
  119. bind("linterm_", &edp_.max_p_inv);
  120. bind("mark_p_", &edp_.mark_p);
  121. bind_bool("use_mark_p_", &edp_.use_mark_p);
  122. bind_bool("setbit_", &edp_.setbit);     // mark instead of drop
  123. bind_bool("gentle_", &edp_.gentle);         // increase the packet
  124.     // drop prob. slowly
  125.     // when ave queue
  126.     // exceeds maxthresh
  127. bind_bool("summarystats_", &summarystats_);
  128. bind_bool("drop_tail_", &drop_tail_);     // drop last pkt
  129. // _RENAMED("drop-tail_", "drop_tail_");
  130. bind_bool("drop_front_", &drop_front_);     // drop first pkt
  131. // _RENAMED("drop-front_", "drop_front_");
  132. bind_bool("drop_rand_", &drop_rand_);     // drop pkt at random
  133. // _RENAMED("drop-rand_", "drop_rand_");
  134. bind_bool("ns1_compat_", &ns1_compat_);     // ns-1 compatibility
  135. // _RENAMED("ns1-compat_", "ns1_compat_");
  136. bind("ave_", &edv_.v_ave);     // average queue sie
  137. bind("prob1_", &edv_.v_prob1);     // dropping probability
  138. bind("curq_", &curq_);     // current queue size
  139. bind("cur_max_p_", &edv_.cur_max_p);        // current max_p
  140. q_ = new PacketQueue();     // underlying queue
  141. pq_ = q_;
  142. //reset();
  143. #ifdef notdef
  144. print_edp();
  145. print_edv();
  146. #endif
  147. }
  148. /*
  149.  * Note: if the link bandwidth changes in the course of the
  150.  * simulation, the bandwidth-dependent RED parameters do not change.
  151.  * This should be fixed, but it would require some extra parameters,
  152.  * and didn't seem worth the trouble...
  153.  */
  154. void REDQueue::initialize_params()
  155. {
  156. /*
  157.  * If q_weight=0, set it to a reasonable value of 1-exp(-1/C)
  158.  * This corresponds to choosing q_weight to be of that value for
  159.  * which the packet time constant -1/ln(1-q_weight) per default RTT 
  160.  * of 100ms is an order of magnitude more than the link capacity, C.
  161.  *
  162.  * If q_weight=-1, then the queue weight is set to be a function of
  163.  * the bandwidth and the link propagation delay.  In particular, 
  164.  * the default RTT is assumed to be three times the link delay and 
  165.  * transmission delay, if this gives a default RTT greater than 100 ms. 
  166.  *
  167.  * If q_weight=-2, set it to a reasonable value of 1-exp(-10/C).
  168.  */
  169. if (edp_.q_w == 0.0) {
  170. edp_.q_w = 1.0 - exp(-1.0/edp_.ptc);
  171.   } else if (edp_.q_w == -1.0) {
  172. double rtt = 3.0*(edp_.delay+1.0/edp_.ptc);
  173. //printf("delay: %5.4f rtt: %5.4fn", edp_.delay, rtt);
  174. if (rtt < 0.1) 
  175. rtt = 0.1;
  176. edp_.q_w = 1.0 - exp(-1.0/(10*rtt*edp_.ptc));
  177. } else if (edp_.q_w == -2.0) {
  178. edp_.q_w = 1.0 - exp(-10.0/edp_.ptc);
  179. }
  180. // printf("ptc: %7.5f bandwidth: %5.3f pktsize: %dn", edp_.ptc, link_->bandwidth(), edp_.mean_pktsize);
  181.         // printf("th_min_pkts: %7.5f th_max_pkts: %7.5fn", edp_.th_min_pkts, edp_.th_max);
  182. if (edp_.th_min_pkts == 0) {
  183. edp_.th_min_pkts = 5.0;
  184. // set th_min_pkts to half of targetqueue, if this is greater
  185. //  than 5 packets.
  186. double targetqueue = edp_.targetdelay * edp_.ptc;
  187. if (edp_.th_min_pkts < targetqueue / 2.0 )
  188. edp_.th_min_pkts = targetqueue / 2.0 ;
  189.         }
  190. if (edp_.th_max_pkts == 0) 
  191. edp_.th_max_pkts = 3.0 * edp_.th_min_pkts;
  192.         //printf("th_min_pkts: %7.5f th_max_pkts: %7.5fn", edp_.th_min_pkts, edp_.th_max);
  193. //printf("q_w: %7.5fn", edp_.q_w);
  194. if (edp_.bottom == 0) {
  195. edp_.bottom = 0.01;
  196. // Set bottom to at most 1/W, for W the delay-bandwidth 
  197. //   product in packets for a connection with this bandwidth,
  198. //   1000-byte packets, and 100 ms RTTs.
  199. // So W = 0.1 * link_->bandwidth() / 8000 
  200. double bottom1 = 80000.0/link_->bandwidth();
  201. if (bottom1 < edp_.bottom) 
  202. edp_.bottom = bottom1;
  203. //printf("bottom: %9.7fn", edp_.bottom);
  204. }
  205. }
  206. void REDQueue::initParams() 
  207. {
  208. edp_.mean_pktsize = 0;
  209. edp_.idle_pktsize = 0;
  210. edp_.bytes = 0;
  211. edp_.wait = 0;
  212. edp_.setbit = 0;
  213. edp_.gentle = 0;
  214. edp_.th_min = 0.0;
  215. edp_.th_min_pkts = 0.0;
  216. edp_.th_max = 0.0;
  217. edp_.th_max_pkts = 0.0;
  218. edp_.max_p_inv = 0.0;
  219. edp_.q_w = 0.0;
  220. edp_.adaptive = 0;
  221. edp_.cautious = 0;
  222. edp_.alpha = 0.0;
  223. edp_.beta = 0.0;
  224. edp_.interval = 0.0;
  225. edp_.targetdelay = 0.0;
  226. edp_.top = 0.0;
  227. edp_.bottom = 0.0;
  228. edp_.feng_adaptive = 0;
  229. edp_.ptc = 0.0;
  230. edp_.delay = 0.0;
  231. edv_.v_ave = 0.0;
  232. edv_.v_prob1 = 0.0;
  233. edv_.v_slope = 0.0;
  234. edv_.v_prob = 0.0;
  235. edv_.v_a = 0.0;
  236. edv_.v_b = 0.0;
  237. edv_.v_c = 0.0;
  238. edv_.v_d = 0.0;
  239. edv_.count = 0;
  240. edv_.count_bytes = 0;
  241. edv_.old = 0;
  242. edv_.cur_max_p = 1.0;
  243. edv_.lastset = 0;
  244. }
  245. void REDQueue::reset()
  246. {
  247.         //printf("3: th_min_pkts: %5.2fn", edp_.th_min_pkts); 
  248. /*
  249.  * Compute the "packet time constant" if we know the
  250.  * link bandwidth.  The ptc is the max number of (avg sized)
  251.  * pkts per second which can be placed on the link.
  252.  * The link bw is given in bits/sec, so scale mean psize
  253.  * accordingly.
  254.  */
  255.         if (link_) {
  256. edp_.ptc = link_->bandwidth() / (8.0 * edp_.mean_pktsize);
  257. initialize_params();
  258. }
  259. if (edp_.th_max_pkts == 0) 
  260. edp_.th_max_pkts = 3.0 * edp_.th_min_pkts;
  261. /*
  262.  * If queue is measured in bytes, scale min/max thresh
  263.  * by the size of an average packet (which is specified by user).
  264.  */
  265.         if (qib_) {
  266. //printf("1: th_min in pkts: %5.2f mean_pktsize: %d n", edp_.th_min_pkts, edp_.mean_pktsize); 
  267.                 edp_.th_min = edp_.th_min_pkts * edp_.mean_pktsize;  
  268.                 edp_.th_max = edp_.th_max_pkts * edp_.mean_pktsize;
  269. //printf("2: th_min in bytes (if qib): %5.2f mean_pktsize: %d n", edp_.th_min, edp_.mean_pktsize); 
  270.         } else {
  271. edp_.th_min = edp_.th_min_pkts;
  272. edp_.th_max = edp_.th_max_pkts;
  273. }
  274.  
  275. edv_.v_ave = 0.0;
  276. edv_.v_slope = 0.0;
  277. edv_.count = 0;
  278. edv_.count_bytes = 0;
  279. edv_.old = 0;
  280. double th_diff = (edp_.th_max - edp_.th_min);
  281. if (th_diff == 0) { 
  282. //XXX this last check was added by a person who knows
  283. //nothing of this code just to stop FP div by zero.
  284. //Values for thresholds were equal at time 0.  If you
  285. //know what should be here, please cleanup and remove
  286. //this comment.
  287. th_diff = 1.0; 
  288. }
  289. edv_.v_a = 1.0 / th_diff;
  290. edv_.cur_max_p = 1.0 / edp_.max_p_inv;
  291. edv_.v_b = - edp_.th_min / th_diff;
  292. edv_.lastset = 0.0;
  293. if (edp_.gentle) {
  294. edv_.v_c = ( 1.0 - edv_.cur_max_p ) / edp_.th_max;
  295. edv_.v_d = 2.0 * edv_.cur_max_p - 1.0;
  296. }
  297. idle_ = 1;
  298. if (&Scheduler::instance() != NULL)
  299. idletime_ = Scheduler::instance().clock();
  300. else
  301. idletime_ = 0.0; /* sched not instantiated yet */
  302. if (debug_) 
  303. printf("Doing a queue resetn");
  304. Queue::reset();
  305. if (debug_) 
  306. printf("Done queue resetn");
  307. }
  308. /*
  309.  *  Updating max_p, following code from Feng et al. 
  310.  *  This is only called for Adaptive RED.
  311.  *  From "A Self-Configuring RED Gateway", from Feng et al.
  312.  *  They recommend alpha = 3, and beta = 2.
  313.  */
  314. void REDQueue::updateMaxPFeng(double new_ave)
  315. {
  316. if ( edp_.th_min < new_ave && new_ave < edp_.th_max) {
  317. edv_.status = edv_.Between;
  318. }
  319. if (new_ave < edp_.th_min && edv_.status != edv_.Below) {
  320. edv_.status = edv_.Below;
  321. edv_.cur_max_p = edv_.cur_max_p / edp_.alpha;
  322. //double max = edv_.cur_max_p; double param = edp_.alpha;
  323. //printf("max: %5.2f alpha: %5.2fn", max, param);
  324. }
  325. if (new_ave > edp_.th_max && edv_.status != edv_.Above) {
  326. edv_.status = edv_.Above;
  327. edv_.cur_max_p = edv_.cur_max_p * edp_.beta;
  328. //double max = edv_.cur_max_p; double param = edp_.alpha;
  329. //printf("max: %5.2f beta: %5.2fn", max, param);
  330. }
  331. }
  332. /*
  333.  *  Updating max_p to keep the average queue size within the target range.
  334.  *  This is only called for Adaptive RED.
  335.  */
  336. void REDQueue::updateMaxP(double new_ave, double now)
  337. {
  338. double part = 0.4*(edp_.th_max - edp_.th_min);
  339. // AIMD rule to keep target Q~1/2(th_min+th_max)
  340. if ( new_ave < edp_.th_min + part && edv_.cur_max_p > edp_.bottom) {
  341. // we increase the average queue size, so decrease max_p
  342. edv_.cur_max_p = edv_.cur_max_p * edp_.beta;
  343. edv_.lastset = now;
  344. } else if (new_ave > edp_.th_max - part && edp_.top > edv_.cur_max_p ) {
  345. // we decrease the average queue size, so increase max_p
  346. double alpha = edp_.alpha;
  347.                         if ( alpha > 0.25*edv_.cur_max_p )
  348. alpha = 0.25*edv_.cur_max_p;
  349. edv_.cur_max_p = edv_.cur_max_p + alpha;
  350. edv_.lastset = now;
  351. }
  352. /*
  353.  * Compute the average queue size.
  354.  * Nqueued can be bytes or packets.
  355.  */
  356. double REDQueue::estimator(int nqueued, int m, double ave, double q_w)
  357. {
  358. double new_ave, old_ave;
  359. new_ave = ave;
  360. while (--m >= 1) {
  361. new_ave *= 1.0 - q_w;
  362. }
  363. old_ave = new_ave;
  364. new_ave *= 1.0 - q_w;
  365. new_ave += q_w * nqueued;
  366. double now = Scheduler::instance().clock();
  367. if (edp_.adaptive == 1) {
  368. if (edp_.feng_adaptive == 1)
  369. updateMaxPFeng(new_ave);
  370. else if (now > edv_.lastset + edp_.interval)
  371. updateMaxP(new_ave, now);
  372. }
  373. return new_ave;
  374. }
  375. /*
  376.  * Return the next packet in the queue for transmission.
  377.  */
  378. Packet* REDQueue::deque()
  379. {
  380. Packet *p;
  381. if (summarystats_ && &Scheduler::instance() != NULL) {
  382. Queue::updateStats(qib_?q_->byteLength():q_->length());
  383. }
  384. p = q_->deque();
  385. if (p != 0) {
  386. idle_ = 0;
  387. } else {
  388. idle_ = 1;
  389. // deque() may invoked by Queue::reset at init
  390. // time (before the scheduler is instantiated).
  391. // deal with this case
  392. if (&Scheduler::instance() != NULL)
  393. idletime_ = Scheduler::instance().clock();
  394. else
  395. idletime_ = 0.0;
  396. }
  397. return (p);
  398. }
  399. /*
  400.  * Calculate the drop probability.
  401.  */
  402. double
  403. REDQueue::calculate_p_new(double v_ave, double th_max, int gentle, double v_a, 
  404. double v_b, double v_c, double v_d, double max_p)
  405. {
  406. double p;
  407. if (gentle && v_ave >= th_max) {
  408. // p ranges from max_p to 1 as the average queue
  409. // size ranges from th_max to twice th_max 
  410. p = v_c * v_ave + v_d;
  411.         } else if (!gentle && v_ave >= th_max) { 
  412.                 // OLD: p continues to range linearly above max_p as
  413.                 // the average queue size ranges above th_max.
  414.                 // NEW: p is set to 1.0 
  415.                 p = 1.0;
  416.         } else {
  417.                 // p ranges from 0 to max_p as the average queue
  418.                 // size ranges from th_min to th_max 
  419.                 p = v_a * v_ave + v_b;
  420.                 // p = (v_ave - th_min) / (th_max - th_min)
  421.                 p *= max_p; 
  422.         }
  423. if (p > 1.0)
  424. p = 1.0;
  425. return p;
  426. }
  427. /*
  428.  * Calculate the drop probability.
  429.  * This is being kept for backwards compatibility.
  430.  */
  431. double
  432. REDQueue::calculate_p(double v_ave, double th_max, int gentle, double v_a, 
  433. double v_b, double v_c, double v_d, double max_p_inv)
  434. {
  435. double p = calculate_p_new(v_ave, th_max, gentle, v_a,
  436. v_b, v_c, v_d, 1.0 / max_p_inv);
  437. return p;
  438. }
  439. /*
  440.  * Make uniform instead of geometric interdrop periods.
  441.  */
  442. double
  443. REDQueue::modify_p(double p, int count, int count_bytes, int bytes, 
  444.    int mean_pktsize, int wait, int size)
  445. {
  446. double count1 = (double) count;
  447. if (bytes)
  448. count1 = (double) (count_bytes/mean_pktsize);
  449. if (wait) {
  450. if (count1 * p < 1.0)
  451. p = 0.0;
  452. else if (count1 * p < 2.0)
  453. p /= (2.0 - count1 * p);
  454. else
  455. p = 1.0;
  456. } else {
  457. if (count1 * p < 1.0)
  458. p /= (1.0 - count1 * p);
  459. else
  460. p = 1.0;
  461. }
  462. if (bytes && p < 1.0) {
  463. p = (p * size) / mean_pktsize;
  464. //p = p * (size / mean_pktsize);
  465. }
  466. if (p > 1.0)
  467. p = 1.0;
  468.   return p;
  469. }
  470. /*
  471.  * 
  472.  */
  473. /*
  474.  * should the packet be dropped/marked due to a probabilistic drop?
  475.  */
  476. int
  477. REDQueue::drop_early(Packet* pkt)
  478. {
  479. hdr_cmn* ch = hdr_cmn::access(pkt);
  480. edv_.v_prob1 = calculate_p_new(edv_.v_ave, edp_.th_max, edp_.gentle, 
  481.      edv_.v_a, edv_.v_b, edv_.v_c, edv_.v_d, edv_.cur_max_p);
  482. edv_.v_prob = modify_p(edv_.v_prob1, edv_.count, edv_.count_bytes,
  483.   edp_.bytes, edp_.mean_pktsize, edp_.wait, ch->size());
  484. // drop probability is computed, pick random number and act
  485. if (edp_.cautious == 1) {
  486.  // Don't drop/mark if the instantaneous queue is much
  487.  //  below the average.
  488.  // For experimental purposes only.
  489. int qsize = qib_?q_->byteLength():q_->length();
  490. // pkts: the number of packets arriving in 50 ms
  491. double pkts = edp_.ptc * 0.05;
  492. double fraction = pow( (1-edp_.q_w), pkts);
  493. // double fraction = 0.9;
  494. if ((double) qsize < fraction * edv_.v_ave) {
  495. // queue could have been empty for 0.05 seconds
  496. // printf("fraction: %5.2fn", fraction);
  497. return (0);
  498. }
  499. }
  500. double u = Random::uniform();
  501. if (edp_.cautious == 2) {
  502.                 // Decrease the drop probability if the instantaneous
  503. //   queue is much below the average.
  504. // For experimental purposes only.
  505. int qsize = qib_?q_->byteLength():q_->length();
  506. // pkts: the number of packets arriving in 50 ms
  507. double pkts = edp_.ptc * 0.05;
  508. double fraction = pow( (1-edp_.q_w), pkts);
  509. // double fraction = 0.9;
  510. double ratio = qsize / (fraction * edv_.v_ave);
  511. if (ratio < 1.0) {
  512. // printf("ratio: %5.2fn", ratio);
  513. u *= 1.0 / ratio;
  514. }
  515. }
  516. if (u <= edv_.v_prob) {
  517. // DROP or MARK
  518. edv_.count = 0;
  519. edv_.count_bytes = 0;
  520. hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt));
  521. if (edp_.setbit && hf->ect() && 
  522.                      (!edp_.use_mark_p || edv_.v_prob1 < edp_.mark_p)) { 
  523. hf->ce() = 1;  // mark Congestion Experienced bit
  524. // Tell the queue monitor here - call emark(pkt)
  525. return (0); // no drop
  526. } else {
  527. return (1); // drop
  528. }
  529. }
  530. return (0); // no DROP/mark
  531. }
  532. /*
  533.  * Pick packet for early congestion notification (ECN). This packet is then
  534.  * marked or dropped. Having a separate function do this is convenient for
  535.  * supporting derived classes that use the standard RED algorithm to compute
  536.  * average queue size but use a different algorithm for choosing the packet for 
  537.  * ECN notification.
  538.  */
  539. Packet*
  540. REDQueue::pickPacketForECN(Packet* pkt)
  541. {
  542. return pkt; /* pick the packet that just arrived */
  543. }
  544. /*
  545.  * Pick packet to drop. Having a separate function do this is convenient for
  546.  * supporting derived classes that use the standard RED algorithm to compute
  547.  * average queue size but use a different algorithm for choosing the victim.
  548.  */
  549. Packet*
  550. REDQueue::pickPacketToDrop() 
  551. {
  552. int victim;
  553. if (drop_front_)
  554. victim = min(1, q_->length()-1);
  555. else if (drop_rand_)
  556. victim = Random::integer(q_->length());
  557. else /* default is drop_tail_ */
  558. victim = q_->length() - 1;
  559. return(q_->lookup(victim)); 
  560. }
  561. /*
  562.  * Receive a new packet arriving at the queue.
  563.  * The average queue size is computed.  If the average size
  564.  * exceeds the threshold, then the dropping probability is computed,
  565.  * and the newly-arriving packet is dropped with that probability.
  566.  * The packet is also dropped if the maximum queue size is exceeded.
  567.  *
  568.  * "Forced" drops mean a packet arrived when the underlying queue was
  569.  * full, or when the average queue size exceeded some threshold and no
  570.  * randomization was used in selecting the packet to be dropped.
  571.  * "Unforced" means a RED random drop.
  572.  *
  573.  * For forced drops, either the arriving packet is dropped or one in the
  574.  * queue is dropped, depending on the setting of drop_tail_.
  575.  * For unforced drops, the arriving packet is always the victim.
  576.  */
  577. #define DTYPE_NONE 0 /* ok, no drop */
  578. #define DTYPE_FORCED 1 /* a "forced" drop */
  579. #define DTYPE_UNFORCED 2 /* an "unforced" (random) drop */
  580. void REDQueue::enque(Packet* pkt)
  581. {
  582. /*
  583.  * if we were idle, we pretend that m packets arrived during
  584.  * the idle period.  m is set to be the ptc times the amount
  585.  * of time we've been idle for
  586.  */
  587. /*  print_edp(); */
  588. int m = 0;
  589. if (idle_) {
  590. // A packet that arrives to an idle queue will never
  591. //  be dropped.
  592. double now = Scheduler::instance().clock();
  593. /* To account for the period when the queue was empty. */
  594. idle_ = 0;
  595. // Use idle_pktsize instead of mean_pktsize, for
  596. //  a faster response to idle times.
  597. if (edp_.cautious == 3) {
  598. double ptc = edp_.ptc * 
  599.    edp_.mean_pktsize / edp_.idle_pktsize;
  600. m = int(ptc * (now - idletime_));
  601. } else
  602.                  m = int(edp_.ptc * (now - idletime_));
  603. }
  604. /*
  605.  * Run the estimator with either 1 new packet arrival, or with
  606.  * the scaled version above [scaled by m due to idle time]
  607.  */
  608. edv_.v_ave = estimator(qib_ ? q_->byteLength() : q_->length(), m + 1, edv_.v_ave, edp_.q_w);
  609. //printf("v_ave: %6.4f (%13.12f) q: %d)n", 
  610. // double(edv_.v_ave), double(edv_.v_ave), q_->length());
  611. if (summarystats_) {
  612. /* compute true average queue size for summary stats */
  613. Queue::updateStats(qib_?q_->byteLength():q_->length());
  614. }
  615. /*
  616.  * count and count_bytes keeps a tally of arriving traffic
  617.  * that has not been dropped (i.e. how long, in terms of traffic,
  618.  * it has been since the last early drop)
  619.  */
  620. hdr_cmn* ch = hdr_cmn::access(pkt);
  621. ++edv_.count;
  622. edv_.count_bytes += ch->size();
  623. /*
  624.  * DROP LOGIC:
  625.  * q = current q size, ~q = averaged q size
  626.  * 1> if ~q > maxthresh, this is a FORCED drop
  627.  * 2> if minthresh < ~q < maxthresh, this may be an UNFORCED drop
  628.  * 3> if (q+1) > hard q limit, this is a FORCED drop
  629.  */
  630. register double qavg = edv_.v_ave;
  631. int droptype = DTYPE_NONE;
  632. int qlen = qib_ ? q_->byteLength() : q_->length();
  633. int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_;
  634. curq_ = qlen; // helps to trace queue during arrival, if enabled
  635. if (qavg >= edp_.th_min && qlen > 1) {
  636. if (!edp_.use_mark_p && 
  637. ((!edp_.gentle && qavg >= edp_.th_max) ||
  638. (edp_.gentle && qavg >= 2 * edp_.th_max))) {
  639. droptype = DTYPE_FORCED;
  640. } else if (edv_.old == 0) {
  641. /* 
  642.  * The average queue size has just crossed the
  643.  * threshold from below to above "minthresh", or
  644.  * from above "minthresh" with an empty queue to
  645.  * above "minthresh" with a nonempty queue.
  646.  */
  647. edv_.count = 1;
  648. edv_.count_bytes = ch->size();
  649. edv_.old = 1;
  650. } else if (drop_early(pkt)) {
  651. droptype = DTYPE_UNFORCED;
  652. }
  653. } else {
  654. /* No packets are being dropped.  */
  655. edv_.v_prob = 0.0;
  656. edv_.old = 0;
  657. }
  658. if (qlen >= qlim) {
  659. // see if we've exceeded the queue size
  660. droptype = DTYPE_FORCED;
  661. }
  662. if (droptype == DTYPE_UNFORCED) {
  663. /* pick packet for ECN, which is dropping in this case */
  664. Packet *pkt_to_drop = pickPacketForECN(pkt);
  665. /* 
  666.  * If the packet picked is different that the one that just arrived,
  667.  * add it to the queue and remove the chosen packet.
  668.  */
  669. if (pkt_to_drop != pkt) {
  670. q_->enque(pkt);
  671. q_->remove(pkt_to_drop);
  672. pkt = pkt_to_drop; /* XXX okay because pkt is not needed anymore */
  673. }
  674. // deliver to special "edrop" target, if defined
  675. if (de_drop_ != NULL) {
  676. //trace first if asked 
  677. // if no snoop object (de_drop_) is defined, 
  678. // this packet will not be traced as a special case.
  679. if (EDTrace != NULL) 
  680. ((Trace *)EDTrace)->recvOnly(pkt);
  681. reportDrop(pkt);
  682. de_drop_->recv(pkt);
  683. }
  684. else {
  685. reportDrop(pkt);
  686. drop(pkt);
  687. }
  688. } else {
  689. /* forced drop, or not a drop: first enqueue pkt */
  690. q_->enque(pkt);
  691. /* drop a packet if we were told to */
  692. if (droptype == DTYPE_FORCED) {
  693. /* drop random victim or last one */
  694. pkt = pickPacketToDrop();
  695. q_->remove(pkt);
  696. reportDrop(pkt);
  697. drop(pkt);
  698. if (!ns1_compat_) {
  699. // bug-fix from Philip Liu, <phill@ece.ubc.ca>
  700. edv_.count = 0;
  701. edv_.count_bytes = 0;
  702. }
  703. }
  704. }
  705. return;
  706. }
  707. int REDQueue::command(int argc, const char*const* argv)
  708. {
  709. Tcl& tcl = Tcl::instance();
  710. if (argc == 2) {
  711. if (strcmp(argv[1], "reset") == 0) {
  712. reset();
  713. return (TCL_OK);
  714. }
  715. if (strcmp(argv[1], "early-drop-target") == 0) {
  716. if (de_drop_ != NULL)
  717. tcl.resultf("%s", de_drop_->name());
  718. return (TCL_OK);
  719. }
  720. if (strcmp(argv[1], "edrop-trace") == 0) {
  721. if (EDTrace != NULL) {
  722. tcl.resultf("%s", EDTrace->name());
  723. if (debug_) 
  724. printf("edrop trace exists according to REDn");
  725. }
  726. else {
  727. if (debug_)
  728. printf("edrop trace doesn't exist according to REDn");
  729. tcl.resultf("0");
  730. }
  731. return (TCL_OK);
  732. }
  733. if (strcmp(argv[1], "trace-type") == 0) {
  734. tcl.resultf("%s", traceType);
  735. return (TCL_OK);
  736. }
  737. if (strcmp(argv[1], "printstats") == 0) {
  738. print_summarystats();
  739. return (TCL_OK);
  740. }
  741. else if (argc == 3) {
  742. // attach a file for variable tracing
  743. if (strcmp(argv[1], "attach") == 0) {
  744. int mode;
  745. const char* id = argv[2];
  746. tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
  747. if (tchan_ == 0) {
  748. tcl.resultf("RED: trace: can't attach %s for writing", id);
  749. return (TCL_ERROR);
  750. }
  751. return (TCL_OK);
  752. }
  753. // tell RED about link stats
  754. if (strcmp(argv[1], "link") == 0) {
  755. LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
  756. if (del == 0) {
  757. tcl.resultf("RED: no LinkDelay object %s",
  758. argv[2]);
  759. return(TCL_ERROR);
  760. }
  761. // set ptc now
  762. link_ = del;
  763. edp_.ptc = link_->bandwidth() /
  764. (8.0 * edp_.mean_pktsize);
  765. edp_.delay = link_->delay();
  766. if (
  767.   (edp_.q_w <= 0.0 || edp_.th_min_pkts == 0 ||
  768. edp_.th_max_pkts == 0))
  769.                          initialize_params();
  770. return (TCL_OK);
  771. }
  772. if (strcmp(argv[1], "early-drop-target") == 0) {
  773. NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
  774. if (p == 0) {
  775. tcl.resultf("no object %s", argv[2]);
  776. return (TCL_ERROR);
  777. }
  778. de_drop_ = p;
  779. return (TCL_OK);
  780. }
  781. if (strcmp(argv[1], "edrop-trace") == 0) {
  782. if (debug_) 
  783. printf("Ok, Heren");
  784. NsObject * t  = (NsObject *)TclObject::lookup(argv[2]);
  785. if (debug_)  
  786. printf("Ok, Here toon");
  787. if (t == 0) {
  788. tcl.resultf("no object %s", argv[2]);
  789. return (TCL_ERROR);
  790. }
  791. EDTrace = t;
  792. if (debug_)  
  793. printf("Ok, Here too too too %dn", ((Trace *)EDTrace)->type_);
  794. return (TCL_OK);
  795. }
  796. if (!strcmp(argv[1], "packetqueue-attach")) {
  797. delete q_;
  798. if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
  799. return (TCL_ERROR);
  800. else {
  801. pq_ = q_;
  802. return (TCL_OK);
  803. }
  804. }
  805. }
  806. return (Queue::command(argc, argv));
  807. }
  808. /*
  809.  * Routine called by TracedVar facility when variables change values.
  810.  * Currently used to trace values of avg queue size, drop probability,
  811.  * and the instantaneous queue size seen by arriving packets.
  812.  * Note that the tracing of each var must be enabled in tcl to work.
  813.  */
  814. void
  815. REDQueue::trace(TracedVar* v)
  816. {
  817. char wrk[500];
  818. const char *p;
  819. if (((p = strstr(v->name(), "ave")) == NULL) &&
  820.     ((p = strstr(v->name(), "prob")) == NULL) &&
  821.     ((p = strstr(v->name(), "curq")) == NULL) &&
  822.     ((p = strstr(v->name(), "cur_max_p"))==NULL) ) {
  823. fprintf(stderr, "RED:unknown trace var %sn",
  824. v->name());
  825. return;
  826. }
  827. if (tchan_) {
  828. int n;
  829. double t = Scheduler::instance().clock();
  830. // XXX: be compatible with nsv1 RED trace entries
  831. if (strstr(v->name(), "curq") != NULL) {
  832. sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
  833. } else {
  834. sprintf(wrk, "%c %g %g", *p, t,
  835. double(*((TracedDouble*) v)));
  836. }
  837. n = strlen(wrk);
  838. wrk[n] = 'n'; 
  839. wrk[n+1] = 0;
  840. (void)Tcl_Write(tchan_, wrk, n+1);
  841. }
  842. return; 
  843. }
  844. /* for debugging help */
  845. void REDQueue::print_edp()
  846. {
  847. printf("mean_pktsz: %dn", edp_.mean_pktsize); 
  848. printf("bytes: %d, wait: %d, setbit: %dn",
  849. edp_.bytes, edp_.wait, edp_.setbit);
  850. printf("minth: %f, maxth: %fn", edp_.th_min, edp_.th_max);
  851. printf("max_p: %f, qw: %f, ptc: %fn",
  852. (double) edv_.cur_max_p, edp_.q_w, edp_.ptc);
  853. printf("qlim: %d, idletime: %fn", qlim_, idletime_);
  854. printf("mark_p: %f, use_mark_p: %dn", edp_.mark_p, edp_.use_mark_p);
  855. printf("=========n");
  856. }
  857. void REDQueue::print_edv()
  858. {
  859. printf("v_a: %f, v_b: %fn", edv_.v_a, edv_.v_b);
  860. }
  861. void REDQueue::print_summarystats()
  862. {
  863. //double now = Scheduler::instance().clock();
  864. printf("True average queue: %5.3f", true_ave_);
  865. if (qib_) 
  866. printf(" (in bytes)");
  867.         printf(" time: %5.3fn", total_time_);
  868. }
  869. /************************************************************/
  870. /*
  871.  * This procedure is obsolete, and only included for backward compatibility.
  872.  * The new procedure is REDQueue::estimator
  873.  */ 
  874. /*
  875.  * Compute the average queue size.
  876.  * The code contains two alternate methods for this, the plain EWMA
  877.  * and the Holt-Winters method.
  878.  * nqueued can be bytes or packets
  879.  */
  880. void REDQueue::run_estimator(int nqueued, int m)
  881. {
  882. double f, f_sl, f_old;
  883. f = edv_.v_ave;
  884. f_sl = edv_.v_slope;
  885. #define RED_EWMA
  886. #ifdef RED_EWMA
  887. while (--m >= 1) {
  888. f_old = f;
  889. f *= 1.0 - edp_.q_w;
  890. }
  891. f_old = f;
  892. f *= 1.0 - edp_.q_w;
  893. f += edp_.q_w * nqueued;
  894. #endif
  895. #ifdef RED_HOLT_WINTERS
  896. while (--m >= 1) {
  897. f_old = f;
  898. f += f_sl;
  899. f *= 1.0 - edp_.q_w;
  900. f_sl *= 1.0 - 0.5 * edp_.q_w;
  901. f_sl += 0.5 * edp_.q_w * (f - f_old);
  902. }
  903. f_old = f;
  904. f += f_sl;
  905. f *= 1.0 - edp_.q_w;
  906. f += edp_.q_w * nqueued;
  907. f_sl *= 1.0 - 0.5 * edp_.q_w;
  908. f_sl += 0.5 * edp_.q_w * (f - f_old);
  909. #endif
  910. edv_.v_ave = f;
  911. edv_.v_slope = f_sl;
  912. }