1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007 University of Washington
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 // The queue base class has a limit on its size, in terms of number of
20 // packets or number of bytes depending on the operating mode.
21 // The base class implements tracing and basic statistics calculations.
22 
23 #ifndef QUEUE_H
24 #define QUEUE_H
25 
26 #include "ns3/packet.h"
27 #include "ns3/object.h"
28 #include "ns3/traced-callback.h"
29 #include "ns3/traced-value.h"
30 #include "ns3/unused.h"
31 #include "ns3/log.h"
32 #include "ns3/queue-size.h"
33 #include "ns3/queue-item.h"
34 #include <string>
35 #include <sstream>
36 #include <list>
37 
38 namespace ns3 {
39 
40 /**
41  * \ingroup network
42  * \defgroup queue Queue
43  */
44 
45 /**
46  * \ingroup queue
47  * \brief Abstract base class for packet Queues
48  *
49  * This class defines the subset of the base APIs for packet queues in the ns-3 system
50  * that is independent of the type of enqueued objects
51  */
52 class QueueBase : public Object
53 {
54 public:
55   /**
56    * \brief Get the type ID.
57    * \return the object TypeId
58    */
59   static TypeId GetTypeId (void);
60 
61   QueueBase ();
62   virtual ~QueueBase ();
63 
64   /**
65    * \brief Append the item type to the provided type ID if the latter does not
66    *        end with '>'
67    *
68    * \param typeId the type ID
69    * \param itemType the item type
70    *
71    * This method is meant to be invoked by helpers to save users from
72    * specifying the type of items stored in a queue. For instance,
73    * PointToPointHelper::SetQueue calls
74    *
75    * \code
76    *   QueueBase::AppendItemTypeIfNotPresent (type, "Packet");
77    * \endcode
78    *
79    * where type specifies the queue type (e.g., "ns3::DropTailQueue").
80    * This allows users to call SetQueue ("ns3::DropTailQueue")
81    * instead of SetQueue ("ns3::DropTailQueue<Packet>")
82    */
83   static void AppendItemTypeIfNotPresent (std::string& typeId, const std::string& itemType);
84 
85   /**
86    * \return true if the queue is empty; false otherwise
87    */
88   bool IsEmpty (void) const;
89 
90   /**
91    * \return The number of packets currently stored in the Queue
92    */
93   uint32_t GetNPackets (void) const;
94 
95   /**
96    * \return The number of bytes currently occupied by the packets in the Queue
97    */
98   uint32_t GetNBytes (void) const;
99 
100   /**
101    * \return The current size of the Queue in terms of packets, if the maximum
102    *         size is specified in packets, or bytes, otherwise
103    */
104   QueueSize GetCurrentSize (void) const;
105 
106   /**
107    * \return The total number of bytes received by this Queue since the
108    * simulation began, or since ResetStatistics was called, according to
109    * whichever happened more recently
110    */
111   uint32_t GetTotalReceivedBytes (void) const;
112 
113   /**
114    * \return The total number of packets received by this Queue since the
115    * simulation began, or since ResetStatistics was called, according to
116    * whichever happened more recently
117    */
118   uint32_t GetTotalReceivedPackets (void) const;
119 
120   /**
121    * \return The total number of bytes dropped by this Queue since the
122    * simulation began, or since ResetStatistics was called, according to
123    * whichever happened more recently
124    */
125   uint32_t GetTotalDroppedBytes (void) const;
126 
127   /**
128    * \return The total number of bytes dropped before enqueue by this Queue
129    * since the simulation began, or since ResetStatistics was called, according
130    * to whichever happened more recently
131    */
132   uint32_t GetTotalDroppedBytesBeforeEnqueue (void) const;
133 
134   /**
135    * \return The total number of bytes dropped after dequeue by this Queue
136    * since the simulation began, or since ResetStatistics was called, according
137    * to whichever happened more recently
138    */
139   uint32_t GetTotalDroppedBytesAfterDequeue (void) const;
140 
141   /**
142    * \return The total number of packets dropped by this Queue since the
143    * simulation began, or since ResetStatistics was called, according to
144    * whichever happened more recently
145    */
146   uint32_t GetTotalDroppedPackets (void) const;
147 
148   /**
149    * \return The total number of packets dropped before enqueue by this Queue
150    * since the simulation began, or since ResetStatistics was called, according
151    * to whichever happened more recently
152    */
153   uint32_t GetTotalDroppedPacketsBeforeEnqueue (void) const;
154 
155   /**
156    * \return The total number of packets dropped after dequeue by this Queue
157    * since the simulation began, or since ResetStatistics was called, according
158    * to whichever happened more recently
159    */
160   uint32_t GetTotalDroppedPacketsAfterDequeue (void) const;
161 
162   /**
163    * Resets the counts for dropped packets, dropped bytes, received packets, and
164    * received bytes.
165    */
166   void ResetStatistics (void);
167 
168   /**
169    * \brief Set the maximum size of this queue
170    *
171    * Trying to set a null size has no effect.
172    *
173    * \param size the maximum size
174    */
175   void SetMaxSize (QueueSize size);
176 
177   /**
178    * \return the maximum size of this queue
179    */
180   QueueSize GetMaxSize (void) const;
181 
182 #if 0
183   // average calculation requires keeping around
184   // a buffer with the date of arrival of past received packets
185   // which are within the average window
186   // so, it is quite costly to do it all the time.
187   // Hence, it is disabled by default and must be explicitly
188   // enabled with this method which specifies the size
189   // of the average window in time units.
190   void EnableRunningAverage (Time averageWindow);
191   void DisableRunningAverage (void);
192   // average
193   double GetQueueSizeAverage (void);
194   double GetReceivedBytesPerSecondAverage (void);
195   double GetReceivedPacketsPerSecondAverage (void);
196   double GetDroppedBytesPerSecondAverage (void);
197   double GetDroppedPacketsPerSecondAverage (void);
198   // variance
199   double GetQueueSizeVariance (void);
200   double GetReceivedBytesPerSecondVariance (void);
201   double GetReceivedPacketsPerSecondVariance (void);
202   double GetDroppedBytesPerSecondVariance (void);
203   double GetDroppedPacketsPerSecondVariance (void);
204 #endif
205 
206 private:
207   TracedValue<uint32_t> m_nBytes;               //!< Number of bytes in the queue
208   uint32_t m_nTotalReceivedBytes;               //!< Total received bytes
209   TracedValue<uint32_t> m_nPackets;             //!< Number of packets in the queue
210   uint32_t m_nTotalReceivedPackets;             //!< Total received packets
211   uint32_t m_nTotalDroppedBytes;                //!< Total dropped bytes
212   uint32_t m_nTotalDroppedBytesBeforeEnqueue;   //!< Total dropped bytes before enqueue
213   uint32_t m_nTotalDroppedBytesAfterDequeue;    //!< Total dropped bytes after dequeue
214   uint32_t m_nTotalDroppedPackets;              //!< Total dropped packets
215   uint32_t m_nTotalDroppedPacketsBeforeEnqueue; //!< Total dropped packets before enqueue
216   uint32_t m_nTotalDroppedPacketsAfterDequeue;  //!< Total dropped packets after dequeue
217 
218   QueueSize m_maxSize;                //!< max queue size
219 
220   /// Friend class
221   template <typename Item>
222   friend class Queue;
223 };
224 
225 
226 /**
227  * \ingroup queue
228  * \brief Template class for packet Queues
229  *
230  * This class defines the subset of the base APIs for packet queues in the ns-3 system
231  * that is dependent on the type of enqueued objects.
232  *
233  * Queue is a template class. The type of the objects stored within the queue
234  * is specified by the type parameter, which can be any class providing a
235  * GetSize () method (e.g., Packet, QueueDiscItem, etc.). Subclasses need to
236  * implement the Enqueue, Dequeue, Remove and Peek methods, and are
237  * encouraged to leverage the DoEnqueue, DoDequeue, DoRemove, and DoPeek
238  * methods in doing so, to ensure that appropriate trace sources are called
239  * and statistics are maintained.
240  *
241  * Users of the Queue template class usually hold a queue through a smart pointer,
242  * hence forward declaration is recommended to avoid pulling the implementation
243  * of the templates included in this file. Thus, do not include queue.h but add
244  * the following forward declaration in your .h file:
245  *
246  * \code
247  *   template <typename Item> class Queue;
248  * \endcode
249  *
250  * Then, include queue.h in the corresponding .cc file.
251  */
252 template <typename Item>
253 class Queue : public QueueBase
254 {
255 public:
256   /**
257    * \brief Get the type ID.
258    * \return the object TypeId
259    */
260   static TypeId GetTypeId (void);
261 
262   Queue ();
263   virtual ~Queue ();
264 
265   /**
266    * Place an item into the Queue (each subclass defines the position)
267    * \param item item to enqueue
268    * \return True if the operation was successful; false otherwise
269    */
270   virtual bool Enqueue (Ptr<Item> item) = 0;
271 
272   /**
273    * Remove an item from the Queue (each subclass defines the position),
274    * counting it and tracing it as dequeued
275    * \return 0 if the operation was not successful; the item otherwise.
276    */
277   virtual Ptr<Item> Dequeue (void) = 0;
278 
279   /**
280    * Remove an item from the Queue (each subclass defines the position),
281    * counting it and tracing it as both dequeued and dropped
282    * \return 0 if the operation was not successful; the item otherwise.
283    */
284   virtual Ptr<Item>  Remove (void) = 0;
285 
286   /**
287    * Get a copy of an item in the queue (each subclass defines the position)
288    * without removing it
289    * \return 0 if the operation was not successful; the item otherwise.
290    */
291   virtual Ptr<const Item> Peek (void) const = 0;
292 
293   /**
294    * Flush the queue by calling Remove() on each item enqueued.  Note that
295    * this operation will cause dequeue and drop counts to be incremented and
296    * traces to be triggered for each Remove() action.
297    */
298   void Flush (void);
299 
300   /// Define ItemType as the type of the stored elements
301   typedef Item ItemType;
302 
303 protected:
304 
305   /// Const iterator.
306   typedef typename std::list<Ptr<Item> >::const_iterator ConstIterator;
307   /// Iterator.
308   typedef typename std::list<Ptr<Item> >::iterator Iterator;
309 
310   /**
311    * \brief Get a const iterator which refers to the first item in the queue.
312    *
313    * Subclasses can browse the items in the queue by using a const iterator
314    *
315    * \code
316    *   for (auto i = begin (); i != end (); ++i)
317    *     {
318    *       (*i)->method ();  // some const method of the Item class
319    *     }
320    * \endcode
321    *
322    * \returns a const iterator which refers to the first item in the queue.
323    */
324   ConstIterator begin (void) const;
325 
326   /**
327    * \brief Get an iterator which refers to the first item in the queue.
328    *
329    * Subclasses can browse the items in the queue by using an iterator
330    *
331    * \code
332    *   for (auto i = begin (); i != end (); ++i)
333    *     {
334    *       (*i)->method ();  // some method of the Item class
335    *     }
336    * \endcode
337    *
338    * \returns an iterator which refers to the first item in the queue.
339    */
340   Iterator begin (void);
341 
342   /**
343    * \brief Get a const iterator which indicates past-the-last item in the queue.
344    *
345    * Subclasses can browse the items in the queue by using a const iterator
346    *
347    * \code
348    *   for (auto i = begin (); i != end (); ++i)
349    *     {
350    *       (*i)->method ();  // some const method of the Item class
351    *     }
352    * \endcode
353    *
354    * \returns a const iterator which indicates past-the-last item in the queue.
355    */
356   ConstIterator end (void) const;
357 
358   /**
359    * \brief Get an iterator which indicates past-the-last item in the queue.
360    *
361    * Subclasses can browse the items in the queue by using an iterator
362    *
363    * \code
364    *   for (auto i = begin (); i != end (); ++i)
365    *     {
366    *       (*i)->method ();  // some method of the Item class
367    *     }
368    * \endcode
369    *
370    * \returns an iterator which indicates past-the-last item in the queue.
371    */
372   Iterator end (void);
373 
374   /**
375    * Push an item in the queue
376    * \param pos the position before which the item will be inserted
377    * \param item the item to enqueue
378    * \return true if success, false if the packet has been dropped.
379    */
380   bool DoEnqueue (ConstIterator pos, Ptr<Item> item);
381 
382   /**
383    * Push an item in the queue
384    * \param pos the position before which the item will be inserted
385    * \param item the item to enqueue
386    * \param[out] ret an iterator pointing to the inserted value
387    * \return true if success, false if the packet has been dropped.
388    */
389   bool DoEnqueue (ConstIterator pos, Ptr<Item> item, Iterator& ret);
390 
391   /**
392    * Pull the item to dequeue from the queue
393    * \param pos the position of the item to dequeue
394    * \return the item.
395    */
396   Ptr<Item> DoDequeue (ConstIterator pos);
397 
398   /**
399    * Pull the item to drop from the queue
400    * \param pos the position of the item to remove
401    * \return the item.
402    */
403   Ptr<Item> DoRemove (ConstIterator pos);
404 
405   /**
406    * Peek the front item in the queue
407    * \param pos the position of the item to peek
408    * \return the item.
409    */
410   Ptr<const Item> DoPeek (ConstIterator pos) const;
411 
412   /**
413    * \brief Drop a packet before enqueue
414    * \param item item that was dropped
415    *
416    * This method is called by the base class when a packet is dropped because
417    * the queue is full and by the subclasses to notify parent (this class) that
418    * a packet has been dropped for other reasons before being enqueued.
419    */
420   void DropBeforeEnqueue (Ptr<Item> item);
421 
422   /**
423    * \brief Drop a packet after dequeue
424    * \param item item that was dropped
425    *
426    * This method is called by the base class when a Remove operation is requested
427    * and by the subclasses to notify parent (this class) that a packet has been
428    * dropped for other reasons after being dequeued.
429    */
430   void DropAfterDequeue (Ptr<Item> item);
431 
432   void DoDispose (void) override;
433 
434 private:
435   std::list<Ptr<Item> > m_packets;          //!< the items in the queue
436   NS_LOG_TEMPLATE_DECLARE;                  //!< the log component
437 
438   /// Traced callback: fired when a packet is enqueued
439   TracedCallback<Ptr<const Item> > m_traceEnqueue;
440   /// Traced callback: fired when a packet is dequeued
441   TracedCallback<Ptr<const Item> > m_traceDequeue;
442   /// Traced callback: fired when a packet is dropped
443   TracedCallback<Ptr<const Item> > m_traceDrop;
444   /// Traced callback: fired when a packet is dropped before enqueue
445   TracedCallback<Ptr<const Item> > m_traceDropBeforeEnqueue;
446   /// Traced callback: fired when a packet is dropped after dequeue
447   TracedCallback<Ptr<const Item> > m_traceDropAfterDequeue;
448 };
449 
450 
451 /**
452  * Implementation of the templates declared above.
453  */
454 
455 template <typename Item>
456 TypeId
GetTypeId(void)457 Queue<Item>::GetTypeId (void)
458 {
459   std::string name = GetTypeParamName<Queue<Item> > ();
460   static TypeId tid = TypeId (("ns3::Queue<" + name + ">").c_str ())
461     .SetParent<QueueBase> ()
462     .SetGroupName ("Network")
463     .AddTraceSource ("Enqueue", "Enqueue a packet in the queue.",
464                      MakeTraceSourceAccessor (&Queue<Item>::m_traceEnqueue),
465                      "ns3::" + name + "::TracedCallback")
466     .AddTraceSource ("Dequeue", "Dequeue a packet from the queue.",
467                      MakeTraceSourceAccessor (&Queue<Item>::m_traceDequeue),
468                      "ns3::" + name + "::TracedCallback")
469     .AddTraceSource ("Drop", "Drop a packet (for whatever reason).",
470                      MakeTraceSourceAccessor (&Queue<Item>::m_traceDrop),
471                      "ns3::" + name + "::TracedCallback")
472     .AddTraceSource ("DropBeforeEnqueue", "Drop a packet before enqueue.",
473                      MakeTraceSourceAccessor (&Queue<Item>::m_traceDropBeforeEnqueue),
474                      "ns3::" + name + "::TracedCallback")
475     .AddTraceSource ("DropAfterDequeue", "Drop a packet after dequeue.",
476                      MakeTraceSourceAccessor (&Queue<Item>::m_traceDropAfterDequeue),
477                      "ns3::" + name + "::TracedCallback")
478   ;
479   return tid;
480 }
481 
482 template <typename Item>
Queue()483 Queue<Item>::Queue ()
484   : NS_LOG_TEMPLATE_DEFINE ("Queue")
485 {
486 }
487 
488 template <typename Item>
~Queue()489 Queue<Item>::~Queue ()
490 {
491 }
492 
493 template <typename Item>
494 bool
DoEnqueue(ConstIterator pos,Ptr<Item> item)495 Queue<Item>::DoEnqueue (ConstIterator pos, Ptr<Item> item)
496 {
497   Iterator ret;
498   return DoEnqueue (pos, item, ret);
499 }
500 
501 template <typename Item>
502 bool
DoEnqueue(ConstIterator pos,Ptr<Item> item,Iterator & ret)503 Queue<Item>::DoEnqueue (ConstIterator pos, Ptr<Item> item, Iterator& ret)
504 {
505   NS_LOG_FUNCTION (this << item);
506 
507   if (GetCurrentSize () + item > GetMaxSize ())
508     {
509       NS_LOG_LOGIC ("Queue full -- dropping pkt");
510       DropBeforeEnqueue (item);
511       return false;
512     }
513 
514   ret = m_packets.insert (pos, item);
515 
516   uint32_t size = item->GetSize ();
517   m_nBytes += size;
518   m_nTotalReceivedBytes += size;
519 
520   m_nPackets++;
521   m_nTotalReceivedPackets++;
522 
523   NS_LOG_LOGIC ("m_traceEnqueue (p)");
524   m_traceEnqueue (item);
525 
526   return true;
527 }
528 
529 template <typename Item>
530 Ptr<Item>
DoDequeue(ConstIterator pos)531 Queue<Item>::DoDequeue (ConstIterator pos)
532 {
533   NS_LOG_FUNCTION (this);
534 
535   if (m_nPackets.Get () == 0)
536     {
537       NS_LOG_LOGIC ("Queue empty");
538       return 0;
539     }
540 
541   Ptr<Item> item = *pos;
542   m_packets.erase (pos);
543 
544   if (item != 0)
545     {
546       NS_ASSERT (m_nBytes.Get () >= item->GetSize ());
547       NS_ASSERT (m_nPackets.Get () > 0);
548 
549       m_nBytes -= item->GetSize ();
550       m_nPackets--;
551 
552       NS_LOG_LOGIC ("m_traceDequeue (p)");
553       m_traceDequeue (item);
554     }
555   return item;
556 }
557 
558 template <typename Item>
559 Ptr<Item>
DoRemove(ConstIterator pos)560 Queue<Item>::DoRemove (ConstIterator pos)
561 {
562   NS_LOG_FUNCTION (this);
563 
564   if (m_nPackets.Get () == 0)
565     {
566       NS_LOG_LOGIC ("Queue empty");
567       return 0;
568     }
569 
570   Ptr<Item> item = *pos;
571   m_packets.erase (pos);
572 
573   if (item != 0)
574     {
575       NS_ASSERT (m_nBytes.Get () >= item->GetSize ());
576       NS_ASSERT (m_nPackets.Get () > 0);
577 
578       m_nBytes -= item->GetSize ();
579       m_nPackets--;
580 
581       // packets are first dequeued and then dropped
582       NS_LOG_LOGIC ("m_traceDequeue (p)");
583       m_traceDequeue (item);
584 
585       DropAfterDequeue (item);
586     }
587   return item;
588 }
589 
590 template <typename Item>
591 void
Flush(void)592 Queue<Item>::Flush (void)
593 {
594   NS_LOG_FUNCTION (this);
595   while (!IsEmpty ())
596     {
597       Remove ();
598     }
599 }
600 
601 template <typename Item>
602 void
DoDispose(void)603 Queue<Item>::DoDispose (void)
604 {
605   NS_LOG_FUNCTION (this);
606   m_packets.clear ();
607   Object::DoDispose ();
608 }
609 
610 template <typename Item>
611 Ptr<const Item>
DoPeek(ConstIterator pos)612 Queue<Item>::DoPeek (ConstIterator pos) const
613 {
614   NS_LOG_FUNCTION (this);
615 
616   if (m_nPackets.Get () == 0)
617     {
618       NS_LOG_LOGIC ("Queue empty");
619       return 0;
620     }
621 
622   return *pos;
623 }
624 
625 template <typename Item>
begin(void)626 typename Queue<Item>::ConstIterator Queue<Item>::begin (void) const
627 {
628   return m_packets.cbegin ();
629 }
630 
631 template <typename Item>
begin(void)632 typename Queue<Item>::Iterator Queue<Item>::begin (void)
633 {
634   return m_packets.begin ();
635 }
636 
637 template <typename Item>
end(void)638 typename Queue<Item>::ConstIterator Queue<Item>::end (void) const
639 {
640   return m_packets.cend ();
641 }
642 
643 template <typename Item>
end(void)644 typename Queue<Item>::Iterator Queue<Item>::end (void)
645 {
646   return m_packets.end ();
647 }
648 
649 template <typename Item>
650 void
DropBeforeEnqueue(Ptr<Item> item)651 Queue<Item>::DropBeforeEnqueue (Ptr<Item> item)
652 {
653   NS_LOG_FUNCTION (this << item);
654 
655   m_nTotalDroppedPackets++;
656   m_nTotalDroppedPacketsBeforeEnqueue++;
657   m_nTotalDroppedBytes += item->GetSize ();
658   m_nTotalDroppedBytesBeforeEnqueue += item->GetSize ();
659 
660   NS_LOG_LOGIC ("m_traceDropBeforeEnqueue (p)");
661   m_traceDrop (item);
662   m_traceDropBeforeEnqueue (item);
663 }
664 
665 template <typename Item>
666 void
DropAfterDequeue(Ptr<Item> item)667 Queue<Item>::DropAfterDequeue (Ptr<Item> item)
668 {
669   NS_LOG_FUNCTION (this << item);
670 
671   m_nTotalDroppedPackets++;
672   m_nTotalDroppedPacketsAfterDequeue++;
673   m_nTotalDroppedBytes += item->GetSize ();
674   m_nTotalDroppedBytesAfterDequeue += item->GetSize ();
675 
676   NS_LOG_LOGIC ("m_traceDropAfterDequeue (p)");
677   m_traceDrop (item);
678   m_traceDropAfterDequeue (item);
679 }
680 
681 // The following explicit template instantiation declarations prevent all the
682 // translation units including this header file to implicitly instantiate the
683 // Queue<Packet> class and the Queue<QueueDiscItem> class. The unique instances
684 // of these classes are explicitly created through the macros
685 // NS_OBJECT_TEMPLATE_CLASS_DEFINE (Queue,Packet) and
686 // NS_OBJECT_TEMPLATE_CLASS_DEFINE (Queue,QueueDiscItem), which are included in queue.cc
687 extern template class Queue<Packet>;
688 extern template class Queue<QueueDiscItem>;
689 
690 } // namespace ns3
691 
692 #endif /* QUEUE_H */
693