1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014 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 #include "tcp-hybla.h"
21 #include "tcp-socket-state.h"
22 
23 #include "ns3/log.h"
24 
25 namespace ns3 {
26 
27 NS_LOG_COMPONENT_DEFINE ("TcpHybla");
28 NS_OBJECT_ENSURE_REGISTERED (TcpHybla);
29 
30 TypeId
GetTypeId(void)31 TcpHybla::GetTypeId (void)
32 {
33   static TypeId tid = TypeId ("ns3::TcpHybla")
34     .SetParent<TcpNewReno> ()
35     .AddConstructor<TcpHybla> ()
36     .SetGroupName ("Internet")
37     .AddAttribute ("RRTT", "Reference RTT",
38                    TimeValue (MilliSeconds (50)),
39                    MakeTimeAccessor (&TcpHybla::m_rRtt),
40                    MakeTimeChecker ())
41     .AddTraceSource ("Rho",
42                      "Rho parameter of Hybla",
43                      MakeTraceSourceAccessor (&TcpHybla::m_rho),
44                      "ns3::TracedValueCallback::Double")
45   ;
46   return tid;
47 }
48 
TcpHybla()49 TcpHybla::TcpHybla ()
50   : TcpNewReno (),
51   m_rho (1.0),
52   m_cWndCnt (0)
53 {
54   NS_LOG_FUNCTION (this);
55 }
56 
TcpHybla(const TcpHybla & sock)57 TcpHybla::TcpHybla (const TcpHybla &sock)
58   : TcpNewReno (sock),
59   m_rho (sock.m_rho),
60   m_cWndCnt (sock.m_cWndCnt)
61 {
62   NS_LOG_FUNCTION (this);
63 }
64 
~TcpHybla()65 TcpHybla::~TcpHybla ()
66 {
67   NS_LOG_FUNCTION (this);
68 }
69 
70 void
RecalcParam(const Ptr<TcpSocketState> & tcb)71 TcpHybla::RecalcParam (const Ptr<TcpSocketState> &tcb)
72 {
73   NS_LOG_FUNCTION (this);
74 
75   m_rho = std::max ((double) tcb->m_minRtt.GetMilliSeconds () / m_rRtt.GetMilliSeconds (), 1.0);
76 
77   NS_ASSERT (m_rho > 0.0);
78   NS_LOG_DEBUG ("Calculated rho=" << m_rho);
79 }
80 
81 void
PktsAcked(Ptr<TcpSocketState> tcb,uint32_t segmentsAcked,const Time & rtt)82 TcpHybla::PktsAcked (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked,
83                      const Time &rtt)
84 {
85   NS_LOG_FUNCTION (this << tcb << segmentsAcked << rtt);
86 
87   if (rtt == tcb->m_minRtt)
88     {
89       RecalcParam (tcb);
90       NS_LOG_DEBUG ("min rtt seen: " << rtt);
91     }
92 }
93 
94 uint32_t
SlowStart(Ptr<TcpSocketState> tcb,uint32_t segmentsAcked)95 TcpHybla::SlowStart (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
96 {
97   NS_LOG_FUNCTION (this << tcb << segmentsAcked);
98 
99   NS_ASSERT (tcb->m_cWnd <= tcb->m_ssThresh);
100 
101   if (segmentsAcked >= 1)
102     {
103       /*
104        * slow start
105        * INC = 2^RHO - 1
106        */
107 
108       double increment = std::pow (2, m_rho) - 1.0;
109       uint32_t incr = static_cast<uint32_t> (increment * tcb->m_segmentSize);
110       NS_LOG_INFO ("Slow start: inc=" << increment);
111 
112       tcb->m_cWnd = std::min (tcb->m_cWnd + incr, tcb->m_ssThresh);
113 
114       NS_LOG_INFO ("In SlowStart, updated to cwnd " << tcb->m_cWnd <<
115                    " ssthresh " << tcb->m_ssThresh <<
116                    " with an increment of " << increment * tcb->m_segmentSize);
117 
118       return segmentsAcked - 1;
119     }
120 
121   return 0;
122 }
123 
124 void
CongestionAvoidance(Ptr<TcpSocketState> tcb,uint32_t segmentsAcked)125 TcpHybla::CongestionAvoidance (Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
126 {
127   NS_LOG_FUNCTION (this << tcb << segmentsAcked);
128 
129   uint32_t segCwnd;
130   double increment;
131 
132   while (segmentsAcked > 0)
133     {
134       /*
135        * congestion avoidance
136        * INC = RHO^2 / W
137        */
138       segCwnd = tcb->GetCwndInSegments ();
139       increment = std::pow (m_rho, 2) / static_cast<double> (segCwnd);
140 
141       m_cWndCnt += increment;
142       segmentsAcked -= 1;
143     }
144 
145   if (m_cWndCnt >= 1.0)
146     {
147       // double to int truncates every time.
148       uint32_t inc = static_cast<uint32_t> (m_cWndCnt);
149       m_cWndCnt -= inc;
150 
151       NS_ASSERT (m_cWndCnt >= 0.0);
152 
153       /* This leaves space for a tcp pacing implementation; it would be easy
154          to setup a limit on the maximum increment of the cWnd per ACK received.
155          The remaining increment is leaved for the next ACK. */
156 
157       tcb->m_cWnd += inc * tcb->m_segmentSize;
158 
159 
160       NS_LOG_INFO ("In CongAvoid, updated to cwnd " << tcb->m_cWnd <<
161                    " ssthresh " << tcb->m_ssThresh <<
162                    " with an increment of " << inc * tcb->m_segmentSize);
163     }
164 }
165 
166 Ptr<TcpCongestionOps>
Fork(void)167 TcpHybla::Fork (void)
168 {
169   return CopyObject<TcpHybla> (this);
170 }
171 
172 std::string
GetName() const173 TcpHybla::GetName () const
174 {
175   return "TcpHybla";
176 }
177 
178 
179 } // namespace ns3
180