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