📄 tcp-newreno.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 + -