From 388695a7a6e57a4a8ceb8a6ef24dfe86dabc56c7 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Wed, 11 May 2016 12:08:46 +0200 Subject: [PATCH] traffic-control: Make the TrafficControlLayer code more readable Instead of keeping the root queue discs in a vector and the netdevice queue interface and the queue discs to wake in a separate map, keep all this information in a single convenient struct. --- .../model/traffic-control-layer.cc | 137 ++++++++++-------- .../model/traffic-control-layer.h | 35 +++-- 2 files changed, 99 insertions(+), 73 deletions(-) diff --git a/src/traffic-control/model/traffic-control-layer.cc b/src/traffic-control/model/traffic-control-layer.cc index d2183e74f..646ff3f18 100644 --- a/src/traffic-control/model/traffic-control-layer.cc +++ b/src/traffic-control/model/traffic-control-layer.cc @@ -19,7 +19,7 @@ #include "traffic-control-layer.h" #include "ns3/log.h" -#include "ns3/object-vector.h" +#include "ns3/object-map.h" #include "ns3/packet.h" #include "ns3/queue-disc.h" @@ -37,9 +37,10 @@ TrafficControlLayer::GetTypeId (void) .SetGroupName ("TrafficControl") .AddConstructor () .AddAttribute ("RootQueueDiscList", "The list of root queue discs associated to this Traffic Control layer.", - ObjectVectorValue (), - MakeObjectVectorAccessor (&TrafficControlLayer::m_rootQueueDiscs), - MakeObjectVectorChecker ()) + ObjectMapValue (), + MakeObjectMapAccessor (&TrafficControlLayer::GetNDevices, + &TrafficControlLayer::GetRootQueueDiscOnDeviceByIndex), + MakeObjectMapChecker ()) ; return tid; } @@ -61,9 +62,8 @@ TrafficControlLayer::DoDispose (void) { NS_LOG_FUNCTION (this); m_node = 0; - m_rootQueueDiscs.clear (); m_handlers.clear (); - m_netDeviceQueueToQueueDiscMap.clear (); + m_netDevices.clear (); Object::DoDispose (); } @@ -71,46 +71,44 @@ void TrafficControlLayer::DoInitialize (void) { NS_LOG_FUNCTION (this); - for (uint32_t j = 0; j < m_rootQueueDiscs.size (); j++) + std::map, NetDeviceInfo>::iterator ndi; + for (ndi = m_netDevices.begin (); ndi != m_netDevices.end (); ndi++) { - if (m_rootQueueDiscs[j]) + if (ndi->second.rootQueueDisc) { - 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 (); + ndi->first->Initialize (); - std::map, NetDeviceInfo>::iterator qdMap = m_netDeviceQueueToQueueDiscMap.find (device); - NS_ASSERT (qdMap != m_netDeviceQueueToQueueDiscMap.end ()); - Ptr devQueueIface = qdMap->second.first; + Ptr devQueueIface = ndi->second.ndqi; NS_ASSERT (devQueueIface); devQueueIface->SetQueueDiscInstalled (true); // set the wake callbacks on netdevice queues - if (m_rootQueueDiscs[j]->GetWakeMode () == QueueDisc::WAKE_ROOT) + if (ndi->second.rootQueueDisc->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]); + devQueueIface->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run, ndi->second.rootQueueDisc)); + ndi->second.queueDiscsToWake.push_back (ndi->second.rootQueueDisc); } } - else if (m_rootQueueDiscs[j]->GetWakeMode () == QueueDisc::WAKE_CHILD) + else if (ndi->second.rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_CHILD) { - NS_ASSERT_MSG (m_rootQueueDiscs[j]->GetNQueueDiscClasses () == devQueueIface->GetTxQueuesN (), + NS_ASSERT_MSG (ndi->second.rootQueueDisc->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 ()); + ndi->second.rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ())); + ndi->second.queueDiscsToWake.push_back (ndi->second.rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ()); } } // initialize the queue disc - m_rootQueueDiscs[j]->Initialize (); + ndi->second.rootQueueDisc->Initialize (); } } Object::DoInitialize (); @@ -121,7 +119,9 @@ TrafficControlLayer::SetupDevice (Ptr device) { NS_LOG_FUNCTION (this << device); - // ensure this setup is done just once (in case of dual stack nodes) + // ensure this setup is done just once. SetupDevice is called by Ipv4L3Protocol + // and Ipv6L3Protocol when they add an interface, thus it might be called twice + // in case of dual stack nodes if (device->GetObject ()) { NS_LOG_DEBUG ("The setup for this device has been already done."); @@ -132,11 +132,22 @@ TrafficControlLayer::SetupDevice (Ptr 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"); + // create an entry in the m_netDevices map for this device, if not existing yet. + // If the tc helper is invoked (to install a queue disc) before the creation of the + // Ipv{4,6}Interface, an entry for this device will be already present in the map + std::map, NetDeviceInfo>::iterator ndi = m_netDevices.find (device); - m_netDeviceQueueToQueueDiscMap[device] = NetDeviceInfo (devQueueIface, QueueDiscVector ()); + if (ndi == m_netDevices.end ()) + { + NetDeviceInfo entry = {0, devQueueIface, QueueDiscVector ()}; + m_netDevices[device] = entry; + } + else + { + NS_ASSERT_MSG (ndi->second.ndqi == 0, "This is a bug, there is no netdevice queue interface " + << "aggregated to the device but the pointer is not null."); + ndi->second.ndqi = devQueueIface; + } } void @@ -160,35 +171,46 @@ TrafficControlLayer::RegisterProtocolHandler (Node::ProtocolHandler handler, void TrafficControlLayer::SetRootQueueDiscOnDevice (Ptr device, Ptr qDisc) { - NS_LOG_FUNCTION (this << device); + NS_LOG_FUNCTION (this << device << qDisc); - 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 ()) + std::map, NetDeviceInfo>::iterator ndi = m_netDevices.find (device); + + if (ndi == m_netDevices.end ()) { - m_rootQueueDiscs.resize (index+1); + // SetupDevice has not been called yet. This may happen when the tc helper is + // invoked (to install a queue disc) before the creation of the Ipv{4,6}Interface + NetDeviceInfo entry = {qDisc, 0, QueueDiscVector ()}; + m_netDevices[device] = entry; + } + else + { + NS_ASSERT_MSG (ndi->second.rootQueueDisc == 0, "Cannot install a root queue disc on a " + << "device already having one. Delete the existing queue disc first."); + ndi->second.rootQueueDisc = qDisc; } - - 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) +TrafficControlLayer::GetRootQueueDiscOnDevice (Ptr device) const { 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 ()) + std::map, NetDeviceInfo>::const_iterator ndi = m_netDevices.find (device); + + if (ndi == m_netDevices.end ()) { - m_rootQueueDiscs.resize (index+1); + NS_LOG_WARN ("GetRootQueueDiscOnDevice should not be called before the " + << "device is setup or a queue disc is installed on the device."); + return 0; } - return m_rootQueueDiscs[index]; + return ndi->second.rootQueueDisc; +} + +Ptr +TrafficControlLayer::GetRootQueueDiscOnDeviceByIndex (uint32_t index) const +{ + NS_LOG_FUNCTION (this << index); + return GetRootQueueDiscOnDevice (m_node->GetDevice (index)); } void @@ -196,15 +218,14 @@ 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" ); + std::map, NetDeviceInfo>::iterator ndi = m_netDevices.find (device); - NS_ASSERT_MSG (index < m_rootQueueDiscs.size () && m_rootQueueDiscs[index] != 0, "No root queue disc" + NS_ASSERT_MSG (ndi != m_netDevices.end () && ndi->second.rootQueueDisc != 0, "No root queue disc" << " installed on device " << device); // remove the root queue disc - m_rootQueueDiscs[index] = 0; + ndi->second.rootQueueDisc = 0; + ndi->second.queueDiscsToWake.clear (); } void @@ -232,14 +253,12 @@ TrafficControlLayer::NotifyNewAggregate () } uint32_t -TrafficControlLayer::GetDeviceIndex (Ptr device) +TrafficControlLayer::GetNDevices (void) const { - NS_LOG_FUNCTION (this << device); - uint32_t i; - for (i = 0; i < m_node->GetNDevices () && device != m_node->GetDevice (i); i++); - return i; + return m_netDevices.size(); } + void TrafficControlLayer::Receive (Ptr device, Ptr p, uint16_t protocol, const Address &from, const Address &to, @@ -282,16 +301,16 @@ TrafficControlLayer::Send (Ptr device, Ptr item) NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " << item->GetProtocol ()); - std::map, NetDeviceInfo>::iterator qdMap = m_netDeviceQueueToQueueDiscMap.find (device); - NS_ASSERT (qdMap != m_netDeviceQueueToQueueDiscMap.end ()); - Ptr devQueueIface = qdMap->second.first; + std::map, NetDeviceInfo>::iterator ndi = m_netDevices.find (device); + NS_ASSERT (ndi != m_netDevices.end ()); + Ptr devQueueIface = ndi->second.ndqi; NS_ASSERT (devQueueIface); // determine the transmission queue of the device where the packet will be enqueued uint8_t txq = devQueueIface->GetSelectedQueue (item); NS_ASSERT (txq < devQueueIface->GetTxQueuesN ()); - if (qdMap->second.second.empty ()) + if (ndi->second.rootQueueDisc == 0) { // The device has no attached queue disc, thus add the header to the packet and // send it directly to the device if the selected queue is not stopped @@ -307,7 +326,7 @@ TrafficControlLayer::Send (Ptr device, Ptr item) // selected for the packet and try to dequeue packets from such queue disc item->SetTxQueueIndex (txq); - Ptr qDisc = qdMap->second.second[txq]; + Ptr qDisc = ndi->second.queueDiscsToWake[txq]; NS_ASSERT (qDisc); qDisc->Enqueue (item); qDisc->Run (); diff --git a/src/traffic-control/model/traffic-control-layer.h b/src/traffic-control/model/traffic-control-layer.h index 0cd095b25..71875557c 100644 --- a/src/traffic-control/model/traffic-control-layer.h +++ b/src/traffic-control/model/traffic-control-layer.h @@ -147,7 +147,7 @@ public: * \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); + virtual Ptr GetRootQueueDiscOnDevice (Ptr device) const; /** * \brief This method can be used to remove the root queue disc (and associated @@ -215,27 +215,34 @@ private: bool promiscuous; //!< true if it is a promiscuous handler }; + /** + * \brief Information to store for each device + */ + struct NetDeviceInfo { + Ptr rootQueueDisc; //!< the root queue disc on the device + Ptr ndqi; //!< the netdevice queue interface + QueueDiscVector queueDiscsToWake; //!< the vector of queue discs to wake + }; + /// 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 + * \brief Required by the object map accessor + * \return the number of devices in the m_netDevices map */ - uint32_t GetDeviceIndex (Ptr device); + uint32_t GetNDevices (void) const; + /** + * \brief Required by the object map accessor + * \param index the index of the device in the node's device list + * \return the root queue disc installed on the specified device + */ + Ptr GetRootQueueDiscOnDeviceByIndex (uint32_t index) const; /// 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; + /// Map storing the required information for each device with a queue disc installed + std::map, NetDeviceInfo> m_netDevices; ProtocolHandlerList m_handlers; //!< List of upper-layer handlers };