Westwood and Westwood+
authorAnh Nguyen annguyen@ittc.ku.edu
Thu, 18 Apr 2013 15:57:07 -0400
changeset 9696 4b977376f383
parent 9695 e62d00344369
child 9697 1c8203172c9d
Westwood and Westwood+
examples/tcp/examples-to-run.py
examples/tcp/tcp-variants-comparison.cc
examples/tcp/wscript
src/internet/model/tcp-westwood.cc
src/internet/model/tcp-westwood.h
src/internet/wscript
src/test/ns3tcp/ns3tcp-loss-test-suite.cc
--- a/examples/tcp/examples-to-run.py	Thu Apr 18 21:14:10 2013 +0200
+++ b/examples/tcp/examples-to-run.py	Thu Apr 18 15:57:07 2013 -0400
@@ -13,6 +13,7 @@
     ("tcp-nsc-lfn", "NSC_ENABLED == True", "False"),
     ("tcp-nsc-zoo", "NSC_ENABLED == True", "False"),
     ("tcp-star-server", "True", "True"),
+    ("tcp-variants-comparison", "True", "True"),
 ]
 
 # A list of Python examples to run in order to ensure that they remain
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/tcp/tcp-variants-comparison.cc	Thu Apr 18 15:57:07 2013 -0400
@@ -0,0 +1,360 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 ResiliNets, ITTC, University of Kansas 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Justin P. Rohrer, Truc Anh N. Nguyen <annguyen@ittc.ku.edu>, Siddharth Gangadhar <siddharth@ittc.ku.edu>
+ *
+ * James P.G. Sterbenz <jpgs@ittc.ku.edu>, director
+ * ResiliNets Research Group  http://wiki.ittc.ku.edu/resilinets
+ * Information and Telecommunication Technology Center (ITTC)
+ * and Department of Electrical Engineering and Computer Science
+ * The University of Kansas Lawrence, KS USA.
+ *
+ * Work supported in part by NSF FIND (Future Internet Design) Program
+ * under grant CNS-0626918 (Postmodern Internet Architecture),
+ * NSF grant CNS-1050226 (Multilayer Network Resilience Analysis and Experimentation on GENI),
+ * US Department of Defense (DoD), and ITTC at The University of Kansas.
+ *
+ * “TCP Westwood(+) Protocol Implementation in ns-3”
+ * Siddharth Gangadhar, Trúc Anh Ngọc Nguyễn , Greeshma Umapathi, and James P.G. Sterbenz,
+ * ICST SIMUTools Workshop on ns-3 (WNS3), Cannes, France, March 2013
+ */
+
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/point-to-point-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/error-model.h"
+#include "ns3/tcp-header.h"
+#include "ns3/udp-header.h"
+#include "ns3/enum.h"
+#include "ns3/event-id.h"
+#include "ns3/flow-monitor-helper.h"
+#include "ns3/ipv4-global-routing-helper.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("TcpVariantsComparison");
+
+double old_time = 0.0;
+EventId output;
+Time current = Time::FromInteger(3, Time::S);  //Only record cwnd and ssthresh values every 3 seconds
+bool first = true;
+
+static void
+OutputTrace ()
+{
+ // *stream->GetStream() << newtime << " " << newval << std::endl;
+ // old_time = newval;
+}
+
+static void
+CwndTracer (Ptr<OutputStreamWrapper>stream, uint32_t oldval, uint32_t newval)
+{
+  double new_time = Simulator::Now().GetSeconds();
+  if (old_time == 0 && first)
+  {
+    double mycurrent = current.GetSeconds();
+    *stream->GetStream() << new_time << " " << mycurrent << " " << newval << std::endl;
+    first = false;
+    output = Simulator::Schedule(current,&OutputTrace);
+  }
+  else
+  {
+    if (output.IsExpired())
+    {
+      *stream->GetStream() << new_time << " " << newval << std::endl;
+      output.Cancel();
+      output = Simulator::Schedule(current,&OutputTrace);
+    }
+  }
+}
+
+static void
+SsThreshTracer (Ptr<OutputStreamWrapper>stream, uint32_t oldval, uint32_t newval)
+{
+  double new_time = Simulator::Now().GetSeconds();
+  if (old_time == 0 && first)
+  {
+    double mycurrent = current.GetSeconds();
+    *stream->GetStream() << new_time << " " << mycurrent << " " << newval << std::endl;
+    first = false;
+    output = Simulator::Schedule(current,&OutputTrace);
+  }
+  else
+  {
+    if (output.IsExpired())
+    {
+      *stream->GetStream() << new_time << " " << newval << std::endl;
+      output.Cancel();
+      output = Simulator::Schedule(current,&OutputTrace);
+    }
+  }
+}
+
+static void
+TraceCwnd (std::string cwnd_tr_file_name)
+{
+  AsciiTraceHelper ascii;
+  if (cwnd_tr_file_name.compare("") == 0)
+     {
+       NS_LOG_DEBUG ("No trace file for cwnd provided");
+       return;
+     }
+  else
+    {
+      Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream(cwnd_tr_file_name.c_str());
+      Config::ConnectWithoutContext ("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",MakeBoundCallback (&CwndTracer, stream));
+    }
+}
+
+static void
+TraceSsThresh(std::string ssthresh_tr_file_name)
+{
+  AsciiTraceHelper ascii;
+  if (ssthresh_tr_file_name.compare("") == 0)
+    {
+      NS_LOG_DEBUG ("No trace file for ssthresh provided");
+      return;
+    }
+  else
+    {
+      Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream(ssthresh_tr_file_name.c_str());
+      Config::ConnectWithoutContext ("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/SlowStartThreshold",MakeBoundCallback (&SsThreshTracer, stream));
+    }
+}
+
+int main (int argc, char *argv[])
+{
+  std::string transport_prot = "TcpWestwood";
+  double error_p = 0.0;
+  std::string bandwidth = "2Mbps";
+  std::string access_bandwidth = "10Mbps";
+  std::string access_delay = "45ms";
+  bool tracing = false;
+  std::string tr_file_name = "";
+  std::string cwnd_tr_file_name = "";
+  std::string ssthresh_tr_file_name = "";
+  double data_mbytes = 0;
+  uint32_t mtu_bytes = 400;
+  uint16_t num_flows = 1;
+  float duration = 100;
+  uint32_t run = 0;
+  bool flow_monitor = true;
+
+
+  CommandLine cmd;
+  cmd.AddValue("transport_prot", "Transport protocol to use: TcpTahoe, TcpReno, TcpNewReno, TcpWestwood, TcpWestwoodPlus ", transport_prot);
+  cmd.AddValue("error_p", "Packet error rate", error_p);
+  cmd.AddValue("bandwidth", "Bottleneck bandwidth", bandwidth);
+  cmd.AddValue("access_bandwidth", "Access link bandwidth", access_bandwidth);
+  cmd.AddValue("delay", "Access link delay", access_delay);
+  cmd.AddValue("tracing", "Flag to enable/disable tracing", tracing);
+  cmd.AddValue("tr_name", "Name of output trace file", tr_file_name);
+  cmd.AddValue("cwnd_tr_name", "Name of output trace file", cwnd_tr_file_name);
+  cmd.AddValue("ssthresh_tr_name", "Name of output trace file", ssthresh_tr_file_name);
+  cmd.AddValue("data", "Number of Megabytes of data to transmit", data_mbytes);
+  cmd.AddValue("mtu", "Size of IP packets to send in bytes", mtu_bytes);
+  cmd.AddValue("num_flows", "Number of flows", num_flows);
+  cmd.AddValue("duration", "Time to allow flows to run in seconds", duration);
+  cmd.AddValue("run", "Run index (for setting repeatable seeds)", run);
+  cmd.AddValue("flow_monitor", "Enable flow monitor", flow_monitor);
+  cmd.Parse (argc, argv);
+
+  SeedManager::SetSeed(1);
+  SeedManager::SetRun(run);
+
+  // User may find it convenient to enable logging
+  //LogComponentEnable("TcpVariantsComparison", LOG_LEVEL_ALL);
+  //LogComponentEnable("BulkSendApplication", LOG_LEVEL_INFO);
+  //LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
+
+  // Calculate the ADU size
+  Header* temp_header = new Ipv4Header();
+  uint32_t ip_header = temp_header->GetSerializedSize();
+  NS_LOG_LOGIC ("IP Header size is: " << ip_header);
+  delete temp_header;
+  temp_header = new TcpHeader();
+  uint32_t tcp_header = temp_header->GetSerializedSize();
+  NS_LOG_LOGIC ("TCP Header size is: " << tcp_header);
+  delete temp_header;
+  uint32_t tcp_adu_size = mtu_bytes - (ip_header + tcp_header);
+  NS_LOG_LOGIC ("TCP ADU size is: " << tcp_adu_size);
+
+  // Set the simulation start and stop time
+  float start_time = 0.1;
+  float stop_time = start_time + duration;
+
+  // Select TCP variant
+  if (transport_prot.compare("TcpTahoe") == 0)
+    Config::SetDefault("ns3::TcpL4Protocol::SocketType", TypeIdValue (TcpTahoe::GetTypeId()));
+  else if (transport_prot.compare("TcpReno") == 0)
+    Config::SetDefault("ns3::TcpL4Protocol::SocketType", TypeIdValue (TcpReno::GetTypeId()));
+  else if (transport_prot.compare("TcpNewReno") == 0)
+    Config::SetDefault("ns3::TcpL4Protocol::SocketType", TypeIdValue (TcpNewReno::GetTypeId()));
+  else if (transport_prot.compare("TcpWestwood") == 0)
+    {// the default protocol type in ns3::TcpWestwood is WESTWOOD
+      Config::SetDefault("ns3::TcpL4Protocol::SocketType", TypeIdValue (TcpWestwood::GetTypeId()));
+      Config::SetDefault("ns3::TcpWestwood::FilterType", EnumValue(TcpWestwood::TUSTIN));
+    }
+  else if (transport_prot.compare("TcpWestwoodPlus") == 0)
+    {
+      Config::SetDefault("ns3::TcpL4Protocol::SocketType", TypeIdValue (TcpWestwood::GetTypeId()));
+      Config::SetDefault("ns3::TcpWestwood::ProtocolType", EnumValue(TcpWestwood::WESTWOODPLUS));
+      Config::SetDefault("ns3::TcpWestwood::FilterType", EnumValue(TcpWestwood::TUSTIN));
+    }
+  else
+    {
+      NS_LOG_DEBUG ("Invalid TCP version");
+      exit (1);
+    }
+
+  // Create gateways, sources, and sinks
+  NodeContainer gateways;
+  gateways.Create (1);
+  NodeContainer sources;
+  sources.Create(num_flows);
+  NodeContainer sinks;
+  sinks.Create(num_flows);
+
+  // Configure the error model
+  // Here we use RateErrorModel with packet error rate
+  Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable>();
+  uv->SetStream (50);
+  RateErrorModel error_model;
+  error_model.SetRandomVariable(uv);
+  error_model.SetUnit(RateErrorModel::ERROR_UNIT_PACKET);
+  error_model.SetRate(error_p);
+
+  PointToPointHelper UnReLink;
+  UnReLink.SetDeviceAttribute ("DataRate", StringValue (bandwidth));
+  UnReLink.SetChannelAttribute ("Delay", StringValue ("0.01ms"));
+  UnReLink.SetDeviceAttribute ("ReceiveErrorModel", PointerValue (&error_model));
+
+
+  InternetStackHelper stack;
+  stack.InstallAll ();
+
+  Ipv4AddressHelper address;
+  address.SetBase ("10.0.0.0", "255.255.255.0");
+
+  // Configure the sources and sinks net devices
+  // and the channels between the sources/sinks and the gateways
+  PointToPointHelper LocalLink;
+  LocalLink.SetDeviceAttribute ("DataRate", StringValue (access_bandwidth));
+  LocalLink.SetChannelAttribute ("Delay", StringValue (access_delay));
+  Ipv4InterfaceContainer sink_interfaces;
+  for (int i=0; i<num_flows; i++)
+    {
+      NetDeviceContainer devices;
+      devices = LocalLink.Install(sources.Get(i), gateways.Get(0));
+      address.NewNetwork();
+      Ipv4InterfaceContainer interfaces = address.Assign (devices);
+      devices = UnReLink.Install(gateways.Get(0), sinks.Get(i));
+      address.NewNetwork();
+      interfaces = address.Assign (devices);
+      sink_interfaces.Add(interfaces.Get(1));
+    }
+
+  NS_LOG_INFO ("Initialize Global Routing.");
+  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+
+  uint16_t port = 50000;
+  Address sinkLocalAddress (InetSocketAddress (Ipv4Address::GetAny (), port));
+  PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress);
+
+  for(uint16_t i=0; i<sources.GetN(); i++)
+    {
+      AddressValue remoteAddress (InetSocketAddress (sink_interfaces.GetAddress(i, 0), port));
+
+      if (transport_prot.compare("TcpTahoe") == 0
+          || transport_prot.compare("TcpReno") == 0
+          || transport_prot.compare("TcpNewReno") == 0
+          || transport_prot.compare("TcpWestwood") == 0
+          || transport_prot.compare("TcpWestwoodPlus") == 0)
+        {
+          Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (tcp_adu_size));
+          BulkSendHelper ftp("ns3::TcpSocketFactory", Address());
+          ftp.SetAttribute ("Remote", remoteAddress);
+          ftp.SetAttribute ("SendSize", UintegerValue (tcp_adu_size));
+          ftp.SetAttribute ("MaxBytes", UintegerValue (int(data_mbytes*1000000)));
+
+          ApplicationContainer sourceApp = ftp.Install (sources.Get(i));
+          sourceApp.Start (Seconds (start_time*i));
+          sourceApp.Stop (Seconds (stop_time - 3));
+          Time check_start (Seconds((start_time*i)+3));
+
+          sinkHelper.SetAttribute ("Protocol", TypeIdValue (TcpSocketFactory::GetTypeId ()));
+          ApplicationContainer sinkApp = sinkHelper.Install (sinks);
+          sinkApp.Start (Seconds (start_time*i));
+          sinkApp.Stop (Seconds (stop_time));
+        }
+      else
+        {
+          NS_LOG_DEBUG ("Invalid transport protocol " << transport_prot << " specified");
+          exit (1);
+        }
+    }
+
+  // Set up tracing if enabled
+  if (tracing)
+    {
+      std::ofstream ascii;
+      Ptr<OutputStreamWrapper> ascii_wrap;
+      if (tr_file_name.compare("") == 0)
+        {
+          NS_LOG_DEBUG ("No trace file provided");
+          exit (1);
+        }
+      else
+        {
+          ascii.open (tr_file_name.c_str());
+          ascii_wrap = new OutputStreamWrapper(tr_file_name.c_str(), std::ios::out);
+        }
+
+      stack.EnableAsciiIpv4All (ascii_wrap);
+
+      Simulator::Schedule(Seconds(0.00001), &TraceCwnd, cwnd_tr_file_name);
+      Simulator::Schedule(Seconds(0.00001), &TraceSsThresh, ssthresh_tr_file_name);
+    }
+
+  UnReLink.EnablePcapAll("TcpVariantsComparison", true);
+  LocalLink.EnablePcapAll("TcpVariantsComparison", true);
+
+  // Flow monitor
+  Ptr<FlowMonitor> flowMonitor;
+  if (flow_monitor)
+    {
+      FlowMonitorHelper flowHelper;
+      flowMonitor = flowHelper.InstallAll();
+    }
+
+  Simulator::Stop (Seconds(stop_time));
+  Simulator::Run ();
+
+  if (flow_monitor)
+    {
+      flowMonitor->SerializeToXmlFile("TcpVariantsComparison.flowmonitor", true, true);
+    }
+
+  Simulator::Destroy ();
+  return 0;
+}
--- a/examples/tcp/wscript	Thu Apr 18 21:14:10 2013 +0200
+++ b/examples/tcp/wscript	Thu Apr 18 15:57:07 2013 -0400
@@ -26,6 +26,12 @@
     obj.source = 'tcp-bulk-send.cc'
 
     obj = bld.create_ns3_program('tcp-nsc-comparison',
+                                 ['point-to-point', 'internet', 'applications'])
+
+    obj.source = 'tcp-nsc-comparison.cc'
+    
+    obj = bld.create_ns3_program('tcp-variants-comparison',
                                  ['point-to-point', 'internet', 'applications', 'flow-monitor'])
 
