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

📄 tcp-newreno.cc

📁 adtcp.tar.gz TCL TCL
💻 CC
字号:
/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
 * Copyright (c) 1990, 1997 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 lint
static const char rcsid[] =
    "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp-newreno.cc,v 1.42 2000/09/01 03:04:07 haoboy Exp $ (LBL)";
#endif

//
// newreno-tcp: a revised reno TCP source, without sack
//

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

#include "packet.h"
#include "ip.h"
#include "tcp.h"
#include "flags.h"


static class NewRenoTcpClass : public TclClass {
public:
	NewRenoTcpClass() : TclClass("Agent/TCP/Newreno") {}
	TclObject* create(int, const char*const*) {
		return (new NewRenoTcpAgent());
	}
} class_newreno;

NewRenoTcpAgent::NewRenoTcpAgent() : newreno_changes_(0), 
  newreno_changes1_(0), acked_(0), firstpartial_(0), 
  partial_window_deflation_(0), exit_recovery_fix_(0)
{
	bind("newreno_changes_", &newreno_changes_);
	bind("newreno_changes1_", &newreno_changes1_);
	bind("exit_recovery_fix_", &exit_recovery_fix_);
	bind("partial_window_deflation_", &partial_window_deflation_);
}

/* 
 * Process a packet that acks previously unacknowleges data, but
 * does not take us out of Fast Retransmit.
 */
void NewRenoTcpAgent::partialnewack(Packet* pkt)
{
	hdr_tcp *tcph = hdr_tcp::access(pkt);
#ifdef notyet
	if (pkt->seqno_ == stp->maxpkts && stp->maxpkts > 0)
		stp->endtime = (float) realtime();
#endif
	if (partial_window_deflation_) {
		// Do partial window deflation before resetting last_ack_
		unsigned int deflate = 0; // Should initialize it?? - haoboy
		if (tcph->seqno() > last_ack_) // assertion
			deflate = tcph->seqno() - last_ack_;
		else 
		  	printf("False call to partialnewack:  deflate %u \
last_ack_ %d\n", deflate, last_ack_);
		if (dupwnd_ > deflate)
			dupwnd_ -= (deflate - 1);
		else {
			cwnd_ -= (deflate - dupwnd_);
			// Leave dupwnd_ > 0 to flag "fast recovery" phase
			dupwnd_ = 1; 
		}
	}
	last_ack_ = tcph->seqno();
	highest_ack_ = last_ack_;
	if (t_seqno_ < last_ack_ + 1)
		t_seqno_ = last_ack_ + 1;
	if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
		rtt_active_ = 0;
		t_backoff_ = 1;
	}
}

void NewRenoTcpAgent::partialnewack_helper(Packet* pkt)
{
	if (!newreno_changes1_ || firstpartial_ == 0) {
		firstpartial_ = 1;
		/* For newreno_changes1_, 
		 * only reset the retransmit timer for the first
		 * partial ACK, so that, in the worst case, we
		 * don't have to wait for one packet retransmitted
		 * per RTT.
		 */
		newtimer(pkt);
	}
	partialnewack(pkt);
	output(last_ack_ + 1, 0);
}

int
NewRenoTcpAgent::allow_fast_retransmit(int /* last_cwnd_action_*/)
{
	return 0;
}

void
NewRenoTcpAgent::dupack_action()
{
        /* FILE*fp = fopen("test.out","a+");
        fprintf(fp,"\ndupack:");
        fclose(fp); */
        int reason= get_reason();

        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:

        recover_ = maxseq_;
        /*
         * save the cwnd_ and ssthresh_ for later restore
         * PO reference behavior 2. next 2 lines By Zhenghua
         */
        save_cwnd_ = cwnd_;
        save_ssthresh_ = ssthresh_;
        last_cwnd_action_ = CWND_ACTION_DUPACK;
        if(reason & F_CONG)	{
                 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
        	 reset_rtx_timer(1,0);
		 output(last_ack_ + 1, TCP_REASON_DUPACK);       // from top
/*
		 FILE * fp;
		fp = fopen("fr_trace","a+");
		fprintf(fp,"%f\tlast_ack_=%d\n",  Scheduler::instance().clock(), (int)last_ack_);
		fclose(fp);
*/
	}
	else
	{
		if(reason & F_ERR || reason == 0)
		{
			reset_rtx_timer(1,0);
			output(last_ack_ + 1, TCP_REASON_DUPACK);       // from top
		}
		else {
			if(reason & F_LINK || reason & F_PO)
			{
				if(cwnd_ > ssthresh_)
				cwnd_ = ssthresh_;
				reset_rtx_timer(1,0);
        			output(last_ack_ + 1, TCP_REASON_DUPACK);       // from top
			};
		};
	};
        return;
}


