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 Mar 6 16:47:46 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6