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

📄 tcp.cc

📁 这个是目前国际上比较怪异的一种长距离高带宽环境下的拥塞控制算法
💻 CC
📖 第 1 页 / 共 4 页
字号:
double TcpAgent::rtt_timeout(){	double timeout;	if (rfc2988_) {	// Correction from Tom Kelly to be RFC2988-compliant, by	// clamping minrto_ before applying t_backoff_.		if (t_rtxcur_ < minrto_)			timeout = minrto_ * t_backoff_;		else			timeout = t_rtxcur_ * t_backoff_;	} else {		timeout = t_rtxcur_ * t_backoff_;		if (timeout < minrto_)			timeout = minrto_;	}	if (timeout > maxrto_)		timeout = maxrto_;		if (timeout < 2.0 * tcp_tick_) {		if (timeout < 0) {			fprintf(stderr, "TcpAgent: negative RTO!  (%f)\n",				timeout);			exit(1);		}		timeout = 2.0 * tcp_tick_;	}	return (timeout);}/* This has been modified to use the tahoe code. */void TcpAgent::rtt_update(double tao){	double now = Scheduler::instance().clock();	if (ts_option_)		t_rtt_ = int(tao /tcp_tick_ + 0.5);	else {		double sendtime = now - tao;		sendtime += boot_time_;		double tickoff = fmod(sendtime, tcp_tick_);		t_rtt_ = int((tao + tickoff) / tcp_tick_);	}	if (t_rtt_ < 1)		t_rtt_ = 1;	//	// srtt has 3 bits to the right of the binary point	// rttvar has 2	//		if (t_srtt_ != 0) {		register short delta;		delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS);  // d = (m - a0)		if ((t_srtt_ += delta) <= 0)    // a1 = 7/8 a0 + 1/8 m			t_srtt_ = 1;		if (delta < 0)			delta = -delta;		delta -= (t_rttvar_ >> T_RTTVAR_BITS);		if ((t_rttvar_ += delta) <= 0)  // var1 = 3/4 var0 + 1/4 |d|			t_rttvar_ = 1;	} else {		t_srtt_ = t_rtt_ << T_SRTT_BITS;        // srtt = rtt		t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1);    // rttvar = rtt / 2	}	//	// Current retransmit value is 	//    (unscaled) smoothed round trip estimate	//    plus 2^rttvar_exp_ times (unscaled) rttvar. 	//	t_rtxcur_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS))) +		t_srtt_)  >> T_SRTT_BITS ) * tcp_tick_;	return;}void TcpAgent::rtt_backoff(){	if (t_backoff_ < 64)		t_backoff_ <<= 1;	if (t_backoff_ > 8) {		/*		 * If backed off this far, clobber the srtt		 * value, storing it in the mean deviation		 * instead.		 */		t_rttvar_ += (t_srtt_ >> T_SRTT_BITS);		t_srtt_ = 0;	}}/* * headersize: *      how big is an IP+TCP header in bytes; include options such as ts * this function should be virtual so others (e.g. SACK) can override */int TcpAgent::headersize(){		int total = tcpip_base_hdr_size_;	if (total < 1) {		fprintf(stderr,		  "TcpAgent(%s): warning: tcpip hdr size is only %d bytes\n",		  name(), tcpip_base_hdr_size_);	}	if (ts_option_)		total += ts_option_size_;		return (total);}void TcpAgent::output(int seqno, int reason){	int force_set_rtx_timer = 0;	Packet* p = allocpkt();	hdr_tcp *tcph = hdr_tcp::access(p);	hdr_flags* hf = hdr_flags::access(p);	hdr_ip *iph = hdr_ip::access(p);	int databytes = hdr_cmn::access(p)->size();	tcph->seqno() = seqno;	tcph->ts() = Scheduler::instance().clock();	tcph->ts_echo() = ts_peer_;	tcph->reason() = reason;	tcph->last_rtt() = int(int(t_rtt_)*tcp_tick_*1000);	if (ecn_) {		hf->ect() = 1;  // ECN-capable transport	}	if (cong_action_) {		hf->cong_action() = TRUE;  // Congestion action.		cong_action_ = FALSE;		}	/* Check if this is the initial SYN packet. */	if (seqno == 0) {		if (syn_) {			databytes = 0;			curseq_ += 1;			hdr_cmn::access(p)->size() = tcpip_base_hdr_size_;		}		if (ecn_) {			hf->ecnecho() = 1;//          hf->cong_action() = 1;			hf->ect() = 0;		}		if (qs_enabled_) {			hdr_qs *qsh = hdr_qs::access(p);				if (rate_request_ > 0) {				// QuickStart code from Srikanth Sundarrajan.				qsh->flag() = QS_REQUEST;				Random::seed_heuristically();				qsh->ttl() = Random::integer(256);				ttl_diff_ = (iph->ttl() - qsh->ttl()) % 256;				qsh->rate() = rate_request_;				qs_requested_ = 1;				} else {				qsh->flag() = QS_DISABLE;			}		}	}	else if (useHeaders_ == true) {		hdr_cmn::access(p)->size() += headersize();	}		hdr_cmn::access(p)->size();	/* if no outstanding data, be sure to set rtx timer again */	if (highest_ack_ == maxseq_)		force_set_rtx_timer = 1;	/* call helper function to fill in additional fields */	output_helper(p);		++ndatapack_;		ndatabytes_ += databytes;	send(p, 0);	if (seqno == curseq_ && seqno > maxseq_)		idle();  // Tell application I have sent everything so far	if (seqno > maxseq_) {		maxseq_ = seqno;		if (!rtt_active_) {			rtt_active_ = 1;			if (seqno > rtt_seq_) {				rtt_seq_ = seqno;				rtt_ts_ = Scheduler::instance().clock();			}							}	} else {			++nrexmitpack_;		nrexmitbytes_ += databytes;	}	if (!(rtx_timer_.status() == TIMER_PENDING) || force_set_rtx_timer)		/* No timer pending.  Schedule one. */		set_rtx_timer();}/* * Must convert bytes into packets for one-way TCPs. * If nbytes == -1, this corresponds to infinite send.  We approximate * infinite by a very large number (TCP_MAXSEQ). */void TcpAgent::sendmsg(int nbytes, const char* /*flags*/){	if (nbytes == -1 && curseq_ <= TCP_MAXSEQ)		curseq_ = TCP_MAXSEQ; 	else		curseq_ += (nbytes/size_ + (nbytes%size_ ? 1 : 0));	send_much(0, 0, maxburst_);}void TcpAgent::advanceby(int delta){  curseq_ += delta;	if (delta > 0)		closed_ = 0;	send_much(0, 0, maxburst_); }int TcpAgent::command(int argc, const char*const* argv){	if (argc == 3) {		if (strcmp(argv[1], "advance") == 0) {			int newseq = atoi(argv[2]);			if (newseq > maxseq_)				advanceby(newseq - curseq_);			else				advanceby(maxseq_ - curseq_);			return (TCL_OK);		}		if (strcmp(argv[1], "advanceby") == 0) {			advanceby(atoi(argv[2]));			return (TCL_OK);		}		if (strcmp(argv[1], "eventtrace") == 0) {			et_ = (EventTrace *)TclObject::lookup(argv[2]);			return (TCL_OK);		}		/*		 * Curtis Villamizar's trick to transfer tcp connection		 * parameters to emulate http persistent connections.		 *		 * Another way to do the same thing is to open one tcp		 * object and use start/stop/maxpkts_ or advanceby to control		 * how much data is sent in each burst.		 * With a single connection, slow_start_restart_		 * should be configured as desired.		 *		 * This implementation (persist) may not correctly		 * emulate pure-BSD-based systems which close cwnd		 * after the connection goes idle (slow-start		 * restart).  See appendix C in		 * Jacobson and Karels ``Congestion		 * Avoidance and Control'' at		 * <ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z>		 * (*not* the original		 * '88 paper) for why BSD does this.  See		 * ``Performance Interactions Between P-HTTP and TCP		 * Implementations'' in CCR 27(2) for descriptions of		 * what other systems do the same.		 *		 */		if (strcmp(argv[1], "persist") == 0) {			TcpAgent *other			  = (TcpAgent*)TclObject::lookup(argv[2]);			cwnd_ = other->cwnd_;			awnd_ = other->awnd_;			ssthresh_ = other->ssthresh_;			t_rtt_ = other->t_rtt_;			t_srtt_ = other->t_srtt_;			t_rttvar_ = other->t_rttvar_;			t_backoff_ = other->t_backoff_;			return (TCL_OK);		}	}	return (Agent::command(argc, argv));}int TcpAgent::window(){	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) {			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;				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 packet drop rate p for highspeed TCP. */double TcpAgent::compute_p(){	double p;	double low_p = 1.5/(low_window_*low_window_);	p = exp(linear(log(cwnd_), log(low_window_), log(low_p), log(high_window_), log(high_p_)));	return p;}/* * Calculating the decrease parameter for highspeed TCP. */double TcpAgent::decrease_param(){	double decrease;	decrease = linear(log(cwnd_), log(low_window_), 0.5, log(high_window_), high_decrease_);	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_ >= cwnd_last_ && cwnd_ < cwnd_frac_ * cwnd_last_ ) {		answer = increase_last_ / cwnd_;			   return answer;	   } else { 		p = compute_p();		decrease = decrease_param();		increase = (cwnd_ * cwnd_ *2.0* decrease * p)/(2.0 - decrease);		 		//      double max_increase = 157.8;		//  if (increase > max_increase) { 		//      increase = max_increase;		//  } 		answer = increase / cwnd_;		cwnd_last_ = cwnd_;		increase_last_ = increase;			return answer;	}       }/* * open up the congestion window */void TcpAgent::opencwnd(){	double increment;	double f;	double fold;	double diff;	double RTT_Scaling;	double now=Scheduler::instance().clock();

⌨️ 快捷键说明

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