diff -Nuarp ns-2.1b9a.orig/Makefile.in ns-2.1b9a-hstcp/Makefile.in --- ns-2.1b9a.orig/Makefile.in Fri Jun 7 00:37:57 2002 +++ ns-2.1b9a-hstcp/Makefile.in Tue Jan 14 13:46:14 2003 @@ -158,7 +158,7 @@ OBJ_CC = \ tcp/tcp-newreno.o \ tcp/tcp-vegas.o tcp/tcp-rbp.o tcp/tcp-full.o tcp/rq.o \ baytcp/tcp-full-bay.o baytcp/ftpc.o baytcp/ftps.o \ - tcp/scoreboard.o tcp/tcp-sack1.o tcp/tcp-fack.o \ + tcp/scoreboard.o tcp/scoreboard-rq.o tcp/tcp-sack1.o tcp/tcp-fack.o \ tcp/tcp-asym.o tcp/tcp-asym-sink.o tcp/tcp-fs.o \ tcp/tcp-asym-fs.o \ tcp/tcp-int.o tcp/chost.o tcp/tcp-session.o \ diff -Nuarp ns-2.1b9a.orig/queue/drop-tail.cc ns-2.1b9a-hstcp/queue/drop-tail.cc --- ns-2.1b9a.orig/queue/drop-tail.cc Tue Jan 1 05:26:10 2002 +++ ns-2.1b9a-hstcp/queue/drop-tail.cc Tue Jan 14 14:48:14 2003 @@ -83,17 +83,19 @@ void DropTail::enque(Packet* p) if (summarystats) { Queue::updateStats(qib_?q_->byteLength():q_->length()); } - q_->enque(p); - int qlimBytes = qlim_ * mean_pktsize_; - if ((!qib_ && q_->length() >= qlim_) || - (qib_ && q_->byteLength() >= qlimBytes)) { + + int qlimBytes = qlim_ * mean_pktsize_; + if ((!qib_ && (q_->length() + 1) >= qlim_) || + (qib_ && (q_->byteLength() + hdr_cmn::access(p)->size()) >= qlimBytes)) { if (drop_front_) { /* remove from head of queue */ + q_->enque(p); Packet *pp = q_->deque(); drop(pp); - } else { - q_->remove(p); + }else{ drop(p); } + }else{ + q_->enque(p); } } diff -Nuarp ns-2.1b9a.orig/tcp/rq.cc ns-2.1b9a-hstcp/tcp/rq.cc --- ns-2.1b9a.orig/tcp/rq.cc Thu Sep 27 01:07:51 2001 +++ ns-2.1b9a-hstcp/tcp/rq.cc Tue Jan 14 13:46:14 2003 @@ -53,6 +53,26 @@ #include "rq.h" +ReassemblyQueue::seginfo* ReassemblyQueue::freelist_ = NULL; + +ReassemblyQueue::seginfo* ReassemblyQueue::newseginfo() +{ + seginfo *s; + + if( (s = freelist_) ){ + freelist_ = s->next_; + return s; + }else{ + return new seginfo; + } +} + +void ReassemblyQueue::deleteseginfo(ReassemblyQueue::seginfo* s) +{ + s->next_ = freelist_; + freelist_ = s; +} + /* * unlink a seginfo from its FIFO */ @@ -142,7 +162,7 @@ ReassemblyQueue::clear() while (head_) { p = head_; head_= head_->next_; - delete(p); + ReassemblyQueue::deleteseginfo(p); } tail_ = NULL; total_ = 0; @@ -166,7 +186,7 @@ ReassemblyQueue::clearto(TcpSeq seq) total_ -= (p->endseq_ - p->startseq_); sremove(p); fremove(p); - delete p; + ReassemblyQueue::deleteseginfo(p); p = q; } else break; @@ -305,7 +325,7 @@ ReassemblyQueue::add(TcpSeq start, TcpSe // nobody there, just insert this one - tail_ = head_ = top_ = bottom_ = new seginfo; + tail_ = head_ = top_ = bottom_ = ReassemblyQueue::newseginfo(); head_->prev_ = head_->next_ = head_->snext_ = head_->sprev_ = NULL; head_->startseq_ = start; head_->endseq_ = end; @@ -391,7 +411,7 @@ start, end, p, q, initcnt += n->cnt_; fremove(n); sremove(n); - delete n; + ReassemblyQueue::deleteseginfo(n); altered = TRUE; } else r = r->next_; @@ -474,7 +494,7 @@ start, end, p, q, } endfast: - n = new seginfo; + n = ReassemblyQueue::newseginfo(); n->startseq_ = start; n->endseq_ = end; n->pflags_ = tiflags; @@ -553,8 +573,8 @@ dumplist(); p->endseq_ = q->endseq_; p->cnt_ += (n->cnt_ + q->cnt_); flags = (p->pflags_ |= n->pflags_); - delete n; - delete q; + ReassemblyQueue::deleteseginfo(n); + ReassemblyQueue::deleteseginfo(q); } else if (p && (p->endseq_ == n->startseq_)) { // new block joins p, but not q // update p with n's seq data, delete new block @@ -563,7 +583,7 @@ dumplist(); p->endseq_ = n->endseq_; flags = (p->pflags_ |= n->pflags_); p->cnt_ += n->cnt_; - delete n; + ReassemblyQueue::deleteseginfo(n); } else if (q && (n->endseq_ == q->startseq_)) { // new block joins q, but not p // update q with n's seq data, delete new block @@ -572,7 +592,7 @@ dumplist(); q->startseq_ = n->startseq_; flags = (q->pflags_ |= n->pflags_); q->cnt_ += n->cnt_; - delete n; + ReassemblyQueue::deleteseginfo(n); p = q; // ensure p points to something } diff -Nuarp ns-2.1b9a.orig/tcp/rq.h ns-2.1b9a-hstcp/tcp/rq.h --- ns-2.1b9a.orig/tcp/rq.h Thu Sep 27 01:06:54 2001 +++ ns-2.1b9a-hstcp/tcp/rq.h Tue Jan 14 13:46:14 2003 @@ -85,6 +85,12 @@ typedef int RqFlag; // meta data (owned * kfall@intel.com */ +/* 01/03 Tom Kelly + * + * Made the newseginfo and deleteseginfo calls to avoid new/delete + * overhead in generating SACK blocks good for HSTCP; see scoreboard-rq + */ + class ReassemblyQueue { struct seginfo { seginfo* next_; // next on FIFO list @@ -120,7 +126,13 @@ public: } void dumplist(); // for debugging + // cache of allocated seginfo blocks + static seginfo* newseginfo(); + static void deleteseginfo(seginfo*); + protected: + static seginfo* freelist_; // cache of free seginfo blocks + seginfo* head_; // head of segs linked list seginfo* tail_; // end of segs linked list diff -Nuarp ns-2.1b9a.orig/tcp/scoreboard-rq.cc ns-2.1b9a-hstcp/tcp/scoreboard-rq.cc --- ns-2.1b9a.orig/tcp/scoreboard-rq.cc Thu Jan 1 01:00:00 1970 +++ ns-2.1b9a-hstcp/tcp/scoreboard-rq.cc Tue Jan 14 13:46:14 2003 @@ -0,0 +1,101 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2002 Tom Kelly, University of Cambridge + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the MASH Research + * Group at the University of California Berkeley. + * 4. Neither the name of the University nor of the Research Group may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include "scoreboard-rq.h" + +// Implementation of a ScoreBoard shim for +// the FullTCP reassembly queue code + +int ScoreBoardRQ::IsEmpty(){ + printf("ScoreBoardRQ::IsEmpty not implemented\n"); + exit(1); +} + +int ScoreBoardRQ::GetNextRetran(){ + int seq; + int fcnt; + int fbytes; + + if(h_seqno_ < sack_min) h_seqno_ = sack_min; + seq = h_seqno_; + + if((seq = rq_.nexthole(seq, fcnt, fbytes)) > 0) { + // adjust h_seqno, as we may have + // been "jumped ahead" by learning + // about a filled hole + + if(fcnt <= 0) return (-1); // no holes above + + //printf("%.4f ", Scheduler::instance().clock()); + //printf("GetNextRetran sack_min: %i h_seqno: %i seq: %i\n", sack_min, h_seqno_, seq); + if(seq > h_seqno_) + h_seqno_ = seq; + + return (seq); + } + return (-1); +} + +int ScoreBoardRQ::UpdateScoreBoard(int last_ack_, hdr_tcp* tcph){ + int old_total = rq_.total(); + changed_ = 0; + + if(sack_min <= last_ack_){ + // beginning of retransmission queue is one beyond last_ack + sack_min = last_ack_+1; + if(!rq_.empty()){ + rq_.cleartonxt(); + changed_ = 1; + } + } + + for(int i = 0 ; i < tcph->sa_length() ; i++){ + //printf("l: %i r: %i\n", tcph->sa_left(i), tcph->sa_right(i)); + rq_.add(tcph->sa_left(i), tcph->sa_right(i), 0); + } + changed_ = changed_ || (old_total != rq_.total()); + + //printf("UpdateScoreBoard dump changed_: %i\n", changed_); + //printf("%.4f ", Scheduler::instance().clock()); + //rq_.dumplist(); + +} + +int ScoreBoardRQ::CheckSndNxt(hdr_tcp* h) { + printf("ScoreBoardRQ::CheckSndNxt not implemented\n"); + exit(1); +} diff -Nuarp ns-2.1b9a.orig/tcp/scoreboard-rq.h ns-2.1b9a-hstcp/tcp/scoreboard-rq.h --- ns-2.1b9a.orig/tcp/scoreboard-rq.h Thu Jan 1 01:00:00 1970 +++ ns-2.1b9a-hstcp/tcp/scoreboard-rq.h Tue Jan 14 13:46:14 2003 @@ -0,0 +1,64 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2002 Tom Kelly, University of Cambridge + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the MASH Research + * Group at the University of California Berkeley. + * 4. Neither the name of the University nor of the Research Group may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ns_scoreboard_rq_h +#define ns_scoreboard_rq_h + +// Definition of the scoreboardRQ class +// - a shim over the FullTCP reassembly queue code + +#include "scoreboard.h" +#include "rq.h" + +class ScoreBoardRQ : public ScoreBoard { +public: + ScoreBoardRQ(): ScoreBoard(NULL, 0), h_seqno_(-1),sack_min(-1), rq_(sack_min){}; + virtual ~ScoreBoardRQ(){delete[] SBN;} + virtual int IsEmpty (); + virtual void ClearScoreBoard () {rq_.clear(); h_seqno_ = -1;}; + virtual int GetNextRetran (); + virtual void MarkRetran (int retran_seqno){if(retran_seqno >= h_seqno_) h_seqno_ = retran_seqno+1;}; + virtual void MarkRetran (int retran_seqno, int snd_nxt){if(retran_seqno >= h_seqno_) h_seqno_ = retran_seqno+1;}; + virtual int UpdateScoreBoard (int last_ack_, hdr_tcp*); + virtual int CheckUpdate() {return (changed_);} + virtual int CheckSndNxt (hdr_tcp*); +protected: + int h_seqno_; + int sack_min; + + ReassemblyQueue rq_; +}; + +#endif diff -Nuarp ns-2.1b9a.orig/tcp/scoreboard.cc ns-2.1b9a-hstcp/tcp/scoreboard.cc --- ns-2.1b9a.orig/tcp/scoreboard.cc Sun Jul 23 02:29:33 2000 +++ ns-2.1b9a-hstcp/tcp/scoreboard.cc Tue Jan 14 13:46:14 2003 @@ -45,17 +45,13 @@ static const char rcsid[] = /* A quick hack version of the scoreboard */ #include #include -#include -#include - -#include "packet.h" #include "scoreboard.h" #include "tcp.h" #define ASSERT(x) if (!(x)) {printf ("Assert SB failed\n"); exit(1);} #define ASSERT1(x) if (!(x)) {printf ("Assert1 SB (length)\n"); exit(1);} -#define SBNI SBN[i%SBSIZE] +#define SBNI SBN[i%sbsize_] // last_ack = TCP last ack int ScoreBoard::UpdateScoreBoard (int last_ack, hdr_tcp* tcph) @@ -64,31 +60,14 @@ int ScoreBoard::UpdateScoreBoard (int la int retran_decr = 0; changed_ = 0; - - // If there is no scoreboard, create one. - if (length_ == 0 && tcph->sa_length()) { - i = last_ack+1; - SBNI.seq_no_ = i; - SBNI.ack_flag_ = 0; - SBNI.sack_flag_ = 0; - SBNI.retran_ = 0; - SBNI.snd_nxt_ = 0; - first_ = i%SBSIZE; - length_++; - if (length_ >= SBSIZE) { - printf ("Error, scoreboard too large (increase SBSIZE for more space)\n"); - exit(1); - } - changed_++; - } - + // Advance the left edge of the block. - if (length_ && SBN[first_].seq_no_ <= last_ack) { - for (i=SBN[first_].seq_no_; i<=last_ack; i++) { + if (length_ && SBN[first_%sbsize_].seq_no_ <= last_ack) { + for (i=SBN[first_%sbsize_].seq_no_; i<=last_ack; i++) { // Advance the ACK if (SBNI.seq_no_ <= last_ack) { - ASSERT(first_ == i%SBSIZE); - first_ = (first_+1)%SBSIZE; + ASSERT(first_ == i); + first_ = (first_+1); length_--; ASSERT1(length_ >= 0); SBNI.ack_flag_ = 1; @@ -104,30 +83,55 @@ int ScoreBoard::UpdateScoreBoard (int la } } } - + + // If there is no scoreboard, create one. + if (length_ == 0 && tcph->sa_length()) { + i = last_ack+1; + SBNI.seq_no_ = i; + SBNI.ack_flag_ = 0; + SBNI.sack_flag_ = 0; + SBNI.retran_ = 0; + SBNI.snd_nxt_ = 0; + first_ = i; + length_++; + if (length_ >= sbsize_) { + printf ("Error, scoreboard too large (increase sbsize_ for more space)\n"); + exit(1); + } + changed_++; + } + for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) { sack_left = tcph->sa_left(sack_index); sack_right = tcph->sa_right(sack_index); - + // Create new entries off the right side. - if (sack_right > SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_) { + if (sack_right > SBN[(first_+length_+sbsize_-1)%sbsize_].seq_no_) { + + // Resize the scoreboard if it is going to overrun the length + while((sack_right - last_ack) >= sbsize_ -1 ){ + resizeSB(sbsize_*2); + } + // Create new entries - for (i = SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_+1; i= SBSIZE) { - printf ("Error, scoreboard too large (increase SBSIZE for more space)\n"); - exit(1); + if (length_ >= sbsize_) { + fprintf(stderr, "ERROR: Scoreboard got too large!!!\n"); + fprintf(stderr, " SBN[first (mod) sbsize_]: %i, sack_right: %i length_: %i\n", SBN[first_%sbsize_].seq_no_,sack_right , length_); + fprintf(stderr, "last_ack: %i SBN[(first_+length_+sbsize_-1) (mod) sbsize_].seq_no_: %i, sbsize_: %i\n", last_ack, SBN[(first_+length_+sbsize_-1)%sbsize_].seq_no_ , sbsize_); + exit(1); } changed_++; } } - for (i=SBN[(first_)%SBSIZE].seq_no_; i= sack_left && SBNI.seq_no_ < sack_right) { if (! SBNI.sack_flag_) { @@ -152,7 +156,7 @@ int ScoreBoard::CheckSndNxt (hdr_tcp* tc sack_left = tcph->sa_left(sack_index); sack_right = tcph->sa_right(sack_index); - for (i=SBN[(first_)%SBSIZE].seq_no_; iClearScoreBoard(); TcpAgent::reset (); } @@ -151,14 +156,14 @@ void FackTcpAgent::recv(Packet *pkt, Han recv_newack_helper(pkt); fack_ = last_ack_; timeout_ = FALSE; - scb_.ClearScoreBoard(); + scb_->ClearScoreBoard(); retran_data_ = 0; wintrim_ = 0; } else if ((int)tcph->seqno() < last_ack_) { // Do nothing; ack may have been misordered } else { - retran_data_ -= scb_.UpdateScoreBoard (highest_ack_, tcph); + retran_data_ -= scb_->UpdateScoreBoard (highest_ack_, tcph); oldack(pkt); ms = maxsack(pkt); if (ms > fack_) @@ -190,7 +195,7 @@ void FackTcpAgent::recv(Packet *pkt, Han } reset_rtx_timer(1,0); fastrecov_ = TRUE; - scb_.MarkRetran (last_ack_+1, t_seqno_); + scb_->MarkRetran (last_ack_+1, t_seqno_); retran_data_++; output(last_ack_ + 1, TCP_REASON_DUPACK); } @@ -213,11 +218,11 @@ void FackTcpAgent::recv(Packet *pkt, Han if (fack_ >= t_seqno_) t_seqno_ = fack_ + 1; - retran_data_ -= scb_.UpdateScoreBoard (highest_ack_, tcph); + retran_data_ -= scb_->UpdateScoreBoard (highest_ack_, tcph); // If the retransmission was lost again, timeout_ forced to TRUE // if timeout_ TRUE, this shuts off send() - timeout_ |= scb_.CheckSndNxt (tcph); + timeout_ |= scb_->CheckSndNxt (tcph); opencwnd(); @@ -229,7 +234,7 @@ void FackTcpAgent::recv(Packet *pkt, Han // No SACK blocks indicates fast recovery is over fastrecov_ = FALSE; timeout_ = FALSE; - scb_.ClearScoreBoard(); + scb_->ClearScoreBoard(); retran_data_ = 0; wintrim_ = 0; dupacks_ = 0; @@ -271,7 +276,7 @@ void FackTcpAgent::timeout(int tno) // close down to 1 segment slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART); } - scb_.ClearScoreBoard(); + scb_->ClearScoreBoard(); /* if there is no outstanding data, don't back off rtx timer */ if (highest_ack_ == maxseq_) reset_rtx_timer(TCP_REASON_TIMEOUT,0); @@ -309,7 +314,7 @@ void FackTcpAgent::send_much(int force, while (( t_seqno_ <= fack_ + win - retran_data_) && (!timeout_)) { if (overhead_ == 0 || force) { found = 0; - xmit_seqno = scb_.GetNextRetran (); + xmit_seqno = scb_->GetNextRetran (); #ifdef DEBUGSACK1A printf("highest_ack: %d xmit_seqno: %d timeout: %d seqno: %d fack: % d win: %d retran_data: %d\n", highest_ack_, xmit_seqno, timeout_, t_seqno_, fack_, win, retran_data_); @@ -330,7 +335,7 @@ void FackTcpAgent::send_much(int force, #endif } else { found = 1; - scb_.MarkRetran (xmit_seqno, t_seqno_); + scb_->MarkRetran (xmit_seqno, t_seqno_); retran_data_++; win = window(); } diff -Nuarp ns-2.1b9a.orig/tcp/tcp-fack.h ns-2.1b9a-hstcp/tcp/tcp-fack.h --- ns-2.1b9a.orig/tcp/tcp-fack.h Mon Feb 7 22:46:37 2000 +++ ns-2.1b9a-hstcp/tcp/tcp-fack.h Tue Jan 14 13:46:14 2003 @@ -50,6 +50,7 @@ class FackTcpAgent : public TcpAgent { public: FackTcpAgent(); + virtual ~FackTcpAgent(); virtual void recv(Packet *pkt, Handler*); virtual void timeout(int tno); virtual void opencwnd(); @@ -69,7 +70,10 @@ class FackTcpAgent : public TcpAgent { int fack_; int retran_data_; int ss_div4_; - ScoreBoard scb_; + + ScoreBoard* scb_; + static const int SBSIZE=1024; }; + #endif diff -Nuarp ns-2.1b9a.orig/tcp/tcp-sack1.cc ns-2.1b9a-hstcp/tcp/tcp-sack1.cc --- ns-2.1b9a.orig/tcp/tcp-sack1.cc Thu Nov 8 20:06:08 2001 +++ ns-2.1b9a-hstcp/tcp/tcp-sack1.cc Tue Jan 14 13:46:14 2003 @@ -17,6 +17,10 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +/* 8/02 Tom Kelly - Made scoreboard a general interface to allow + * easy swapping of scoreboard algorithms. + */ + #ifndef lint static const char rcsid[] = "@(#) $Header: /home/ctk21/cvsroot/toms-lce-website/code/ns-2.1b9a-hstcp.patch,v 1.2 2003/01/15 14:06:45 ctk21 Exp $ (PSC)"; @@ -30,6 +34,7 @@ static const char rcsid[] = #include "tcp.h" #include "flags.h" #include "scoreboard.h" +#include "scoreboard-rq.h" #include "random.h" #define TRUE 1 @@ -41,6 +46,7 @@ static const char rcsid[] = class Sack1TcpAgent : public TcpAgent { public: Sack1TcpAgent(); + virtual ~Sack1TcpAgent(); virtual void recv(Packet *pkt, Handler*); void reset(); virtual void timeout(int tno); @@ -51,24 +57,34 @@ class Sack1TcpAgent : public TcpAgent { u_char timeout_; /* boolean: sent pkt from timeout? */ u_char fastrecov_; /* boolean: doing fast recovery? */ int pipe_; /* estimate of pipe size (fast recovery) */ - ScoreBoard scb_; + ScoreBoard* scb_; + static const int SBSIZE=64; /* Initial scoreboard size */ }; static class Sack1TcpClass : public TclClass { public: Sack1TcpClass() : TclClass("Agent/TCP/Sack1") {} - TclObject* create(int, const char*const*) { + TclObject* create(int, const char*const*) { return (new Sack1TcpAgent()); } } class_sack; Sack1TcpAgent::Sack1TcpAgent() : fastrecov_(FALSE), pipe_(-1) { + /* Use the Reassembly Queue based scoreboard as + * ScoreBoard is O(cwnd) which is bad for HSTCP + * scb_ = new ScoreBoard(new ScoreBoardNode[SBSIZE],SBSIZE); + */ + scb_ = new ScoreBoardRQ(); +} + +Sack1TcpAgent::~Sack1TcpAgent(){ + delete scb_; } void Sack1TcpAgent::reset () { - scb_.ClearScoreBoard(); + scb_->ClearScoreBoard(); TcpAgent::reset (); } @@ -107,7 +123,7 @@ void Sack1TcpAgent::recv(Packet *pkt, Ha */ recv_newack_helper(pkt); timeout_ = FALSE; - scb_.ClearScoreBoard(); + scb_->ClearScoreBoard(); if (last_ack_ == 0 && delay_growth_) { cwnd_ = initial_window(); } @@ -119,13 +135,13 @@ void Sack1TcpAgent::recv(Packet *pkt, Ha tcph->seqno(), last_ack_); abort(); } - scb_.UpdateScoreBoard (highest_ack_, tcph); + scb_->UpdateScoreBoard (highest_ack_, tcph); /* * Check for a duplicate ACK. * Check that the SACK block actually * acknowledges new data. */ - if(scb_.CheckUpdate()) { + if(scb_->CheckUpdate()) { if (++dupacks_ == numdupacks_) { /* * Assume we dropped just one packet. @@ -134,7 +150,7 @@ void Sack1TcpAgent::recv(Packet *pkt, Ha */ dupack_action(); } else if (dupacks_ < numdupacks_ && singledup_ ) { - send_one(); + send_one(); } } } @@ -154,7 +170,7 @@ void Sack1TcpAgent::recv(Packet *pkt, Ha finish(); } timeout_ = FALSE; - scb_.ClearScoreBoard(); + scb_->ClearScoreBoard(); /* New window: W/2 - K or W/2? */ } else if ((int)tcph->seqno() > highest_ack_) { @@ -167,13 +183,13 @@ void Sack1TcpAgent::recv(Packet *pkt, Ha * was instead from the original packet, reordered, * then this might be too aggressive. */ highest_ack_ = (int)tcph->seqno(); - scb_.UpdateScoreBoard (highest_ack_, tcph); + scb_->UpdateScoreBoard (highest_ack_, tcph); t_backoff_ = 1; newtimer(pkt); } else if (timeout_ == FALSE) { /* got another dup ack */ - scb_.UpdateScoreBoard (highest_ack_, tcph); - if(scb_.CheckUpdate()) { + scb_->UpdateScoreBoard (highest_ack_, tcph); + if(scb_->CheckUpdate()) { if (dupacks_ > 0) dupacks_++; } @@ -219,7 +235,7 @@ Sack1TcpAgent::dupack_action() pipe_ = maxseq_ - highest_ack_ - numdupacks_; //pipe_ = int(cwnd_) - numdupacks_; fastrecov_ = TRUE; - scb_.MarkRetran(highest_ack_+1); + scb_->MarkRetran(highest_ack_+1); output(last_ack_ + 1, TCP_REASON_DUPACK); return; } @@ -247,7 +263,7 @@ sack_action: slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF); reset_rtx_timer(1,0); fastrecov_ = TRUE; - scb_.MarkRetran(highest_ack_+1); + scb_->MarkRetran(highest_ack_+1); output(last_ack_ + 1, TCP_REASON_DUPACK); // from top /* * If dynamically adjusting numdupacks_, record information @@ -272,11 +288,11 @@ void Sack1TcpAgent::timeout(int tno) if (highest_ack_ > last_ack_) last_ack_ = highest_ack_; #ifdef DEBUGSACK1A - printf ("timeout. highest_ack: %d seqno: %d\n", - highest_ack_, t_seqno_); + printf ("timeout. highest_ack: %i seqno: %i fid: %i\n", + (int)highest_ack_, (int)t_seqno_, fid_); #endif recover_ = maxseq_; - scb_.ClearScoreBoard(); + scb_->ClearScoreBoard(); } TcpAgent::timeout(tno); } @@ -299,11 +315,11 @@ void Sack1TcpAgent::send_much(int force, if (overhead_ == 0 || force) { found = 0; - xmit_seqno = scb_.GetNextRetran (); + xmit_seqno = scb_->GetNextRetran (); #ifdef DEBUGSACK1A printf("highest_ack: %d xmit_seqno: %d\n", - highest_ack_, xmit_seqno); + (int)highest_ack_, xmit_seqno); #endif if (xmit_seqno == -1) { if ((!fastrecov_ && t_seqno_<=highest_ack_+win)|| @@ -317,7 +333,7 @@ void Sack1TcpAgent::send_much(int force, } } else if (recover_>0 && xmit_seqno<=highest_ack_+int(wnd_)) { found = 1; - scb_.MarkRetran (xmit_seqno); + scb_->MarkRetran (xmit_seqno); win = window(); } if (found) { diff -Nuarp ns-2.1b9a.orig/tcp/tcp-sink.cc ns-2.1b9a-hstcp/tcp/tcp-sink.cc --- ns-2.1b9a.orig/tcp/tcp-sink.cc Sun Dec 30 05:54:39 2001 +++ ns-2.1b9a-hstcp/tcp/tcp-sink.cc Tue Jan 14 13:46:14 2003 @@ -37,6 +37,8 @@ static const char rcsid[] = "@(#) $Header: /home/ctk21/cvsroot/toms-lce-website/code/ns-2.1b9a-hstcp.patch,v 1.2 2003/01/15 14:06:45 ctk21 Exp $ (LBL)"; #endif +/* 8/02 Tom Kelly - Dynamic resizing of seen buffer */ + #include "flags.h" #include "ip.h" #include "tcp-sink.h" @@ -52,9 +54,7 @@ public: Acker::Acker() : next_(0), maxseen_(0), wndmask_(MWM), ecn_unacked_(0), ts_to_echo_(0) { - seen_ = new int[MWS]; // changed by Brad/Sylvia - // used dynamic alloc to eliminate fhuge-objects pb - // when compiling with really large MWS + seen_ = new int[MWS]; memset(seen_, 0, (sizeof(int) * (MWS))); } @@ -65,12 +65,26 @@ void Acker::reset() memset(seen_, 0, (sizeof(int) * (wndmask_ + 1))); } -/* resize Acker's buffers for highspeed -- Sylvia */ -void Acker::resize_buffers() { - wndmask_ = HS_MWM; +// dynamically increase the seen buffer as needed +// size must be a factor of two for the wndmask_ to work... +void Acker::resize_buffers(int sz) { + int* new_seen = new int[sz]; + int new_wndmask = sz - 1; + + if(!new_seen){ + fprintf(stderr, "Unable to allocate buffer seen_[%i]\n", sz); + exit(1); + } + + memset(new_seen, 0, (sizeof(int) * (sz))); + + for(int i = next_; i <= maxseen_+1; i++){ + new_seen[i & new_wndmask] = seen_[i&wndmask_]; + } + delete[] seen_; - seen_ = new int[HS_MWS]; - memset(seen_, 0, (sizeof(int) * (HS_MWS))); + seen_ = new_seen; + wndmask_ = new_wndmask; return; } @@ -90,12 +104,12 @@ int Acker::update(int seq, int numBytes) if (numBytes <= 0) printf("Error, received TCP packet size <= 0\n"); int numToDeliver = 0; - if (seq - next_ >= wndmask_) { + while(seq + 1 - next_ >= wndmask_) { // next_ is next packet expected; wndmask_ is the maximum // window size minus 1; if somehow the seqno of the // packet is greater than the one we're expecting+wndmask_, - // then ignore it. - return 0; + // then resize the buffer. + resize_buffers((wndmask_+1)*2); } if (seq > maxseen_) { @@ -219,7 +233,8 @@ int TcpSink::command(int argc, const cha return (TCL_OK); } if (strcmp(argv[1], "resize_buffers") == 0) { - resize_buffers(); + // no need for this as seen buffer set dynamically + fprintf(stderr,"DEPRECIATED: resize_buffers\n"); return (TCL_OK); } } @@ -300,11 +315,6 @@ void TcpSink::add_to_ack(Packet*) return; } -/* resize Acker's buffers for highspeed -- Sylvia */ -void TcpSink::resize_buffers() { - acker_->resize_buffers(); - return; -} void TcpSink::recv(Packet* pkt, Handler*) { @@ -630,6 +640,8 @@ void Sacker::append_ack(hdr_cmn* ch, hdr } h->sa_left(sack_index) = sack_left; h->sa_right(sack_index) = sack_right; + + // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %i\n" ,old_seqno, seqno, sack_index, sack_left, sack_right); // record the block sack_index++; } @@ -662,12 +674,15 @@ void Sacker::append_ack(hdr_cmn* ch, hdr h->sa_left(sack_index) = sack_left; h->sa_right(sack_index) = sack_right; + + // printf("pkt_seqno: %i cuml_seqno: %i sa_idx: %i sa_left: %i sa_right: %i\n" ,old_seqno, seqno, sack_index, sack_left, sack_right); + // store the old sack (i.e. move it down one) sack_index++; k++; - } + if (old_seqno > seqno) { /* put most recent block onto stack */ sf_->push(); diff -Nuarp ns-2.1b9a.orig/tcp/tcp-sink.h ns-2.1b9a-hstcp/tcp/tcp-sink.h --- ns-2.1b9a.orig/tcp/tcp-sink.h Sun Dec 30 05:54:39 2001 +++ ns-2.1b9a-hstcp/tcp/tcp-sink.h Tue Jan 14 13:46:14 2003 @@ -37,15 +37,12 @@ #ifndef ns_tcpsink_h #define ns_tcpsink_h -#include #include "agent.h" #include "tcp.h" /* max window size */ -#define MWS 1024 +#define MWS 64 #define MWM (MWS-1) -#define HS_MWS 65536 -#define HS_MWM (MWS-1) /* For Tahoe TCP, the "window" parameter, representing the receiver's * advertised window, should be less than MWM. For Reno TCP, the * "window" parameter should be less than MWM/2. @@ -65,12 +62,13 @@ public: double ts_to_echo() { return ts_to_echo_;} int ecn_unacked() { return ecn_unacked_;} inline int Maxseen() const { return (maxseen_); } - void resize_buffers(); // grow Acker's arrays for large window sizes -- Sylvia + void resize_buffers(int sz); // resize the seen_ buffer protected: + int next_; /* next packet expected */ int maxseen_; /* max packet number seen */ - int wndmask_; /* window mask - either MWM or HS_MWM - Sylvia */ + int wndmask_; /* dynamic window mask - a multiple of 2 */ int ecn_unacked_; /* ECN forwarded to sender, but not yet * acknowledged. */ int *seen_; /* array of packets seen */ @@ -103,7 +101,7 @@ public: TracedInt& maxsackblocks() { return max_sack_blocks_; } protected: void ack(Packet*); - void resize_buffers(); // grow Acker's arrays for large window sizes -- Sylvia + virtual void add_to_ack(Packet* pkt); virtual void delay_bind_init_all();