📄 tcp.cc
字号:
TcpAgent::slowdown(int how){ double decrease; /* added for highspeed - sylvia */ double win, halfwin, decreasewin; double ctemp_ = cwnd_; // ktnahm for monitoring convenience int slowstart = 0; ++ncwndcuts_; if (!(how & TCP_IDLE) && !(how & NO_OUTSTANDING_DATA)){ ++ncwndcuts1_; } // we are in slowstart for sure if cwnd < ssthresh if (ctemp_ < 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 && (ctemp_ > 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) && (ctemp_ > 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*ctemp_/4) ssthresh_ = (int)(3*ctemp_/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) { ctemp_ = halfwin; } else ctemp_ = 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. ctemp_ = decreasewin; if (ctemp_ < 1) ctemp_ = 1; } else if (how & CLOSE_CWND_RESTART) ctemp_ = int(wnd_restart_); else if (how & CLOSE_CWND_INIT) ctemp_ = int(wnd_init_); else if (how & CLOSE_CWND_ONE) ctemp_ = 1; else if (how & CLOSE_CWND_HALF_WAY) { // cwnd_ = win - (win - W_used)/2 ; ctemp_ = W_used + decrease_num_ * (win - W_used); if (ctemp_ < 1) ctemp_ = 1; } // ktnahm recover if ( ctemp_ < 1 ) // ktnahm: min. cwnd_ is set to 1 now ctemp_ = 1; cwnd_ = ctemp_; if (ssthresh_ < 2 && increase_num_ >= 1.0) // ktnahm mod ssthresh_ = 2; if (ssthresh_ < 0) ssthresh_ = 0; // ktnahm add 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) if ( (cwnd_ == 1 && increase_num_ >= 1.0) || slowstart ) // ktnahm // 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"); }/* * Process a packet that acks previously unacknowleged data. */void TcpAgent::newack(Packet* pkt){ double now = Scheduler::instance().clock(); 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_) { ts_echo_=tcph->ts_echo(); rtt_update(now - tcph->ts_echo()); if (ts_resetRTO_ && (!ect_ || !ecn_backoff_ || !hdr_flags::access(pkt)->ecnecho())) { // From Andrei Gurtov /* * Don't end backoff if still in ECN-Echo with * a congestion window of 1 packet. */ t_backoff_ = 1; ecn_backoff_ = 0; } } 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_;}/* * 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 (cwnd_ <= 1.0 && increase_num_ >= 1.0) { // ktnahm change for FeW 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 (qs_window_ && highest_ack_ >= qs_window_) { // All segments in the QS window have been acknowledged. // We can exit the Quick-Start phase. qs_window_ = 0; } 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(); } if (frto_ == 1) { /* * New ack after RTO. If F-RTO is enabled, try to transmit new * previously unsent segments. * If there are no new data or receiver window limits the * transmission, revert to traditional recovery. */ if (recover_ + 1 >= highest_ack_ + wnd_ || recover_ + 1 >= curseq_) { frto_ = 0; } else if (highest_ack_ == recover_) { /* * F-RTO step 2a) RTO retransmission fixes whole * window => cancel F-RTO */ frto_ = 0; } else { t_seqno_ = recover_ + 1; frto_ = 2; } } else if (frto_ == 2) { /* * Second new ack after RTO. If F-RTO is enabled, RTO can be * declared spurious */ spurious_timeout(); }}/* * Set the initial window. */doubleTcpAgent::initial_window(){ // If Quick-Start Request was approved, use that as a basis for // initial window if (qs_cwnd_) { return (qs_cwnd_); } // // 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;}voidTcpAgent::dupack_action(){ int recovered = (highest_ack_ > recover_); if (recovered || (!bug_fix_ && !ecn_)) { goto tahoe_action; } if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) { last_cwnd_action_ = CWND_ACTION_DUPACK; slowdown(CLOSE_CWND_ONE); reset_rtx_timer(0,0); return; } if (bug_fix_) { /* * The line below, for "bug_fix_" true, avoids * problems with multiple fast retransmits in one * window of data. */ return; }tahoe_action: recover_ = maxseq_; if (!lossQuickStart()) { // we are now going to fast-retransmit and willtrace that event trace_event("FAST_RETX"); last_cwnd_action_ = CWND_ACTION_DUPACK; slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_ONE); } reset_rtx_timer(0,0); return;}/* * When exiting QuickStart, reduce the congestion window to the * size that was actually used. */void TcpAgent::endQuickStart(){ qs_approved_ = 0; qs_cwnd_ = 0; qs_window_ = maxseq_; int new_cwnd = maxseq_ - last_ack_; if (new_cwnd > 1 && new_cwnd < cwnd_) { cwnd_ = new_cwnd; if (cwnd_ < initial_window()) cwnd_ = initial_window(); }}void TcpAgent::processQuickStart(Packet *pkt){ // QuickStart code from Srikanth Sundarrajan. hdr_tcp *tcph = hdr_tcp::access(pkt); hdr_qs *qsh = hdr_qs::access(pkt); double now = Scheduler::instance().clock(); int app_rate; // printf("flag: %d ttl: %d ttl_diff: %d rate: %d\n", qsh->flag(), // qsh->ttl(), ttl_diff_, qsh->rate()); qs_requested_ = 0; qs_approved_ = 0; if (qsh->flag() == QS_RESPONSE && qsh->ttl() == ttl_diff_ && qsh->rate() > 0) { app_rate = (int) (hdr_qs::rate_to_Bps(qsh->rate()) * (now - tcph->ts_echo()) / (size_ + headersize()));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -