A Discrete-Event Network Simulator
API
tcp-veno.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 ResiliNets, ITTC, University of Kansas
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Truc Anh N. Nguyen <annguyen@ittc.ku.edu>
18  *
19  * James P.G. Sterbenz <jpgs@ittc.ku.edu>, director
20  * ResiliNets Research Group https://resilinets.org/
21  * Information and Telecommunication Technology Center (ITTC)
22  * and Department of Electrical Engineering and Computer Science
23  * The University of Kansas Lawrence, KS USA.
24  */
25 
26 #include "tcp-veno.h"
27 
28 #include "tcp-socket-state.h"
29 
30 #include "ns3/log.h"
31 
32 namespace ns3
33 {
34 
35 NS_LOG_COMPONENT_DEFINE("TcpVeno");
37 
38 TypeId
40 {
41  static TypeId tid = TypeId("ns3::TcpVeno")
43  .AddConstructor<TcpVeno>()
44  .SetGroupName("Internet")
45  .AddAttribute("Beta",
46  "Threshold for congestion detection",
47  UintegerValue(3),
49  MakeUintegerChecker<uint32_t>());
50  return tid;
51 }
52 
54  : TcpNewReno(),
55  m_baseRtt(Time::Max()),
56  m_minRtt(Time::Max()),
57  m_cntRtt(0),
58  m_doingVenoNow(true),
59  m_diff(0),
60  m_inc(true),
61  m_ackCnt(0),
62  m_beta(6)
63 {
64  NS_LOG_FUNCTION(this);
65 }
66 
68  : TcpNewReno(sock),
69  m_baseRtt(sock.m_baseRtt),
70  m_minRtt(sock.m_minRtt),
71  m_cntRtt(sock.m_cntRtt),
72  m_doingVenoNow(true),
73  m_diff(0),
74  m_inc(true),
75  m_ackCnt(sock.m_ackCnt),
76  m_beta(sock.m_beta)
77 {
78  NS_LOG_FUNCTION(this);
79 }
80 
82 {
83  NS_LOG_FUNCTION(this);
84 }
85 
88 {
89  return CopyObject<TcpVeno>(this);
90 }
91 
92 void
93 TcpVeno::PktsAcked(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked, const Time& rtt)
94 {
95  NS_LOG_FUNCTION(this << tcb << segmentsAcked << rtt);
96 
97  if (rtt.IsZero())
98  {
99  return;
100  }
101 
102  m_minRtt = std::min(m_minRtt, rtt);
103  NS_LOG_DEBUG("Updated m_minRtt= " << m_minRtt);
104 
105  m_baseRtt = std::min(m_baseRtt, rtt);
106  NS_LOG_DEBUG("Updated m_baseRtt= " << m_baseRtt);
107 
108  // Update RTT counter
109  m_cntRtt++;
110  NS_LOG_DEBUG("Updated m_cntRtt= " << m_cntRtt);
111 }
112 
113 void
115 {
116  NS_LOG_FUNCTION(this);
117 
118  m_doingVenoNow = true;
119  m_minRtt = Time::Max();
120 }
121 
122 void
124 {
125  NS_LOG_FUNCTION(this);
126 
127  m_doingVenoNow = false;
128 }
129 
130 void
132 {
133  NS_LOG_FUNCTION(this << tcb << newState);
134  if (newState == TcpSocketState::CA_OPEN)
135  {
136  EnableVeno();
137  NS_LOG_LOGIC("Veno is now on.");
138  }
139  else
140  {
141  DisableVeno();
142  NS_LOG_LOGIC("Veno is turned off.");
143  }
144 }
145 
146 void
147 TcpVeno::IncreaseWindow(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
148 {
149  NS_LOG_FUNCTION(this << tcb << segmentsAcked);
150 
151  // Always calculate m_diff, even if we are not doing Veno now
152  uint32_t targetCwnd;
153  uint32_t segCwnd = tcb->GetCwndInSegments();
154 
155  /*
156  * Calculate the cwnd we should have. baseRtt is the minimum RTT
157  * per-connection, minRtt is the minimum RTT in this window
158  *
159  * little trick:
160  * desidered throughput is currentCwnd * baseRtt
161  * target cwnd is throughput / minRtt
162  */
163  double tmp = m_baseRtt.GetSeconds() / m_minRtt.GetSeconds();
164  targetCwnd = static_cast<uint32_t>(segCwnd * tmp);
165  NS_LOG_DEBUG("Calculated targetCwnd = " << targetCwnd);
166  NS_ASSERT(segCwnd >= targetCwnd); // implies baseRtt <= minRtt
167 
168  // Calculate the difference between actual and target cwnd
169  m_diff = segCwnd - targetCwnd;
170  NS_LOG_DEBUG("Calculated m_diff = " << m_diff);
171 
172  if (!m_doingVenoNow)
173  {
174  // If Veno is not on, we follow NewReno algorithm
175  NS_LOG_LOGIC("Veno is not turned on, we follow NewReno algorithm.");
176  TcpNewReno::IncreaseWindow(tcb, segmentsAcked);
177  return;
178  }
179 
180  // We do the Veno calculations only if we got enough RTT samples
181  if (m_cntRtt <= 2)
182  { // We do not have enough RTT samples, so we should behave like NewReno
183  NS_LOG_LOGIC("We do not have enough RTT samples to perform Veno "
184  "calculations, we behave like NewReno.");
185  TcpNewReno::IncreaseWindow(tcb, segmentsAcked);
186  }
187  else
188  {
189  NS_LOG_LOGIC("We have enough RTT samples to perform Veno calculations.");
190 
191  if (tcb->m_cWnd < tcb->m_ssThresh)
192  { // Slow start mode. Veno employs same slow start algorithm as NewReno's.
193  NS_LOG_LOGIC("We are in slow start, behave like NewReno.");
194  TcpNewReno::SlowStart(tcb, segmentsAcked);
195  }
196  else
197  { // Congestion avoidance mode
198  NS_LOG_LOGIC("We are in congestion avoidance, execute Veno additive "
199  "increase algo.");
200 
201  if (m_diff < m_beta)
202  {
203  // Available bandwidth is not fully utilized,
204  // increase cwnd by 1 every RTT
205  NS_LOG_LOGIC("Available bandwidth not fully utilized, increase "
206  "cwnd by 1 every RTT");
207  TcpNewReno::CongestionAvoidance(tcb, segmentsAcked);
208  }
209  else
210  {
211  // Available bandwidth is fully utilized,
212  // increase cwnd by 1 every other RTT
213  NS_LOG_LOGIC("Available bandwidth fully utilized, increase cwnd "
214  "by 1 every other RTT");
215  if (m_inc)
216  {
217  TcpNewReno::CongestionAvoidance(tcb, segmentsAcked);
218  m_inc = false;
219  }
220  else
221  {
222  m_inc = true;
223  }
224  }
225  }
226  }
227 
228  // Reset cntRtt & minRtt every RTT
229  m_cntRtt = 0;
230  m_minRtt = Time::Max();
231 }
232 
233 std::string
235 {
236  return "TcpVeno";
237 }
238 
239 uint32_t
241 {
242  NS_LOG_FUNCTION(this << tcb << bytesInFlight);
243 
244  if (m_diff < m_beta)
245  {
246  // random loss due to bit errors is most likely to have occurred,
247  // we cut cwnd by 1/5
248  NS_LOG_LOGIC("Random loss is most likely to have occurred, "
249  "cwnd is reduced by 1/5");
250  static double tmp = 4.0 / 5.0;
251  return std::max(static_cast<uint32_t>(bytesInFlight * tmp), 2 * tcb->m_segmentSize);
252  }
253  else
254  {
255  // congestion-based loss is most likely to have occurred,
256  // we reduce cwnd by 1/2 as in NewReno
257  NS_LOG_LOGIC("Congestive loss is most likely to have occurred, "
258  "cwnd is halved");
259  return TcpNewReno::GetSsThresh(tcb, bytesInFlight);
260  }
261 }
262 
263 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
The NewReno implementation.
virtual uint32_t SlowStart(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked)
Tcp NewReno slow start algorithm.
virtual void CongestionAvoidance(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked)
NewReno congestion avoidance.
uint32_t GetSsThresh(Ptr< const TcpSocketState > tcb, uint32_t bytesInFlight) override
Get the slow start threshold after a loss event.
void IncreaseWindow(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked) override
Try to increase the cWnd following the NewReno specification.
uint32_t GetCwndInSegments() const
Get cwnd in segments rather than bytes.
TcpCongState_t
Definition of the Congestion state machine.
@ CA_OPEN
Normal state, no dubious events.
TracedValue< uint32_t > m_cWnd
Congestion window.
TracedValue< uint32_t > m_ssThresh
Slow start threshold.
An implementation of TCP Veno.
Definition: tcp-veno.h:72
std::string GetName() const override
Get the name of the congestion control algorithm.
Definition: tcp-veno.cc:234
bool m_inc
If true, cwnd needs to be incremented.
Definition: tcp-veno.h:167
void PktsAcked(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked, const Time &rtt) override
Perform RTT sampling needed to execute Veno algorithm.
Definition: tcp-veno.cc:93
uint32_t GetSsThresh(Ptr< const TcpSocketState > tcb, uint32_t bytesInFlight) override
Get slow start threshold during Veno multiplicative-decrease phase.
Definition: tcp-veno.cc:240
uint32_t m_cntRtt
Number of RTT measurements during last RTT.
Definition: tcp-veno.h:164
static TypeId GetTypeId()
Get the type ID.
Definition: tcp-veno.cc:39
void EnableVeno()
Enable Veno algorithm to start Veno sampling.
Definition: tcp-veno.cc:114
void IncreaseWindow(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked) override
Adjust cwnd following Veno additive increase algorithm.
Definition: tcp-veno.cc:147
Time m_minRtt
Minimum of RTTs measured within last RTT.
Definition: tcp-veno.h:163
bool m_doingVenoNow
If true, do Veno for this RTT.
Definition: tcp-veno.h:165
uint32_t m_beta
Threshold for congestion detection.
Definition: tcp-veno.h:169
void DisableVeno()
Turn off Veno.
Definition: tcp-veno.cc:123
void CongestionStateSet(Ptr< TcpSocketState > tcb, const TcpSocketState::TcpCongState_t newState) override
Enable/disable Veno depending on the congestion state.
Definition: tcp-veno.cc:131
~TcpVeno() override
Definition: tcp-veno.cc:81
TcpVeno()
Create an unbound tcp socket.
Definition: tcp-veno.cc:53
uint32_t m_diff
Difference between expected and actual throughput.
Definition: tcp-veno.h:166
Ptr< TcpCongestionOps > Fork() override
Copy the congestion control algorithm across sockets.
Definition: tcp-veno.cc:87
Time m_baseRtt
Minimum of all RTT measurements seen during connection.
Definition: tcp-veno.h:162
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition: nstime.h:297
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:315
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Hold an unsigned integer type.
Definition: uinteger.h:45
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46