-    obj.source = 'tcp-nsc-comparison.cc'
+    obj.source = 'tcp-variants-comparison.cc'
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet/model/tcp-westwood.cc	Thu Apr 18 15:57:07 2013 -0400
@@ -0,0 +1,419 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 ResiliNets, ITTC, University of Kansas 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Siddharth Gangadhar <siddharth@ittc.ku.edu>, Truc Anh N. Nguyen <annguyen@ittc.ku.edu>,
+ * and Greeshma Umapathi
+ *
+ * James P.G. Sterbenz <jpgs@ittc.ku.edu>, director
+ * ResiliNets Research Group  http://wiki.ittc.ku.edu/resilinets
+ * Information and Telecommunication Technology Center (ITTC)
+ * and Department of Electrical Engineering and Computer Science
+ * The University of Kansas Lawrence, KS USA.
+ *
+ * Work supported in part by NSF FIND (Future Internet Design) Program
+ * under grant CNS-0626918 (Postmodern Internet Architecture),
+ * NSF grant CNS-1050226 (Multilayer Network Resilience Analysis and Experimentation on GENI),
+ * US Department of Defense (DoD), and ITTC at The University of Kansas.
+ */
+
+#define NS_LOG_APPEND_CONTEXT \
+  if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
+
+#include "tcp-westwood.h"
+#include "ns3/log.h"
+#include "ns3/trace-source-accessor.h"
+#include "ns3/simulator.h"
+#include "ns3/abort.h"
+#include "ns3/node.h"
+#include "ns3/sequence-number.h"
+#include "rtt-estimator.h"
+
+NS_LOG_COMPONENT_DEFINE("TcpWestwood");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED(TcpWestwood);
+
+TypeId
+TcpWestwood::GetTypeId (void)
+{
+  static TypeId tid = TypeId("ns3::TcpWestwood")
+      .SetParent<TcpSocketBase>()
+      .AddConstructor<TcpWestwood>()
+      .AddTraceSource("CongestionWindow", "The TCP connection's congestion window",
+                      MakeTraceSourceAccessor(&TcpWestwood::m_cWnd))
+      .AddAttribute("FilterType", "Use this to choose no filter or Tustin's approximation filter",
+                    EnumValue(TcpWestwood::TUSTIN), MakeEnumAccessor(&TcpWestwood::m_fType),
+                    MakeEnumChecker(TcpWestwood::NONE, "None", TcpWestwood::TUSTIN, "Tustin"))
+      .AddAttribute("ProtocolType", "Use this to let the code run as Westwood or WestwoodPlus",
+                    EnumValue(TcpWestwood::WESTWOOD),
+                    MakeEnumAccessor(&TcpWestwood::m_pType),
+                    MakeEnumChecker(TcpWestwood::WESTWOOD, "Westwood",TcpWestwood::WESTWOODPLUS, "WestwoodPlus"))
+      .AddTraceSource("EstimatedBW", "The estimated bandwidth",
+                    MakeTraceSourceAccessor(&TcpWestwood::m_currentBW));
+  return tid;
+}
+
+TcpWestwood::TcpWestwood (void) :
+  m_inFastRec(false),
+  m_currentBW(0),
+  m_lastSampleBW(0),
+  m_lastBW(0),
+  m_minRtt(0),
+  m_lastAck(0),
+  m_prevAckNo(0),
+  m_accountedFor(0),
+  m_ackedSegments(0),
+  m_IsCount(false)
+{
+  NS_LOG_FUNCTION (this);
+}
+
+TcpWestwood::TcpWestwood (const TcpWestwood& sock) :
+  TcpSocketBase(sock),
+  m_cWnd(sock.m_cWnd),
+  m_ssThresh(sock.m_ssThresh),
+  m_initialCWnd(sock.m_initialCWnd),
+  m_inFastRec(false),
+  m_currentBW(sock.m_currentBW),
+  m_lastSampleBW(sock.m_lastSampleBW),
+  m_lastBW(sock.m_lastBW),
+  m_minRtt(sock.m_minRtt),
+  m_lastAck(sock.m_lastAck),
+  m_prevAckNo(sock.m_prevAckNo),
+  m_accountedFor(sock.m_accountedFor)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_LOGIC ("Invoked the copy constructor");
+  NS_LOG_INFO ("m_minRtt at copy constructor" << m_minRtt);
+}
+
+TcpWestwood::~TcpWestwood (void)
+{
+}
+
+int
+TcpWestwood::Listen (void)
+{
+  NS_LOG_FUNCTION (this);
+  InitializeCwnd();
+  return TcpSocketBase::Listen();
+}
+
+int
+TcpWestwood::Connect (const Address & address)
+{
+  NS_LOG_FUNCTION (this << address);
+  InitializeCwnd();
+  return TcpSocketBase::Connect(address);
+}
+
+uint32_t
+TcpWestwood::Window (void)
+{
+  NS_LOG_FUNCTION (this);
+  return std::min (m_rWnd.Get (), m_cWnd.Get ());
+}
+
+Ptr<TcpSocketBase>
+TcpWestwood::Fork (void)
+{
+  NS_LOG_FUNCTION (this);
+  return CopyObject<TcpWestwood>(this);
+}
+
+void
+TcpWestwood::NewAck (const SequenceNumber32& seq)
+{ // Same as Reno
+  NS_LOG_FUNCTION (this << seq);
+  NS_LOG_LOGIC ("TcpWestwood receieved ACK for seq " << seq <<
+                " cwnd " << m_cWnd <<
+                " ssthresh " << m_ssThresh);
+
+  // Check for exit condition of fast recovery
+  if (m_inFastRec)
+    {// First new ACK after fast recovery, reset cwnd as in Reno
+      m_cWnd = m_ssThresh;
+      m_inFastRec = false;
+      NS_LOG_INFO ("Reset cwnd to " << m_cWnd);
+    };
+
+  // Increase of cwnd based on current phase (slow start or congestion avoidance)
+  if (m_cWnd < m_ssThresh)
+    { // Slow start mode, add one segSize to cWnd as in Reno
+      m_cWnd += m_segmentSize;
+      NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
+    }
+  else
+    { // Congestion avoidance mode, increase by (segSize*segSize)/cwnd as in Reno
+      double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get();
+      adder = std::max(1.0, adder);
+      m_cWnd += static_cast<uint32_t>(adder);
+      NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
+    }
+
+  // Complete newAck processing
+  TcpSocketBase::NewAck(seq);
+}
+
+void
+TcpWestwood::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader)
+{
+  NS_LOG_FUNCTION (this);
+  int acked = 0;
+  if ((0 != (tcpHeader.GetFlags () & TcpHeader::ACK)) && tcpHeader.GetAckNumber() >= m_prevAckNo)
+    {// It is a duplicate ACK or a new ACK. Old ACK is ignored.
+      if (m_pType == TcpWestwood::WESTWOOD)
+        {// For Westwood, calculate the number of ACKed segments and estimate the BW
+          acked = CountAck (tcpHeader);
+          EstimateBW (acked, tcpHeader, Time(0));
+        }
+      else if (m_pType == TcpWestwood::WESTWOODPLUS)
+        {// For Weswood+, calculate the number of ACKed segments and update m_ackedSegments
+          if (m_IsCount)
+            {
+              acked = CountAck (tcpHeader);
+              UpdateAckedSegments (acked);
+            }
+        }
+    }
+
+  TcpSocketBase::ReceivedAck (packet, tcpHeader);
+}
+
+void
+TcpWestwood::EstimateBW (int acked, const TcpHeader& tcpHeader, Time rtt)
+{
+  NS_LOG_FUNCTION (this);
+  if (m_pType == TcpWestwood::WESTWOOD)
+    {
+      // Get the time when the current ACK is received
+      double currentAck = static_cast<double> (Simulator::Now().GetSeconds());
+      // Calculate the BW
+      m_currentBW = acked * m_segmentSize / (currentAck - m_lastAck);
+      // Update the last ACK time
+      m_lastAck = currentAck;
+    }
+  else if (m_pType == TcpWestwood::WESTWOODPLUS)
+    {
+      // Calculate the BW
+      m_currentBW = m_ackedSegments * m_segmentSize / rtt.GetSeconds();
+      // Reset m_ackedSegments and m_IsCount for the next sampling
+      m_ackedSegments = 0;
+      m_IsCount = false;
+    }
+
+  // Filter the BW sample
+  Filtering();
+}
+
+int
+TcpWestwood::CountAck (const TcpHeader& tcpHeader)
+{
+  NS_LOG_FUNCTION (this);
+
+  // Calculate the number of acknowledged segments based on the received ACK number
+  int cumul_ack = (tcpHeader.GetAckNumber() - m_prevAckNo) / m_segmentSize;
+
+  if (cumul_ack == 0)
+    {// A DUPACK counts for 1 segment delivered successfully
+      m_accountedFor++;
+      cumul_ack = 1;
+    }
+  if (cumul_ack > 1)
+    {// A delayed ACK or a cumulative ACK after a retransmission
+     // Check how much new data it ACKs
+      if (m_accountedFor >= cumul_ack)
+        {
+          m_accountedFor -= cumul_ack;
+          cumul_ack = 1;
+        }
+      else if (m_accountedFor < cumul_ack)
+        {
+          cumul_ack -= m_accountedFor;
+          m_accountedFor = 0;
+        }
+    }
+
+  // Update the previous ACK number
+  m_prevAckNo = tcpHeader.GetAckNumber();
+
+  return cumul_ack;
+}
+
+void
+TcpWestwood::UpdateAckedSegments (int acked)
+{
+  m_ackedSegments += acked;
+}
+
+void
+TcpWestwood::DupAck (const TcpHeader& header, uint32_t count)
+{
+  NS_LOG_FUNCTION (this << count << m_cWnd);
+
+  if (count == 3 && !m_inFastRec)
+    {// Triple duplicate ACK triggers fast retransmit
+     // Adjust cwnd and ssthresh based on the estimated BW
+      m_ssThresh = m_currentBW * static_cast<double> (m_minRtt.GetSeconds());
+      if (m_cWnd > m_ssThresh)
+        {
+          m_cWnd = m_ssThresh;
+        }
+      m_inFastRec = true;
+      NS_LOG_INFO ("Triple dupack. Enter fast recovery mode. Reset cwnd to " << m_cWnd <<", ssthresh to " << m_ssThresh);
+      DoRetransmit ();
+    }
+  else if (m_inFastRec)
+    {// Increase cwnd for every additional DUPACK as in Reno
+      m_cWnd += m_segmentSize;
+      NS_LOG_INFO ("Dupack in fast recovery mode. Increase cwnd to " << m_cWnd);
+      SendPendingData (m_connected);
+    }
+}
+
+void
+TcpWestwood::Retransmit (void)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
+  m_inFastRec = false;
+
+  // If erroneous timeout in closed/timed-wait state, just return
+  if (m_state == CLOSED || m_state == TIME_WAIT)
+    return;
+  // If all data are received, just return
+  if (m_txBuffer.HeadSequence() >= m_nextTxSequence)
+    return;
+
+  // Upon an RTO, adjust cwnd and ssthresh based on the estimated BW
+  m_ssThresh = std::max (static_cast<double> (2 * m_segmentSize), m_currentBW.Get() * static_cast<double> (m_minRtt.GetSeconds()));
+  m_cWnd = m_segmentSize;
+
+  // Restart from highest ACK
+  m_nextTxSequence = m_txBuffer.HeadSequence();
+  NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
+      ", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
+
+  // Double the next RTO
+  m_rtt->IncreaseMultiplier();
+
+  // Retransmit the packet
+  DoRetransmit();
+}
+
+void
+TcpWestwood::EstimateRtt (const TcpHeader& tcpHeader)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  // Calculate m_lastRtt
+  TcpSocketBase::EstimateRtt (tcpHeader);
+
+  // Update minRtt
+  if (m_minRtt == 0)
+    {
+      m_minRtt = m_lastRtt;
+    }
+  else
+    {
+      if (m_lastRtt < m_minRtt)
+        {
+          m_minRtt = m_lastRtt;
+        }
+    }
+
+  // For Westwood+, start running a clock on the currently estimated RTT if possible
+  // to trigger a new BW sampling event
+  if (m_pType == TcpWestwood::WESTWOODPLUS)
+   {
+     if(m_lastRtt != 0 && m_state == ESTABLISHED && !m_IsCount)
+       {
+         m_IsCount = true;
+         m_bwEstimateEvent.Cancel();
+         m_bwEstimateEvent = Simulator::Schedule (m_lastRtt, &TcpWestwood::EstimateBW,this,m_ackedSegments,tcpHeader,m_lastRtt);
+       }
+   }
+}
+
+void
+TcpWestwood::Filtering ()
+{
+  NS_LOG_FUNCTION (this);
+
+  double alpha = 0.9;
+
+  if (m_fType == TcpWestwood::NONE)
+    {
+    }
+  else if (m_fType == TcpWestwood::TUSTIN)
+    {
+      double sample_bwe = m_currentBW;
+      m_currentBW = (alpha * m_lastBW) + ((1 - alpha) * ((sample_bwe + m_lastSampleBW) / 2));
+      m_lastSampleBW = sample_bwe;
+      m_lastBW = m_currentBW;
+    }
+}
+
+void
+TcpWestwood::SetSegSize (uint32_t size)
+{
+  NS_ABORT_MSG_UNLESS(m_state == CLOSED, "TcpWestwood::SetSegSize() cannot change segment size after connection started.");
+  m_segmentSize = size;
+}
+
+void
+TcpWestwood::SetSSThresh (uint32_t threshold)
+{
+  NS_LOG_FUNCTION (this);
+  m_ssThresh = threshold;
+}
+
+uint32_t
+TcpWestwood::GetSSThresh (void) const
+{
+  NS_LOG_FUNCTION (this);
+  return m_ssThresh;
+}
+
+void
+TcpWestwood::SetInitialCwnd (uint32_t cwnd)
+{
+  NS_ABORT_MSG_UNLESS(m_state == CLOSED, "TcpWestwood::SetInitialCwnd() cannot change initial cwnd after connection started.");
+  m_initialCWnd = cwnd;
+}
+
+uint32_t
+TcpWestwood::GetInitialCwnd (void) const
+{
+  NS_LOG_FUNCTION (this);
+  return m_initialCWnd;
+}
+
+void
+TcpWestwood::InitializeCwnd(void)
+{
+  NS_LOG_FUNCTION (this);
+  /*
+   * Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
+   * not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
+   * m_segmentSize are set by the attribute system in ns3::TcpSocket.
+   */
+  m_cWnd = m_initialCWnd * m_segmentSize;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet/model/tcp-westwood.h	Thu Apr 18 15:57:07 2013 -0400
@@ -0,0 +1,222 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 ResiliNets, ITTC, University of Kansas 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Siddharth Gangadhar <siddharth@ittc.ku.edu>, Truc Anh N. Nguyen <annguyen@ittc.ku.edu>,
+ * and Greeshma Umapathi
+ *
+ * James P.G. Sterbenz <jpgs@ittc.ku.edu>, director
+ * ResiliNets Research Group  http://wiki.ittc.ku.edu/resilinets
+ * Information and Telecommunication Technology Center (ITTC)
+ * and Department of Electrical Engineering and Computer Science
+ * The University of Kansas Lawrence, KS USA.
+ *
+ * Work supported in part by NSF FIND (Future Internet Design) Program
+ * under grant CNS-0626918 (Postmodern Internet Architecture),
+ * NSF grant CNS-1050226 (Multilayer Network Resilience Analysis and Experimentation on GENI),
+ * US Department of Defense (DoD), and ITTC at The University of Kansas.
+ */
+
+#ifndef TCP_WESTWOOD_H
+#define TCP_WESTWOOD_H
+
+#include "tcp-socket-base.h"
+#include "ns3/packet.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup socket
+ * \ingroup tcp
+ *
+ * \brief An implementation of a stream socket using TCP.
+ *
+ * This class contains the implementation of TCP Westwood and Westwood+.
+ *
+ * Westwood and Westwood+ employ the AIAD (Additive Increase/Adaptive Decrease) 
+ * congestion control paradigm. When a congestion episode happens, 
+ * instead of halving the cwnd, these protocols try to estimate the network's
+ * bandwidth and use the estimated value to adjust the cwnd. 
+ * While Westwood performs the bandwidth sampling every ACK reception, 
+ * Westwood+ samples the bandwidth every RTT.
+ *
+ * The two main methods in the implementation are the CountAck (const TCPHeader&)
+ * and the EstimateBW (int, const, Time). The CountAck method calculates
+ * the number of acknowledged segments on the receipt of an ACK.
+ * The EstimateBW estimates the bandwidth based on the value returned by CountAck
+ * and the sampling interval (last ACK inter-arrival time for Westwood and last RTT for Westwood+).   
+ */
+class TcpWestwood : public TcpSocketBase
+{
+public:
+  static TypeId GetTypeId (void);
+
+  TcpWestwood (void);
+  TcpWestwood (const TcpWestwood& sock);
+  virtual ~TcpWestwood (void);
+
+  enum ProtocolType 
+  {
+    WESTWOOD,
+    WESTWOODPLUS
+  };
+
+  enum FilterType 
+  {
+    NONE,
+    TUSTIN
+  };
+
+  // From TcpSocketBase
+  virtual int Connect (const Address &address);
+  virtual int Listen (void);
+
+protected:
+  /**
+   * Limit the size of outstanding data based on the cwnd and the receiver's advertised window
+   *
+   * \return the max. possible number of unacked bytes
+   */  
+  virtual uint32_t Window (void);
+
+  /**
+   * Call CopyObject<TcpWestwood> to clone me
+   */  
+  virtual Ptr<TcpSocketBase> Fork (void);
+
+  /**
+   * Process the newly received ACK
+   *
+   * \param packet the received ACK packet
+   * \param tcpHeader the header attached to the ACK packet
+   */  
+  virtual void ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader);
+  
+  /**
+   * Adjust the cwnd based on the current congestion control phase,
+   * and then call the TcpSocketBase::NewAck() to complete the processing
+   *
+   * \param seq the acknowledgment number
+   */  
+  virtual void NewAck (SequenceNumber32 const& seq);
+
+  /**
+   * Adjust the cwnd using the currently estimated bandwidth,
+   * retransmit the missing packet, and enter fast recovery if 3 DUPACKs are received
+   *
+   * \param header the TCP header of the ACK packet
+   * \param count the number of DUPACKs
+   */  
+  virtual void DupAck (const TcpHeader& header, uint32_t count);
+
+  /**
+   * Upon an RTO event, adjust the cwnd using the currently estimated bandwidth,
+   * retransmit the missing packet, and exit fast recovery
+   */  
+  virtual void Retransmit (void);
+
+  /**
+   * Estimate the RTT, record the minimum value,
+   * and run a clock on the RTT to trigger Westwood+ bandwidth sampling
+   */
+  virtual void EstimateRtt (const TcpHeader& header);
+
+  // Implementing ns3::TcpSocket -- Attribute get/set
+  /**
+   * \param size the segment size to be used in a connection
+   */  
+  virtual void SetSegSize (uint32_t size);
+
+  /**
+   * \param the slow-start threshold
+   */  
+  virtual void SetSSThresh (uint32_t threshold);
+
+  /**
+   * \return the slow-start threshold
+   */  
+  virtual uint32_t GetSSThresh (void) const;
+
+  /**
+   * \param cwnd the initial cwnd
+   */  
+  virtual void SetInitialCwnd (uint32_t cwnd);
+
+  /**
+   * \return the initial cwnd
+   */ 
+  virtual uint32_t GetInitialCwnd (void) const;
+
+private:
+  /**
+   * Initialize cwnd at the beginning of a connection
+   */
+  void InitializeCwnd (void);
+
+  /**
+   * Calculate the number of acknowledged packets upon the receipt of an ACK packet
+   *
+   * \param tcpHeader the header of the received ACK packet
+   * \return the number of ACKed packets
+   */
+  int CountAck (const TcpHeader& tcpHeader);
+
+  /**
+   * Update the total number of acknowledged packets during the current RTT
+   *
+   * \param acked the number of packets the currently received ACK acknowledges
+   */
+  void UpdateAckedSegments (int acked);
+
+  /**
+   * Estimate the network's bandwidth
+   *
+   * \param acked the number of acknowledged packets returned by CountAck
+   * \param tcpHeader the header of the packet
+   * \param rtt the RTT estimation
+   */
+  void EstimateBW (int acked, const TcpHeader& tcpHeader, Time rtt);
+
+  /**
+   * Tustin filter
+   */
+  void Filtering (void);
+
+protected:
+  TracedValue<uint32_t>  m_cWnd;                   //< Congestion window
+  uint32_t               m_ssThresh;               //< Slow Start Threshold
+  uint32_t               m_initialCWnd;            //< Initial cWnd value
+  bool                   m_inFastRec;              //< Currently in fast recovery if TRUE
+
+  TracedValue<double>    m_currentBW;              //< Current value of the estimated BW
+  double                 m_lastSampleBW;           //< Last bandwidth sample
+  double                 m_lastBW;                 //< Last bandwidth sample after being filtered
+  Time                   m_minRtt;                 //< Minimum RTT
+  double                 m_lastAck;                //< The time last ACK was received
+  SequenceNumber32       m_prevAckNo;              //< Previously received ACK number
+  int                    m_accountedFor;           //< The number of received DUPACKs
+  enum ProtocolType      m_pType;                  //< 0 for Westwood, 1 for Westwood+
+  enum FilterType        m_fType;                  //< 0 for none, 1 for Tustin
+
+  int                    m_ackedSegments;          //< The number of segments ACKed between RTTs
+  bool                   m_IsCount;                //< Start keeping track of m_ackedSegments for Westwood+ if TRUE
+  EventId                m_bwEstimateEvent;        //< The BW estimation event for Westwood+
+
+};
+
+} // namespace ns3
+
+#endif /* TCP_WESTWOOD_H */
--- a/src/internet/wscript	Thu Apr 18 21:14:10 2013 +0200
+++ b/src/internet/wscript	Thu Apr 18 15:57:07 2013 -0400
@@ -135,6 +135,7 @@
         'model/tcp-tahoe.cc',
         'model/tcp-reno.cc',
         'model/tcp-newreno.cc',
