00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] =
00022 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-reno.cc,v 1.42 2005/07/13 03:51:32 tomh Exp $ (LBL)";
00023 #endif
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <sys/types.h>
00028
00029 #include "ip.h"
00030 #include "tcp.h"
00031 #include "flags.h"
00032
00033
00034 static class RenoTcpClass : public TclClass {
00035 public:
00036 RenoTcpClass() : TclClass("Agent/TCP/Reno") {}
00037 TclObject* create(int, const char*const*) {
00038 return (new RenoTcpAgent());
00039 }
00040 } class_reno;
00041
00042 int RenoTcpAgent::window()
00043 {
00044
00045
00046
00047
00048
00049 int win = int(cwnd_) + dupwnd_;
00050 if (frto_ == 2) {
00051
00052
00053 win = force_wnd(2);
00054 }
00055 if (win > int(wnd_))
00056 win = int(wnd_);
00057 return (win);
00058 }
00059
00060 double RenoTcpAgent::windowd()
00061 {
00062
00063
00064
00065
00066
00067 double win = cwnd_ + dupwnd_;
00068 if (win > wnd_)
00069 win = wnd_;
00070 return (win);
00071 }
00072
00073 RenoTcpAgent::RenoTcpAgent() : TcpAgent(), dupwnd_(0)
00074 {
00075 }
00076
00077 void RenoTcpAgent::recv(Packet *pkt, Handler*)
00078 {
00079 hdr_tcp *tcph = hdr_tcp::access(pkt);
00080 int valid_ack = 0;
00081 if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
00082 endQuickStart();
00083 if (qs_requested_ == 1)
00084 processQuickStart(pkt);
00085 #ifdef notdef
00086 if (pkt->type_ != PT_ACK) {
00087 fprintf(stderr,
00088 "ns: confiuration error: tcp received non-ack\n");
00089 exit(1);
00090 }
00091 #endif
00092
00093 if (tcph->ts() < lastreset_) {
00094
00095 Packet::free(pkt);
00096 return;
00097 }
00098 ++nackpack_;
00099 ts_peer_ = tcph->ts();
00100
00101 if (hdr_flags::access(pkt)->ecnecho() && ecn_)
00102 ecn(tcph->seqno());
00103 recv_helper(pkt);
00104 recv_frto_helper(pkt);
00105 if (tcph->seqno() > last_ack_) {
00106 if (last_cwnd_action_ == CWND_ACTION_DUPACK)
00107 last_cwnd_action_ = CWND_ACTION_EXITED;
00108 dupwnd_ = 0;
00109 recv_newack_helper(pkt);
00110 if (last_ack_ == 0 && delay_growth_) {
00111 cwnd_ = initial_window();
00112 }
00113 } else if (tcph->seqno() == last_ack_) {
00114 if (hdr_flags::access(pkt)->eln_ && eln_) {
00115 tcp_eln(pkt);
00116 return;
00117 }
00118 if (++dupacks_ == numdupacks_) {
00119 dupack_action();
00120 if (!exitFastRetrans_)
00121 dupwnd_ = numdupacks_;
00122 } else if (dupacks_ > numdupacks_ && (!exitFastRetrans_
00123 || last_cwnd_action_ == CWND_ACTION_DUPACK )) {
00124 ++dupwnd_;
00125 } else if (dupacks_ < numdupacks_ && singledup_ ) {
00126 send_one();
00127 }
00128 }
00129 if (tcph->seqno() >= last_ack_)
00130
00131 valid_ack = 1;
00132 Packet::free(pkt);
00133 #ifdef notyet
00134 if (trace_)
00135 plot();
00136 #endif
00137
00138
00139
00140
00141
00142 if (valid_ack || aggressive_maxburst_)
00143 if (dupacks_ == 0 || dupacks_ > numdupacks_ - 1)
00144 send_much(0, 0, maxburst_);
00145 }
00146
00147 int
00148 RenoTcpAgent::allow_fast_retransmit(int last_cwnd_action_)
00149 {
00150 return (last_cwnd_action_ == CWND_ACTION_DUPACK);
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 void
00171 RenoTcpAgent::dupack_action()
00172 {
00173 int recovered = (highest_ack_ > recover_);
00174 int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_);
00175 if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit) {
00176 goto reno_action;
00177 }
00178
00179 if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
00180 last_cwnd_action_ = CWND_ACTION_DUPACK;
00181
00182
00183
00184
00185
00186
00187
00188
00189 reset_rtx_timer(1,0);
00190 output(last_ack_ + 1, TCP_REASON_DUPACK);
00191 dupwnd_ = numdupacks_;
00192 return;
00193 }
00194
00195 if (bug_fix_) {
00196
00197
00198
00199
00200
00201 return;
00202 }
00203
00204 reno_action:
00205
00206 trace_event("RENO_FAST_RETX");
00207 recover_ = maxseq_;
00208 last_cwnd_action_ = CWND_ACTION_DUPACK;
00209 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
00210 reset_rtx_timer(1,0);
00211 output(last_ack_ + 1, TCP_REASON_DUPACK);
00212 dupwnd_ = numdupacks_;
00213 return;
00214 }
00215
00216 void RenoTcpAgent::timeout(int tno)
00217 {
00218 if (tno == TCP_TIMER_RTX) {
00219 dupwnd_ = 0;
00220 dupacks_ = 0;
00221 if (bug_fix_) recover_ = maxseq_;
00222 TcpAgent::timeout(tno);
00223 } else {
00224 timeout_nonrtx(tno);
00225 }
00226 }