⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.cc

📁 这个是目前国际上比较怪异的一种长距离高带宽环境下的拥塞控制算法
💻 CC
📖 第 1 页 / 共 4 页
字号:
}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:	// we are now going to fast-retransmit and willtrace that event	trace_event("FAST_RETX");	recover_ = maxseq_;	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;	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) (qsh->rate() * (now - tcph->ts_echo())) ;		printf("Quick Start approved, rate %d, window %d\n", 					 qsh->rate(), app_rate);				if (app_rate > initial_window()) {						wnd_init_option_ = 1;						wnd_init_ = app_rate;						qs_approved_ = 1;				}		} else { // Quick Start rejected				printf("Quick Start rejected\n");		}}/* * 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);	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);	/* 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());	Packet::free(pkt);	/*	 * Try to send more data.	 */	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");			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);			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);			}			else {				++nrexmit_;				last_cwnd_action_ = CWND_ACTION_TIMEOUT;				slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);			}		}		/* 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)			ssthresh_ = 2;		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)			ssthresh_ = 2;      		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)			ssthresh_ = 2;		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) ;			for (int i = 0 ; i < (tcp_now - T_last)/rto; i ++) {				slowdown(CWND_HALF_WITH_MIN);			}			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);				slowdown(CLOSE_CWND_HALF_WAY);				T_prev = tcp_now ;				W_used = 0 ;			}		}	} else {		rtt_counting();	}}/* * Check if the sender has been idle or application-limited for more * than an RTO, and if so, reduce the congestion window, for a TCP sender * that "counts RTTs" by estimating the number of RTTs that fit into * a single clock tick. */voidTcpAgent::rtt_counting(){		int tcp_now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);	int rtt = (int(t_srtt_) >> T_SRTT_BITS) ;	if (rtt < 1) 		rtt = 1 ;	if (tcp_now - T_last >= 2*rtt) {		// The sender has been idle.		int RTTs ; 		RTTs = (tcp_now -T_last)*RTT_goodcount/(rtt*2) ; 		RTTs = RTTs - Backoffs ; 		Backoffs = 0 ; 		if (RTTs > 0) {			slowdown(THREE_QUARTER_SSTHRESH) ;			for (int i = 0 ; i < RTTs ; i ++) {				slowdown(CWND_HALF_WITH_MIN);				RTT_prev = RTT_count ; 				W_used = 0 ;			}		}	}	T_last = tcp_now ;	if (tcp_now - T_start >= 2*rtt) {		if ((RTT_count > RTT_goodcount) || (F_full == 1)) {			RTT_goodcount = RTT_count ; 			if (RTT_goodcount < 1) RTT_goodcount = 1 ; 		}		RTT_prev = RTT_prev - RTT_count ;		RTT_count = 0 ; 		T_start  = tcp_now ;		F_full = 0;	}	if (t_seqno_ == highest_ack_ + window()) {		W_used = 0 ; 		F_full = 1 ; 		RTT_prev = RTT_count ;	}	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 (RTT_count - RTT_prev >= 2) {			// The sender has been application-limited.			slowdown(THREE_QUARTER_SSTHRESH) ;			slowdown(CLOSE_CWND_HALF_WAY);			RTT_prev = RTT_count ; 			Backoffs ++ ; 			W_used = 0;		}	}	if (F_counting == 0) {		W_timed = t_seqno_  ;		F_counting = 1 ;	}}void TcpAgent::process_qoption_after_ack (int seqno){	if (F_counting == 1) {		if (seqno >= W_timed) {			RTT_count ++ ; 			F_counting = 0 ; 		}		else {			if (dupacks_ == numdupacks_)				RTT_count ++ ;		}	}}void TcpAgent::trace_event(char *eventtype){	if (et_ == NULL) return;	int seqno = t_seqno_;	char *wrk = et_->buffer();	char *nwrk = et_->nbuffer();	if (wrk != 0)		sprintf(wrk,			"E "TIME_FORMAT" %d %d TCP %s %d %d %d",			et_->round(Scheduler::instance().clock()),   // time			addr(),                       // owner (src) node id			daddr(),                      // dst node id			eventtype,                    // event type			fid_,                         // flow-id			seqno,                        // current seqno			int(cwnd_)                         //cong. window			);		if (nwrk != 0)		sprintf(nwrk,			"E -t "TIME_FORMAT" -o TCP -e %s -s %d.%d -d %d.%d",			et_->round(Scheduler::instance().clock()),   // time			eventtype,                    // event type			addr(),                       // owner (src) node id			port(),                       // owner (src) port id			daddr(),                      // dst node id			dport()                       // dst port id			);	et_->trace();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -