Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

ivs.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1996-1997 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by the Computer Systems
00017  *      Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  */
00034 
00035 #ifndef lint
00036 static const char rcsid[] =
00037     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/common/ivs.cc,v 1.16 2000/09/01 03:04:05 haoboy Exp $ (LBL)";
00038 #endif
00039 
00040 #include <stdlib.h>
00041 #include <math.h>
00042 #include "message.h"
00043 #include "trace.h"
00044 #include "agent.h"
00045 
00046 /* ivs data packet; ctrl packets are sent back as "messages" */
00047 struct hdr_ivs {
00048         double ts_;                     /* timestamp sent at source */
00049         u_int8_t S_;
00050         u_int8_t R_;
00051         u_int8_t state_;
00052         u_int8_t rshft_;
00053         u_int8_t kshft_;
00054         u_int16_t key_;
00055         double maxrtt_;
00056         int seqno_;
00057 
00058         static int offset_;
00059         inline static int& offset() { return offset_; }
00060         inline static hdr_ivs* access(Packet* p) {
00061                 return (hdr_ivs*) p->access(offset_);
00062         }
00063 
00064         /* per-field member functions */
00065         double& ts() { return (ts_); }
00066         u_int8_t& S() { return (S_); }
00067         u_int8_t& R() { return (R_); }
00068         u_int8_t& state() { return (state_); }
00069         u_int8_t& rshft() { return (rshft_); }
00070         u_int8_t& kshft() { return (kshft_); }
00071         u_int16_t& key() { return (key_); }
00072         double& maxrtt() { return (maxrtt_); }
00073         int& seqno() { return (seqno_); }
00074 };
00075 
00076 int hdr_ivs::offset_;
00077 
00078 static class IvsHeaderClass : public PacketHeaderClass {
00079 public:
00080         IvsHeaderClass() : PacketHeaderClass("PacketHeader/IVS",
00081                                              sizeof(hdr_ivs)) {
00082                 bind_offset(&hdr_ivs::offset_);
00083         }
00084 } class_ivshdr;
00085 
00086 class IvsSource : public Agent {
00087 public:
00088         IvsSource();
00089 protected:
00090         void reset();
00091         void recv(Packet *pkt, Handler*);
00092         void sendpkt();
00093 
00094         int S_;
00095         int R_;
00096         int state_;
00097 #define ST_U 0
00098 #define ST_L 1
00099 #define ST_C 2
00100         int rttShift_;
00101         int keyShift_;
00102         int key_;
00103         double maxrtt_;
00104 };
00105 
00106 struct Mc_Hole {
00107         int start;
00108         int end;
00109         double time;
00110         Mc_Hole* next;
00111 };
00112 
00113 class IvsReceiver : public Agent {
00114 public:
00115         IvsReceiver();
00116         int command(int argc, const char*const* argv);
00117 protected:
00118         void recv(Packet *pkt, Handler*);
00119         void update_ipg(double now);
00120         int lossMeter(double timeDiff, u_int32_t seq, double maxrtt);
00121         void upcall_respond(double ts, int matchS);
00122         void upcall_rtt_solicit(double ts, int rshift);
00123 
00124         int state_;
00125         u_int32_t nextSeq_;
00126 
00127         double timeMean_;
00128         double timeVar_;
00129         double ipg_;            /* interpkt gap (estimator) */
00130         Mc_Hole* head_;
00131         Mc_Hole* tail_;
00132         double lastPktTime_;
00133         int ignoreR_;
00134         double lastTime_;       /* last time a resp pkt sent */
00135         int key_;
00136 };
00137 
00138 static class IvsSourceClass : public TclClass {
00139 public:
00140         IvsSourceClass() : TclClass("Agent/IVS/Source") {}
00141         TclObject* create(int, const char*const*) {
00142                 return (new IvsSource());
00143         }
00144 } class_ivs_source;
00145 
00146 static class IvsReceiverClass : public TclClass {
00147 public:
00148         IvsReceiverClass() : TclClass("Agent/IVS/Receiver") {}
00149         TclObject* create(int, const char*const*) {
00150                 return (new IvsReceiver());
00151         }
00152 } class_ivs_receiver;
00153 
00154 IvsSource::IvsSource() : Agent(PT_MESSAGE), S_(0), R_(0), state_(ST_U),
00155         rttShift_(0), keyShift_(0), key_(0), maxrtt_(0)
00156 {
00157         bind("S_", &S_);
00158         bind("R_", &R_);
00159         bind("state_", &state_);
00160         bind("rttShift_", &rttShift_);
00161         bind("keyShift_", &keyShift_);
00162         bind("key_", &key_);
00163         bind("maxrtt_", &maxrtt_);
00164 }
00165 
00166 void IvsSource::reset()
00167 {
00168 }
00169 
00170 /*
00171  * main reception path - should only see acks, otherwise the
00172  * network connections are misconfigured
00173  */
00174 void IvsSource::recv(Packet* pkt, Handler*)
00175 {
00176         char wrk[128];/*XXX*/
00177         Tcl& tcl = Tcl::instance();
00178         hdr_msg *q = hdr_msg::access(pkt);
00179         sprintf(wrk, "%s handle {%s}", name(), q->msg());
00180         tcl.eval(wrk);
00181         Packet::free(pkt);
00182 }
00183 
00184 #ifdef notdef
00185 void IvsSource::probe_timeout()
00186 {
00187         rndStart_ = now;
00188 
00189         if (keyShift_ == 15) {
00190                 if (key_ == 0) {
00191                         if (solicitedResponses_ == 0)
00192                                 estReceivers_ = 0;
00193                                 /*
00194                                  * Got through a round without being LOADED.
00195                                  * increase send rate.
00196                                  */
00197                         if (state_ == ST_U)
00198                                 increase();
00199 
00200                                 /* Reset keys et al */
00201                         S_ = 1;
00202                         state_ = ST_U;
00203 
00204                                 /*XXX*/
00205                         setRttSolicit(mcstate);
00206 
00207                         solicitedResponses_ = 0;
00208                         keyShift_ = startShift_;
00209                                 /*XXX do all this in tcl? */
00210                         setkey();
00211                         
00212                 } else { mcstate->hdr.key = 0; }
00213         } else {
00214                 if (probeTimeout_ > 0)
00215                         ++keyShift_;
00216         }
00217         sched(pktTime + 2 * maxrtt_, IVS_TIMER_PROBE);
00218 }
00219 #endif
00220 
00221 void IvsSource::sendpkt()
00222 {
00223         Packet* pkt = allocpkt();
00224         hdr_ivs *p = hdr_ivs::access(pkt);
00225         /*fill in ivs fields */
00226         p->ts() = Scheduler::instance().clock();
00227         p->S() = S_;
00228         p->R() = R_;
00229         p->state() = state_;
00230         p->rshft() = rttShift_;
00231         p->kshft() = keyShift_;
00232         p->key() = key_;
00233         p->maxrtt() = maxrtt_;
00234 
00235         target_->recv(pkt, (Handler *)0);
00236 }
00237 
00238 IvsReceiver::IvsReceiver() : Agent(PT_MESSAGE), state_(ST_U),
00239         nextSeq_(0),
00240         timeMean_(0.), timeVar_(0.),/*XXX*/
00241         ipg_(0.),
00242         head_(0),
00243         tail_(0),
00244         lastPktTime_(0.),
00245         ignoreR_(0),
00246         lastTime_(0.),
00247         key_(0)
00248 {
00249         bind("ignoreR_", &ignoreR_);
00250         bind("key_", &key_);
00251         bind("state_", &state_);
00252         bind("packetSize_", &size_);
00253 }
00254 
00255 inline void IvsReceiver::update_ipg(double v)
00256 {
00257         /* Update the estimated interpacket gap */
00258         ipg_ = (15 * ipg_ + v) / 16;
00259 }
00260 
00261 /*
00262  * timestamp comes in milliseconds since start of connection according to
00263  * remote clock
00264  * now is milliseconds since start of connection
00265  * rtt in milliseconds
00266  * This congestion meter is not terribly good at figuring out when the net is 
00267  * loaded, since the loss of a packet over a rtt is a transitory event
00268  * Eventually we ought to have a memory thing, that records state once a 
00269  * maxrtt, with thresholds to decide current state
00270  */
00271 int IvsReceiver::lossMeter(double timeDiff, u_int32_t seq, double maxrtt)
00272 {
00273         /*
00274          * The congestion signal is calculated here by measuring the loss in a 
00275          * given period of packets - if the threshold for lost packets is
00276          * passed then signal Congested.  If there are no lost packets,
00277          * then we are at UNLOADED, else LOADED
00278          */
00279         /* if sequence number is next, increase expected number */
00280         
00281         double now = Scheduler::instance().clock();
00282         if (nextSeq_ == 0)
00283                 nextSeq_ = seq + 1;
00284         else if (seq == nextSeq_)
00285                 nextSeq_++;
00286         else if (seq > nextSeq_) {
00287 #ifdef notdef
00288                 if (trace_ != 0) {
00289                         sprintf(trace_->buffer(), "d %g %d",
00290                                 lastPktTime_, seq - nextSeq_);
00291                         trace_->dump();
00292                 }
00293 #endif
00294 
00295                 /* This is definitely a hole */
00296                 Mc_Hole* hole = new Mc_Hole;
00297                 hole->time = now;
00298                 hole->start = nextSeq_;
00299                 hole->end = seq - 1;
00300                 hole->next = 0;
00301                 /* Now add it to the list */
00302                 if (head_ == NULL) {
00303                         head_ = hole;
00304                         tail_ = hole;
00305                 } else {
00306                         tail_->next = hole;
00307                         tail_ = hole;
00308                 }
00309                 nextSeq_ = seq + 1;
00310         } else {
00311                 /* XXX can't happen in current ns simulations */
00312                 fprintf(stderr, "ns: ivs rcvr: seq number went backward\n");
00313                 abort();
00314         }
00315 
00316         /* update the calculation of the variance in the rtt */
00317         /* get the time averaged mean of the difference */
00318         if (timeMean_ == 0)
00319                 timeMean_ = timeDiff;
00320         else
00321                 timeMean_ = (7 * timeMean_ + timeDiff) / 8;
00322 
00323         timeDiff -= timeMean_;
00324         if (timeDiff < 0)
00325                 timeDiff = -timeDiff;
00326 
00327         timeVar_ = (7 * timeVar_ + timeDiff) / 8;
00328 
00329         int lostPkts = 0;
00330         /* 
00331          * Check down the list of holes, discarding those that before
00332          * now-rttvar-rtt, counting those that fall within
00333          * now-rttvar to now-rttvar-rtt
00334          */
00335         if (head_ == 0)
00336                 return (ST_U);
00337 
00338         Mc_Hole *cur = head_, *prev = NULL;
00339 
00340         double validEnd = now - 2 * timeVar_;
00341         double validStart = validEnd - maxrtt;
00342 
00343         /* for each hole, if it is older than required, dump it */
00344         /* If it is valid, add the size to the loss count */
00345         /* Go to the next hole */
00346 
00347         while (cur != NULL) {
00348                 if (cur->time < validStart) {
00349                         if (prev == NULL)
00350                                 head_ = cur->next;
00351                         else
00352                                 prev->next = cur->next;
00353                         delete cur;
00354                         if (prev == NULL)
00355                                 cur = head_;
00356                         else
00357                                 cur = prev->next;
00358                 } else {
00359                         if (cur->time < validEnd)
00360                                 lostPkts += cur->end - cur->start + 1;
00361                         prev = cur;
00362                         cur = cur->next;
00363                 }
00364         }
00365 
00366         /*
00367          * Update the moving average calculation of the number of holes, if
00368          * nowMs is another rtt away
00369          */
00370 
00371         double pps = (ipg_ != 0) ? maxrtt / ipg_ : 0.;
00372 
00373 /*XXX*/
00374 #ifdef notdef
00375         if (trace_ != 0) {
00376                 double now = Scheduler::instance().clock();
00377                 sprintf(trace_->buffer(), "%.17g %g", now,
00378                         (double)lostPkts / pps);
00379                 trace_->dump();
00380         }
00381 #endif
00382 
00383 /*XXX*/
00384 #define LOSSCONGTH 15
00385 #define LOSSLOADTH 5
00386         /* If the rtt is smaller than the ipg, set the thresholds to 0,1,2 */
00387         if ((pps * LOSSCONGTH) / 100 < 2)
00388                 pps = 200 / LOSSCONGTH;
00389 
00390         if (lostPkts <= (LOSSLOADTH * pps) / 100)
00391                 return (ST_U);
00392         else if (lostPkts <= (LOSSCONGTH * pps) / 100)
00393                 return (ST_L);
00394         else
00395                 return (ST_C);
00396 }
00397 
00398 void IvsReceiver::recv(Packet* pkt, Handler*)
00399 {
00400         hdr_ivs *p = hdr_ivs::access(pkt);
00401         double now = Scheduler::instance().clock();
00402 
00403         if (lastPktTime_ == 0.) {
00404                 lastPktTime_ = now;
00405                 Packet::free(pkt);
00406                 return;
00407         }
00408         update_ipg(now - lastPktTime_);
00409         double ts = p->ts();
00410         int prevState = state_;
00411         state_ = lossMeter(now - ts, p->seqno(), p->maxrtt());
00412 
00413         lastPktTime_ = now;
00414 
00415         /* If soliciting rtt */
00416         if (p->R() && !ignoreR_)
00417                 /* upcall into tcl */
00418                 upcall_rtt_solicit(ts, p->rshft());
00419 
00420         /*
00421          * send a response if we're congested and its over an rtt since
00422          * we last sent one OR
00423          * any response is solicited to estimate size and we match the key OR
00424          * we're LOADED and we match the key and its over an rtt since we last
00425          * sent a response
00426          */
00427 
00428         if (now - lastTime_ < p->maxrtt() && state_ <= prevState) {
00429                 Packet::free(pkt);
00430                 return;
00431         }
00432 
00433         int shift = p->kshft();
00434         int match;
00435         if (p->key() == 0)
00436                 match = 1;
00437         else
00438                 match = (key_ >> shift) == (p->key() >> shift);
00439 
00440         int matchS = match ? p->S() : 0;
00441 
00442         if (state_ == ST_C || matchS || (match && state_ == ST_L)) {
00443                 upcall_respond(ts, matchS);
00444                 lastTime_ = now;
00445         }
00446 
00447         Packet::free(pkt);
00448 }
00449 
00450 void IvsReceiver::upcall_respond(double ts, int matchS)
00451 {
00452         Tcl::instance().evalf("%s respond %.17g %d", name(), ts, matchS);
00453 }
00454 
00455 void IvsReceiver::upcall_rtt_solicit(double ts, int rshift)
00456 {
00457         Tcl::instance().evalf("%s solicit-rtt %.17g %d", name(), ts, rshift);
00458 }
00459 
00460 int IvsReceiver::command(int argc, const char*const* argv)
00461 {
00462         Tcl& tcl = Tcl::instance();
00463         if (argc == 3) {
00464                 if (strcmp(argv[1], "send") == 0) {
00465                         Packet* pkt = allocpkt();
00466                         hdr_msg* p = hdr_msg::access(pkt);
00467                         const char* s = argv[2];
00468                         int n = strlen(s);
00469                         if (n >= p->maxmsg()) {
00470                                 tcl.result("message too big");
00471                                 Packet::free(pkt);
00472                                 return (TCL_ERROR);
00473                         }
00474                         strcpy(p->msg(), s);
00475                         target_->recv(pkt, (Handler*)0);
00476                         return (TCL_OK);
00477                 }
00478         }
00479         return (Agent::command(argc, argv));
00480 }

Generated on Tue Apr 20 12:14:20 2004 for NS2.26SourcesOriginal by doxygen 1.3.3