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

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1997 The 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 Network Research
  17.  *  Group at Lawrence Berkeley National 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. #ifndef lint
  35. static const char rcsid[] =
  36.     "@(#) $Header: /cvsroot/nsnam/ns-2/queue/cbq.cc,v 1.28 2005/07/27 01:13:44 tomh Exp $ (LBL)";
  37. #endif
  38. //
  39. // new version of cbq using the ns-2 fine-grain
  40. // objects.  Also, re-orginaize CBQ to look more like how
  41. // its description reads in ToN v3n4 and simplify extraneous stuff -KF
  42. //
  43. // there is a 1-1 relationship between classes and queues, except
  44. // that internal nodes in the LS tree don't have queues
  45. //
  46. // Definitions:
  47. // overlimit:
  48. // recently used more than allocated link-sharing bandwidth
  49. // (in bytes/sec averaged over specified interval)
  50. //
  51. // level:
  52. // all leaves are at level 1
  53. // interior nodes are at a level 1 greater than
  54. //     the highest level number of any of its children
  55. //
  56. // unsatisfied:
  57. // (leaf): underlimit and has demand
  58. // (interior): underlimit and has some descendant w/demand
  59. // [either a leaf or interior descendant]
  60. //
  61. // formal link-sharing:
  62. // class may continue unregulated if either:
  63. // 1> class is underlimit or at-limit
  64. // 2> class has a under(at)-limit ancestor at level i
  65. // and no unsatisfied classes at any levels < i
  66. //
  67. // ancestors-only link-sharing:
  68. // class may continue unregulated if either:
  69. // 1> class is under/at limit
  70. // 2> class has an UNDER-limit ancestor [at-limit not ok]
  71. //
  72. // top-level link-sharing:
  73. // class may continue unregulated if either:
  74. // 1> class is under/at limit
  75. // 2> class has an UNDER-limit ancestor with level
  76. // <= the value of "top-level"
  77. #include "queue-monitor.h"
  78. #include "queue.h"
  79. #include "delay.h"
  80. #define MAXPRIO 10 /* # priorities in scheduler */
  81. #define MAXLEVEL 32 /* max depth of link-share tree(s) */
  82. #define LEAF_LEVEL 1 /* level# for leaves */
  83. #define POWEROFTWO 16
  84. class CBQueue;
  85. class CBQClass : public Connector {
  86. public:
  87. friend class CBQueue;
  88. friend class WRR_CBQueue;
  89. CBQClass();
  90. int command(int argc, const char*const* argv);
  91. void recv(Packet*, Handler*); // from upstream classifier
  92. protected:
  93. void newallot(double); // change an allotment
  94. void update(Packet*, double); // update when sending pkt
  95. void delayed(double); // when overlim/can't borrow
  96. int satisfied(double); // satisfied?
  97. int  demand(); // do I have demand?
  98. int  leaf(); // am I a leaf class?
  99. int ancestor(CBQClass*p); // are we an ancestor of p?
  100. int desc_with_demand(); // any desc has demand?
  101. CBQueue* cbq_; // the CBQueue I'm part of
  102. CBQClass* peer_; // peer at same sched prio level
  103. CBQClass* level_peer_; // peer at same LS level
  104. CBQClass* lender_; // parent I can borrow from
  105. Queue* q_; // underlying queue
  106. QueueMonitor* qmon_; // monitor for the queue
  107. double allotment_; // frac of link bw
  108. double maxidle_; // bound on idle time
  109. double maxrate_; // bound on bytes/sec rate
  110. double extradelay_; // adjustment to delay
  111. double last_time_; // last xmit time this class
  112. double undertime_; // will become unsat/eligible
  113. double avgidle_; // EWMA of idle
  114. int pri_; // priority for scheduler
  115. int level_; // depth in link-sharing tree
  116. int delayed_; // boolean-was I delayed
  117. int bytes_alloc_; // for wrr only
  118. int permit_borrowing_; // ok to borrow?
  119. };
  120. class CBQueue : public Queue {
  121. public:
  122. CBQueue();
  123. void reset();
  124. void enque(Packet*) { abort(); }
  125. void recv(Packet*, Handler*);
  126. LinkDelay* link() const { return (link_); }
  127. CBQClass* level(int n) const { return levels_[n]; }
  128. Packet* deque();
  129. virtual int command(int argc, const char*const* argv);
  130. virtual void addallot(int, double) { }
  131. Packet* pending_pkt() const { return (pending_pkt_); }
  132. void sched();
  133. int toplevel() { // are we using toplevel?
  134. //  return (eligible_ == &eligible_toplevel);
  135. return (eligible_ == TOPLEVEL);
  136. }
  137. void toplevel_arrival(CBQClass*, double);
  138. protected:
  139. Event intr_;
  140. int algorithm(const char *);
  141. virtual int insert_class(CBQClass*);
  142. int send_permitted(CBQClass*, double);
  143. CBQClass* find_lender(CBQClass*, double);
  144. void toplevel_departure(CBQClass*, double);
  145. CBQClass* last_lender_;
  146. Packet* pending_pkt_; // queued packet
  147. LinkDelay* link_; // managed link
  148. CBQClass* active_[MAXPRIO]; // classes at prio of index
  149. CBQClass* levels_[MAXLEVEL+1]; // LL of classes per level
  150. int maxprio_; // highest prio# seen
  151. int maxpkt_; // largest pkt (used by WRR)
  152. int maxlevel_; // highest level# seen
  153. int toplevel_; // for top-level LS
  154. //  typedef int (CBQueue::*eligible_type_)(CBQClass*, double);
  155. //  eligible_type_ eligible_; // eligible function
  156. enum eligible_type_ { NONE, FORMAL, ANCESTORS, TOPLEVEL };
  157. eligible_type_ eligible_;
  158. int eligible_formal(CBQClass*, double);
  159. int eligible_ancestors(CBQClass*, double) { return (1); }
  160. int eligible_toplevel(CBQClass* cl, double) {
  161. return(cl->level_ <= toplevel_);
  162. }
  163. };
  164. static class CBQQueueClass : public TclClass {
  165. public:
  166. CBQQueueClass() : TclClass("Queue/CBQ") { }
  167. TclObject* create(int, const char*const*) {
  168. return (new CBQueue);
  169. }
  170. } class_cbq;
  171. static class CBQClassClass : public TclClass {
  172. public:
  173. CBQClassClass() : TclClass("CBQClass") { }
  174. TclObject* create(int, const char*const*) {
  175. return (new CBQClass);
  176. }
  177. } class_cbqclass;
  178. CBQueue::CBQueue() : last_lender_(NULL), pending_pkt_(NULL), link_(NULL),
  179. maxprio_(-1), maxpkt_(-1), maxlevel_(-1), toplevel_(MAXLEVEL),
  180. //  eligible_((eligible_type_)NULL)
  181. eligible_(NONE)
  182. {
  183. bind("maxpkt_", &maxpkt_);
  184. memset(active_, '', sizeof(active_));
  185. memset(levels_, '', sizeof(levels_));
  186. }
  187. /*
  188.  * schedule ourselves, used by CBQClass::recv
  189.  */
  190. void
  191. CBQueue::sched()
  192. {
  193. Scheduler& s = Scheduler::instance();
  194. blocked_ = 1;
  195. s.schedule(&qh_, &intr_, 0);
  196. }
  197. /*
  198.  * invoked by passing a packet from one of our managed queues
  199.  * basically provides a queue of one packet
  200.  */
  201. void
  202. CBQueue::recv(Packet* p, Handler*)
  203. {
  204. if (pending_pkt_ != NULL)
  205. abort();
  206. blocked_ = 1;
  207. pending_pkt_ = p;
  208. }
  209. void
  210. CBQueue::reset()
  211. {
  212. // don't do anything
  213. // in particular, don't let Queue::reset() call
  214. // our deque() method
  215. }
  216. int
  217. CBQueue::algorithm(const char *arg)
  218. {
  219. if (*arg == '0' || (strcmp(arg, "ancestor-only") == 0)) {
  220. //  eligible_ = &eligible_ancestors;
  221. eligible_ = ANCESTORS;
  222. return (1);
  223. } else if (*arg == '1' || (strcmp(arg, "top-level") == 0)) {
  224. //  eligible_ = &eligible_toplevel;
  225. eligible_ = TOPLEVEL;
  226. return (1);
  227. } else if (*arg == '2' || (strcmp(arg, "formal") == 0)) {
  228. //  eligible_ = &eligible_formal;
  229. eligible_ = FORMAL;
  230. return (1);
  231. } else if (*arg == '3' || (strcmp(arg, "old-formal") == 0)) {
  232. fprintf(stderr, "CBQ: old-formal LS not supportedn");
  233. return (-1);
  234. }
  235. return (-1);
  236. }
  237. /*
  238.  *
  239.  * toplevel_arrival: called only using TL link sharing on arrival
  240.  * toplevel_departure: called only using TL link sharing on departure
  241.  */
  242. void
  243. CBQueue::toplevel_departure(CBQClass *cl, double now)
  244. {
  245. if (toplevel_ >= last_lender_->level_) {
  246. if ((cl->qmon_->pkts() <= 1) ||
  247.     last_lender_->undertime_ > now) {
  248. toplevel_ = MAXLEVEL;
  249. } else {
  250. toplevel_ = last_lender_->level_;
  251. }
  252. }
  253. }
  254. void
  255. CBQueue::toplevel_arrival(CBQClass *cl, double now)
  256. {
  257. if (toplevel_ > 1) {
  258. if (cl->undertime_ < now)
  259. toplevel_ = 1;
  260. else if (toplevel_ > 2 && cl->permit_borrowing_ && cl->lender_ != NULL) {
  261. if (cl->lender_->undertime_ < now)
  262. toplevel_ = 2;
  263. }
  264. }
  265. }
  266. /*
  267.  * deque: this gets invoked by way of our downstream
  268.  * (i.e. linkdelay) neighbor doing a 'resume' on us
  269.  * via our handler (by Queue::resume()), or by our upstream
  270.  * neighbor when it gives us a packet when we were
  271.  * idle
  272.  */
  273. Packet *
  274. CBQueue::deque()
  275. {
  276. Scheduler& s = Scheduler::instance();
  277. double now = s.clock();
  278. CBQClass* first = NULL;
  279. CBQClass* eligible = NULL;
  280. CBQClass* cl;
  281. register int prio;
  282. Packet* rval;
  283. int none_found = 0;
  284. /*
  285.  * prio runs from 0 .. maxprio_
  286.  *
  287.  * round-robin through all the classes at priority 'prio'
  288.  *  if any class is ok to send, resume it's queue
  289.  * go on to next lowest priority (higher prio nuber) and repeat
  290.  * [lowest priority number is the highest priority]
  291.  */
  292. for (prio = 0; prio <= maxprio_; prio++) {
  293. // see if there is any class at this prio
  294. if ((cl = active_[prio]) == NULL) {
  295. // nobody at this prio level
  296. continue;
  297. }
  298. // look for underlimit peer with something to send
  299. do {
  300. // anything to send?
  301. if (cl->demand()) {
  302. if (first == NULL && cl->permit_borrowing_ && cl->lender_ != NULL)
  303. first = cl;
  304. if (send_permitted(cl, now)) {
  305. // ok to send
  306. eligible = cl;
  307. goto found;
  308. } else {
  309. // not ok right now
  310. cl->delayed(now);
  311. }
  312. }
  313. cl = cl->peer_; // move to next at same prio
  314. } while (cl != active_[prio]);
  315. }
  316. // did not find anyone so let first go
  317. // eligible will be NULL at this point
  318. if (first != NULL) {
  319. none_found = 1;
  320. eligible = first;
  321. }
  322. found:
  323. if (eligible != NULL) {
  324. active_[eligible->pri_] = eligible->peer_;
  325. // eligible->q_->unblock();
  326. eligible->q_->resume(); // fills in pending
  327. if (pending_pkt_ && !none_found) {
  328. eligible->update(pending_pkt_, now);
  329. if (toplevel())
  330. toplevel_departure(eligible, now);
  331. }
  332. }
  333. rval = pending_pkt_;
  334. pending_pkt_ = NULL;
  335. return (rval);
  336. }
  337. /*
  338.  * we are permitted to send if either
  339.  * 1> we are not overlimit (ie we are underlimit or at limit)
  340.  * 2> one of the varios algorithm-dependent conditions is met
  341.  *
  342.  * if we are permitted, who did we borrow from? [could be ourselves
  343.  * if we were not overlimit]
  344.  */
  345. int CBQueue::send_permitted(CBQClass* cl, double now)
  346. {
  347. if (cl->undertime_ < now) {
  348. cl->delayed_ = 0;
  349. last_lender_ = cl;
  350. return (1);
  351. } else if (cl->permit_borrowing_ &&
  352.    (((cl = find_lender(cl, now)) != NULL))) {
  353. last_lender_ = cl;
  354. return (1);
  355. }
  356. return (0);
  357. }
  358. /*
  359.  * find_lender(class, time)
  360.  *
  361.  * find a lender for the provided class according to the
  362.  * various algorithms
  363.  *
  364.  */
  365. CBQClass*
  366. CBQueue::find_lender(CBQClass* cl, double now)
  367. {
  368. if ((!cl->permit_borrowing_) || ((cl = cl->lender_) == NULL))
  369. return (NULL); // no ancestor to borrow from
  370. while (cl != NULL) {
  371. // skip past overlimit ancestors
  372. // if using TL and we're above the TL limit
  373. // do early out
  374. if (cl->undertime_ > now) {
  375. if (toplevel() && cl->level_ > toplevel_)
  376. return (NULL);
  377. cl = cl->lender_;
  378. continue;
  379. }
  380. // found what may be an eligible
  381. // lender, check using per-algorithm eligibility
  382. // criteria
  383. // XXX we explicitly invoke this indirect method with
  384. // the "this" pointer because MS VC++ can't parse it
  385. // without it...
  386. //  if ((this->*eligible_)(cl, now))
  387. //  return (cl);
  388. switch (eligible_) {
  389. case TOPLEVEL:
  390. if (eligible_toplevel(cl, now))
  391. return (cl);
  392. break;
  393. case ANCESTORS:
  394. if (eligible_ancestors(cl, now))
  395. return (cl);
  396. break;
  397. case FORMAL:
  398. if (eligible_formal(cl, now))
  399. return (cl);
  400. break;
  401. default:
  402. fprintf(stderr, "Wrong eligible_n");
  403. abort();
  404. }
  405. cl = cl->lender_;
  406. }
  407. return (cl);
  408. }
  409. /*
  410.  * rule #2 for formal link-sharing
  411.  * class must have no unsatisfied classes below it
  412.  */
  413. int
  414. CBQueue::eligible_formal(CBQClass *cl, double now)
  415. {
  416. int level;
  417. CBQClass *p;
  418. // check from leaf level to (cl->level - 1)
  419. for (level = LEAF_LEVEL; level < cl->level_; level++) {
  420. p = levels_[level];
  421. while (p != NULL) {
  422. if (!p->satisfied(now))
  423. return (0);
  424. p = p->level_peer_;
  425. }
  426. }
  427. return (1);
  428. }
  429. /*
  430.  * insert a class into the cbq object
  431.  */
  432. int
  433. CBQueue::insert_class(CBQClass *p)
  434. {
  435. p->cbq_ = this;
  436. /*
  437.  * Add to circularly-linked list "active_"
  438.  *    of peers for the given priority.
  439.  */
  440. if (p->pri_ < 0 || p->pri_ > (MAXPRIO-1)) {
  441. fprintf(stderr, "CBQ class %s has invalid pri %dn",
  442. p->name(), p->pri_);
  443. return (-1);
  444. }
  445. if (p->q_ != NULL) {
  446. // only leaf nodes (which have associated queues)
  447. // are scheduled
  448. if (active_[p->pri_] != NULL) {
  449. p->peer_ = active_[p->pri_]->peer_;
  450. active_[p->pri_]->peer_ = p;
  451. } else {
  452. p->peer_ = p;
  453. active_[p->pri_] = p;
  454. }
  455. if (p->pri_ > maxprio_)
  456. maxprio_ = p->pri_;
  457. }
  458. /*
  459.  * Compute maxrate from allotment.
  460.  * convert to bytes/sec
  461.  * and store the highest prio# we've seen
  462.  */
  463. if (p->allotment_ < 0.0 || p->allotment_ > 1.0) {
  464. fprintf(stderr, "CBQ class %s has invalid allot %fn",
  465. p->name(), p->allotment_);
  466. return (-1);
  467. }
  468. if (link_ == NULL) {
  469. fprintf(stderr, "CBQ obj %s has no link!n", name());
  470. return (-1);
  471. }
  472. if (link_->bandwidth() <= 0.0) {
  473. fprintf(stderr, "CBQ obj %s has invalid link bw %f on link %sn",
  474. name(), link_->bandwidth(), link_->name());
  475. return (-1);
  476. }
  477. p->maxrate_ = p->allotment_ * (link_->bandwidth() / 8.0);
  478. addallot(p->pri_, p->allotment_);
  479. /*
  480.  * Add to per-level list
  481.  * and store the highest level# we've seen
  482.  */
  483. if (p->level_ <= 0 || p->level_ > MAXLEVEL) {
  484. fprintf(stderr, "CBQ class %s has invalid level %dn",
  485. p->name(), p->level_);
  486. return (-1);
  487. }
  488. p->level_peer_ = levels_[p->level_];
  489. levels_[p->level_] = p;
  490. if (p->level_ > maxlevel_)
  491. maxlevel_ = p->level_;
  492. /*
  493.  * Check that parent and borrow linkage are acyclic.
  494.  */
  495. #ifdef notdef
  496. check_for_cycles(CBQClass::parent);
  497. check_for_cycles(CBQClass::borrow);
  498. #endif
  499. return 0;
  500. }
  501. int CBQueue::command(int argc, const char*const* argv)
  502. {
  503. Tcl& tcl = Tcl::instance();
  504. if (argc == 3) {
  505. if (strcmp(argv[1], "insert-class") == 0) {
  506. CBQClass *cl = (CBQClass*)TclObject::lookup(argv[2]);
  507. if (cl == 0) {
  508. tcl.resultf("CBQ: no class object %s",
  509. argv[2]);
  510. return (TCL_ERROR);
  511. }
  512. if (insert_class(cl) < 0) {
  513. tcl.resultf("CBQ: trouble inserting class %s",
  514. argv[2]);
  515. return (TCL_ERROR);
  516. }
  517. return (TCL_OK);
  518. }
  519. if (strcmp(argv[1], "link") == 0) {
  520. LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
  521. if (del == 0) {
  522. tcl.resultf("CBQ: no LinkDelay object %s",
  523. argv[2]);
  524. return(TCL_ERROR);
  525. }
  526. link_ = del;
  527. return (TCL_OK);
  528. }
  529. if (strcmp(argv[1], "algorithm") == 0) {
  530. if (algorithm(argv[2]) < 0)
  531. return (TCL_ERROR);
  532. return (TCL_OK);
  533. }
  534. }
  535. return (Queue::command(argc, argv));
  536. }
  537. class WRR_CBQueue : public CBQueue {
  538. public:
  539. WRR_CBQueue() {
  540. memset(M_, '', sizeof(M_));
  541. memset(alloc_, '', sizeof(alloc_));
  542. memset(cnt_, '', sizeof(cnt_));
  543. }
  544. void addallot(int prio, double diff) {
  545. alloc_[prio] += diff;
  546. setM();
  547. }
  548. protected:
  549. Packet *deque();
  550. int insert_class(CBQClass*);
  551. void setM();
  552. double alloc_[MAXPRIO];
  553. double M_[MAXPRIO];
  554. int cnt_[MAXPRIO]; // # classes at prio of index
  555. int command(int argc, const char*const* argv);
  556. };
  557. static class WRR_CBQQueueClass : public TclClass {
  558. public:
  559. WRR_CBQQueueClass() : TclClass("Queue/CBQ/WRR") { }
  560. TclObject* create(int, const char*const*) {
  561. return (new WRR_CBQueue);
  562. }
  563. } class_wrr_cbq;
  564. int WRR_CBQueue::command(int argc, const char*const* argv)
  565. {
  566. Tcl& tcl = Tcl::instance();
  567. if (strcmp(argv[1], "insert-class") == 0) {
  568. CBQClass *cl = (CBQClass*)TclObject::lookup(argv[2]);
  569. if (cl == 0) {
  570. tcl.resultf("WRR-CBQ: no class object %s",
  571. argv[2]);
  572. return (TCL_ERROR);
  573. }
  574. if (insert_class(cl) < 0) {
  575. tcl.resultf("WRR-CBQ: trouble inserting class %s",
  576. argv[2]);
  577. return (TCL_ERROR);
  578. }
  579. return (TCL_OK);
  580. }
  581. return (CBQueue::command(argc, argv));
  582. }
  583. Packet *
  584. WRR_CBQueue::deque()
  585. {
  586. double now = Scheduler::instance().clock();
  587. CBQClass* first = NULL;
  588. CBQClass* eligible = NULL;
  589. CBQClass* next_eligible = NULL;
  590. CBQClass* cl;
  591. register int prio;
  592. int deficit, done;
  593. int none_found = 0;
  594. Packet* rval;
  595. /*
  596.  * prio runs from 0 .. maxprio_
  597.  *
  598.  * round-robin through all the classes at priority 'prio'
  599.  *      if any class is ok to send, resume it's queue
  600.  * go on to next lowest priority (higher prio nuber) and repeat
  601.  * [lowest priority number is the highest priority]
  602.  */
  603. for (prio = 0; prio <= maxprio_; prio++) {
  604. // see if there is any class at this prio
  605. if ((cl = active_[prio]) == NULL) {
  606. // nobody at this prio level
  607. continue;
  608. }
  609.                 /* 
  610.                  * The WRR round for this priority level starts at deficit 0.
  611.                  *  The round ends if some class is found that is ready
  612.                  *  to send and has positive "bytes_alloc_".
  613.                  * Status advances to deficit 1 if some class was found  
  614.                  *  that was able to send except for insufficient
  615.                  *  "bytes_alloc_".
  616.                  * If status was deficit 1 at the end of the first round,
  617.                  *  then status advances to deficit 2.
  618.                  * Another round of WRR is then begun at deficit 2, looking
  619.                  *  for a class to send even with insufficient "bytes_alloc_".
  620.                  */
  621. deficit = done = 0;
  622. while (!done) {
  623.                         // look for class at this priority level ok to send
  624. do {
  625.                                 // set up "weight" for WRR
  626. if (deficit < 2 && cl->bytes_alloc_ <= 0)
  627. cl->bytes_alloc_ +=
  628. (int)(cl->allotment_ * M_[cl->pri_]);
  629.                                 // anything to send?
  630. if (cl->demand()) {
  631. if (first == NULL && cl->permit_borrowing_ && cl->lender_ != NULL)
  632. first = cl;
  633. if (!send_permitted(cl, now)) {
  634.                                                 // not ok to send right now
  635. cl->delayed(now);
  636. } else {
  637.                                                 // ok to send, if class has
  638.                                                 //  enough "weight" for WRR.
  639. int bytes = cl->bytes_alloc_;
  640. if (bytes > 0 || deficit > 1) {
  641. eligible = cl;
  642. goto found;
  643. } else
  644. deficit = 1;
  645. }
  646. }
  647. cl->bytes_alloc_ = 0;
  648. cl = cl->peer_;
  649. } while (cl != active_[prio] && cl != 0);
  650. if (deficit == 1)
  651. deficit = 2;
  652. else
  653. done = 1;
  654. }
  655. }
  656.         // did not find anyone so let first go
  657. if ((eligible == NULL) && first != NULL) {
  658. none_found = 1;
  659. eligible = first;
  660. }
  661. found:
  662. // do accounting
  663. if (eligible != NULL) {
  664. next_eligible = eligible->peer_;
  665. eligible->q_->resume();
  666. if (pending_pkt_ != NULL && !none_found) {
  667. // reduce our alloc
  668. // by the packet size.  If we're
  669. // still positive, we get to go again
  670. int bytes = eligible->bytes_alloc_;
  671. hdr_cmn* hdr = hdr_cmn::access(pending_pkt_);
  672. if (bytes > 0) {
  673. eligible->bytes_alloc_ -= hdr->size();
  674. }
  675. bytes = eligible->bytes_alloc_;
  676. if (bytes > 0) {
  677. next_eligible = eligible;
  678. }
  679. eligible->update(pending_pkt_, now);
  680. if (toplevel())
  681. toplevel_departure(eligible, now);
  682. }
  683. active_[eligible->pri_] = next_eligible;
  684. }
  685. rval = pending_pkt_;
  686. pending_pkt_ = NULL;
  687. return (rval);
  688. }
  689. int
  690. WRR_CBQueue::insert_class(CBQClass *p)
  691. {
  692. if (CBQueue::insert_class(p) < 0)
  693. return (-1);
  694. ++cnt_[p->pri_];
  695. setM();
  696. return (0);
  697. }
  698. void
  699. WRR_CBQueue::setM()
  700. {
  701. int i;
  702. for (i = 0; i <= maxprio_; i++) {
  703. if (alloc_[i] > 0.0)
  704.                         // allocate "cnt_[i] * maxpkt_" bytes to each
  705.                         //  priority level:
  706.                         M_[i] = cnt_[i] * maxpkt_ * 1.0 / alloc_[i];
  707.                         // allocate "alloc_[i] * 2.0 * cnt_[i] * maxpkt_"
  708.                         //  bytes to each priority level:
  709.                         //  M_[i] = 2.0 * cnt_[i] * maxpkt_;
  710. else
  711. M_[i] = 0.0;
  712. if (M_[i] < 0.0) {
  713. fprintf(stderr, "M_[i]: %f, cnt_[i]: %d, maxpkt_: %d, alloc_[i]: %fn",
  714. M_[i], cnt_[i], maxpkt_, alloc_[i]);
  715. abort();
  716. }
  717. }
  718. return;
  719. }
  720. /******************** CBQClass definitions **********************/
  721. CBQClass::CBQClass() : cbq_(0), peer_(0), level_peer_(0), lender_(0),
  722. q_(0), qmon_(0), allotment_(0.0), maxidle_(-1.0), maxrate_(0.0),
  723. extradelay_(0.0), last_time_(0.0), undertime_(0.0), avgidle_(0.0),
  724. pri_(-1), level_(-1), delayed_(0), bytes_alloc_(0),
  725. permit_borrowing_(1)
  726. {
  727. /* maxidle_ is no longer bound; it is now a method interface */
  728. bind("priority_", &pri_);
  729. bind("level_", &level_);
  730. bind("extradelay_", &extradelay_);
  731. bind_bool("okborrow_", &permit_borrowing_);
  732. if (pri_ < 0 || pri_ > (MAXPRIO-1))
  733. abort();
  734. if (level_ <= 0 || level_ > MAXLEVEL)
  735. abort();
  736. }
  737. // why can't these two be inline (?)
  738. int
  739. CBQClass::demand()
  740. {
  741. return (qmon_->pkts() > 0);
  742. }
  743. int
  744. CBQClass::leaf()
  745. {
  746. return (level_ == LEAF_LEVEL);
  747. }
  748. /*
  749.  * we are upstream from the queue
  750.  * the queue should be unblocked if the downstream
  751.  * cbq is not busy and blocked otherwise
  752.  *
  753.  * we get our packet from the classifier, because of
  754.  * this the handler is NULL.  Besides the queue downstream
  755.  * from us (Queue::recv) ignores the handler anyhow
  756.  * 
  757.  */
  758. void
  759. CBQClass::recv(Packet *pkt, Handler *h)
  760. {
  761. if (cbq_->toplevel()) {
  762. Scheduler* s;
  763. if ((s = &Scheduler::instance()) != NULL)
  764. cbq_->toplevel_arrival(this, s->clock());
  765. }
  766. send(pkt, h); // queue packet downstream
  767. if (!cbq_->blocked()) {
  768. cbq_->sched();
  769. }
  770. return;
  771. }
  772. /*
  773.  * update a class' statistics and all parent classes
  774.  * up to the root
  775.  */
  776. void CBQClass::update(Packet* p, double now)
  777. {
  778. double idle, avgidle;
  779. hdr_cmn* hdr = hdr_cmn::access(p);
  780. int pktsize = hdr->size();
  781. double tx_time = cbq_->link()->txtime(p);
  782. double fin_time = now + tx_time;
  783. idle = (fin_time - last_time_) - (pktsize / maxrate_);
  784. avgidle = avgidle_;
  785. avgidle += (idle - avgidle) / POWEROFTWO;
  786. if (maxidle_ < 0) {
  787. fprintf(stderr,
  788. "CBQClass: warning: maxidle_ not configured!n");
  789. } else if (avgidle > maxidle_)
  790. avgidle = maxidle_;
  791. avgidle_ = avgidle;
  792. if (avgidle <= 0) {
  793. undertime_ = fin_time + tx_time *
  794. (1.0 / allotment_ - 1.0);
  795. undertime_ += (1-POWEROFTWO) * avgidle;
  796. }
  797. last_time_ = fin_time;
  798. // tail-recurse up to root of tree performing updates
  799. if (lender_)
  800. lender_->update(p, now);
  801. return;
  802. }
  803. /*
  804.  * satisfied: is this class satisfied?
  805.  */
  806. int
  807. CBQClass::satisfied(double now)
  808. {
  809. if (leaf()) {
  810. /* leaf is unsat if underlimit with backlog */
  811. if (undertime_ < now && demand())
  812. return (0);
  813. else
  814. return (1);
  815. }
  816. if (undertime_ < now && desc_with_demand())
  817. return (0);
  818. return (1);
  819. }
  820. /*
  821.  * desc_with_demand: is there a descendant of this class with demand
  822.  * really, is there a leaf which is a descendant of me with
  823.  * a backlog
  824.  */
  825. int
  826. CBQClass::desc_with_demand()
  827. {
  828. CBQClass *p = cbq_->level(LEAF_LEVEL);
  829. for (; p != NULL; p = p->level_peer_) {
  830. if (p->demand() && ancestor(p))
  831. return (1);
  832. }
  833. return (0);
  834. }
  835. /*
  836.  * happens when a class is unable to send because it
  837.  * is being regulated
  838.  */
  839. void CBQClass::delayed(double now)
  840. {
  841. double delay = undertime_ - now + extradelay_;
  842. if (delay > 0 && !delayed_) {
  843. undertime_ += extradelay_;
  844. undertime_ -= (1-POWEROFTWO) * avgidle_;
  845. delayed_ = 1;
  846. }
  847. }
  848. /*
  849.  * return 1 if we are an ancestor of p, 0 otherwise
  850.  */
  851. int
  852. CBQClass::ancestor(CBQClass *p)
  853. {
  854. if (!p->permit_borrowing_ || p->lender_ == NULL)
  855. return (0);
  856. else if (p->lender_ == this)
  857. return (1);
  858. return (ancestor(p->lender_));
  859. }
  860. /*
  861.  * change an allotment
  862.  */
  863. void
  864. CBQClass::newallot(double bw)
  865. {
  866.         if (allotment_ < 0)
  867.                 allotment_ = 0;
  868.         if (bw < 0)
  869.                 bw = 0;
  870. maxrate_ = bw * ( cbq_->link()->bandwidth() / 8.0 );
  871. double diff = bw - allotment_;
  872. allotment_ = bw;
  873. cbq_->addallot(pri_, diff);
  874. return;
  875. }
  876. /*
  877.  * OTcl Interface
  878.  */
  879. /* 
  880.  * $class1 parent $class2
  881.  * $class1 borrow $class2
  882.  * $class1 qdisc $queue
  883.  * $class1 allot
  884.  * $class1 allot new-bw
  885.  */
  886. int CBQClass::command(int argc, const char*const* argv)
  887. {
  888. Tcl& tcl = Tcl::instance();
  889. if (argc == 2) {
  890. if (strcmp(argv[1], "allot") == 0) {
  891. tcl.resultf("%g", allotment_);
  892. return (TCL_OK);
  893. }
  894. if (strcmp(argv[1], "cbq") == 0) {
  895. if (cbq_ != NULL)
  896. tcl.resultf("%s", cbq_->name());
  897. else
  898. tcl.resultf("");
  899. return(TCL_OK);
  900. }
  901. if (strcmp(argv[1], "qdisc") == 0) {
  902. if (q_ != NULL)
  903. tcl.resultf("%s", q_->name());
  904. else
  905. tcl.resultf("");
  906. return (TCL_OK);
  907. }
  908. if (strcmp(argv[1], "qmon") == 0) {
  909. if (qmon_ != NULL)
  910. tcl.resultf("%s", qmon_->name());
  911. else
  912. tcl.resultf("");
  913. return (TCL_OK);
  914. }
  915. } else if (argc == 3) {
  916. // for now these are the same
  917. if ((strcmp(argv[1], "parent") == 0)) {
  918. if (strcmp(argv[2], "none") == 0) {
  919. lender_ = NULL;
  920. return (TCL_OK);
  921. }
  922. lender_ = (CBQClass*)TclObject::lookup(argv[2]);
  923. if (lender_ != NULL)
  924. return (TCL_OK);
  925. return (TCL_ERROR);
  926. }
  927. if (strcmp(argv[1], "qdisc") == 0) {
  928. q_ = (Queue*) TclObject::lookup(argv[2]);
  929. if (q_ != NULL)
  930. return (TCL_OK);
  931. tcl.resultf("couldn't find object %s",
  932. argv[2]);
  933. return (TCL_ERROR);
  934. }
  935. if (strcmp(argv[1], "qmon") == 0) {
  936. qmon_ = (QueueMonitor*) TclObject::lookup(argv[2]);
  937. if (qmon_ != NULL)
  938. return (TCL_OK);
  939. return (TCL_ERROR);
  940. }
  941. if (strcmp(argv[1], "allot") == 0) {
  942. double bw = atof(argv[2]);
  943. if (bw < 0.0)
  944. return (TCL_ERROR);
  945. if (allotment_ != 0.0) {
  946. tcl.resultf(" class %s already has allotment of %f!",
  947.     name(), allotment_);
  948. return (TCL_ERROR);
  949. }
  950. allotment_ = bw;
  951. return (TCL_OK);
  952. }
  953. if (strcmp(argv[1], "newallot") == 0) {
  954. double bw = atof(argv[2]);
  955. if (bw < 0.0)
  956. return (TCL_ERROR);
  957. newallot(bw);
  958. return (TCL_OK);
  959. }
  960. if (strcmp(argv[1], "maxidle") == 0) {
  961. double m = atof(argv[2]);
  962. if (m < 0.0) {
  963. tcl.resultf("invalid maxidle value %s (must be non-negative)",
  964.     argv[2]);
  965. return (TCL_ERROR);
  966. }
  967. maxidle_ = m;
  968. return (TCL_OK);
  969. }
  970. }
  971. return (Connector::command(argc, argv));
  972. }