1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * Copyright (c) 2016 NITK Surathkal
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 * Author: Ankit Deepak <adadeepak8@gmail.com>
19 *
20 */
21
22 #include "tcp-ledbat.h"
23 #include "tcp-socket-state.h"
24
25 #include "ns3/log.h"
26 #include "ns3/simulator.h" // Now ()
27
28 namespace ns3 {
29
30 NS_LOG_COMPONENT_DEFINE ("TcpLedbat");
31 NS_OBJECT_ENSURE_REGISTERED (TcpLedbat);
32
33 TypeId
GetTypeId(void)34 TcpLedbat::GetTypeId (void)
35 {
36 static TypeId tid = TypeId ("ns3::TcpLedbat")
37 .SetParent<TcpNewReno> ()
38 .AddConstructor<TcpLedbat> ()
39 .SetGroupName ("Internet")
40 .AddAttribute ("TargetDelay",
41 "Targeted Queue Delay",
42 TimeValue (MilliSeconds (100)),
43 MakeTimeAccessor (&TcpLedbat::m_target),
44 MakeTimeChecker ())
45 .AddAttribute ("BaseHistoryLen",
46 "Number of Base delay samples",
47 UintegerValue (10),
48 MakeUintegerAccessor (&TcpLedbat::m_baseHistoLen),
49 MakeUintegerChecker<uint32_t> ())
50 .AddAttribute ("NoiseFilterLen",
51 "Number of Current delay samples",
52 UintegerValue (4),
53 MakeUintegerAccessor (&TcpLedbat::m_noiseFilterLen),
54 MakeUintegerChecker<uint32_t> ())
55 .AddAttribute ("Gain",
56 "Offset Gain",
57 DoubleValue (1.0),
58 MakeDoubleAccessor (&TcpLedbat::m_gain),
59 MakeDoubleChecker<double> ())
60 .AddAttribute ("SSParam",
61 "Possibility of Slow Start",
62 EnumValue (DO_SLOWSTART),
63 MakeEnumAccessor (&TcpLedbat::SetDoSs),
64 MakeEnumChecker (DO_SLOWSTART, "yes",
65 DO_NOT_SLOWSTART, "no"))
66 .AddAttribute ("MinCwnd",
67 "Minimum cWnd for Ledbat",
68 UintegerValue (2),
69 MakeUintegerAccessor (&TcpLedbat::m_minCwnd),
70 MakeUintegerChecker<uint32_t> ())
71 ;
72 return tid;
73 }
74
SetDoSs(SlowStartType doSS)75 void TcpLedbat::SetDoSs (SlowStartType doSS)
76 {
77 NS_LOG_FUNCTION (this << doSS);
78 m_doSs = doSS;
79 if (m_doSs)
80 {
81 m_flag |= LEDBAT_CAN_SS;
82 }
83 else
84 {
85 m_flag &= ~LEDBAT_CAN_SS;
86 }
87 }
88
TcpLedbat(void)89 TcpLedbat::TcpLedbat (void)
90 : TcpNewReno ()
91 {
92 NS_LOG_FUNCTION (this);
93 m_target = MilliSeconds (100);
94 m_gain = 1;
95 m_doSs = DO_SLOWSTART;
96 m_baseHistoLen = 10;
97 m_noiseFilterLen = 4;
98 InitCircBuf (m_baseHistory);
99 InitCircBuf (m_noiseFilter);
100 m_lastRollover = 0;
101 m_sndCwndCnt = 0;
102 m_flag = LEDBAT_CAN_SS;
103 m_minCwnd = 2;
104 };
105
InitCircBuf(struct OwdCircBuf & buffer)106 void TcpLedbat::InitCircBuf (struct OwdCircBuf &buffer)
107 {
108 NS_LOG_FUNCTION (this);
109 buffer.buffer.clear ();
110 buffer.min = 0;
111 }
112
TcpLedbat(const TcpLedbat & sock)113 TcpLedbat::TcpLedbat (const TcpLedbat& sock)
114 : TcpNewReno (sock)
115 {
116 NS_LOG_FUNCTION (this);
117 m_target = sock.m_target;
118 m_gain = sock.m_gain;
119 m_doSs = sock.m_doSs;
120 m_baseHistoLen = sock.m_baseHistoLen;
121 m_noiseFilterLen = sock.m_noiseFilterLen;
122 m_baseHistory = sock.m_baseHistory;
123 m_noiseFilter = sock.m_noiseFilter;
124 m_lastRollover = sock.m_lastRollover;
125 m_sndCwndCnt = sock.m_sndCwndCnt;
126 m_flag = sock.m_flag;
127 m_minCwnd = sock.m_minCwnd;
128 }
129
~TcpLedbat(void)130 TcpLedbat::~TcpLedbat (void)
131 {
132 NS_LOG_FUNCTION (this);
133 }
134
135 Ptr<TcpCongestionOps>
Fork(void)136 TcpLedbat::Fork (void)
137 {
138 return CopyObject<TcpLedbat> (this);
139 }
140
141 std::string
GetName() const142 TcpLedbat::GetName () const
143 {
144 return "TcpLedbat";
145 }
146
MinCircBuf(struct OwdCircBuf & b)147 uint32_t TcpLedbat::MinCircBuf (struct OwdCircBuf &b)
148 {
149 NS_LOG_FUNCTION_NOARGS ();
150 if (b.buffer.size () == 0)
151 {
152 return ~0U;
153 }
154 else
155 {
156 return b.buffer[b.min];
157 }
158 }
159
CurrentDelay(FilterFunction filter)160 uint32_t TcpLedbat::CurrentDelay (FilterFunction filter)
161 {
162 NS_LOG_FUNCTION (this);
163 return filter (m_noiseFilter);
164 }
165
BaseDelay()166 uint32_t TcpLedbat::BaseDelay ()
167 {
168 NS_LOG_FUNCTION (this);
169 return MinCircBuf (m_baseHistory);
170 }
171
IncreaseWindow(Ptr<TcpSocketState> tcb,uint32_t segmentsAcked)172 void TcpLedbat::IncreaseWindow (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
173 {
174 NS_LOG_FUNCTION (this << tcb << segmentsAcked);
175 if (tcb->m_cWnd.Get () <= tcb->m_segmentSize)
176 {
177 m_flag |= LEDBAT_CAN_SS;
178 }
179 if (m_doSs == DO_SLOWSTART && tcb->m_cWnd <= tcb->m_ssThresh && (m_flag & LEDBAT_CAN_SS))
180 {
181 SlowStart (tcb, segmentsAcked);
182 }
183 else
184 {
185 m_flag &= ~LEDBAT_CAN_SS;
186 CongestionAvoidance (tcb, segmentsAcked);
187 }
188 }
189
CongestionAvoidance(Ptr<TcpSocketState> tcb,uint32_t segmentsAcked)190 void TcpLedbat::CongestionAvoidance (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
191 {
192 NS_LOG_FUNCTION (this << tcb << segmentsAcked);
193 if ((m_flag & LEDBAT_VALID_OWD) == 0)
194 {
195 TcpNewReno::CongestionAvoidance (tcb, segmentsAcked); //letting it fall to TCP behaviour if no timestamps
196 return;
197 }
198 int64_t queue_delay;
199 double offset;
200 uint32_t cwnd = (tcb->m_cWnd.Get ());
201 uint32_t max_cwnd;
202 uint64_t current_delay = CurrentDelay (&TcpLedbat::MinCircBuf);
203 uint64_t base_delay = BaseDelay ();
204
205 if (current_delay > base_delay)
206 {
207 queue_delay = static_cast<int64_t> (current_delay - base_delay);
208 offset = m_target.GetMilliSeconds () - queue_delay;
209 }
210 else
211 {
212 queue_delay = static_cast<int64_t> (base_delay - current_delay);
213 offset = m_target.GetMilliSeconds () + queue_delay;
214 }
215 offset *= m_gain;
216 m_sndCwndCnt = static_cast<int32_t> (offset * segmentsAcked * tcb->m_segmentSize);
217 double inc = (m_sndCwndCnt * 1.0) / (m_target.GetMilliSeconds () * tcb->m_cWnd.Get ());
218 cwnd += (inc * tcb->m_segmentSize);
219
220 max_cwnd = static_cast<uint32_t>(tcb->m_highTxMark.Get () - tcb->m_lastAckedSeq) + segmentsAcked * tcb->m_segmentSize;
221 cwnd = std::min (cwnd, max_cwnd);
222 cwnd = std::max (cwnd, m_minCwnd * tcb->m_segmentSize);
223 tcb->m_cWnd = cwnd;
224
225 if (tcb->m_cWnd <= tcb->m_ssThresh)
226 {
227 tcb->m_ssThresh = tcb->m_cWnd - 1;
228 }
229 }
230
AddDelay(struct OwdCircBuf & cb,uint32_t owd,uint32_t maxlen)231 void TcpLedbat::AddDelay (struct OwdCircBuf &cb, uint32_t owd, uint32_t maxlen)
232 {
233 NS_LOG_FUNCTION (this << owd << maxlen << cb.buffer.size ());
234 if (cb.buffer.size () == 0)
235 {
236 NS_LOG_LOGIC ("First Value for queue");
237 cb.buffer.push_back (owd);
238 cb.min = 0;
239 return;
240 }
241 cb.buffer.push_back (owd);
242 if (cb.buffer[cb.min] > owd)
243 {
244 cb.min = static_cast<uint32_t> (cb.buffer.size () - 1);
245 }
246 if (cb.buffer.size () >= maxlen)
247 {
248 NS_LOG_LOGIC ("Queue full" << maxlen);
249 cb.buffer.erase (cb.buffer.begin ());
250 cb.min = 0;
251 NS_LOG_LOGIC ("Current min element" << cb.buffer[cb.min]);
252 for (uint32_t i = 1; i < maxlen - 1; i++)
253 {
254 if (cb.buffer[i] < cb.buffer[cb.min])
255 {
256 cb.min = i;
257 }
258 }
259 }
260 }
261
UpdateBaseDelay(uint32_t owd)262 void TcpLedbat::UpdateBaseDelay (uint32_t owd)
263 {
264 NS_LOG_FUNCTION (this << owd );
265 if (m_baseHistory.buffer.size () == 0)
266 {
267 AddDelay (m_baseHistory, owd, m_baseHistoLen);
268 return;
269 }
270 uint64_t timestamp = static_cast<uint64_t> (Simulator::Now ().GetSeconds ());
271
272 if (timestamp - m_lastRollover > 60)
273 {
274 m_lastRollover = timestamp;
275 AddDelay (m_baseHistory, owd, m_baseHistoLen);
276 }
277 else
278 {
279 uint32_t last = static_cast<uint32_t> (m_baseHistory.buffer.size () - 1);
280 if (owd < m_baseHistory.buffer[last])
281 {
282 m_baseHistory.buffer[last] = owd;
283 if (owd < m_baseHistory.buffer[m_baseHistory.min])
284 {
285 m_baseHistory.min = last;
286 }
287 }
288 }
289 }
290
PktsAcked(Ptr<TcpSocketState> tcb,uint32_t segmentsAcked,const Time & rtt)291 void TcpLedbat::PktsAcked (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked,
292 const Time& rtt)
293 {
294 NS_LOG_FUNCTION (this << tcb << segmentsAcked << rtt);
295 if (tcb->m_rcvTimestampValue == 0 || tcb->m_rcvTimestampEchoReply == 0)
296 {
297 m_flag &= ~LEDBAT_VALID_OWD;
298 }
299 else
300 {
301 m_flag |= LEDBAT_VALID_OWD;
302 }
303 if (rtt.IsPositive ())
304 {
305 AddDelay (m_noiseFilter, tcb->m_rcvTimestampValue - tcb->m_rcvTimestampEchoReply, m_noiseFilterLen);
306 UpdateBaseDelay (tcb->m_rcvTimestampValue - tcb->m_rcvTimestampEchoReply);
307 }
308 }
309
310 } // namespace ns3
311