+        'model/tcp-westwood.cc',
         'model/tcp-rx-buffer.cc',
         'model/tcp-tx-buffer.cc',
         'model/ipv4-packet-info-tag.cc',
@@ -281,6 +282,15 @@
         'helper/ipv6-interface-container.h',
         'helper/ipv6-routing-helper.h',
         'model/ipv6-address-generator.h',
+        'model/tcp-rfc793.h',        
+        'model/tcp-tahoe.h',
+        'model/tcp-reno.h',
+        'model/tcp-newreno.h',
+        'model/tcp-westwood.h',
+        'model/tcp-socket-base.h',
+        'model/tcp-tx-buffer.h',
+        'model/tcp-rx-buffer.h',
+        'model/rtt-estimator.h',
        ]
 
     if bld.env['NSC_ENABLED']:
--- a/src/test/ns3tcp/ns3tcp-loss-test-suite.cc	Thu Apr 18 21:14:10 2013 +0200
+++ b/src/test/ns3tcp/ns3tcp-loss-test-suite.cc	Thu Apr 18 15:57:07 2013 -0400
@@ -38,12 +38,13 @@
 #include "ns3/error-model.h"
 #include "ns3/pointer.h"
 #include "ns3tcp-socket-writer.h"
+#include "ns3/tcp-westwood.h"
 
 using namespace ns3;
 
 NS_LOG_COMPONENT_DEFINE ("Ns3TcpLossTest");
 
