traffic-control: Add the QueueDisc base class
QueueDisc is a base class providing the interface and implementing the operations common to all the queueing disciplines. Child classes need to implement the methods used to enqueue a packet (DoEnqueue), dequeue a single packet (DoDequeue), get a copy of the next packet to extract (DoPeek), plus methods to classify enqueued packets in case they manage multiple queues internally.
This commit is contained in:
@@ -77,6 +77,7 @@ SOURCES = \
|
||||
$(SRC)/uan/doc/uan.rst \
|
||||
$(SRC)/topology-read/doc/topology.rst \
|
||||
$(SRC)/traffic-control/doc/traffic-control-layer.rst \
|
||||
$(SRC)/traffic-control/doc/queue-discs.rst \
|
||||
$(SRC)/spectrum/doc/spectrum.rst \
|
||||
$(SRC)/stats/doc/adaptor.rst \
|
||||
$(SRC)/stats/doc/aggregator.rst \
|
||||
@@ -266,6 +267,8 @@ SOURCEFIGS = \
|
||||
$(SRC)/spectrum/doc/spectrum-tv-rand-geo-points.eps \
|
||||
$(SRC)/spectrum/doc/spectrum-tv-8vsb.png \
|
||||
$(SRC)/spectrum/doc/spectrum-tv-cofdm.png \
|
||||
$(SRC)/traffic-control/doc/classful-queue-disc.dia \
|
||||
$(SRC)/traffic-control/doc/multi-queue-aware-queue-disc.dia \
|
||||
$(SRC)/lr-wpan/doc/lr-wpan-arch.dia \
|
||||
$(SRC)/lr-wpan/doc/lr-wpan-data-example.dia \
|
||||
$(SRC)/lr-wpan/doc/lr-wpan-primitives.dia \
|
||||
@@ -352,6 +355,8 @@ IMAGES_EPS = \
|
||||
$(FIGURES)/auvmobility-classes.eps \
|
||||
$(FIGURES)/spectrum-analyzer-example.eps \
|
||||
$(FIGURES)/spectrum-tv-rand-geo-points.eps \
|
||||
$(FIGURES)/classful-queue-disc.eps \
|
||||
$(FIGURES)/multi-queue-aware-queue-disc.eps \
|
||||
$(FIGURES)/lr-wpan-primitives.eps \
|
||||
$(FIGURES)/lr-wpan-data-example.eps \
|
||||
$(FIGURES)/lr-wpan-arch.eps \
|
||||
|
||||
@@ -4,3 +4,4 @@ Traffic Control Layer
|
||||
.. toctree::
|
||||
|
||||
traffic-control-layer
|
||||
queue-discs
|
||||
|
||||
BIN
src/traffic-control/doc/classful-queue-disc.dia
Normal file
BIN
src/traffic-control/doc/classful-queue-disc.dia
Normal file
Binary file not shown.
BIN
src/traffic-control/doc/multi-queue-aware-queue-disc.dia
Normal file
BIN
src/traffic-control/doc/multi-queue-aware-queue-disc.dia
Normal file
Binary file not shown.
210
src/traffic-control/doc/queue-discs.rst
Normal file
210
src/traffic-control/doc/queue-discs.rst
Normal file
@@ -0,0 +1,210 @@
|
||||
Queue disciplines
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. heading hierarchy:
|
||||
------------- Chapter
|
||||
************* Section (#.#)
|
||||
============= Subsection (#.#.#)
|
||||
############# Paragraph (no number)
|
||||
|
||||
Model Description
|
||||
*****************
|
||||
|
||||
Packets received by the Traffic Control layer for transmission to a netdevice
|
||||
can be passed to a Queue Discipline to perform scheduling and policing.
|
||||
A netdevice can have a single (root) queue disc installed on it.
|
||||
Installing a queue disc on a netdevice is not mandatory. If a netdevice does
|
||||
not have a queue disc installed on it, the traffic control layer sends the packets
|
||||
directly to the netdevice. This is the case, for instance, of the loopback netdevice.
|
||||
|
||||
As in Linux, a queue disc may contain distinct elements:
|
||||
|
||||
* queues, which actually store the packets waiting for transmission
|
||||
* classes, which allow to reserve a different treatment to different packets
|
||||
* filters, which determine the queue or class which a packet is destined to
|
||||
|
||||
Notice that a child queue disc must be attached to every class and a packet
|
||||
filter is only able to classify packets of a single protocol. Also, while in Linux
|
||||
some queue discs (e.g., fq-codel) use an internal classifier and do not make use of
|
||||
packet filters, in ns-3 every queue disc including multiple queues or multiple classes
|
||||
needs an external filter to classify packets (this is to avoid having the traffic-control
|
||||
module depend on other modules such as internet).
|
||||
|
||||
Queue disc configuration vary from queue disc to queue disc. A typical taxonomy divides
|
||||
queue discs in classful (i.e., support classes) and classless (i.e., do not support
|
||||
classes). More recently, after the appearance of multi-queue devices (such as Wi-Fi),
|
||||
some multi-queue aware queue discs have been introduced. Multi-queue aware queue discs
|
||||
handle as many queues (or queue discs -- without using classes) as the number of
|
||||
transmission queues used by the device on which the queue disc is installed.
|
||||
An attempt is made, also, to enqueue each packet in the "same" queue both within the
|
||||
queue disc and within the device.
|
||||
|
||||
The traffic control layer interacts with a queue disc in a simple manner: after requesting
|
||||
to enqueue a packet, the traffic control layer requests the qdisc to "run", i.e., to
|
||||
dequeue a set of packets, until a predefined number ("quota") of packets is dequeued
|
||||
or the netdevice stops the queue disc. A netdevice may stop the queue disc when its
|
||||
transmission queue(s) is/are (almost) full. Also, a netdevice may wake the
|
||||
queue disc when its transmission queue(s) is/are (almost) empty. Waking a queue disc
|
||||
is equivalent to make it run.
|
||||
|
||||
Design
|
||||
==========
|
||||
|
||||
An abstract base class, class QueueDisc, is subclassed to implement a specific
|
||||
queue disc. A subclass is required to implement the following methods:
|
||||
|
||||
* ``bool DoEnqueue (Ptr<QueueDiscItem> item)``: Enqueue a packet
|
||||
* ``Ptr<QueueDiscItem> DoDequeue (void)``: Dequeue a packet
|
||||
* ``Ptr<const QueueDiscItem> DoPeek (void) const``: Peek a packet
|
||||
* ``bool CheckConfig (void) const``: Check if the configuration is correct
|
||||
|
||||
The base class QueueDisc implements:
|
||||
|
||||
* methods to add/get a single queue, class or filter and methods to get the number \
|
||||
of installed queues, classes or filters
|
||||
* a ``Classify`` method which classifies a packet by processing the list of filters \
|
||||
until a filter able to classify the packet is found
|
||||
* methods to extract multiple packets from the queue disc, while handling transmission \
|
||||
(to the device) failures by requeuing packets
|
||||
|
||||
The base class QueueDisc provides many trace sources:
|
||||
|
||||
* ``Enqueue``
|
||||
* ``Dequeue``
|
||||
* ``Requeue``
|
||||
* ``Drop``
|
||||
* ``PacketsInQueue``
|
||||
* ``BytesInQueue``
|
||||
|
||||
The base class QueueDisc holds the list of attached queues, classes and filter
|
||||
by means of three vectors accessible through attributes (InternalQueueList,
|
||||
QueueDiscClassList and PacketFilterList).
|
||||
|
||||
Internal queues are implemented as (subclasses of) Queue objects. A Queue stores
|
||||
QueueItem objects, which consist of just a Ptr<Packet>. Since a queue disc has to
|
||||
store at least the destination address and the protocol number for each enqueued
|
||||
packet, a new class, QueueDiscItem, is derived from QueueItem to store such
|
||||
additional information for each packet. Thus, internal queues are implemented as
|
||||
Queue objects storing QueueDiscItem objects. Also, there could be the need to store
|
||||
further information depending on the network layer protocol of the packet. For
|
||||
instance, for IPv4 and IPv6 packets it is needed to separately store the header
|
||||
and the payload, so that header fields can be manipulated, e.g., to support ECN.
|
||||
To this end, Ipv4QueueDiscItem and Ipv6QueueDiscItem are derived from QueueDiscItem
|
||||
to additionally store the packet header and provide protocol specific operations
|
||||
such as ECN marking.
|
||||
|
||||
Classes are implemented via the QueueDiscClass class, which just consists of a pointer
|
||||
to the attached queue disc. Such a pointer is accessible through the QueueDisc attribute.
|
||||
Classful queue discs needing to set parameters for their classes can subclass
|
||||
QueueDiscClass and add the required parameters as attributes.
|
||||
|
||||
An abstract base class, PacketFilter, is subclassed to implement specific filters.
|
||||
Subclasses are required to implement two virtual private pure methods:
|
||||
|
||||
* ``bool CheckProtocol (Ptr<QueueDiscItem> item) const``: check whether the filter \
|
||||
is able to classify packets of the same protocol as the given packet
|
||||
* ``int32_t DoClassify (Ptr<QueueDiscItem> item) const``: actually classify the packet
|
||||
|
||||
PacketFilter provides a public method, ``Classify``, which first calls ``CheckProtocol``
|
||||
to check that the protocol of the packet matches the protocol of the filter and then
|
||||
calls ``DoClassify``. Specific filters subclassed from PacketFilter should not be
|
||||
placed in the traffic-control module but in the module corresponding to the protocol
|
||||
of the classified packets.
|
||||
|
||||
In Linux, information about the status of a transmission queue of a device is
|
||||
stored in the struct netdev_queue, which includes a qdisc field that is mainly used
|
||||
to solve the following problems:
|
||||
|
||||
* if a device transmission queue is (almost) empty, identify the queue disc to wake
|
||||
* if a packet will be enqueued in a given device transmission queue, identify the \
|
||||
queue disc which the packet must be enqueued into
|
||||
|
||||
The latter problem arises because Linux attempts to determine the device transmission
|
||||
queue which a packet will be enqueued into before passing the packet to a queue disc.
|
||||
This is done by calling a specific function of the device driver, if implemented, or
|
||||
by employing fallback mechanisms (such as hashing of the addresses) otherwise. The
|
||||
identifier of the selected device transmission queue is stored in the queue_mapping \
|
||||
field of the struct sk_buff, so that both the queue disc and the device driver can
|
||||
get the same information. In ns-3, such identifier is stored in a member of the
|
||||
QueueDiscItem class.
|
||||
|
||||
The qdisc field of the Linux struct netdev_queue cannot be
|
||||
similarly stored in a NetDeviceQueue object, because it would make the network module
|
||||
depend on the traffic-control module. Instead, this information is stored in the
|
||||
TrafficControlLayer object aggregated to each node. In particular, a TrafficControlLayer
|
||||
object holds a map which stores, for each NetDevice, a vector of Ptr<QueueDisc>.
|
||||
The size of such a vector is the number of device transmission queues and each
|
||||
element of this vector is a pointer to the queue disc to activate when the above
|
||||
problems occur. The TrafficControlLayer::SetRootQueueDiscOnDevice method takes care
|
||||
of configuring such a map, based on the "wake mode" of the root queue disc. If the
|
||||
wake mode of the root queue disc is WAKE_ROOT, then all the elements of the vector
|
||||
are pointers to the root queue disc. If the wake mode of the root queue disc is
|
||||
WAKE_CHILD, then each element of the vector is a pointer to a distinct child queue
|
||||
disc. This requires that the number of child queue discs matches the number of
|
||||
netdevice queues. It follows that the wake mode of a classless queue disc must
|
||||
necessarily be WAKE_ROOT. These two configurations are illustrated by the figures below.
|
||||
|
||||
:ref:`fig-classful-queue-disc` below shows how the TrafficControlLayer map looks like in
|
||||
case of a classful root queue disc whose wake mode is WAKE_ROOT.
|
||||
|
||||
.. _fig-classful-queue-disc:
|
||||
|
||||
.. figure:: figures/classful-queue-disc.*
|
||||
|
||||
Setup of a queue disc (wake mode: WAKE_ROOT)
|
||||
|
||||
:ref:`fig-multi-queue-aware-queue-disc` below shows instead how the TrafficControlLayer
|
||||
map looks like in case of a classful root queue disc whose wake mode is WAKE_CHILD.
|
||||
|
||||
.. _fig-multi-queue-aware-queue-disc:
|
||||
|
||||
.. figure:: figures/multi-queue-aware-queue-disc.*
|
||||
|
||||
Setup of a multi-queue aware queue disc
|
||||
|
||||
Besides the map described above, a TrafficControlLayer object also stores a vector
|
||||
of Ptr<QueueDisc> representing the root queue discs installed on all the devices of
|
||||
the node. This vector has as many elements as the number of devices. In this vector,
|
||||
devices are sorted as in Node::m_devices. This vector is accessible through the
|
||||
RootQueueDiscList attribute.
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
By default, the InternetStackHelper aggregates a TrafficControlLayer object to every
|
||||
node. When invoked to assign an IPv{4,6} address to a device, the Ipv{4,6}AddressHelper,
|
||||
besides creating a Ipv{4,6}Interface, also installs the default qdisc, PfifoFastQueueDisc,
|
||||
on the device, unless a queue disc has been already installed. Thus, devices get the default
|
||||
queue disc installed even if they are added to the node after the Internet stack has been
|
||||
installed on the node.
|
||||
|
||||
To install a queue disc other than the default one, it is necessary to install such queue
|
||||
disc before an IP address is assigned to the device. Alternatively, the default queue disc
|
||||
can be removed from the device after assigning an IP address, by using the convenient
|
||||
Uninstall method of the TrafficControlHelper class, and then installing a different
|
||||
queue disc on the device. Clearly, it is also possible to have no queue disc installed on a device.
|
||||
|
||||
Helpers
|
||||
=======
|
||||
|
||||
A typical usage pattern is to create a traffic control helper and to configure type
|
||||
and attributes of queue discs, queues, classes and filters from the helper, For example,
|
||||
the default pfifo_fast can be configured as follows:
|
||||
|
||||
.. sourcecode:: cpp
|
||||
|
||||
TrafficControlHelper tch;
|
||||
uint16_t handle = tch.SetRootQueueDisc ("ns3::PfifoFastQueueDisc");
|
||||
tch.AddInternalQueues (handle, 3, "ns3::DropTailQueue", "MaxPackets", UintegerValue (1000));
|
||||
tch.AddPacketFilter (handle, "ns3::PfifoFastIpv4PacketFilter");
|
||||
QueueDiscContainer qdiscs = tch.Install (devices);
|
||||
|
||||
The above code adds three internal queues and a packet filter to the root queue disc of type PfifoFast.
|
||||
With the above configuration, the config path of the root queue disc installed on the j-th
|
||||
device of the i-th node (the index of a device is the same as in DeviceList) is:
|
||||
|
||||
/NodeList/[i]/$ns3::TrafficControlLayer/RootQueueDiscList/[j]
|
||||
|
||||
and the config path of the second internal queue is:
|
||||
|
||||
/NodeList/[i]/$ns3::TrafficControlLayer/RootQueueDiscList/[j]/InternalQueueList/1
|
||||
63
src/traffic-control/model/packet-filter.cc
Normal file
63
src/traffic-control/model/packet-filter.cc
Normal file
@@ -0,0 +1,63 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/integer.h"
|
||||
#include "queue-disc.h"
|
||||
#include "packet-filter.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("PacketFilter");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (PacketFilter);
|
||||
|
||||
TypeId
|
||||
PacketFilter::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::PacketFilter")
|
||||
.SetParent<Object> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
PacketFilter::PacketFilter ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
PacketFilter::~PacketFilter()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
int32_t
|
||||
PacketFilter::Classify (Ptr<QueueDiscItem> item) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
|
||||
if (!CheckProtocol (item))
|
||||
{
|
||||
NS_LOG_LOGIC ("Unable to classify packets of this protocol");
|
||||
return PF_NO_MATCH;
|
||||
}
|
||||
|
||||
return DoClassify (item);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
69
src/traffic-control/model/packet-filter.h
Normal file
69
src/traffic-control/model/packet-filter.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2016 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PACKET_FILTER_H
|
||||
#define PACKET_FILTER_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class QueueDiscItem;
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control
|
||||
*
|
||||
* PacketFilter is the abstract base class for filters used by queue discs
|
||||
* to classify packets.
|
||||
*/
|
||||
class PacketFilter: public Object {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
PacketFilter ();
|
||||
virtual ~PacketFilter ();
|
||||
|
||||
static const int PF_NO_MATCH = -1;
|
||||
|
||||
/**
|
||||
* \return -1 if this filter is not able to classify packets of the same protocol
|
||||
* as item or the item does not match the filter conditions, the configured return
|
||||
* value otherwise.
|
||||
*/
|
||||
int32_t Classify (Ptr<QueueDiscItem> item) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* \return true if this filter is able to classify packets of the same protocol as item.
|
||||
*/
|
||||
virtual bool CheckProtocol (Ptr<QueueDiscItem> item) const = 0;
|
||||
|
||||
/**
|
||||
* \return -1 if the item does not match the filter conditions, the configured
|
||||
* return value otherwise.
|
||||
*/
|
||||
virtual int32_t DoClassify (Ptr<QueueDiscItem> item) const = 0;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* PACKET_FILTER */
|
||||
593
src/traffic-control/model/queue-disc.cc
Normal file
593
src/traffic-control/model/queue-disc.cc
Normal file
@@ -0,0 +1,593 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007, 2014 University of Washington
|
||||
* 2015 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/object-vector.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "queue-disc.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("QueueDisc");
|
||||
|
||||
QueueDiscItem::QueueDiscItem (Ptr<Packet> p, const Address& addr, uint16_t protocol)
|
||||
: QueueItem (p),
|
||||
m_address (addr),
|
||||
m_protocol (protocol),
|
||||
m_txq (0)
|
||||
{
|
||||
}
|
||||
|
||||
QueueDiscItem::~QueueDiscItem()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
Address
|
||||
QueueDiscItem::GetAddress (void) const
|
||||
{
|
||||
return m_address;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
QueueDiscItem::GetProtocol (void) const
|
||||
{
|
||||
return m_protocol;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
QueueDiscItem::GetTxQueueIndex (void) const
|
||||
{
|
||||
return m_txq;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDiscItem::SetTxQueueIndex (uint8_t txq)
|
||||
{
|
||||
m_txq = txq;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDiscItem::Print (std::ostream& os) const
|
||||
{
|
||||
os << GetPacket () << " "
|
||||
<< "Dst addr " << m_address << " "
|
||||
<< "proto " << (uint16_t) m_protocol << " "
|
||||
<< "txq " << (uint8_t) m_txq
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (QueueDiscClass);
|
||||
|
||||
TypeId QueueDiscClass::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::QueueDiscClass")
|
||||
.SetParent<Object> ()
|
||||
.SetGroupName ("TrafficControl")
|
||||
.AddConstructor<QueueDiscClass> ()
|
||||
.AddAttribute ("QueueDisc", "The queue disc attached to the class",
|
||||
PointerValue (),
|
||||
MakePointerAccessor (&QueueDiscClass::m_queueDisc),
|
||||
MakePointerChecker<QueueDisc> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
QueueDiscClass::QueueDiscClass()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
QueueDiscClass::DoDispose (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_queueDisc = 0;
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
Ptr<QueueDisc>
|
||||
QueueDiscClass::GetQueueDisc (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_queueDisc;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDiscClass::SetQueueDisc (Ptr<QueueDisc> qd)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_queueDisc = qd;
|
||||
}
|
||||
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (QueueDisc);
|
||||
|
||||
TypeId QueueDisc::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::QueueDisc")
|
||||
.SetParent<Object> ()
|
||||
.SetGroupName ("TrafficControl")
|
||||
.AddAttribute ("Quota", "The maximum number of packets dequeued in a qdisc run",
|
||||
UintegerValue (DEFAULT_QUOTA),
|
||||
MakeUintegerAccessor (&QueueDisc::SetQuota,
|
||||
&QueueDisc::GetQuota),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("InternalQueueList", "The list of internal queues.",
|
||||
ObjectVectorValue (),
|
||||
MakeObjectVectorAccessor (&QueueDisc::m_queues),
|
||||
MakeObjectVectorChecker<Queue> ())
|
||||
.AddAttribute ("PacketFilterList", "The list of packet filters.",
|
||||
ObjectVectorValue (),
|
||||
MakeObjectVectorAccessor (&QueueDisc::m_filters),
|
||||
MakeObjectVectorChecker<PacketFilter> ())
|
||||
.AddAttribute ("QueueDiscClassList", "The list of queue disc classes.",
|
||||
ObjectVectorValue (),
|
||||
MakeObjectVectorAccessor (&QueueDisc::m_classes),
|
||||
MakeObjectVectorChecker<QueueDiscClass> ())
|
||||
.AddTraceSource ("Enqueue", "Enqueue a packet in the queue disc",
|
||||
MakeTraceSourceAccessor (&QueueDisc::m_traceEnqueue),
|
||||
"ns3::QueueItem::TracedCallback")
|
||||
.AddTraceSource ("Dequeue", "Dequeue a packet from the queue disc",
|
||||
MakeTraceSourceAccessor (&QueueDisc::m_traceDequeue),
|
||||
"ns3::QueueItem::TracedCallback")
|
||||
.AddTraceSource ("Requeue", "Requeue a packet in the queue disc",
|
||||
MakeTraceSourceAccessor (&QueueDisc::m_traceRequeue),
|
||||
"ns3::QueueItem::TracedCallback")
|
||||
.AddTraceSource ("Drop", "Drop a packet stored in the queue disc",
|
||||
MakeTraceSourceAccessor (&QueueDisc::m_traceDrop),
|
||||
"ns3::QueueItem::TracedCallback")
|
||||
.AddTraceSource ("PacketsInQueue",
|
||||
"Number of packets currently stored in the queue disc",
|
||||
MakeTraceSourceAccessor (&QueueDisc::m_nPackets),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
.AddTraceSource ("BytesInQueue",
|
||||
"Number of bytes currently stored in the queue disc",
|
||||
MakeTraceSourceAccessor (&QueueDisc::m_nBytes),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
QueueDisc::QueueDisc ()
|
||||
: m_nPackets (0),
|
||||
m_nBytes (0),
|
||||
m_nTotalReceivedPackets (0),
|
||||
m_nTotalReceivedBytes (0),
|
||||
m_nTotalDroppedPackets (0),
|
||||
m_nTotalDroppedBytes (0),
|
||||
m_nTotalRequeuedPackets (0),
|
||||
m_nTotalRequeuedBytes (0),
|
||||
m_running (false),
|
||||
m_InitCompleted (false)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::DoDispose (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_queues.clear ();
|
||||
m_filters.clear ();
|
||||
m_classes.clear ();
|
||||
m_device = 0;
|
||||
m_devQueueIface = 0;
|
||||
m_requeued = 0;
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::DoInitialize (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
// When adding a new interface, the traffic control aggregates
|
||||
// a NetDeviceQueueInterface object to the netdevice
|
||||
if (m_device)
|
||||
{
|
||||
m_devQueueIface = m_device->GetObject<NetDeviceQueueInterface> ();
|
||||
}
|
||||
|
||||
// Check the configuration and initialize the parameters of this queue disc
|
||||
NS_ASSERT_MSG (CheckConfig (), "The queue disc configuration is not correct");
|
||||
InitializeParams ();
|
||||
|
||||
// Check the configuration and initialize the parameters of the child queue discs
|
||||
for (std::vector<Ptr<QueueDiscClass> >::iterator cl = m_classes.begin ();
|
||||
cl != m_classes.end (); cl++)
|
||||
{
|
||||
(*cl)->GetQueueDisc ()->Initialize ();
|
||||
}
|
||||
|
||||
Object::DoInitialize ();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetNPackets () const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_nPackets;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetNBytes (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_nBytes;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetTotalReceivedPackets (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_nTotalReceivedPackets;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetTotalReceivedBytes (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_nTotalReceivedBytes;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetTotalDroppedPackets (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_nTotalDroppedPackets;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc:: GetTotalDroppedBytes (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_nTotalDroppedBytes;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetTotalRequeuedPackets (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_nTotalRequeuedPackets;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc:: GetTotalRequeuedBytes (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_nTotalRequeuedBytes;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::SetNetDevice (Ptr<NetDevice> device)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << device);
|
||||
m_device = device;
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
QueueDisc::GetNetDevice (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_device;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::SetQuota (const uint32_t quota)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << quota);
|
||||
m_quota = quota;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetQuota (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return m_quota;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::AddInternalQueue (Ptr<Queue> queue)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_queues.push_back (queue);
|
||||
}
|
||||
|
||||
Ptr<Queue>
|
||||
QueueDisc::GetInternalQueue (uint32_t i) const
|
||||
{
|
||||
NS_ASSERT (i < m_queues.size ());
|
||||
return m_queues[i];
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetNInternalQueues (void) const
|
||||
{
|
||||
return m_queues.size ();
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::AddPacketFilter (Ptr<PacketFilter> filter)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_filters.push_back (filter);
|
||||
}
|
||||
|
||||
Ptr<PacketFilter>
|
||||
QueueDisc::GetPacketFilter (uint32_t i) const
|
||||
{
|
||||
NS_ASSERT (i < m_filters.size ());
|
||||
return m_filters[i];
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetNPacketFilters (void) const
|
||||
{
|
||||
return m_filters.size ();
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::AddQueueDiscClass (Ptr<QueueDiscClass> qdClass)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_ABORT_MSG_IF (qdClass->GetQueueDisc () == 0, "Cannot add a class with no attached queue disc");
|
||||
m_classes.push_back (qdClass);
|
||||
}
|
||||
|
||||
Ptr<QueueDiscClass>
|
||||
QueueDisc::GetQueueDiscClass (uint32_t i) const
|
||||
{
|
||||
NS_ASSERT (i < m_classes.size ());
|
||||
return m_classes[i];
|
||||
}
|
||||
|
||||
uint32_t
|
||||
QueueDisc::GetNQueueDiscClasses (void) const
|
||||
{
|
||||
return m_classes.size ();
|
||||
}
|
||||
|
||||
int32_t
|
||||
QueueDisc::Classify (Ptr<QueueDiscItem> item)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
|
||||
int32_t ret = PacketFilter::PF_NO_MATCH;
|
||||
for (std::vector<Ptr<PacketFilter> >::iterator f = m_filters.begin ();
|
||||
f != m_filters.end () && ret == PacketFilter::PF_NO_MATCH; f++)
|
||||
{
|
||||
ret = (*f)->Classify (item);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QueueDisc::WakeMode
|
||||
QueueDisc::GetWakeMode (void)
|
||||
{
|
||||
return WAKE_ROOT;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::Drop (Ptr<QueueDiscItem> item)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
NS_ASSERT_MSG (m_nPackets >= 1u, "No packet in the queue disc, cannot drop");
|
||||
NS_ASSERT_MSG (m_nBytes >= item->GetPacketSize (), "The size of the packet that"
|
||||
<< " is reported to be dropped is greater than the amount of bytes"
|
||||
<< "stored in the queue disc");
|
||||
|
||||
m_nPackets--;
|
||||
m_nBytes -= item->GetPacketSize ();
|
||||
m_nTotalDroppedPackets++;
|
||||
m_nTotalDroppedBytes += item->GetPacketSize ();
|
||||
|
||||
NS_LOG_LOGIC ("m_traceDrop (p)");
|
||||
m_traceDrop (item);
|
||||
}
|
||||
|
||||
bool
|
||||
QueueDisc::Enqueue (Ptr<QueueDiscItem> item)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
|
||||
m_nPackets++;
|
||||
m_nBytes += item->GetPacketSize ();
|
||||
m_nTotalReceivedPackets++;
|
||||
m_nTotalReceivedBytes += item->GetPacketSize ();
|
||||
|
||||
NS_LOG_LOGIC ("m_traceEnqueue (p)");
|
||||
m_traceEnqueue (item);
|
||||
|
||||
return DoEnqueue (item);
|
||||
}
|
||||
|
||||
Ptr<QueueDiscItem>
|
||||
QueueDisc::Dequeue (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
Ptr<QueueDiscItem> item;
|
||||
item = DoDequeue ();
|
||||
|
||||
if (item != 0)
|
||||
{
|
||||
m_nPackets--;
|
||||
m_nBytes -= item->GetPacketSize ();
|
||||
|
||||
NS_LOG_LOGIC ("m_traceDequeue (p)");
|
||||
m_traceDequeue (item);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
Ptr<const QueueDiscItem>
|
||||
QueueDisc::Peek (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return DoPeek ();
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::Run (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
if (RunBegin ())
|
||||
{
|
||||
uint32_t quota = m_quota;
|
||||
while (Restart ())
|
||||
{
|
||||
quota -= 1;
|
||||
if (quota <= 0)
|
||||
{
|
||||
/// \todo netif_schedule (q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
RunEnd ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
QueueDisc::RunBegin (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (m_running)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::RunEnd (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
bool
|
||||
QueueDisc::Restart (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
Ptr<QueueDiscItem> item = DequeuePacket();
|
||||
if (item == 0)
|
||||
{
|
||||
NS_LOG_LOGIC ("No packet to send");
|
||||
return false;
|
||||
}
|
||||
|
||||
return Transmit (item);
|
||||
}
|
||||
|
||||
Ptr<QueueDiscItem>
|
||||
QueueDisc::DequeuePacket ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_ASSERT (m_devQueueIface);
|
||||
Ptr<QueueDiscItem> item;
|
||||
|
||||
// First check if there is a requeued packet
|
||||
if (m_requeued != 0)
|
||||
{
|
||||
// If the queue where the requeued packet is destined to is not stopped, return
|
||||
// the requeued packet; otherwise, return an empty packet.
|
||||
// If the device does not support flow control, the device queue is never stopped
|
||||
if (!m_devQueueIface->GetTxQueue (m_requeued->GetTxQueueIndex ())->IsStopped ())
|
||||
{
|
||||
item = m_requeued;
|
||||
m_requeued = 0;
|
||||
|
||||
m_nPackets--;
|
||||
m_nBytes -= item->GetPacketSize ();
|
||||
|
||||
NS_LOG_LOGIC ("m_traceDequeue (p)");
|
||||
m_traceDequeue (item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the device is multi-queue (actually, Linux checks if the queue disc has
|
||||
// multiple queues), ask the queue disc to dequeue a packet (a multi-queue aware
|
||||
// queue disc should try not to dequeue a packet destined to a stopped queue).
|
||||
// Otherwise, ask the queue disc to dequeue a packet only if the (unique) queue
|
||||
// is not stopped.
|
||||
if (m_devQueueIface->GetTxQueuesN ()>1 || !m_devQueueIface->GetTxQueue (0)->IsStopped ())
|
||||
{
|
||||
item = Dequeue ();
|
||||
// Here, Linux tries bulk dequeues
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
void
|
||||
QueueDisc::Requeue (Ptr<QueueDiscItem> item)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
m_requeued = item;
|
||||
/// \todo netif_schedule (q);
|
||||
|
||||
m_nPackets++; // it's still part of the queue
|
||||
m_nBytes += item->GetPacketSize ();
|
||||
m_nTotalRequeuedPackets++;
|
||||
m_nTotalRequeuedBytes += item->GetPacketSize ();
|
||||
|
||||
NS_LOG_LOGIC ("m_traceRequeue (p)");
|
||||
m_traceRequeue (item);
|
||||
}
|
||||
|
||||
bool
|
||||
QueueDisc::Transmit (Ptr<QueueDiscItem> item)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << item);
|
||||
NS_ASSERT (m_devQueueIface);
|
||||
bool ret = false;
|
||||
|
||||
if (!m_devQueueIface->GetTxQueue (item->GetTxQueueIndex ())->IsStopped ())
|
||||
{
|
||||
// send a copy of the packet because the device might add the
|
||||
// MAC header even if the transmission is unsuccessful (see BUG 2284)
|
||||
Ptr<Packet> copy = item->GetPacket ()->Copy ();
|
||||
ret = m_device->Send (copy, item->GetAddress (), item->GetProtocol ());
|
||||
}
|
||||
|
||||
// If the transmission did not happen or failed, requeue the item
|
||||
if (!ret)
|
||||
{
|
||||
Requeue (item);
|
||||
}
|
||||
|
||||
// If the transmission succeeded but now the queue is stopped, return false
|
||||
if (ret && m_devQueueIface->GetTxQueue (item->GetTxQueueIndex ())->IsStopped ())
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
541
src/traffic-control/model/queue-disc.h
Normal file
541
src/traffic-control/model/queue-disc.h
Normal file
@@ -0,0 +1,541 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007, 2014 University of Washington
|
||||
* 2015 Universita' degli Studi di Napoli Federico II
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_DISC_H
|
||||
#define QUEUE_DISC_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/traced-value.h"
|
||||
#include <ns3/queue.h>
|
||||
#include "ns3/net-device.h"
|
||||
#include <vector>
|
||||
#include "packet-filter.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Packet;
|
||||
class QueueDisc;
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control
|
||||
*
|
||||
* QueueDiscItem is the abstract base class for items that are stored in a queue
|
||||
* disc. It is derived from QueueItem (which only consists of a Ptr<Packet>)
|
||||
* to additionally store the destination MAC address, the
|
||||
* L3 protocol number and the transmission queue index,
|
||||
*/
|
||||
class QueueDiscItem : public QueueItem {
|
||||
public:
|
||||
/**
|
||||
* \brief Create a queue disc item.
|
||||
* \param p the packet included in the created item.
|
||||
* \param addr the destination MAC address
|
||||
* \param protocol the L3 protocol number
|
||||
*/
|
||||
QueueDiscItem (Ptr<Packet> p, const Address & addr, uint16_t protocol);
|
||||
|
||||
virtual ~QueueDiscItem ();
|
||||
|
||||
/**
|
||||
* \brief Get the MAC address included in this item
|
||||
* \return the MAC address included in this item.
|
||||
*/
|
||||
Address GetAddress (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the L3 protocol included in this item
|
||||
* \return the L3 protocol included in this item.
|
||||
*/
|
||||
uint16_t GetProtocol (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the transmission queue index included in this item
|
||||
* \return the transmission queue index included in this item.
|
||||
*/
|
||||
uint8_t GetTxQueueIndex (void) const;
|
||||
|
||||
/**
|
||||
* \brief Set the transmission queue index to store in this item
|
||||
* \param txq the transmission queue index to store in this item.
|
||||
*/
|
||||
void SetTxQueueIndex (uint8_t txq);
|
||||
|
||||
/**
|
||||
* \brief Print the item contents.
|
||||
* \param os output stream in which the data should be printed.
|
||||
*/
|
||||
virtual void Print (std::ostream &os) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Default constructor
|
||||
*
|
||||
* Defined and unimplemented to avoid misuse
|
||||
*/
|
||||
QueueDiscItem ();
|
||||
/**
|
||||
* \brief Copy constructor
|
||||
*
|
||||
* Defined and unimplemented to avoid misuse
|
||||
*/
|
||||
QueueDiscItem (const QueueDiscItem &);
|
||||
/**
|
||||
* \brief Assignment operator
|
||||
*
|
||||
* Defined and unimplemented to avoid misuse
|
||||
* \returns
|
||||
*/
|
||||
QueueDiscItem &operator = (const QueueDiscItem &);
|
||||
|
||||
Address m_address; //!< MAC destination address
|
||||
uint16_t m_protocol; //!< L3 Protocol number
|
||||
uint8_t m_txq; //!< Transmission queue index
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control
|
||||
*
|
||||
* QueueDiscClass is the base class for classes that are included in a queue
|
||||
* disc. It has a single attribute, QueueDisc, used to set the child queue disc
|
||||
* attached to the class. Classful queue discs needing to set parameters for
|
||||
* their classes can subclass QueueDiscClass and add the required parameters
|
||||
* as attributes.
|
||||
*/
|
||||
class QueueDiscClass : public Object {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
QueueDiscClass ();
|
||||
virtual ~QueueDiscClass () {}
|
||||
|
||||
/**
|
||||
* \brief Get the queue disc attached to this class
|
||||
* \return the queue disc attached to this class.
|
||||
*/
|
||||
Ptr<QueueDisc> GetQueueDisc (void) const;
|
||||
|
||||
/**
|
||||
* \brief Set the queue disc attached to this class
|
||||
*/
|
||||
void SetQueueDisc (Ptr<QueueDisc> qd);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Dispose of the object
|
||||
*/
|
||||
virtual void DoDispose (void);
|
||||
|
||||
private:
|
||||
Ptr<QueueDisc> m_queueDisc; //!< Queue disc attached to this class
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup traffic-control
|
||||
*
|
||||
* QueueDisc is an abstract base class providing the interface and implementing
|
||||
* the operations common to all the queueing disciplines. Child classes
|
||||
* need to implement the methods used to enqueue a packet (DoEnqueue),
|
||||
* dequeue a single packet (DoDequeue), get a copy of the next packet
|
||||
* to extract (DoPeek), check whether the current configuration is correct
|
||||
* (CheckConfig).
|
||||
*
|
||||
* As in Linux, a queue disc may contain distinct elements:
|
||||
* - queues, which actually store the packets waiting for transmission
|
||||
* - classes, which allow to reserve a different treatment to different packets
|
||||
* - filters, which determine the queue or class which a packet is destined to
|
||||
*
|
||||
* Notice that a child queue disc must be attached to every class and a packet
|
||||
* filter is only able to classify packets of a single protocol. Also, while in Linux
|
||||
* some queue discs (e.g., fq-codel) use an internal classifier and do not make use of
|
||||
* packet filters, in ns-3 every queue disc including multiple queues or multiple classes
|
||||
* needs an external filter to classify packets (this is to avoid having the traffic-control
|
||||
* module depend on other modules such as internet).
|
||||
*
|
||||
* Queue disc configuration vary from queue disc to queue disc. A typical taxonomy divides
|
||||
* queue discs in classful (i.e., support classes) and classless (i.e., do not support
|
||||
* classes). More recently, after the appearance of multi-queue devices (such as Wifi),
|
||||
* some multi-queue aware queue discs have been introduced. Multi-queue aware queue discs
|
||||
* handle as many queues (or queue discs -- without using classes) as the number of
|
||||
* transmission queues used by the device on which the queue disc is installed.
|
||||
* An attempt is made, also, to enqueue each packet in the "same" queue both within the
|
||||
* queue disc and within the device.
|
||||
*
|
||||
* The traffic control layer interacts with a queue disc in a simple manner: after requesting
|
||||
* to enqueue a packet, the traffic control layer requests the qdisc to "run", i.e., to
|
||||
* dequeue a set of packets, until a predefined number ("quota") of packets is dequeued
|
||||
* or the netdevice stops the queue disc. A netdevice may stop the queue disc when its
|
||||
* transmission queue(s) is/are (almost) full. Also, a netdevice may wake the
|
||||
* queue disc when its transmission queue(s) is/are (almost) empty. Waking a queue disc
|
||||
* is equivalent to make it run.
|
||||
*
|
||||
* The design and implementation of this class is heavily inspired by Linux.
|
||||
* For more details, see the traffic-control model page.
|
||||
*/
|
||||
class QueueDisc : public Object {
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
QueueDisc ();
|
||||
|
||||
/**
|
||||
* \brief Get the number of packets stored by the queue disc
|
||||
* \return the number of packets stored by the queue disc.
|
||||
*
|
||||
* Note that the number of packets stored by the queue disc is updated as soon
|
||||
* as a packet is received by the queue disc and before actually enqueuing the
|
||||
* packet (i.e., before calling DoEnqueue). Thus, while implementing the DoEnqueue
|
||||
* method of a subclass, keep in mind that GetNPackets returns the number of
|
||||
* packets stored in the queue disc, including the packet that we are trying
|
||||
* to enqueue.
|
||||
*/
|
||||
uint32_t GetNPackets (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the amount of bytes stored by the queue disc
|
||||
* \return the amount of bytes stored by the queue disc.
|
||||
*
|
||||
* Note that the amount of bytes stored by the queue disc is updated as soon
|
||||
* as a packet is received by the queue disc and before actually enqueuing the
|
||||
* packet (i.e., before calling DoEnqueue). Thus, while implementing the DoEnqueue
|
||||
* method of a subclass, keep in mind that GetNBytes returns the amount of
|
||||
* bytes stored in the queue disc, including the size of the packet that we are
|
||||
* trying to enqueue.
|
||||
*/
|
||||
uint32_t GetNBytes (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the total number of received packets
|
||||
* \return the total number of received packets.
|
||||
*/
|
||||
uint32_t GetTotalReceivedPackets (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the total amount of received bytes
|
||||
* \return the total amount of received bytes.
|
||||
*/
|
||||
uint32_t GetTotalReceivedBytes (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the total number of dropped packets
|
||||
* \return the total number of dropped packets.
|
||||
*/
|
||||
uint32_t GetTotalDroppedPackets (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the total amount of dropped bytes
|
||||
* \return the total amount of dropped bytes.
|
||||
*/
|
||||
uint32_t GetTotalDroppedBytes (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the total number of requeued packets
|
||||
* \return the total number of requeued packets.
|
||||
*/
|
||||
uint32_t GetTotalRequeuedPackets (void) const;
|
||||
|
||||
/**
|
||||
* \brief Get the total amount of requeued bytes
|
||||
* \return the total amount of requeued bytes.
|
||||
*/
|
||||
uint32_t GetTotalRequeuedBytes (void) const;
|
||||
|
||||
/**
|
||||
* \brief Set the NetDevice on which this queue discipline is installed.
|
||||
* \param device the NetDevice on which this queue discipline is installed.
|
||||
*/
|
||||
void SetNetDevice (Ptr<NetDevice> device);
|
||||
|
||||
/**
|
||||
* \brief Get the NetDevice on which this queue discipline is installed
|
||||
* \return the NetDevice on which this queue discipline is installed.
|
||||
*/
|
||||
Ptr<NetDevice> GetNetDevice (void) const;
|
||||
|
||||
/**
|
||||
* \brief Set the maximum number of dequeue operations following a packet enqueue
|
||||
* \param quota the maximum number of dequeue operations following a packet enqueue.
|
||||
*/
|
||||
virtual void SetQuota (const uint32_t quota);
|
||||
|
||||
/**
|
||||
* \brief Get the maximum number of dequeue operations following a packet enqueue
|
||||
* \return the maximum number of dequeue operations following a packet enqueue.
|
||||
*/
|
||||
virtual uint32_t GetQuota (void) const;
|
||||
|
||||
/**
|
||||
* Pass a packet to store to the queue discipline. This function only updates
|
||||
* the statistics and calls the (private) DoEnqueue function, which must be
|
||||
* implemented by derived classes.
|
||||
* \param item item to enqueue
|
||||
* \return True if the operation was successful; false otherwise
|
||||
*/
|
||||
bool Enqueue (Ptr<QueueDiscItem> item);
|
||||
|
||||
/**
|
||||
* Request the queue discipline to extract a packet. This function only updates
|
||||
* the statistics and calls the (private) DoDequeue function, which must be
|
||||
* implemented by derived classes.
|
||||
* \return 0 if the operation was not successful; the item otherwise.
|
||||
*/
|
||||
Ptr<QueueDiscItem> Dequeue (void);
|
||||
|
||||
/**
|
||||
* Get a copy of the next packet the queue discipline will extract, without
|
||||
* actually extracting the packet. This function only calls the (private)
|
||||
* DoPeek function, which must be implemented by derived classes.
|
||||
* \return 0 if the operation was not successful; the item otherwise.
|
||||
*/
|
||||
Ptr<const QueueDiscItem> Peek (void) const;
|
||||
|
||||
/**
|
||||
* Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c)
|
||||
* Dequeues multiple packets, until a quota is exceeded or sending a packet
|
||||
* to the device failed.
|
||||
*/
|
||||
void Run (void);
|
||||
|
||||
/**
|
||||
* \brief Add an internal queue to the tail of the list of queues.
|
||||
* \param queue the queue to be added
|
||||
*/
|
||||
void AddInternalQueue (Ptr<Queue> queue);
|
||||
|
||||
/**
|
||||
* \brief Get the i-th internal queue
|
||||
* \param i the index of the queue
|
||||
* \return the i-th internal queue.
|
||||
*/
|
||||
Ptr<Queue> GetInternalQueue (uint32_t i) const;
|
||||
|
||||
/**
|
||||
* \brief Get the number of internal queues
|
||||
* \return the number of internal queues.
|
||||
*/
|
||||
uint32_t GetNInternalQueues (void) const;
|
||||
|
||||
/**
|
||||
* \brief Add a packet filter to the tail of the list of filters used to classify packets.
|
||||
* \param filter the packet filter to be added
|
||||
*/
|
||||
void AddPacketFilter (Ptr<PacketFilter> filter);
|
||||
|
||||
/**
|
||||
* \brief Get the i-th packet filter
|
||||
* \param i the index of the packet filter
|
||||
* \return the i-th packet filter.
|
||||
*/
|
||||
Ptr<PacketFilter> GetPacketFilter (uint32_t i) const;
|
||||
|
||||
/**
|
||||
* \brief Get the number of packet filters
|
||||
* \return the number of packet filters.
|
||||
*/
|
||||
uint32_t GetNPacketFilters (void) const;
|
||||
|
||||
/**
|
||||
* \brief Add a queue disc class to the tail of the list of classes.
|
||||
* \param qdClass the queue disc class to be added
|
||||
*/
|
||||
void AddQueueDiscClass (Ptr<QueueDiscClass> qdClass);
|
||||
|
||||
/**
|
||||
* \brief Get the i-th queue disc class
|
||||
* \param i the index of the queue disc class
|
||||
* \return the i-th queue disc class.
|
||||
*/
|
||||
Ptr<QueueDiscClass> GetQueueDiscClass (uint32_t i) const;
|
||||
|
||||
/**
|
||||
* \brief Get the number of queue disc classes
|
||||
* \return the number of queue disc classes.
|
||||
*/
|
||||
uint32_t GetNQueueDiscClasses (void) const;
|
||||
|
||||
/**
|
||||
* Classify a packet by calling the packet filters, one at a time, until either
|
||||
* a filter able to classify the packet is found or all the filters have been
|
||||
* processed.
|
||||
* \param item item to classify
|
||||
* \return -1 if no filter able to classify the packet has been found, the value
|
||||
* returned by first filter found to be able to classify the packet otherwise.
|
||||
*/
|
||||
int32_t Classify (Ptr<QueueDiscItem> item);
|
||||
|
||||
/**
|
||||
* \enum WakeMode
|
||||
* \brief Used to determine whether the queue disc itself or its children must
|
||||
* be activated when a netdevice wakes a transmission queue
|
||||
*/
|
||||
enum WakeMode
|
||||
{
|
||||
WAKE_ROOT = 0x00,
|
||||
WAKE_CHILD = 0x01
|
||||
};
|
||||
|
||||
/**
|
||||
* When setting up the wake callbacks on the netdevice queues, it is necessary to
|
||||
* determine which queue disc (the root queue disc or one of its children) should
|
||||
* be activated when the netdevice wakes one of its transmission queues. The
|
||||
* implementation of this method for the base class returns WAKE_ROOT, i.e., the
|
||||
* root queue disc is activated. Subclasses implementing queue discs adopting
|
||||
* a different strategy (e.g., multi-queue aware queue discs such as mq) have
|
||||
* to redefine this method.
|
||||
*
|
||||
* \return the wake mode adopted by this queue disc.
|
||||
*/
|
||||
WakeMode GetWakeMode (void);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Dispose of the object
|
||||
*/
|
||||
virtual void DoDispose (void);
|
||||
|
||||
/**
|
||||
* \brief Check whether the configuration is correct and initialize parameters
|
||||
*/
|
||||
virtual void DoInitialize (void);
|
||||
|
||||
/**
|
||||
* \brief Drop a packet
|
||||
* \param item item that was dropped
|
||||
* This method is called by subclasses to notify parent (this class) of packet drops.
|
||||
*/
|
||||
void Drop (Ptr<QueueDiscItem> item);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* This function actually enqueues a packet into the queue disc.
|
||||
* \param item item to enqueue
|
||||
* \return True if the operation was successful; false otherwise
|
||||
*/
|
||||
virtual bool DoEnqueue (Ptr<QueueDiscItem> item) = 0;
|
||||
|
||||
/**
|
||||
* This function actually extracts a packet from the queue disc.
|
||||
* \return 0 if the operation was not successful; the item otherwise.
|
||||
*/
|
||||
virtual Ptr<QueueDiscItem> DoDequeue (void) = 0;
|
||||
|
||||
/**
|
||||
* This function returns a copy of the next packet the queue disc will extract.
|
||||
* \return 0 if the operation was not successful; the packet otherwise.
|
||||
*/
|
||||
virtual Ptr<const QueueDiscItem> DoPeek (void) const = 0;
|
||||
|
||||
/**
|
||||
* Check whether the current configuration is correct. Default objects (such
|
||||
* as internal queues) might be created by this method to ensure the
|
||||
* configuration is correct.
|
||||
* \return true if the configuration is correct, false otherwise
|
||||
*/
|
||||
virtual bool CheckConfig (void) = 0;
|
||||
|
||||
/**
|
||||
* Initialize parameters (if any) before the first packet is enqueued.
|
||||
*/
|
||||
virtual void InitializeParams (void) = 0;
|
||||
|
||||
/**
|
||||
* Modelled after the Linux function qdisc_run_begin (include/net/sch_generic.h).
|
||||
* \return false if the qdisc is already running; otherwise, set the qdisc as running and return true.
|
||||
*/
|
||||
bool RunBegin (void);
|
||||
|
||||
/**
|
||||
* Modelled after the Linux function qdisc_run_end (include/net/sch_generic.h).
|
||||
* Set the qdisc as not running.
|
||||
*/
|
||||
void RunEnd (void);
|
||||
|
||||
/**
|
||||
* Modelled after the Linux function qdisc_restart (net/sched/sch_generic.c)
|
||||
* Dequeue a packet (by calling DequeuePacket) and send it to the device (by calling Transmit).
|
||||
* \return true if a packet is successfully sent to the device.
|
||||
*/
|
||||
bool Restart (void);
|
||||
|
||||
/**
|
||||
* Modelled after the Linux function dequeue_skb (net/sched/sch_generic.c)
|
||||
* \return the requeued packet, if any, or the packet dequeued by the queue disc, otherwise.
|
||||
*/
|
||||
Ptr<QueueDiscItem> DequeuePacket (void);
|
||||
|
||||
/**
|
||||
* Modelled after the Linux function dev_requeue_skb (net/sched/sch_generic.c)
|
||||
* Requeues a packet whose transmission failed.
|
||||
* \param p the packet to requeue
|
||||
*/
|
||||
void Requeue (Ptr<QueueDiscItem> p);
|
||||
|
||||
/**
|
||||
* Modelled after the Linux function sch_direct_xmit (net/sched/sch_generic.c)
|
||||
* Sends a packet to the device and requeues it in case transmission fails.
|
||||
* \param p the packet to transmit
|
||||
* \return true if the transmission succeeded and the queue is not stopped
|
||||
*/
|
||||
bool Transmit (Ptr<QueueDiscItem> p);
|
||||
|
||||
static const uint32_t DEFAULT_QUOTA = 64; //!< Default quota (as in /proc/sys/net/core/dev_weight)
|
||||
|
||||
std::vector<Ptr<Queue> > m_queues; //!< Internal queues
|
||||
std::vector<Ptr<PacketFilter> > m_filters; //!< Packet filters
|
||||
std::vector<Ptr<QueueDiscClass> > m_classes; //!< Classes
|
||||
|
||||
TracedValue<uint32_t> m_nPackets; //!< Number of packets in the queue
|
||||
TracedValue<uint32_t> m_nBytes; //!< Number of bytes in the queue
|
||||
|
||||
uint32_t m_nTotalReceivedPackets; //!< Total received packets
|
||||
uint32_t m_nTotalReceivedBytes; //!< Total received bytes
|
||||
uint32_t m_nTotalDroppedPackets; //!< Total dropped packets
|
||||
uint32_t m_nTotalDroppedBytes; //!< Total dropped bytes
|
||||
uint32_t m_nTotalRequeuedPackets; //!< Total requeued packets
|
||||
uint32_t m_nTotalRequeuedBytes; //!< Total requeued bytes
|
||||
uint32_t m_quota; //!< Maximum number of packets dequeued in a qdisc run
|
||||
Ptr<NetDevice> m_device; //!< The NetDevice on which this queue discipline is installed
|
||||
Ptr<NetDeviceQueueInterface> m_devQueueIface; //!< NetDevice queue interface
|
||||
bool m_running; //!< The queue disc is performing multiple dequeue operations
|
||||
bool m_InitCompleted; //!< True if the config has been verified and the parameters initialized
|
||||
Ptr<QueueDiscItem> m_requeued; //!< The last packet that failed to be transmitted
|
||||
|
||||
/// Traced callback: fired when a packet is enqueued
|
||||
TracedCallback<Ptr<const QueueItem> > m_traceEnqueue;
|
||||
/// Traced callback: fired when a packet is dequeued
|
||||
TracedCallback<Ptr<const QueueItem> > m_traceDequeue;
|
||||
/// Traced callback: fired when a packet is requeued
|
||||
TracedCallback<Ptr<const QueueItem> > m_traceRequeue;
|
||||
/// Traced callback: fired when a packet is dropped
|
||||
TracedCallback<Ptr<const QueueItem> > m_traceDrop;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* QueueDisc */
|
||||
@@ -9,7 +9,9 @@
|
||||
def build(bld):
|
||||
module = bld.create_ns3_module('traffic-control', ['core'])
|
||||
module.source = [
|
||||
'model/traffic-control-layer.cc'
|
||||
'model/traffic-control-layer.cc',
|
||||
'model/packet-filter.cc',
|
||||
'model/queue-disc.cc'
|
||||
]
|
||||
|
||||
module_test = bld.create_ns3_module_test_library('traffic-control')
|
||||
@@ -19,7 +21,9 @@ def build(bld):
|
||||
headers = bld(features='ns3header')
|
||||
headers.module = 'traffic-control'
|
||||
headers.source = [
|
||||
'model/traffic-control-layer.h'
|
||||
'model/traffic-control-layer.h',
|
||||
'model/packet-filter.h',
|
||||
'model/queue-disc.h'
|
||||
]
|
||||
|
||||
if bld.env.ENABLE_EXAMPLES:
|
||||
|
||||
Reference in New Issue
Block a user