pi.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.  */
  36. /*
  37.  * Based on PI controller described in:
  38.  * C. Hollot, V. Misra, D. Towsley and W. Gong. 
  39.  * On Designing Improved Controllers for AQM Routers
  40.  * Supporting TCP Flows, 
  41.  * INFOCOMM 2001. 
  42.  */
  43. #include <math.h>
  44. #include <sys/types.h>
  45. #include "config.h"
  46. #include "template.h"
  47. #include "random.h"
  48. #include "flags.h"
  49. #include "delay.h"
  50. #include "pi.h"
  51. static class PIClass : public TclClass {
  52. public:
  53. PIClass() : TclClass("Queue/PI") {}
  54. TclObject* create(int argc, const char*const* argv) {
  55. if (argc==5) 
  56. return (new PIQueue(argv[4]));
  57. else
  58. return (new PIQueue("Drop"));
  59. }
  60. } class_pi;
  61. PIQueue::PIQueue(const char * trace) : CalcTimer(this), link_(NULL), q_(NULL),
  62. qib_(0), de_drop_(NULL), EDTrace(NULL), tchan_(0), curq_(0),
  63. edp_(), edv_(), first_reset_(1)
  64. {
  65. if (strlen(trace) >=20) {
  66. printf("trace type too long - allocate more space to traceType in pi.h and recompilen");
  67. exit(0);
  68. }
  69. strcpy(traceType, trace);
  70. bind_bool("bytes_", &edp_.bytes);     // boolean: use bytes?
  71. bind_bool("queue_in_bytes_", &qib_);     // boolean: q in bytes?
  72. bind("a_", &edp_.a);
  73. bind("b_", &edp_.b);    
  74. bind("w_", &edp_.w);   
  75. bind("qref_", &edp_.qref);   
  76. bind("mean_pktsize_", &edp_.mean_pktsize);  // avg pkt size
  77. bind_bool("setbit_", &edp_.setbit);     // mark instead of drop
  78. bind("prob_", &edv_.v_prob);     // dropping probability
  79. bind("curq_", &curq_);     // current queue size
  80. q_ = new PacketQueue();     // underlying queue
  81. pq_ = q_;
  82. reset();
  83. }
  84. void PIQueue::reset()
  85. {
  86. //double now = Scheduler::instance().clock();
  87. /*
  88. if (qib_ && first_reset_ == 1) {
  89. edp_.qref = edp_.qref*edp_.mean_pktsize;
  90. }
  91. */
  92. edv_.count = 0;
  93. edv_.count_bytes = 0;
  94. edv_.v_prob = 0;
  95. edv_.qold = 0;
  96. curq_ = 0;
  97. calculate_p();
  98. Queue::reset();
  99. }
  100. void PIQueue::enque(Packet* pkt)
  101. {
  102. //double now = Scheduler::instance().clock();
  103. hdr_cmn* ch = hdr_cmn::access(pkt);
  104. ++edv_.count;
  105. edv_.count_bytes += ch->size();
  106. int droptype = DTYPE_NONE;
  107. int qlen = qib_ ? q_->byteLength() : q_->length();
  108. curq_ = qlen; // helps to trace queue during arrival, if enabled
  109. int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_;
  110. if (qlen >= qlim) {
  111. droptype = DTYPE_FORCED;
  112. }
  113. else {
  114. if (drop_early(pkt, qlen)) {
  115. droptype = DTYPE_UNFORCED;
  116. }
  117. }
  118. if (droptype == DTYPE_UNFORCED) {
  119. Packet *pkt_to_drop = pickPacketForECN(pkt);
  120. if (pkt_to_drop != pkt) {
  121. q_->enque(pkt);
  122. q_->remove(pkt_to_drop);
  123. pkt = pkt_to_drop; /* XXX okay because pkt is not needed anymore */
  124. }
  125. if (de_drop_ != NULL) {
  126. if (EDTrace != NULL) 
  127. ((Trace *)EDTrace)->recvOnly(pkt);
  128. de_drop_->recv(pkt);
  129. }
  130. else {
  131. drop(pkt);
  132. }
  133. } else {
  134. q_->enque(pkt);
  135. if (droptype == DTYPE_FORCED) {
  136. pkt = pickPacketToDrop();
  137. q_->remove(pkt);
  138. drop(pkt);
  139. edv_.count = 0;
  140. edv_.count_bytes = 0;
  141. }
  142. }
  143. return;
  144. }
  145. double PIQueue::calculate_p()
  146. {
  147. //double now = Scheduler::instance().clock();
  148. double p;
  149. int qlen = qib_ ? q_->byteLength() : q_->length();
  150. if (qib_) {
  151. p=edp_.a*(qlen*1.0/edp_.mean_pktsize-edp_.qref)-
  152. edp_.b*(edv_.qold*1.0/edp_.mean_pktsize-edp_.qref)+
  153. edv_.v_prob;
  154. }
  155. else {
  156. p=edp_.a*(qlen-edp_.qref)-edp_.b*(edv_.qold-edp_.qref)+edv_.v_prob;
  157. }
  158. if (p < 0) p = 0;
  159. if (p > 1) p = 1;
  160. edv_.v_prob = p;
  161. edv_.qold = qlen;
  162. CalcTimer.resched(1.0/edp_.w);
  163. return p;
  164. }
  165. int PIQueue::drop_early(Packet* pkt, int qlen)
  166. {
  167. //double now = Scheduler::instance().clock();
  168. hdr_cmn* ch = hdr_cmn::access(pkt);
  169. double p = edv_.v_prob; 
  170. if (edp_.bytes) {
  171. p = p*ch->size()/edp_.mean_pktsize;
  172. if (p > 1) p = 1; 
  173. }
  174. double u = Random::uniform();
  175. if (u <= p) {
  176. edv_.count = 0;
  177. edv_.count_bytes = 0;
  178. hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt));
  179. if (edp_.setbit && hf->ect()) {
  180. hf->ce() = 1;  // mark Congestion Experienced bit
  181. return (0); // no drop
  182. } else {
  183. return (1); // drop
  184. }
  185. }
  186. return (0); // no DROP/mark
  187. }
  188. Packet* PIQueue::pickPacketForECN(Packet* pkt)
  189. {
  190. return pkt; /* pick the packet that just arrived */
  191. }
  192. Packet* PIQueue::pickPacketToDrop() 
  193. {
  194. int victim;
  195. victim = q_->length() - 1;
  196. return(q_->lookup(victim)); 
  197. }
  198. Packet* PIQueue::deque()
  199. {
  200. Packet *p;
  201. p = q_->deque();
  202. curq_ = qib_ ? q_->byteLength() : q_->length(); // helps to trace queue during arrival, if enabled
  203. return (p);
  204. }
  205. int PIQueue::command(int argc, const char*const* argv)
  206. {
  207. Tcl& tcl = Tcl::instance();
  208. if (argc == 2) {
  209. if (strcmp(argv[1], "reset") == 0) {
  210. reset();
  211. return (TCL_OK);
  212. }
  213. if (strcmp(argv[1], "early-drop-target") == 0) {
  214. if (de_drop_ != NULL)
  215. tcl.resultf("%s", de_drop_->name());
  216. return (TCL_OK);
  217. }
  218. if (strcmp(argv[1], "edrop-trace") == 0) {
  219. if (EDTrace != NULL) {
  220. tcl.resultf("%s", EDTrace->name());
  221. }
  222. else {
  223. tcl.resultf("0");
  224. }
  225. return (TCL_OK);
  226. }
  227. if (strcmp(argv[1], "trace-type") == 0) {
  228. tcl.resultf("%s", traceType);
  229. return (TCL_OK);
  230. }
  231. else if (argc == 3) {
  232. // attach a file for variable tracing
  233. if (strcmp(argv[1], "attach") == 0) {
  234. int mode;
  235. const char* id = argv[2];
  236. tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
  237. if (tchan_ == 0) {
  238. tcl.resultf("PI: trace: can't attach %s for writing", id);
  239. return (TCL_ERROR);
  240. }
  241. return (TCL_OK);
  242. }
  243. // tell PI about link stats
  244. if (strcmp(argv[1], "link") == 0) {
  245. LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
  246. if (del == 0) {
  247. tcl.resultf("PI: no LinkDelay object %s", argv[2]);
  248. return(TCL_ERROR);
  249. }
  250. link_ = del;
  251. return (TCL_OK);
  252. }
  253. if (strcmp(argv[1], "early-drop-target") == 0) {
  254. NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
  255. if (p == 0) {
  256. tcl.resultf("no object %s", argv[2]);
  257. return (TCL_ERROR);
  258. }
  259. de_drop_ = p;
  260. return (TCL_OK);
  261. }
  262. if (strcmp(argv[1], "edrop-trace") == 0) {
  263. NsObject * t  = (NsObject *)TclObject::lookup(argv[2]);
  264. if (t == 0) {
  265. tcl.resultf("no object %s", argv[2]);
  266. return (TCL_ERROR);
  267. }
  268. EDTrace = t;
  269. return (TCL_OK);
  270. }
  271. if (!strcmp(argv[1], "packetqueue-attach")) {
  272. delete q_;
  273. if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
  274. return (TCL_ERROR);
  275. else {
  276. pq_ = q_;
  277. return (TCL_OK);
  278. }
  279. }
  280. }
  281. return (Queue::command(argc, argv));
  282. }
  283. void PIQueue::trace(TracedVar* v)
  284. {
  285. char wrk[500];
  286. const char *p;
  287. if (((p = strstr(v->name(), "prob")) == NULL) &&
  288.     ((p = strstr(v->name(), "curq")) == NULL)) {
  289. fprintf(stderr, "PI:unknown trace var %sn", v->name());
  290. return;
  291. }
  292. if (tchan_) {
  293. int n;
  294. double t = Scheduler::instance().clock();
  295. // XXX: be compatible with nsv1 PI trace entries
  296. if (*p == 'c') {
  297. sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
  298. } else {
  299. sprintf(wrk, "%c %g %g", *p, t, double(*((TracedDouble*) v)));
  300. }
  301. n = strlen(wrk);
  302. wrk[n] = 'n'; 
  303. wrk[n+1] = 0;
  304. (void)Tcl_Write(tchan_, wrk, n+1);
  305. }
  306. return; 
  307. }
  308. void PICalcTimer::expire(Event *)
  309. {
  310. a_->calculate_p();
  311. }