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

通讯编程

开发平台:

Visual C++

  1. /* -*-  Mode:C++; c-basic-offset:4; tab-width:4; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1994 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. /* Marking scheme proposed by Kunniyur and Srikant in "Decentralized Adaptive
  35. *    ECN Algorithms" published in the Proceedings of Infocom2000, Tel-Aviv, 
  36. *    Israel, March 2000.
  37. * Basic Idea of the AVQ (Adaptive Virtual Queue) Algorithm
  38. * --------------------------------------------------------
  39. * The scheme involves having a virtual queue at each link with the same
  40. * arrival rate as the original queue, but with the service rate scaled
  41. * down by some factor (ecnlim_). The buffer capacity remains the same,
  42. * but if needed we can also scale the buffer capacity by come constant
  43. * (buflim_). When a packet is dropped from the virtual queue, mark a
  44. * packet at the front of the real queue. Although in this implemetation,
  45. * a "drop-tail" function is used in the VIRTUAL QUEUE to mark packets in
  46. * the original queue, any algorithm (like RED) can be used in the
  47. * virtual queue to signal congestion. The capacity of the virtual queue
  48. * is adapted periodically to guarantee loss-free service. 
  49. * The update of the virtual capacity (capacity of the virtual queue) is
  50. * done using a token-bucket. For implentation details, please refer to
  51. * the Sigcomm 2001 paper titled "Analysis and Design of an Adaptive
  52. * Virtual Queue (AVQ) algorithm for Active Queue Management (AQM). 
  53. * The virtual queue length can be taken in packets or in bytes. If the
  54. * packet sizes are not fixed, then it is recommended to use bytes
  55. * instead of packets as units of length. If the variable (qib_) is set,
  56. * then the virtual queue is measured in bytes, else it is measured in
  57. * packets and the mean packet size is set to 1000. 
  58. *                          -Srisankar
  59. * ********************************************************************  
  60. * Options in the AVQ algorithm code:
  61. * ----------------------------------
  62. * * ecnlim_ -> This parameter specifies the capacity of the virtual 
  63. *              queue as a fraction of the capcity of the original queue.
  64. * * buflim_ -> This parameter specifies the buffer capacity of the
  65. *              virtual queue as a fraction of the buffer capacity of the
  66. *              original queue.
  67. * * queue_in_bytes_ -> Indicates whether you want to measure the queue
  68. *                      in bytes or packets. 
  69. * * markpkts_ -> Set to 1 if router wants to emply marking for that
  70. *                link. Set to 0, if dropping is preferred. 
  71. * * markfront_ -> Set to 1 if mark from front policy is employed. Usually
  72. *                 set to zero.   
  73. * * mean_pktsize- -> The mean packet size is set to 1000.
  74. * * gamma -> This parameter specifies the desired arrival rate at the link.
  75. * ********************************************************************  
  76. */
  77. #ifndef lint
  78. static const char rcsid[] =
  79.     "@(#) $Header: /cvsroot/nsnam/ns-2/queue/vq.cc,v 1.6 2006/12/17 15:21:59 mweigle Exp $ (LBL)";
  80. #endif
  81. #include "flags.h"
  82. #include "delay.h"
  83. #include "vq.h"
  84. #include "math.h"
  85. static class VqClass : public TclClass {
  86. public:
  87. VqClass() : TclClass("Queue/Vq") {}
  88. TclObject* create(int argc, const char*const* argv) {
  89. if (argc==5) 
  90. return (new Vq(argv[4]));
  91. else
  92. return (new Vq("Drop"));
  93. }
  94. } class_vq;
  95. Vq::Vq(const char * trace) : link_(NULL), EDTrace(NULL), tchan_(0){
  96. q_ = new PacketQueue;
  97. pq_ = q_;
  98. bind_bool("drop_front_", &drop_front_);
  99. bind("ecnlim_", &ecnlim_); //  = ctilde/c ; Initial value set to 0.8
  100. bind("buflim_", &buflim_); /* Fraction of the original buffer that the VQ buffer has. Default is 1.0 */
  101. bind_bool("queue_in_bytes_", &qib_);  // boolean: q in bytes?
  102. bind("gamma_", &gamma_); // Defines the utilization. Default is 0.98
  103. bind_bool("markpkts_", &markpkts_); /* Whether to mark or drop?  Default is drop */
  104. bind_bool("markfront_", &markfront_); /* Mark from front?  Deafult is false */
  105. bind("mean_pktsize_", &mean_pktsize_);  // avg pkt size
  106. bind("curq_", &curq_);          // current queue size
  107. vq_len = 0.0;
  108. prev_time = 0.0;
  109. vqprev_time = 0.0;
  110. alpha2 = 0.15; // Determines how fast we adapt at the link
  111. Pktdrp = 0; /* Useful if we are dropping pkts instead of marking */
  112. firstpkt = 1;
  113. qlength = 0; /* Tracks the queue length */
  114. }
  115. int Vq::command(int argc, const char*const* argv) {
  116. Tcl& tcl = Tcl::instance();
  117.   if (argc == 3) {
  118.   if (strcmp(argv[1], "link") == 0) {
  119.   LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
  120.   if (del == 0) {
  121.   return(TCL_ERROR);
  122.   }
  123.   // set capacity now
  124. link_ = del;
  125.   c_ = del->bandwidth();
  126.   return (TCL_OK);
  127.   }
  128.   if (!strcmp(argv[1], "packetqueue-attach")) {
  129.   delete q_;
  130.   if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
  131.   return (TCL_ERROR);
  132.   else {
  133.   pq_ = q_;
  134.   return (TCL_OK);
  135.   }
  136.   }
  137. // attach a file for variable tracing
  138. if (strcmp(argv[1], "attach") == 0) {
  139. int mode;
  140. const char* id = argv[2];
  141. tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
  142. if (tchan_ == 0) {
  143. tcl.resultf("Vq: trace: can't attach %s for writing", id);
  144. return (TCL_ERROR);
  145. }
  146. return (TCL_OK);
  147. }
  148.   }
  149.   return Queue::command(argc, argv);
  150. }
  151. void Vq::enque(Packet* p)
  152. {
  153. q_->enque(p);
  154. hdr_cmn* ch = hdr_cmn::access(p);
  155. qlength = qlength + (qib_ * ch->size()) + (1 - qib_);
  156. if(firstpkt){
  157. /* Changing c_ so that it is measured in packets per second */
  158. /* Assuming packets are fixed size with 1000 bytes */
  159. if(qib_) c_ = c_ / (8.0);
  160. else c_ = c_ / (8.0 * mean_pktsize_);
  161. firstpkt = 0;
  162. ctilde = c_ * ecnlim_;
  163. prev_time = Scheduler::instance().clock();
  164. vqprev_time = Scheduler::instance().clock();
  165. }
  166. /* Update the Virtual Queue length */ 
  167. curr_time = Scheduler::instance().clock();
  168. vq_len = vq_len - (ctilde * (curr_time - vqprev_time));
  169. vqprev_time = curr_time;
  170. if(vq_len < 0.0) vq_len = 0.0;
  171. vq_len = vq_len + qib_ * ch->size() + (1 - qib_);
  172. /* checkPacketForECN() returns 1 if we need to mark or drop a packet*/
  173. if(checkPacketForECN()){
  174. if(markpkts_)
  175. markPacketForECN(p);
  176. else
  177. dropPacketForECN(p);
  178. }
  179. /* Adaptation of the virtual capacity, tilde(C) */
  180. /* Use the token bucket system  */
  181. /* Scale alpha appropriately if qib_ is set */
  182. if(Pktdrp == 0){ // Do the adaptation
  183. /* Pktdrp = 0 always when marking */
  184. ctilde = ctilde + alpha2*gamma_*c_*(curr_time - prev_time) - alpha2*(1.0 - qib_) - alpha2*qib_*ch->size();
  185. if(ctilde > c_) ctilde = c_;
  186. if(ctilde <0.0) ctilde = 0.0;
  187. prev_time = curr_time;
  188. }
  189. else{ // No adaptation and reset Pktdrp
  190. Pktdrp = 0;
  191. }
  192. if (qlength > qlim_*( 1 - qib_ + qib_*mean_pktsize_)) {
  193. if (drop_front_) { /* remove from head of queue */
  194. if(q_->length() > 0){
  195. Packet *pp = q_->head();
  196. qlength = qlength - qib_ * ch->size() - (1 - qib_);
  197. q_->remove(pp); 
  198. drop(pp);
  199. }
  200. else {
  201. q_->remove(p);
  202. qlength = qlength - qib_ * ch->size() - (1 - qib_);
  203. drop(p);
  204. }
  205. }
  206. curq_ = qlength;
  207. }
  208. /* This is a simple DropTail on the VQ. However, one Can add 
  209.    any AQM scheme on VQ here */
  210. int Vq::checkPacketForECN(){
  211. if(vq_len > (buflim_ * qlim_ * ( 1 - qib_ + qib_*mean_pktsize_))){
  212. return 1;
  213. }
  214. else{
  215. return 0;
  216. }
  217. }
  218. /* Implements a simple mark-tail/mark-front here. If needed other
  219.    mechanism (like mark-random ) can also be implemented */ 
  220. void  Vq::markPacketForECN(Packet* pkt)
  221. {
  222. /* Update the VQ length */
  223. hdr_cmn* ch = hdr_cmn::access(pkt);
  224. vq_len = vq_len - qib_ * ch->size() - (1.0 - qib_);
  225. if(vq_len < 0.0) vq_len = 0.0;
  226. if(markfront_){ 
  227. Packet *pp = q_->head();
  228. hdr_flags* hf = hdr_flags::access(pp);
  229. if(hf->ect() == 1)  // ECN capable flow
  230. hf->ce() = 1; // Mark the TCP Flow;
  231. }
  232. else{ 
  233. /* Mark the current packet and forget about it */
  234. hdr_flags* hdr = hdr_flags::access(pkt);
  235. if(hdr->ect() == 1)  // ECN capable flow
  236. hdr->ce() = 1; // For TCP Flows
  237. }
  238. }
  239. /* Implements a simple drop-tail/drop-front here. If needed other
  240.    mechanism (like drop-random ) can also be implemented */ 
  241. void Vq::dropPacketForECN(Packet* pkt) 
  242. {
  243. /* Update the VQ length */
  244. hdr_cmn* ch = hdr_cmn::access(pkt);
  245. vq_len = vq_len - qib_ * ch->size() - (1.0 - qib_);
  246. if(vq_len < 0.0) vq_len = 0.0;
  247. if(drop_front_){
  248. /* If drop from front is enabled, then deque a 
  249.    packet from the front of the queue and drop it ...
  250.    Usually not recommended */ 
  251. if(q_->length() > 0 ){
  252. Packet *pp = q_->head();
  253. qlength = qlength - qib_ * ch->size() - (1 - qib_);
  254. q_->remove(pp); /* The queue length is taken care of in
  255.  in the deque program */
  256. drop(pp);
  257. }
  258. }
  259. else{
  260. q_->remove(pkt);
  261. qlength = qlength - qib_ * ch->size() - (1 - qib_);
  262. drop(pkt);
  263. }
  264. /* If one is dropping packets, one needs to be careful about 
  265.    measuring the total arrival rate to calculate the virtual
  266.    capacity, tilde(C). In this case, the arrival rate that is
  267.    taken into the adaptation algorithm is the accepted rate and
  268.    not the offered rate. */
  269. Pktdrp = 1; // Do not update tilde(C)
  270. }
  271. Packet* Vq::deque()
  272. {
  273. if((q_->length() > 0)){
  274. Packet *ppp = q_->deque();
  275. hdr_cmn* ch = hdr_cmn::access(ppp);
  276. qlength = qlength - qib_ * ch->size() - (1 - qib_);
  277. curq_ = qlength;
  278. return ppp;
  279. }
  280. else return q_->deque();
  281. }
  282. /*
  283.  * Routine called by TracedVar facility when variables change values.
  284.  * Currently used to trace value of 
  285.  * the instantaneous queue size seen by arriving packets.
  286.  * Note that the tracing of each var must be enabled in tcl to work.
  287.  */
  288. void Vq::trace(TracedVar* v)
  289. {
  290. char wrk[500];
  291. const char *p;
  292. if ((p = strstr(v->name(), "curq")) == NULL) {
  293. fprintf(stderr, "Vq:unknown trace var %sn", v->name());
  294. return;
  295. }
  296. if (tchan_) {
  297. int n;
  298. double t = Scheduler::instance().clock();
  299. // XXX: be compatible with nsv1 RED trace entries
  300. if (*p == 'c') {
  301. sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
  302. } else {
  303. sprintf(wrk, "%c %g %g", *p, t, double(*((TracedDouble*) v)));
  304. }
  305. n = strlen(wrk);
  306. wrk[n] = 'n'; 
  307. wrk[n+1] = 0;
  308. (void)Tcl_Write(tchan_, wrk, n+1);
  309. }
  310. return; 
  311. }