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
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #include <math.h>
00046 #include <sys/types.h>
00047 #include "config.h"
00048 #include "template.h"
00049 #include "random.h"
00050 #include "flags.h"
00051 #include "delay.h"
00052 #include "pi.h"
00053
00054 static class PIClass : public TclClass {
00055 public:
00056 PIClass() : TclClass("Queue/PI") {}
00057 TclObject* create(int argc, const char*const* argv) {
00058 if (argc==5)
00059 return (new PIQueue(argv[4]));
00060 else
00061 return (new PIQueue("Drop"));
00062 }
00063 } class_pi;
00064
00065
00066 PIQueue::PIQueue(const char * trace) : CalcTimer(this), link_(NULL), q_(NULL),
00067 qib_(0), de_drop_(NULL), EDTrace(NULL), tchan_(0), curq_(0),
00068 edp_(), edv_(), first_reset_(1)
00069 {
00070 if (strlen(trace) >=20) {
00071 printf("trace type too long - allocate more space to traceType in pi.h and recompile\n");
00072 exit(0);
00073 }
00074 strcpy(traceType, trace);
00075
00076 bind_bool("bytes_", &edp_.bytes);
00077 bind_bool("queue_in_bytes_", &qib_);
00078 bind("a_", &edp_.a);
00079 bind("b_", &edp_.b);
00080 bind("w_", &edp_.w);
00081 bind("qref_", &edp_.qref);
00082 bind("mean_pktsize_", &edp_.mean_pktsize);
00083 bind_bool("setbit_", &edp_.setbit);
00084 bind("prob_", &edv_.v_prob);
00085 bind("curq_", &curq_);
00086 q_ = new PacketQueue();
00087 pq_ = q_;
00088 reset();
00089 }
00090
00091 void PIQueue::reset()
00092 {
00093
00094
00095
00096
00097
00098
00099 edv_.count = 0;
00100 edv_.count_bytes = 0;
00101 edv_.v_prob = 0;
00102 edv_.qold = 0;
00103 curq_ = 0;
00104 calculate_p();
00105 Queue::reset();
00106 }
00107
00108
00109 void PIQueue::enque(Packet* pkt)
00110 {
00111
00112 hdr_cmn* ch = hdr_cmn::access(pkt);
00113 ++edv_.count;
00114 edv_.count_bytes += ch->size();
00115
00116 int droptype = DTYPE_NONE;
00117
00118 int qlen = qib_ ? q_->byteLength() : q_->length();
00119 curq_ = qlen;
00120
00121 int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_;
00122
00123 if (qlen >= qlim) {
00124 droptype = DTYPE_FORCED;
00125 }
00126 else {
00127 if (drop_early(pkt, qlen)) {
00128 droptype = DTYPE_UNFORCED;
00129 }
00130 }
00131
00132 if (droptype == DTYPE_UNFORCED) {
00133 Packet *pkt_to_drop = pickPacketForECN(pkt);
00134 if (pkt_to_drop != pkt) {
00135 q_->enque(pkt);
00136 q_->remove(pkt_to_drop);
00137 pkt = pkt_to_drop;
00138 }
00139
00140 if (de_drop_ != NULL) {
00141 if (EDTrace != NULL)
00142 ((Trace *)EDTrace)->recvOnly(pkt);
00143 de_drop_->recv(pkt);
00144 }
00145 else {
00146 drop(pkt);
00147 }
00148 } else {
00149 q_->enque(pkt);
00150 if (droptype == DTYPE_FORCED) {
00151 pkt = pickPacketToDrop();
00152 q_->remove(pkt);
00153 drop(pkt);
00154 edv_.count = 0;
00155 edv_.count_bytes = 0;
00156 }
00157 }
00158 return;
00159 }
00160
00161 double PIQueue::calculate_p()
00162 {
00163
00164 double p;
00165 int qlen = qib_ ? q_->byteLength() : q_->length();
00166
00167 if (qib_) {
00168 p=edp_.a*(qlen*1.0/edp_.mean_pktsize-edp_.qref)-
00169 edp_.b*(edv_.qold*1.0/edp_.mean_pktsize-edp_.qref)+
00170 edv_.v_prob;
00171 }
00172 else {
00173 p=edp_.a*(qlen-edp_.qref)-edp_.b*(edv_.qold-edp_.qref)+edv_.v_prob;
00174 }
00175
00176 if (p < 0) p = 0;
00177 if (p > 1) p = 1;
00178
00179 edv_.v_prob = p;
00180 edv_.qold = qlen;
00181
00182 CalcTimer.resched(1.0/edp_.w);
00183 return p;
00184 }
00185
00186 int PIQueue::drop_early(Packet* pkt, int qlen)
00187 {
00188
00189 hdr_cmn* ch = hdr_cmn::access(pkt);
00190 double p = edv_.v_prob;
00191
00192 if (edp_.bytes) {
00193 p = p*ch->size()/edp_.mean_pktsize;
00194 if (p > 1) p = 1;
00195 }
00196
00197 double u = Random::uniform();
00198 if (u <= p) {
00199 edv_.count = 0;
00200 edv_.count_bytes = 0;
00201 hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt));
00202 if (edp_.setbit && hf->ect()) {
00203 hf->ce() = 1;
00204 return (0);
00205 } else {
00206 return (1);
00207 }
00208 }
00209 return (0);
00210 }
00211
00212 Packet* PIQueue::pickPacketForECN(Packet* pkt)
00213 {
00214 return pkt;
00215 }
00216
00217 Packet* PIQueue::pickPacketToDrop()
00218 {
00219 int victim;
00220 victim = q_->length() - 1;
00221 return(q_->lookup(victim));
00222 }
00223
00224 Packet* PIQueue::deque()
00225 {
00226 Packet *p;
00227 p = q_->deque();
00228 curq_ = qib_ ? q_->byteLength() : q_->length();
00229 return (p);
00230 }
00231
00232 int PIQueue::command(int argc, const char*const* argv)
00233 {
00234 Tcl& tcl = Tcl::instance();
00235 if (argc == 2) {
00236 if (strcmp(argv[1], "reset") == 0) {
00237 reset();
00238 return (TCL_OK);
00239 }
00240 if (strcmp(argv[1], "early-drop-target") == 0) {
00241 if (de_drop_ != NULL)
00242 tcl.resultf("%s", de_drop_->name());
00243 return (TCL_OK);
00244 }
00245 if (strcmp(argv[1], "edrop-trace") == 0) {
00246 if (EDTrace != NULL) {
00247 tcl.resultf("%s", EDTrace->name());
00248 }
00249 else {
00250 tcl.resultf("0");
00251 }
00252 return (TCL_OK);
00253 }
00254 if (strcmp(argv[1], "trace-type") == 0) {
00255 tcl.resultf("%s", traceType);
00256 return (TCL_OK);
00257 }
00258 }
00259 else if (argc == 3) {
00260
00261 if (strcmp(argv[1], "attach") == 0) {
00262 int mode;
00263 const char* id = argv[2];
00264 tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00265 if (tchan_ == 0) {
00266 tcl.resultf("PI: trace: can't attach %s for writing", id);
00267 return (TCL_ERROR);
00268 }
00269 return (TCL_OK);
00270 }
00271
00272 if (strcmp(argv[1], "link") == 0) {
00273 LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
00274 if (del == 0) {
00275 tcl.resultf("PI: no LinkDelay object %s", argv[2]);
00276 return(TCL_ERROR);
00277 }
00278 link_ = del;
00279 return (TCL_OK);
00280 }
00281 if (strcmp(argv[1], "early-drop-target") == 0) {
00282 NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
00283 if (p == 0) {
00284 tcl.resultf("no object %s", argv[2]);
00285 return (TCL_ERROR);
00286 }
00287 de_drop_ = p;
00288 return (TCL_OK);
00289 }
00290 if (strcmp(argv[1], "edrop-trace") == 0) {
00291 NsObject * t = (NsObject *)TclObject::lookup(argv[2]);
00292 if (t == 0) {
00293 tcl.resultf("no object %s", argv[2]);
00294 return (TCL_ERROR);
00295 }
00296 EDTrace = t;
00297 return (TCL_OK);
00298 }
00299 if (!strcmp(argv[1], "packetqueue-attach")) {
00300 delete q_;
00301 if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
00302 return (TCL_ERROR);
00303 else {
00304 pq_ = q_;
00305 return (TCL_OK);
00306 }
00307 }
00308 }
00309 return (Queue::command(argc, argv));
00310 }
00311
00312 void PIQueue::trace(TracedVar* v)
00313 {
00314 char wrk[500], *p;
00315
00316 if (((p = strstr(v->name(), "prob")) == NULL) &&
00317 ((p = strstr(v->name(), "curq")) == NULL)) {
00318 fprintf(stderr, "PI:unknown trace var %s\n", v->name());
00319 return;
00320 }
00321 if (tchan_) {
00322 int n;
00323 double t = Scheduler::instance().clock();
00324
00325 if (*p == 'c') {
00326 sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
00327 } else {
00328 sprintf(wrk, "%c %g %g", *p, t, double(*((TracedDouble*) v)));
00329 }
00330 n = strlen(wrk);
00331 wrk[n] = '\n';
00332 wrk[n+1] = 0;
00333 (void)Tcl_Write(tchan_, wrk, n+1);
00334 }
00335 return;
00336 }
00337
00338 void PICalcTimer::expire(Event *)
00339 {
00340 a_->calculate_p();
00341 }