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) 2010 Adrian Sai-wah Tam | 3 * Copyright (c) 2010 Adrian Sai-wah Tam |
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 * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com> | 18 * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com> |
19 */ | 19 */ |
| 20 |
| 21 #define NS_LOG_APPEND_CONTEXT \ |
| 22 if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_n
ode->GetId () << "] "; } |
20 | 23 |
21 #include "tcp-newreno.h" | 24 #include "tcp-newreno.h" |
22 #include "ns3/log.h" | 25 #include "ns3/log.h" |
23 #include "ns3/trace-source-accessor.h" | 26 #include "ns3/trace-source-accessor.h" |
24 #include "ns3/simulator.h" | 27 #include "ns3/simulator.h" |
25 #include "ns3/abort.h" | 28 #include "ns3/abort.h" |
26 #include "ns3/node.h" | 29 #include "ns3/node.h" |
27 | 30 |
28 NS_LOG_COMPONENT_DEFINE ("TcpNewReno"); | 31 NS_LOG_COMPONENT_DEFINE ("TcpNewReno"); |
29 | 32 |
30 namespace ns3 { | 33 namespace ns3 { |
31 | 34 |
32 NS_OBJECT_ENSURE_REGISTERED (TcpNewReno); | 35 NS_OBJECT_ENSURE_REGISTERED (TcpNewReno); |
33 | 36 |
34 TypeId | 37 TypeId |
35 TcpNewReno::GetTypeId (void) | 38 TcpNewReno::GetTypeId (void) |
36 { | 39 { |
37 static TypeId tid = TypeId ("ns3::TcpNewReno") | 40 static TypeId tid = TypeId ("ns3::TcpNewReno") |
38 .SetParent<TcpReno> () | 41 .SetParent<TcpSocketBase> () |
39 .AddConstructor<TcpNewReno> () | 42 .AddConstructor<TcpNewReno> () |
| 43 .AddTraceSource ("CongestionWindow", |
| 44 "The TCP connection's congestion window", |
| 45 MakeTraceSourceAccessor (&TcpNewReno::m_cWnd)) |
40 ; | 46 ; |
41 return tid; | 47 return tid; |
42 } | 48 } |
43 | 49 |
44 TcpNewReno::TcpNewReno (void) | 50 TcpNewReno::TcpNewReno (void) : m_inFastRec (false) |
45 { | 51 { |
| 52 NS_LOG_FUNCTION (this); |
46 } | 53 } |
47 | 54 |
48 TcpNewReno::TcpNewReno (const TcpNewReno& sock) | 55 TcpNewReno::TcpNewReno (const TcpNewReno& sock) |
49 : TcpReno (sock), m_inFastRec(false) | 56 : TcpSocketBase (sock), |
50 { | 57 m_cWnd (sock.m_cWnd), |
| 58 m_ssThresh (sock.m_ssThresh), |
| 59 m_initialCWnd (sock.m_initialCWnd), |
| 60 m_inFastRec (false) |
| 61 { |
| 62 NS_LOG_FUNCTION (this); |
| 63 NS_LOG_LOGIC ("Invoked the copy constructor"); |
51 } | 64 } |
52 | 65 |
53 TcpNewReno::~TcpNewReno (void) | 66 TcpNewReno::~TcpNewReno (void) |
54 { | 67 { |
| 68 } |
| 69 |
| 70 void |
| 71 TcpNewReno::SetNode (Ptr<Node> node) |
| 72 { |
| 73 TcpSocketBase::SetNode (node); |
| 74 /* |
| 75 * Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must |
| 76 * not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and |
| 77 * m_segmentSize are set by the attribute system in ns3::TcpSocket. |
| 78 */ |
| 79 m_cWnd = m_initialCWnd * m_segmentSize; |
| 80 } |
| 81 |
| 82 /** Limit the size of in-flight data by cwnd and receiver's rxwin */ |
| 83 uint32_t |
| 84 TcpNewReno::Window (void) |
| 85 { |
| 86 NS_LOG_FUNCTION (this); |
| 87 return std::min (m_rWnd.Get (), m_cWnd.Get ()); |
55 } | 88 } |
56 | 89 |
57 Ptr<TcpSocketBase> | 90 Ptr<TcpSocketBase> |
58 TcpNewReno::Fork (void) | 91 TcpNewReno::Fork (void) |
59 { | 92 { |
60 return CopyObject<TcpNewReno> (this); | 93 return CopyObject<TcpNewReno> (this); |
61 } | 94 } |
62 | 95 |
63 /** Increase cwnd and call CommonNewAck() upon a new seqnum received */ | 96 /** New ACK (up to seqnum seq) received. Increase cwnd and call TcpSocketBase::N
ewAck() */ |
64 void | 97 void |
65 TcpNewReno::NewAck (SequenceNumber const& seq) | 98 TcpNewReno::NewAck (const SequenceNumber32& seq) |
66 { | 99 { |
67 if (m_inFastRec && seq == m_recover) | 100 NS_LOG_FUNCTION (this << seq); |
68 { // Full ACK (RFC2582 sec.3) | 101 NS_LOG_LOGIC ("TcpNewReno receieved ACK for seq " << seq << |
| 102 " cwnd " << m_cWnd << |
| 103 " ssthresh " << m_ssThresh); |
| 104 |
| 105 // Check for exit condition of fast recovery |
| 106 if (m_inFastRec && seq < m_recover) |
| 107 { // Partial ACK, partial window deflation (RFC2582 sec.3 bullet #5 paragrap
h 3) |
| 108 m_cWnd += m_segmentSize; // increase cwnd |
| 109 NS_LOG_INFO ("Partial ACK in fast recovery: cwnd set to " << m_cWnd); |
| 110 TcpSocketBase::NewAck(seq); // update m_nextTxSequence and send new data i
f allowed by window |
| 111 DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet |
| 112 return; |
| 113 } |
| 114 else if (m_inFastRec && seq >= m_recover) |
| 115 { // Full ACK (RFC2582 sec.3 bullet #5 paragraph 2, option 1) |
69 m_cWnd = std::min (m_ssThresh, BytesInFlight () + m_segmentSize); | 116 m_cWnd = std::min (m_ssThresh, BytesInFlight () + m_segmentSize); |
70 m_inFastRec = false; | 117 m_inFastRec = false; |
71 } | 118 NS_LOG_INFO ("Received full ACK. Leaving fast recovery with cwnd set to "
<< m_cWnd); |
72 else if (m_inFastRec && seq < m_recover) | 119 } |
73 { // Partial ACK, partial window deflation (RFC2582 sec.3) | 120 |
74 m_cWnd += m_segmentSize; // increase cwnd | 121 // Increase of cwnd based on current phase (slow start or congestion avoidance
) |
75 TcpSocketBase::NewAck(seq); // update m_nextTxSequence | 122 if (m_cWnd < m_ssThresh) |
76 DoRetransmit (); // Retransmit lost packet | 123 { // Slow start mode, add one segSize to cWnd. Default m_ssThresh is 65535.
(RFC2001, sec.1) |
77 SendPendingData (); // Send new data if allowed by window | 124 m_cWnd += m_segmentSize; |
78 return; | 125 NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " <<
m_ssThresh); |
79 } | 126 } |
80 TcpTahoe::NewAck(seq); | 127 else |
81 } | 128 { // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581
, sec.3.1) |
82 | 129 // To increase cwnd for one segSize per RTT, it should be (ackBytes*segSiz
e)/cwnd |
83 /** Cut down cwnd and reset m_nextTxSequence to retransmit upon triple dupack */ | 130 double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWn
d.Get (); |
| 131 adder = std::max (1.0, adder); |
| 132 m_cWnd += static_cast<uint32_t> (adder); |
| 133 NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " <<
m_ssThresh); |
| 134 } |
| 135 |
| 136 // Complete newAck processing |
| 137 TcpSocketBase::NewAck (seq); |
| 138 } |
| 139 |
| 140 /** Cut cwnd and enter fast recovery mode upon triple dupack */ |
84 void | 141 void |
85 TcpNewReno::DupAck (const TcpHeader& t, uint32_t count) | 142 TcpNewReno::DupAck (const TcpHeader& t, uint32_t count) |
86 { | 143 { |
87 if (count == 3) | 144 if (count == 3 && ! m_inFastRec) |
88 { // triple duplicate ack triggers fast retransmit (RFC2582 sec.3) | 145 { // triple duplicate ack triggers fast retransmit (RFC2582 sec.3 bullet #1) |
89 m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2); | 146 m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2); |
90 m_cWnd = m_ssThresh + 3 * m_segmentSize; | 147 m_cWnd = m_ssThresh + 3 * m_segmentSize; |
91 if (!m_inFastRec) | 148 m_recover = m_highTxMark; |
92 { | 149 m_inFastRec = true; |
93 m_recover = m_nextTxSequence; | 150 NS_LOG_INFO ("Triple dupack. Enter fast recovery mode. Reset cwnd to " <<
m_cWnd << |
94 m_inFastRec = true; | 151 ", ssthresh to " << m_ssThresh << " at fast recovery seqnum
" << m_recover); |
95 } | |
96 DoRetransmit (); | 152 DoRetransmit (); |
97 } | 153 } |
98 else if (m_inFastRec) | 154 else if (m_inFastRec) |
99 { // Increase cwnd for every additional dupack (RFC2582, sec.3) | 155 { // Increase cwnd for every additional dupack (RFC2582, sec.3 bullet #3) |
100 m_cWnd += m_segmentSize; | 156 m_cWnd += m_segmentSize; |
| 157 NS_LOG_INFO ("Dupack in fast recovery mode. Increase cwnd to " << m_cWnd); |
101 SendPendingData (m_connected); | 158 SendPendingData (m_connected); |
102 }; | 159 }; |
103 } | 160 } |
104 | 161 |
| 162 /** Retransmit timeout */ |
| 163 void |
| 164 TcpNewReno::Retransmit (void) |
| 165 { |
| 166 NS_LOG_FUNCTION (this); |
| 167 NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().Get
Seconds ()); |
| 168 m_inFastRec = false; |
| 169 |
| 170 // If erroneous timeout in closed/timed-wait state, just return |
| 171 if (m_state == CLOSED || m_state == TIME_WAIT) return; |
| 172 // If all data are received, just return |
| 173 if (m_txBuffer.HeadSequence () >= m_nextTxSequence) return; |
| 174 |
| 175 // According to RFC2581 sec.3.1, upon RTO, ssthresh is set to half of flight |
| 176 // size and cwnd is set to 1*MSS, then the lost packet is retransmitted and |
| 177 // TCP back to slow start |
| 178 m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2); |
| 179 m_cWnd = m_segmentSize; |
| 180 m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack |
| 181 NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd << |
| 182 ", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_
nextTxSequence); |
| 183 m_rtt->IncreaseMultiplier (); // Double the next RTO |
| 184 DoRetransmit (); // Retransmit the packet |
| 185 } |
| 186 |
| 187 void |
| 188 TcpNewReno::SetSegSize (uint32_t size) |
| 189 { |
| 190 NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpNewReno::SetSegSize() cannot chang
e segment size after connection started."); |
| 191 m_segmentSize = size; |
| 192 m_cWnd = m_initialCWnd * m_segmentSize; |
| 193 } |
| 194 |
| 195 void |
| 196 TcpNewReno::SetSSThresh (uint32_t threshold) |
| 197 { |
| 198 m_ssThresh = threshold; |
| 199 } |
| 200 |
| 201 uint32_t |
| 202 TcpNewReno::GetSSThresh (void) const |
| 203 { |
| 204 return m_ssThresh; |
| 205 } |
| 206 |
| 207 void |
| 208 TcpNewReno::SetInitialCwnd (uint32_t cwnd) |
| 209 { |
| 210 NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpNewReno::SetInitialCwnd() cannot c
hange initial cwnd after connection started."); |
| 211 m_initialCWnd = cwnd; |
| 212 m_cWnd = m_initialCWnd * m_segmentSize; |
| 213 } |
| 214 |
| 215 uint32_t |
| 216 TcpNewReno::GetInitialCwnd (void) const |
| 217 { |
| 218 return m_initialCWnd; |
| 219 } |
| 220 |
105 } // namespace ns3 | 221 } // namespace ns3 |
LEFT | RIGHT |