A Discrete-Event Network Simulator
Home
Tutorials ▼
English
Portuguese
Docs ▼
Wiki
Manual
Models
Develop ▼
API
Bugs
API
Main Page
Related Pages
Modules
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Properties
Friends
Macros
Groups
Pages
tcp-westwood.cc
Go to the documentation of this file.
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
113
TcpWestwood::Listen
(
void
)
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
129
TcpWestwood::Window
(
void
)
130
{
131
NS_LOG_FUNCTION
(
this
);
132
return
std::min (
m_rWnd
.
Get
(),
m_cWnd
.
Get
());
133
}
134
135
Ptr<TcpSocketBase>
136
TcpWestwood::Fork
(
void
)
137
{
138
NS_LOG_FUNCTION
(
this
);
139
return
CopyObject<TcpWestwood>(
this
);
140
}
141
142
void
143
TcpWestwood::NewAck
(
const
SequenceNumber32
& seq)
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
177
TcpWestwood::ReceivedAck
(
Ptr<Packet>
packet,
const
TcpHeader
& tcpHeader)
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
228
TcpWestwood::CountAck
(
const
TcpHeader
& tcpHeader)
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
262
TcpWestwood::UpdateAckedSegments
(
int
acked)
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
293
TcpWestwood::Retransmit
(
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
323
TcpWestwood::EstimateRtt
(
const
TcpHeader
& tcpHeader)
324
{
325
NS_LOG_FUNCTION_NOARGS
();
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
357
TcpWestwood::Filtering
()
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
390
TcpWestwood::GetSSThresh
(
void
)
const
391
{
392
NS_LOG_FUNCTION
(
this
);
393
return
m_ssThresh
;
394
}
395
396
void
397
TcpWestwood::SetInitialCwnd
(uint32_t cwnd)
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
404
TcpWestwood::GetInitialCwnd
(
void
)
const
405
{
406
NS_LOG_FUNCTION
(
this
);
407
return
m_initialCWnd
;
408
}
409
410
void
411
TcpWestwood::InitializeCwnd
(
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
src
internet
model
tcp-westwood.cc
Generated on Tue May 14 2013 11:08:23 for ns-3 by
1.8.1.2