📄 tcp.cc
字号:
* If F-RTO is enabled and first ack has come in, temporarily open * window for sending two segments. * The F-RTO code is from Pasi Sarolahti. F-RTO is an algorithm * for detecting spurious retransmission timeouts. */ if (frto_ == 2) { return (force_wnd(2) < wnd_ ? force_wnd(2) : (int)wnd_); } else { return (cwnd_ < wnd_ ? (int)cwnd_ : (int)wnd_); }}double TcpAgent::windowd(){ return (cwnd_ < wnd_ ? (double)cwnd_ : (double)wnd_);}/* * Try to send as much data as the window will allow. The link layer will * do the buffering; we ask the application layer for the size of the packets. */void TcpAgent::send_much(int force, int reason, int maxburst){ send_idle_helper(); int win = window(); int npackets = 0; 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(); if (burstsnd_timer_.status() == TIMER_PENDING) return; while (t_seqno_ <= highest_ack_ + win && t_seqno_ < curseq_) { if (overhead_ == 0 || force || qs_approved_) { output(t_seqno_, reason); npackets++; if (QOption_) process_qoption_after_send () ; t_seqno_ ++ ; if (qs_approved_ == 1) { // delay = effective RTT / window double delay = (double) t_rtt_ * tcp_tick_ / win; if (overhead_) { delsnd_timer_.resched(delay + Random::uniform(overhead_)); } else { delsnd_timer_.resched(delay); } return; } } else if (!(delsnd_timer_.status() == TIMER_PENDING)) { /* * Set a delayed send timeout. */ delsnd_timer_.resched(Random::uniform(overhead_)); return; } win = window(); if (maxburst && npackets == maxburst) break; } /* call helper function */ send_helper(maxburst);}/* * We got a timeout or too many duplicate acks. Clear the retransmit timer. * Resume the sequence one past the last packet acked. * "mild" is 0 for timeouts and Tahoe dup acks, 1 for Reno dup acks. * "backoff" is 1 if the timer should be backed off, 0 otherwise. */void TcpAgent::reset_rtx_timer(int mild, int backoff){ if (backoff) rtt_backoff(); set_rtx_timer(); if (!mild) t_seqno_ = highest_ack_ + 1; rtt_active_ = 0;}/* * Set retransmit timer using current rtt estimate. By calling resched(), * it does not matter whether the timer was already running. */void TcpAgent::set_rtx_timer(){ rtx_timer_.resched(rtt_timeout());}/* * Set new retransmission timer if not all outstanding * or available data acked, or if we are unable to send because * cwnd is less than one (as when the ECN bit is set when cwnd was 1). * Otherwise, if a timer is still outstanding, cancel it. */void TcpAgent::newtimer(Packet* pkt){ hdr_tcp *tcph = hdr_tcp::access(pkt); /* * t_seqno_, the next packet to send, is reset (decreased) * to highest_ack_ + 1 after a timeout, * so we also have to check maxseq_, the highest seqno sent. * In addition, if the packet sent after the timeout has * the ECN bit set, then the returning ACK caused cwnd_ to * be decreased to less than one, and we can't send another * packet until the retransmit timer again expires. * So we have to check for "cwnd_ < 1" as well. */ if (t_seqno_ > tcph->seqno() || tcph->seqno() < maxseq_ || cwnd_ < 1) set_rtx_timer(); else cancel_rtx_timer();}/* * for experimental, high-speed TCP */double TcpAgent::linear(double x, double x_1, double y_1, double x_2, double y_2){ // The y coordinate factor ranges from y_1 to y_2 // as the x coordinate ranges from x_1 to x_2. double y = y_1 + ((y_2 - y_1) * ((x - x_1)/(x_2-x_1))); return y;}/* * Limited Slow-Start for large congestion windows. * This is only used when max_ssthresh_ is non-zero. */double TcpAgent::limited_slow_start(double cwnd, double max_ssthresh, double increment){ int round = int(cwnd / (double(max_ssthresh)/2.0)); double increment1 = 1.0/(double(round)); if (increment < increment1) increment = increment1; return increment;}/* * For retrieving numdupacks_. */int TcpAgent::numdupacks(double cwnd){ int cwndfraction = (int) cwnd/numdupacksFrac_; if (numdupacks_ > cwndfraction) { return numdupacks_; } else { return cwndfraction; }}/* * Calculating the decrease parameter for highspeed TCP. */double TcpAgent::decrease_param(){ double decrease; // OLD: // decrease = linear(log(cwnd_), log(low_window_), 0.5, log(high_window_), high_decrease_); // NEW (but equivalent): decrease = hstcp_.dec1 + log(cwnd_) * hstcp_.dec2; return decrease;}/* * Calculating the increase parameter for highspeed TCP. */double TcpAgent::increase_param(){ double increase, decrease, p, answer; /* extending the slow-start for high-speed TCP */ /* for highspeed TCP -- from Sylvia Ratnasamy, */ /* modifications by Sally Floyd and Evandro de Souza */ // p ranges from 1.5/W^2 at congestion window low_window_, to // high_p_ at congestion window high_window_, on a log-log scale. // The decrease factor ranges from 0.5 to high_decrease // as the window ranges from low_window to high_window, // as the log of the window. // For an efficient implementation, this would just be looked up // in a table, with the increase and decrease being a function of the // congestion window. if (cwnd_ <= low_window_) { answer = 1 / cwnd_; return answer; } else if (cwnd_ >= hstcp_.cwnd_last_ && cwnd_ < hstcp_.cwnd_last_ + cwnd_range_) { // cwnd_range_ can be set to 0 to be disabled, // or can be set from 1 to 100 answer = hstcp_.increase_last_ / cwnd_; return answer; } else { // OLD: // p = exp(linear(log(cwnd_), log(low_window_), log(hstcp_.low_p), log(high_window_), log(high_p_))); // NEW, but equivalent: p = exp(hstcp_.p1 + log(cwnd_) * hstcp_.p2); decrease = decrease_param(); // OLD: // increase = cwnd_*cwnd_*p *(2.0*decrease)/(2.0 - decrease); // NEW, but equivalent: increase = cwnd_ * cwnd_ * p /(1/decrease - 0.5); // if (increase > max_increase) { // increase = max_increase; // } answer = increase / cwnd_; hstcp_.cwnd_last_ = cwnd_; hstcp_.increase_last_ = increase; return answer; } }/* * open up the congestion window */void TcpAgent::opencwnd(){ double increment; if (cwnd_ < ssthresh_) { /* slow-start (exponential) */ cwnd_ += 1; } else { /* linear */ double f; switch (wnd_option_) { case 0: if (++count_ >= cwnd_) { count_ = 0; ++cwnd_; } break; case 1: /* This is the standard algorithm. */ increment = increase_num_ / cwnd_; if ((last_cwnd_action_ == 0 || last_cwnd_action_ == CWND_ACTION_TIMEOUT) && max_ssthresh_ > 0) { increment = limited_slow_start(cwnd_, max_ssthresh_, increment); } cwnd_ += increment; break; case 2: /* These are window increase algorithms * for experimental purposes only. */ /* This is the Constant-Rate increase algorithm * from the 1991 paper by S. Floyd on "Connections * with Multiple Congested Gateways". * The window is increased by roughly * wnd_const_*RTT^2 packets per round-trip time. */ f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_; f *= f; f *= wnd_const_; /* f = wnd_const_ * RTT^2 */ f += fcnt_; if (f > cwnd_) { fcnt_ = 0; ++cwnd_; } else fcnt_ = f; break; case 3: /* The window is increased by roughly * awnd_^2 * wnd_const_ packets per RTT, * for awnd_ the average congestion window. */ f = awnd_; f *= f; f *= wnd_const_; f += fcnt_; if (f > cwnd_) { fcnt_ = 0; ++cwnd_; } else fcnt_ = f; break; case 4: /* The window is increased by roughly * awnd_ * wnd_const_ packets per RTT, * for awnd_ the average congestion window. */ f = awnd_; f *= wnd_const_; f += fcnt_; if (f > cwnd_) { fcnt_ = 0; ++cwnd_; } else fcnt_ = f; break; case 5: /* The window is increased by roughly wnd_const_*RTT * packets per round-trip time, as discussed in * the 1992 paper by S. Floyd on "On Traffic * Phase Effects in Packet-Switched Gateways". */ f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_; f *= wnd_const_; f += fcnt_; if (f > cwnd_) { fcnt_ = 0; ++cwnd_; } else fcnt_ = f; break; case 6: /* binomial controls */ cwnd_ += increase_num_ / (cwnd_*pow(cwnd_,k_parameter_)); break; case 8: /* high-speed TCP, RFC 3649 */ increment = increase_param(); if ((last_cwnd_action_ == 0 || last_cwnd_action_ == CWND_ACTION_TIMEOUT) && max_ssthresh_ > 0) { increment = limited_slow_start(cwnd_, max_ssthresh_, increment); } cwnd_ += increment; break; default:#ifdef notdef /*XXX*/ error("illegal window option %d", wnd_option_);#endif abort(); } } // if maxcwnd_ is set (nonzero), make it the cwnd limit if (maxcwnd_ && (int(cwnd_) > maxcwnd_)) cwnd_ = maxcwnd_; return;}voidTcpAgent::slowdown(int how){ double decrease; /* added for highspeed - sylvia */ double win, halfwin, decreasewin; int slowstart = 0; ++ncwndcuts_; if (!(how & TCP_IDLE) && !(how & NO_OUTSTANDING_DATA)){ ++ncwndcuts1_; } // we are in slowstart for sure if cwnd < ssthresh if (cwnd_ < ssthresh_) slowstart = 1; if (precision_reduce_) { halfwin = windowd() / 2; if (wnd_option_ == 6) { /* binomial controls */ decreasewin = windowd() - (1.0-decrease_num_)*pow(windowd(),l_parameter_); } else if (wnd_option_ == 8 && (cwnd_ > low_window_)) { /* experimental highspeed TCP */ decrease = decrease_param(); //if (decrease < 0.1) // decrease = 0.1; decrease_num_ = decrease; decreasewin = windowd() - (decrease * windowd()); } else { decreasewin = decrease_num_ * windowd(); } win = windowd(); } else { int temp; temp = (int)(window() / 2); halfwin = (double) temp; if (wnd_option_ == 6) { /* binomial controls */ temp = (int)(window() - (1.0-decrease_num_)*pow(window(),l_parameter_)); } else if ((wnd_option_ == 8) && (cwnd_ > low_window_)) { /* experimental highspeed TCP */ decrease = decrease_param(); //if (decrease < 0.1) // decrease = 0.1; decrease_num_ = decrease; temp = (int)(windowd() - (decrease * windowd())); } else { temp = (int)(decrease_num_ * window()); } decreasewin = (double) temp; win = (double) window(); } if (how & CLOSE_SSTHRESH_HALF) // For the first decrease, decrease by half // even for non-standard values of decrease_num_. if (first_decrease_ == 1 || slowstart || last_cwnd_action_ == CWND_ACTION_TIMEOUT) { // Do we really want halfwin instead of decreasewin // after a timeout? ssthresh_ = (int) halfwin; } else { ssthresh_ = (int) decreasewin; } else if (how & THREE_QUARTER_SSTHRESH) if (ssthresh_ < 3*cwnd_/4) ssthresh_ = (int)(3*cwnd_/4); if (how & CLOSE_CWND_HALF) // For the first decrease, decrease by half // even for non-standard values of decrease_num_. if (first_decrease_ == 1 || slowstart || decrease_num_ == 0.5) { cwnd_ = halfwin; } else cwnd_ = decreasewin; else if (how & CWND_HALF_WITH_MIN) { // We have not thought about how non-standard TCPs, with // non-standard values of decrease_num_, should respond // after quiescent periods. cwnd_ = decreasewin; if (cwnd_ < 1) cwnd_ = 1; } else if (how & CLOSE_CWND_RESTART) cwnd_ = int(wnd_restart_); else if (how & CLOSE_CWND_INIT) cwnd_ = int(wnd_init_); else if (how & CLOSE_CWND_ONE) cwnd_ = 1; else if (how & CLOSE_CWND_HALF_WAY) { // cwnd_ = win - (win - W_used)/2 ; cwnd_ = W_used + decrease_num_ * (win - W_used); if (cwnd_ < 1) cwnd_ = 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -