?? tcp-fast.c
字號:
* The need for a mechanism to ensure that Sack TCP sends a packet in
* response to a partial ACK has been discussed in
* "Challenges to Reliable Data Transport over Heterogeneous
* Wireless Networks", Hari Balakrishnan, 1998, and in
* "Responding to Spurious Timeouts in TCP", Andrei Gurtov and
* Reiner Ludwig, 2003.
*/
void
FastTcpAgent::partial_ack_action()
{
if (next_pkt_ < highest_ack_ + 1)
{
next_pkt_ = highest_ack_ + 1;
}
// Output two packets in response to a partial ack,
// so as not to do worse than slow-start.
int i;
for (i = 1; i<=2; i++)
{
int getNext = scb_->GetNextUnacked(next_pkt_);
if (getNext > next_pkt_)
{
next_pkt_ = getNext;
}
if (t_seqno_ < next_pkt_)
{
t_seqno_ = next_pkt_;
}
output(next_pkt_, TCP_REASON_PARTIALACK);
scb_->MarkRetran(next_pkt_);
++next_pkt_;
}
return;
}
void FastTcpAgent::timeout(int tno)
{
if (tno == TCP_TIMER_RTX)
{
/*
* IF DSACK and dynamic adjustment of numdupacks_,
* check whether a smaller value of numdupacks_
* would have prevented this retransmit timeout.
* If DSACK and detection of premature retransmit
* timeouts, then save some info here.
*/
dupacks_ = 0;
fastrecov_ = FALSE;
timeout_ = TRUE;
if (highest_ack_ > last_ack_)
last_ack_ = highest_ack_;
recover_ = maxseq_;
scb_->ClearScoreBoard();
if (highest_ack_ == maxseq_ && !slow_start_restart_)
{
/*
* TCP option:
* If no outstanding data, then don't do anything.
*
* Note: in the USC implementation,
* slow_start_restart_ == 0.
* I don't know what the U. Arizona implementation
* defaults to.
*/
return;
};
last_cwnd_action_ = CWND_ACTION_TIMEOUT;
reset_rtx_timer(0, 0);
++nrexmit_;
slowdown(CLOSE_CWND_RESTART|CLOSE_SSTHRESH_HALF);
cwnd_ = double(slowstart_);
newcwnd_ = 0;
send_much(0, TCP_REASON_TIMEOUT, maxburst_);
} else
{
/* delayed-sent timer, with random overhead to avoid
* phase effect. */
send_much(1, TCP_REASON_TIMEOUT, 3);
}
}
void FastTcpAgent::send_much(int force, int reason, int maxburst)
{
register int found, npacket = 0;
int win = window();
int xmit_seqno;
found = 1;
if (!force && delsnd_timer_.status() == TIMER_PENDING)
return;
/* Save time when first packet was sent, for newreno --Allman */
if (t_seqno_ == 0)
firstsent_ = Scheduler::instance().clock();
/*
* as long as the pipe is open and there is app data to send...
*/
while (((!fastrecov_ && (t_seqno_ <= last_ack_ + win)) ||
(fastrecov_ && (pipe_ < int(cwnd_))))
&& t_seqno_ < curseq_ && found)
{
if (overhead_ == 0 || force)
{
found = 0;
int oldest_unacked_pkt = scb_->GetNextUnacked(last_ack_);
if (oldest_unacked_pkt != -1 &&
fasttime() - sendtime_[oldest_unacked_pkt%maxwnd_] > 2*avgRTT_) //當未得到確認的包超時時重新傳送該包
{
xmit_seqno = oldest_unacked_pkt;
}
else
xmit_seqno = scb_->GetNextRetran ();
if (xmit_seqno == -1)
{
if ((!fastrecov_ && t_seqno_<=highest_ack_+win)||
(fastrecov_ && t_seqno_<=highest_ack_+int(wnd_)))
{
found = 1;
xmit_seqno = t_seqno_++; //遞加要發(fā)送包序號
}
} else if (recover_>0 && xmit_seqno<=highest_ack_+int(wnd_))
{
found = 1;
scb_->MarkRetran (xmit_seqno);
win = window();
}
if (found)
{
output(xmit_seqno, reason);
if (t_seqno_ <= xmit_seqno)
t_seqno_ = xmit_seqno + 1;
npacket++;
pipe_++;
if (QOption_)
process_qoption_after_send () ;
if (qs_approved_ == 1)
{
double delay = (double) t_rtt_ * tcp_tick_ / cwnd_;
delsnd_timer_.resched(delay);
return;
}
}
} else if (!(delsnd_timer_.status() == TIMER_PENDING))
{
/*
* Set a delayed send timeout.
* This is only for the simulator,to add some
* randomization if speficied.
*/
delsnd_timer_.resched(Random::uniform(overhead_));
return;
}
if (maxburst && npacket == maxburst)
break;
} /* while */
}
void
FastTcpAgent::output(int seqno, int reason)
{
Packet* p = allocpkt();
hdr_tcp *tcph = hdr_tcp::access(p);
double now = Scheduler::instance().clock();
hdr_flags* hf = hdr_flags::access(p);
hdr_ip *iph = hdr_ip::access(p);
int databytes = hdr_cmn::access(p)->size();
tcph->seqno() = seqno;
tcph->ts() = now;
tcph->reason() = reason;
/* if this is the 1st pkt, setup senttime[] and transmits[]
* I alloc mem here, instrad of in the constructor, to cover
* cases which windows get set by each different tcp flows */
if (seqno==0)
{
maxwnd_ = int(wnd_);
if (sendtime_)
delete []sendtime_;
if (transmits_)
delete []transmits_;
if (cwnd_array_)
delete []cwnd_array_;
sendtime_ = new double[maxwnd_];
transmits_ = new int[maxwnd_];
cwnd_array_= new double[maxwnd_];
for(int i=0;i<maxwnd_;i++)
{
sendtime_[i] = -1.;
transmits_[i] = 0;
cwnd_array_[i]=-1;
}
}
if (ecn_)
{
hf->ect() = 1; // ECN capable transport.
}
/* Check if this is the initial SYN packet. */
if (seqno == 0)
{
if (syn_)
{
databytes= 0;
curseq_ += 1;
hdr_cmn::access(p)->size() = tcpip_base_hdr_size_;
}
if (ecn_)
{
hf->ecnecho() = 1;
// hf->cong_action() = 1;
hf->ect() = 0;
}
}
else if (useHeaders_ == true)
{
hdr_cmn::access(p)->size() += headersize();
}
// record a find grained send time and # of transmits
int index = seqno % maxwnd_;
sendtime_[index] = fasttime();
cwnd_array_[index]=avg_cwnd_last_RTT_;
++transmits_[index];
/* support ndatabytes_ in output - Lloyd Wood 14 March 2000 */
int bytes = hdr_cmn::access(p)->size();
ndatabytes_ += bytes;
ndatapack_++; // Added this - Debojyoti 12th Oct 2000
send(p, 0);
if (seqno == curseq_ && seqno > maxseq_)
idle(); // Tell application I have sent everything so far
if (seqno > maxseq_)
{
maxseq_ = seqno;
if (!rtt_active_)
{
rtt_active_ = 1;
if (seqno > rtt_seq_)
{
rtt_seq_ = seqno;
rtt_ts_ = now;
}
}
} else
{
++nrexmitpack_;
nrexmitbytes_ += bytes;
}
if (!(rtx_timer_.status() == TIMER_PENDING))
/* No timer pending. Schedule one. */
set_rtx_timer();
}
/******************************************************************************/
/* Space out increments to cwnd as acknowledegements arrive */
/* cwndp points to the actual cwnd value */
/* cwnd_incre (0 or 1) specifies the desired amount to increase cwnd by */
/* (eventually) */
void
FastTcpAgent::fast_pace(TracedDouble *cwndp, int incre_4_cwnd)
{
if ( !avgRTT_ ) //初始化時
return;
double acks_per_period = (double)acks_last_rtt * fast_update_cwnd_interval_ / avgRTT_;//平均RTT時間內收到的確認數(shù)
if ( incre_4_cwnd >= 1 )
{
cwnd_increments += incre_4_cwnd;
/* bc_spacing: target number of ACKs between increments */
bc_spacing = (short unsigned int)(acks_per_period/cwnd_increments);
/* bc_ack: number of ACKs since last increment */
bc_ack = 1;
}else
{
bc_ack ++;
}
if (cwnd_increments)
{
/* if cwnd small, increment immediately */
if (*cwndp <= 4) //窗口初值很小
{
/* if increment would more than double cwnd, do it in stages *///最大只能以倍數(shù)增大窗口
if (*cwndp < cwnd_increments)
{
cwnd_increments -= (unsigned int)*cwndp;
*cwndp += *cwndp;
}
else
{
*cwndp += cwnd_increments;
cwnd_increments=0;
bc_spacing=0;
}
bc_ack=0;
}
else if (bc_ack >= bc_spacing)
{
(*cwndp)++;
cwnd_increments--;
bc_ack = 0;
}
}
}
/******************************************************************************/
/*
* return -1 if the oldest sent pkt has not been timeout (based on
* fine grained timer).
*/
int
FastTcpAgent::fast_expire(Packet* pkt)
{
hdr_tcp *tcph = hdr_tcp::access(pkt);
double elapse = fasttime() - sendtime_[(tcph->seqno()+1)%maxwnd_];
if (elapse >= 2 * avgRTT_) //超過兩倍的平均RTT時間,確定已經超時;
{
return(tcph->seqno()+1);
}
return(-1);
}
/******************************************************************************/
void
FastTcpAgent::fast_recv_newack_helper(Packet *pkt)
{
newack(pkt);
if (ect_)
{
if (!hdr_flags::access(pkt)->ecnecho())
ecn_backoff_ = 0;
if (!ecn_burst_ && hdr_flags::access(pkt)->ecnecho())
ecn_burst_ = TRUE;
else if (ecn_burst_ && ! hdr_flags::access(pkt)->ecnecho())
ecn_burst_ = FALSE;
}
if (!ect_ && hdr_flags::access(pkt)->ecnecho() &&
!hdr_flags::access(pkt)->cong_action())
ect_ = 1;
/* if the connection is done, call finish() */
if ((highest_ack_ >= curseq_-1) && !closed_)
{
closed_ = 1;
finish();
}
if (QOption_ && curseq_ == highest_ack_ +1)
{
cancel_rtx_timer();
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -