📄 tcp.cc
字号:
int temp; if (cwnd_ < ssthresh_) { /* slow-start (exponential) */ cwnd_ += 1; dl_count_=0; dl_mode_=1; } else { /* linear */ dl_mode_=2; if (wnd_option_ < 0) temp=-wnd_option_; else temp=wnd_option_; switch (temp) { 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. */ f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_; f *= f; f *= wnd_const_; f += fcnt_; if (f > cwnd_) { fcnt_ = 0; ++cwnd_; } else fcnt_ = f; break; case 3: f = awnd_; f *= f; f *= wnd_const_; f += fcnt_; if (f > cwnd_) { fcnt_ = 0; ++cwnd_; } else fcnt_ = f; break; case 4: f = awnd_; f *= wnd_const_; f += fcnt_; if (f > cwnd_) { fcnt_ = 0; ++cwnd_; } else fcnt_ = f; break; case 5: 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 */ 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; case 10: /* H-TCP continuous */ dl_count_+=1.0 / cwnd_; RTT_Scaling = dl_minrtt_*tcp_tick_/0.1; if (RTT_Scaling < 0.1) RTT_Scaling = 0.1; if (RTT_Scaling >2) RTT_Scaling=2; diff = dl_count_*dl_minrtt_*tcp_tick_-1.0; if (diff<0.0) f=1; else { f= 1+10*diff+(diff/2)*(diff/2); f= f*RTT_Scaling; if (f<1) f=1; // ensure RTT scaling doesn't lead to unfairness against standard AIMD } f = f*(1-decrease_num_)/(1-0.5); dl_alpha_=f; cwnd_+=f/cwnd_; break; case 11: /* This is the standard algorithm with adaptive backoff. */ increment = increase_num_/ cwnd_; dl_count_+=1.0 / cwnd_; if (wnd_option_<0) increment *= (1-decrease_num_)/(1-0.5); dl_alpha_=increment*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; 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, xx, prev_cwnd_; int slowstart = 0; ++ncwndcuts_; // 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 { if (wnd_option_ < 0) { double thresh=0.2; cwnd_ -= dl_alpha_-1; //account for overshoot due to delay in detecting congestion if ( (dl_maxB_ > (1-thresh)*dl_oldmaxB_)&&(dl_maxB_ < (1+thresh)*dl_oldmaxB_) ) { dl_modecount_ ++; if (dl_modecount_ > 1 && dl_maxrtt_>0) decrease_num_ = dl_minrtt_/dl_maxrtt_; else decrease_num_ = 0.5; } else { dl_modecount_ = 0; decrease_num_ = 0.5; } if (decrease_num_ <0.5) decrease_num_=0.5; if (decrease_num_ >0.8) decrease_num_=0.8; dl_oldmaxB_ = dl_maxB_; // add slowly fading memory for maxRTT to accommodate routing changes etc if (dl_minrtt_ > 0 && dl_maxrtt_ > dl_minrtt_) dl_maxrtt_ = dl_minrtt_ + ((dl_maxrtt_-dl_minrtt_)*95)/100; } 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; dl_modecount_=0; } 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 || how & SOFT_CLOSE_CWND) // 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; } if (ssthresh_ < 2) ssthresh_ = 2; if (how & (CLOSE_CWND_HALF|CLOSE_CWND_RESTART|CLOSE_CWND_INIT|CLOSE_CWND_ONE)) cong_action_ = TRUE; fcnt_ = count_ = 0; if (first_decrease_ == 1) first_decrease_ = 0; // for event tracing slow start if (cwnd_ == 1 || slowstart) // Not sure if this is best way to capture slow_start // This is probably tracing a superset of slowdowns of // which all may not be slow_start's --Padma, 07/'01. trace_event("SLOW_START"); dl_count_=0; dl_mode_=0; }/* * Process a packet that acks previously unacknowleged data. */void TcpAgent::newack(Packet* pkt){ double now = Scheduler::instance().clock(); int rtt; hdr_tcp *tcph = hdr_tcp::access(pkt); /* * Wouldn't it be better to set the timer *after* * updating the RTT, instead of *before*? */ if (!timerfix_) newtimer(pkt); dupacks_ = 0; last_ack_ = tcph->seqno(); prev_highest_ack_ = highest_ack_ ; highest_ack_ = last_ack_; if (t_seqno_ < last_ack_ + 1) t_seqno_ = last_ack_ + 1; /* * Update RTT only if it's OK to do so from info in the flags header. * This is needed for protocols in which intermediate agents * in the network intersperse acks (e.g., ack-reconstructors) for * various reasons (without violating e2e semantics). */ hdr_flags *fh = hdr_flags::access(pkt); if (!fh->no_ts_) { if (ts_option_) rtt_update(now - tcph->ts_echo()); if (rtt_active_ && tcph->seqno() >= rtt_seq_) { if (!ect_ || !ecn_backoff_ || !hdr_flags::access(pkt)->ecnecho()) { /* * Don't end backoff if still in ECN-Echo with * a congestion window of 1 packet. */ t_backoff_ = 1; ecn_backoff_ = 0; } rtt_active_ = 0; if (!ts_option_) rtt_update(now - rtt_ts_); } } if (timerfix_) newtimer(pkt); /* update average window */ awnd_ *= 1.0 - wnd_th_; awnd_ += wnd_th_ * cwnd_; dl_rtti_ = (now - tcph->ts_echo()); if (dl_rtti_/tcp_tick_ < dl_minrtt_) dl_minrtt_= dl_rtti_/tcp_tick_; rtt= int(t_srtt_)>>3; if (!first_decrease_ && rtt > dl_maxrtt_) dl_maxrtt_= rtt; // max smoothed rtt ok with delayed acking if (dl_mode_>0) dl_packetcount_+=(highest_ack_ -prev_highest_ack_); else { //during backoff phase dl_thresh_=now; dl_packetcount_=0; } if (dl_packetcount_ >= int(cwnd_- dl_alpha_) && now-dl_thresh_ >= dl_minrtt_*tcp_tick_ ) { if (dl_count_ <=3 && cwnd_ >= ssthresh_) { //congestion avoidance and just after backoff dl_Bi_=dl_packetcount_/(now-dl_thresh_); dl_minB_ = (cwnd_ - dl_alpha_)/(dl_minrtt_*tcp_tick_); dl_maxB_=dl_Bi_; } else { dl_Bi_=0.75*dl_Bi_+0.25*dl_packetcount_/(now-dl_thresh_); //useful with delayed acking //dl_Bi_=dl_packetcount_/(now-dl_thresh_); if (dl_Bi_ > dl_maxB_) dl_maxB_=dl_Bi_; } dl_thresh_=now; dl_packetcount_=0; }}/* * 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. * * Note that this procedure is called before "highest_ack_" is * updated to reflect the current ACK packet. */void TcpAgent::ecn(int seqno){ if (seqno > recover_ || last_cwnd_action_ == CWND_ACTION_TIMEOUT) { recover_ = maxseq_; last_cwnd_action_ = CWND_ACTION_ECN; if (cwnd_ <= 1.0) { if (ecn_backoff_) rtt_backoff(); else ecn_backoff_ = 1; } else ecn_backoff_ = 0; slowdown(CLOSE_CWND_HALF|CLOSE_SSTHRESH_HALF); ++necnresponses_ ; // added by sylvia to count number of ecn responses }}/* * Is the connection limited by the network (instead of by a lack * of data from the application? */int TcpAgent::network_limited() { int win = window () ; if (t_seqno_ > (prev_highest_ack_ + win)) return 1; else return 0;}void TcpAgent::recv_newack_helper(Packet *pkt) { //hdr_tcp *tcph = hdr_tcp::access(pkt); newack(pkt); if (!ect_ || !hdr_flags::access(pkt)->ecnecho() || (old_ecn_ && ecn_burst_)) { /* If "old_ecn", this is not the first ACK carrying ECN-Echo * after a period of ACKs without ECN-Echo. * Therefore, open the congestion window. */ /* if control option is set, and the sender is not window limited, then do not increase the window size */ if (!control_increase_ || (control_increase_ && (network_limited() == 1))) opencwnd(); } 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(); }}/* * Set the initial window. */doubleTcpAgent::initial_window(){ // // init_option = 1: static iw of wnd_init_ // if (wnd_init_option_ == 1) { return (wnd_init_); } else if (wnd_init_option_ == 2) { // do iw according to Internet draft if (size_ <= 1095) { return (4.0); } else if (size_ < 2190) { return (3.0); } else { return (2.0); } } // XXX what should we return here??? fprintf(stderr, "Wrong number of wnd_init_option_ %d\n", wnd_init_option_); abort(); return (2.0); // XXX make msvc happy.}/* * Dupack-action: what to do on a DUP ACK. After the initial check * of 'recover' below, this function implements the following truth * table: * * bugfix ecn last-cwnd == ecn action * * 0 0 0 tahoe_action * 0 0 1 tahoe_action [impossible] * 0 1 0 tahoe_action * 0 1 1 slow-start, return * 1 0 0 nothing * 1 0 1 nothing [impossible] * 1 1 0 nothing * 1 1 1 slow-start, return *//* * A first or second duplicate acknowledgement has arrived, and * singledup_ is enabled. * If the receiver's advertised window permits, and we are exceeding our * congestion window by less than numdupacks_, then send a new packet. */voidTcpAgent::send_one(){ if (t_seqno_ <= highest_ack_ + wnd_ && t_seqno_ < curseq_ && t_seqno_ <= highest_ack_ + cwnd_ + dupacks_ ) { output(t_seqno_, 0); if (QOption_) process_qoption_after_send () ; t_seqno_ ++ ; // send_helper(); ?? } return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -