A Discrete-Event Network Simulator
API
fq-codel-queue-disc.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2016 Universita' degli Studi di Napoli Federico II
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  * Authors: Pasquale Imputato <p.imputato@gmail.com>
19  * Stefano Avallone <stefano.avallone@unina.it>
20 */
21 
22 #include "ns3/log.h"
23 #include "ns3/string.h"
24 #include "fq-codel-queue-disc.h"
25 
26 namespace ns3 {
27 
28 NS_LOG_COMPONENT_DEFINE ("FqCoDelQueueDisc");
29 
30 NS_OBJECT_ENSURE_REGISTERED (FqCoDelFlow);
31 
33 {
34  static TypeId tid = TypeId ("ns3::FqCoDelFlow")
36  .SetGroupName ("TrafficControl")
37  .AddConstructor<FqCoDelFlow> ()
38  ;
39  return tid;
40 }
41 
43  : m_deficit (0),
44  m_status (INACTIVE)
45 {
46  NS_LOG_FUNCTION (this);
47 }
48 
50 {
51  NS_LOG_FUNCTION (this);
52 }
53 
54 void
55 FqCoDelFlow::SetDeficit (uint32_t deficit)
56 {
57  NS_LOG_FUNCTION (this << deficit);
58  m_deficit = deficit;
59 }
60 
61 int32_t
63 {
64  NS_LOG_FUNCTION (this);
65  return m_deficit;
66 }
67 
68 void
70 {
71  NS_LOG_FUNCTION (this << deficit);
72  m_deficit += deficit;
73 }
74 
75 void
77 {
78  NS_LOG_FUNCTION (this);
79  m_status = status;
80 }
81 
84 {
85  NS_LOG_FUNCTION (this);
86  return m_status;
87 }
88 
89 
91 
93 {
94  static TypeId tid = TypeId ("ns3::FqCoDelQueueDisc")
95  .SetParent<QueueDisc> ()
96  .SetGroupName ("TrafficControl")
97  .AddConstructor<FqCoDelQueueDisc> ()
98  .AddAttribute ("Interval",
99  "The CoDel algorithm interval for each FQCoDel queue",
100  StringValue ("100ms"),
103  .AddAttribute ("Target",
104  "The CoDel algorithm target queue delay for each FQCoDel queue",
105  StringValue ("5ms"),
108  .AddAttribute ("PacketLimit",
109  "The hard limit on the real queue size, measured in packets",
110  UintegerValue (10 * 1024),
112  MakeUintegerChecker<uint32_t> ())
113  .AddAttribute ("Flows",
114  "The number of queues into which the incoming packets are classified",
115  UintegerValue (1024),
117  MakeUintegerChecker<uint32_t> ())
118  .AddAttribute ("DropBatchSize",
119  "The maximum number of packets dropped from the fat flow",
120  UintegerValue (64),
122  MakeUintegerChecker<uint32_t> ())
123  ;
124  return tid;
125 }
126 
128  : m_quantum (0),
129  m_overlimitDroppedPackets (0)
130 {
131  NS_LOG_FUNCTION (this);
132 }
133 
135 {
136  NS_LOG_FUNCTION (this);
137 }
138 
139 void
141 {
142  NS_LOG_FUNCTION (this << quantum);
143  m_quantum = quantum;
144 }
145 
146 uint32_t
148 {
149  return m_quantum;
150 }
151 
152 bool
154 {
155  NS_LOG_FUNCTION (this << item);
156 
157  int32_t ret = Classify (item);
158 
159  if (ret == PacketFilter::PF_NO_MATCH)
160  {
161  NS_LOG_ERROR ("No filter has been able to classify this packet, drop it.");
162  Drop (item);
163  return false;
164  }
165 
166  uint32_t h = ret % m_flows;
167 
168  Ptr<FqCoDelFlow> flow;
169  if (m_flowsIndices.find (h) == m_flowsIndices.end ())
170  {
171  NS_LOG_DEBUG ("Creating a new flow queue with index " << h);
172  flow = m_flowFactory.Create<FqCoDelFlow> ();
174  qd->Initialize ();
175  flow->SetQueueDisc (qd);
176  AddQueueDiscClass (flow);
177 
179  }
180  else
181  {
182  flow = StaticCast<FqCoDelFlow> (GetQueueDiscClass (m_flowsIndices[h]));
183  }
184 
185  if (flow->GetStatus () == FqCoDelFlow::INACTIVE)
186  {
187  flow->SetStatus (FqCoDelFlow::NEW_FLOW);
188  flow->SetDeficit (m_quantum);
189  m_newFlows.push_back (flow);
190  }
191 
192  flow->GetQueueDisc ()->Enqueue (item);
193 
194  NS_LOG_DEBUG ("Packet enqueued into flow " << h << "; flow index " << m_flowsIndices[h]);
195 
196  if (GetNPackets () > m_limit)
197  {
198  FqCoDelDrop ();
199  }
200 
201  return true;
202 }
203 
206 {
207  NS_LOG_FUNCTION (this);
208 
209  Ptr<FqCoDelFlow> flow;
210  Ptr<QueueDiscItem> item;
211 
212  do
213  {
214  bool found = false;
215 
216  while (!found && !m_newFlows.empty ())
217  {
218  flow = m_newFlows.front ();
219 
220  if (flow->GetDeficit () <= 0)
221  {
222  flow->IncreaseDeficit (m_quantum);
223  flow->SetStatus (FqCoDelFlow::OLD_FLOW);
224  m_oldFlows.push_back (flow);
225  m_newFlows.pop_front ();
226  }
227  else
228  {
229  NS_LOG_DEBUG ("Found a new flow with positive deficit");
230  found = true;
231  }
232  }
233 
234  while (!found && !m_oldFlows.empty ())
235  {
236  flow = m_oldFlows.front ();
237 
238  if (flow->GetDeficit () <= 0)
239  {
240  flow->IncreaseDeficit (m_quantum);
241  m_oldFlows.push_back (flow);
242  m_oldFlows.pop_front ();
243  }
244  else
245  {
246  NS_LOG_DEBUG ("Found an old flow with positive deficit");
247  found = true;
248  }
249  }
250 
251  if (!found)
252  {
253  NS_LOG_DEBUG ("No flow found to dequeue a packet");
254  return 0;
255  }
256 
257  item = flow->GetQueueDisc ()->Dequeue ();
258 
259  if (!item)
260  {
261  NS_LOG_DEBUG ("Could not get a packet from the selected flow queue");
262  if (!m_newFlows.empty ())
263  {
264  flow->SetStatus (FqCoDelFlow::OLD_FLOW);
265  m_oldFlows.push_back (flow);
266  m_newFlows.pop_front ();
267  }
268  else
269  {
270  flow->SetStatus (FqCoDelFlow::INACTIVE);
271  m_oldFlows.pop_front ();
272  }
273  }
274  else
275  {
276  NS_LOG_DEBUG ("Dequeued packet " << item->GetPacket ());
277  }
278  } while (item == 0);
279 
280  flow->IncreaseDeficit (-item->GetPacketSize ());
281 
282  return item;
283 }
284 
287 {
288  NS_LOG_FUNCTION (this);
289 
290  Ptr<FqCoDelFlow> flow;
291 
292  if (!m_newFlows.empty ())
293  {
294  flow = m_newFlows.front ();
295  }
296  else
297  {
298  if (!m_oldFlows.empty ())
299  {
300  flow = m_oldFlows.front ();
301  }
302  else
303  {
304  return 0;
305  }
306  }
307 
308  return flow->GetQueueDisc ()->Peek ();
309 }
310 
311 bool
313 {
314  NS_LOG_FUNCTION (this);
315  if (GetNQueueDiscClasses () > 0)
316  {
317  NS_LOG_ERROR ("FqCoDelQueueDisc cannot have classes");
318  return false;
319  }
320 
321  if (GetNPacketFilters () == 0)
322  {
323  NS_LOG_ERROR ("FqCoDelQueueDisc needs at least a packet filter");
324  return false;
325  }
326 
327  if (GetNInternalQueues () > 0)
328  {
329  NS_LOG_ERROR ("FqCoDelQueueDisc cannot have internal queues");
330  return false;
331  }
332 
333  return true;
334 }
335 
336 void
338 {
339  NS_LOG_FUNCTION (this);
340 
341  // we are at initialization time. If the user has not set a quantum value,
342  // set the quantum to the MTU of the device
343  if (!m_quantum)
344  {
345  Ptr<NetDevice> device = GetNetDevice ();
346  NS_ASSERT_MSG (device, "Device not set for the queue disc");
347  m_quantum = device->GetMtu ();
348  NS_LOG_DEBUG ("Setting the quantum to the MTU of the device: " << m_quantum);
349  }
350 
351  m_flowFactory.SetTypeId ("ns3::FqCoDelFlow");
352 
353  m_queueDiscFactory.SetTypeId ("ns3::CoDelQueueDisc");
355  m_queueDiscFactory.Set ("MaxPackets", UintegerValue (m_limit + 1));
358 }
359 
360 uint32_t
362 {
363  NS_LOG_FUNCTION (this);
364 
365  uint32_t maxBacklog = 0, index = 0;
366  Ptr<QueueDisc> qd;
367 
368  /* Queue is full! Find the fat flow and drop packet(s) from it */
369  for (uint32_t i = 0; i < GetNQueueDiscClasses (); i++)
370  {
371  qd = GetQueueDiscClass (i)->GetQueueDisc ();
372  uint32_t bytes = qd->GetNBytes ();
373  if (bytes > maxBacklog)
374  {
375  maxBacklog = bytes;
376  index = i;
377  }
378  }
379 
380  /* Our goal is to drop half of this fat flow backlog */
381  uint32_t len = 0, count = 0, threshold = maxBacklog >> 1;
382  qd = GetQueueDiscClass (index)->GetQueueDisc ();
383  Ptr<QueueItem> item;
384 
385  do
386  {
387  item = qd->GetInternalQueue (0)->Remove ();
388  len += item->GetPacketSize ();
389  } while (++count < m_dropBatchSize && len < threshold);
390 
391  m_overlimitDroppedPackets += count;
392 
393  return index;
394 }
395 
396 } // namespace ns3
void SetDeficit(uint32_t deficit)
Set the deficit for this flow.
Ptr< const AttributeChecker > MakeStringChecker(void)
Definition: string.cc:30
A FqCoDel packet queue disc.
uint32_t GetNQueueDiscClasses(void) const
Get the number of queue disc classes.
Definition: queue-disc.cc:379
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
uint32_t m_quantum
Deficit assigned to flows at each round.
void AddQueueDiscClass(Ptr< QueueDiscClass > qdClass)
Add a queue disc class to the tail of the list of classes.
Definition: queue-disc.cc:357
static const int PF_NO_MATCH
Standard value used by packet filters to indicate that no match was possible.
Definition: packet-filter.h:48
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
Hold variables of type string.
Definition: string.h:41
Ptr< Queue > GetInternalQueue(uint32_t i) const
Get the i-th internal queue.
Definition: queue-disc.cc:324
uint32_t GetNBytes(void) const
Get the amount of bytes stored by the queue disc.
Definition: queue-disc.cc:237
uint32_t FqCoDelDrop(void)
Drop a packet from the head of the queue with the largest current byte count.
uint32_t m_dropBatchSize
Max number of packets dropped from the fat flow.
static TypeId GetTypeId(void)
Get the type ID.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
QueueDisc is an abstract base class providing the interface and implementing the operations common to...
Definition: queue-disc.h:205
FqCoDelFlow()
FqCoDelFlow constructor.
void SetStatus(FlowStatus status)
Set the status for this flow.
A flow queue used by the FqCoDel queue disc.
int32_t m_deficit
the deficit for this flow
uint32_t m_flows
Number of flow queues.
uint32_t GetNInternalQueues(void) const
Get the number of internal queues.
Definition: queue-disc.cc:331
void Drop(Ptr< QueueItem > item)
Drop a packet.
Definition: queue-disc.cc:411
Hold variables of type enum.
Definition: enum.h:54
virtual Ptr< const QueueDiscItem > DoPeek(void) const
This function returns a copy of the next packet the queue disc will extract.
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
Hold an unsigned integer type.
Definition: uinteger.h:44
FlowStatus GetStatus(void) const
Get the status of this flow.
virtual bool CheckConfig(void)
Check whether the current configuration is correct.
int32_t Classify(Ptr< QueueDiscItem > item)
Classify a packet by calling the packet filters, one at a time, until either a filter able to classif...
Definition: queue-disc.cc:385
uint32_t GetNPacketFilters(void) const
Get the number of packet filters.
Definition: queue-disc.cc:351
QueueDiscClass is the base class for classes that are included in a queue disc.
Definition: queue-disc.h:130
std::list< Ptr< FqCoDelFlow > > m_newFlows
The list of new flows.
int32_t GetDeficit(void) const
Get the deficit for this flow.
uint32_t GetQuantum(void) const
Get the quantum value.
virtual Ptr< QueueDiscItem > DoDequeue(void)
This function actually extracts a packet from the queue disc.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::string m_interval
CoDel interval attribute.
void SetQuantum(uint32_t quantum)
Set the quantum value.
std::string m_target
CoDel target attribute.
uint32_t m_overlimitDroppedPackets
Number of overlimit dropped packets.
ObjectFactory m_queueDiscFactory
Factory to create a new queue.
static TypeId GetTypeId(void)
Get the type ID.
std::map< uint32_t, uint32_t > m_flowsIndices
Map with the index of class for each flow.
FqCoDelQueueDisc()
FqCoDelQueueDisc constructor.
void Set(std::string name, const AttributeValue &value)
Set an attribute to be set during construction.
virtual void InitializeParams(void)
Initialize parameters (if any) before the first packet is enqueued.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:90
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:236
std::list< Ptr< FqCoDelFlow > > m_oldFlows
The list of old flows.
virtual bool DoEnqueue(Ptr< QueueDiscItem > item)
This function actually enqueues a packet into the queue disc.
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:220
Use number of packets for maximum queue size.
Definition: queue.h:132
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: string.h:42
void IncreaseDeficit(int32_t deficit)
Increase the deficit for this flow.
FlowStatus
Used to determine the status of this flow queue.
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: uinteger.h:45
FlowStatus m_status
the status of this flow
a unique identifier for an interface.
Definition: type-id.h:58
uint32_t m_limit
Maximum number of packets in the queue disc.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:904
Ptr< NetDevice > GetNetDevice(void) const
Get the NetDevice on which this queue discipline is installed.
Definition: queue-disc.cc:293
void Initialize(void)
Invoke DoInitialize on all Objects aggregated to this one.
Definition: object.cc:183
Ptr< QueueDiscClass > GetQueueDiscClass(uint32_t i) const
Get the i-th queue disc class.
Definition: queue-disc.cc:372
ObjectFactory m_flowFactory
Factory to create a new flow.
uint32_t GetNPackets(void) const
Get the number of packets stored by the queue disc.
Definition: queue-disc.cc:230