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.38 2003/01/27 02:34:38 sfloyd 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 (win > int(wnd_))
00051 win = int(wnd_);
00052 return (win);
00053 }
00054
00055 double RenoTcpAgent::windowd()
00056 {
00057
00058
00059
00060
00061
00062 double win = cwnd_ + dupwnd_;
00063 if (win > wnd_)
00064 win = wnd_;
00065 return (win);
00066 }
00067
00068 RenoTcpAgent::RenoTcpAgent() : TcpAgent(), dupwnd_(0)
00069 {
00070 }
00071
00072 void RenoTcpAgent::recv(Packet *pkt, Handler*)
00073 {
00074 hdr_tcp *tcph = hdr_tcp::access(pkt);
00075 if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
00076 endQuickStart();
00077 if (qs_requested_ == 1)
00078 processQuickStart(pkt);
00079 #ifdef notdef
00080 if (pkt->type_ != PT_ACK) {
00081 fprintf(stderr,
00082 "ns: confiuration error: tcp received non-ack\n");
00083 exit(1);
00084 }
00085 #endif
00086
00087 if (tcph->ts() < lastreset_) {
00088
00089 Packet::free(pkt);
00090 return;
00091 }
00092 ++nackpack_;
00093 ts_peer_ = tcph->ts();
00094
00095 if (hdr_flags::access(pkt)->ecnecho() && ecn_)
00096 ecn(tcph->seqno());
00097 recv_helper(pkt);
00098 if (tcph->seqno() > last_ack_) {
00099 dupwnd_ = 0;
00100 recv_newack_helper(pkt);
00101 if (last_ack_ == 0 && delay_growth_) {
00102 cwnd_ = initial_window();
00103 }
00104 } else if (tcph->seqno() == last_ack_) {
00105 if (hdr_flags::access(pkt)->eln_ && eln_) {
00106 tcp_eln(pkt);
00107 return;
00108 }
00109 if (++dupacks_ == numdupacks_) {
00110 dupack_action();
00111 dupwnd_ = numdupacks_;
00112 } else if (dupacks_ > numdupacks_) {
00113 ++dupwnd_;
00114 } else if (dupacks_ < numdupacks_ && singledup_ ) {
00115 send_one();
00116 }
00117 }
00118 Packet::free(pkt);
00119 #ifdef notyet
00120 if (trace_)
00121 plot();
00122 #endif
00123
00124
00125
00126
00127
00128 if (dupacks_ == 0 || dupacks_ > numdupacks_ - 1)
00129 send_much(0, 0, maxburst_);
00130 }
00131
00132 int
00133 RenoTcpAgent::allow_fast_retransmit(int last_cwnd_action_)
00134 {
00135 return (last_cwnd_action_ == CWND_ACTION_DUPACK);
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 void
00156 RenoTcpAgent::dupack_action()
00157 {
00158 int recovered = (highest_ack_ > recover_);
00159 int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_);
00160 if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit) {
00161 goto reno_action;
00162 }
00163
00164 if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
00165 last_cwnd_action_ = CWND_ACTION_DUPACK;
00166
00167
00168
00169
00170
00171
00172
00173
00174 reset_rtx_timer(1,0);
00175 output(last_ack_ + 1, TCP_REASON_DUPACK);
00176 return;
00177 }
00178
00179 if (bug_fix_) {
00180
00181
00182
00183
00184
00185 return;
00186 }
00187
00188 reno_action:
00189
00190 trace_event("RENO_FAST_RETX");
00191 recover_ = maxseq_;
00192 last_cwnd_action_ = CWND_ACTION_DUPACK;
00193 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
00194 reset_rtx_timer(1,0);
00195 output(last_ack_ + 1, TCP_REASON_DUPACK);
00196 return;
00197 }
00198
00199 void RenoTcpAgent::timeout(int tno)
00200 {
00201 if (tno == TCP_TIMER_RTX) {
00202 dupwnd_ = 0;
00203 dupacks_ = 0;
00204 if (bug_fix_) recover_ = maxseq_;
00205 TcpAgent::timeout(tno);
00206 } else {
00207 timeout_nonrtx(tno);
00208 }
00209 }