$Id: ns-233-freezetcp.patch 252 2008-05-27 01:37:40Z omehani $
Freeze-TCP patch for ns-2.33 based on the initial FreezeTCP ns-2.1b9a
implemetation by Adeel Baig <abaig@cse.unsw.edu.au> et al.

Notable changes:
 - fixed the weird behavior mentionned in the ns-2.1b9a patch (sender still
   sending after ZWA has been received);
 - removed the loss monitoring overhead in TcpSink (this patch _only_ adds
   Freeze-TCP support);
 - removed some discreetly unused variables;
 - FreezeTcpAgent now inherits from RenoTcpAgent to reduce code redundancy.

Olivier Mehani <olivier.mehani@nicta.com.au>
====
diff -urNU5 ns-2.33-orig/common/packet.h ns-2.33-freezetcp/common/packet.h
--- ns-2.33-orig/common/packet.h	2008-05-09 16:10:50.000000000 +1000
+++ ns-2.33-freezetcp/common/packet.h	2008-05-09 17:14:02.000000000 +1000
@@ -177,12 +177,16 @@
 static const packet_t PT_HDLC = 59;
 
         // Bell Labs Traffic Trace Type (PackMime OL)
 static const packet_t PT_BLTRACE = 60;
 
+	// Freeze-TCP
+static const packet_t PT_ZWA = 61;
+static const packet_t PT_NZWA = 62;
+
         // insert new packet types here