void NewRenoTcpAgent::recv(Packet *pkt, Handler*)
{
	hdr_tcp *tcph = hdr_tcp::access(pkt);


        if(tcph->reason_ == TCP_REASON_ELFN)
        {
                probing_state = 1;
                Packet::free(pkt);
                FILE *fpelfn = fopen("elfn","a+");
                fprintf(fpelfn,"*** tcp_%d received elfn at %f\n",(int) nodeid_,Scheduler::instance().clock());
                fclose(fpelfn);

                /* reset the retransmit timeout here */
                 if ((t_srtt_ >> T_SRTT_BITS)*tcp_tick_ < 2)
                           rtx_timer_.resched(2);
                        else
                           rtx_timer_.resched((t_srtt_ >> T_SRTT_BITS)*tcp_tick_);  


                return;
        }


	/* Use first packet to calculate the RTT  --contributed by Allman */
	if (++acked_ == 1) 
		basertt_ = Scheduler::instance().clock() - firstsent_;

	/* Estimate ssthresh based on the calculated RTT and the estimated
	   bandwidth (using ACKs 2 and 3).  */

	else if (acked_ == 2)
		ack2_ = Scheduler::instance().clock();
	else if (acked_ == 3) {
		ack3_ = Scheduler::instance().clock();
		new_ssthresh_ = int((basertt_ * (size_ / (ack3_ - ack2_))) / size_);
		if (newreno_changes_ > 0 && new_ssthresh_ < ssthresh_)
			ssthresh_ = new_ssthresh_;
	}

#ifdef notdef
	if (pkt->type_ != PT_ACK) {
		fprintf(stderr,
			"ns: confiuration error: tcp received non-ack\n");
		exit(1);
	}
#endif
	++nackpack_;
	ts_peer_ = tcph->ts();

	if (hdr_flags::access(pkt)->ecnecho() && ecn_)
		ecn(tcph->seqno());
	recv_helper(pkt);
	if (tcph->seqno() > last_ack_) {
		if (tcph->seqno() >= recover_ 
		    || (last_cwnd_action_ != CWND_ACTION_DUPACK &&
			tcph->seqno() > last_ack_)) {
			if (dupwnd_ > 0 && exit_recovery_fix_) {
				int outstanding = maxseq_ - tcph->seqno() + 1;
				if (ssthresh_ < outstanding)
					cwnd_ = ssthresh_;
				else
					cwnd_ = outstanding;
			}
                        /* 2 line add by Zhenghua for PO reference behavior 2 */
                        //if (last_cwnd_action_ == CWND_ACTION_DUPACK)
                        //   cwnd_ = save_cwnd_;

			dupwnd_ = 0;
			firstpartial_ = 0;
			recv_newack_helper(pkt);
			if (last_ack_ == 0 && delay_growth_) {
				cwnd_ = initial_window();
			}
		} else {
			/* received new ack for a packet sent during Fast
			 *  Recovery, but sender stays in Fast Recovery */
			if (partial_window_deflation_ == 0)
				dupwnd_ = 0;
			partialnewack_helper(pkt);
		}
	} else if (tcph->seqno() == last_ack_) {

		if (hdr_flags::access(pkt)->eln_ && eln_) {
			tcp_eln(pkt);
			return;
		}
		if (++dupacks_ == numdupacks_) {
			dupack_action();
			dupwnd_ = numdupacks_;
		} else if (dupacks_ > numdupacks_) {
			++dupwnd_;	// fast recovery
			/* For every two duplicate ACKs we receive (in the
			 * "fast retransmit phase"), send one entirely new
			 * data packet "to keep the flywheel going".  --Allman
			 */
			if (newreno_changes_ > 0 && (dupacks_ % 2) == 1)
				output (t_seqno_++,0);
		} else if (dupacks_ < numdupacks_ && singledup_ ) {
                        send_one();
                }
	}
	Packet::free(pkt);
#ifdef notyet
	if (trace_)
		plot();
#endif

	/*
	 * Try to send more data
	 */

	if (dupacks_ == 0) 
		/*
		 * Maxburst is really only needed for the first
		 *  window of data on exiting Fast Recovery.
		 */
		send_much(0, 0, maxburst_);
	else if (dupacks_ > numdupacks_ - 1 && newreno_changes_ == 0)
		send_much(0, 0, 2);
}

⌨️ 快捷键说明

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