A Discrete-Event Network Simulator
API
tcp-vegas.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-vegas.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("TcpVegas");
37 
38 TypeId
40 {
41  static TypeId tid = TypeId("ns3::TcpVegas")
43  .AddConstructor<TcpVegas>()
44  .SetGroupName("Internet")
45  .AddAttribute("Alpha",
46  "Lower bound of packets in network",
47  UintegerValue(2),
49  MakeUintegerChecker<uint32_t>())
50  .AddAttribute("Beta",
51  "Upper bound of packets in network",
52  UintegerValue(4),
54  MakeUintegerChecker<uint32_t>())
55  .AddAttribute("Gamma",
56  "Limit on increase",
57  UintegerValue(1),
59  MakeUintegerChecker<uint32_t>());
60  return tid;
61 }
62 
64  : TcpNewReno(),
65  m_alpha(2),
66  m_beta(4),
67  m_gamma(1),
68  m_baseRtt(Time::Max()),
69  m_minRtt(Time::Max()),
70  m_cntRtt(0),
71  m_doingVegasNow(true),
72  m_begSndNxt(0)
73 {
74  NS_LOG_FUNCTION(this);
75 }
76 
78  : TcpNewReno(sock),
79  m_alpha(sock.m_alpha),
80  m_beta(sock.m_beta),
81  m_gamma(sock.m_gamma),
82  m_baseRtt(sock.m_baseRtt),
83  m_minRtt(sock.m_minRtt),
84  m_cntRtt(sock.m_cntRtt),
85  m_doingVegasNow(true),
86  m_begSndNxt(0)
87 {
88  NS_LOG_FUNCTION(this);
89 }
90 
92 {
93  NS_LOG_FUNCTION(this);
94 }
95 
98 {
99  return CopyObject<TcpVegas>(this);
100 }
101 
102 void
103 TcpVegas::PktsAcked(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked, const Time& rtt)
104 {
105  NS_LOG_FUNCTION(this << tcb << segmentsAcked << rtt);
106 
107  if (rtt.IsZero())
108  {
109  return;
110  }
111 
112  m_minRtt = std::min(m_minRtt, rtt);
113  NS_LOG_DEBUG("Updated m_minRtt = " << m_minRtt);
114 
115  m_baseRtt = std::min(m_baseRtt, rtt);
116  NS_LOG_DEBUG("Updated m_baseRtt = " << m_baseRtt);
117 
118  // Update RTT counter
119  m_cntRtt++;
120  NS_LOG_DEBUG("Updated m_cntRtt = " << m_cntRtt);
121 }
122 
123 void
125 {
126  NS_LOG_FUNCTION(this << tcb);
127 
128  m_doingVegasNow = true;
130  m_cntRtt = 0;
131  m_minRtt = Time::Max();
132 }
133 
134 void
136 {
137  NS_LOG_FUNCTION(this);
138 
139  m_doingVegasNow = false;
140 }
141 
142 void
144 {
145  NS_LOG_FUNCTION(this << tcb << newState);
146  if (newState == TcpSocketState::CA_OPEN)
147  {
148  EnableVegas(tcb);
149  }
150  else
151  {
152  DisableVegas();
153  }
154 }
155 
156 void
157 TcpVegas::IncreaseWindow(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
158 {
159  NS_LOG_FUNCTION(this << tcb << segmentsAcked);
160 
161  if (!m_doingVegasNow)
162  {
163  // If Vegas is not on, we follow NewReno algorithm
164  NS_LOG_LOGIC("Vegas is not turned on, we follow NewReno algorithm.");
165  TcpNewReno::IncreaseWindow(tcb, segmentsAcked);
166  return;
167  }
168 
169  if (tcb->m_lastAckedSeq >= m_begSndNxt)
170  { // A Vegas cycle has finished, we do Vegas cwnd adjustment every RTT.
171 
172  NS_LOG_LOGIC("A Vegas cycle has finished, we adjust cwnd once per RTT.");
173 
174  // Save the current right edge for next Vegas cycle
176 
177  /*
178  * We perform Vegas calculations only if we got enough RTT samples to
179  * insure that at least 1 of those samples wasn't from a delayed ACK.
180  */
181  if (m_cntRtt <= 2)
182  { // We do not have enough RTT samples, so we should behave like Reno
183  NS_LOG_LOGIC(
184  "We do not have enough RTT samples to do Vegas, so we behave like NewReno.");
185  TcpNewReno::IncreaseWindow(tcb, segmentsAcked);
186  }
187  else
188  {
189  NS_LOG_LOGIC("We have enough RTT samples to perform Vegas calculations");
190  /*
191  * We have enough RTT samples to perform Vegas algorithm.
192  * Now we need to determine if cwnd should be increased or decreased
193  * based on the calculated difference between the expected rate and actual sending
194  * rate and the predefined thresholds (alpha, beta, and gamma).
195  */
196  uint32_t diff;
197  uint32_t targetCwnd;
198  uint32_t segCwnd = tcb->GetCwndInSegments();
199 
200  /*
201  * Calculate the cwnd we should have. baseRtt is the minimum RTT
202  * per-connection, minRtt is the minimum RTT in this window
203  *
204  * little trick:
205  * desidered throughput is currentCwnd * baseRtt
206  * target cwnd is throughput / minRtt
207  */
208  double tmp = m_baseRtt.GetSeconds() / m_minRtt.GetSeconds();
209  targetCwnd = static_cast<uint32_t>(segCwnd * tmp);
210  NS_LOG_DEBUG("Calculated targetCwnd = " << targetCwnd);
211  NS_ASSERT(segCwnd >= targetCwnd); // implies baseRtt <= minRtt
212 
213  /*
214  * Calculate the difference between the expected cWnd and
215  * the actual cWnd
216  */
217  diff = segCwnd - targetCwnd;
218  NS_LOG_DEBUG("Calculated diff = " << diff);
219 
220  if (diff > m_gamma && (tcb->m_cWnd < tcb->m_ssThresh))
221  {
222  /*
223  * We are going too fast. We need to slow down and change from
224  * slow-start to linear increase/decrease mode by setting cwnd
225  * to target cwnd. We add 1 because of the integer truncation.
226  */
227  NS_LOG_LOGIC("We are going too fast. We need to slow down and "
228  "change to linear increase/decrease mode.");
229  segCwnd = std::min(segCwnd, targetCwnd + 1);
230  tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
231  tcb->m_ssThresh = GetSsThresh(tcb, 0);
232  NS_LOG_DEBUG("Updated cwnd = " << tcb->m_cWnd << " ssthresh=" << tcb->m_ssThresh);
233  }
234  else if (tcb->m_cWnd < tcb->m_ssThresh)
235  { // Slow start mode
236  NS_LOG_LOGIC("We are in slow start and diff < m_gamma, so we "
237  "follow NewReno slow start");
238  TcpNewReno::SlowStart(tcb, segmentsAcked);
239  }
240  else
241  { // Linear increase/decrease mode
242  NS_LOG_LOGIC("We are in linear increase/decrease mode");
243  if (diff > m_beta)
244  {
245  // We are going too fast, so we slow down
246  NS_LOG_LOGIC("We are going too fast, so we slow down by decrementing cwnd");
247  segCwnd--;
248  tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
249  tcb->m_ssThresh = GetSsThresh(tcb, 0);
250  NS_LOG_DEBUG("Updated cwnd = " << tcb->m_cWnd
251  << " ssthresh=" << tcb->m_ssThresh);
252  }
253  else if (diff < m_alpha)
254  {
255  // We are going too slow (having too little data in the network),
256  // so we speed up.
257  NS_LOG_LOGIC("We are going too slow, so we speed up by incrementing cwnd");
258  segCwnd++;
259  tcb->m_cWnd = segCwnd * tcb->m_segmentSize;
260  NS_LOG_DEBUG("Updated cwnd = " << tcb->m_cWnd
261  << " ssthresh=" << tcb->m_ssThresh);
262  }
263  else
264  {
265  // We are going at the right speed
266  NS_LOG_LOGIC("We are sending at the right speed");
267  }
268  }
269  tcb->m_ssThresh = std::max(tcb->m_ssThresh, 3 * tcb->m_cWnd / 4);
270  NS_LOG_DEBUG("Updated ssThresh = " << tcb->m_ssThresh);
271  }
272 
273  // Reset cntRtt & minRtt every RTT
274  m_cntRtt = 0;
275  m_minRtt = Time::Max();
276  }
277  else if (tcb->m_cWnd < tcb->m_ssThresh)
278  {
279  TcpNewReno::SlowStart(tcb, segmentsAcked);
280  }
281 }
282 
283 std::string
285 {
286  return "TcpVegas";
287 }
288 
289 uint32_t
291 {
292  NS_LOG_FUNCTION(this << tcb << bytesInFlight);
293  return std::max(std::min(tcb->m_ssThresh.Get(), tcb->m_cWnd.Get() - tcb->m_segmentSize),
294  2 * tcb->m_segmentSize);
295 }
296 
297 } // 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.
void IncreaseWindow(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked) override
Try to increase the cWnd following the NewReno specification.
uint32_t m_segmentSize
Segment size.
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.
SequenceNumber32 m_lastAckedSeq
Last sequence ACKed.
TracedValue< uint32_t > m_cWnd
Congestion window.
TracedValue< SequenceNumber32 > m_nextTxSequence
Next seqnum to be sent (SND.NXT), ReTx pushes it back.
TracedValue< uint32_t > m_ssThresh
Slow start threshold.
An implementation of TCP Vegas.
Definition: tcp-vegas.h:66
uint32_t GetSsThresh(Ptr< const TcpSocketState > tcb, uint32_t bytesInFlight) override
Get slow start threshold following Vegas principle.
Definition: tcp-vegas.cc:290
void DisableVegas()
Stop taking Vegas samples.
Definition: tcp-vegas.cc:135
~TcpVegas() override
Definition: tcp-vegas.cc:91
uint32_t m_cntRtt
Number of RTT measurements during last RTT.
Definition: tcp-vegas.h:162
std::string GetName() const override
Get the name of the congestion control algorithm.
Definition: tcp-vegas.cc:284
Ptr< TcpCongestionOps > Fork() override
Copy the congestion control algorithm across sockets.
Definition: tcp-vegas.cc:97
uint32_t m_alpha
Alpha threshold, lower bound of packets in network.
Definition: tcp-vegas.h:157
uint32_t m_beta
Beta threshold, upper bound of packets in network.
Definition: tcp-vegas.h:158
void IncreaseWindow(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked) override
Adjust cwnd following Vegas linear increase/decrease algorithm.
Definition: tcp-vegas.cc:157
bool m_doingVegasNow
If true, do Vegas for this RTT.
Definition: tcp-vegas.h:163
void EnableVegas(Ptr< TcpSocketState > tcb)
Enable Vegas algorithm to start taking Vegas samples.
Definition: tcp-vegas.cc:124
Time m_minRtt
Minimum of all RTT measurements within last RTT.
Definition: tcp-vegas.h:161
void PktsAcked(Ptr< TcpSocketState > tcb, uint32_t segmentsAcked, const Time &rtt) override
Compute RTTs needed to execute Vegas algorithm.
Definition: tcp-vegas.cc:103
void CongestionStateSet(Ptr< TcpSocketState > tcb, const TcpSocketState::TcpCongState_t newState) override
Enable/disable Vegas algorithm depending on the congestion state.
Definition: tcp-vegas.cc:143
TcpVegas()
Create an unbound tcp socket.
Definition: tcp-vegas.cc:63
Time m_baseRtt
Minimum of all Vegas RTT measurements seen during connection.
Definition: tcp-vegas.h:160
uint32_t m_gamma
Gamma threshold, limit on increase.
Definition: tcp-vegas.h:159
static TypeId GetTypeId()
Get the type ID.
Definition: tcp-vegas.cc:39
SequenceNumber32 m_begSndNxt
Right edge during last RTT.
Definition: tcp-vegas.h:164
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