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