tcp-int.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  * Contributed by the Daedalus Research Group, U.C.Berkeley
00035  * http://daedalus.cs.berkeley.edu
00036  *
00037  * $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-int.cc,v 1.15 2000/09/01 03:04:07 haoboy Exp $
00038  */
00039 
00040 
00041 /*
00042  * We separate TCP functionality into two parts: that having to do with 
00043  * providing a reliable, ordered byte-stream service, and that having to do with
00044  * congestion control and loss recovery. The former is done on a per-connection
00045  * basis and is implemented as part of IntTcpAgent ("integrated TCP"). The 
00046  * latter is done in an integrated fashion across multiple TCP connections, and
00047  * is implemented as part of TcpSessionAgent ("TCP session"). TcpSessionAgent is
00048  * derived from CorresHost ("correspondent host"), which keeps track of the 
00049  * state of all TCP (TCP/Int) connections to a host that it is corresponding 
00050  * with.
00051  *
00052  * The motivation for this separation of functionality is to make an ensemble of
00053  * connection more well-behaved than a set of independent TCP connections.
00054  * The packet loss rate is cut down and the chances of losses being recovered 
00055  * via data-driven techniques (rather than via timeouts) is improved. At the 
00056  * same time, we do not introduce any unnecessary coupling between the 
00057  * logically-independent byte-streams that the set of connections represents. 
00058  * This is in contrast to the coupling that is inherent in the multiplexing at 
00059  * the application layer of multiple byte-streams onto a single TCP connection.
00060  */
00061 
00062 #include <stdio.h>
00063 #include <stdlib.h>
00064 #include <sys/types.h>
00065 
00066 #include "packet.h"
00067 #include "ip.h"
00068 #include "tcp.h"
00069 #include "flags.h"
00070 #include "nilist.h"
00071 #include "tcp-int.h"
00072 #include "chost.h"
00073 #include "tcp-session.h"
00074 #include "random.h"
00075 
00076 Islist<TcpSessionAgent> TcpSessionAgent::sessionList_;
00077 
00078 static class IntTcpClass : public TclClass {
00079 public:
00080     IntTcpClass() : TclClass("Agent/TCP/Int") {}
00081     TclObject* create(int, const char*const*) {
00082         return (new IntTcpAgent());
00083     }
00084 } class_tcp_int;
00085 
00086 IntTcpAgent::IntTcpAgent() : TcpAgent(), slink(), 
00087     session_(0), closecwTS_(0), lastTS_(-1), count_(0), 
00088     wt_(1), wndIncSeqno_(0), num_thresh_dupack_segs_(0)
00089 {
00090     bind("rightEdge_", &rightEdge_);
00091     bind("uniqTS_", &uniqTS_);
00092     bind("winInc_", &winInc_);
00093     bind("winMult_", &winMult_);
00094 }
00095 
00096 int
00097 IntTcpAgent::command(int argc, const char*const* argv)
00098 {
00099     Tcl& tcl = Tcl::instance();
00100 
00101     if (argc == 3) {
00102         if (!strcmp(argv[1], "setwt")) {
00103             if (!session_)
00104                 createTcpSession();
00105             session_->set_weight(this,atoi(argv[2]));
00106             return (TCL_OK);
00107         }
00108     }
00109     else if (argc == 2) {
00110         if (!strcmp(argv[1], "session")) {
00111             if (!session_)
00112                 createTcpSession();
00113             tcl.resultf("%s", session_->name());
00114             return (TCL_OK);
00115         }
00116     }
00117     return (TcpAgent::command(argc,argv));
00118 }
00119 
00120 /* 
00121  * Update the ack information and reset the timer. RTT update is done in 
00122  * TcpSessionAgent.
00123  */
00124 void
00125 IntTcpAgent::newack(Packet* pkt)
00126 {
00127     hdr_tcp *tcph = hdr_tcp::access(pkt);
00128     last_ack_ = tcph->seqno();
00129     highest_ack_ = last_ack_;
00130 
00131     if (t_seqno_ < last_ack_ + 1)
00132         t_seqno_ = last_ack_ + 1;
00133     /* if the connection is done, call finish() */
00134     if ((highest_ack_ >= curseq_-1) && !closed_) {
00135         closed_ = 1;
00136         finish();
00137     }
00138 }
00139 
00140 void 
00141 IntTcpAgent::recv(Packet *pkt, Handler *)
00142 {
00143     hdr_tcp *tcph = hdr_tcp::access(pkt);
00144     int amt_data_acked = 0;
00145 
00146     if (tcph->seqno() > last_ack_) {
00147         amt_data_acked = tcph->seqno() - last_ack_;
00148         newack(pkt);
00149     } 
00150     session_->recv(this, pkt, amt_data_acked);
00151 }
00152 
00153 void
00154 IntTcpAgent::createTcpSession()
00155 {
00156     Tcl& tcl = Tcl::instance();
00157 
00158     tcl.evalf("%s set node_", name());
00159     tcl.evalf("%s createTcpSession %d", tcl.result(), daddr());
00160     Islist_iter<TcpSessionAgent> session_iter(TcpSessionAgent::sessionList_);
00161     TcpSessionAgent *cur;
00162 
00163     while ((cur = session_iter()) != NULL) {
00164         if (cur->addr()/256 == addr() && cur->daddr() == daddr()) {
00165             session_ = cur;
00166             break;
00167         }
00168     }
00169     if (!session_) {
00170         printf("In IntTcpAgent::createTcpSession(): failed\n");
00171         abort();
00172     }
00173     session_->add_agent(this, size_, winMult_, winInc_, ssthresh_);
00174 }
00175 
00176 void
00177 IntTcpAgent::output(int seqno, int reason)
00178 {
00179     Packet *pkt = allocpkt();
00180     hdr_tcp *tcph = hdr_tcp::access(pkt);
00181     tcph->seqno() = seqno;
00182     tcph->ts() = Scheduler::instance().clock();
00183     tcph->ts_echo() = ts_peer_;
00184     tcph->reason() = reason;
00185 
00186     session_->setflags(pkt);
00187     
00188     int bytes = hdr_cmn::access(pkt)->size();
00189 
00190     /* call helper function to fill in additional fields */
00191     output_helper(pkt);
00192 
00193         ++ndatapack_;
00194     ndatabytes_ += bytes;
00195     send(pkt, 0);
00196     if (seqno == curseq_ && seqno > maxseq_)
00197         idle();  // Tell application I have sent everything so far
00198     if (seqno > maxseq_) {
00199         maxseq_ = seqno;
00200     }
00201     else {
00202             ++nrexmitpack_;
00203             nrexmitbytes_ += bytes;
00204     }
00205     if (wndIncSeqno_ == 0)
00206         wndIncSeqno_ = maxseq_;
00207 }
00208 
00209 
00210 /*
00211  * Unlike in other flavors of TCP, IntTcpAgent does not decide when to send 
00212  * packets and how many of them to send. That decision is made by 
00213  * TcpSessionAgent. So send_much() does little more than defer to 
00214  * TcpSessionAgent.
00215  */
00216 void
00217 IntTcpAgent::send_much(int force, int reason, int /*maxburst*/)
00218 {
00219     if (!session_)
00220         createTcpSession();
00221     if (!force && delsnd_timer_.status() == TIMER_PENDING)
00222         return;
00223     if (overhead_ && !force) {
00224         delsnd_timer_.resched(Random::uniform(overhead_));
00225         return;
00226     }
00227     session_->send_much(this, force,reason);
00228 }
00229 
00230 /*
00231  * Send one new packet.
00232  */
00233 void
00234 IntTcpAgent::send_one(int sessionSeqno)
00235 {
00236     int dst_addr = daddr();
00237     int dst_port = dport();
00238     int sport = port();
00239 
00240     if (!session_)
00241         createTcpSession();
00242     /* 
00243      * XXX We assume that the session layer has already made sure that
00244      * we have data to send.
00245      */
00246     output(t_seqno_++); 
00247     session_->add_pkts(size_, t_seqno_ - 1, sessionSeqno,
00248                dst_addr, dst_port, sport, lastTS_, this); 
00249 }
00250 
00251 
00252 /*
00253  * open up the congestion window
00254  */
00255 void 
00256 IntTcpAgent::opencwnd()
00257 {
00258     session_->opencwnd(size_, this);
00259 }
00260 
00261 /*
00262  * close down the congestion window
00263  */
00264 void 
00265 IntTcpAgent::closecwnd(int how)
00266 {   
00267     session_->closecwnd(how, this);
00268 }
00269 
00270 Segment *
00271 IntTcpAgent::rxmit_last(int reason, int seqno, int sessionSeqno, double /*ts*/)
00272 {
00273     session_->agent_rcov(this);
00274     /* 
00275      * XXX kludge -- IntTcpAgent is not supposed to deal with 
00276      * rtx timer 
00277      */
00278     session_->reset_rtx_timer(1,0); 
00279     output(seqno, reason);
00280     daddr_ = daddr();
00281     dport_ = dport();
00282     sport_ = port();
00283     return (session_->add_pkts(size_, seqno, sessionSeqno, daddr_, 
00284                    dport_, sport_, lastTS_, this));
00285     return NULL;
00286 }
00287 unsigned long output_helper_count=0;
00288 double last_clock=0;
00289 void
00290 IntTcpAgent::output_helper(Packet *p)
00291 {
00292     double now = Scheduler::instance().clock();
00293     output_helper_count++;
00294     last_clock = now;
00295     hdr_tcp *tcph = hdr_tcp::access(p);
00296 
00297     /* This is to make sure that we get unique times for each xmission */
00298     while (uniqTS_ && now <= lastTS_) {
00299         now += 0.000001; // something arbitrarily small
00300     }
00301 
00302     lastTS_ = now;
00303     tcph->ts() = now;
00304     /* if this is a fast start pkt and not a retransmission, mark it */
00305     if (session_->fs_pkt() && tcph->seqno() > maxseq_)
00306         hdr_flags::access(p)->fs_ = 1;
00307     return;
00308 }
00309 
00310 int 
00311 IntTcpAgent::data_left_to_send() {
00312     return (curseq_ > t_seqno_);
00313 }

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