-static packet_t       PT_NTYPE = 61; // This MUST be the LAST one
+static packet_t       PT_NTYPE = 63; // This MUST be the LAST one
 
 enum packetClass
 {
 	UNCLASSIFIED,
 	ROUTING,
@@ -355,10 +359,14 @@
 
 #ifdef HAVE_STL
 		// for PGM
 		name_[PT_PGM] = "PGM";
 #endif //STL
+ 
+ 		// for Freeze-TCP
+ 		name_[PT_ZWA] = "ZWA";
+ 		name_[PT_NZWA] = "NZWA";
 
 		// LMS entries
 		name_[PT_LMS]="LMS";
 		name_[PT_LMS_SETUP]="LMS_SETUP";
 
diff -urNU5 ns-2.33-orig/Makefile.in ns-2.33-freezetcp/Makefile.in
--- ns-2.33-orig/Makefile.in	2008-05-09 16:10:50.000000000 +1000
+++ ns-2.33-freezetcp/Makefile.in	2008-05-09 17:22:29.000000000 +1000
@@ -189,10 +189,11 @@
 	common/ivs.o \
 	common/messpass.o common/tp.o common/tpm.o apps/worm.o \
 	tcp/tcp.o tcp/tcp-sink.o tcp/tcp-reno.o \
 	tcp/tcp-newreno.o \
 	tcp/tcp-vegas.o tcp/tcp-rbp.o tcp/tcp-full.o tcp/rq.o \
+	tcp/freeze-tcp.o \
 	baytcp/tcp-full-bay.o baytcp/ftpc.o baytcp/ftps.o \
 	tcp/scoreboard.o tcp/scoreboard-rq.o tcp/tcp-sack1.o tcp/tcp-fack.o \
 	tcp/linux/tcp_naivereno.o\
 	tcp/linux/src/tcp_cong.o\
 	tcp/linux/src/tcp_highspeed.o tcp/linux/src/tcp_bic.o tcp/linux/src/tcp_htcp.o tcp/linux/src/tcp_scalable.o tcp/linux/src/tcp_cubic.o\
diff -urNU5 ns-2.33-orig/tcl/freeze-tcp/exponential.pl ns-2.33-freezetcp/tcl/freeze-tcp/exponential.pl
--- ns-2.33-orig/tcl/freeze-tcp/exponential.pl	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-freezetcp/tcl/freeze-tcp/exponential.pl	2008-05-12 15:05:39.000000000 +1000
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+
+# Set the default parameter values
+$uptime = 1.0;
+$downtime = 1.0;
+$finish = 50000;
+$pred = 0.0;
+$ZWA_ahead = 1.50455;
+$NZWA_after = 0.0001;
+$seed = (time ^ $$ or time ^ ($$ + ($$ << 15)));
+# Note: default for $link_file and $predictor_file set below
+
+# Get the numerical command-line parameters
+(grep {($uptime=$1,1) if /^uptime=(.*)/i} @ARGV) or &warn("uptime", $uptime);
+(grep {($downtime=$1,1) if /^downtime=(.*)/i} @ARGV) or &warn("downtime", $downtime);
+(grep {($finish=$1,1) if /^finish=(.*)/i} @ARGV) or &warn("finish", $finish);
+(grep {($pred=$1,1) if /^pred=(.*)/i} @ARGV) or &warn("pred", $pred);
+(grep {($ZWA_ahead=$1,1) if /^ZWA_ahead=(.*)/i} @ARGV) or &warn("ZWA_ahead", $ZWA_ahead);
+(grep {($NZWA_after=$1,1) if /^NZWA_after=(.*)/i} @ARGV) or &warn("NZWA_after", $NZWA_after);
+(grep {($seed=$1,1) if /^seed=(.*)/i} @ARGV) or &warn("seed", $seed);
+
+# Create output file names (or get them from command line) and open them
+$link_file = "link_".$uptime."_".$downtime."_".$pred;
+$predictor_file = "predict_".$uptime."_".$downtime."_".$pred;
+(grep {($link_file=$1,1) if /^link_file=(.*)/i} @ARGV) or &warn("link_file", $link_file =~ /^-$/ ? "standard output" : $link_file); $link_file =~ s/^['"](.*)['"]$/$1/;
+(grep {($predictor_file=$1,1) if /^predictor_file=(.*)/i} @ARGV) or &warn("predictor_file", $predictor_file =~ /^-$/ ? "standard output" : $predictor_file); $predictor_file =~ s/^['"](.*)['"]$/$1/;
+open LINK,">$link_file" or die("Cannot open link file\n");
+open PREDICTOR,">$predictor_file" or die("Cannot open predictor file\n");
+print LINK "# This file was generated with seed=$seed, uptime=$uptime, downtime=$downtime\n";
+print PREDICTOR "# This file was generated with seed=$seed, uptime=$uptime, downtime=$downtime, pred=$pred, ZWA_ahead=$ZWA_ahead, NZWA_after=$NZWA_after\n";
+
+# Do some initializations
+srand($seed);
+$time = 0;
+$state = 1; # link is up initially
+$last_up = $time;
+
+# Main loop
+while (1) {
+	last if (($time += &exp_rand($state ? $uptime : $downtime)) > $finish);
+	if ($state) {
+		print LINK "\$ns_ rtmodel-at $time down \$n0_ \$n1_\n";
+
+		# If the link was up for a sufficient time (at least NZWA_after),
+		# complete the notification that it came up
+		$predictor_string1 = $predictor_string2 = "";
+
+		if ($last_up > 0 && $time >= $last_up+$NZWA_after) {
+			$predictor_string1 = "\$ns_ at ".(($last_up+$NZWA_after)." \"\$sink_ unfreeze\"\n#Link going UP\n");
+		}
+
+		# Notify the link going down only if it has been up for
+		# a sufficient time (at least ZWA_ahead)
+		# Note: because of short-circuit boolean evaluation,
+		# rand() has to be called first in the following condition
+		# to make the random sequence reproducible (for a given seed)
+		# regardless of the value of ZWA_ahead
+		if (rand() < $pred && $time >= $last_up+$ZWA_ahead) {
+			$predictor_string2 = "\$ns_ at ".(($time-$ZWA_ahead)." \"\$sink_ freeze\"\n#Link going DOWN\n");
+		}
+
+		# Output the strings in the correct order
+		if ($last_up+$NZWA_after <= $time-$ZWA_ahead) {
+			print PREDICTOR $predictor_string1.$predictor_string2;
+		}
+		else {
+			print PREDICTOR $predictor_string2.$predictor_string1;
+		}
+	}
+	else {
+		printf LINK "\$ns_ rtmodel-at $time up \$n0_ \$n1_\n";
+		# Note: we do not notify the link going up here, as it may
+		# go down again before NZWA_after elapses. The notification
+		# is completed in the next 'going down' event.
+		$last_up = $time;
+	}
+	$state = !$state;
+}
+
+# Clean up
+close PREDICTOR;
+close LINK;
+
+# Warning subroutine
+sub warn {
+	my ($param,$value) = @_;
+	print STDERR "Warning: $param not specified, defaulting to $value\n" unless grep {/^-q$/i} @ARGV;
+}
+
+# Subroutine for generating random exponential value
+sub exp_rand {
+	my $mu = shift;
+	return -$mu*log(1-rand);
+}
diff -urNU5 ns-2.33-orig/tcl/freeze-tcp/samplelink.tcl ns-2.33-freezetcp/tcl/freeze-tcp/samplelink.tcl
--- ns-2.33-orig/tcl/freeze-tcp/samplelink.tcl	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-freezetcp/tcl/freeze-tcp/samplelink.tcl	2008-05-09 17:05:39.000000000 +1000
@@ -0,0 +1,17 @@
+# This file was generated with seed=1070857529, uptime=150, downtime=30
+$ns_ rtmodel-at 169.031128180058 down $n0_ $n1_
+$ns_ rtmodel-at 189.979278303447 up $n0_ $n1_
+$ns_ rtmodel-at 428.156895213858 down $n0_ $n1_
+$ns_ rtmodel-at 456.597868340819 up $n0_ $n1_
+$ns_ rtmodel-at 583.93079620231 down $n0_ $n1_
+$ns_ rtmodel-at 588.961634814243 up $n0_ $n1_
+$ns_ rtmodel-at 862.842912539964 down $n0_ $n1_
+$ns_ rtmodel-at 896.396348802862 up $n0_ $n1_
+$ns_ rtmodel-at 928.151570089597 down $n0_ $n1_
+$ns_ rtmodel-at 951.326004468653 up $n0_ $n1_
+$ns_ rtmodel-at 1162.80369926841 down $n0_ $n1_
+$ns_ rtmodel-at 1214.63871804316 up $n0_ $n1_
+$ns_ rtmodel-at 1314.36455775416 down $n0_ $n1_
+$ns_ rtmodel-at 1378.71074273608 up $n0_ $n1_
+$ns_ rtmodel-at 1461.48346111635 down $n0_ $n1_
+$ns_ rtmodel-at 1496.76812599506 up $n0_ $n1_
diff -urNU5 ns-2.33-orig/tcl/freeze-tcp/samplepredict.tcl ns-2.33-freezetcp/tcl/freeze-tcp/samplepredict.tcl
--- ns-2.33-orig/tcl/freeze-tcp/samplepredict.tcl	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-freezetcp/tcl/freeze-tcp/samplepredict.tcl	2008-05-09 17:05:39.000000000 +1000
@@ -0,0 +1,33 @@
+# This file was generated with seed=1070857529, uptime=150, downtime=30, pred=1, ZWA_ahead=1.50455, NZWA_after=0.0001
+$ns_ at 167.526578180058 "$sink_ freeze"
+#Link going DOWN
+$ns_ at 189.979378303447 "$sink_ unfreeze"
+#Link going UP
+$ns_ at 426.652345213858 "$sink_ freeze"
+#Link going DOWN
+$ns_ at 456.597968340819 "$sink_ unfreeze"
+#Link going UP
+$ns_ at 582.42624620231 "$sink_ freeze"
+#Link going DOWN
+$ns_ at 588.961734814243 "$sink_ unfreeze"
+#Link going UP
+$ns_ at 861.338362539964 "$sink_ freeze"
+#Link going DOWN
+$ns_ at 896.396448802862 "$sink_ unfreeze"
+#Link going UP
+$ns_ at 926.647020089597 "$sink_ freeze"
+#Link going DOWN
+$ns_ at 951.326104468653 "$sink_ unfreeze"
+#Link going UP
+$ns_ at 1161.29914926841 "$sink_ freeze"
+#Link going DOWN
+$ns_ at 1214.63881804316 "$sink_ unfreeze"
+#Link going UP
+$ns_ at 1312.86000775416 "$sink_ freeze"
+#Link going DOWN
+$ns_ at 1378.71084273608 "$sink_ unfreeze"
+#Link going UP
+$ns_ at 1459.97891111635 "$sink_ freeze"
+#Link going DOWN
+$ns_ at 1496.76822599506 "$sink_ unfreeze"
+#Link going UP
diff -urNU5 ns-2.33-orig/tcl/freeze-tcp/tcpvsfreeze.tcl ns-2.33-freezetcp/tcl/freeze-tcp/tcpvsfreeze.tcl
--- ns-2.33-orig/tcl/freeze-tcp/tcpvsfreeze.tcl	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-freezetcp/tcl/freeze-tcp/tcpvsfreeze.tcl	2008-05-12 17:23:11.000000000 +1000
@@ -0,0 +1,43 @@
+# Simple TCP vs. Freeze-TCP (with disconnections) NS-2 script
+# Olivier Mehani <olivier.mehani@nicta.com.au>
+set ns_ [new Simulator]
+
+set tracefile_ [open out.tr w]
+$ns_ trace-all $tracefile_
+
+set n0_ [$ns_ node]
+set n1_ [$ns_ node]
+$ns_ duplex-link $n0_ $n1_ 100Mb 2ms DropTail
+
+set sink_ [new Agent/TCPSink]
+if { $argc == 1 && [lindex $argv 0] == "freeze" } {
+	puts "Using Freeze-TCP..."
+	set tcp_ [new Agent/TCP/Freeze]
+	source samplepredict.tcl
+} else {
+	puts "Using regular TCP (Reno)..."
+	set tcp_ [new Agent/TCP]
+}
+
+$ns_ attach-agent $n0_ $tcp_
+$ns_ attach-agent $n1_ $sink_
+
+source samplelink.tcl
+
+set ftp_ [new Application/FTP] 
+$ftp_ attach-agent $tcp_
+
+$sink_ listen
+$ns_ connect $tcp_ $sink_
+$ns_ at 0.1 "$ftp_ start"
+
+proc finish {} {
+	global ns_ tracefile_
+	$ns_ flush-trace
+	close $tracefile_
+	
+	exit 0
+}
+$ns_ at 200. "finish"
+
+$ns_ run
diff -urNU5 ns-2.33-orig/tcp/freeze-tcp.cc ns-2.33-freezetcp/tcp/freeze-tcp.cc
--- ns-2.33-orig/tcp/freeze-tcp.cc	1970-01-01 10:00:00.000000000 +1000
+++ ns-2.33-freezetcp/tcp/freeze-tcp.cc	2008-05-12 17:26:04.000000000 +1000
@@ -0,0 +1,87 @@
+/* -*-	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.
+ */
+
+/*
+ * NS-2.1b9 support for Freeze-TCP
+ *
+ * This code was adapted by Adeel Baig at the School of Computer Science and
+ * Engineering of the University of New South Wales
+ *
+ * Ported to ns-2.33 by Olivier Mehani <olivier.mehani@nicta.com.au>
+ */
+
+#ifndef lint
+static const char rcsid[] =
+    "@(#) $Header: /cvsroot/nsnam/ns-2/tcp/tcp-reno.cc,v 1.43 2006/06/14 18:05:30 sallyfloyd Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "ip.h"
+#include "tcp.h"
+#include "flags.h"
+
+
+static class FreezeTcpClass : public TclClass {
+public:
+	FreezeTcpClass() : TclClass("Agent/TCP/Freeze") {}
+	TclObject* create(int, const char*const*) {
+		return (new FreezeTcpAgent());
+	}
+} class_freeze;
+
+FreezeTcpAgent::FreezeTcpAgent() : RenoTcpAgent()
+{
+}
+
+void FreezeTcpAgent::recv(Packet *pkt, Handler *hnd)
+{
+	hdr_cmn * ahdr = hdr_cmn::access(pkt) ;
+	double anow = Scheduler::instance().clock();
+	
+	if( ahdr->ptype() == PT_ZWA )
+	{
+		printf("Freeze-TCP: source received ZWA at %f\n", anow ) ;
+
+		prev_ssthresh_ = ssthresh_;
+		prev_cwnd_ = cwnd_;
+		prev_wnd_ = wnd_;
+
+		ssthresh_ = 1;
+		cwnd_ = 0;
+		wnd_ = 0;
+
+		set_rtx_timer();
+	}
+
+	if( ahdr->ptype() == PT_NZWA )
+	{
+		printf("Freeze-TCP: source received N-ZWA at %f\n", anow ) ;
+
+		wnd_ = prev_wnd_;
+		cwnd_ = prev_cwnd_;
+		ssthresh_ = prev_ssthresh_;
+
+		set_rtx_timer( );
+	}
+
+	RenoTcpAgent::recv(pkt, hnd);
+}
diff -urNU5 ns-2.33-orig/tcp/tcp.h ns-2.33-freezetcp/tcp/tcp.h
--- ns-2.33-orig/tcp/tcp.h	2008-05-09 16:10:50.000000000 +1000
+++ ns-2.33-freezetcp/tcp/tcp.h	2008-05-12 17:20:13.000000000 +1000
@@ -545,10 +545,21 @@
  protected:
 	int allow_fast_retransmit(int last_cwnd_action_);
 	unsigned int dupwnd_;
 };
 
+/* Freeze-TCP */
+class FreezeTcpAgent : public virtual RenoTcpAgent {
+ public:
+	FreezeTcpAgent();
+	virtual void recv(Packet *pkt, Handler*);
+ protected:
+	int prev_ssthresh_;
+	int prev_cwnd_;
+	double prev_wnd_;
+};
+
 /* TCP New Reno */
 class NewRenoTcpAgent : public virtual RenoTcpAgent {
  public:
 	NewRenoTcpAgent();
 	virtual void recv(Packet *pkt, Handler*);
diff -urNU5 ns-2.33-orig/tcp/tcp-sink.cc ns-2.33-freezetcp/tcp/tcp-sink.cc
--- ns-2.33-orig/tcp/tcp-sink.cc	2008-05-09 16:10:50.000000000 +1000
+++ ns-2.33-freezetcp/tcp/tcp-sink.cc	2008-05-12 15:54:18.000000000 +1000
@@ -31,10 +31,19 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
  
 /* 8/02 Tom Kelly - Dynamic resizing of seen buffer */
+  
+/*
+ * NS-2.1b9 support for Freeze-TCP
+ *
+ * This code was first adapted by Adeel Baig at the School of Computer
+ * Science and Engineering of the University of New South Wales
+ *
+ * Ported to ns-2.33 by Olivier Mehani <olivier.mehani@nicta.com.au>
+ */
 
 #include "flags.h"
 #include "ip.h"
 #include "tcp-sink.h"
 #include "hdr_qs.h"
@@ -180,10 +189,14 @@
 	lastreset_(0.0)
 {
 	bytes_ = 0; 
 	bind("bytes_", &bytes_);
 
+	power_ = 1;
+	do_freeze = 0;
+	do_unfreeze = 0;
+
 	/*
 	 * maxSackBlocks_ does wierd tracing things.
 	 * don't make it delay-bound yet.
 	 */
 #if defined(TCP_DELAY_BIND_ALL) && 0
@@ -246,10 +259,22 @@
 		if (strcmp(argv[1], "resize_buffers") == 0) {
 			// no need for this as seen buffer set dynamically
 			fprintf(stderr,"DEPRECIATED: resize_buffers\n");
 			return (TCL_OK);
 		}
+ 		if (strcmp(argv[1], "freeze") == 0) {
+ 			power_ = 0;
+ 			do_freeze = 1;
+ 			predict_discon();
+ 			return (TCL_OK);
+ 		}
+ 		if (strcmp(argv[1], "unfreeze") == 0) {
+ 			power_ = 1;
+ 			do_unfreeze = 1;
+ 			predict_con();
+ 			return (TCL_OK);
+ 		}
 	}
 
 	return (Agent::command(argc, argv));
 }
 
@@ -748,5 +773,60 @@
 	// set the Length of the sack stack in the header
 	ch->size() += sack_index * 8;
 	// change the size of the common header to account for the
 	// Sack strings (2 4-byte words for each element)
 }
+
+void 
+TcpSink::predict_con()
+{
+	if (power_ == 1 && do_unfreeze == 1)
+	{ 
+		Packet* npkt1 = allocpkt();
+
+		double now = Scheduler::instance().clock();
+		hdr_tcp *ntcp1 = hdr_tcp::access(npkt1);
+
+		ntcp1->seqno() = acker_->Seqno();
+		// get the cumulative sequence number to put in the ACK; this
+		// is just the left edge of the receive window - 1
+		ntcp1->ts() = now;
+
+		hdr_cmn * ahdr = HDR_CMN(npkt1) ;
+
+		ahdr->ptype() = PT_NZWA ;
+
+		send(npkt1, 0);
+
+		printf("Freeze-TCP: sink sending N-ZWA at %f\n", now ); 
+
+		do_unfreeze = 0;
+	}
+}
+
+
+void 
+TcpSink::predict_discon()
+{
+	if (power_ == 0 && do_freeze == 1)
+	{ 
+		Packet* npkt1 = allocpkt();
+
+		double now = Scheduler::instance().clock();
+
+		hdr_tcp *ntcp1 = hdr_tcp::access(npkt1);
+
+		ntcp1->seqno() = acker_->Seqno();
+		// get the cumulative sequence number to put in the ACK; this
+		// is just the left edge of the receive window - 1
+		ntcp1->ts() = now;
+
+		hdr_cmn * ahdr = HDR_CMN(npkt1) ;
+
+		ahdr->ptype() = PT_ZWA ;
+
+		send( npkt1 , 0 );
+		printf("Freeze-TCP: sink sending ZWA at %f\n", now );
+
+		do_freeze  = 0;
+	}
+}
diff -urNU5 ns-2.33-orig/tcp/tcp-sink.h ns-2.33-freezetcp/tcp/tcp-sink.h
--- ns-2.33-orig/tcp/tcp-sink.h	2008-05-09 16:10:50.000000000 +1000
+++ ns-2.33-freezetcp/tcp/tcp-sink.h	2008-05-12 15:54:51.000000000 +1000
@@ -103,10 +102,14 @@
 	void recv(Packet* pkt, Handler*);
 	void reset();
 	int command(int argc, const char*const* argv);
 	TracedInt& maxsackblocks() { return max_sack_blocks_; }
 protected:
+	// Freeze-TCP methods
+ 	void predict_con();
+ 	void predict_discon();
+
 	void ack(Packet*);
 	virtual void add_to_ack(Packet* pkt);
 
         virtual void delay_bind_init_all();
         virtual int delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer);
@@ -127,10 +130,14 @@
 					// for RFC2581-compliant gap-filling.
 	double lastreset_; 	/* W.N. used for detecting packets  */
 				/* from previous incarnations */
         int ecn_syn_;           /* allow SYN/ACK packets to be ECN-capable */
 
+	/* additions for Freeze-TCP */
+	int power_;
+	int do_freeze;
+	int do_unfreeze;
 };
 
 class DelAckSink;
 
 class DelayTimer : public TimerHandler {
