📄 tcp.cc
字号:
// in 1-way TCP, syn_ indicates we are modeling// a SYN exchange at the beginning. If this is true// and we are delaying growth, then use an initial// window of one. If not, we do whatever initial_window()// says to do.//voidTcpAgent::set_initial_window(){ afew_=1; if (syn_ && delay_growth_) cwnd_ = 1.0; else cwnd_ = initial_window();}voidTcpAgent::reset_qoption(){ int now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5); T_start = now ; RTT_count = 0 ; RTT_prev = 0 ; RTT_goodcount = 1 ; F_counting = 0 ; W_timed = -1 ; F_full = 0 ; Backoffs = 0 ; }voidTcpAgent::reset(){ afew_=1; rtt_init(); rtt_seq_ = -1; /*XXX lookup variables */ dupacks_ = 0; curseq_ = 0; set_initial_window(); t_seqno_ = 0; maxseq_ = -1; last_ack_ = -1; highest_ack_ = -1; ssthresh_ = int(wnd_); if (max_ssthresh_ > 0 && max_ssthresh_ < ssthresh_) ssthresh_ = max_ssthresh_; wnd_restart_ = 1.; awnd_ = wnd_init_ / 2.0; recover_ = 0; closed_ = 0; last_cwnd_action_ = 0; boot_time_ = Random::uniform(tcp_tick_); first_decrease_ = 1; /* W.N.: for removing packets from previous incarnations */ lastreset_ = Scheduler::instance().clock(); /* Now these variables will be reset - Debojyoti Dutta 12th Oct'2000 */ ndatapack_ = 0; ndatabytes_ = 0; nackpack_ = 0; nrexmitbytes_ = 0; nrexmit_ = 0; nrexmitpack_ = 0; necnresponses_ = 0; ncwndcuts_ = 0; ncwndcuts1_ = 0; if (control_increase_) { prev_highest_ack_ = highest_ack_ ; } if (wnd_option_ == 8) { // HighSpeed TCP hstcp_.low_p = 1.5/(low_window_*low_window_); double highLowWin = log(high_window_)-log(low_window_); double highLowP = log(high_p_) - log(hstcp_.low_p); hstcp_.dec1 = 0.5 - log(low_window_) * (high_decrease_ - 0.5)/highLowWin; hstcp_.dec2 = (high_decrease_ - 0.5)/highLowWin; hstcp_.p1 = log(hstcp_.low_p) - log(low_window_) * highLowP/highLowWin; hstcp_.p2 = highLowP/highLowWin; } if (QOption_) { int now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5); T_last = now ; T_prev = now ; W_used = 0 ; if (EnblRTTCtr_) { reset_qoption(); } }}/* * Initialize variables for the retransmit timer. */void TcpAgent::rtt_init(){ t_rtt_ = 0; t_srtt_ = int(srtt_init_ / tcp_tick_) << T_SRTT_BITS; t_rttvar_ = int(rttvar_init_ / tcp_tick_) << T_RTTVAR_BITS; t_rtxcur_ = rtxcur_init_; t_backoff_ = 1;}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; // // t_srtt_ has 3 bits to the right of the binary point // t_rttvar_ has 2 // Thus "t_srtt_ >> T_SRTT_BITS" is the actual srtt, // and "t_srtt_" is 8*srtt. // Similarly, "t_rttvar_ >> T_RTTVAR_BITS" is the actual rttvar, // and "t_rttvar_" is 4*rttvar. // 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);}#include <address.h>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(); int is_retransmit = (seqno < maxseq_); //add by chen if(0){ struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); // hack the IP address to convert pkt format to hostid format // for now until port ids are removed from IP address. -Padma. int src = Address::instance().get_nodeaddr(ih->saddr()); int dst = Address::instance().get_nodeaddr(ih->daddr()); printf("seq%d:-Is %d.%d -Id %d.%d -It %s -Il %d -If %d -Ii %d -Iv %d\n",seqno, src, // packet src ih->sport(), // src port dst, // packet dest ih->dport(), // dst port packet_info.name(ch->ptype()), // packet type ch->size(), // packet size ih->flowid(), // flow id ch->uid(), // unique id ih->ttl_);}//add end // Mark packet for diagnosis purposes if we are in Quick-Start Phase if (qs_approved_) { hf->qs() = 1; } // store timestamps, with bugfix_ts_. From Andrei Gurtov. // (A real TCP would use scoreboard for this.) if (bugfix_ts_ && tss==NULL) { tss = (double*) calloc(tss_size_, sizeof(double)); if (tss==NULL) exit(1); } //dynamically grow the timestamp array if it's getting full if (bugfix_ts_ && window() > tss_size_* 0.9) { double *ntss; ntss = (double*) calloc(tss_size_*2, sizeof(double)); printf("resizing timestamp table\n"); if (ntss == NULL) exit(1); for (int i=0; i<tss_size_; i++) ntss[(highest_ack_ + i) % (tss_size_ * 2)] = tss[(highest_ack_ + i) % tss_size_]; free(tss); tss_size_ *= 2; tss = ntss; } if (tss!=NULL) tss[seqno % tss_size_] = tcph->ts(); 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_ && (!is_retransmit || SetCWRonRetransmit_)) { 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); // dataout is kilobytes queued for sending int dataout = (curseq_ - maxseq_ - 1) * (size_ + headersize()) / 1024; int qs_rr = rate_request_; if (qs_request_mode_ == 1) { // PS: Avoid making unnecessary QS requests // use a rough estimation of RTT in qs_rtt_ // to calculate the desired rate from dataout. if (dataout * 1000 / qs_rtt_ < qs_rr) { qs_rr = dataout * 1000 / qs_rtt_; } // qs_thresh_ is minimum number of unsent // segments needed to activate QS request if ((curseq_ - maxseq_ - 1) < qs_thresh_) { qs_rr = 0; } } if (qs_rr > 0) { // QuickStart code from Srikanth Sundarrajan. qsh->flag() = QS_REQUEST; qsh->ttl() = Random::integer(256); ttl_diff_ = (iph->ttl() - qsh->ttl()) % 256; qsh->rate() = hdr_qs::Bps_to_rate(qs_rr * 1024); 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. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -