From bedc89eea9e2a2510b2d5e5c129c446d996fe396 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Tue, 8 Mar 2016 10:44:13 -0800 Subject: [PATCH] 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. --- doc/models/Makefile | 5 + doc/models/source/traffic-control.rst | 1 + .../doc/classful-queue-disc.dia | Bin 0 -> 2509 bytes .../doc/multi-queue-aware-queue-disc.dia | Bin 0 -> 2636 bytes src/traffic-control/doc/queue-discs.rst | 210 +++++++ src/traffic-control/model/packet-filter.cc | 63 ++ src/traffic-control/model/packet-filter.h | 69 ++ src/traffic-control/model/queue-disc.cc | 593 ++++++++++++++++++ src/traffic-control/model/queue-disc.h | 541 ++++++++++++++++ src/traffic-control/wscript | 8 +- 10 files changed, 1488 insertions(+), 2 deletions(-) create mode 100644 src/traffic-control/doc/classful-queue-disc.dia create mode 100644 src/traffic-control/doc/multi-queue-aware-queue-disc.dia create mode 100644 src/traffic-control/doc/queue-discs.rst create mode 100644 src/traffic-control/model/packet-filter.cc create mode 100644 src/traffic-control/model/packet-filter.h create mode 100644 src/traffic-control/model/queue-disc.cc create mode 100644 src/traffic-control/model/queue-disc.h diff --git a/doc/models/Makefile b/doc/models/Makefile index 47a06b47f..8ca770b47 100644 --- a/doc/models/Makefile +++ b/doc/models/Makefile @@ -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 \ diff --git a/doc/models/source/traffic-control.rst b/doc/models/source/traffic-control.rst index a3b1ad51f..26bd003be 100644 --- a/doc/models/source/traffic-control.rst +++ b/doc/models/source/traffic-control.rst @@ -4,3 +4,4 @@ Traffic Control Layer .. toctree:: traffic-control-layer + queue-discs diff --git a/src/traffic-control/doc/classful-queue-disc.dia b/src/traffic-control/doc/classful-queue-disc.dia new file mode 100644 index 0000000000000000000000000000000000000000..76b128e305b51749a15d8b922b052b7958842fae GIT binary patch literal 2509 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 item)``: Enqueue a packet +* ``Ptr DoDequeue (void)``: Dequeue a packet +* ``Ptr 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. 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 item) const``: check whether the filter \ + is able to classify packets of the same protocol as the given packet +* ``int32_t DoClassify (Ptr 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. +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 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 diff --git a/src/traffic-control/model/packet-filter.cc b/src/traffic-control/model/packet-filter.cc new file mode 100644 index 000000000..60218b1c5 --- /dev/null +++ b/src/traffic-control/model/packet-filter.cc @@ -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 () + ; + return tid; +} + +PacketFilter::PacketFilter () +{ + NS_LOG_FUNCTION (this); +} + +PacketFilter::~PacketFilter() +{ + NS_LOG_FUNCTION (this); +} + +int32_t +PacketFilter::Classify (Ptr 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 diff --git a/src/traffic-control/model/packet-filter.h b/src/traffic-control/model/packet-filter.h new file mode 100644 index 000000000..d2fe75fa4 --- /dev/null +++ b/src/traffic-control/model/packet-filter.h @@ -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 item) const; + +private: + /** + * \return true if this filter is able to classify packets of the same protocol as item. + */ + virtual bool CheckProtocol (Ptr item) const = 0; + + /** + * \return -1 if the item does not match the filter conditions, the configured + * return value otherwise. + */ + virtual int32_t DoClassify (Ptr item) const = 0; +}; + +} // namespace ns3 + +#endif /* PACKET_FILTER */ diff --git a/src/traffic-control/model/queue-disc.cc b/src/traffic-control/model/queue-disc.cc new file mode 100644 index 000000000..f3d6d36b2 --- /dev/null +++ b/src/traffic-control/model/queue-disc.cc @@ -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 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 () + .SetGroupName ("TrafficControl") + .AddConstructor () + .AddAttribute ("QueueDisc", "The queue disc attached to the class", + PointerValue (), + MakePointerAccessor (&QueueDiscClass::m_queueDisc), + MakePointerChecker ()) + ; + return tid; +} + +QueueDiscClass::QueueDiscClass() +{ + NS_LOG_FUNCTION (this); +} + +void +QueueDiscClass::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + m_queueDisc = 0; + Object::DoDispose (); +} + +Ptr +QueueDiscClass::GetQueueDisc (void) const +{ + NS_LOG_FUNCTION (this); + return m_queueDisc; +} + +void +QueueDiscClass::SetQueueDisc (Ptr qd) +{ + NS_LOG_FUNCTION (this); + m_queueDisc = qd; +} + + +NS_OBJECT_ENSURE_REGISTERED (QueueDisc); + +TypeId QueueDisc::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::QueueDisc") + .SetParent () + .SetGroupName ("TrafficControl") + .AddAttribute ("Quota", "The maximum number of packets dequeued in a qdisc run", + UintegerValue (DEFAULT_QUOTA), + MakeUintegerAccessor (&QueueDisc::SetQuota, + &QueueDisc::GetQuota), + MakeUintegerChecker ()) + .AddAttribute ("InternalQueueList", "The list of internal queues.", + ObjectVectorValue (), + MakeObjectVectorAccessor (&QueueDisc::m_queues), + MakeObjectVectorChecker ()) + .AddAttribute ("PacketFilterList", "The list of packet filters.", + ObjectVectorValue (), + MakeObjectVectorAccessor (&QueueDisc::m_filters), + MakeObjectVectorChecker ()) + .AddAttribute ("QueueDiscClassList", "The list of queue disc classes.", + ObjectVectorValue (), + MakeObjectVectorAccessor (&QueueDisc::m_classes), + MakeObjectVectorChecker ()) + .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 (); + } + + // 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 >::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 device) +{ + NS_LOG_FUNCTION (this << device); + m_device = device; +} + +Ptr +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) +{ + NS_LOG_FUNCTION (this); + m_queues.push_back (queue); +} + +Ptr +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 filter) +{ + NS_LOG_FUNCTION (this); + m_filters.push_back (filter); +} + +Ptr +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 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 +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 item) +{ + NS_LOG_FUNCTION (this << item); + + int32_t ret = PacketFilter::PF_NO_MATCH; + for (std::vector >::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 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 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 +QueueDisc::Dequeue (void) +{ + NS_LOG_FUNCTION (this); + + Ptr item; + item = DoDequeue (); + + if (item != 0) + { + m_nPackets--; + m_nBytes -= item->GetPacketSize (); + + NS_LOG_LOGIC ("m_traceDequeue (p)"); + m_traceDequeue (item); + } + + return item; +} + +Ptr +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 item = DequeuePacket(); + if (item == 0) + { + NS_LOG_LOGIC ("No packet to send"); + return false; + } + + return Transmit (item); +} + +Ptr +QueueDisc::DequeuePacket () +{ + NS_LOG_FUNCTION (this); + NS_ASSERT (m_devQueueIface); + Ptr 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 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 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 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 diff --git a/src/traffic-control/model/queue-disc.h b/src/traffic-control/model/queue-disc.h new file mode 100644 index 000000000..85e519ac0 --- /dev/null +++ b/src/traffic-control/model/queue-disc.h @@ -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 +#include "ns3/net-device.h" +#include +#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) + * 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 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 GetQueueDisc (void) const; + + /** + * \brief Set the queue disc attached to this class + */ + void SetQueueDisc (Ptr qd); + +protected: + /** + * \brief Dispose of the object + */ + virtual void DoDispose (void); + +private: + Ptr 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 device); + + /** + * \brief Get the NetDevice on which this queue discipline is installed + * \return the NetDevice on which this queue discipline is installed. + */ + Ptr 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 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 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 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); + + /** + * \brief Get the i-th internal queue + * \param i the index of the queue + * \return the i-th internal queue. + */ + Ptr 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 filter); + + /** + * \brief Get the i-th packet filter + * \param i the index of the packet filter + * \return the i-th packet filter. + */ + Ptr 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 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 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 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 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 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 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 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 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 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 p); + + static const uint32_t DEFAULT_QUOTA = 64; //!< Default quota (as in /proc/sys/net/core/dev_weight) + + std::vector > m_queues; //!< Internal queues + std::vector > m_filters; //!< Packet filters + std::vector > m_classes; //!< Classes + + TracedValue m_nPackets; //!< Number of packets in the queue + TracedValue 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 m_device; //!< The NetDevice on which this queue discipline is installed + Ptr 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 m_requeued; //!< The last packet that failed to be transmitted + + /// Traced callback: fired when a packet is enqueued + TracedCallback > m_traceEnqueue; + /// Traced callback: fired when a packet is dequeued + TracedCallback > m_traceDequeue; + /// Traced callback: fired when a packet is requeued + TracedCallback > m_traceRequeue; + /// Traced callback: fired when a packet is dropped + TracedCallback > m_traceDrop; +}; + +} // namespace ns3 + +#endif /* QueueDisc */ diff --git a/src/traffic-control/wscript b/src/traffic-control/wscript index 2cef94b37..d4cdb4ed7 100644 --- a/src/traffic-control/wscript +++ b/src/traffic-control/wscript @@ -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: