ack-recons.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 The 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 at Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group 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  * ack-recons.cc: contributed by the Daedalus Research Group, 
00035  * UC Berkeley (http://daedalus.cs.berkeley.edu).
00036  *
00037  * $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/ack-recons.cc,v 1.6 2000/09/01 03:04:05 haoboy Exp $
00038  */
00039 
00040 /*
00041  * TCP Ack reconstructor.  This object sits on the other end of a constrained 
00042  * link and intersperses TCP acks to the source (without violating the e2e 
00043  * semantics of TCP acks).  This allows us to get good performance for TCP 
00044  * over various asymmetric networks, in conjunction with techniques to reduce 
00045  * the frequency of acks (such as ack filtering) with making any changes to 
00046  * the TCP source (e.g., like those implemented in tcp-asym.cc).  
00047  */
00048 
00049 #include "template.h"
00050 #include "ack-recons.h"
00051 
00052 static class AckReconsControllerClass : public TclClass {
00053 public:
00054     AckReconsControllerClass() : TclClass("AckReconsControllerClass") { }
00055     TclObject* create(int, const char*const*) {
00056         return (new AckReconsController);
00057     }
00058 } class_ackrecons_controller;
00059 
00060 static class AckReconsClass : public TclClass {
00061 public:
00062     AckReconsClass() : TclClass("Agent/AckReconsClass") { }
00063     TclObject* create(int, const char*const* argv) {
00064         return new AckRecons(atoi(argv[4]), atoi(argv[5]));
00065     }
00066 } class_ackrecons;
00067 
00068 /*
00069  * Demux a packet to the right ack reconstructor.
00070  */
00071 void
00072 AckReconsController::recv(Packet *p, Handler *)
00073 {
00074     Tcl& tcl = Tcl::instance();
00075     hdr_ip *ip = hdr_ip::access(p);
00076     tcl.evalf("%s demux %d %d", name(),
00077           ip->saddr(), ip->daddr());
00078     AckRecons *ackRecons = 
00079         (AckRecons *) TclObject::lookup(tcl.result());
00080     if (ackRecons == NULL) {
00081         printf("Error: malformed ack reconstructor\n");
00082         abort();
00083     }
00084     ackRecons->spq_ = spq_;
00085     ackRecons->recv(p);
00086 }
00087 
00088 void 
00089 AckRecons::recv(Packet *pkt)
00090 {
00091     double now = Scheduler::instance().clock();
00092     hdr_tcp *tcph = hdr_tcp::access(pkt);
00093     int &ack = tcph->seqno(), a, i;
00094     Tcl& tcl = Tcl::instance();
00095 #ifdef DEBUG
00096     printf("%f\tRecd ack %d\n", now, ack);
00097 #endif
00098     if (ackTemplate_ == 0)
00099         ackTemplate_ = pkt->copy();
00100     if (adaptive_)
00101         tcl.evalf("%s ackbw %d %f\n", name(), ack, now);
00102     /* The ack spacing policy is implemented in Tcl for flexibility */
00103     tcl.evalf("%s spacing %d\n", name(), ack);
00104     /* 
00105      * If the difference in acks is less than a threshold, let
00106      * it go through.  Later, we will look for rapid ack arrivals
00107      * to smooth them out and avoid the adverse effects of ack comp.
00108      */
00109     if ((!ackPending_ && ack-lastAck_ <= deltaAckThresh_) || dupacks_) {
00110         if (ack == lastRealAck_)
00111             dupacks_++;
00112         else if (ack > lastAck_) {
00113             dupacks_ = 0;
00114             lastAck_ = ack;
00115             lastTime_ = now;
00116         }
00117         spq_->reconsAcks_ = 0;
00118         spq_->enque(pkt);
00119         spq_->reconsAcks_ = 1;
00120 #ifdef DEBUG
00121         printf("\t%f\tEnqueuing ack %d in order\n", now, ack);
00122 #endif
00123     } else {
00124         if (ack == lastRealAck_)
00125             dupacks_++;
00126         /* Intersperse some acks and schedule their transmissions. */
00127         double starttime = max(now, lastTime_);
00128         for (a = lastAck_+delack_, i=0; a <= ack; a += delack_, i++)
00129             sendack(a, starttime + i*ackSpacing_ - now);
00130         if ((a-ack)%delack_)
00131             sendack(ack, starttime + i*ackSpacing_ - now);
00132         Packet::free(pkt);
00133     }
00134     if (ack >= lastRealAck_) {
00135         lastRealAck_ = ack;
00136         lastRealTime_ = now;
00137     }
00138 }
00139 
00140 int
00141 AckRecons::command(int argc, const char*const* argv)
00142 {
00143     return Agent::command(argc, argv);
00144 }
00145 
00146 /*
00147  * Arrange to send ack a at time t from now.
00148  */
00149 void
00150 AckRecons::sendack(int ack, double t)
00151 {
00152     Packet *ackp = ackTemplate_->copy();
00153     Scheduler &s = Scheduler::instance();
00154     hdr_tcp *th = hdr_tcp::access(ackp);
00155     th->seqno() = ack;
00156     /* Set no_ts_ in flags because we don't want an rtt sample for this */
00157     if (th->ts() == hdr_tcp::access(ackp)->ts()) {
00158         hdr_flags *fh = hdr_flags::access(ackp);
00159         fh->no_ts_ = 1;
00160         th->ts_ = s.clock();    /* for debugging purposes only */
00161     }
00162     s.schedule((Handler *)this, (Event *)ackp, t);
00163     ackPending_++;
00164 #ifdef DEBUG
00165     printf("\t%f\tScheduling ack %d to be sent at %f\n", 
00166            s.clock(), ack, s.clock() + t);
00167 #endif
00168 }
00169 
00170 /* 
00171  * Handle scheduling of acks.
00172  */
00173 void
00174 AckRecons::handle(Event *e)
00175 {
00176     Packet *p = (Packet *) e;
00177     hdr_tcp *th = hdr_tcp::access(p);
00178     ackPending_--;
00179     if (lastAck_ < th->seqno()) {
00180         spq_->reconsAcks_ = 0;
00181         /* 
00182          * need to do queue's recv here, so that a deque is
00183          * forced if the queue isn't blocked.  It's not
00184          * sufficient to call spq_->recv() alone.
00185          */
00186         target_->recv(p); /* maybe do acksfirst for this ack? */
00187         spq_->reconsAcks_ = 1;
00188         lastTime_ = Scheduler::instance().clock();
00189         lastAck_ = th->seqno();
00190 #ifdef DEBUG
00191         printf("%f\tSending scheduled ack %d\n",lastTime_,th->seqno());
00192 #endif
00193     } else {
00194         Packet::free(p);
00195 #ifdef DEBUG
00196         printf("%f\tack %d superceded by ack %d at %f\n", 
00197                Scheduler::instance().clock(), th->seqno(), lastAck_,
00198                lastTime_);
00199 #endif
00200     }
00201 }

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