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

通讯编程

开发平台:

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.  * ns-2 code written by: Sanjeewa Athuraliya (sanjeewa@caltech.edu)
  36.  *                       Caltech, Pasadena,
  37.  *  CA 91125
  38.  *                       Victor Li
  39.  *                       University of Melbourne, Parkville
  40.  *                       Vic., Australia.
  41.  *
  42.  * Ref: Active Queue Management (REM), IEEE Network, May/June 2001.
  43.  *      http://netlab.caltech.edu
  44.  */
  45. #include <math.h>
  46. #include <sys/types.h>
  47. #include "config.h"
  48. #include "template.h"
  49. #include "random.h"
  50. #include "flags.h"
  51. #include "delay.h"
  52. #include "rem.h"
  53. #include <iostream>
  54. static class REMClass : public TclClass {
  55. public:
  56. REMClass() : TclClass("Queue/REM") {}
  57. TclObject* create(int, const char*const*) {
  58. return (new REMQueue);
  59. }
  60. } class_rem;
  61. void REMQueue :: set_update_timer()
  62. {
  63. rem_timer_.resched(remp_.p_updtime);
  64. }
  65. void REMQueue :: timeout()
  66. {
  67. //do price update
  68. run_updaterule();
  69. set_update_timer();
  70. }
  71. void REMTimer :: expire (Event *e) {
  72.  a_->timeout();
  73. }
  74. REMQueue::REMQueue() : link_(NULL), tchan_(0), rem_timer_(this) 
  75. {
  76. bind("gamma_", &remp_.p_gamma);
  77. bind("phi_", &remp_.p_phi);
  78. bind("inw_", &remp_.p_inw);
  79. bind("mean_pktsize_", &remp_.p_pktsize); 
  80. bind("pupdtime_", &remp_.p_updtime); 
  81. bind("pbo_", &remp_.p_bo); 
  82. bind("prob_", &remv_.v_prob);     // dropping probability
  83. bind("curq_", &curq_);     // current queue size
  84. bind("pmark_", &pmark_);       //number of packets being marked 
  85. bind_bool("markpkts_", &markpkts_); /* Whether to mark or drop?  Default is drop */
  86. bind_bool("qib_", &qib_); /* queue in bytes? */ 
  87. q_ = new PacketQueue();     // underlying queue
  88. pq_ = q_;
  89. reset();
  90. #ifdef notdef
  91. print_remp();
  92. print_remv();
  93. #endif
  94. }
  95. void REMQueue::reset()
  96. {
  97. /*
  98.  * Compute the "packet time constant" if we know the
  99.  * link bandwidth.  The ptc is the max number of 
  100.  * pkts per second which can be placed on the link.
  101.  * The link bw is given in bits/sec, so scale psize
  102.  * accordingly.
  103.  */
  104.  
  105. if (link_)
  106. remp_.p_ptc = link_->bandwidth() / (8.0 * remp_.p_pktsize);
  107. remv_.v_pl = 0.0;
  108. remv_.v_prob = 0.0;
  109. remv_.v_in = 0.0;
  110.   remv_.v_ave = 0.0;
  111. remv_.v_count = 0.0;
  112. remv_.v_pl1 = 0.0;
  113. remv_.v_pl2 = 0.0;
  114. remv_.v_in1 = 0.0;
  115. remv_.v_in2 = 0.0;
  116. pmark_ = 0.0;
  117. bcount_ = 0; 
  118. //Queue::reset();
  119. set_update_timer();
  120. }
  121. /*
  122.  * Compute the average input rate, the price and the marking prob..
  123.  */
  124. void REMQueue::run_updaterule()
  125. {
  126. double in, in_avg, nqueued, pl, pr;
  127.         // link price, the congestion measure
  128. pl = remv_.v_pl;
  129. // in is the number of bytes (if qib_ is true) or packets (otherwise)
  130. // arriving at the link (input rate) during one update time interval
  131. in = remv_.v_count;
  132.        
  133. // in_avg is the low pss filtered input rate
  134. // which is in bytes if qib_ is true and in packets otherwise.
  135. in_avg = remv_.v_ave;
  136.   
  137. in_avg *= (1.0 - remp_.p_inw);
  138. if (qib_) {
  139. in_avg += remp_.p_inw*in/remp_.p_pktsize; 
  140. nqueued = bcount_/remp_.p_pktsize; 
  141.         }
  142. else {
  143. in_avg += remp_.p_inw*in;
  144. nqueued = q_ -> length();
  145. }
  146. // c measures the maximum number of packets that 
  147. // could be sent during one update interval.
  148. double c  = remp_.p_updtime*remp_.p_ptc;
  149. pl = pl + remp_.p_gamma*( in_avg + 0.1*(nqueued-remp_.p_bo) - c );
  150. if ( pl < 0.0) {
  151.     pl = 0.0;
  152. }
  153. double pow1 = pow (remp_.p_phi, -pl);
  154. pr = 1.0-pow1;
  155. remv_.v_count = 0.0;
  156. remv_.v_ave = in_avg;
  157. remv_.v_pl = pl;
  158. remv_.v_prob = pr;
  159. }
  160. /*
  161.  * Return the next packet in the queue for transmission.
  162.  */
  163. Packet* REMQueue::deque() 
  164. {
  165. Packet *p = q_->deque();
  166. if (p != 0) {
  167. bcount_ -= hdr_cmn::access(p)->size ();
  168. }
  169. if (markpkts_) {
  170. double u = Random::uniform();
  171. if (p!=0) {
  172. double pro = remv_.v_prob;
  173. if (qib_) {
  174. int size = hdr_cmn::access(p)->size ();
  175. pro = remv_.v_prob*size/remp_.p_pktsize; 
  176. }
  177.     if ( u <= pro ) {
  178. hdr_flags* hf = hdr_flags::access(p);
  179. if(hf->ect() == 1) { 
  180. hf->ce() = 1; 
  181. pmark_++;
  182. }
  183. }
  184. }
  185. }
  186. double qlen = qib_ ? bcount_ : q_->length();
  187. curq_ = (int) qlen;
  188. return (p);
  189. }
  190. /*
  191.  * Receive a new packet arriving at the queue.
  192.  * The packet is dropped if the maximum queue size is exceeded.
  193.  */
  194. void REMQueue::enque(Packet* pkt)
  195. {
  196. hdr_cmn* ch = hdr_cmn::access(pkt);
  197. double qlen; 
  198. if (qib_) {
  199. remv_.v_count += ch->size();
  200. }
  201. else {
  202. ++remv_.v_count;
  203. }
  204. double qlim = qib_ ? (qlim_*remp_.p_pktsize) : qlim_ ;
  205. q_ -> enque(pkt);
  206. bcount_ += ch->size();
  207. qlen = qib_ ? bcount_ : q_->length();
  208. if (qlen >= qlim) {
  209. q_->remove(pkt);
  210. bcount_ -= ch->size();
  211. drop(pkt);
  212. }
  213. else  {
  214. if (!markpkts_) {
  215. double u = Random::uniform(); 
  216. double pro = remv_.v_prob;
  217. if (qib_) {
  218. pro = remv_.v_prob*ch->size()/remp_.p_pktsize; 
  219. }
  220. if ( u <= pro ) {
  221. q_->remove(pkt);
  222. bcount_ -= ch->size();
  223. drop(pkt);
  224. }     
  225. }
  226. }
  227. qlen = qib_ ? bcount_ : q_->length();
  228. curq_ = (int) qlen;
  229. }
  230. int REMQueue::command(int argc, const char*const* argv)
  231. {
  232. Tcl& tcl = Tcl::instance();
  233. if (argc == 2) {
  234. if (strcmp(argv[1], "reset") == 0) {
  235. reset();
  236. return (TCL_OK);
  237. }
  238. } else if (argc == 3) {
  239. // attach a file for variable tracing
  240. if (strcmp(argv[1], "attach") == 0) {
  241. int mode;
  242. const char* id = argv[2];
  243. tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
  244. if (tchan_ == 0) {
  245. tcl.resultf("REM: trace: can't attach %s for writing", id);
  246. return (TCL_ERROR);
  247. }
  248. return (TCL_OK);
  249. }
  250. // tell REM about link stats
  251. if (strcmp(argv[1], "link") == 0) {
  252. LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
  253. if (del == 0) {
  254. tcl.resultf("REM: no LinkDelay object %s",
  255. argv[2]);
  256. return(TCL_ERROR);
  257. }
  258. // set ptc now
  259. link_ = del;
  260. remp_.p_ptc = link_->bandwidth() /
  261. (8. * remp_.p_pktsize);
  262. return (TCL_OK);
  263. }
  264. if (!strcmp(argv[1], "packetqueue-attach")) {
  265. delete q_;
  266. if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
  267. return (TCL_ERROR);
  268. else {
  269. pq_ = q_;
  270. return (TCL_OK);
  271. }
  272. }
  273. }
  274. return (Queue::command(argc, argv));
  275. }
  276. /*
  277.  * Routine called by TracedVar facility when variables change values.
  278.  * Currently used to trace values of avg queue size, drop probability,
  279.  * and the instantaneous queue size seen by arriving packets.
  280.  * Note that the tracing of each var must be enabled in tcl to work.
  281.  */
  282. void
  283. REMQueue::trace(TracedVar* v)
  284. {
  285. char wrk[500];
  286. const char *p;
  287. if (((p = strstr(v->name(), "ave")) == NULL) &&
  288.     ((p = strstr(v->name(), "prob")) == NULL) &&
  289.     ((p = strstr(v->name(), "curq")) == NULL)) {
  290. fprintf(stderr, "REM:unknown trace var %sn",
  291. v->name());
  292. return;
  293. }
  294. if (tchan_) {
  295. int n;
  296. double t = Scheduler::instance().clock();
  297. if (*p == 'c') {
  298. sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
  299. } else {
  300. sprintf(wrk, "%c %g %g", *p, t,
  301. double(*((TracedDouble*) v)));
  302. }
  303. n = strlen(wrk);
  304. wrk[n] = 'n'; 
  305. wrk[n+1] = 0;
  306. (void)Tcl_Write(tchan_, wrk, n+1);
  307. }
  308. return; 
  309. }
  310. /* for debugging help */
  311. void REMQueue::print_remp()
  312. {
  313. printf("=========n");
  314. }
  315. void REMQueue::print_remv()
  316. {
  317. printf("=========n");
  318. }