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