?? tcp.cc
字號:
#ifdef QS_DEBUG printf("Quick Start approved, rate %d, window %d\n", qsh->rate(), app_rate);#endif if (app_rate > initial_window()) { qs_cwnd_ = app_rate; qs_approved_ = 1; } } else { // Quick Start rejected#ifdef QS_DEBUG printf("Quick Start rejected\n");#endif }}/* * ACK has been received, hook from recv() */void TcpAgent::recv_frto_helper(Packet *pkt){ hdr_tcp *tcph = hdr_tcp::access(pkt); if (tcph->seqno() == last_ack_ && frto_ != 0) { /* * Duplicate ACK while in F-RTO indicates that the * timeout was valid. Go to slow start retransmissions. */ t_seqno_ = highest_ack_ + 1; cwnd_ = frto_; frto_ = 0; // Must zero dupacks (in order to trigger send_much at recv) // dupacks is increased in recv after exiting this function dupacks_ = -1; }}/* * A spurious timeout has been detected. Do appropriate actions. */void TcpAgent::spurious_timeout(){ frto_ = 0; switch (spurious_response_) { case 1: default: /* * Full revert of congestion window * (FlightSize before last acknowledgment) */ cwnd_ = t_seqno_ - prev_highest_ack_; break; case 2: /* * cwnd = reduced ssthresh (approx. half of the earlier pipe) */ cwnd_ = ssthresh_; break; case 3: /* * slow start, but without retransmissions */ cwnd_ = 1; break; } /* * Revert ssthresh to size before retransmission timeout */ ssthresh_ = pipe_prev_; /* If timeout was spurious, bugfix is not needed */ recover_ = highest_ack_ - 1;}/* * Loss occurred in Quick-Start window. * If Quick-Start is enabled, packet loss in the QS phase should * trigger slow start instead of the regular fast retransmit, * see [draft-amit-quick-start-03.txt] (to appear). * We use variable tcp_qs_recovery_ to toggle this behaviour on and off. * If tcp_qs_recovery_ is true, initiate slow start to probe for * a correct window size. * * Return value: non-zero if Quick-Start specific loss recovery took place */int TcpAgent::lossQuickStart(){ if (qs_window_ && tcp_qs_recovery_) { //recover_ = maxseq_; //reset_rtx_timer(1,0); slowdown(CLOSE_CWND_INIT); // reset ssthresh to half of W-D/2? qs_window_ = 0; output(last_ack_ + 1, TCP_REASON_DUPACK); return 1; } return 0;}/* * main reception path - should only see acks, otherwise the * network connections are misconfigured */void TcpAgent::recv(Packet *pkt, Handler*){ hdr_tcp *tcph = hdr_tcp::access(pkt); int valid_ack = 0; if (qs_approved_ == 1 && tcph->seqno() > last_ack_) endQuickStart(); if (qs_requested_ == 1) processQuickStart(pkt);#ifdef notdef if (pkt->type_ != PT_ACK) { Tcl::instance().evalf("%s error \"received non-ack\"", name()); Packet::free(pkt); return; }#endif /* W.N.: check if this is from a previous incarnation */ if (tcph->ts() < lastreset_) { // Remove packet and do nothing Packet::free(pkt); return; } ++nackpack_; ts_peer_ = tcph->ts(); int ecnecho = hdr_flags::access(pkt)->ecnecho(); if (ecnecho && ecn_) ecn(tcph->seqno()); recv_helper(pkt); recv_frto_helper(pkt); /* grow cwnd and check if the connection is done */ if (tcph->seqno() > last_ack_) { recv_newack_helper(pkt); if (last_ack_ == 0 && delay_growth_) { cwnd_ = initial_window(); } } else if (tcph->seqno() == last_ack_) { if (hdr_flags::access(pkt)->eln_ && eln_) { tcp_eln(pkt); return; } if (++dupacks_ == numdupacks_ && !noFastRetrans_) { dupack_action(); } else if (dupacks_ < numdupacks_ && singledup_ ) { send_one(); } } if (QOption_ && EnblRTTCtr_) process_qoption_after_ack (tcph->seqno()); if (tcph->seqno() >= last_ack_) // Check if ACK is valid. Suggestion by Mark Allman. valid_ack = 1; Packet::free(pkt); /* * Try to send more data. */ if (valid_ack || aggressive_maxburst_) send_much(0, 0, maxburst_);}/* * Process timeout events other than rtx timeout. Having this as a separate * function allows derived classes to make alterations/enhancements (e.g., * response to new types of timeout events). */ void TcpAgent::timeout_nonrtx(int tno) { if (tno == TCP_TIMER_DELSND) { /* * delayed-send timer, with random overhead * to avoid phase effects */ send_much(1, TCP_REASON_TIMEOUT, maxburst_); }} void TcpAgent::timeout(int tno){ /* retransmit timer */ if (tno == TCP_TIMER_RTX) { // There has been a timeout - will trace this event trace_event("TIMEOUT"); frto_ = 0; // Set pipe_prev as per Eifel Response pipe_prev_ = (window() > ssthresh_) ? window() : (int)ssthresh_; if (cwnd_ < 1) cwnd_ = 1; if (qs_approved_ == 1) qs_approved_ = 0; if (highest_ack_ == maxseq_ && !slow_start_restart_) { /* * TCP option: * If no outstanding data, then don't do anything. */ // Should this return be here? // What if CWND_ACTION_ECN and cwnd < 1? // return; } else { recover_ = maxseq_; if (highest_ack_ == -1 && wnd_init_option_ == 2) /* * First packet dropped, so don't use larger * initial windows. */ wnd_init_option_ = 1; if (highest_ack_ == maxseq_ && restart_bugfix_) /* * if there is no outstanding data, don't cut * down ssthresh_. */ slowdown(CLOSE_CWND_ONE|NO_OUTSTANDING_DATA); else if (highest_ack_ < recover_ && last_cwnd_action_ == CWND_ACTION_ECN) { /* * if we are in recovery from a recent ECN, * don't cut down ssthresh_. */ slowdown(CLOSE_CWND_ONE); if (frto_enabled_ || sfrto_enabled_) { frto_ = 1; } } else { ++nrexmit_; last_cwnd_action_ = CWND_ACTION_TIMEOUT; slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART); if (frto_enabled_ || sfrto_enabled_) { frto_ = 1; } } } /* if there is no outstanding data, don't back off rtx timer */ if (highest_ack_ == maxseq_ && restart_bugfix_) { reset_rtx_timer(0,0); } else { reset_rtx_timer(0,1); } last_cwnd_action_ = CWND_ACTION_TIMEOUT; send_much(0, TCP_REASON_TIMEOUT, maxburst_); } else { timeout_nonrtx(tno); }}/* * Check if the packet (ack) has the ELN bit set, and if it does, and if the * last ELN-rxmitted packet is smaller than this one, then retransmit the * packet. Do not adjust the cwnd when this happens. */void TcpAgent::tcp_eln(Packet *pkt){ //int eln_rxmit; hdr_tcp *tcph = hdr_tcp::access(pkt); int ack = tcph->seqno(); if (++dupacks_ == eln_rxmit_thresh_ && ack > eln_last_rxmit_) { /* Retransmit this packet */ output(last_ack_ + 1, TCP_REASON_DUPACK); eln_last_rxmit_ = last_ack_+1; } else send_much(0, 0, maxburst_); Packet::free(pkt); return;}/* * This function is invoked when the connection is done. It in turn * invokes the Tcl finish procedure that was registered with TCP. */void TcpAgent::finish(){ Tcl::instance().evalf("%s done", this->name());}void RtxTimer::expire(Event*){ a_->timeout(TCP_TIMER_RTX);}void DelSndTimer::expire(Event*){ a_->timeout(TCP_TIMER_DELSND);}void BurstSndTimer::expire(Event*){ a_->timeout(TCP_TIMER_BURSTSND);}/* * THE FOLLOWING FUNCTIONS ARE OBSOLETE, but REMAIN HERE * DUE TO OTHER PEOPLE's TCPs THAT MIGHT USE THEM * * These functions are now replaced by ecn() and slowdown(), * respectively. *//* * Respond either to a source quench or to a congestion indication bit. * This is done at most once a roundtrip time; after a source quench, * another one will not be done until the last packet transmitted before * the previous source quench has been ACKed. */void TcpAgent::quench(int how){ if (highest_ack_ >= recover_) { recover_ = maxseq_; last_cwnd_action_ = CWND_ACTION_ECN; closecwnd(how); }}/* * close down the congestion window */void TcpAgent::closecwnd(int how){ static int first_time = 1; if (first_time == 1) { fprintf(stderr, "the TcpAgent::closecwnd() function is now deprecated, please use the function slowdown() instead\n"); } switch (how) { case 0: /* timeouts */ ssthresh_ = int( window() / 2 ); if (ssthresh_ < 2 && increase_num_ >= 1.0) // ktnahm mod ssthresh_ = 2; if (ssthresh_ < 0) // ktnahm add ssthresh_ = 0; // ktnahm cwnd_ = int(wnd_restart_); break; case 1: /* Reno dup acks, or after a recent congestion indication. */ // cwnd_ = window()/2; cwnd_ = decrease_num_ * window(); ssthresh_ = int(cwnd_); if (ssthresh_ < 2 && increase_num_ >= 1.0) // ktnahm mod ssthresh_ = 2; if (ssthresh_ < 0) // ktnahm add ssthresh_ = 0; // ktnahm break; case 2: /* Tahoe dup acks * after a recent congestion indication */ cwnd_ = wnd_init_; break; case 3: /* Retransmit timeout, but no outstanding data. */ cwnd_ = int(wnd_init_); break; case 4: /* Tahoe dup acks */ ssthresh_ = int( window() / 2 ); if (ssthresh_ < 2 && increase_num_ >= 1.0) // ktnahm mod ssthresh_ = 2; if (ssthresh_ < 0) // ktnahm add ssthresh_ = 0; // ktnahm cwnd_ = 1; break; default: abort(); } fcnt_ = 0.; count_ = 0;}/* * Check if the sender has been idle or application-limited for more * than an RTO, and if so, reduce the congestion window. */void TcpAgent::process_qoption_after_send (){ int tcp_now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5); int rto = (int)(t_rtxcur_/tcp_tick_) ; /*double ct = Scheduler::instance().clock();*/ if (!EnblRTTCtr_) { if (tcp_now - T_last >= rto) { // The sender has been idle. slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE) ; for (int i = 0 ; i < (tcp_now - T_last)/rto; i ++) { slowdown(CWND_HALF_WITH_MIN|TCP_IDLE); } T_prev = tcp_now ; W_used = 0 ; } T_last = tcp_now ; if (t_seqno_ == highest_ack_+ window()) { T_prev = tcp_now ; W_used = 0 ; } else if (t_seqno_ == curseq_-1) { // The sender has no more data to send. int tmp = t_seqno_ - highest_ack_ ; if (tmp > W_used) W_used = tmp ; if (tcp_now - T_prev >= rto) { // The sender has been application-limited. slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE); slowdown(CLOSE_CWND_HALF_WAY|TCP_IDLE); T_prev = tcp_now ; W_used
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -