?? tcp-fast.c
字號:
#endif
return (double)inst_cwnd;
}
/******************************************************************************/
/* parameter estimation */
void
FastTcpAgent::fast_est(Packet *pkt,double rtt)
{
hdr_tcp *tcph = hdr_tcp::access(pkt);
if(rtt < baseRTT_)
avg_cwnd_last_RTT_ = (fast_est_update_avg_cwnd(t_seqno_ - tcph->seqno() - dupacks_));//在該版本中fast_est_update_avg_cwnd函數始終都只返回參數值,即返回t_seqno_ - tcph->seqno() - dupacks_
avgRTT_ = fast_est_update_avgrtt(rtt);//更新平均RTT值
}
/******************************************************************************/
/* congestion control */
void
FastTcpAgent::fast_cc(double rtt, double old_cwnd)
{
// We update acks_last_rtt every RTT. //記錄最近一個RTT時間內收到的確認數保存在acks_last_rtt中
if ( fast_calc_cwnd_end + rtt < currentTime )
{
fast_calc_cwnd_end = currentTime;
acks_last_rtt = acks_per_rtt; //保存最近一個RTT時間的確認數
acks_per_rtt = 0; //重新清零
if ( on_first_rtt_ == true ) //反轉on_first_rtt,當定義UPDATE_CWND_EVERY_OTHER_RTT時用于標識兩次fast_update_cwnd_interval_時間間隔才更新一次窗口值
on_first_rtt_ = false;
else
on_first_rtt_ = true;
}
acks_per_rtt++; //累加該RTT內收到的確認數
// We use MI to increase cwnd_ when there is little queueing delay
if ( avgRTT_ - baseRTT_ < mi_threshold_ && (fast_opts & FAST_ALLOW_MI) )//有小部分的包排隊延時時,使用加數增大窗口,防止窗口增大過快
{
cwnd_++;
cwnd_update_time = currentTime;
return;
}
// If queueing delay is large, we use fast algorithm
if ( currentTime >= cwnd_update_time + fast_update_cwnd_interval_ //間隔fast_update_cwnd_interval_才計算一次新窗口大小
#ifdef UPDATE_CWND_EVERY_OTHER_RTT
&& on_first_rtt_ == true
#endif
)
{
double updated_cwnd;
cwnd_increments = 0; //在fast_pace()中用于計算窗口步進值
updated_cwnd = fast_calc_cwnd(cwnd_,old_cwnd); //計算新窗口大小
if ( updated_cwnd >= cwnd_ && baseRTT_ >= 0.004 && baseRTT_ != DOUBLE_VARABLE_INVALID_VALUE )//帶寬不高且要增大窗口
{
fast_pace(&cwnd_, (int)(updated_cwnd-cwnd_));
}
else
cwnd_ = updated_cwnd;
cwnd_update_time = currentTime;
}
else if ( baseRTT_ >= 0.004 && baseRTT_ != DOUBLE_VARABLE_INVALID_VALUE )
fast_pace(&cwnd_, 0);
}
#define MIN(x, y) ((x)<(y) ? (x) : (y))
/******************************************************************************/
void
FastTcpAgent::recv(Packet *pkt, Handler *)
{
currentTime = fasttime();
hdr_tcp *tcph = hdr_tcp::access(pkt); //pkt偏移得到tcp頭
hdr_flags *flagh = hdr_flags::access(pkt);
int valid_ack = 0;
if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
endQuickStart();
if (qs_requested_ == 1)
processQuickStart(pkt);
/* W.N.: check if this is from a previous incarnation */
if (tcph->ts() < lastreset_) //tcp->ts()返回該包的產生時間,因為對方重傳包時.包產生時間不變.所以可以用來確定該包是否為重傳的包
{
// Remove packet and do nothing
Packet::free(pkt);
return;
}
++nackpack_;
if(firstrecv_<0) //初始化時設為-0.1
{ // init fast rtt vars
firstrecv_ = currentTime; //currentTime 是以firstsent_做為基準值開始計時的
baseRTT_ = avgRTT_ = rtt_ = firstrecv_; //接收到的第一個包的時間
}
if (flagh->ecnecho())
ecn(tcph->seqno());
int ecnecho = hdr_flags::access(pkt)->ecnecho();
if (ecnecho && ecn_)
ecn(tcph->seqno());
// Check if ACK is valid. Suggestion by Mark Allman.
if (tcph->seqno() >= last_ack_) //包的序號比之前已經確認收到的序號大.即有效包
valid_ack = 1;
#ifdef FASTTCPAGENT_DEBUG
if (cwnd_ <= 0)
printf("%8.3f : cwnd is not positive! cwnd is %f .\n", (double)currentTime, (double)cwnd_);
#endif
/*
* If DSACK is being used, check for DSACK blocks here.
* Possibilities: Check for unnecessary Fast Retransmits.
*/
if (!fastrecov_)
{//未啟用快恢復(快重傳)
/* normal... not fast recovery */
if ((int)tcph->seqno() > last_ack_) //收到比要確認包值更大的包,即提前收到了要接收的下一個包后面的包.也說明了要收的last_ack_未到達
{
if (last_ack_ == 0 ) //是第一個包
{
cwnd_ = initial_window(); //初始化窗口值
}
/* check if cwnd has been inflated */
#if 1
if(dupacks_ > numdupacks_ && cwnd_ > newcwnd_)
{
//check t_seqno_ before changing cwnd.
if (t_seqno_ < tcph->seqno())
t_seqno_ = tcph->seqno();
//cwnd becomes a negative number in some case.
cwnd_ = t_seqno_ - tcph->seqno() + 1; //確保cwnd_最小為1
dupacks_ = 0;
for (int i=0;i<maxwnd_;i++)
cwnd_array_[i]=cwnd_;
}
#endif
firstpartial_ = 0;
// reset sendtime for acked pkts and incr transmits_
double sendTime = sendtime_[tcph->seqno()%maxwnd_];
double old_pif=cwnd_array_[tcph->seqno()%maxwnd_];
int transmits = transmits_[tcph->seqno()% maxwnd_];
for(int k= (last_natural_ack_number_+1); k<=tcph->seqno(); ++k)//last_natural_ack_number_+1到tcph->seqno()之間的包未到達
{
sendtime_[k%maxwnd_] = -1.0;
transmits_[k%maxwnd_] = 0;
cwnd_array_[k%maxwnd_]=-1;
}
if (t_seqno_ > tcph->seqno())
{
if ((transmits == 1) && (currentTime - sendTime > 0))
rtt_ = currentTime - sendTime;
else
rtt_ = avgRTT_;
}else
rtt_ = avgRTT_; //出現重傳時不影響平均RTT的計算
fast_recv_newack_helper(pkt);
timeout_ = FALSE;
scb_->ClearScoreBoard();
fast_est(pkt, rtt_);
fast_cc(rtt_, old_pif); //擁塞控制
last_natural_ack_number_ = tcph->seqno(); //最近收到的包序號;
} else if ((int)tcph->seqno() < last_ack_) //重復的包,即該已經確認收到了
{
/*NOTHING*/
//the follows are if (int)tcph->seqno() == last_ack_
} else if (timeout_ == FALSE)
{
if (tcph->seqno() != last_ack_)
{
fprintf(stderr, "pkt seq %d should be %d\n", tcph->seqno(), last_ack_);
abort();
}
scb_->UpdateScoreBoard (highest_ack_, tcph);
/*
* Check for a duplicate ACK.
* Check that the SACK block actually
* acknowledges new data.
*/
if(scb_->CheckUpdate())
{
if (++dupacks_ == numdupacks(cwnd_))
{
/*
* Assume we dropped just one packet.
* Retransmit last ack + 1
* and try to resume the sequence.
*/
dupack_action(); //確認次數超過一定值.重傳該包
} else if (dupacks_ < numdupacks(cwnd_) && singledup_ )
{
send_one(); //發送新包
}
}
}
if (valid_ack || aggressive_maxburst_)
if (dupacks_ == 0)
send_much(FALSE, 0, maxburst_); //將窗口中的包發完
} else
{//啟用快恢復(快重傳)
/* we are in fast recovery */
cwnd_update_time = currentTime;
--pipe_;
if ((int)tcph->seqno() >= recover_)
{
/* ACK indicates fast recovery is over */
recover_ = 0;
fastrecov_ = FALSE;
newack(pkt); //新的未確認的包到達
/* if the connection is done, call finish() */
if ((highest_ack_ >= curseq_-1) && !closed_)
{
closed_ = 1;
finish();
}
timeout_ = FALSE;
scb_->ClearScoreBoard();
/* New window: W/2 - K or W/2? */
} else if ((int)tcph->seqno() > highest_ack_)
{
/* Not out of fast recovery yet.
* Update highest_ack_, but not last_ack_. */
highest_ack_ = (int)tcph->seqno(); //更新確認序號,即收到的最大序號
scb_->UpdateScoreBoard (highest_ack_, tcph);
if (partial_ack_)
{
/* partial_ack_ is needed to guarantee that */
/* a new packet is sent in response to a */
/* partial ack. */
partial_ack_action();
++pipe_;
if (firstpartial_ == 0)
{
newtimer(pkt);
t_backoff_ = 1;
firstpartial_ = 1;
}
} else
{
--pipe_;
newtimer(pkt);
t_backoff_ = 1;
/* If this partial ACK is from a retransmitted pkt,*/
/* then we decrement pipe_ again, so that we never */
/* do worse than slow-start. If this partial ACK */
/* was instead from the original packet, reordered,*/
/* then this might be too aggressive. */
}
} else if (timeout_ == FALSE)
{
/* got another dup ack */
scb_->UpdateScoreBoard (highest_ack_, tcph);
if(scb_->CheckUpdate())
{
if (dupacks_ > 0)
dupacks_++;
}
}
if (valid_ack || aggressive_maxburst_)
send_much(FALSE, 0, maxburst_);
}
Packet::free(pkt);
}
/******************************************************************************/
void
FastTcpAgent::dupack_action()
{
int recovered = (highest_ack_ > recover_);
if (recovered || (!bug_fix_ && !ecn_))
{
goto sack_action;
}
if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN)
{
last_cwnd_action_ = CWND_ACTION_DUPACK;
/*
* What if there is a DUPACK action followed closely by ECN
* followed closely by a DUPACK action?
* The optimal thing to do would be to remember all
* congestion actions from the most recent window
* of data. Otherwise "bugfix" might not prevent
* all unnecessary Fast Retransmits.
*/
reset_rtx_timer(1,0);
/*
* There are three possibilities:
* (1) pipe_ = int(cwnd_) - numdupacks_;
* (2) pipe_ = window() - numdupacks_;
* (3) pipe_ = maxseq_ - highest_ack_ - numdupacks_;
* equation (2) takes into account the receiver's
* advertised window, and equation (3) takes into
* account a data-limited sender.
*/
if (singledup_ && LimTransmitFix_)
{
pipe_ = maxseq_ - highest_ack_ - 1;
}
else
{
// numdupacks(cwnd_) packets have left the pipe
pipe_ = maxseq_ - highest_ack_ - numdupacks(cwnd_);
}
fastrecov_ = TRUE; //啟動快重傳
scb_->MarkRetran(highest_ack_+1);
output(last_ack_ + 1, TCP_REASON_DUPACK);
return;
}
if (bug_fix_)
{
/*
* The line below, for "bug_fix_" true, avoids
* problems with multiple fast retransmits in one
* window of data.
*/
return;
}
sack_action:
// we are now going into fast_recovery and will trace that event
trace_event("FAST_RECOVERY");
recover_ = maxseq_;
last_cwnd_action_ = CWND_ACTION_DUPACK;
if (oldCode_)
{
pipe_ = int(cwnd_) - numdupacks(cwnd_);
} else if (singledup_ && LimTransmitFix_)
{
pipe_ = maxseq_ - highest_ack_ - 1;
}
else
{
// numdupacks(cwnd_) packets have left the pipe
pipe_ = maxseq_ - highest_ack_ - numdupacks(cwnd_);
}
slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
reset_rtx_timer(1,0);
fastrecov_ = TRUE;
scb_->MarkRetran(highest_ack_+1);
output(last_ack_ + 1, TCP_REASON_DUPACK); // from top
/*
* If dynamically adjusting numdupacks_, record information
* at this point.
*/
return;
}
/*
* Process a packet that acks previously unacknowledges data, but
* does not take us out of Fast Retransmit.
*
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -