A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
tcp-westwood.cc
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013 ResiliNets, ITTC, University of Kansas
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Authors: Siddharth Gangadhar <siddharth@ittc.ku.edu>, Truc Anh N. Nguyen <annguyen@ittc.ku.edu>,
19  * and Greeshma Umapathi
20  *
21  * James P.G. Sterbenz <jpgs@ittc.ku.edu>, director
22  * ResiliNets Research Group http://wiki.ittc.ku.edu/resilinets
23  * Information and Telecommunication Technology Center (ITTC)
24  * and Department of Electrical Engineering and Computer Science
25  * The University of Kansas Lawrence, KS USA.
26  *
27  * Work supported in part by NSF FIND (Future Internet Design) Program
28  * under grant CNS-0626918 (Postmodern Internet Architecture),
29  * NSF grant CNS-1050226 (Multilayer Network Resilience Analysis and Experimentation on GENI),
30  * US Department of Defense (DoD), and ITTC at The University of Kansas.
31  */
32 
33 #define NS_LOG_APPEND_CONTEXT \
34  if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
35 
36 #include "tcp-westwood.h"
37 #include "ns3/log.h"
38 #include "ns3/trace-source-accessor.h"
39 #include "ns3/simulator.h"
40 #include "ns3/abort.h"
41 #include "ns3/node.h"
42 #include "ns3/sequence-number.h"
43 #include "rtt-estimator.h"
44 
45 NS_LOG_COMPONENT_DEFINE("TcpWestwood");
46 
47 namespace ns3 {
48 
49 NS_OBJECT_ENSURE_REGISTERED(TcpWestwood);
50 
51 TypeId
52 TcpWestwood::GetTypeId (void)
53 {
54  static TypeId tid = TypeId("ns3::TcpWestwood")
55  .SetParent<TcpSocketBase>()
56  .AddConstructor<TcpWestwood>()
57  .AddTraceSource("CongestionWindow", "The TCP connection's congestion window",
58  MakeTraceSourceAccessor(&TcpWestwood::m_cWnd))
59  .AddAttribute("FilterType", "Use this to choose no filter or Tustin's approximation filter",
60  EnumValue(TcpWestwood::TUSTIN), MakeEnumAccessor(&TcpWestwood::m_fType),
61  MakeEnumChecker(TcpWestwood::NONE, "None", TcpWestwood::TUSTIN, "Tustin"))
62  .AddAttribute("ProtocolType", "Use this to let the code run as Westwood or WestwoodPlus",
63  EnumValue(TcpWestwood::WESTWOOD),
64  MakeEnumAccessor(&TcpWestwood::m_pType),
65  MakeEnumChecker(TcpWestwood::WESTWOOD, "Westwood",TcpWestwood::WESTWOODPLUS, "WestwoodPlus"))
66  .AddTraceSource("EstimatedBW", "The estimated bandwidth",
67  MakeTraceSourceAccessor(&TcpWestwood::m_currentBW));
68  return tid;
69 }
70 
71 TcpWestwood::TcpWestwood (void) :
72  m_inFastRec(false),
73  m_currentBW(0),
74  m_lastSampleBW(0),
75  m_lastBW(0),
76  m_minRtt(0),
77  m_lastAck(0),
78  m_prevAckNo(0),
79  m_accountedFor(0),
80  m_ackedSegments(0),
81  m_IsCount(false)
82 {
83  NS_LOG_FUNCTION (this);
84 }
85 
86 TcpWestwood::TcpWestwood (const TcpWestwood& sock) :
87  TcpSocketBase(sock),
88  m_cWnd(sock.m_cWnd),
89  m_ssThresh(sock.m_ssThresh),
90  m_initialCWnd(sock.m_initialCWnd),
91  m_inFastRec(false),
92  m_currentBW(sock.m_currentBW),
93  m_lastSampleBW(sock.m_lastSampleBW),
94  m_lastBW(sock.m_lastBW),
95  m_minRtt(sock.m_minRtt),
96  m_lastAck(sock.m_lastAck),
97  m_prevAckNo(sock.m_prevAckNo),
98  m_accountedFor(sock.m_accountedFor),
99  m_pType(sock.m_pType),
100  m_fType(sock.m_fType),
101  m_IsCount(sock.m_IsCount)
102 {
103  NS_LOG_FUNCTION (this);
104  NS_LOG_LOGIC ("Invoked the copy constructor");
105  NS_LOG_INFO ("m_minRtt at copy constructor" << m_minRtt);
106 }
107 
108 TcpWestwood::~TcpWestwood (void)
109 {
110 }
111 
112 int
114 {
115  NS_LOG_FUNCTION (this);
116  InitializeCwnd();
117  return TcpSocketBase::Listen();
118 }
119 
120 int
121 TcpWestwood::Connect (const Address & address)
122 {
123  NS_LOG_FUNCTION (this << address);
124  InitializeCwnd();
125  return TcpSocketBase::Connect(address);
126 }
127 
128 uint32_t
130 {
131  NS_LOG_FUNCTION (this);
132  return std::min (m_rWnd.Get (), m_cWnd.Get ());
133 }
134 
137 {
138  NS_LOG_FUNCTION (this);
139  return CopyObject<TcpWestwood>(this);
140 }
141 
142 void
144 { // Same as Reno
145  NS_LOG_FUNCTION (this << seq);
146  NS_LOG_LOGIC ("TcpWestwood receieved ACK for seq " << seq <<
147  " cwnd " << m_cWnd <<
148  " ssthresh " << m_ssThresh);
149 
150  // Check for exit condition of fast recovery
151  if (m_inFastRec)
152  {// First new ACK after fast recovery, reset cwnd as in Reno
153  m_cWnd = m_ssThresh;
154  m_inFastRec = false;
155  NS_LOG_INFO ("Reset cwnd to " << m_cWnd);
156  };
157 
158  // Increase of cwnd based on current phase (slow start or congestion avoidance)
159  if (m_cWnd < m_ssThresh)
160  { // Slow start mode, add one segSize to cWnd as in Reno
161  m_cWnd += m_segmentSize;
162  NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
163  }
164  else
165  { // Congestion avoidance mode, increase by (segSize*segSize)/cwnd as in Reno
166  double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get();
167  adder = std::max(1.0, adder);
168  m_cWnd += static_cast<uint32_t>(adder);
169  NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
170  }
171 
172  // Complete newAck processing
173  TcpSocketBase::NewAck(seq);
174 }
175 
176 void
178 {
179  NS_LOG_FUNCTION (this);
180  int acked = 0;
181  if ((0 != (tcpHeader.GetFlags () & TcpHeader::ACK)) && tcpHeader.GetAckNumber() >= m_prevAckNo)
182  {// It is a duplicate ACK or a new ACK. Old ACK is ignored.
183  if (m_pType == TcpWestwood::WESTWOOD)
184  {// For Westwood, calculate the number of ACKed segments and estimate the BW
185  acked = CountAck (tcpHeader);
186  EstimateBW (acked, tcpHeader, Time(0));
187  }
188  else if (m_pType == TcpWestwood::WESTWOODPLUS)
189  {// For Weswood+, calculate the number of ACKed segments and update m_ackedSegments
190  if (m_IsCount)
191  {
192  acked = CountAck (tcpHeader);
193  UpdateAckedSegments (acked);
194  }
195  }
196  }
197 
198  TcpSocketBase::ReceivedAck (packet, tcpHeader);
199 }
200 
201 void
202 TcpWestwood::EstimateBW (int acked, const TcpHeader& tcpHeader, Time rtt)
203 {
204  NS_LOG_FUNCTION (this);
205  if (m_pType == TcpWestwood::WESTWOOD)
206  {
207  // Get the time when the current ACK is received
208  double currentAck = static_cast<double> (Simulator::Now().GetSeconds());
209  // Calculate the BW
210  m_currentBW = acked * m_segmentSize / (currentAck - m_lastAck);
211  // Update the last ACK time
212  m_lastAck = currentAck;
213  }
214  else if (m_pType == TcpWestwood::WESTWOODPLUS)
215  {
216  // Calculate the BW
217  m_currentBW = m_ackedSegments * m_segmentSize / rtt.GetSeconds();
218  // Reset m_ackedSegments and m_IsCount for the next sampling
219  m_ackedSegments = 0;
220  m_IsCount = false;
221  }
222 
223  // Filter the BW sample
224  Filtering();
225 }
226 
227 int
229 {
230  NS_LOG_FUNCTION (this);
231 
232  // Calculate the number of acknowledged segments based on the received ACK number
233  int cumul_ack = (tcpHeader.GetAckNumber() - m_prevAckNo) / m_segmentSize;
234 
235  if (cumul_ack == 0)
236  {// A DUPACK counts for 1 segment delivered successfully
237  m_accountedFor++;
238  cumul_ack = 1;
239  }
240  if (cumul_ack > 1)
241  {// A delayed ACK or a cumulative ACK after a retransmission
242  // Check how much new data it ACKs
243  if (m_accountedFor >= cumul_ack)
244  {
245  m_accountedFor -= cumul_ack;
246  cumul_ack = 1;
247  }
248  else if (m_accountedFor < cumul_ack)
249  {
250  cumul_ack -= m_accountedFor;
251  m_accountedFor = 0;
252  }
253  }
254 
255  // Update the previous ACK number
256  m_prevAckNo = tcpHeader.GetAckNumber();
257 
258  return cumul_ack;
259 }
260 
261 void
263 {
264  m_ackedSegments += acked;
265 }
266 
267 void
268 TcpWestwood::DupAck (const TcpHeader& header, uint32_t count)
269 {
270  NS_LOG_FUNCTION (this << count << m_cWnd);
271 
272  if (count == 3 && !m_inFastRec)
273  {// Triple duplicate ACK triggers fast retransmit
274  // Adjust cwnd and ssthresh based on the estimated BW
275  m_ssThresh = m_currentBW * static_cast<double> (m_minRtt.GetSeconds());
276  if (m_cWnd > m_ssThresh)
277  {
278  m_cWnd = m_ssThresh;
279  }
280  m_inFastRec = true;
281  NS_LOG_INFO ("Triple dupack. Enter fast recovery mode. Reset cwnd to " << m_cWnd <<", ssthresh to " << m_ssThresh);
282  DoRetransmit ();
283  }
284  else if (m_inFastRec)
285  {// Increase cwnd for every additional DUPACK as in Reno
286  m_cWnd += m_segmentSize;
287  NS_LOG_INFO ("Dupack in fast recovery mode. Increase cwnd to " << m_cWnd);
288  SendPendingData (m_connected);
289  }
290 }
291 
292 void
294 {
295  NS_LOG_FUNCTION (this);
296  NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
297  m_inFastRec = false;
298 
299  // If erroneous timeout in closed/timed-wait state, just return
300  if (m_state == CLOSED || m_state == TIME_WAIT)
301  return;
302  // If all data are received, just return
303  if (m_txBuffer.HeadSequence() >= m_nextTxSequence)
304  return;
305 
306  // Upon an RTO, adjust cwnd and ssthresh based on the estimated BW
307  m_ssThresh = std::max (static_cast<double> (2 * m_segmentSize), m_currentBW.Get() * static_cast<double> (m_minRtt.GetSeconds()));
308  m_cWnd = m_segmentSize;
309 
310  // Restart from highest ACK
311  m_nextTxSequence = m_txBuffer.HeadSequence();
312  NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
313  ", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
314 
315  // Double the next RTO
316  m_rtt->IncreaseMultiplier();
317 
318  // Retransmit the packet
319  DoRetransmit();
320 }
321 
322 void
324 {
326 
327  // Calculate m_lastRtt
328  TcpSocketBase::EstimateRtt (tcpHeader);
329 
330  // Update minRtt
331  if (m_minRtt == 0)
332  {
333  m_minRtt = m_lastRtt;
334  }
335  else
336  {
337  if (m_lastRtt < m_minRtt)
338  {
339  m_minRtt = m_lastRtt;
340  }
341  }
342 
343  // For Westwood+, start running a clock on the currently estimated RTT if possible
344  // to trigger a new BW sampling event
345  if (m_pType == TcpWestwood::WESTWOODPLUS)
346  {
347  if(m_lastRtt != 0 && m_state == ESTABLISHED && !m_IsCount)
348  {
349  m_IsCount = true;
350  m_bwEstimateEvent.Cancel();
351  m_bwEstimateEvent = Simulator::Schedule (m_lastRtt, &TcpWestwood::EstimateBW,this,m_ackedSegments,tcpHeader,m_lastRtt);
352  }
353  }
354 }
355 
356 void
358 {
359  NS_LOG_FUNCTION (this);
360 
361  double alpha = 0.9;
362 
363  if (m_fType == TcpWestwood::NONE)
364  {
365  }
366  else if (m_fType == TcpWestwood::TUSTIN)
367  {
368  double sample_bwe = m_currentBW;
369  m_currentBW = (alpha * m_lastBW) + ((1 - alpha) * ((sample_bwe + m_lastSampleBW) / 2));
370  m_lastSampleBW = sample_bwe;
371  m_lastBW = m_currentBW;
372  }
373 }
374 
375 void
376 TcpWestwood::SetSegSize (uint32_t size)
377 {
378  NS_ABORT_MSG_UNLESS(m_state == CLOSED, "TcpWestwood::SetSegSize() cannot change segment size after connection started.");
379  m_segmentSize = size;
380 }
381 
382 void
383 TcpWestwood::SetSSThresh (uint32_t threshold)
384 {
385  NS_LOG_FUNCTION (this);
386  m_ssThresh = threshold;
387 }
388 
389 uint32_t
391 {
392  NS_LOG_FUNCTION (this);
393  return m_ssThresh;
394 }
395 
396 void
398 {
399  NS_ABORT_MSG_UNLESS(m_state == CLOSED, "TcpWestwood::SetInitialCwnd() cannot change initial cwnd after connection started.");
400  m_initialCWnd = cwnd;
401 }
402 
403 uint32_t
405 {
406  NS_LOG_FUNCTION (this);
407  return m_initialCWnd;
408 }
409 
410 void
412 {
413  NS_LOG_FUNCTION (this);
414  /*
415  * Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
416  * not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
417  * m_segmentSize are set by the attribute system in ns3::TcpSocket.
418  */
419  m_cWnd = m_initialCWnd * m_segmentSize;
420 }
421 
422 } // namespace ns3
void InitializeCwnd(void)
int CountAck(const TcpHeader &tcpHeader)
virtual int Listen(void)
keep track of time unit.
Definition: nstime.h:149
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:59
virtual void EstimateRtt(const TcpHeader &)
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
virtual void ReceivedAck(Ptr< Packet >, const TcpHeader &)
uint8_t GetFlags() const
Definition: tcp-header.cc:108
SequenceNumber32 HeadSequence(void) const
SequenceNumber32 GetAckNumber() const
Definition: tcp-header.cc:100
virtual void NewAck(SequenceNumber32 const &seq)
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
#define NS_LOG_INFO(msg)
Definition: log.h:264
#define NS_LOG_FUNCTION_NOARGS()
Definition: log.h:275
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Definition: simulator.h:820
virtual uint32_t Window(void)
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if cond is false.
Definition: abort.h:131
virtual void Retransmit(void)
virtual int Listen(void)
a polymophic address class
Definition: address.h:86
double GetSeconds(void) const
Definition: nstime.h:262
void Filtering(void)
virtual uint32_t GetInitialCwnd(void) const
virtual void SetSSThresh(uint32_t threshold)
virtual void DupAck(const TcpHeader &header, uint32_t count)
#define NS_LOG_LOGIC(msg)
Definition: log.h:334
void UpdateAckedSegments(int acked)
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Header for the Transmission Control Protocol.
Definition: tcp-header.h:43
virtual int Connect(const Address &address)
static Time Now(void)
Definition: simulator.cc:179
virtual void SetSegSize(uint32_t size)
virtual void ReceivedAck(Ptr< Packet > packet, const TcpHeader &tcpHeader)
virtual void SetInitialCwnd(uint32_t cwnd)
virtual Ptr< TcpSocketBase > Fork(void)
void Cancel(void)
Definition: event-id.cc:47
void EstimateBW(int acked, const TcpHeader &tcpHeader, Time rtt)
virtual uint32_t GetSSThresh(void) const
virtual int Connect(const Address &address)
virtual void EstimateRtt(const TcpHeader &header)
bool SendPendingData(bool withAck=false)