Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ | |
2 /* | |
3 * Copyright (c) 2013 Natale Patriciello <natale.patriciello@gmail.com> | |
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 */ | |
19 | |
20 #define NS_LOG_APPEND_CONTEXT \ | |
21 if (m_node) \ | |
22 { std::clog << Simulator::Now ().GetSeconds () << \ | |
23 " [node " << m_node->GetId () << "] "; } | |
24 | |
25 #include "tcp-noordwijk.h" | |
26 #include "ns3/node.h" | |
27 #include "ns3/log.h" | |
28 #include "ns3/abort.h" | |
29 | |
30 NS_LOG_COMPONENT_DEFINE ("TcpNoordwijk"); | |
31 | |
32 using namespace ns3; | |
33 | |
34 NS_OBJECT_ENSURE_REGISTERED (TcpNoordwijk); | |
35 | |
36 #define LAMBDA 2 | |
37 #define STAB 2 | |
38 #define BURST_MIN (m_segmentSize * 3) | |
Tom Henderson
2015/01/05 15:36:17
make into constants
| |
39 | |
40 // Assumption: defBurstWnd <= m_rWnd , so SETUP RIGHT Timer and InitialCwnd | |
Tom Henderson
2015/01/05 15:36:17
can you elaborate a bit more on this assumption, o
| |
41 | |
42 TypeId | |
43 TcpNoordwijk::GetTypeId (void) | |
44 { | |
45 static TypeId tid = TypeId ("ns3::TcpNoordwijk") | |
46 .SetParent<TcpSocketBase> () | |
47 .AddConstructor<TcpNoordwijk> () | |
48 .AddAttribute ("TxTime", "Default transmission timer", | |
49 TimeValue (MilliSeconds (500)), | |
50 MakeTimeAccessor (&TcpNoordwijk::m_initialTxTime), | |
51 MakeTimeChecker ()) | |
52 .AddAttribute ("B", "Congestion thresold", | |
53 TimeValue (MilliSeconds (200)), | |
54 MakeTimeAccessor (&TcpNoordwijk::m_congThresold), | |
55 MakeTimeChecker ()) | |
56 ; | |
57 return tid; | |
58 } | |
59 | |
60 TcpNoordwijk::TcpNoordwijk () : TcpSocketBase (), | |
61 m_txTimer (Timer::CANCEL_ON_DESTROY), | |
62 m_trainReceived (0), | |
Tom Henderson
2015/01/05 15:36:17
the indentation style is actually to return after
| |
63 m_bytesAcked (0), | |
64 m_minRtt (Time::Max ()), | |
65 m_maxRtt (Time::Min ()), | |
66 m_firstAck (Time::FromInteger (0, Time::MS)), | |
67 m_lastAckedSegmentInRTO (0), | |
68 m_bytesRetransmitted (0), | |
69 m_bytesTransmitted (0), | |
70 m_restore (false), | |
71 m_firstDupAck (Time::FromInteger (0, Time::MS)) | |
72 { | |
73 SetTcpNoDelay (true); | |
74 | |
75 m_cWnd = m_bWnd = m_initialBWnd = 0; | |
76 } | |
77 | |
78 void | |
79 TcpNoordwijk::SetInitialSSThresh (uint32_t threshold) | |
80 { | |
81 (void) threshold; | |
Tom Henderson
2015/01/05 15:36:18
was a compiler requiring this cast?
| |
82 NS_LOG_WARN ("TcpNoordwijk does not perform slow start"); | |
83 } | |
84 | |
85 uint32_t | |
86 TcpNoordwijk::GetInitialSSThresh (void) const | |
87 { | |
88 NS_LOG_WARN ("TcpNoordwijk does not perform slow start"); | |
89 return 0; | |
90 } | |
91 | |
92 void | |
93 TcpNoordwijk::SetInitialCwnd (uint32_t cwnd) | |
94 { | |
95 NS_ABORT_MSG_UNLESS (m_state == CLOSED, | |
96 "TcpNoordwijk::SetInitialCwnd() cannot change initial " | |
97 "cwnd after connection started."); | |
98 m_initialBWnd = cwnd; | |
99 } | |
100 | |
101 uint32_t | |
102 TcpNoordwijk::GetInitialCwnd (void) const | |
103 { | |
104 return m_initialBWnd; | |
105 } | |
106 | |
107 int | |
108 TcpNoordwijk::Connect (const Address &address) | |
109 { | |
110 NS_LOG_FUNCTION (this); | |
111 | |
112 int res = TcpSocketBase::Connect (address); | |
113 | |
114 InitializeCwnd (); | |
115 StartTxTimer (); | |
116 | |
117 return res; | |
118 } | |
119 | |
120 void | |
121 TcpNoordwijk::InitializeCwnd () | |
122 { | |
123 NS_LOG_FUNCTION (this); | |
124 | |
125 // initialBWnd is in segment, as specified by SetInitialCwnd | |
126 m_initialBWnd = m_initialBWnd * m_segmentSize; | |
127 m_bWnd = m_initialBWnd; | |
128 | |
129 m_txTime = m_initialTxTime; | |
130 | |
131 NS_ASSERT (m_bWnd <= 65536); // HardCode this. | |
Tom Henderson
2015/01/05 15:36:18
elaborate on the reason for this check? should it
| |
132 | |
133 NS_LOG_DEBUG ("bWnd: " << m_bWnd << ", txTime: " << | |
134 m_initialTxTime.GetMilliSeconds () << " ms"); | |
135 } | |
136 | |
137 void | |
138 TcpNoordwijk::StartTxTimer () | |
139 { | |
140 NS_LOG_FUNCTION (this); | |
141 | |
142 NS_ASSERT (!m_txTimer.IsRunning ()); | |
143 NS_ASSERT (m_txTime.Get ().GetSeconds () != 0.0); | |
144 | |
145 //NS_ASSERT (m_txTime.Get ().GetSeconds () < 1.0); | |
Tom Henderson
2015/01/05 15:36:17
dead code
| |
146 | |
147 m_txTimer.SetFunction (&TcpNoordwijk::CallSendPendingData, this); | |
148 m_txTimer.SetDelay (m_txTime); | |
149 m_txTimer.Schedule (); | |
150 } | |
151 | |
152 uint32_t | |
153 TcpNoordwijk::Window () | |
154 { | |
155 NS_LOG_FUNCTION (this); | |
156 | |
157 // We take care of m_rWnd in CallSendPendingData. | |
158 //NS_LOG_DEBUG (" m_cWnd: " << m_cWnd << | |
159 // " m_rWnd: " << m_rWnd << | |
160 // " UnAck: " << UnAckDataCount () << | |
161 // " m_bWnd: " << m_bWnd); | |
Tom Henderson
2015/01/05 15:36:18
either uncomment or delete (probably uncomment)
| |
162 NS_ASSERT (m_cWnd - UnAckDataCount () <= m_rWnd); | |
163 | |
164 return m_cWnd; | |
165 } | |
166 | |
167 uint32_t | |
168 TcpNoordwijk::AvailableWindow () | |
169 { | |
170 uint32_t availableWindow = TcpSocketBase::AvailableWindow (); | |
Tom Henderson
2015/01/05 15:36:18
NS_LOG_FUNCTION()
| |
171 | |
172 //if (availableWindow <= m_bWnd) | |
173 // NS_LOG_DEBUG (" m_cWnd: " << m_cWnd << | |
174 // " m_rWnd: " << m_rWnd << | |
175 // " UnAck: " << UnAckDataCount () << | |
176 // " m_bWnd: " << m_bWnd); | |
Tom Henderson
2015/01/05 15:36:17
uncomment or delete
| |
177 | |
178 NS_ASSERT (availableWindow <= m_bWnd); | |
179 | |
180 return availableWindow; | |
181 } | |
182 | |
183 void | |
184 TcpNoordwijk::CallSendPendingData () | |
185 { | |
186 // Goal: have the right amount of bytes to send in (cWnd), and | |
187 // add it to the actual UnAckDataCount to create the m_cWnd to use. | |
188 | |
189 NS_ASSERT (m_bWnd >= BURST_MIN || m_bWnd == 0); | |
190 uint32_t cWnd = m_bWnd; | |
191 uint32_t bRetr = m_bytesRetransmitted; | |
192 | |
193 if (m_bytesTransmitted != 0) | |
194 { | |
195 NS_ASSERT (m_bytesTransmitted % m_segmentSize == 0); | |
196 m_historyBWnd[m_historyBWnd.size () - 1] = m_bytesTransmitted; | |
197 } | |
198 | |
199 m_bytesTransmitted = 0; | |
200 | |
201 if (cWnd >= m_bytesRetransmitted) | |
202 { | |
203 cWnd -= m_bytesRetransmitted; | |
204 m_bytesRetransmitted = 0; | |
205 } | |
206 else | |
207 { | |
208 NS_LOG_WARN ("TcpNoordwijk::CallSendPendingData, retransmitted more than b Wnd"); | |
209 cWnd = 0; | |
210 m_bytesRetransmitted -= m_bWnd; | |
211 } | |
212 | |
213 if (cWnd > m_rWnd) | |
214 { | |
215 cWnd = m_rWnd; | |
216 RoundInf (cWnd); | |
217 } | |
218 | |
219 m_cWnd = UnAckDataCount () + cWnd; | |
220 | |
221 if (cWnd != 0) | |
222 { | |
223 m_historyBWnd.push_back (cWnd); | |
224 } | |
225 | |
226 NS_ASSERT (cWnd % m_segmentSize == 0); | |
227 NS_LOG_DEBUG ("cWnd incr: " << cWnd << " rWnd: " << m_rWnd << " bRetr: " << bR etr); | |
228 | |
229 SendPendingData (true); | |
230 } | |
231 | |
232 bool | |
233 TcpNoordwijk::SendPendingData (bool withAck) | |
234 { | |
235 NS_LOG_FUNCTION (this << withAck); | |
236 | |
237 if (m_cWnd > UnAckDataCount () && m_cWnd - UnAckDataCount () > std::min (m_rWn d.Get (), m_bWnd)) | |
238 { | |
239 m_cWnd = UnAckDataCount () + std::min (m_rWnd.Get (), m_bWnd); | |
240 RoundInf (m_cWnd); | |
241 } | |
242 | |
243 NS_ASSERT (m_cWnd % m_segmentSize == 0); | |
244 SequenceNumber32 head = m_highTxMark.Get (); | |
245 | |
246 bool res = TcpSocketBase::SendPendingData (withAck); | |
247 | |
248 uint32_t bytesTransmitted = m_highTxMark.Get () - head; | |
249 | |
250 if (res) | |
251 { | |
252 NS_LOG_DEBUG ("From:" << head << " To: " << m_highTxMark << | |
253 ", #bytes: " << bytesTransmitted << " bWnd: " << m_bWnd); | |
254 | |
255 Range32 rangeTransmitted (head, m_highTxMark.Get ()); | |
256 PairOfRangeAndTime transmitTime (rangeTransmitted, Simulator::Now ()); | |
257 | |
258 m_historyTransmitTime.insert (m_historyTransmitTime.end (), transmitTime); | |
259 } | |
260 | |
261 NS_ASSERT (bytesTransmitted <= m_bWnd); | |
262 m_bytesTransmitted += bytesTransmitted; | |
263 | |
264 if (!m_txTimer.IsRunning ()) | |
265 { | |
266 StartTxTimer (); | |
267 } | |
268 | |
269 return res; | |
270 } | |
271 | |
272 MapOfTransmitTime::iterator | |
273 TcpNoordwijk::GetIteratorOf (SequenceNumber32 seq) | |
274 { | |
275 MapOfTransmitTime::iterator it; | |
Tom Henderson
2015/01/05 15:36:18
NS_LOG_FUNCTION()
| |
276 | |
277 for (it = m_historyTransmitTime.begin (); it != m_historyTransmitTime.end (); ++it) | |
278 { | |
279 Range32 range = it->first; | |
280 if (range.first <= seq && range.second >= seq) | |
281 { | |
282 return it; | |
283 } | |
284 } | |
285 | |
286 return it; | |
287 } | |
288 | |
289 Time | |
290 TcpNoordwijk::GetTransmitTime (SequenceNumber32 seq) | |
291 { | |
292 MapOfTransmitTime::iterator it = GetIteratorOf (seq); | |
293 | |
294 if (it != m_historyTransmitTime.end ()) | |
295 { | |
296 NS_LOG_LOGIC ("Seq " << seq << " transmitted " << it->second.GetSeconds () ); | |
297 return it->second; | |
298 } | |
299 | |
300 return Time (); | |
301 } | |
302 | |
303 void | |
304 TcpNoordwijk::DiscardTimeUpTo (SequenceNumber32 seq) | |
305 { | |
306 MapOfTransmitTime::iterator it; | |
307 | |
308 for (it = m_historyTransmitTime.begin (); it != m_historyTransmitTime.end (); ++it) | |
309 { | |
310 Range32 range = it->first; | |
311 | |
312 if (range.second <= seq) | |
313 { | |
314 break; | |
315 } | |
316 | |
317 if (range.first >= seq) | |
318 { | |
319 return; | |
320 } | |
321 } | |
322 | |
323 if (it != m_historyTransmitTime.end ()) | |
324 { | |
325 NS_LOG_LOGIC ("Remove Range from " << it->first.first << " to " << it->fir st.second); | |
326 m_historyTransmitTime.erase (it); | |
327 } | |
328 } | |
329 | |
330 void | |
331 TcpNoordwijk::NewAck (SequenceNumber32 const& rAck) | |
332 { | |
333 NS_LOG_FUNCTION (this << rAck); | |
334 | |
335 Time now = Simulator::Now (); | |
336 | |
337 if (m_state == SYN_RCVD) | |
338 { | |
339 TcpSocketBase::NewAck (rAck); | |
340 return; | |
341 } | |
342 | |
343 uint32_t bytesAcked = rAck - m_txBuffer.HeadSequence (); | |
344 uint32_t segmentAcked = bytesAcked / m_segmentSize; | |
345 | |
346 NS_ASSERT (bytesAcked >= 0); | |
347 | |
348 if (bytesAcked % m_segmentSize == 1) | |
349 { | |
350 --bytesAcked; | |
351 } | |
352 | |
353 NS_ASSERT (bytesAcked % m_segmentSize == 0); | |
354 | |
355 // Ack stands for first byte receiver needs.. so to split acks we should start | |
356 // from i=1. | |
357 for (uint32_t i = 1; i <= segmentAcked; ++i) | |
358 { | |
359 SequenceNumber32 ack = m_txBuffer.HeadSequence () + (m_segmentSize * i); | |
360 Time rtt = now - GetTransmitTime (ack); | |
361 DiscardTimeUpTo (ack); | |
362 | |
363 NS_LOG_DEBUG ("ACK num=" << ack << " rtt=" << rtt.GetMilliSeconds ()); | |
364 | |
365 ACCE (m_segmentSize, rtt, now); | |
366 } | |
367 | |
368 if (m_cWnd >= bytesAcked) | |
369 { | |
370 m_cWnd -= bytesAcked; | |
371 } | |
372 else | |
373 { | |
374 m_cWnd = UnAckDataCount (); | |
375 } | |
376 | |
377 TcpSocketBase::NewAck (rAck); | |
378 | |
379 //NS_LOG_DEBUG (" m_cWnd: " << m_cWnd << | |
380 // " m_rWnd: " << m_rWnd << | |
381 // " UnAck: " << UnAckDataCount ()); | |
Tom Henderson
2015/01/05 15:36:18
uncomment or delete
| |
382 } | |
383 | |
384 void | |
385 TcpNoordwijk::ACCE (uint32_t bytesAcked, Time rtt, Time now) | |
Tom Henderson
2015/01/05 15:36:17
avoid acronyms for method names; can you spell out
| |
386 { | |
387 NS_LOG_FUNCTION (this << bytesAcked << rtt.GetMilliSeconds ()); | |
388 Time ackTrainDispersion, ackDispersion, deltaRtt; | |
389 | |
390 if (m_minRtt > rtt) | |
391 { | |
392 m_minRtt = rtt; | |
393 } | |
394 | |
395 if (m_maxRtt < rtt) | |
396 { | |
397 m_maxRtt = rtt; | |
398 } | |
399 | |
400 if (m_firstAck.IsZero ()) | |
401 { | |
402 m_firstAck = now; | |
403 NS_LOG_DEBUG ("Time first ack " << now.GetSeconds ()); | |
404 } | |
405 | |
406 uint32_t bWnd = m_historyBWnd.front (); | |
407 | |
408 if (bWnd == 0) // m_historyBWnd is empty | |
409 { | |
410 return; | |
411 } | |
412 | |
413 m_bytesAcked += bytesAcked; | |
414 | |
415 if (m_bytesAcked >= bWnd) | |
416 { | |
417 NS_LOG_DEBUG ("Time last ack " << now.GetSeconds ()); | |
418 ackTrainDispersion = now - m_firstAck; | |
419 ackDispersion = MicroSeconds ( | |
420 ackTrainDispersion.GetMicroSeconds () / (bWnd / m_segmentSize)); | |
421 deltaRtt = m_maxRtt - m_minRtt; | |
422 | |
423 if ((bWnd == m_initialBWnd && ackDispersion.GetSeconds () != 0.0) | |
424 || m_ackDispersion.GetSeconds () == 0.0) | |
425 { | |
426 m_ackDispersion = ackDispersion; | |
427 } | |
428 | |
429 NS_ASSERT (m_ackDispersion.GetSeconds () != 0.0); | |
430 NS_LOG_DEBUG ("ACK train of " << bWnd / m_segmentSize << " acks rcvd. Trai nDisp=" | |
431 << ackTrainDispersion.GetMilliSeconds () << " ms, AckDisp= " | |
432 << ackDispersion.GetMicroSeconds () << " us. Using AckDisp=" | |
433 << m_ackDispersion.GetMicroSeconds () << " u s"); | |
434 | |
435 TrainReceived (bWnd, ackTrainDispersion, deltaRtt); | |
436 | |
437 m_historyBWnd.pop_front (); | |
438 m_bytesAcked -= bWnd; | |
439 m_minRtt = Time::Max (); | |
440 m_maxRtt = Time::Min (); | |
441 m_firstAck = Time::FromInteger (0, Time::MS); | |
442 | |
443 NS_ASSERT (m_bWnd <= m_initialBWnd); | |
444 | |
445 if (m_bytesAcked > 0) | |
446 { | |
447 uint32_t delta = bytesAcked - bWnd; | |
448 m_bytesAcked -= delta; | |
449 ACCE (delta, rtt, now); | |
450 } | |
451 } | |
452 } | |
453 | |
454 void | |
455 TcpNoordwijk::TrainReceived (uint32_t bWnd, Time ackTrainDispersion, Time deltaR tt) | |
456 { | |
457 NS_LOG_FUNCTION (this << bWnd << ackTrainDispersion); | |
458 | |
459 ++m_trainReceived; | |
460 | |
461 if (m_trainReceived < STAB) | |
462 { | |
463 return; | |
464 } | |
465 | |
466 NS_LOG_DEBUG ("Stab reached. DeltaRtt=" << deltaRtt.GetMilliSeconds () << " ms "); | |
467 | |
468 if (ackTrainDispersion.GetSeconds () != 0.0 && deltaRtt.GetSeconds () != 0.0) | |
469 { | |
470 if (deltaRtt > m_congThresold) | |
471 { | |
472 RateAdjustment (bWnd, ackTrainDispersion, deltaRtt); | |
473 } | |
474 else | |
475 { | |
476 RateTracking (bWnd, m_ackDispersion); | |
477 } | |
478 } | |
479 else if (m_dupAckTrainDispersion.GetSeconds () != 0.0 && deltaRtt.GetSeconds ( ) != 0.0) | |
480 { | |
481 if (deltaRtt > m_congThresold) | |
482 { | |
483 RateAdjustment (bWnd, m_dupAckTrainDispersion, deltaRtt); | |
484 } | |
485 else | |
486 { | |
487 RateTracking (bWnd, m_dupAckDispersion); | |
488 } | |
489 } | |
490 | |
491 if (m_restore) | |
492 { | |
493 m_bWnd = m_initialBWnd; | |
494 m_txTime = m_initialTxTime; | |
495 m_restore = false; | |
496 } | |
497 | |
498 m_trainReceived = 0; | |
499 } | |
500 | |
501 /** | |
502 * \brief Rate Adjustment algorithm (there is congestion) | |
503 * | |
504 * Algorithm invoked when there are some symptom of congestion. | |
505 * Definining terms as: | |
506 * | |
507 * - \f$B_{i+1}\f$ as the next burst size | |
508 * - \f$B_{i}\f$ as the actual burst size | |
509 * (opportunely decreased by the number of retransmitted packets) | |
510 * - \f$\Delta_{i}\f$ as the ack train dispersion (in other words, the arrival | |
511 * time of first ack minus the arrival time of last ack) | |
512 * - \f${\Delta}RTT_{i}\f$ as the difference between last RTT and the minimum RT T | |
513 * - \f$\delta_{i} = \frac{Time_{LastAck} - Time_{m_firstAck}}{B_{i}}\f$ as the | |
514 * ack dispersion of the \f$i\f$-th burst | |
515 * | |
516 * We could define next burst size as: | |
517 * \f$B_{i+1} = \frac{\Delta_{i}}{\Delta_{i}+{\Delta}RTT_{i}} \cdot B_{i} = \fra c{B_{i}}{1+\frac{{\Delta}RTT_{i}}{\Delta_{i}}}\f$ | |
518 * | |
519 * We also compute a new TX_TIMER: | |
520 * | |
521 * \f$TX_TIMER_{i+1} = \lambda * B_{0} * \delta_{i}\f$ | |
522 * | |
523 * Where \f$\lambda = 1 \f$ if \f$B_{i+1}\f$ is greater than a fixed value | |
524 * (3 packets), \f$\lambda=2\f$ otherwise. | |
525 * | |
526 * \param ackTrainDispersion arrival time of first ack minus the arrival time of last ack | |
527 * \param deltaRtt difference between last RTT and the minimun RTT | |
528 */ | |
Tom Henderson
2015/01/05 15:36:17
separate documentation into interface (put into th
| |
529 void | |
530 TcpNoordwijk::RateAdjustment (uint32_t bWnd, const Time& ackTrainDispersion, | |
531 const Time& deltaRtt) | |
532 { | |
533 NS_LOG_FUNCTION (this << ackTrainDispersion.GetMilliSeconds () | |
534 << deltaRtt.GetMilliSeconds ()); | |
535 | |
536 NS_ASSERT (deltaRtt.GetSeconds () != 0.0); | |
537 NS_ASSERT (ackTrainDispersion.GetSeconds () != 0.0); | |
538 NS_LOG_DEBUG ("before: " << | |
539 " bWnd: " << m_bWnd << | |
540 " tx_timer:" << m_txTime.Get ().GetMilliSeconds () << | |
541 " ms, ackdisp=" << m_ackDispersion.GetMilliSeconds () << | |
542 " ms, AckTrainDisp=" << ackTrainDispersion.GetMilliSeconds () << | |
543 " ms, DRTT:" << deltaRtt.GetMilliSeconds () << | |
544 " ms"); | |
545 | |
546 uint32_t oldBWnd = m_bWnd; | |
547 | |
548 double tmp = (ackTrainDispersion.GetSeconds () / | |
549 (ackTrainDispersion.GetSeconds () + deltaRtt.GetSeconds ())); | |
550 NS_ASSERT (tmp <= 1.0); | |
551 | |
552 m_bWnd = m_bWnd * tmp; | |
553 | |
554 // The burst window could be not "aligned" with the segment size; round up | |
555 // to the next multiple of the segment size. | |
556 RoundSupBurstWnd (); | |
557 | |
558 if (m_bWnd > BURST_MIN) | |
559 { | |
560 m_txTime = MilliSeconds ((m_initialBWnd / m_segmentSize) * m_ackDispersion .GetMilliSeconds ()); | |
561 } | |
562 else | |
563 { | |
564 m_txTime = MilliSeconds (LAMBDA * (m_initialBWnd / m_segmentSize) * m_ackD ispersion.GetMilliSeconds ()); | |
565 } | |
566 | |
567 if (m_txTime.Get ().GetSeconds () == 0.0) | |
568 { | |
569 m_txTime = m_initialTxTime; | |
570 } | |
571 | |
572 if (oldBWnd > m_bWnd) | |
573 { | |
574 uint32_t diff = oldBWnd - m_bWnd; | |
575 | |
576 if (m_cWnd - UnAckDataCount () > diff) | |
577 { | |
578 m_cWnd -= diff; | |
579 } | |
580 else | |
581 { | |
582 m_cWnd = UnAckDataCount (); | |
583 } | |
584 | |
585 NS_ASSERT (m_bWnd >= m_cWnd - UnAckDataCount ()); | |
586 } | |
587 | |
588 RoundTxTime (); | |
589 | |
590 NS_LOG_DEBUG (" after: " << | |
591 " bWnd: " << m_bWnd << | |
592 " tx_timer:" << m_txTime.Get ().GetMilliSeconds () << | |
593 " ms"); | |
594 } | |
595 | |
596 /** | |
597 * \brief Rate tracking algorithm (no congestion) | |
598 * | |
599 * This algorithm aims at adapting transmission rate to the maximum allowed | |
600 * rate through the following steps: gradually increase burst size (logarithmic | |
601 * grow) up to the initial burst size, and tx_timer is fixed to the optimal | |
602 * value for default-sized bursts. | |
603 * | |
604 * With | |
605 * | |
606 * - \f$B_{0}\f$ as the default burst size | |
607 * - \f$B_{i+1}\f$ as the next burst size | |
608 * - \f$B_{i}\f$ as the actual burst size | |
609 * - \f$\delta_{i} = \frac{Time_{LastAck} - Time_{m_firstAck}}{B_{i}}\f$ as | |
610 * the ack dispersion of the \f$i\f$-th burst | |
611 * | |
612 * We could define next burst size as: | |
613 * | |
614 * \f$B_{i+1} = B_{i} + \frac{B_{0}-B_{i}}{2}\f$ | |
615 * | |
616 * We update also the tx_timer here, with the following function: | |
617 * | |
618 * \f$TX_TIMER_{i+1} = B_{0} * \delta_{i}\f$ | |
619 */ | |
620 void | |
621 TcpNoordwijk::RateTracking (uint32_t bWnd, Time ackDispersion) | |
622 { | |
623 NS_LOG_FUNCTION (this); | |
624 NS_ASSERT (ackDispersion.GetSeconds () != 0.0); | |
625 | |
626 NS_LOG_DEBUG (" before:" << | |
627 " bWnd=" << m_bWnd << | |
628 " B, tx_timer=" << m_txTime.Get ().GetMilliSeconds () << | |
629 " ms, AckDisp: " << m_ackDispersion.GetMilliSeconds () << | |
630 " ms, def burst: " << m_initialBWnd); | |
631 | |
632 uint32_t bytesToAdd = (m_initialBWnd - m_bWnd) / 2; | |
633 | |
634 m_bWnd += bytesToAdd; | |
635 | |
636 // The burst window could be not "aligned" with the segment size; round up | |
637 // to the previous multiple of the segment size. | |
638 RoundSupBurstWnd (); | |
639 | |
640 m_txTime = MicroSeconds ((m_initialBWnd / m_segmentSize) * ackDispersion.GetMi croSeconds ()); | |
641 | |
642 RoundTxTime (); | |
643 | |
644 NS_LOG_DEBUG (" after:" << | |
645 " bWnd=" << m_bWnd << | |
646 " B, tx_timer=" << m_txTime.Get ().GetMilliSeconds () << | |
647 " ms"); | |
648 } | |
649 | |
650 void | |
651 TcpNoordwijk::RoundSupBurstWnd () | |
652 { | |
653 if (m_bWnd % m_segmentSize != 0) | |
654 { | |
655 uint32_t diff = m_bWnd % m_segmentSize; | |
656 m_bWnd -= diff; | |
657 | |
658 m_bWnd += m_segmentSize; | |
659 } | |
660 | |
661 // Stupid coder | |
Tom Henderson
2015/01/05 15:36:18
delete comment, or elaborate
| |
662 if (m_bWnd > m_initialBWnd) | |
663 { | |
664 m_bWnd -= m_segmentSize; | |
665 } | |
666 | |
667 NS_ASSERT (m_bWnd <= m_initialBWnd); | |
668 } | |
669 | |
670 void | |
671 TcpNoordwijk::RoundInf (uint32_t &value) | |
672 { | |
673 if (value % m_segmentSize != 0) | |
674 { | |
675 uint32_t diff = value % m_segmentSize; | |
676 value -= diff; | |
677 } | |
678 } | |
679 | |
680 void | |
681 TcpNoordwijk::RoundTxTime () | |
682 { | |
683 /** \todo m_bWnd *= 0.5 is ugly. Please do little steps */ | |
684 while (m_txTime.Get ().GetSeconds () > 1.0) | |
685 { | |
686 m_txTime = m_txTime.Get () / 2; | |
687 m_bWnd = m_bWnd / 2; | |
688 RoundSupBurstWnd (); | |
689 } | |
690 | |
691 /* Wow. That's bad. We adjust the rate, because txTimer is the same */ | |
Tom Henderson
2015/01/05 15:36:17
is this an XXX comment about this implementation?
| |
692 if (m_bWnd < BURST_MIN) | |
693 { | |
694 m_bWnd = BURST_MIN; | |
695 } | |
696 } | |
697 | |
698 /** | |
699 * \brief Received a DupAck for a segment size | |
700 * | |
701 * There is (probably) a loss when we detect a triple dupack, so resend | |
702 * the next segment of duplicate ack. Increase also the retransmitted packet | |
703 * count. | |
704 * | |
705 * \param t TcpHeader (unused) | |
706 * \param count Dupack count | |
707 */ | |
708 void | |
709 TcpNoordwijk::DupAck (const TcpHeader& t, uint32_t count) | |
710 { | |
711 NS_LOG_FUNCTION (this << "t " << count); | |
712 | |
713 NS_LOG_DEBUG ("Dupack for segment " << t.GetAckNumber () << " count=" << count ); | |
714 | |
715 /* if (m_firstDupAck.IsZero ()) | |
716 m_firstDupAck = Simulator::Now (); | |
717 | |
718 if (count % 20 == 0) | |
719 { | |
720 m_dupAckTrainDispersion = Simulator::Now () - m_firstDupAck; | |
721 m_dupAckDispersion = MicroSeconds(m_dupAckTrainDispersion.GetMicroSeconds () / 20); | |
722 | |
723 m_firstDupAck = Time::FromInteger (0, Time::S); | |
724 m_restore = true; | |
725 } | |
726 */ | |
Tom Henderson
2015/01/05 15:36:18
dead code
| |
727 // Wait the third dupack | |
728 if (count != 6) | |
729 { | |
730 return; | |
731 } | |
732 | |
733 | |
734 //if (m_bytesRetransmitted >= m_bWnd) | |
735 // return; | |
Tom Henderson
2015/01/05 15:36:17
dead code
| |
736 | |
737 NS_LOG_DEBUG ("Doing a retransmit of " << m_segmentSize << " bytes. Reset TxTi mer"); | |
738 | |
739 DoRetransmit (); | |
740 m_bytesRetransmitted += m_segmentSize; | |
741 | |
742 m_initialTxTime = m_initialTxTime + m_initialTxTime; | |
743 m_bWnd = m_initialBWnd; | |
744 m_txTime = m_initialTxTime; | |
745 m_restore = true; | |
746 | |
747 if (m_txTimer.IsRunning ()) | |
748 { | |
749 Time left = m_txTimer.GetDelayLeft (); | |
750 m_txTimer.Cancel (); | |
751 m_txTimer.SetDelay (m_txTime - left); | |
752 } | |
753 | |
754 RoundTxTime (); | |
755 } | |
756 | |
757 /** | |
758 * \brief Retransmit timeout | |
759 * | |
760 * Retransmit first non ack packet, increase the retransmitted packet count, | |
761 * and set recover flag for the initial values of burst size and tx_timer | |
762 * | |
763 * In case of consecutive RTO expiration, retransmission is repeated while the | |
764 * default tx_timer is doubled. | |
765 */ | |
766 void | |
767 TcpNoordwijk::Retransmit (void) | |
768 { | |
769 NS_LOG_FUNCTION (this); | |
770 | |
771 // If erroneous timeout in closed/timed-wait state, just return | |
772 if (m_state == CLOSED || m_state == TIME_WAIT) | |
773 { | |
774 return; | |
775 } | |
776 // If all data are received (non-closing socket and nothing to send), just ret urn | |
777 if (m_state <= ESTABLISHED && m_txBuffer.HeadSequence () >= m_highTxMark) | |
778 { | |
779 return; | |
780 } | |
781 | |
782 NS_LOG_DEBUG ("Retransmit"); | |
783 | |
784 // if (m_txBuffer.HeadSequence () == m_lastAckedSegmentInRTO) | |
785 // { | |
Tom Henderson
2015/01/05 15:36:18
dead code
| |
786 m_initialTxTime = m_initialTxTime + m_initialTxTime; | |
787 if (m_initialTxTime.GetSeconds () > 1.0) | |
788 { | |
789 m_initialTxTime = Seconds (0.9); | |
790 } | |
791 | |
792 m_txTime = m_initialTxTime; | |
793 m_restore = true; | |
794 | |
795 if (m_txTimer.IsRunning ()) | |
796 { | |
797 Time left = m_txTimer.GetDelayLeft (); | |
798 m_txTimer.Cancel (); | |
799 m_txTimer.SetDelay (m_txTime - left); | |
800 } | |
801 // } | |
802 | |
803 m_lastAckedSegmentInRTO = m_txBuffer.HeadSequence (); | |
804 | |
805 TcpSocketBase::Retransmit (); | |
806 | |
807 m_bytesRetransmitted += m_segmentSize; | |
808 m_cWnd = UnAckDataCount (); | |
809 } | |
810 | |
811 Ptr<TcpSocketBase> | |
812 TcpNoordwijk::Fork (void) | |
813 { | |
814 return CopyObject<TcpNoordwijk> (this); | |
815 } | |
OLD | NEW |