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-newreno.cc,v 1.56 2004/10/26 22:59:42 sfloyd Exp $ (LBL)";
00023 #endif
00024
00025
00026
00027
00028
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <sys/types.h>
00032
00033 #include "packet.h"
00034 #include "ip.h"
00035 #include "tcp.h"
00036 #include "flags.h"
00037
00038
00039 static class NewRenoTcpClass : public TclClass {
00040 public:
00041 NewRenoTcpClass() : TclClass("Agent/TCP/Newreno") {}
00042 TclObject* create(int, const char*const*) {
00043 return (new NewRenoTcpAgent());
00044 }
00045 } class_newreno;
00046
00047 NewRenoTcpAgent::NewRenoTcpAgent() : newreno_changes_(0),
00048 newreno_changes1_(0), acked_(0), firstpartial_(0),
00049 partial_window_deflation_(0), exit_recovery_fix_(0)
00050 {
00051 bind("newreno_changes_", &newreno_changes_);
00052 bind("newreno_changes1_", &newreno_changes1_);
00053 bind("exit_recovery_fix_", &exit_recovery_fix_);
00054 bind("partial_window_deflation_", &partial_window_deflation_);
00055 }
00056
00057
00058
00059
00060
00061 void NewRenoTcpAgent::partialnewack(Packet* pkt)
00062 {
00063 hdr_tcp *tcph = hdr_tcp::access(pkt);
00064 if (partial_window_deflation_) {
00065
00066 unsigned int deflate = 0;
00067 if (tcph->seqno() > last_ack_)
00068 deflate = tcph->seqno() - last_ack_;
00069 else
00070 printf("False call to partialnewack: deflate %u \
00071 last_ack_ %d\n", deflate, last_ack_);
00072 if (dupwnd_ > deflate)
00073 dupwnd_ -= (deflate - 1);
00074 else {
00075 cwnd_ -= (deflate - dupwnd_);
00076
00077 dupwnd_ = 1;
00078 }
00079 if (cwnd_ < 1) {cwnd_ = 1;}
00080 }
00081 last_ack_ = tcph->seqno();
00082 highest_ack_ = last_ack_;
00083 if (t_seqno_ < last_ack_ + 1)
00084 t_seqno_ = last_ack_ + 1;
00085 if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
00086 rtt_active_ = 0;
00087 t_backoff_ = 1;
00088 }
00089 }
00090
00091 void NewRenoTcpAgent::partialnewack_helper(Packet* pkt)
00092 {
00093 if (!newreno_changes1_ || firstpartial_ == 0) {
00094 firstpartial_ = 1;
00095
00096
00097
00098
00099
00100
00101 newtimer(pkt);
00102 }
00103 partialnewack(pkt);
00104 output(last_ack_ + 1, 0);
00105 }
00106
00107 int
00108 NewRenoTcpAgent::allow_fast_retransmit(int )
00109 {
00110 return 0;
00111 }
00112
00113 void
00114 NewRenoTcpAgent::dupack_action()
00115 {
00116 int recovered = (highest_ack_ > recover_);
00117 int recovered1 = (highest_ack_ == recover_);
00118 int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_);
00119 if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit) {
00120 goto reno_action;
00121 }
00122 if (bug_fix_ && less_careful_ && recovered1) {
00123
00124
00125
00126
00127
00128
00129 goto reno_action;
00130 }
00131
00132 if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
00133 last_cwnd_action_ = CWND_ACTION_DUPACK;
00134
00135
00136
00137
00138
00139
00140
00141
00142 reset_rtx_timer(1,0);
00143 output(last_ack_ + 1, TCP_REASON_DUPACK);
00144 dupwnd_ = numdupacks_;
00145 return;
00146 }
00147
00148 if (bug_fix_) {
00149 if (bugfix_ts_ && tss[highest_ack_ % tss_size_] == ts_echo_)
00150 goto reno_action;
00151 else if (bugfix_ack_ && cwnd_ > 1 && highest_ack_ - prev_highest_ack_ <= numdupacks_)
00152 goto reno_action;
00153 else
00154
00155
00156
00157
00158
00159 return;
00160 }
00161
00162 reno_action:
00163 recover_ = maxseq_;
00164 reset_rtx_timer(1,0);
00165 if (!lossQuickStart()) {
00166 trace_event("NEWRENO_FAST_RETX");
00167 last_cwnd_action_ = CWND_ACTION_DUPACK;
00168 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
00169 output(last_ack_ + 1, TCP_REASON_DUPACK);
00170 dupwnd_ = numdupacks_;
00171 }
00172 return;
00173 }
00174
00175
00176 void NewRenoTcpAgent::recv(Packet *pkt, Handler*)
00177 {
00178 hdr_tcp *tcph = hdr_tcp::access(pkt);
00179 int valid_ack = 0;
00180
00181
00182
00183 if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
00184 endQuickStart();
00185 if (qs_requested_ == 1)
00186 processQuickStart(pkt);
00187 if (++acked_ == 1)
00188 basertt_ = Scheduler::instance().clock() - firstsent_;
00189
00190
00191
00192
00193 else if (acked_ == 2)
00194 ack2_ = Scheduler::instance().clock();
00195 else if (acked_ == 3) {
00196 ack3_ = Scheduler::instance().clock();
00197 new_ssthresh_ = int((basertt_ * (size_ / (ack3_ - ack2_))) / size_);
00198 if (newreno_changes_ > 0 && new_ssthresh_ < ssthresh_)
00199 ssthresh_ = new_ssthresh_;
00200 }
00201
00202 #ifdef notdef
00203 if (pkt->type_ != PT_ACK) {
00204 fprintf(stderr,
00205 "ns: confiuration error: tcp received non-ack\n");
00206 exit(1);
00207 }
00208 #endif
00209
00210 if (tcph->ts() < lastreset_) {
00211
00212 Packet::free(pkt);
00213 return;
00214 }
00215 ++nackpack_;
00216 ts_peer_ = tcph->ts();
00217
00218 if (hdr_flags::access(pkt)->ecnecho() && ecn_)
00219 ecn(tcph->seqno());
00220 recv_helper(pkt);
00221 recv_frto_helper(pkt);
00222 if (tcph->seqno() > last_ack_) {
00223 if (tcph->seqno() >= recover_
00224 || (last_cwnd_action_ != CWND_ACTION_DUPACK)) {
00225 if (dupwnd_ > 0) {
00226 dupwnd_ = 0;
00227 if (last_cwnd_action_ == CWND_ACTION_DUPACK)
00228 last_cwnd_action_ = CWND_ACTION_EXITED;
00229 if (exit_recovery_fix_) {
00230 int outstanding = maxseq_ - tcph->seqno() + 1;
00231 if (ssthresh_ < outstanding)
00232 cwnd_ = ssthresh_;
00233 else
00234 cwnd_ = outstanding;
00235 }
00236 }
00237 firstpartial_ = 0;
00238 recv_newack_helper(pkt);
00239 if (last_ack_ == 0 && delay_growth_) {
00240 cwnd_ = initial_window();
00241 }
00242 } else {
00243
00244
00245 if (partial_window_deflation_ == 0)
00246 dupwnd_ = 0;
00247 partialnewack_helper(pkt);
00248 }
00249 } else if (tcph->seqno() == last_ack_) {
00250 if (hdr_flags::access(pkt)->eln_ && eln_) {
00251 tcp_eln(pkt);
00252 return;
00253 }
00254 if (++dupacks_ == numdupacks_) {
00255 dupack_action();
00256 if (!exitFastRetrans_)
00257 dupwnd_ = numdupacks_;
00258 } else if (dupacks_ > numdupacks_ && (!exitFastRetrans_
00259 || last_cwnd_action_ == CWND_ACTION_DUPACK)) {
00260 trace_event("NEWRENO_FAST_RECOVERY");
00261 ++dupwnd_;
00262
00263
00264
00265
00266
00267 if (newreno_changes_ > 0 && (dupacks_ % 2) == 1)
00268 output (t_seqno_++,0);
00269 } else if (dupacks_ < numdupacks_ && singledup_ ) {
00270 send_one();
00271 }
00272 }
00273 if (tcph->seqno() >= last_ack_)
00274
00275 valid_ack = 1;
00276 Packet::free(pkt);
00277 #ifdef notyet
00278 if (trace_)
00279 plot();
00280 #endif
00281
00282
00283
00284
00285
00286 if (valid_ack || aggressive_maxburst_)
00287 if (dupacks_ == 0)
00288
00289
00290
00291
00292 send_much(0, 0, maxburst_);
00293 else if (dupacks_ > numdupacks_ - 1 && newreno_changes_ == 0)
00294 send_much(0, 0, 2);
00295 }
00296