00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifndef lint
00036 static const char rcsid[] =
00037 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/cbq.cc,v 1.28 2005/07/27 01:13:44 tomh Exp $ (LBL)";
00038 #endif
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 #include "queue-monitor.h"
00082 #include "queue.h"
00083 #include "delay.h"
00084
00085 #define MAXPRIO 10
00086 #define MAXLEVEL 32
00087 #define LEAF_LEVEL 1
00088 #define POWEROFTWO 16
00089
00090 class CBQueue;
00091
00092 class CBQClass : public Connector {
00093 public:
00094 friend class CBQueue;
00095 friend class WRR_CBQueue;
00096
00097 CBQClass();
00098 int command(int argc, const char*const* argv);
00099 void recv(Packet*, Handler*);
00100
00101 protected:
00102
00103 void newallot(double);
00104 void update(Packet*, double);
00105 void delayed(double);
00106
00107 int satisfied(double);
00108 int demand();
00109 int leaf();
00110
00111 int ancestor(CBQClass*p);
00112 int desc_with_demand();
00113
00114 CBQueue* cbq_;
00115
00116 CBQClass* peer_;
00117 CBQClass* level_peer_;
00118 CBQClass* lender_;
00119
00120 Queue* q_;
00121 QueueMonitor* qmon_;
00122
00123 double allotment_;
00124 double maxidle_;
00125 double maxrate_;
00126 double extradelay_;
00127 double last_time_;
00128 double undertime_;
00129 double avgidle_;
00130 int pri_;
00131 int level_;
00132 int delayed_;
00133 int bytes_alloc_;
00134 int permit_borrowing_;
00135
00136 };
00137
00138 class CBQueue : public Queue {
00139 public:
00140 CBQueue();
00141 void reset();
00142 void enque(Packet*) { abort(); }
00143 void recv(Packet*, Handler*);
00144 LinkDelay* link() const { return (link_); }
00145 CBQClass* level(int n) const { return levels_[n]; }
00146 Packet* deque();
00147 virtual int command(int argc, const char*const* argv);
00148 virtual void addallot(int, double) { }
00149 Packet* pending_pkt() const { return (pending_pkt_); }
00150 void sched();
00151 int toplevel() {
00152
00153 return (eligible_ == TOPLEVEL);
00154 }
00155 void toplevel_arrival(CBQClass*, double);
00156 protected:
00157 Event intr_;
00158 int algorithm(const char *);
00159 virtual int insert_class(CBQClass*);
00160 int send_permitted(CBQClass*, double);
00161 CBQClass* find_lender(CBQClass*, double);
00162 void toplevel_departure(CBQClass*, double);
00163
00164 CBQClass* last_lender_;
00165 Packet* pending_pkt_;
00166 LinkDelay* link_;
00167
00168 CBQClass* active_[MAXPRIO];
00169 CBQClass* levels_[MAXLEVEL+1];
00170 int maxprio_;
00171 int maxpkt_;
00172 int maxlevel_;
00173 int toplevel_;
00174
00175
00176
00177 enum eligible_type_ { NONE, FORMAL, ANCESTORS, TOPLEVEL };
00178 eligible_type_ eligible_;
00179 int eligible_formal(CBQClass*, double);
00180 int eligible_ancestors(CBQClass*, double) { return (1); }
00181 int eligible_toplevel(CBQClass* cl, double) {
00182 return(cl->level_ <= toplevel_);
00183 }
00184 };
00185
00186 static class CBQQueueClass : public TclClass {
00187 public:
00188 CBQQueueClass() : TclClass("Queue/CBQ") { }
00189 TclObject* create(int, const char*const*) {
00190 return (new CBQueue);
00191 }
00192 } class_cbq;
00193
00194 static class CBQClassClass : public TclClass {
00195 public:
00196 CBQClassClass() : TclClass("CBQClass") { }
00197 TclObject* create(int, const char*const*) {
00198 return (new CBQClass);
00199 }
00200 } class_cbqclass;
00201
00202 CBQueue::CBQueue() : last_lender_(NULL), pending_pkt_(NULL), link_(NULL),
00203 maxprio_(-1), maxpkt_(-1), maxlevel_(-1), toplevel_(MAXLEVEL),
00204
00205 eligible_(NONE)
00206 {
00207 bind("maxpkt_", &maxpkt_);
00208 memset(active_, '\0', sizeof(active_));
00209 memset(levels_, '\0', sizeof(levels_));
00210 }
00211
00212
00213
00214
00215
00216 void
00217 CBQueue::sched()
00218 {
00219 Scheduler& s = Scheduler::instance();
00220 blocked_ = 1;
00221 s.schedule(&qh_, &intr_, 0);
00222 }
00223
00224
00225
00226
00227
00228
00229 void
00230 CBQueue::recv(Packet* p, Handler*)
00231 {
00232
00233 if (pending_pkt_ != NULL)
00234 abort();
00235
00236 blocked_ = 1;
00237 pending_pkt_ = p;
00238 }
00239
00240 void
00241 CBQueue::reset()
00242 {
00243
00244
00245
00246 }
00247
00248 int
00249 CBQueue::algorithm(const char *arg)
00250 {
00251
00252 if (*arg == '0' || (strcmp(arg, "ancestor-only") == 0)) {
00253
00254 eligible_ = ANCESTORS;
00255 return (1);
00256 } else if (*arg == '1' || (strcmp(arg, "top-level") == 0)) {
00257
00258 eligible_ = TOPLEVEL;
00259 return (1);
00260 } else if (*arg == '2' || (strcmp(arg, "formal") == 0)) {
00261
00262 eligible_ = FORMAL;
00263 return (1);
00264 } else if (*arg == '3' || (strcmp(arg, "old-formal") == 0)) {
00265 fprintf(stderr, "CBQ: old-formal LS not supported\n");
00266 return (-1);
00267 }
00268 return (-1);
00269 }
00270
00271
00272
00273
00274
00275
00276
00277 void
00278 CBQueue::toplevel_departure(CBQClass *cl, double now)
00279 {
00280 if (toplevel_ >= last_lender_->level_) {
00281 if ((cl->qmon_->pkts() <= 1) ||
00282 last_lender_->undertime_ > now) {
00283 toplevel_ = MAXLEVEL;
00284 } else {
00285 toplevel_ = last_lender_->level_;
00286 }
00287 }
00288 }
00289
00290 void
00291 CBQueue::toplevel_arrival(CBQClass *cl, double now)
00292 {
00293 if (toplevel_ > 1) {
00294 if (cl->undertime_ < now)
00295 toplevel_ = 1;
00296 else if (toplevel_ > 2 && cl->permit_borrowing_ && cl->lender_ != NULL) {
00297 if (cl->lender_->undertime_ < now)
00298 toplevel_ = 2;
00299 }
00300 }
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 Packet *
00312 CBQueue::deque()
00313 {
00314
00315 Scheduler& s = Scheduler::instance();
00316 double now = s.clock();
00317
00318 CBQClass* first = NULL;
00319 CBQClass* eligible = NULL;
00320 CBQClass* cl;
00321 register int prio;
00322 Packet* rval;
00323
00324 int none_found = 0;
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 for (prio = 0; prio <= maxprio_; prio++) {
00336
00337 if ((cl = active_[prio]) == NULL) {
00338
00339 continue;
00340 }
00341
00342
00343 do {
00344
00345 if (cl->demand()) {
00346 if (first == NULL && cl->permit_borrowing_ && cl->lender_ != NULL)
00347 first = cl;
00348 if (send_permitted(cl, now)) {
00349
00350 eligible = cl;
00351 goto found;
00352 } else {
00353
00354 cl->delayed(now);
00355 }
00356 }
00357 cl = cl->peer_;
00358 } while (cl != active_[prio]);
00359 }
00360
00361
00362 if (first != NULL) {
00363 none_found = 1;
00364 eligible = first;
00365 }
00366
00367 found:
00368 if (eligible != NULL) {
00369 active_[eligible->pri_] = eligible->peer_;
00370
00371 eligible->q_->resume();
00372 if (pending_pkt_ && !none_found) {
00373 eligible->update(pending_pkt_, now);
00374 if (toplevel())
00375 toplevel_departure(eligible, now);
00376 }
00377 }
00378 rval = pending_pkt_;
00379 pending_pkt_ = NULL;
00380
00381 return (rval);
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 int CBQueue::send_permitted(CBQClass* cl, double now)
00393 {
00394 if (cl->undertime_ < now) {
00395 cl->delayed_ = 0;
00396 last_lender_ = cl;
00397 return (1);
00398 } else if (cl->permit_borrowing_ &&
00399 (((cl = find_lender(cl, now)) != NULL))) {
00400 last_lender_ = cl;
00401 return (1);
00402 }
00403 return (0);
00404 }
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 CBQClass*
00415 CBQueue::find_lender(CBQClass* cl, double now)
00416 {
00417 if ((!cl->permit_borrowing_) || ((cl = cl->lender_) == NULL))
00418 return (NULL);
00419
00420 while (cl != NULL) {
00421
00422
00423
00424 if (cl->undertime_ > now) {
00425 if (toplevel() && cl->level_ > toplevel_)
00426 return (NULL);
00427 cl = cl->lender_;
00428 continue;
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 switch (eligible_) {
00440 case TOPLEVEL:
00441 if (eligible_toplevel(cl, now))
00442 return (cl);
00443 break;
00444 case ANCESTORS:
00445 if (eligible_ancestors(cl, now))
00446 return (cl);
00447 break;
00448 case FORMAL:
00449 if (eligible_formal(cl, now))
00450 return (cl);
00451 break;
00452 default:
00453 fprintf(stderr, "Wrong eligible_\n");
00454 abort();
00455 }
00456 cl = cl->lender_;
00457 }
00458 return (cl);
00459 }
00460
00461
00462
00463
00464
00465 int
00466 CBQueue::eligible_formal(CBQClass *cl, double now)
00467 {
00468 int level;
00469 CBQClass *p;
00470
00471
00472 for (level = LEAF_LEVEL; level < cl->level_; level++) {
00473 p = levels_[level];
00474 while (p != NULL) {
00475 if (!p->satisfied(now))
00476 return (0);
00477 p = p->level_peer_;
00478 }
00479 }
00480 return (1);
00481 }
00482
00483
00484
00485
00486
00487 int
00488 CBQueue::insert_class(CBQClass *p)
00489 {
00490 p->cbq_ = this;
00491
00492
00493
00494
00495
00496
00497 if (p->pri_ < 0 || p->pri_ > (MAXPRIO-1)) {
00498 fprintf(stderr, "CBQ class %s has invalid pri %d\n",
00499 p->name(), p->pri_);
00500 return (-1);
00501 }
00502
00503 if (p->q_ != NULL) {
00504
00505
00506 if (active_[p->pri_] != NULL) {
00507 p->peer_ = active_[p->pri_]->peer_;
00508 active_[p->pri_]->peer_ = p;
00509 } else {
00510 p->peer_ = p;
00511 active_[p->pri_] = p;
00512 }
00513 if (p->pri_ > maxprio_)
00514 maxprio_ = p->pri_;
00515 }
00516
00517
00518
00519
00520
00521
00522
00523 if (p->allotment_ < 0.0 || p->allotment_ > 1.0) {
00524 fprintf(stderr, "CBQ class %s has invalid allot %f\n",
00525 p->name(), p->allotment_);
00526 return (-1);
00527 }
00528
00529 if (link_ == NULL) {
00530 fprintf(stderr, "CBQ obj %s has no link!\n", name());
00531 return (-1);
00532 }
00533 if (link_->bandwidth() <= 0.0) {
00534 fprintf(stderr, "CBQ obj %s has invalid link bw %f on link %s\n",
00535 name(), link_->bandwidth(), link_->name());
00536 return (-1);
00537 }
00538
00539 p->maxrate_ = p->allotment_ * (link_->bandwidth() / 8.0);
00540 addallot(p->pri_, p->allotment_);
00541
00542
00543
00544
00545
00546
00547 if (p->level_ <= 0 || p->level_ > MAXLEVEL) {
00548 fprintf(stderr, "CBQ class %s has invalid level %d\n",
00549 p->name(), p->level_);
00550 return (-1);
00551 }
00552
00553 p->level_peer_ = levels_[p->level_];
00554 levels_[p->level_] = p;
00555 if (p->level_ > maxlevel_)
00556 maxlevel_ = p->level_;
00557
00558
00559
00560
00561 #ifdef notdef
00562 check_for_cycles(CBQClass::parent);
00563 check_for_cycles(CBQClass::borrow);
00564 #endif
00565 return 0;
00566 }
00567
00568 int CBQueue::command(int argc, const char*const* argv)
00569 {
00570
00571 Tcl& tcl = Tcl::instance();
00572 if (argc == 3) {
00573 if (strcmp(argv[1], "insert-class") == 0) {
00574 CBQClass *cl = (CBQClass*)TclObject::lookup(argv[2]);
00575 if (cl == 0) {
00576 tcl.resultf("CBQ: no class object %s",
00577 argv[2]);
00578 return (TCL_ERROR);
00579 }
00580 if (insert_class(cl) < 0) {
00581 tcl.resultf("CBQ: trouble inserting class %s",
00582 argv[2]);
00583 return (TCL_ERROR);
00584 }
00585 return (TCL_OK);
00586 }
00587 if (strcmp(argv[1], "link") == 0) {
00588 LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
00589 if (del == 0) {
00590 tcl.resultf("CBQ: no LinkDelay object %s",
00591 argv[2]);
00592 return(TCL_ERROR);
00593 }
00594 link_ = del;
00595 return (TCL_OK);
00596 }
00597 if (strcmp(argv[1], "algorithm") == 0) {
00598 if (algorithm(argv[2]) < 0)
00599 return (TCL_ERROR);
00600 return (TCL_OK);
00601 }
00602 }
00603 return (Queue::command(argc, argv));
00604 }
00605
00606 class WRR_CBQueue : public CBQueue {
00607 public:
00608 WRR_CBQueue() {
00609 memset(M_, '\0', sizeof(M_));
00610 memset(alloc_, '\0', sizeof(alloc_));
00611 memset(cnt_, '\0', sizeof(cnt_));
00612 }
00613 void addallot(int prio, double diff) {
00614 alloc_[prio] += diff;
00615 setM();
00616 }
00617 protected:
00618 Packet *deque();
00619 int insert_class(CBQClass*);
00620 void setM();
00621 double alloc_[MAXPRIO];
00622 double M_[MAXPRIO];
00623 int cnt_[MAXPRIO];
00624 int command(int argc, const char*const* argv);
00625 };
00626
00627 static class WRR_CBQQueueClass : public TclClass {
00628 public:
00629 WRR_CBQQueueClass() : TclClass("Queue/CBQ/WRR") { }
00630 TclObject* create(int, const char*const*) {
00631 return (new WRR_CBQueue);
00632 }
00633 } class_wrr_cbq;
00634
00635 int WRR_CBQueue::command(int argc, const char*const* argv)
00636 {
00637 Tcl& tcl = Tcl::instance();
00638 if (strcmp(argv[1], "insert-class") == 0) {
00639 CBQClass *cl = (CBQClass*)TclObject::lookup(argv[2]);
00640 if (cl == 0) {
00641 tcl.resultf("WRR-CBQ: no class object %s",
00642 argv[2]);
00643 return (TCL_ERROR);
00644 }
00645 if (insert_class(cl) < 0) {
00646 tcl.resultf("WRR-CBQ: trouble inserting class %s",
00647 argv[2]);
00648 return (TCL_ERROR);
00649 }
00650 return (TCL_OK);
00651 }
00652 return (CBQueue::command(argc, argv));
00653 }
00654
00655 Packet *
00656 WRR_CBQueue::deque()
00657 {
00658
00659 double now = Scheduler::instance().clock();
00660
00661 CBQClass* first = NULL;
00662 CBQClass* eligible = NULL;
00663 CBQClass* next_eligible = NULL;
00664 CBQClass* cl;
00665
00666 register int prio;
00667 int deficit, done;
00668 int none_found = 0;
00669
00670 Packet* rval;
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681 for (prio = 0; prio <= maxprio_; prio++) {
00682
00683 if ((cl = active_[prio]) == NULL) {
00684
00685 continue;
00686 }
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699 deficit = done = 0;
00700 while (!done) {
00701
00702 do {
00703
00704 if (deficit < 2 && cl->bytes_alloc_ <= 0)
00705 cl->bytes_alloc_ +=
00706 (int)(cl->allotment_ * M_[cl->pri_]);
00707
00708 if (cl->demand()) {
00709 if (first == NULL && cl->permit_borrowing_ && cl->lender_ != NULL)
00710 first = cl;
00711 if (!send_permitted(cl, now)) {
00712
00713 cl->delayed(now);
00714 } else {
00715
00716
00717 int bytes = cl->bytes_alloc_;
00718 if (bytes > 0 || deficit > 1) {
00719 eligible = cl;
00720 goto found;
00721 } else
00722 deficit = 1;
00723 }
00724 }
00725 cl->bytes_alloc_ = 0;
00726 cl = cl->peer_;
00727 } while (cl != active_[prio] && cl != 0);
00728 if (deficit == 1)
00729 deficit = 2;
00730 else
00731 done = 1;
00732 }
00733 }
00734
00735 if ((eligible == NULL) && first != NULL) {
00736 none_found = 1;
00737 eligible = first;
00738 }
00739
00740 found:
00741
00742 if (eligible != NULL) {
00743 next_eligible = eligible->peer_;
00744 eligible->q_->resume();
00745 if (pending_pkt_ != NULL && !none_found) {
00746
00747
00748
00749 int bytes = eligible->bytes_alloc_;
00750 hdr_cmn* hdr = hdr_cmn::access(pending_pkt_);
00751 if (bytes > 0) {
00752 eligible->bytes_alloc_ -= hdr->size();
00753 }
00754 bytes = eligible->bytes_alloc_;
00755 if (bytes > 0) {
00756 next_eligible = eligible;
00757 }
00758 eligible->update(pending_pkt_, now);
00759 if (toplevel())
00760 toplevel_departure(eligible, now);
00761 }
00762 active_[eligible->pri_] = next_eligible;
00763 }
00764 rval = pending_pkt_;
00765 pending_pkt_ = NULL;
00766
00767 return (rval);
00768 }
00769
00770 int
00771 WRR_CBQueue::insert_class(CBQClass *p)
00772 {
00773 if (CBQueue::insert_class(p) < 0)
00774 return (-1);
00775 ++cnt_[p->pri_];
00776 setM();
00777 return (0);
00778 }
00779
00780 void
00781 WRR_CBQueue::setM()
00782 {
00783 int i;
00784 for (i = 0; i <= maxprio_; i++) {
00785 if (alloc_[i] > 0.0)
00786
00787
00788 M_[i] = cnt_[i] * maxpkt_ * 1.0 / alloc_[i];
00789
00790
00791
00792 else
00793 M_[i] = 0.0;
00794
00795 if (M_[i] < 0.0) {
00796 fprintf(stderr, "M_[i]: %f, cnt_[i]: %d, maxpkt_: %d, alloc_[i]: %f\n",
00797 M_[i], cnt_[i], maxpkt_, alloc_[i]);
00798 abort();
00799 }
00800
00801 }
00802 return;
00803 }
00804
00805
00806
00807 CBQClass::CBQClass() : cbq_(0), peer_(0), level_peer_(0), lender_(0),
00808 q_(0), qmon_(0), allotment_(0.0), maxidle_(-1.0), maxrate_(0.0),
00809 extradelay_(0.0), last_time_(0.0), undertime_(0.0), avgidle_(0.0),
00810 pri_(-1), level_(-1), delayed_(0), bytes_alloc_(0),
00811 permit_borrowing_(1)
00812 {
00813
00814 bind("priority_", &pri_);
00815 bind("level_", &level_);
00816 bind("extradelay_", &extradelay_);
00817 bind_bool("okborrow_", &permit_borrowing_);
00818
00819 if (pri_ < 0 || pri_ > (MAXPRIO-1))
00820 abort();
00821
00822 if (level_ <= 0 || level_ > MAXLEVEL)
00823 abort();
00824 }
00825
00826
00827 int
00828 CBQClass::demand()
00829 {
00830 return (qmon_->pkts() > 0);
00831 }
00832
00833 int
00834 CBQClass::leaf()
00835 {
00836 return (level_ == LEAF_LEVEL);
00837 }
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849 void
00850 CBQClass::recv(Packet *pkt, Handler *h)
00851 {
00852 if (cbq_->toplevel()) {
00853 Scheduler* s;
00854 if ((s = &Scheduler::instance()) != NULL)
00855 cbq_->toplevel_arrival(this, s->clock());
00856 }
00857 send(pkt, h);
00858 if (!cbq_->blocked()) {
00859 cbq_->sched();
00860 }
00861 return;
00862 }
00863
00864
00865
00866
00867
00868 void CBQClass::update(Packet* p, double now)
00869 {
00870 double idle, avgidle;
00871
00872 hdr_cmn* hdr = hdr_cmn::access(p);
00873 int pktsize = hdr->size();
00874
00875 double tx_time = cbq_->link()->txtime(p);
00876 double fin_time = now + tx_time;
00877
00878 idle = (fin_time - last_time_) - (pktsize / maxrate_);
00879 avgidle = avgidle_;
00880 avgidle += (idle - avgidle) / POWEROFTWO;
00881 if (maxidle_ < 0) {
00882 fprintf(stderr,
00883 "CBQClass: warning: maxidle_ not configured!\n");
00884 } else if (avgidle > maxidle_)
00885 avgidle = maxidle_;
00886 avgidle_ = avgidle;
00887
00888 if (avgidle <= 0) {
00889 undertime_ = fin_time + tx_time *
00890 (1.0 / allotment_ - 1.0);
00891 undertime_ += (1-POWEROFTWO) * avgidle;
00892 }
00893 last_time_ = fin_time;
00894
00895 if (lender_)
00896 lender_->update(p, now);
00897
00898 return;
00899 }
00900
00901
00902
00903
00904
00905 int
00906 CBQClass::satisfied(double now)
00907 {
00908 if (leaf()) {
00909
00910 if (undertime_ < now && demand())
00911 return (0);
00912 else
00913 return (1);
00914 }
00915 if (undertime_ < now && desc_with_demand())
00916 return (0);
00917
00918 return (1);
00919 }
00920
00921
00922
00923
00924
00925
00926
00927 int
00928 CBQClass::desc_with_demand()
00929 {
00930 CBQClass *p = cbq_->level(LEAF_LEVEL);
00931 for (; p != NULL; p = p->level_peer_) {
00932 if (p->demand() && ancestor(p))
00933 return (1);
00934 }
00935 return (0);
00936 }
00937
00938
00939
00940
00941
00942
00943 void CBQClass::delayed(double now)
00944 {
00945 double delay = undertime_ - now + extradelay_;
00946
00947 if (delay > 0 && !delayed_) {
00948 undertime_ += extradelay_;
00949 undertime_ -= (1-POWEROFTWO) * avgidle_;
00950 delayed_ = 1;
00951 }
00952 }
00953
00954
00955
00956
00957 int
00958 CBQClass::ancestor(CBQClass *p)
00959 {
00960 if (!p->permit_borrowing_ || p->lender_ == NULL)
00961 return (0);
00962 else if (p->lender_ == this)
00963 return (1);
00964 return (ancestor(p->lender_));
00965 }
00966
00967
00968
00969
00970 void
00971 CBQClass::newallot(double bw)
00972 {
00973 if (allotment_ < 0)
00974 allotment_ = 0;
00975 if (bw < 0)
00976 bw = 0;
00977 maxrate_ = bw * ( cbq_->link()->bandwidth() / 8.0 );
00978 double diff = bw - allotment_;
00979 allotment_ = bw;
00980 cbq_->addallot(pri_, diff);
00981 return;
00982 }
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995 int CBQClass::command(int argc, const char*const* argv)
00996 {
00997 Tcl& tcl = Tcl::instance();
00998 if (argc == 2) {
00999 if (strcmp(argv[1], "allot") == 0) {
01000 tcl.resultf("%g", allotment_);
01001 return (TCL_OK);
01002 }
01003 if (strcmp(argv[1], "cbq") == 0) {
01004 if (cbq_ != NULL)
01005 tcl.resultf("%s", cbq_->name());
01006 else
01007 tcl.resultf("");
01008 return(TCL_OK);
01009 }
01010 if (strcmp(argv[1], "qdisc") == 0) {
01011 if (q_ != NULL)
01012 tcl.resultf("%s", q_->name());
01013 else
01014 tcl.resultf("");
01015 return (TCL_OK);
01016 }
01017 if (strcmp(argv[1], "qmon") == 0) {
01018 if (qmon_ != NULL)
01019 tcl.resultf("%s", qmon_->name());
01020 else
01021 tcl.resultf("");
01022 return (TCL_OK);
01023 }
01024 } else if (argc == 3) {
01025
01026 if ((strcmp(argv[1], "parent") == 0)) {
01027
01028 if (strcmp(argv[2], "none") == 0) {
01029 lender_ = NULL;
01030 return (TCL_OK);
01031 }
01032 lender_ = (CBQClass*)TclObject::lookup(argv[2]);
01033 if (lender_ != NULL)
01034 return (TCL_OK);
01035
01036 return (TCL_ERROR);
01037 }
01038 if (strcmp(argv[1], "qdisc") == 0) {
01039 q_ = (Queue*) TclObject::lookup(argv[2]);
01040 if (q_ != NULL)
01041 return (TCL_OK);
01042 tcl.resultf("couldn't find object %s",
01043 argv[2]);
01044 return (TCL_ERROR);
01045 }
01046 if (strcmp(argv[1], "qmon") == 0) {
01047 qmon_ = (QueueMonitor*) TclObject::lookup(argv[2]);
01048 if (qmon_ != NULL)
01049 return (TCL_OK);
01050 return (TCL_ERROR);
01051 }
01052 if (strcmp(argv[1], "allot") == 0) {
01053 double bw = atof(argv[2]);
01054 if (bw < 0.0)
01055 return (TCL_ERROR);
01056 if (allotment_ != 0.0) {
01057 tcl.resultf(" class %s already has allotment of %f!",
01058 name(), allotment_);
01059 return (TCL_ERROR);
01060 }
01061 allotment_ = bw;
01062 return (TCL_OK);
01063 }
01064 if (strcmp(argv[1], "newallot") == 0) {
01065 double bw = atof(argv[2]);
01066 if (bw < 0.0)
01067 return (TCL_ERROR);
01068 newallot(bw);
01069 return (TCL_OK);
01070 }
01071 if (strcmp(argv[1], "maxidle") == 0) {
01072 double m = atof(argv[2]);
01073 if (m < 0.0) {
01074 tcl.resultf("invalid maxidle value %s (must be non-negative)",
01075 argv[2]);
01076 return (TCL_ERROR);
01077 }
01078 maxidle_ = m;
01079 return (TCL_OK);
01080 }
01081 }
01082 return (Connector::command(argc, argv));
01083 }