LEFT | RIGHT |
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ | 1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
2 /* | 2 /* |
3 * Copyright (c) 2014 Natale Patriciello <natale.patriciello@gmail.com> | 3 * Copyright (c) 2014 Natale Patriciello <natale.patriciello@gmail.com> |
4 * | 4 * |
5 * This program is free software; you can redistribute it and/or modify | 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 | 6 * it under the terms of the GNU General Public License version 2 as |
7 * published by the Free Software Foundation; | 7 * published by the Free Software Foundation; |
8 * | 8 * |
9 * This program is distributed in the hope that it will be useful, | 9 * This program is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 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 | 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 | 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
17 * | 17 * |
18 */ | 18 */ |
19 #include "tcp-bic.h" | 19 #include "tcp-bic.h" |
20 | 20 |
21 #include "ns3/log.h" | 21 #include "ns3/log.h" |
22 | 22 |
23 NS_LOG_COMPONENT_DEFINE ("TcpBic"); | 23 NS_LOG_COMPONENT_DEFINE ("TcpBic"); |
24 | 24 |
25 namespace ns3 { | 25 namespace ns3 { |
26 | 26 |
27 NS_OBJECT_ENSURE_REGISTERED (TcpBic); | 27 NS_OBJECT_ENSURE_REGISTERED (TcpBic); |
28 | 28 |
29 #define BICTCP_B 4 /* | |
30 * In binary search, | |
31 * go to point (max+min)/N | |
32 */ | |
33 | |
34 TypeId | 29 TypeId |
35 TcpBic::GetTypeId (void) | 30 TcpBic::GetTypeId (void) |
36 { | 31 { |
37 static TypeId tid = TypeId ("ns3::TcpBic") | 32 static TypeId tid = TypeId ("ns3::TcpBic") |
38 .SetParent<TcpSocketBase> () | 33 .SetParent<TcpSocketBase> () |
39 .AddConstructor<TcpBic> () | 34 .AddConstructor<TcpBic> () |
40 .AddAttribute ("FastConvergence", "Turn on/off fast convergence", | 35 .SetGroupName ("Internet") |
| 36 .AddAttribute ("FastConvergence", "Turn on/off fast convergence.", |
41 BooleanValue (true), | 37 BooleanValue (true), |
42 MakeBooleanAccessor (&TcpBic::m_fastConvergence), | 38 MakeBooleanAccessor (&TcpBic::m_fastConvergence), |
43 MakeBooleanChecker ()) | 39 MakeBooleanChecker ()) |
44 .AddAttribute ("Beta", "Beta for multiplicative increase", | 40 .AddAttribute ("Beta", "Beta for multiplicative decrease", |
45 DoubleValue (0.8), | 41 DoubleValue (0.8), |
46 MakeDoubleAccessor (&TcpBic::m_beta), | 42 MakeDoubleAccessor (&TcpBic::m_beta), |
47 MakeDoubleChecker <double> (0.0)) | 43 MakeDoubleChecker <double> (0.0)) |
48 .AddAttribute ("MaxIncr", "Limit on increment allowed during binary search", | 44 .AddAttribute ("MaxIncr", "Limit on increment allowed during binary search", |
49 UintegerValue (16), | 45 UintegerValue (16), |
50 MakeUintegerAccessor (&TcpBic::m_maxIncr), | 46 MakeUintegerAccessor (&TcpBic::m_maxIncr), |
51 MakeUintegerChecker <uint32_t> ()) | 47 MakeUintegerChecker <uint32_t> (1)) |
52 .AddAttribute ("LowWnd", "Lower bound on congestion window (for TCP friendli
ness)", | 48 .AddAttribute ("LowWnd", "Threshold window size (in segments) for engaging B
IC response", |
53 UintegerValue (14), | 49 UintegerValue (14), |
54 MakeUintegerAccessor (&TcpBic::m_lowWnd), | 50 MakeUintegerAccessor (&TcpBic::m_lowWnd), |
55 MakeUintegerChecker <uint32_t> ()) | 51 MakeUintegerChecker <uint32_t> ()) |
56 .AddAttribute ("SmoothPart", "log(B/(B*Smin))/log(B/(B-1))+B, # of RTT from
Wmax-B to Wmax", | 52 .AddAttribute ("SmoothPart", "Number of RTT needed to approach cWnd_max from
" |
| 53 "cWnd_max-BinarySearchCoefficient. It can be viewed as the gr
adient " |
| 54 "of the slow start AIM phase: less this value is, " |
| 55 "more steep the increment will be.", |
57 IntegerValue (5), | 56 IntegerValue (5), |
58 MakeIntegerAccessor (&TcpBic::m_smoothPart), | 57 MakeIntegerAccessor (&TcpBic::m_smoothPart), |
59 MakeIntegerChecker <int> ()) | 58 MakeIntegerChecker <int> (1)) |
| 59 .AddAttribute ("BinarySearchCoefficient", "Inverse of the coefficient for th
e " |
| 60 "binary search. Default 4, as in Linux", |
| 61 UintegerValue (4), |
| 62 MakeUintegerAccessor (&TcpBic::m_b), |
| 63 MakeUintegerChecker <uint8_t> (2)) |
| 64 .AddAttribute ("ReTxThreshold", "Threshold for fast retransmit", |
| 65 UintegerValue (3), |
| 66 MakeUintegerAccessor (&TcpBic::m_retxThresh), |
| 67 MakeUintegerChecker<uint32_t> ()) |
60 .AddTraceSource ("CongestionWindow", | 68 .AddTraceSource ("CongestionWindow", |
61 "The TCP connection's congestion window", | 69 "The TCP connection's congestion window", |
62 MakeTraceSourceAccessor (&TcpBic::m_cWnd), | 70 MakeTraceSourceAccessor (&TcpBic::m_cWnd), |
63 "ns3::TracedValue::Uint32Callback") | 71 "ns3::TracedValue::Uint32Callback") |
64 .AddTraceSource ("SlowStartThreshold", | 72 .AddTraceSource ("SlowStartThreshold", |
65 "TCP slow start threshold (bytes)", | 73 "TCP slow start threshold (bytes)", |
66 MakeTraceSourceAccessor (&TcpBic::m_ssThresh), | 74 MakeTraceSourceAccessor (&TcpBic::m_ssThresh), |
67 "ns3::TracedValue::Uint32Callback") | 75 "ns3::TracedValue::Uint32Callback") |
| 76 .AddTraceSource ("BicState", |
| 77 "State of TCP BIC", |
| 78 MakeTraceSourceAccessor (&TcpBic::m_bicState), |
| 79 "ns3::TracedValue::Uint8Callback") |
68 ; | 80 ; |
69 return tid; | 81 return tid; |
70 } | 82 } |
71 | 83 |
72 | 84 |
73 TcpBic::TcpBic () : TcpSocketBase () | 85 TcpBic::TcpBic () : TcpSocketBase () |
74 { | 86 { |
75 m_cWndCnt = 0; | 87 m_cWndCnt = 0; |
76 } | 88 } |
77 | 89 |
78 void | 90 void |
79 TcpBic::Reset () | 91 TcpBic::Reset () |
80 { | 92 { |
81 NS_LOG_FUNCTION (this); | 93 NS_LOG_FUNCTION (this); |
82 | 94 |
83 m_lastMaxCwnd = 0; | 95 m_lastMaxCwnd = 0; |
84 m_epochStart = Time::Min (); | 96 m_epochStart = Time::Min (); |
85 } | 97 } |
86 | 98 |
87 void | 99 void |
88 TcpBic::SetInitialSSThresh (uint32_t threshold) | 100 TcpBic::SetInitialSSThresh (uint32_t threshold) |
89 { | 101 { |
90 NS_LOG_FUNCTION (this); | 102 NS_LOG_FUNCTION (this << threshold); |
91 m_ssThresh = threshold; | 103 m_ssThresh = threshold; |
92 } | 104 } |
93 | 105 |
94 uint32_t | 106 uint32_t |
95 TcpBic::GetInitialSSThresh (void) const | 107 TcpBic::GetInitialSSThresh (void) const |
96 { | 108 { |
97 NS_LOG_FUNCTION (this); | 109 NS_LOG_FUNCTION (this); |
98 return m_ssThresh; | 110 return m_ssThresh; |
99 } | 111 } |
100 | 112 |
101 void | 113 void |
102 TcpBic::SetInitialCwnd (uint32_t cwnd) | 114 TcpBic::SetInitialCwnd (uint32_t cWnd) |
103 { | 115 { |
104 NS_LOG_FUNCTION (this); | 116 NS_LOG_FUNCTION (this << cWnd); |
105 m_initialCwnd = cwnd; | 117 m_initialCwnd = cWnd; |
106 } | 118 } |
107 | 119 |
108 uint32_t | 120 uint32_t |
109 TcpBic::GetInitialCwnd (void) const | 121 TcpBic::GetInitialCwnd (void) const |
110 { | 122 { |
111 NS_LOG_FUNCTION (this); | 123 NS_LOG_FUNCTION (this); |
112 return m_initialCwnd; | 124 return m_initialCwnd; |
113 } | 125 } |
114 | 126 |
115 void | 127 void |
(...skipping 25 matching lines...) Expand all Loading... |
141 Init (); | 153 Init (); |
142 | 154 |
143 Reset (); | 155 Reset (); |
144 | 156 |
145 return TcpSocketBase::Connect (address); | 157 return TcpSocketBase::Connect (address); |
146 } | 158 } |
147 | 159 |
148 void | 160 void |
149 TcpBic::NewAck (SequenceNumber32 const& seq) | 161 TcpBic::NewAck (SequenceNumber32 const& seq) |
150 { | 162 { |
151 NS_LOG_FUNCTION (this); | 163 NS_LOG_FUNCTION (this << seq); |
152 | 164 |
153 m_bicState = OPEN; | 165 m_bicState = OPEN; |
154 CongAvoid (); | 166 CongAvoid (); |
155 | 167 |
156 TcpSocketBase::NewAck (seq); | 168 TcpSocketBase::NewAck (seq); |
157 } | 169 } |
158 | 170 |
159 void | 171 void |
160 TcpBic::CongAvoid (void) | 172 TcpBic::CongAvoid (void) |
161 { | 173 { |
162 NS_LOG_FUNCTION (this); | 174 NS_LOG_FUNCTION (this); |
163 | 175 |
164 if (m_cWnd < m_ssThresh) | 176 if (m_cWnd < m_ssThresh) |
165 { | 177 { |
166 NS_LOG_DEBUG ("SlowStart: Increase cwnd by one segment size"); | 178 NS_LOG_DEBUG ("SlowStart: Increase cwnd by one segment size"); |
167 m_cWnd += m_segmentSize; | 179 m_cWnd += m_segmentSize; |
168 } | 180 } |
169 else | 181 else |
170 { | 182 { |
171 ++m_cWndCnt; | 183 ++m_cWndCnt; |
172 uint32_t cnt = Update (); | 184 uint32_t cnt = Update (); |
173 | 185 |
174 // According to the BIC paper and RFC 6356 even once the new cwnd is | 186 /* According to the BIC paper and RFC 6356 even once the new cwnd is |
175 // calculated you must compare this to the number of ACKs received since | 187 * calculated you must compare this to the number of ACKs received since |
176 // the last cwnd update. If not enough ACKs have been received then cwnd | 188 * the last cwnd update. If not enough ACKs have been received then cwnd |
177 // cannot be updated. | 189 * cannot be updated. |
| 190 */ |
178 if (m_cWndCnt > cnt) | 191 if (m_cWndCnt > cnt) |
179 { | 192 { |
180 m_cWnd += m_segmentSize; | 193 m_cWnd += m_segmentSize; |
181 m_cWndCnt = 0; | 194 m_cWndCnt = 0; |
182 NS_LOG_DEBUG("Increment cwnd to " << m_cWnd/m_segmentSize); | 195 NS_LOG_DEBUG ("Increment cwnd to " << m_cWnd / m_segmentSize); |
183 } | 196 } |
184 else | 197 else |
185 { | 198 { |
186 NS_LOG_DEBUG("Not enough segments have been ACKed to increment cwnd. U
ntil now " << m_cWndCnt); | 199 NS_LOG_DEBUG ("Not enough segments have been ACKed to increment cwnd.
Until now " << m_cWndCnt); |
187 } | 200 } |
188 } | 201 } |
189 } | 202 } |
190 | 203 |
191 uint32_t | 204 uint32_t |
192 TcpBic::Update () | 205 TcpBic::Update () |
193 { | 206 { |
194 NS_LOG_FUNCTION (this); | 207 NS_LOG_FUNCTION (this); |
195 | 208 |
196 uint32_t segCwnd = m_cWnd / m_segmentSize; | 209 uint32_t segCwnd = m_cWnd / m_segmentSize; |
197 uint32_t cnt; | 210 uint32_t cnt; |
198 | 211 |
199 m_lastCwnd = segCwnd; | 212 m_lastCwnd = segCwnd; |
200 m_lastTime = Simulator::Now (); | |
201 | 213 |
202 NS_LOG_DEBUG ("New ack. cWnd=" << segCwnd); | 214 NS_LOG_DEBUG ("New ack. cWnd=" << segCwnd); |
203 | 215 |
204 if (m_epochStart == Time::Min ()) | 216 if (m_epochStart == Time::Min ()) |
205 { | 217 { |
206 m_epochStart = Simulator::Now (); /* record the beginning of an epoch */ | 218 m_epochStart = Simulator::Now (); /* record the beginning of an epoch */ |
207 } | 219 } |
208 | 220 |
209 if (segCwnd < m_lowWnd) | 221 if (segCwnd < m_lowWnd) |
210 { | 222 { |
211 cnt = segCwnd; | 223 cnt = segCwnd; |
212 NS_LOG_DEBUG ("cWnd less than lowWnd ("<<m_lowWnd<<")"); | 224 NS_LOG_DEBUG ("cWnd less than lowWnd (" << m_lowWnd << ")"); |
213 return cnt; | 225 return cnt; |
214 } | 226 } |
215 | 227 |
216 if (segCwnd < m_lastMaxCwnd) | 228 if (segCwnd < m_lastMaxCwnd) |
217 { | 229 { |
218 double dist = (m_lastMaxCwnd - segCwnd) / BICTCP_B; | 230 double dist = (m_lastMaxCwnd - segCwnd) / m_b; |
219 | 231 |
220 NS_LOG_DEBUG ("Under lastMax. lastMaxCwnd="<<m_lastMaxCwnd << " and dist="
<< dist); | 232 NS_LOG_DEBUG ("Under lastMax. lastMaxCwnd=" << m_lastMaxCwnd << " and dist
=" << dist); |
221 if (dist > m_maxIncr) | 233 if (dist > m_maxIncr) |
222 { | 234 { |
223 /* Linear increase */ | 235 /* Linear increase */ |
224 cnt = segCwnd / m_maxIncr; | 236 cnt = segCwnd / m_maxIncr; |
225 NS_LOG_DEBUG ("Linear increase (maxIncr="<<m_maxIncr<<"), cnt=" << cnt
); | 237 NS_LOG_DEBUG ("Linear increase (maxIncr=" << m_maxIncr << "), cnt=" <<
cnt); |
226 } | 238 } |
227 else if (dist <= 1) | 239 else if (dist <= 1) |
228 { | 240 { |
229 /* binary search increase */ | 241 /* smoothed binary search increase: when our window is really |
230 cnt = (segCwnd * m_smoothPart) / BICTCP_B; | 242 * close to the last maximum, we parametrize in m_smoothPart the numbe
r |
231 | 243 * of RTT needed to reach that window. |
232 NS_LOG_DEBUG ("Binary search increase (smoothParth="<<m_smoothPart<<")
, cnt=" << cnt); | 244 */ |
| 245 cnt = (segCwnd * m_smoothPart) / m_b; |
| 246 |
| 247 NS_LOG_DEBUG ("Binary search increase (smoothParth=" << m_smoothPart <
< "), cnt=" << cnt); |
233 } | 248 } |
234 else | 249 else |
235 { | 250 { |
236 /* binary search increase */ | 251 /* binary search increase */ |
237 cnt = segCwnd / dist; | 252 cnt = segCwnd / dist; |
238 | 253 |
239 NS_LOG_DEBUG ("Binary search increase, cnt=" << cnt); | 254 NS_LOG_DEBUG ("Binary search increase, cnt=" << cnt); |
240 } | 255 } |
241 } | 256 } |
242 else | 257 else |
243 { | 258 { |
244 NS_LOG_DEBUG ("Above last max. lastMaxCwnd="<<m_lastMaxCwnd); | 259 NS_LOG_DEBUG ("Above last max. lastMaxCwnd=" << m_lastMaxCwnd); |
245 if (segCwnd < m_lastMaxCwnd + BICTCP_B) | 260 if (segCwnd < m_lastMaxCwnd + m_b) |
246 { | 261 { |
247 /* slow start AMD linear increase */ | 262 /* slow start AMD linear increase */ |
248 cnt = (segCwnd * m_smoothPart) / BICTCP_B; | 263 cnt = (segCwnd * m_smoothPart) / m_b; |
249 NS_LOG_DEBUG ("Slow start AMD, cnt=" << cnt); | 264 NS_LOG_DEBUG ("Slow start AMD, cnt=" << cnt); |
250 } | 265 } |
251 else if (segCwnd < m_lastMaxCwnd + m_maxIncr * (BICTCP_B - 1)) | 266 else if (segCwnd < m_lastMaxCwnd + m_maxIncr * (m_b - 1)) |
252 { | 267 { |
253 /* slow start */ | 268 /* slow start */ |
254 cnt = (segCwnd * (BICTCP_B - 1)) / (segCwnd - m_lastMaxCwnd); | 269 cnt = (segCwnd * (m_b - 1)) / (segCwnd - m_lastMaxCwnd); |
255 | 270 |
256 NS_LOG_DEBUG ("Slow start, cnt=" << cnt); | 271 NS_LOG_DEBUG ("Slow start, cnt=" << cnt); |
257 } | 272 } |
258 else | 273 else |
259 { | 274 { |
260 /* linear increase */ | 275 /* linear increase */ |
261 cnt = segCwnd / m_maxIncr; | 276 cnt = segCwnd / m_maxIncr; |
262 | 277 |
263 NS_LOG_DEBUG ("Linear, cnt=" << cnt); | 278 NS_LOG_DEBUG ("Linear, cnt=" << cnt); |
264 } | 279 } |
265 } | 280 } |
266 | 281 |
267 /* if in slow start or link utilization is very low */ | 282 /* if in slow start or link utilization is very low. Code taken from Linux |
| 283 * kernel, not sure of the source they take it. Usually, it is not reached, |
| 284 * since if m_lastMaxCwnd is 0, we are (hopefully) in slow start. |
| 285 */ |
268 if (m_lastMaxCwnd == 0) | 286 if (m_lastMaxCwnd == 0) |
269 { | 287 { |
270 if (cnt > 20) /* increase cwnd 5% per RTT */ | 288 if (cnt > 20) /* increase cwnd 5% per RTT */ |
271 { | 289 { |
272 cnt = 20; | 290 cnt = 20; |
273 } | 291 } |
274 } | 292 } |
275 | 293 |
276 if (cnt == 0) | 294 if (cnt == 0) |
277 { | 295 { |
(...skipping 30 matching lines...) Expand all Loading... |
308 } | 326 } |
309 else | 327 else |
310 { | 328 { |
311 m_lastMaxCwnd = segCwnd; | 329 m_lastMaxCwnd = segCwnd; |
312 NS_LOG_DEBUG ("Last max cwnd: " << m_lastMaxCwnd); | 330 NS_LOG_DEBUG ("Last max cwnd: " << m_lastMaxCwnd); |
313 } | 331 } |
314 | 332 |
315 if (segCwnd < m_lowWnd) | 333 if (segCwnd < m_lowWnd) |
316 { | 334 { |
317 m_ssThresh = std::max ((uint32_t) (m_segmentSize * (segCwnd >> 2)), 2U * m
_segmentSize); | 335 m_ssThresh = std::max ((uint32_t) (m_segmentSize * (segCwnd >> 2)), 2U * m
_segmentSize); |
318 NS_LOG_DEBUG ("Less than lowWindow, ssTh and cWnd= " << m_ssThresh/m_segme
ntSize); | 336 NS_LOG_DEBUG ("Less than lowWindow, ssTh and cWnd= " << m_ssThresh / m_seg
mentSize); |
319 } | 337 } |
320 else | 338 else |
321 { | 339 { |
322 m_ssThresh = std::max ((uint32_t) (m_segmentSize * (segCwnd * m_beta)), 2U
* m_segmentSize); | 340 m_ssThresh = std::max ((uint32_t) (m_segmentSize * (segCwnd * m_beta)), 2U
* m_segmentSize); |
323 NS_LOG_DEBUG ("More than lowWindow, ssTh and cWnd= " << m_ssThresh/m_segme
ntSize); | 341 NS_LOG_DEBUG ("More than lowWindow, ssTh and cWnd= " << m_ssThresh / m_seg
mentSize); |
324 } | 342 } |
325 | 343 |
326 m_cWnd = m_ssThresh; | 344 m_cWnd = m_ssThresh; |
327 } | 345 } |
328 | 346 |
329 void | 347 void |
330 TcpBic::DupAck (const TcpHeader& t, uint32_t count) | 348 TcpBic::DupAck (const TcpHeader& t, uint32_t count) |
331 { | 349 { |
332 NS_LOG_FUNCTION (this); | 350 NS_LOG_FUNCTION (this << t << count); |
333 (void) t; | 351 (void) t; |
334 | 352 |
335 /* After 3 DUPAcks, there is a Loss. */ | 353 /* After 3 DUPAcks, there is a Loss. */ |
336 if (count == 3) | 354 if (count == m_retxThresh) |
337 { | 355 { |
338 RecalcSsthresh (); | 356 RecalcSsthresh (); |
339 m_bicState = LOSS; | 357 m_bicState = LOSS; |
340 DoRetransmit (); | 358 DoRetransmit (); |
341 } | 359 } |
342 else if (count > 3) | 360 else if (count > m_retxThresh) |
343 { | 361 { |
344 CongAvoid(); | 362 CongAvoid (); |
345 SendPendingData (m_connected); | 363 SendPendingData (m_connected); |
346 } | 364 } |
347 } | 365 } |
348 | 366 |
349 void | 367 void |
350 TcpBic::Retransmit (void) | 368 TcpBic::Retransmit (void) |
351 { | 369 { |
352 NS_LOG_FUNCTION (this); | 370 NS_LOG_FUNCTION (this); |
353 | 371 |
354 RecalcSsthresh (); | 372 RecalcSsthresh (); |
(...skipping 12 matching lines...) Expand all Loading... |
367 | 385 |
368 uint32_t | 386 uint32_t |
369 TcpBic::Window (void) | 387 TcpBic::Window (void) |
370 { | 388 { |
371 NS_LOG_FUNCTION (this); | 389 NS_LOG_FUNCTION (this); |
372 | 390 |
373 /* Limit the size of in-flight data by cwnd and receiver's rxwin */ | 391 /* Limit the size of in-flight data by cwnd and receiver's rxwin */ |
374 return std::min (m_rWnd.Get (), m_cWnd.Get ()); | 392 return std::min (m_rWnd.Get (), m_cWnd.Get ()); |
375 } | 393 } |
376 | 394 |
| 395 void |
| 396 TcpBic::ScaleSsThresh (uint8_t scaleFactor) |
| 397 { |
| 398 NS_LOG_FUNCTION (this << static_cast<int> (scaleFactor)); |
| 399 m_ssThresh <<= scaleFactor; |
| 400 } |
| 401 |
377 } // namespace ns3 | 402 } // namespace ns3 |
LEFT | RIGHT |