-const bool WRITE_VECTORS = false;           // set to true to write response vectors
+const bool WRITE_VECTORS = false;            // set to true to write response vectors
 const bool WRITE_LOGGING = false;            // set to true to write logging
 const uint32_t PCAP_LINK_TYPE = 1187373557; // Some large random number -- we use to verify data was written by this program
 const uint32_t PCAP_SNAPLEN   = 64;         // Don't bother to save much data
@@ -95,7 +96,7 @@
     m_writeResults (false),
     m_writeLogging (WRITE_LOGGING),
     m_needToClose (true),
-    m_tcpModel ("ns3::TcpTahoe")
+    m_tcpModel ("ns3::TcpWestwood")
 {
 }
 
@@ -121,7 +122,7 @@
   //
   std::ostringstream oss;
   oss << "/response-vectors/ns3tcp-loss-" << m_tcpModel << m_testCase << "-response-vectors.pcap";
-    m_pcapFilename = CreateDataDirFilename(oss.str ());
+  m_pcapFilename = CreateDataDirFilename(oss.str ());
 
   if (m_writeVectors)
     {
@@ -286,8 +287,19 @@
 
   std::ostringstream tcpModel;
   tcpModel << "ns3::Tcp" << m_tcpModel;
-  Config::SetDefault ("ns3::TcpL4Protocol::SocketType", 
+  if (m_tcpModel.compare("WestwoodPlus") == 0)
+    {
+	  Config::SetDefault("ns3::TcpL4Protocol::SocketType",
+			             TypeIdValue (TcpWestwood::GetTypeId()));
+	  Config::SetDefault("ns3::TcpWestwood::ProtocolType",
+			             EnumValue(TcpWestwood::WESTWOODPLUS));
+    }
+  else
+    {
+	  Config::SetDefault ("ns3::TcpL4Protocol::SocketType",
                       StringValue (tcpModel.str ()));
+    }
+
   Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1000));
   Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1));
 
