📄 tcp.cc
字号:
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(){ 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);}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_); // 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->cwnd() = cwnd_; tcph->t_rtt() = t_rtt_; 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. * * 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));}/* * Returns the window size adjusted to allow <num> segments past recovery * point to be transmitted on next ack. */int TcpAgent::force_wnd(int num){ return recover_ + num - (int)highest_ack_;}int TcpAgent::window(){ /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -