tcp-sink.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) 1991-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 /* 8/02 Tom Kelly - Dynamic resizing of seen buffer */
00036 
00037 #include "flags.h"
00038 #include "ip.h"
00039 #include "tcp-sink.h"
00040 #include "hdr_qs.h"
00041 
00042 static class TcpSinkClass : public TclClass {
00043 public:
00044     TcpSinkClass() : TclClass("Agent/TCPSink") {}
00045     TclObject* create(int, const char*const*) {
00046         return (new TcpSink(new Acker));
00047     }
00048 } class_tcpsink;
00049 
00050 Acker::Acker() : next_(0), maxseen_(0), wndmask_(MWM), ecn_unacked_(0), 
00051     ts_to_echo_(0), last_ack_sent_(0)
00052 {
00053     seen_ = new int[MWS];
00054     memset(seen_, 0, (sizeof(int) * (MWS)));
00055 }
00056 
00057 void Acker::reset() 
00058 {
00059     next_ = 0;
00060     maxseen_ = 0;
00061     memset(seen_, 0, (sizeof(int) * (wndmask_ + 1)));
00062 }   
00063 
00064 // dynamically increase the seen buffer as needed
00065 // size must be a factor of two for the wndmask_ to work...
00066 void Acker::resize_buffers(int sz) { 
00067     int* new_seen = new int[sz];
00068     int new_wndmask = sz - 1;
00069     
00070     if(!new_seen){
00071         fprintf(stderr, "Unable to allocate buffer seen_[%i]\n", sz);
00072         exit(1);
00073     }
00074     
00075     memset(new_seen, 0, (sizeof(int) * (sz)));
00076     
00077     for(int i = next_; i <= maxseen_+1; i++){
00078         new_seen[i & new_wndmask] = seen_[i&wndmask_];
00079     }
00080     
00081     delete[] seen_;
00082     seen_ = new_seen;      
00083     wndmask_ = new_wndmask;
00084     return; 
00085 }
00086 
00087 void Acker::update_ts(int seqno, double ts, int rfc1323)
00088 {
00089     // update timestamp if segment advances with ACK.
00090         // Code changed by Andrei Gurtov.
00091         if (rfc1323 && seqno == last_ack_sent_ + 1)
00092                ts_to_echo_ = ts;
00093         else if (ts >= ts_to_echo_ && seqno <= last_ack_sent_ + 1)
00094                //rfc1323-bis, update timestamps from duplicate segments
00095                ts_to_echo_ = ts;
00096 }
00097 
00098 // returns number of bytes that can be "delivered" to application
00099 // also updates the receive window (i.e. next_, maxseen, and seen_ array)
00100 int Acker::update(int seq, int numBytes)
00101 {
00102     bool just_marked_as_seen = FALSE;
00103     is_dup_ = FALSE;
00104     // start by assuming the segment hasn't been received before
00105     if (numBytes <= 0)
00106         printf("Error, received TCP packet size <= 0\n");
00107     int numToDeliver = 0;
00108     while(seq + 1 - next_ >= wndmask_) {
00109         // next_ is next packet expected; wndmask_ is the maximum
00110         // window size minus 1; if somehow the seqno of the
00111         // packet is greater than the one we're expecting+wndmask_,
00112         // then resize the buffer.
00113         resize_buffers((wndmask_+1)*2);
00114     }
00115 
00116     if (seq > maxseen_) {
00117         // the packet is the highest one we've seen so far
00118         int i;
00119         for (i = maxseen_ + 1; i < seq; ++i)
00120             seen_[i & wndmask_] = 0;
00121         // we record the packets between the old maximum and
00122         // the new max as being "unseen" i.e. 0 bytes of each
00123         // packet have been received
00124         maxseen_ = seq;
00125         seen_[maxseen_ & wndmask_] = numBytes;
00126         // store how many bytes have been seen for this packet
00127         seen_[(maxseen_ + 1) & wndmask_] = 0;
00128         // clear the array entry for the packet immediately
00129         // after this one
00130         just_marked_as_seen = TRUE;
00131         // necessary so this packet isn't confused as being a duplicate
00132     }
00133     int next = next_;
00134     if (seq < next) {
00135         // Duplicate packet case 1: the packet is to the left edge of
00136         // the receive window; therefore we must have seen it
00137         // before
00138 #ifdef DEBUGDSACK
00139         printf("%f\t Received duplicate packet %d\n",Scheduler::instance().clock(),seq);
00140 #endif
00141         is_dup_ = TRUE;
00142     }
00143 
00144     if (seq >= next && seq <= maxseen_) {
00145         // next is the left edge of the recv window; maxseen_
00146         // is the right edge; execute this block if there are
00147         // missing packets in the recv window AND if current
00148         // packet falls within those gaps
00149 
00150         if (seen_[seq & wndmask_] && !just_marked_as_seen) {
00151         // Duplicate case 2: the segment has already been
00152         // recorded as being received (AND not because we just
00153         // marked it as such)
00154             is_dup_ = TRUE;
00155 #ifdef DEBUGDSACK
00156             printf("%f\t Received duplicate packet %d\n",Scheduler::instance().clock(),seq);
00157 #endif
00158         }
00159         seen_[seq & wndmask_] = numBytes;
00160         // record the packet as being seen
00161         while (seen_[next & wndmask_]) {
00162             // this loop first gets executed if seq==next;
00163             // i.e., this is the next packet in order that
00164             // we've been waiting for.  the loop sets how
00165             // many bytes we can now deliver to the
00166             // application, due to this packet arriving
00167             // (and the prior arrival of any segments
00168             // immediately to the right)
00169 
00170             numToDeliver += seen_[next & wndmask_];
00171             ++next;
00172         }
00173         next_ = next;
00174         // store the new left edge of the window
00175     }
00176     return numToDeliver;
00177 }
00178 
00179 TcpSink::TcpSink(Acker* acker) : Agent(PT_ACK), acker_(acker), save_(NULL),
00180     lastreset_(0.0)
00181 {
00182     bytes_ = 0; 
00183     bind("bytes_", &bytes_);
00184 
00185     /*
00186      * maxSackBlocks_ does wierd tracing things.
00187      * don't make it delay-bound yet.
00188      */
00189 #if defined(TCP_DELAY_BIND_ALL) && 0
00190 #else /* ! TCP_DELAY_BIND_ALL */
00191     bind("maxSackBlocks_", &max_sack_blocks_); // used only by sack
00192 #endif /* TCP_DELAY_BIND_ALL */
00193 }
00194 
00195 void
00196 TcpSink::delay_bind_init_all()
00197 {
00198         delay_bind_init_one("packetSize_");
00199         delay_bind_init_one("ts_echo_bugfix_");
00200     delay_bind_init_one("ts_echo_rfc1323_");
00201     delay_bind_init_one("bytes_"); // For throughput measurements in JOBS
00202         delay_bind_init_one("generateDSacks_"); // used only by sack
00203     delay_bind_init_one("qs_enabled_");
00204     delay_bind_init_one("RFC2581_immediate_ack_");
00205 #if defined(TCP_DELAY_BIND_ALL) && 0
00206         delay_bind_init_one("maxSackBlocks_");
00207 #endif /* TCP_DELAY_BIND_ALL */
00208 
00209     Agent::delay_bind_init_all();
00210 }
00211 
00212 int
00213 TcpSink::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
00214 {
00215         if (delay_bind(varName, localName, "packetSize_", &size_, tracer)) return TCL_OK;
00216         if (delay_bind_bool(varName, localName, "ts_echo_bugfix_", &ts_echo_bugfix_, tracer)) return TCL_OK;
00217     if (delay_bind_bool(varName, localName, "ts_echo_rfc1323_", &ts_echo_rfc1323_, tracer)) return TCL_OK;
00218         if (delay_bind_bool(varName, localName, "generateDSacks_", &generate_dsacks_, tracer)) return TCL_OK;
00219         if (delay_bind_bool(varName, localName, "qs_enabled_", &qs_enabled_, tracer)) return TCL_OK;
00220         if (delay_bind_bool(varName, localName, "RFC2581_immediate_ack_", &RFC2581_immediate_ack_, tracer)) return TCL_OK;
00221 #if defined(TCP_DELAY_BIND_ALL) && 0
00222         if (delay_bind(varName, localName, "maxSackBlocks_", &max_sack_blocks_, tracer)) return TCL_OK;
00223 #endif /* TCP_DELAY_BIND_ALL */
00224 
00225         return Agent::delay_bind_dispatch(varName, localName, tracer);
00226 }
00227 
00228 void Acker::append_ack(hdr_cmn*, hdr_tcp*, int) const
00229 {
00230 }
00231 
00232 void Acker::update_ecn_unacked(int value)
00233 {
00234     ecn_unacked_ = value;
00235 }
00236 
00237 int TcpSink::command(int argc, const char*const* argv)
00238 {
00239     if (argc == 2) {
00240         if (strcmp(argv[1], "reset") == 0) {
00241             reset();
00242             return (TCL_OK);
00243         }
00244         if (strcmp(argv[1], "resize_buffers") == 0) {
00245             // no need for this as seen buffer set dynamically
00246             fprintf(stderr,"DEPRECIATED: resize_buffers\n");
00247             return (TCL_OK);
00248         }
00249     }
00250 
00251     return (Agent::command(argc, argv));
00252 }
00253 
00254 void TcpSink::reset() 
00255 {
00256     acker_->reset();    
00257     save_ = NULL;
00258     lastreset_ = Scheduler::instance().clock(); /* W.N. - for detecting */
00259                 /* packets from previous incarnations */
00260 }
00261 
00262 void TcpSink::ack(Packet* opkt)
00263 {
00264     Packet* npkt = allocpkt();
00265     // opkt is the "old" packet that was received
00266     // npkt is the "new" packet being constructed (for the ACK)
00267     double now = Scheduler::instance().clock();
00268 
00269     hdr_tcp *otcp = hdr_tcp::access(opkt);
00270     hdr_ip *oiph = hdr_ip::access(opkt);
00271     hdr_tcp *ntcp = hdr_tcp::access(npkt);
00272 
00273     if (qs_enabled_) {
00274         // QuickStart code from Srikanth Sundarrajan.
00275         hdr_qs *oqsh = hdr_qs::access(opkt);
00276         hdr_qs *nqsh = hdr_qs::access(npkt);
00277             if (otcp->seqno() == 0 && oqsh->flag() == QS_REQUEST) {
00278                     nqsh->flag() = QS_RESPONSE;
00279                     nqsh->ttl() = (oiph->ttl() - oqsh->ttl()) % 256;
00280                     nqsh->rate() = (oqsh->rate() < MWS) ? oqsh->rate() : MWS;
00281             }
00282             else {
00283                     nqsh->flag() = QS_DISABLE;
00284             }
00285     }
00286 
00287 
00288     // get the tcp headers
00289     ntcp->seqno() = acker_->Seqno();
00290     // get the cumulative sequence number to put in the ACK; this
00291     // is just the left edge of the receive window - 1
00292     ntcp->ts() = now;
00293     // timestamp the packet
00294 
00295     if (ts_echo_bugfix_)  /* TCP/IP Illustrated, Vol. 2, pg. 870 */
00296         ntcp->ts_echo() = acker_->ts_to_echo();
00297     else
00298         ntcp->ts_echo() = otcp->ts();
00299     // echo the original's time stamp
00300 
00301     hdr_ip* oip = hdr_ip::access(opkt);
00302     hdr_ip* nip = hdr_ip::access(npkt);
00303     // get the ip headers
00304     nip->flowid() = oip->flowid();
00305     // copy the flow id
00306     
00307     hdr_flags* of = hdr_flags::access(opkt);
00308     hdr_flags* nf = hdr_flags::access(npkt);
00309     hdr_flags* sf;
00310     if (save_ != NULL)
00311         sf = hdr_flags::access(save_);
00312     else 
00313         sf = 0;
00314         // Look at delayed packet being acked. 
00315     if ( (sf != 0 && sf->cong_action()) || of->cong_action() ) 
00316         // Sender has responsed to congestion. 
00317         acker_->update_ecn_unacked(0);
00318     if ( (sf != 0 && sf->ect() && sf->ce())  || 
00319             (of->ect() && of->ce()) )
00320         // New report of congestion.  
00321         acker_->update_ecn_unacked(1);
00322     if ( (sf != 0 && sf->ect()) || of->ect() )
00323         // Set EcnEcho bit.  
00324         nf->ecnecho() = acker_->ecn_unacked();
00325     if (!of->ect() && of->ecnecho() ||
00326         (sf != 0 && !sf->ect() && sf->ecnecho()) ) 
00327          // This is the negotiation for ECN-capability.
00328          // We are not checking for of->cong_action() also. 
00329          // In this respect, this does not conform to the 
00330          // specifications in the internet draft 
00331         nf->ecnecho() = 1;
00332     acker_->append_ack(hdr_cmn::access(npkt),
00333                ntcp, otcp->seqno());
00334     add_to_ack(npkt);
00335     // the above function is used in TcpAsymSink
00336 
00337         // Andrei Gurtov
00338         acker_->last_ack_sent_ = ntcp->seqno();
00339         // printf("ACK %d ts %f\n", ntcp->seqno(), ntcp->ts_echo());
00340     
00341     send(npkt, 0);
00342     // send it
00343 }
00344 
00345 void TcpSink::add_to_ack(Packet*)
00346 {
00347     return;
00348 }
00349 
00350 
00351 void TcpSink::recv(Packet* pkt, Handler*)
00352 {
00353     int numToDeliver;
00354     int numBytes = hdr_cmn::access(pkt)->size();
00355     // number of bytes in the packet just received
00356     hdr_tcp *th = hdr_tcp::access(pkt);
00357     /* W.N. Check if packet is from previous incarnation */
00358     if (th->ts() < lastreset_) {
00359         // Remove packet and do nothing
00360         Packet::free(pkt);
00361         return;
00362     }
00363     acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);
00364     // update the timestamp to echo
00365     
00366         numToDeliver = acker_->update(th->seqno(), numBytes);
00367     // update the recv window; figure out how many in-order-bytes
00368     // (if any) can be removed from the window and handed to the
00369     // application
00370     if (numToDeliver) {
00371         bytes_ += numToDeliver;
00372         recvBytes(numToDeliver);
00373     }
00374     // send any packets to the application
00375         ack(pkt);
00376     // ACK the packet
00377     Packet::free(pkt);
00378     // remove it from the system
00379 }
00380 
00381 static class DelSinkClass : public TclClass {
00382 public:
00383     DelSinkClass() : TclClass("Agent/TCPSink/DelAck") {}
00384     TclObject* create(int, const char*const*) {
00385         return (new DelAckSink(new Acker));
00386     }
00387 } class_delsink;
00388 
00389 DelAckSink::DelAckSink(Acker* acker) : TcpSink(acker), delay_timer_(this)
00390 {
00391     bind_time("interval_", &interval_);
00392     // Deleted the line below, since this is bound in TcpSink.
00393     // bind("bytes_", &bytes_); // useby JOBS
00394 }
00395 
00396 void DelAckSink::reset() {
00397     if (delay_timer_.status() == TIMER_PENDING)
00398         delay_timer_.cancel();
00399     TcpSink::reset();
00400 }
00401 
00402 void DelAckSink::recv(Packet* pkt, Handler*)
00403 {
00404     int numToDeliver;
00405     int numBytes = hdr_cmn::access(pkt)->size();
00406     hdr_tcp *th = hdr_tcp::access(pkt);
00407     /* W.N. Check if packet is from previous incarnation */
00408     if (th->ts() < lastreset_) {
00409         // Remove packet and do nothing
00410         Packet::free(pkt);
00411         return;
00412     }
00413     acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);
00414     numToDeliver = acker_->update(th->seqno(), numBytes);
00415     if (numToDeliver) {
00416                 bytes_ += numToDeliver; // for JOBS
00417                 recvBytes(numToDeliver);
00418         }
00419     
00420         // If there's no timer and the packet is in sequence, set a timer.
00421         // Otherwise, send the ack and update the timer.
00422         if (delay_timer_.status() != TIMER_PENDING &&
00423                                 th->seqno() == acker_->Seqno()) {
00424                 // There's no timer, so we can set one and choose
00425         // to delay this ack.
00426         // If we're following RFC2581 (section 4.2) exactly,
00427         // we should only delay the ACK if we're know we're
00428         // not doing recovery, i.e. not gap-filling.
00429         // Since this is a change to previous ns behaviour,
00430         // it's controlled by an optional bound flag.
00431         // discussed April 2000 in the ns-users list archives.
00432         if (RFC2581_immediate_ack_ && 
00433             (th->seqno() < acker_->Maxseen())) {
00434             // don't delay the ACK since
00435             // we're filling in a gap
00436         } else {
00437             // delay the ACK and start the timer.
00438                     save_ = pkt;
00439                     delay_timer_.resched(interval_);
00440                     return;
00441         }
00442         }
00443         // If there was a timer, turn it off.
00444     if (delay_timer_.status() == TIMER_PENDING) 
00445         delay_timer_.cancel();
00446     ack(pkt);
00447         if (save_ != NULL) {
00448                 Packet::free(save_);
00449                 save_ = NULL;
00450         }
00451 
00452     Packet::free(pkt);
00453 }
00454 
00455 void DelAckSink::timeout(int)
00456 {
00457     // The timer expired so we ACK the last packet seen.
00458     if ( save_ != NULL ) {
00459         Packet* pkt = save_;
00460         ack(pkt);
00461         save_ = NULL;
00462         Packet::free(pkt);
00463     }
00464 }
00465 
00466 void DelayTimer::expire(Event* /*e*/) {
00467     a_->timeout(0);
00468 }
00469 
00470 /* "sack1-tcp-sink" is for Matt and Jamshid's implementation of sack. */
00471 
00472 class SackStack {
00473 protected:
00474     int size_;
00475     int cnt_;
00476     struct Sf_Entry {
00477         int left_;
00478         int right_;
00479     } *SFE_;
00480 public:
00481     SackStack(int);     // create a SackStack of size (int)
00482     ~SackStack();
00483     int& head_right(int n = 0) { return SFE_[n].right_; }
00484     int& head_left(int n = 0) { return SFE_[n].left_; }
00485     int cnt() { return cnt_; }      // how big is the stack
00486     void reset() {
00487         register int i;
00488         for (i = 0; i < cnt_; i++)
00489             SFE_[i].left_ = SFE_[i].right_ = -1;
00490 
00491         cnt_ = 0;
00492     }
00493 
00494     inline void push(int n = 0) {
00495         if (cnt_ >= size_) cnt_ = size_ - 1;  // overflow check
00496         register int i;
00497         for (i = cnt_-1; i >= n; i--)
00498             SFE_[i+1] = SFE_[i];    // not efficient for big size
00499         cnt_++;
00500     }
00501 
00502     inline void pop(int n = 0) {
00503         register int i;
00504         for (i = n; i < cnt_-1; i++)
00505             SFE_[i] = SFE_[i+1];    // not efficient for big size
00506         SFE_[i].left_ = SFE_[i].right_ = -1;
00507         cnt_--;
00508     }
00509 };
00510 
00511 SackStack::SackStack(int sz)
00512 {
00513     register int i;
00514     size_ = sz;
00515     SFE_ = new Sf_Entry[sz];
00516     for (i = 0; i < sz; i++)
00517         SFE_[i].left_ = SFE_[i].right_ = -1;
00518     cnt_ = 0;
00519 }
00520 
00521 SackStack::~SackStack()
00522 {
00523     delete SFE_;
00524 }
00525 
00526 static class Sack1TcpSinkClass : public TclClass {
00527 public:
00528         Sack1TcpSinkClass() : TclClass("Agent/TCPSink/Sack1") {}
00529     TclObject* create(int, const char*const*) {
00530         Sacker* sacker = new Sacker;
00531         TcpSink* sink = new TcpSink(sacker);
00532         sacker->configure(sink);
00533         return (sink);
00534         }
00535 } class_sack1tcpsink;
00536 
00537 static class Sack1DelAckTcpSinkClass : public TclClass {
00538 public:
00539     Sack1DelAckTcpSinkClass() : TclClass("Agent/TCPSink/Sack1/DelAck") {}
00540     TclObject* create(int, const char*const*) {
00541         Sacker* sacker = new Sacker;
00542         TcpSink* sink = new DelAckSink(sacker);
00543         sacker->configure(sink);
00544         return (sink);
00545     }
00546 } class_sack1delacktcpsink;
00547 
00548 void Sacker::configure(TcpSink *sink)
00549 {
00550     if (sink == NULL) {
00551         fprintf(stderr, "warning: Sacker::configure(): no TCP sink!\n");
00552         return;
00553     }
00554 
00555     TracedInt& nblocks = sink->max_sack_blocks_;
00556     if (int(nblocks) > NSA) {
00557         fprintf(stderr, "warning(Sacker::configure): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(nblocks));
00558         nblocks = NSA;
00559     }
00560     sf_ = new SackStack(int(nblocks));
00561     nblocks.tracer(this);
00562     base_nblocks_ = int(nblocks);
00563     dsacks_ = &(sink->generate_dsacks_);
00564 }
00565 
00566 void
00567 Sacker::trace(TracedVar *v)
00568 {
00569     // we come here if "nblocks" changed
00570     TracedInt* ti = (TracedInt*) v;
00571 
00572     if (int(*ti) > NSA) {
00573         fprintf(stderr, "warning(Sacker::trace): TCP header limits number of SACK blocks to %d, not %d\n", NSA, int(*ti));
00574         *ti = NSA;
00575     }
00576 
00577     int newval = int(*ti);
00578     delete sf_;
00579     sf_ = new SackStack(newval);
00580     base_nblocks_ = newval;
00581 }
00582 
00583 void Sacker::reset() 
00584 {
00585     sf_->reset();
00586     Acker::reset();
00587 }
00588 
00589 Sacker::~Sacker()
00590 {
00591     delete sf_;
00592 }
00593 
00594 void Sacker::append_ack(hdr_cmn* ch, hdr_tcp* h, int old_seqno) const
00595 {
00596     // ch and h are the common and tcp headers of the Ack being constructed
00597     // old_seqno is the sequence # of the packet we just got
00598     
00599         int sack_index, i, sack_right, sack_left;
00600     int recent_sack_left, recent_sack_right;
00601           
00602     int seqno = Seqno();
00603     // the last in-order packet seen (i.e. the cumulative ACK # - 1)
00604 
00605         sack_index = 0;
00606     sack_left = sack_right = -1;
00607     // initialization; sack_index=0 and sack_{left,right}= -1
00608 
00609         if (old_seqno < 0) {
00610                 printf("Error: invalid packet number %d\n", old_seqno);
00611         } else if (seqno >= maxseen_ && (sf_->cnt() != 0))
00612         sf_->reset();
00613     // if the Cumulative ACK seqno is at or beyond the right edge
00614     // of the window, and if the SackStack is not empty, reset it
00615     // (empty it)
00616     else if (( (seqno < maxseen_) || is_dup_ ) && (base_nblocks_ > 0)) {
00617         // Otherwise, if the received packet is to the left of
00618         // the right edge of the receive window (but not at
00619         // the right edge), OR if it is a duplicate, AND we
00620         // can have 1 or more Sack blocks, then execute the
00621         // following, which computes the most recent Sack
00622         // block
00623 
00624         if ((*dsacks_) && is_dup_) {
00625             // Record the DSACK Block
00626             h->sa_left(sack_index) = old_seqno;
00627             h->sa_right(sack_index) = old_seqno+1;
00628             // record the block
00629             sack_index++;
00630 #ifdef DEBUGDSACK
00631             printf("%f\t Generating D-SACK for packet %d\n", Scheduler::instance().clock(),old_seqno);
00632 #endif
00633 
00634             
00635         }
00636 
00637         //  Build FIRST (traditional) SACK block
00638 
00639         // If we already had a DSACK block due to a duplicate
00640         // packet, and if that duplicate packet is in the
00641         // receiver's window (i.e. the packet's sequence
00642         // number is > than the cumulative ACK) then the
00643         // following should find the SACK block it's a subset
00644         // of.  If it's <= cum ACK field then the following
00645         // shouldn't record a superset SACK block for it.
00646 
00647                 if (sack_index >= base_nblocks_) {
00648             printf("Error: can't use DSACK with less than 2 SACK blocks\n");
00649         } else {
00650                 sack_right=-1;
00651 
00652         // look rightward for first hole 
00653         // start at the current packet 
00654                 for (i=old_seqno; i<=maxseen_; i++) {
00655             if (!seen_[i & wndmask_]) {
00656                 sack_right=i;
00657                 break;
00658             }
00659         }
00660 
00661         // if there's no hole set the right edge of the sack
00662         // to be the next expected packet
00663                 if (sack_right == -1) {
00664             sack_right = maxseen_+1;
00665                 }
00666 
00667         // if the current packet's seqno is smaller than the
00668         // left edge of the window, set the sack_left to 0
00669         if (old_seqno <= seqno) {
00670             sack_left = 0;
00671             // don't record/send the block
00672         } else {
00673             // look leftward from right edge for first hole 
00674                     for (i = sack_right-1; i > seqno; i--) {
00675                 if (!seen_[i & wndmask_]) {
00676                     sack_left = i+1;
00677                     break;
00678                 }
00679                     }
00680             h->sa_left(sack_index) = sack_left;
00681             h->sa_right(sack_index) = sack_right;
00682             
00683             // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %i\n" ,old_seqno, seqno, sack_index, sack_left, sack_right);
00684             // record the block
00685             sack_index++;
00686         }
00687 
00688         recent_sack_left = sack_left;
00689         recent_sack_right = sack_right;
00690 
00691         // first sack block is built, check the others 
00692         // make sure that if max_sack_blocks has been made
00693         // large from tcl we don't over-run the stuff we
00694         // allocated in Sacker::Sacker()
00695         int k = 0;
00696                 while (sack_index < base_nblocks_) {
00697 
00698             sack_left = sf_->head_left(k);
00699             sack_right = sf_->head_right(k);
00700 
00701             // no more history 
00702             if (sack_left < 0 || sack_right < 0 ||
00703                 sack_right > maxseen_ + 1)
00704                 break;
00705 
00706             // newest ack "covers up" this one 
00707 
00708             if (recent_sack_left <= sack_left &&
00709                 recent_sack_right >= sack_right) {
00710                 sf_->pop(k);
00711                 continue;
00712             }
00713 
00714             h->sa_left(sack_index) = sack_left;
00715             h->sa_right(sack_index) = sack_right;
00716             
00717             // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %i\n" ,old_seqno, seqno, sack_index, sack_left, sack_right);
00718             
00719             // store the old sack (i.e. move it down one)
00720             sack_index++;
00721             k++;
00722                 }
00723 
00724 
00725         if (old_seqno > seqno) {
00726             /* put most recent block onto stack */
00727             sf_->push();
00728             // this just moves things down 1 from the
00729             // beginning, but it doesn't push any values
00730             // on the stack
00731             sf_->head_left() = recent_sack_left;
00732             sf_->head_right() = recent_sack_right;
00733             // this part stores the left/right values at
00734             // the top of the stack (slot 0)
00735         }
00736 
00737         } // this '}' is for the DSACK base_nblocks_ >= test;
00738           // (didn't feel like re-indenting all the code and 
00739           // causing a large diff)
00740         
00741         }
00742     h->sa_length() = sack_index;
00743     // set the Length of the sack stack in the header
00744     ch->size() += sack_index * 8;
00745     // change the size of the common header to account for the
00746     // Sack strings (2 4-byte words for each element)
00747 }

Generated on Tue Mar 6 16:47:52 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6