@@ -297,6 +309,7 @@
       LogComponentEnable ("TcpLossResponse", LOG_LEVEL_ALL);
       LogComponentEnable ("ErrorModel", LOG_LEVEL_DEBUG);
       LogComponentEnable ("TcpLossResponse", LOG_LEVEL_ALL);
+      LogComponentEnable ("TcpWestwood", LOG_LEVEL_ALL);
       LogComponentEnable ("TcpNewReno", LOG_LEVEL_INFO);
       LogComponentEnable ("TcpReno", LOG_LEVEL_INFO);
       LogComponentEnable ("TcpTahoe", LOG_LEVEL_INFO);
@@ -465,6 +478,19 @@
   AddTestCase (new Ns3TcpLossTestCase ("NewReno", 3), TestCase::QUICK);
   AddTestCase (new Ns3TcpLossTestCase ("NewReno", 4), TestCase::QUICK);
 
+  AddTestCase (new Ns3TcpLossTestCase ("Westwood", 0), TestCase::QUICK);
+  AddTestCase (new Ns3TcpLossTestCase ("Westwood", 1), TestCase::QUICK);
+  AddTestCase (new Ns3TcpLossTestCase ("Westwood", 2), TestCase::QUICK);
+  AddTestCase (new Ns3TcpLossTestCase ("Westwood", 3), TestCase::QUICK);
+  AddTestCase (new Ns3TcpLossTestCase ("Westwood", 4), TestCase::QUICK);
+
+  AddTestCase (new Ns3TcpLossTestCase ("WestwoodPlus", 0), TestCase::QUICK);
+  AddTestCase (new Ns3TcpLossTestCase ("WestwoodPlus", 1), TestCase::QUICK);
+  AddTestCase (new Ns3TcpLossTestCase ("WestwoodPlus", 2), TestCase::QUICK);
+  AddTestCase (new Ns3TcpLossTestCase ("WestwoodPlus", 3), TestCase::QUICK);
+  AddTestCase (new Ns3TcpLossTestCase ("WestwoodPlus", 4), TestCase::QUICK);
+
 }
 
 static Ns3TcpLossTestSuite ns3TcpLossTestSuite;
+