traffic-control: The traffic control layer enqueues packets in the queue disc

...aggregated to the outgoing network device, if any. Otherwise,
packets are sent directly to the device.
This commit is contained in:
Stefano Avallone
2016-03-08 10:44:19 -08:00
parent bedc89eea9
commit 374639c6fe
2 changed files with 278 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2015 Natale Patriciello <natale.patriciello@gmail.com>
* 2016 Stefano Avallone <stavallo@unina.it>
*
* 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<Object> ()
.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> ())
;
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<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 ();
std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator qdMap = m_netDeviceQueueToQueueDiscMap.find (device);
NS_ASSERT (qdMap != m_netDeviceQueueToQueueDiscMap.end ());
Ptr<NetDeviceQueueInterface> 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<NetDevice> device)
{
NS_LOG_FUNCTION (this << device);
// ensure this setup is done just once (in case of dual stack nodes)
if (device->GetObject<NetDeviceQueueInterface> ())
{
NS_LOG_DEBUG ("The setup for this device has been already done.");
return;
}
// create a NetDeviceQueueInterface object and aggregate it to the 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");
m_netDeviceQueueToQueueDiscMap[device] = NetDeviceInfo (devQueueIface, QueueDiscVector ());
}
void
TrafficControlLayer::RegisterProtocolHandler (Node::ProtocolHandler handler,
uint16_t protocolType, Ptr<NetDevice> device)
@@ -67,6 +157,89 @@ TrafficControlLayer::RegisterProtocolHandler (Node::ProtocolHandler handler,
protocolType << ".");
}
void
TrafficControlLayer::SetRootQueueDiscOnDevice (Ptr<NetDevice> device, Ptr<QueueDisc> 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<QueueDisc>
TrafficControlLayer::GetRootQueueDiscOnDevice (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" );
if (index >= m_rootQueueDiscs.size ())
{
m_rootQueueDiscs.resize (index+1);
}
return m_rootQueueDiscs[index];
}
void
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" );
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> node)
{
NS_LOG_FUNCTION (this << node);
m_node = node;
}
void
TrafficControlLayer::NotifyNewAggregate ()
{
NS_LOG_FUNCTION (this);
if (m_node == 0)
{
Ptr<Node> node = this->GetObject<Node> ();
//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<NetDevice> 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<NetDevice> device, Ptr<const Packet> p,
uint16_t protocol, const Address &from, const Address &to,
@@ -110,7 +283,36 @@ TrafficControlLayer::Send (Ptr<NetDevice> device, Ptr<Packet> packet,
NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " <<
protocolNumber);
device->Send (packet, dest, protocolNumber);
std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator qdMap = m_netDeviceQueueToQueueDiscMap.find (device);
NS_ASSERT (qdMap != m_netDeviceQueueToQueueDiscMap.end ());
Ptr<NetDeviceQueueInterface> 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<QueueDiscItem> (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<QueueDiscItem> item = Create<QueueDiscItem> (packet, dest, protocolNumber);
item->SetTxQueueIndex (txq);
Ptr<QueueDisc> qDisc = qdMap->second.second[txq];
NS_ASSERT (qDisc);
qDisc->Enqueue (item);
qDisc->Run ();
}
}
} // namespace ns3

View File

@@ -1,6 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2015 Natale Patriciello <natale.patriciello@gmail.com>
* 2016 Stefano Avallone <stavallo@unina.it>
*
* 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 <map>
#include <vector>
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<NetDevice> device);
/// Typedef for queue disc vector
typedef std::vector<Ptr<QueueDisc> > 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<NetDevice> 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<NetDevice> device, Ptr<QueueDisc> 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<QueueDisc> GetRootQueueDiscOnDevice (Ptr<NetDevice> 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<NetDevice> device);
/**
* \brief Set node associated with this stack.
* \param node node to set
*/
void SetNode (Ptr<Node> node);
/**
* \brief Called by NetDevices, incoming packet
*
@@ -141,6 +191,12 @@ public:
virtual void Send (Ptr<NetDevice> device, Ptr<Packet> 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<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
*/
uint32_t GetDeviceIndex (Ptr<NetDevice> device);
/// 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;
ProtocolHandlerList m_handlers; //!< List of upper-layer handlers
};