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 000000000..76b128e30 Binary files /dev/null and b/src/traffic-control/doc/classful-queue-disc.dia differ diff --git a/src/traffic-control/doc/multi-queue-aware-queue-disc.dia b/src/traffic-control/doc/multi-queue-aware-queue-disc.dia new file mode 100644 index 000000000..939d97faf Binary files /dev/null and b/src/traffic-control/doc/multi-queue-aware-queue-disc.dia differ diff --git a/src/traffic-control/doc/queue-discs.rst b/src/traffic-control/doc/queue-discs.rst new file mode 100644 index 000000000..659cc6673 --- /dev/null +++ b/src/traffic-control/doc/queue-discs.rst @@ -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 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: