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.
This commit is contained in:
Stefano Avallone
2016-05-11 12:08:46 +02:00
parent dcbec12bd7
commit 388695a7a6
2 changed files with 99 additions and 73 deletions

View File

@@ -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<TrafficControlLayer> ()
.AddAttribute ("RootQueueDiscList", "The list of root queue discs associated to this Traffic Control layer.",
ObjectVectorValue (),
MakeObjectVectorAccessor (&TrafficControlLayer::m_rootQueueDiscs),
MakeObjectVectorChecker<QueueDisc> ())
ObjectMapValue (),
MakeObjectMapAccessor (&TrafficControlLayer::GetNDevices,
&TrafficControlLayer::GetRootQueueDiscOnDeviceByIndex),
MakeObjectMapChecker<QueueDisc> ())
;
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<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi;
for (ndi = m_netDevices.begin (); ndi != m_netDevices.end (); ndi++)
{
if (m_rootQueueDiscs[j])
if (ndi->second.rootQueueDisc)
{
Ptr<NetDevice> 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<Ptr<NetDevice>, NetDeviceInfo>::iterator qdMap = m_netDeviceQueueToQueueDiscMap.find (device);
NS_ASSERT (qdMap != m_netDeviceQueueToQueueDiscMap.end ());
Ptr<NetDeviceQueueInterface> devQueueIface = qdMap->second.first;
Ptr<NetDeviceQueueInterface> 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<NetDevice> 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<NetDeviceQueueInterface> ())
{
NS_LOG_DEBUG ("The setup for this device has been already done.");
@@ -132,11 +132,22 @@ TrafficControlLayer::SetupDevice (Ptr<NetDevice> device)
Ptr<NetDeviceQueueInterface> devQueueIface = CreateObject<NetDeviceQueueInterface> ();
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<Ptr<NetDevice>, 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<NetDevice> device, Ptr<QueueDisc> 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<Ptr<NetDevice>, 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<QueueDisc>
TrafficControlLayer::GetRootQueueDiscOnDevice (Ptr<NetDevice> device)
TrafficControlLayer::GetRootQueueDiscOnDevice (Ptr<NetDevice> 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<Ptr<NetDevice>, 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<QueueDisc>
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<NetDevice> 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<Ptr<NetDevice>, 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<NetDevice> 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<NetDevice> device, Ptr<const Packet> p,
uint16_t protocol, const Address &from, const Address &to,
@@ -282,16 +301,16 @@ TrafficControlLayer::Send (Ptr<NetDevice> device, Ptr<QueueDiscItem> item)
NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " <<
item->GetProtocol ());
std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator qdMap = m_netDeviceQueueToQueueDiscMap.find (device);
NS_ASSERT (qdMap != m_netDeviceQueueToQueueDiscMap.end ());
Ptr<NetDeviceQueueInterface> devQueueIface = qdMap->second.first;
std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
NS_ASSERT (ndi != m_netDevices.end ());
Ptr<NetDeviceQueueInterface> 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<NetDevice> device, Ptr<QueueDiscItem> item)
// selected for the packet and try to dequeue packets from such queue disc
item->SetTxQueueIndex (txq);
Ptr<QueueDisc> qDisc = qdMap->second.second[txq];
Ptr<QueueDisc> qDisc = ndi->second.queueDiscsToWake[txq];
NS_ASSERT (qDisc);
qDisc->Enqueue (item);
qDisc->Run ();

View File

@@ -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<QueueDisc> GetRootQueueDiscOnDevice (Ptr<NetDevice> device);
virtual Ptr<QueueDisc> GetRootQueueDiscOnDevice (Ptr<NetDevice> 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<QueueDisc> rootQueueDisc; //!< the root queue disc on the device
Ptr<NetDeviceQueueInterface> ndqi; //!< the netdevice queue interface
QueueDiscVector queueDiscsToWake; //!< the vector of queue discs to wake
};
/// Typedef for protocol handlers container
typedef std::vector<struct ProtocolHandlerEntry> ProtocolHandlerList;
/// Typedef for queue disc vector
typedef std::pair<Ptr<NetDeviceQueueInterface>, QueueDiscVector> NetDeviceInfo;
/**
* \brief Lookup a given Ptr<NetDevice> 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<NetDevice> 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<QueueDisc> GetRootQueueDiscOnDeviceByIndex (uint32_t index) const;
/// The node this TrafficControlLayer object is aggregated to
Ptr<Node> 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<Ptr<NetDevice>, NetDeviceInfo> m_netDeviceQueueToQueueDiscMap;
/// Map storing the required information for each device with a queue disc installed
std::map<Ptr<NetDevice>, NetDeviceInfo> m_netDevices;
ProtocolHandlerList m_handlers; //!< List of upper-layer handlers
};