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

snoop.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) 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 Daedalus Research
00017  *      Group at the University of California Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group may be
00019  *    used 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/tcp/snoop.cc,v 1.25 2003/01/28 23:31:03 sfloyd Exp $ (UCB)";
00038 #endif
00039 
00040 #include "snoop.h"
00041 
00042 int hdr_snoop::offset_;
00043 
00044 class SnoopHeaderClass : public PacketHeaderClass {
00045 public:
00046         SnoopHeaderClass() : PacketHeaderClass("PacketHeader/Snoop",
00047                                                 sizeof(hdr_snoop)) {
00048                 bind_offset(&hdr_snoop::offset_);
00049         }
00050 } class_snoophdr;
00051 
00052 static class LLSnoopClass : public TclClass {
00053 public:
00054         LLSnoopClass() : TclClass("LL/LLSnoop") {}
00055         TclObject* create(int, const char*const*) {
00056                 return (new LLSnoop());
00057         }
00058 } llsnoop_class;
00059 
00060 static class SnoopClass : public TclClass {
00061 public:
00062         SnoopClass() : TclClass("Snoop") {}
00063         TclObject* create(int, const char*const*) {
00064                 return (new Snoop());
00065         }
00066 } snoop_class;
00067 
00068 Snoop::Snoop() : NsObject(),
00069         fstate_(0), lastSeen_(-1), lastAck_(-1), 
00070         expNextAck_(0), expDupacks_(0), bufhead_(0), 
00071         toutPending_(0), buftail_(0),
00072         wl_state_(SNOOP_WLEMPTY), wl_lastSeen_(-1), wl_lastAck_(-1), 
00073         wl_bufhead_(0), wl_buftail_(0)
00074 {
00075         bind("snoopDisable_", &snoopDisable_);
00076         bind_time("srtt_", &srtt_);
00077         bind_time("rttvar_", &rttvar_);
00078         bind("maxbufs_", &maxbufs_);
00079         bind("snoopTick_", &snoopTick_);
00080         bind("g_", &g_);
00081         bind("tailTime_", &tailTime_);
00082         bind("rxmitStatus_", &rxmitStatus_);
00083         bind("lru_", &lru_);
00084 
00085         rxmitHandler_ = new SnoopRxmitHandler(this);
00086 
00087         int i;
00088         for (i = 0; i < SNOOP_MAXWIND; i++) /* data from wired->wireless */
00089                 pkts_[i] = 0;
00090         for (i = 0; i < SNOOP_WLSEQS; i++) {/* data from wireless->wired */
00091                 wlseqs_[i] = (hdr_seq *) malloc(sizeof(hdr_seq));
00092                 wlseqs_[i]->seq = wlseqs_[i]->num = 0;
00093         }
00094         if (maxbufs_ == 0)
00095                 maxbufs_ = SNOOP_MAXWIND;
00096 }
00097 
00098 void
00099 Snoop::reset()
00100 {
00101 //      printf("%x resetting\n", this);
00102         fstate_ = 0;
00103         lastSeen_ = -1;
00104         lastAck_ = -1;
00105         expNextAck_ = 0;
00106         expDupacks_ = 0;
00107         bufhead_ = buftail_ = 0;
00108         if (toutPending_) {
00109                 Scheduler::instance().cancel(toutPending_);
00110                 // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure).
00111                 toutPending_ = 0;
00112         };
00113         for (int i = 0; i < SNOOP_MAXWIND; i++) {
00114                 if (pkts_[i]) {
00115                         Packet::free(pkts_[i]);
00116                         pkts_[i] = 0;
00117                 }
00118         }
00119 }
00120 
00121 void 
00122 Snoop::wlreset()
00123 {
00124         wl_state_ = SNOOP_WLEMPTY;
00125         wl_bufhead_ = wl_buftail_ = 0;
00126         for (int i = 0; i < SNOOP_WLSEQS; i++) {
00127                 wlseqs_[i]->seq = wlseqs_[i]->num = 0;
00128         }
00129 }
00130 
00131 
00132 int 
00133 Snoop::command(int argc, const char*const* argv)
00134 {
00135         //Tcl& tcl = Tcl::instance();
00136 
00137         if (argc == 3) {
00138                 if (strcmp(argv[1], "llsnoop") == 0) {
00139                         parent_ = (LLSnoop *) TclObject::lookup(argv[2]);
00140                         if (parent_)
00141                                 recvtarget_ = parent_->uptarget();
00142                         return (TCL_OK);
00143                 }
00144                 
00145                 if (strcmp(argv[1], "check-rxmit") == 0) {
00146                         if (empty_()) {
00147                                 rxmitStatus_ = SNOOP_PROPAGATE;
00148                                 return (TCL_OK);
00149                         }
00150 
00151                         Packet *p = pkts_[buftail_];
00152                         hdr_snoop *sh = hdr_snoop::access(p);
00153 
00154                         if (sh->sndTime()!=-1 && sh->sndTime()<atoi(argv[2]) &&
00155                             sh->numRxmit() == 0)
00156                                 /* candidate for retransmission */
00157                                 rxmitStatus_ = snoop_rxmit(p);
00158                         else
00159                                 rxmitStatus_ = SNOOP_PROPAGATE;
00160                         return (TCL_OK);
00161                 }
00162         }
00163         return NsObject::command(argc, argv);
00164 }
00165 
00166 void LLSnoop::recv(Packet *p, Handler *h)
00167 {
00168         Tcl &tcl = Tcl::instance();
00169         hdr_ip *iph = hdr_ip::access(p);
00170 
00171         /* get-snoop creates a snoop object if none currently exists */
00172         hdr_cmn *ch = HDR_CMN(p);
00173         if(ch->direction() == hdr_cmn::UP) 
00174                 /* get-snoop creates a snoop object if none currently exists */
00175                 /* In ns, addresses have ports embedded in them. */
00176                 tcl.evalf("%s get-snoop %d %d", name(), iph->daddr(),
00177                           iph->saddr()); 
00178        
00179         else  
00180                 tcl.evalf("%s get-snoop %d %d", name(), iph->saddr(),
00181                           iph->daddr());
00182         
00183         Snoop *snoop = (Snoop *) TclObject::lookup(tcl.result());
00184         
00185         snoop->recv(p, h);
00186         
00187         if (integrate_)
00188                 tcl.evalf("%s integrate %d %d", name(), iph->saddr(),
00189                           iph->daddr());
00190         if (h)                  /* resume higher layer (queue) */
00191                 Scheduler::instance().schedule(h, &intr_, 0.000001);
00192         return;
00193 }
00194 
00195 /*
00196  * Receive a packet from higher layer or from the network.
00197  * Call snoop_data() if TCP packet and forward it on if it's an ack.
00198  */
00199 void
00200 Snoop::recv(Packet* p, Handler* h )
00201 {       
00202         
00203         hdr_cmn *ch = HDR_CMN(p);       
00204         if(ch->direction() == hdr_cmn::UP) {
00205                 handle((Event *) p);
00206                 return;
00207         }
00208         
00209         packet_t type = hdr_cmn::access(p)->ptype();
00210         /* Put packet (if not ack) in cache after checking, and send it on */
00211         
00212         if (type == PT_TCP) 
00213                 snoop_data(p);
00214         
00215         else if (type == PT_ACK)
00216                 snoop_wired_ack(p);
00217         
00218         ch->direction() = hdr_cmn::DOWN;  // Ben added
00219         parent_->sendDown(p);   /* vector to LLSnoop's sendto() */
00220 }
00221 
00222 /*
00223  * Handle a packet received from peer across wireless link.  Check first
00224  * for packet errors, then call snoop_ack() or pass it up as necessary.
00225  */
00226 void
00227 Snoop::handle(Event *e)
00228 {
00229 
00230         Packet *p = (Packet *) e;
00231         packet_t type = hdr_cmn::access(p)->ptype();
00232         //int seq = hdr_tcp::access(p)->seqno();
00233         int prop = SNOOP_PROPAGATE; // by default;  propagate ack or packet
00234         Scheduler& s = Scheduler::instance();
00235 
00236         //hdr_ll *llh = hdr_ll::access(p);
00237         if (hdr_cmn::access(p)->error()) {
00238                 parent_->drop(p);       // drop packet if it's been corrupted
00239                 return;
00240         }
00241 
00242         if (type == PT_ACK) 
00243                 prop = snoop_ack(p); 
00244 
00245         else if (type == PT_TCP) /* XXX what about TELNET? */
00246                 snoop_wless_data(p);
00247 
00248         if (prop == SNOOP_PROPAGATE)
00249                 s.schedule(recvtarget_, e, parent_->delay());
00250         else {                  // suppress ack
00251                 /*              printf("---- %f suppressing ack %d\n", s.clock(), seq);*/
00252                 Packet::free(p);
00253         }
00254 }
00255 
00256 /*
00257  * Data packet processing.  p is guaranteed to be of type PT_TCP when 
00258  * this function is called.
00259  */
00260 void
00261 Snoop::snoop_data(Packet *p)
00262 {
00263         Scheduler &s = Scheduler::instance();
00264         int seq = hdr_tcp::access(p)->seqno();
00265         int resetPending = 0;
00266         
00267         //      printf("%x snoop_data: %f sending packet %d\n", this, s.clock(), seq);
00268         if (fstate_ & SNOOP_ALIVE && seq == 0)
00269                 reset();
00270         fstate_ |= SNOOP_ALIVE;
00271         if ((fstate_ & SNOOP_FULL) && !lru_) {
00272 //              printf("snoop full, fwd'ing\n t %d h %d", buftail_, bufhead_);
00273                 if (seq > lastSeen_)
00274                         lastSeen_ = seq;
00275                 return;
00276         }
00277         /* 
00278          * Only if the ifq is NOT full do we insert, since otherwise we want
00279          * congestion control to kick in.
00280          */
00281 
00282         if (parent_->ifq()->length() < parent_->ifq()->limit()-1)
00283                 resetPending = snoop_insert(p);
00284         if (toutPending_ && resetPending == SNOOP_TAIL) {
00285                 s.cancel(toutPending_);
00286                 // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure).
00287                 toutPending_ = 0;
00288         }
00289         if (!toutPending_ && !empty_()) {
00290                 toutPending_ = (Event *) (pkts_[buftail_]);
00291                 s.schedule(rxmitHandler_, toutPending_, timeout());
00292         }
00293         return;
00294 }
00295 
00296 /* 
00297  * snoop_insert() does all the hard work for snoop_data(). It traverses the 
00298  * snoop cache and looks for the right place to insert this packet (or
00299  * determines if its already been cached). It then decides whether
00300  * this is a packet in the normal increasing sequence, whether it
00301  * is a sender-rexmitted-but-lost-due-to-congestion (or network 
00302  * out-of-order) packet, or if it is a sender-rexmitted packet that
00303  * was buffered by us before.
00304  */
00305 int
00306 Snoop::snoop_insert(Packet *p)
00307 {
00308 
00309 
00310 
00311         int i, seq = hdr_tcp::access(p)->seqno(), retval=0;
00312 
00313         if (seq <= lastAck_) 
00314                 return retval;
00315         
00316         if (fstate_ & SNOOP_FULL) {
00317                 /* free tail and go on */
00318                 printf("snoop full, making room\n");
00319                 Packet::free(pkts_[buftail_]);
00320                 pkts_[buftail_] = 0;
00321                 buftail_ = next(buftail_);
00322                 fstate_ |= ~SNOOP_FULL;
00323         }
00324 
00325         if (seq > lastSeen_ || pkts_[buftail_] == 0) { // in-seq or empty cache
00326                 i = bufhead_;
00327                 bufhead_ = next(bufhead_);
00328         } else if (seq < hdr_snoop::access(pkts_[buftail_])->seqno()) {
00329                 buftail_ = prev(buftail_);
00330                 i = buftail_;
00331         } else {
00332                 for (i = buftail_; i != bufhead_; i = next(i)) {
00333                         hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
00334                         if (sh->seqno() == seq) {  // cached before
00335 
00336                                 sh->numRxmit() = 0;
00337                                 sh->senderRxmit() = 1; //must be a sender retr
00338                                 sh->sndTime() = Scheduler::instance().clock();
00339                                 return SNOOP_TAIL;
00340                         } else if (sh->seqno() > seq) { 
00341 
00342                                 //not cached before, should insert in the middle
00343                                 // find the position it should be: prev(i)
00344  
00345                                 Packet *temp = pkts_[prev(buftail_)];
00346                                 for (int j = buftail_; j != i; j = next(j)) 
00347                                         pkts_[prev(j)] = pkts_[j];
00348                                 i = prev(i);
00349                                 pkts_[i] = temp;   // seems not necessary. Ben comments
00350                                 buftail_ = prev(buftail_);
00351                                 break;
00352                         }
00353                 }
00354 
00355                 // This should not happen, since seq must be > lastSeen, which is 
00356                 // handled before in the first if.   Ben comments
00357                 if (i == bufhead_)
00358                         bufhead_ = next(bufhead_);
00359         }
00360         
00361         // save in the buffer
00362         savepkt_(p, seq, i);
00363         
00364         if (bufhead_ == buftail_)
00365                 fstate_ |= SNOOP_FULL;
00366         /* 
00367          * If we have one of the following packets:
00368          * 1. a network-out-of-order packet, or
00369          * 2. a fast rxmit packet, or 3. a sender retransmission 
00370          * AND it hasn't already been buffered, 
00371          * then seq will be < lastSeen_. 
00372          * We mark this packet as having been due to a sender rexmit 
00373          * and use this information in snoop_ack(). We let the dupacks
00374          * for this packet go through according to expDupacks_.
00375          */
00376         if (seq < lastSeen_) { /* not in-order -- XXX should it be <= ? */
00377                 if (buftail_ == i) {
00378                         hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
00379                         sh->senderRxmit() = 1;
00380                         sh->numRxmit() = 0;
00381                 }
00382                 expNextAck_ = buftail_;
00383                 retval = SNOOP_TAIL;
00384         } else
00385                 lastSeen_ = seq;
00386         
00387         return retval;
00388 }
00389 
00390 void
00391 Snoop::savepkt_(Packet *p, int seq, int i)
00392 {
00393         pkts_[i] = p->copy();
00394         Packet *pkt = pkts_[i];
00395         hdr_snoop *sh = hdr_snoop::access(pkt);
00396         sh->seqno() = seq;
00397         sh->numRxmit() = 0;
00398         sh->senderRxmit() = 0;
00399         sh->sndTime() = Scheduler::instance().clock();
00400 }
00401 
00402 /*
00403  * Ack processing in snoop protocol.  We know for sure that this is an ack.
00404  * Return SNOOP_SUPPRESS if ack is to be suppressed and SNOOP_PROPAGATE o.w.
00405  */
00406 int
00407 Snoop::snoop_ack(Packet *p)
00408 {
00409         Packet *pkt;
00410 
00411         int ack = hdr_tcp::access(p)->seqno();
00412 
00413         /*
00414          * There are 3 cases:
00415          * 1. lastAck_ > ack.  In this case what has happened is
00416          *    that the acks have come out of order, so we don't
00417          *    do any local processing but forward it on.
00418          * 2. lastAck_ == ack.  This is a duplicate ack. If we have
00419          *    the packet we resend it, and drop the dupack.
00420          *    Otherwise we never got it from the fixed host, so we
00421          *    need to let the dupack get through.
00422          *    Set expDupacks_ to number of packets already sent
00423          *    This is the number of dup acks to ignore.
00424          * 3. lastAck_ < ack.  Set lastAck_ = ack, and update
00425          *    the head of the buffer queue. Also clean up ack'd packets.
00426          */
00427         if (fstate_ & SNOOP_CLOSED || lastAck_ > ack) 
00428                 return SNOOP_PROPAGATE; // send ack onward
00429 
00430         if (lastAck_ == ack) {  
00431                 /* A duplicate ack; pure window updates don't occur in ns. */
00432 
00433                 pkt = pkts_[buftail_];
00434                 
00435                 if (pkt == 0) 
00436                         return SNOOP_PROPAGATE;
00437                 
00438                 hdr_snoop *sh = hdr_snoop::access(pkt);
00439 
00440                 if (pkt == 0 || sh->seqno() > ack + 1) 
00441                         /* don't have packet, letting thru' */
00442                         return SNOOP_PROPAGATE;
00443 
00444                 /* 
00445                  * We have the packet: one of 3 possibilities:
00446                  * 1. We are not expecting any dupacks (expDupacks_ == 0)
00447                  * 2. We are expecting dupacks (expDupacks_ > 0)
00448                  * 3. We are in an inconsistent state (expDupacks_ == -1)
00449                  */
00450 
00451                         
00452                 if (expDupacks_ == 0) { // not expecting it
00453 #define RTX_THRESH 1
00454                         
00455                         static int thresh = 0;
00456                         if (thresh++ < RTX_THRESH) 
00457                                 /* no action if under RTX_THRESH */
00458                                 return SNOOP_PROPAGATE;
00459                         
00460                         thresh = 0;
00461                         
00462                         // if the packet is a sender retransmission, pass on
00463                         if (sh->senderRxmit()) 
00464                                 return SNOOP_PROPAGATE;
00465                         
00466                         /*
00467                          * Otherwise, not triggered by sender.  If this is
00468                          * the first dupack recd., we must determine how many
00469                          * dupacks will arrive that must be ignored, and also
00470                          * rexmit the desired packet.  Note that expDupacks_
00471                          * will be -1 if we miscount for some reason.
00472                          */
00473                         
00474                         
00475                         expDupacks_ = bufhead_ - expNextAck_;
00476                         if (expDupacks_ < 0)
00477                                 expDupacks_ += SNOOP_MAXWIND;
00478                         expDupacks_ -= RTX_THRESH + 1;
00479                         expNextAck_ = next(buftail_);
00480 
00481                         if (sh->numRxmit() == 0) 
00482                                 return snoop_rxmit(pkt);
00483                 } else if (expDupacks_ > 0) {
00484                         expDupacks_--;
00485                         return SNOOP_SUPPRESS;
00486                 } else if (expDupacks_ == -1) {
00487                         if (sh->numRxmit() < 2) {
00488                                 return snoop_rxmit(pkt);
00489                         }
00490                 } else          // let sender deal with it
00491                         return SNOOP_PROPAGATE;
00492         } else {                // a new ack
00493 
00494                 fstate_ &= ~SNOOP_NOACK; // have seen at least 1 new ack
00495 
00496                 /* free buffers */
00497                 double sndTime = snoop_cleanbufs_(ack);
00498                 
00499                 if (sndTime != -1)
00500                         snoop_rtt(sndTime);
00501 
00502                 expDupacks_ = 0;
00503                 expNextAck_ = buftail_;
00504                 lastAck_ = ack;
00505         }
00506         return SNOOP_PROPAGATE;
00507 }
00508 
00509 /* 
00510  * Handle data packets that arrive from a wireless link, and we're not
00511  * the end recipient.  See if there are any holes in the transmission, and
00512  * if there are, mark them as candidates for wireless loss.  Then, when
00513  * (dup)acks troop back for this loss, set the ELN bit in their header, to
00514  * help the sender (or a snoop agent downstream) retransmit.
00515  */
00516 void
00517 Snoop::snoop_wless_data(Packet *p)
00518 {
00519         hdr_tcp *th = hdr_tcp::access(p);
00520         int i, seq = th->seqno();
00521 
00522         if (wl_state_ & SNOOP_WLALIVE && seq == 0)
00523                 wlreset();
00524         wl_state_ |= SNOOP_WLALIVE;
00525 
00526         if (wl_state_ & SNOOP_WLEMPTY && seq >= wl_lastAck_) {
00527                 wlseqs_[wl_bufhead_]->seq = seq;
00528                 wlseqs_[wl_bufhead_]->num = 1;
00529                 wl_buftail_ = wl_bufhead_;
00530                 wl_bufhead_ = wl_next(wl_bufhead_);
00531                 wl_lastSeen_ = seq;
00532                 wl_state_ &= ~SNOOP_WLEMPTY;
00533                 return;
00534         }
00535         /* WL data list definitely not empty at this point. */
00536         if (seq >= wl_lastSeen_) {
00537                 wl_lastSeen_ = seq;
00538                 i = wl_prev(wl_bufhead_);
00539                 if (wlseqs_[i]->seq + wlseqs_[i]->num == seq) {
00540                         wlseqs_[i]->num++;
00541                         return;
00542                 }
00543                 i = wl_bufhead_;
00544                 wl_bufhead_ = wl_next(wl_bufhead_);
00545         } else if (seq == wlseqs_[i = wl_buftail_]->seq - 1) {
00546         } else
00547                 return;
00548 
00549         wlseqs_[i]->seq = seq;
00550         wlseqs_[i]->num++;
00551 
00552         /* Ignore network out-of-ordering and retransmissions for now */
00553         return;
00554 }
00555 
00556 /*
00557  * Ack from wired side (for sender on "other" side of wireless link.
00558  */
00559 void 
00560 Snoop::snoop_wired_ack(Packet *p)
00561 {
00562         hdr_tcp *th = hdr_tcp::access(p);
00563         int ack = th->seqno();
00564         int i;
00565         
00566         if (ack == wl_lastAck_ && snoop_wlessloss(ack)) {
00567                 hdr_flags::access(p)->eln_ = 1;
00568         } else if (ack > wl_lastAck_) {
00569                 /* update info about unack'd data */
00570                 for (i = wl_buftail_; i != wl_bufhead_; i = wl_next(i)) {
00571                         hdr_seq *t = wlseqs_[i];
00572                         if (t->seq + t->num - 1 <= ack) {
00573                                 t->seq = t->num = 0;
00574                         } else if (ack < t->seq) {
00575                                 break;
00576                         } else if (ack < t->seq + t->num - 1) {
00577                                 /* ack for part of a block */
00578                                 t->num -= ack - t->seq +1;
00579                                 t->seq = ack + 1;
00580                                 break;
00581                         }
00582                 }
00583                 wl_buftail_ = i;
00584                 if (wl_buftail_ == wl_bufhead_)
00585                         wl_state_ |= SNOOP_WLEMPTY;
00586                 wl_lastAck_ = ack;
00587                 /* Even a new ack could cause an ELN to be set. */
00588                 if (wl_bufhead_ != wl_buftail_ && snoop_wlessloss(ack))
00589                         hdr_flags::access(p)->eln_ = 1;
00590         }
00591 }
00592 
00593 /* 
00594  * Return 1 if we think this packet loss was not congestion-related, and 
00595  * 0 otherwise.  This function simply implements the lookup into the table
00596  * that maintains this info; most of the hard work is done in 
00597  * snoop_wless_data() and snoop_wired_ack().
00598  */
00599 int
00600 Snoop::snoop_wlessloss(int ack)
00601 {
00602         if ((wl_bufhead_ == wl_buftail_) || wlseqs_[wl_buftail_]->seq > ack+1)
00603                 return 1;
00604         return 0;
00605 }
00606 
00607 /*
00608  * clean snoop cache of packets that have been acked.
00609  */
00610 double
00611 Snoop::snoop_cleanbufs_(int ack)
00612 {
00613         Scheduler &s = Scheduler::instance();
00614         double sndTime = -1;
00615 
00616         if (toutPending_) {
00617                 s.cancel(toutPending_);
00618                 // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure).
00619                 toutPending_ = 0;
00620         };
00621 
00622         if (empty_())
00623                 return sndTime;
00624 
00625         int i = buftail_;
00626         do {
00627                 hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
00628                 int seq = hdr_tcp::access(pkts_[i])->seqno();
00629 
00630                 if (seq <= ack) {
00631                         sndTime = sh->sndTime();
00632                         Packet::free(pkts_[i]);
00633                         pkts_[i] = 0;
00634                         fstate_ &= ~SNOOP_FULL; /* XXX redundant? */
00635                 } else if (seq > ack)
00636                         break;
00637                 i = next(i);
00638         } while (i != bufhead_);
00639 
00640         if ((i != buftail_) || (bufhead_ != buftail_)) {
00641                 fstate_ &= ~SNOOP_FULL;
00642                 buftail_ = i;
00643         }
00644         if (!empty_()) {
00645                 toutPending_ = (Event *) (pkts_[buftail_]);
00646                 s.schedule(rxmitHandler_, toutPending_, timeout());
00647                 hdr_snoop *sh = hdr_snoop::access(pkts_[buftail_]);
00648                 tailTime_ = sh->sndTime();
00649         }
00650 
00651         return sndTime;
00652 }
00653 
00654 /* 
00655  * Calculate smoothed rtt estimate and linear deviation.
00656  */
00657 void
00658 Snoop::snoop_rtt(double sndTime)
00659 {
00660         double rtt = Scheduler::instance().clock() - sndTime;
00661 
00662         if (parent_->integrate()) {
00663                 parent_->snoop_rtt(sndTime);
00664                 return;
00665         }
00666         
00667         if (rtt > 0) {
00668                 srtt_ = g_*srtt_ + (1-g_)*rtt;
00669                 double delta = rtt - srtt_;
00670                 if (delta < 0)
00671                         delta = -delta;
00672                 if (rttvar_ != 0)
00673                         rttvar_ = g_*delta + (1-g_)*rttvar_;
00674                 else 
00675                         rttvar_ = delta;
00676         }
00677 }
00678 
00679 
00680 /* 
00681  * Calculate smoothed rtt estimate and linear deviation.
00682  */
00683 void
00684 LLSnoop::snoop_rtt(double sndTime)
00685 {
00686         double rtt = Scheduler::instance().clock() - sndTime;
00687         if (rtt > 0) {
00688                 srtt_ = g_*srtt_ + (1-g_)*rtt;
00689                 double delta = rtt - srtt_;
00690                 if (delta < 0)
00691                         delta = -delta;
00692                 if (rttvar_ != 0)
00693                         rttvar_ = g_*delta + (1-g_)*rttvar_;
00694                 else 
00695                         rttvar_ = delta;
00696         }
00697 }
00698 
00699 /*
00700  * Returns 1 if recent queue length is <= half the maximum and 0 otherwise.
00701  */
00702 int 
00703 Snoop::snoop_qlong()
00704 {
00705         /* For now only instantaneous lengths */
00706         //      if (parent_->ifq()->length() <= 3*parent_->ifq()->limit()/4)
00707         
00708         return 1;
00709                 //      return 0;
00710 }
00711 
00712 /*
00713  * Ideally, would like to schedule snoop retransmissions at higher priority.
00714  */
00715 int
00716 Snoop::snoop_rxmit(Packet *pkt)
00717 {
00718         Scheduler& s = Scheduler::instance();
00719         if (pkt != 0) {
00720                 hdr_snoop *sh = hdr_snoop::access(pkt);
00721                 if (sh->numRxmit() < SNOOP_MAX_RXMIT && snoop_qlong()) {
00722                         /*                      && sh->seqno() == lastAck_+1)  */
00723                         
00724 #if 0
00725                         printf("%f Rxmitting packet %d\n", s.clock(), 
00726                                hdr_tcp::access(pkt)->seqno());
00727 #endif
00728                         
00729                         // need to specify direction, in this case, down
00730                         hdr_cmn *ch = HDR_CMN(pkt);       
00731                         ch->direction() = hdr_cmn::DOWN;  // Ben added
00732 
00733                         sh->sndTime() = s.clock();
00734                         sh->numRxmit() = sh->numRxmit() + 1;
00735                         Packet *p = pkt->copy();
00736                         parent_->sendDown(p);
00737                 } else 
00738                         return SNOOP_PROPAGATE;
00739         }
00740         /* Reset timeout for later time. */
00741         if (toutPending_) {
00742                 s.cancel(toutPending_);
00743                 // xxx: I think that toutPending_ doesn't need to be freed because snoop didn't allocate it (but I'm not sure).
00744         };
00745         toutPending_ = (Event *)pkt;
00746         s.schedule(rxmitHandler_, toutPending_, timeout());
00747         return SNOOP_SUPPRESS;
00748 }
00749 
00750 void 
00751 Snoop::snoop_cleanup()
00752 {
00753 }
00754 
00755 void
00756 SnoopRxmitHandler::handle(Event *)
00757 {
00758         Packet *p = snoop_->pkts_[snoop_->buftail_];
00759         snoop_->toutPending_ = 0;
00760         if (p == 0)
00761                 return;
00762         hdr_snoop *sh = hdr_snoop::access(p);
00763         if (sh->seqno() != snoop_->lastAck_ + 1)
00764                 return;
00765         if ((snoop_->bufhead_ != snoop_->buftail_) || 
00766             (snoop_->fstate_ & SNOOP_FULL)) {
00767                 //              printf("%f Snoop timeout\n", Scheduler::instance().clock());
00768                 if (snoop_->snoop_rxmit(p) == SNOOP_SUPPRESS)
00769                         snoop_->expNextAck_ = snoop_->next(snoop_->buftail_);
00770         }
00771 }
00772 
00773 
00774 

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