diff --git a/src/traffic-control/model/traffic-control-layer.cc b/src/traffic-control/model/traffic-control-layer.cc index 36db69ec2..ef3445ae0 100644 --- a/src/traffic-control/model/traffic-control-layer.cc +++ b/src/traffic-control/model/traffic-control-layer.cc @@ -1,6 +1,7 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2015 Natale Patriciello + * 2016 Stefano Avallone * * 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 @@ -18,7 +19,9 @@ #include "traffic-control-layer.h" #include "ns3/log.h" +#include "ns3/object-vector.h" #include "ns3/packet.h" +#include "ns3/queue-disc.h" namespace ns3 { @@ -33,6 +36,10 @@ TrafficControlLayer::GetTypeId (void) .SetParent () .SetGroupName ("TrafficControl") .AddConstructor () + .AddAttribute ("RootQueueDiscList", "The list of root queue discs associated to this Traffic Control layer.", + ObjectVectorValue (), + MakeObjectVectorAccessor (&TrafficControlLayer::m_rootQueueDiscs), + MakeObjectVectorChecker ()) ; return tid; } @@ -49,6 +56,89 @@ TrafficControlLayer::TrafficControlLayer () NS_LOG_FUNCTION_NOARGS (); } +void +TrafficControlLayer::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + m_node = 0; + m_rootQueueDiscs.clear (); + m_handlers.clear (); + m_netDeviceQueueToQueueDiscMap.clear (); + Object::DoDispose (); +} + +void +TrafficControlLayer::DoInitialize (void) +{ + NS_LOG_FUNCTION (this); + for (uint32_t j = 0; j < m_rootQueueDiscs.size (); j++) + { + if (m_rootQueueDiscs[j]) + { + Ptr device = m_node->GetDevice (j); + // NetDevices supporting flow control can set the number of device transmission + // queues through the NetDevice queue interface during initialization. Thus, + // ensure that the device has completed initialization + device->Initialize (); + + std::map, NetDeviceInfo>::iterator qdMap = m_netDeviceQueueToQueueDiscMap.find (device); + NS_ASSERT (qdMap != m_netDeviceQueueToQueueDiscMap.end ()); + Ptr devQueueIface = qdMap->second.first; + NS_ASSERT (devQueueIface); + + devQueueIface->SetQueueDiscInstalled (true); + + // set the wake callbacks on netdevice queues + if (m_rootQueueDiscs[j]->GetWakeMode () == QueueDisc::WAKE_ROOT) + { + for (uint32_t i = 0; i < devQueueIface->GetTxQueuesN (); i++) + { + devQueueIface->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run, m_rootQueueDiscs[j])); + qdMap->second.second.push_back (m_rootQueueDiscs[j]); + } + } + else if (m_rootQueueDiscs[j]->GetWakeMode () == QueueDisc::WAKE_CHILD) + { + NS_ASSERT_MSG (m_rootQueueDiscs[j]->GetNQueueDiscClasses () == devQueueIface->GetTxQueuesN (), + "The number of child queue discs does not match the number of netdevice queues"); + for (uint32_t i = 0; i < devQueueIface->GetTxQueuesN (); i++) + { + devQueueIface->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run, + m_rootQueueDiscs[j]->GetQueueDiscClass (i)->GetQueueDisc ())); + qdMap->second.second.push_back (m_rootQueueDiscs[j]->GetQueueDiscClass (i)->GetQueueDisc ()); + } + } + + // initialize the queue disc + m_rootQueueDiscs[j]->Initialize (); + } + } + Object::DoInitialize (); +} + +void +TrafficControlLayer::SetupDevice (Ptr device) +{ + NS_LOG_FUNCTION (this << device); + + // ensure this setup is done just once (in case of dual stack nodes) + if (device->GetObject ()) + { + NS_LOG_DEBUG ("The setup for this device has been already done."); + return; + } + + // create a NetDeviceQueueInterface object and aggregate it to the device + Ptr devQueueIface = CreateObject (); + device->AggregateObject (devQueueIface); + + // store a pointer to the created queue interface + NS_ASSERT_MSG (m_netDeviceQueueToQueueDiscMap.find (device) == m_netDeviceQueueToQueueDiscMap.end (), + "This is a bug: SetupDevice should be called only once per device"); + + m_netDeviceQueueToQueueDiscMap[device] = NetDeviceInfo (devQueueIface, QueueDiscVector ()); +} + void TrafficControlLayer::RegisterProtocolHandler (Node::ProtocolHandler handler, uint16_t protocolType, Ptr device) @@ -67,6 +157,89 @@ TrafficControlLayer::RegisterProtocolHandler (Node::ProtocolHandler handler, protocolType << "."); } +void +TrafficControlLayer::SetRootQueueDiscOnDevice (Ptr device, Ptr qDisc) +{ + NS_LOG_FUNCTION (this << device); + + uint32_t index = GetDeviceIndex (device); + NS_ASSERT_MSG (index < m_node->GetNDevices (), "The provided device does not belong to" + << " the node which this TrafficControlLayer object is aggregated to" ); + if (index >= m_rootQueueDiscs.size ()) + { + m_rootQueueDiscs.resize (index+1); + } + + NS_ASSERT_MSG (m_rootQueueDiscs[index] == 0, "Cannot install a root queue disc on a " + << "device already having one. Delete the existing queue disc first."); + + m_rootQueueDiscs[index] = qDisc; +} + +Ptr +TrafficControlLayer::GetRootQueueDiscOnDevice (Ptr device) +{ + NS_LOG_FUNCTION (this << device); + + uint32_t index = GetDeviceIndex (device); + NS_ASSERT_MSG (index < m_node->GetNDevices (), "The provided device does not belong to" + << " the node which this TrafficControlLayer object is aggregated to" ); + if (index >= m_rootQueueDiscs.size ()) + { + m_rootQueueDiscs.resize (index+1); + } + return m_rootQueueDiscs[index]; +} + +void +TrafficControlLayer::DeleteRootQueueDiscOnDevice (Ptr device) +{ + NS_LOG_FUNCTION (this << device); + + uint32_t index = GetDeviceIndex (device); + NS_ASSERT_MSG (index < m_node->GetNDevices (), "The provided device does not belong to" + << " the node which this TrafficControlLayer object is aggregated to" ); + + NS_ASSERT_MSG (index < m_rootQueueDiscs.size () && m_rootQueueDiscs[index] != 0, "No root queue disc" + << " installed on device " << device); + + // remove the root queue disc + m_rootQueueDiscs[index] = 0; +} + +void +TrafficControlLayer::SetNode (Ptr node) +{ + NS_LOG_FUNCTION (this << node); + m_node = node; +} + +void +TrafficControlLayer::NotifyNewAggregate () +{ + NS_LOG_FUNCTION (this); + if (m_node == 0) + { + Ptr node = this->GetObject (); + //verify that it's a valid node and that + //the node was not set before + if (node != 0) + { + this->SetNode (node); + } + } + Object::NotifyNewAggregate (); +} + +uint32_t +TrafficControlLayer::GetDeviceIndex (Ptr device) +{ + NS_LOG_FUNCTION (this << device); + uint32_t i; + for (i = 0; i < m_node->GetNDevices () && device != m_node->GetDevice (i); i++); + return i; +} + void TrafficControlLayer::Receive (Ptr device, Ptr p, uint16_t protocol, const Address &from, const Address &to, @@ -110,7 +283,36 @@ TrafficControlLayer::Send (Ptr device, Ptr packet, NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " << protocolNumber); - device->Send (packet, dest, protocolNumber); + std::map, NetDeviceInfo>::iterator qdMap = m_netDeviceQueueToQueueDiscMap.find (device); + NS_ASSERT (qdMap != m_netDeviceQueueToQueueDiscMap.end ()); + Ptr devQueueIface = qdMap->second.first; + NS_ASSERT (devQueueIface); + + // determine the transmission queue of the device where the packet will be enqueued + uint8_t txq = devQueueIface->GetSelectedQueue (Create (packet, dest, protocolNumber)); + NS_ASSERT (txq < devQueueIface->GetTxQueuesN ()); + + if (qdMap->second.second.empty ()) + { + // The device has no attached queue disc, thus send the packet + // directly to the device if the selected queue is not stopped + if (!devQueueIface->GetTxQueue (txq)->IsStopped ()) + { + device->Send (packet, dest, protocolNumber); + } + } + else + { + // Enqueue the packet in the queue disc associated with the netdevice queue + // selected for the packet and try to dequeue packets from such queue disc + Ptr item = Create (packet, dest, protocolNumber); + item->SetTxQueueIndex (txq); + + Ptr qDisc = qdMap->second.second[txq]; + NS_ASSERT (qDisc); + qDisc->Enqueue (item); + qDisc->Run (); + } } } // namespace ns3 diff --git a/src/traffic-control/model/traffic-control-layer.h b/src/traffic-control/model/traffic-control-layer.h index 2dd68bf18..b518c917b 100644 --- a/src/traffic-control/model/traffic-control-layer.h +++ b/src/traffic-control/model/traffic-control-layer.h @@ -1,6 +1,7 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2015 Natale Patriciello + * 2016 Stefano Avallone * * 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 @@ -22,12 +23,17 @@ #include "ns3/address.h" #include "ns3/net-device.h" #include "ns3/node.h" +#include "queue-disc.h" +#include +#include namespace ns3 { class Packet; /** + * \ingroup traffic-control + * * \brief Traffic control layer definition * * This layer stays between NetDevices (L2) and any network protocol (e.g. IP). @@ -37,7 +43,9 @@ class Packet; * Basically, we manage both IN and OUT directions (sometimes called RX and TX, * respectively). The OUT direction is easy to follow, since it involves * direct calls: upper layer (e.g. IP) calls the Send method on an instance of - * this class, which then call the Send method of some NetDevice. + * this class, which then calls the Enqueue method of the QueueDisc associated + * with the device. The Dequeue method of the QueueDisc finally calls the Send + * method of the NetDevice. * * The IN direction uses a little trick to reduce dependencies between modules. * In simple words, we use Callbacks to connect upper layer (which should register @@ -112,6 +120,48 @@ public: uint16_t protocolType, Ptr device); + /// Typedef for queue disc vector + typedef std::vector > QueueDiscVector; + + /** + * \brief Perform the operations that the traffic control layer needs to do when + * an IPv4/v6 interface is added to a device + * \param device the device which the IPv4/v6 interface has been added to + * + * This method creates a NetDeviceQueueInterface for the device + */ + virtual void SetupDevice (Ptr device); + + /** + * \brief This method can be used to set the root queue disc installed on a device + * + * \param device the device on which the provided queue disc will be installed + * \param qDisc the queue disc to be installed as root queue disc on device + */ + virtual void SetRootQueueDiscOnDevice (Ptr device, Ptr qDisc); + + /** + * \brief This method can be used to get the root queue disc installed on a device + * + * \param device the device on which the requested root queue disc is installed + * \return the root queue disc installed on the given device + */ + virtual Ptr GetRootQueueDiscOnDevice (Ptr device); + + /** + * \brief This method can be used to remove the root queue disc (and associated + * filters, classes and queues) installed on a device + * + * \param device the device on which the installed queue disc will be deleted + */ + virtual void DeleteRootQueueDiscOnDevice (Ptr device); + + /** + * \brief Set node associated with this stack. + * \param node node to set + */ + void SetNode (Ptr node); + /** * \brief Called by NetDevices, incoming packet * @@ -141,6 +191,12 @@ public: virtual void Send (Ptr device, Ptr packet, const Address& dest, uint16_t protocolNumber); +protected: + + virtual void DoDispose (void); + virtual void DoInitialize (void); + virtual void NotifyNewAggregate (void); + private: /** * \brief Protocol handler entry. @@ -156,6 +212,24 @@ private: /// Typedef for protocol handlers container typedef std::vector ProtocolHandlerList; + /// Typedef for queue disc vector + typedef std::pair, QueueDiscVector> NetDeviceInfo; + + /** + * \brief Lookup a given Ptr in the node's list of devices + * \param device the device to lookup + * \return the index of device in the node's list of devices, if it is + * found, and the number of devices, otherwise + */ + uint32_t GetDeviceIndex (Ptr device); + + /// The node this TrafficControlLayer object is aggregated to + Ptr m_node; + /// This vector stores the root queue discs installed on all the devices of the node. + /// Devices are sorted as in Node::m_devices + QueueDiscVector m_rootQueueDiscs; + /// This map plays the role of the qdisc field of the netdev_queue struct in Linux + std::map, NetDeviceInfo> m_netDeviceQueueToQueueDiscMap; ProtocolHandlerList m_handlers; //!< List of upper-layer handlers };