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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user