📄 tcp-westwood-nr.cc
字号:
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- *//* * Copyright (c) 1990, 2001 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Lawrence Berkeley Laboratory, * Berkeley, CA. The name of the University may not be used to * endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef lintstatic const char rcsid[] = "@(#) $Header: /mvalla/tcp-w-nr.cc,v 1.2 2001/09/17 15:12:29 mvalla Exp mvalla $ (LBL)";#endif//// tcp-w-nr: a revised New Reno TCP source, with faster recovery//#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <math.h>#include "packet.h"#include "ip.h"#include "tcp.h"#include "flags.h"#include "address.h"#include "tcp-westwood-nr.h"static class WestwoodNRTcpClass : public TclClass {public: WestwoodNRTcpClass() : TclClass("Agent/TCP/WestwoodNR") {} TclObject* create(int, const char*const*) { return (new WestwoodNRTcpAgent()); }} class_westwoodnr;///// // WestwoodNRTcpAgent()WestwoodNRTcpAgent::WestwoodNRTcpAgent() : NewRenoTcpAgent(), // these where originally in TcpAgent() current_bwe_(0), last_bwe_sample_(0), unaccounted_(0), fr_a_(0), min_rtt_estimate(5.0), myseqno_(1),last_ts_(0),last_echoed_ts_(0),last_seq_(0), lastackrx_(0.0), fr_alpha_(0.9), filter_type_(1), tau_(1.0), total_time_(0.0), total_size_(0.0), fr_prev_(20.0){ // Read defaults variables from ns-defaults.tcl // these where originally in TcpAgent() bind("current_bwe_", ¤t_bwe_); bind("last_bwe_sample_", &last_bwe_sample_); bind("unaccounted_", &unaccounted_); bind("fr_a_", &fr_a_); bind("fr_amin_", &fr_amin_); bind("fr_amax_", &fr_amax_); bind("fr_prev_", &fr_prev_); bind("min_rtt_estimate", &min_rtt_estimate); bind("fr_alpha_", &fr_alpha_); bind("filter_type_", &filter_type_); bind("tau_", &tau_); bind("west_type_",&west_type_); bind("qest_",&qest_); bind("total_time_",&total_time_); bind("total_size_",&total_size_); bind("interp_type_",&interp_type_); bind("last_ts_",&last_ts_); bind("last_echoed_ts_",&last_echoed_ts_); bind("last_seq_",&last_seq_); bind("last_cwnd_",&last_cwnd_); bind("current_ts_",¤t_ts_); bind("current_echoed_ts_",¤t_echoed_ts_); // these where originally in NewRenoTcpAgent() bind("newreno_changes_", &newreno_changes_); bind("newreno_changes1_", &newreno_changes1_); bind("exit_recovery_fix_", &exit_recovery_fix_); bind("partial_window_deflation_", &partial_window_deflation_); bind("openadd_", &openadd_); //printf("Westwood New Reno binding done!\n");}///// // dupack_action()void WestwoodNRTcpAgent::dupack_action(){ int recovered = (highest_ack_ > recover_); int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_); if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit) { goto reno_action; } if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) { last_cwnd_action_ = CWND_ACTION_DUPACK; /* * What if there is a DUPACK action followed closely by ECN * followed closely by a DUPACK action? * The optimal thing to do would be to remember all * congestion actions from the most recent window * of data. Otherwise "bugfix" might not prevent * all unnecessary Fast Retransmits. */ reset_rtx_timer(1,0); output(last_ack_ + 1, TCP_REASON_DUPACK); return; } if (bug_fix_) { /* * The line below, for "bug_fix_" true, avoids * problems with multiple fast retransmits in one * window of data. */ return; }reno_action:/* if (ssthresh_ > cwnd_) { fr_a_+=0.25; if (fr_a_ > 4) fr_a_=4; } else { fr_a_ = 1; } ssthresh_ = (int)((current_bwe_/size_/8) * min_rtt_estimate); if (cwnd_ > ssthresh_) { cwnd_ = ssthresh_; } */double fr_now = Scheduler::instance().clock();double rtt_estimate = t_rtt_ * tcp_tick_;if ((rtt_estimate < min_rtt_estimate)&&(rtt_estimate > 0)) { min_rtt_estimate = rtt_estimate; }/* west_type_ = 3 west+ *///if (west_type_<=4)fr_a_=-1;double sstemp=(((current_bwe_*(min_rtt_estimate))/((double)(size_*8.0))));if (sstemp < 2) sstemp = 2;//if (sstemp1 < 2) sstemp1 = 2; ssthresh_ = (int)(sstemp); if (cwnd_ > sstemp) {cwnd_ = sstemp;} trace_event("TCPWNR_FAST_RETX"); recover_ = maxseq_; last_cwnd_action_ = CWND_ACTION_DUPACK; // The slowdown was already performed // slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF); reset_rtx_timer(1,0); output(last_ack_ + 1, TCP_REASON_DUPACK); return;}/////// timeout()void WestwoodNRTcpAgent::timeout(int tno){ /* retransmit timer */ if (tno == TCP_TIMER_RTX) { if (highest_ack_ == maxseq_ && !slow_start_restart_) { /* * TCP option: * If no outstanding data, then don't do anything. */ return; }; 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_; slowdown(CLOSE_FASTER); } /* 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); }}///// // bwe_computation()void WestwoodNRTcpAgent::bwe_computation(Packet *pkt) { hdr_tcp *tcph = hdr_tcp::access(pkt); double fr_now = Scheduler::instance().clock(); hdr_flags *fh = hdr_flags::access(pkt); // last_ack_ indicates the ack no. of the ack received _before_ // the current one // START BWE COMPUTATION // Idea: cumulative ACKs acking more than 2 packets count for 1 packet // since DUPACKs have already been accounted for int cumul_ack = tcph->seqno_ - last_ack_; int cumul_ack1 = cumul_ack; //used for queueing time estimation myseqno_ = tcph->seqno_; if (cumul_ack > 1) { /* check if current ACK ACKs fewer or same number of segments than */ /* expected: if so, the missing ones were already accounted for by */ /* DUPACKs, and current ACK only counts as 1 */ if (unaccounted_ >= cumul_ack) { unaccounted_-=cumul_ack; cumul_ack=1; } else /* check if current ACK ACKs more segments than expected: if so, */ /* part of them were already accounted for by DUPACKs; the rest */ /* are cumulatively ACKed by present ACK. Make present ACK count */ /* as the unacknowledged ACKs in excess*/ if (unaccounted_ < cumul_ack) { cumul_ack-=unaccounted_; unaccounted_=0; } } /* if cumul_ack=0, the current ACK is clearly a DUPACK and should */ /* count 1 */ if (cumul_ack == 0) { unaccounted_++; cumul_ack=1; } /* safety check; if the previous steps are followed exactly, */ /* cumul_ack should not be >2 unless some strage events occur */ /* (e.g., an ACK is dropped on the way back and the following one */ /* appears to ACK more than its due) */ if (cumul_ack > 2) { cumul_ack=2; } nackpack_+= cumul_ack; last_seq_+=cumul_ack; //qest_=cwnd_-(current_bwe_*min_rtt_estimate)/(8.0*(double)size_); current_ts_=tcph->ts(); current_echoed_ts_=tcph->ts_echo(); double rtt_estimate = t_rtt_ * tcp_tick_; if ((rtt_estimate < min_rtt_estimate)&&(rtt_estimate > 0)) { min_rtt_estimate = rtt_estimate; qest_=0; last_echoed_ts_=current_echoed_ts_; last_ts_=current_ts_; } qest_=qest_+(current_ts_-last_ts_)-(current_echoed_ts_-last_echoed_ts_); last_echoed_ts_=current_echoed_ts_; last_ts_=current_ts_;//if (west_type_==5) qest_=cwnd_-(current_bwe_*min_rtt_estimate)/(8.0*(double)size_); int acked_size = size_ * 8 * cumul_ack; double ack_interv = fr_now - lastackrx_; double sample_bwe; double last_tmp_bwe; int idle_intervals; switch (filter_type_) { case 0: // original filter sample_bwe = acked_size/ack_interv; current_bwe_ = current_bwe_ * fr_alpha_ + sample_bwe * (1 - fr_alpha_); last_bwe_sample_ = sample_bwe; break; case 1: // filter type 1 sample_bwe = acked_size/ack_interv; current_bwe_ = current_bwe_ * .9047 + (sample_bwe + last_bwe_sample_) * .0476; last_bwe_sample_ = sample_bwe; break; case 2: // filter type 2: 'lower' pass sample_bwe = acked_size/ack_interv; current_bwe_ = current_bwe_ * .93548 + (sample_bwe+last_bwe_sample_) * .03225; last_bwe_sample_ = sample_bwe; break; case 3: // filter type 3: time constant tau_ // compute how many intervals of length tau_/2 went by since we // received the last ACK. For each tau_/2 interval without ACK, feed // a zero-bandwidth sample to the filter. idle_intervals = (int)(ack_interv / tau_*2.0); // printf("idle_intervals = %d (%f,%f)=%f\n", idle_intervals, ack_interv, tau_, // ack_interv / tau_); // printf("idle_intervals = %d, ratio= %f\n",idle_intervals, ack_interv / tau_); ack_interv -= tau_ /2.0 * idle_intervals; //if ( (ack_interv < 0.01) && (idle_intervals == 0) ){ // printf("TCP-W error: (ack_interv < 0.01) && (idle_intervals == 0)\n"); // printf("time=%lf, last_ack=%lf, ack_interv=%lf\n", fr_now, lastackrx_, ack_interv); // //exit(0); //} if ( (ack_interv < 0.01) && (idle_intervals > 0) ) { // ack_interv was a multiple of tau_/2 or the remainder is too small (less than 10ms), so // we consider tau_ / 2 as the last interval ack_interv = tau_ / 2.0; idle_intervals -= 1; // we do not count the last tau_/2 interval } sample_bwe = acked_size/ack_interv; if (idle_intervals > 0) { // feed the filter // printf("idle_intervals = %d\n", idle_intervals); for (int i=0; i<idle_intervals; i++) { current_bwe_ = current_bwe_ * 3.0 / 5.0 + last_bwe_sample_/5.0; last_bwe_sample_ = 0.0; // printf("idle_interval: current_bwe=%f\n", current_bwe_); } } last_tmp_bwe = current_bwe_; // we need it just for the printf... current_bwe_ = current_bwe_ * (2.0*tau_-ack_interv) / (2.0*tau_+ack_interv) + ack_interv*(sample_bwe + last_bwe_sample_)/(2.0*tau_+ack_interv); last_bwe_sample_ = sample_bwe; if (current_bwe_ < 0) { printf("TCP-W error: current_bwe_ < 0\n"); printf("time: %f, last_tmp_bwe=%f\n", fr_now, last_tmp_bwe); printf("current_bwe_%f, ack_interv=%f, sample_bwe=%f, last_bwe_sample_=%f\n", current_bwe_, ack_interv, sample_bwe, last_bwe_sample_); exit(0); } break; case 4: total_size_ = total_size_ + acked_size; total_time_ = total_time_ + ack_interv; if (((rtt_estimate >0)&&(total_time_>rtt_estimate))) { sample_bwe = total_size_/total_time_; double m=(sample_bwe-last_bwe_sample_)/pow(total_time_,interp_type_);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -