A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
traffic-control-layer.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2015 Natale Patriciello <natale.patriciello@gmail.com>
4  * 2016 Stefano Avallone <stavallo@unina.it>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19 
20 #include "traffic-control-layer.h"
21 #include "ns3/log.h"
22 #include "ns3/object-map.h"
23 #include "ns3/packet.h"
24 #include "ns3/queue-disc.h"
25 
26 namespace ns3 {
27 
28 NS_LOG_COMPONENT_DEFINE ("TrafficControlLayer");
29 
30 NS_OBJECT_ENSURE_REGISTERED (TrafficControlLayer);
31 
32 TypeId
34 {
35  static TypeId tid = TypeId ("ns3::TrafficControlLayer")
36  .SetParent<Object> ()
37  .SetGroupName ("TrafficControl")
38  .AddConstructor<TrafficControlLayer> ()
39  .AddAttribute ("RootQueueDiscList", "The list of root queue discs associated to this Traffic Control layer.",
40  ObjectMapValue (),
43  MakeObjectMapChecker<QueueDisc> ())
44  ;
45  return tid;
46 }
47 
48 TypeId
50 {
51  return GetTypeId ();
52 }
53 
55  : Object ()
56 {
58 }
59 
60 void
62 {
63  NS_LOG_FUNCTION (this);
64  m_node = 0;
65  m_handlers.clear ();
66  m_netDevices.clear ();
68 }
69 
70 void
72 {
73  NS_LOG_FUNCTION (this);
74  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi;
75  for (ndi = m_netDevices.begin (); ndi != m_netDevices.end (); ndi++)
76  {
77  if (ndi->second.rootQueueDisc)
78  {
79  // NetDevices supporting flow control can set the number of device transmission
80  // queues through the NetDevice queue interface during initialization. Thus,
81  // ensure that the device has completed initialization
82  ndi->first->Initialize ();
83 
84  Ptr<NetDeviceQueueInterface> devQueueIface = ndi->second.ndqi;
85  NS_ASSERT (devQueueIface);
86 
87  // set the wake callbacks on netdevice queues
88  if (ndi->second.rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_ROOT)
89  {
90  for (uint32_t i = 0; i < devQueueIface->GetTxQueuesN (); i++)
91  {
92  devQueueIface->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run, ndi->second.rootQueueDisc));
93  ndi->second.queueDiscsToWake.push_back (ndi->second.rootQueueDisc);
94  }
95  }
96  else if (ndi->second.rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_CHILD)
97  {
98  NS_ASSERT_MSG (ndi->second.rootQueueDisc->GetNQueueDiscClasses () == devQueueIface->GetTxQueuesN (),
99  "The number of child queue discs does not match the number of netdevice queues");
100  for (uint32_t i = 0; i < devQueueIface->GetTxQueuesN (); i++)
101  {
102  devQueueIface->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run,
103  ndi->second.rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ()));
104  ndi->second.queueDiscsToWake.push_back (ndi->second.rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ());
105  }
106  }
107 
108  // initialize the queue disc
109  ndi->second.rootQueueDisc->Initialize ();
110  }
111  }
113 }
114 
115 void
117 {
118  NS_LOG_FUNCTION (this << device);
119 
120  // ensure this setup is done just once. SetupDevice is called by Ipv4L3Protocol
121  // and Ipv6L3Protocol when they add an interface, thus it might be called twice
122  // in case of dual stack nodes
123  if (device->GetObject<NetDeviceQueueInterface> ())
124  {
125  NS_LOG_DEBUG ("The setup for this device has been already done.");
126  return;
127  }
128 
129  // create a NetDeviceQueueInterface object and aggregate it to the device
130  Ptr<NetDeviceQueueInterface> devQueueIface = CreateObject<NetDeviceQueueInterface> ();
131  device->AggregateObject (devQueueIface);
132 
133  // create an entry in the m_netDevices map for this device, if not existing yet.
134  // If the tc helper is invoked (to install a queue disc) before the creation of the
135  // Ipv{4,6}Interface, an entry for this device will be already present in the map
136  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
137 
138  if (ndi == m_netDevices.end ())
139  {
140  NetDeviceInfo entry = {0, devQueueIface, QueueDiscVector ()};
141  m_netDevices[device] = entry;
142  }
143  else
144  {
145  NS_ASSERT_MSG (ndi->second.ndqi == 0, "This is a bug, there is no netdevice queue interface "
146  << "aggregated to the device but the pointer is not null.");
147  ndi->second.ndqi = devQueueIface;
148  }
149 }
150 
151 void
153  uint16_t protocolType, Ptr<NetDevice> device)
154 {
155  NS_LOG_FUNCTION (this << protocolType << device);
156 
157  struct ProtocolHandlerEntry entry;
158  entry.handler = handler;
159  entry.protocol = protocolType;
160  entry.device = device;
161  entry.promiscuous = false;
162 
163  m_handlers.push_back (entry);
164 
165  NS_LOG_DEBUG ("Handler for NetDevice: " << device << " registered for protocol " <<
166  protocolType << ".");
167 }
168 
169 void
171 {
172  NS_LOG_FUNCTION (this << device << qDisc);
173 
174  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
175 
176  if (ndi == m_netDevices.end ())
177  {
178  // SetupDevice has not been called yet. This may happen when the tc helper is
179  // invoked (to install a queue disc) before the creation of the Ipv{4,6}Interface
180  NetDeviceInfo entry = {qDisc, 0, QueueDiscVector ()};
181  m_netDevices[device] = entry;
182  }
183  else
184  {
185  NS_ASSERT_MSG (ndi->second.rootQueueDisc == 0, "Cannot install a root queue disc on a "
186  << "device already having one. Delete the existing queue disc first.");
187  ndi->second.rootQueueDisc = qDisc;
188  }
189 }
190 
193 {
194  NS_LOG_FUNCTION (this << device);
195 
196  std::map<Ptr<NetDevice>, NetDeviceInfo>::const_iterator ndi = m_netDevices.find (device);
197 
198  if (ndi == m_netDevices.end ())
199  {
200  NS_LOG_WARN ("GetRootQueueDiscOnDevice should not be called before the "
201  << "device is setup or a queue disc is installed on the device.");
202  return 0;
203  }
204  return ndi->second.rootQueueDisc;
205 }
206 
209 {
210  NS_LOG_FUNCTION (this << index);
211  return GetRootQueueDiscOnDevice (m_node->GetDevice (index));
212 }
213 
214 void
216 {
217  NS_LOG_FUNCTION (this << device);
218 
219  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
220 
221  NS_ASSERT_MSG (ndi != m_netDevices.end () && ndi->second.rootQueueDisc != 0, "No root queue disc"
222  << " installed on device " << device);
223 
224  // remove the root queue disc
225  ndi->second.rootQueueDisc = 0;
226  ndi->second.queueDiscsToWake.clear ();
227 }
228 
229 void
231 {
232  NS_LOG_FUNCTION (this << node);
233  m_node = node;
234 }
235 
236 void
238 {
239  NS_LOG_FUNCTION (this);
240  if (m_node == 0)
241  {
242  Ptr<Node> node = this->GetObject<Node> ();
243  //verify that it's a valid node and that
244  //the node was not set before
245  if (node != 0)
246  {
247  this->SetNode (node);
248  }
249  }
251 }
252 
253 uint32_t
255 {
256  return m_netDevices.size();
257 }
258 
259 
260 void
262  uint16_t protocol, const Address &from, const Address &to,
263  NetDevice::PacketType packetType)
264 {
265  NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType);
266 
267  bool found = false;
268 
269  for (ProtocolHandlerList::iterator i = m_handlers.begin ();
270  i != m_handlers.end (); i++)
271  {
272  if (i->device == 0
273  || (i->device != 0 && i->device == device))
274  {
275  if (i->protocol == 0
276  || i->protocol == protocol)
277  {
278  NS_LOG_DEBUG ("Found handler for packet " << p << ", protocol " <<
279  protocol << " and NetDevice " << device <<
280  ". Send packet up");
281  i->handler (device, p, protocol, from, to, packetType);
282  found = true;
283  }
284  }
285  }
286 
287  if (! found)
288  {
289  NS_FATAL_ERROR ("Handler for protocol " << p << " and device " << device <<
290  " not found. It isn't forwarded up; it dies here.");
291  }
292 }
293 
294 void
296 {
297  NS_LOG_FUNCTION (this << device << item);
298 
299  NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " <<
300  item->GetProtocol ());
301 
302  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
303  NS_ASSERT (ndi != m_netDevices.end ());
304  Ptr<NetDeviceQueueInterface> devQueueIface = ndi->second.ndqi;
305  NS_ASSERT (devQueueIface);
306 
307  // determine the transmission queue of the device where the packet will be enqueued
308  uint8_t txq = devQueueIface->GetSelectedQueue (item);
309  NS_ASSERT (txq < devQueueIface->GetTxQueuesN ());
310 
311  if (ndi->second.rootQueueDisc == 0)
312  {
313  // The device has no attached queue disc, thus add the header to the packet and
314  // send it directly to the device if the selected queue is not stopped
315  if (!devQueueIface->GetTxQueue (txq)->IsStopped ())
316  {
317  item->AddHeader ();
318  device->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ());
319  }
320  }
321  else
322  {
323  // Enqueue the packet in the queue disc associated with the netdevice queue
324  // selected for the packet and try to dequeue packets from such queue disc
325  item->SetTxQueueIndex (txq);
326 
327  Ptr<QueueDisc> qDisc = ndi->second.queueDiscsToWake[txq];
328  NS_ASSERT (qDisc);
329  qDisc->Enqueue (item);
330  qDisc->Run ();
331  }
332 }
333 
334 } // namespace ns3
virtual void DeleteRootQueueDiscOnDevice(Ptr< NetDevice > device)
This method can be used to remove the root queue disc (and associated filters, classes and queues) in...
virtual void DoInitialize(void)
Initialize() implementation.
Definition: object.cc:347
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
virtual void SetRootQueueDiscOnDevice(Ptr< NetDevice > device, Ptr< QueueDisc > qDisc)
This method can be used to set the root queue disc installed on a device.
bool Enqueue(Ptr< QueueDiscItem > item)
Pass a packet to store to the queue discipline.
Definition: queue-disc.cc:450
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
Traffic control layer definition.
ProtocolHandlerList m_handlers
List of upper-layer handlers.
bool promiscuous
true if it is a promiscuous handler
virtual void DoInitialize(void)
Initialize() implementation.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
virtual void NotifyNewAggregate(void)
Notify all Objects aggregated to this one of a new Object being aggregated.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:340
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
virtual void Receive(Ptr< NetDevice > device, Ptr< const Packet > p, uint16_t protocol, const Address &from, const Address &to, NetDevice::PacketType packetType)
Called by NetDevices, incoming packet.
uint16_t protocol
the protocol number
a polymophic address class
Definition: address.h:90
void SetNode(Ptr< Node > node)
Set node associated with this stack.
void Run(void)
Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) Dequeues multiple packets...
Definition: queue-disc.cc:493
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:142
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
Network device transmission queue interface.
Definition: net-device.h:219
std::vector< Ptr< QueueDisc > > QueueDiscVector
Typedef for queue disc vector.
Ptr< NetDevice > device
the NetDevice
static TypeId GetTypeId(void)
Get the type ID.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:90
virtual void Send(Ptr< NetDevice > device, Ptr< QueueDiscItem > item)
Called from upper layer to queue a packet for the transmission.
Ptr< Node > m_node
The node this TrafficControlLayer object is aggregated to.
virtual Ptr< QueueDisc > GetRootQueueDiscOnDevice(Ptr< NetDevice > device) const
This method can be used to get the root queue disc installed on a device.
std::map< Ptr< NetDevice >, NetDeviceInfo > m_netDevices
Map storing the required information for each device with a queue disc installed. ...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:228
Protocol handler entry.
virtual void SetupDevice(Ptr< NetDevice > device)
Perform the operations that the traffic control layer needs to do when an IPv4/v6 interface is added ...
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:236
uint32_t GetNDevices(void) const
Required by the object map accessor.
Information to store for each device.
Ptr< const AttributeAccessor > MakeObjectMapAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-map.h:80
Node::ProtocolHandler handler
the protocol handler
A base class which provides memory management and object aggregation.
Definition: object.h:87
virtual void NotifyNewAggregate(void)
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:319
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:546
virtual TypeId GetInstanceTypeId(void) const
Get the type ID for the instance.
Container for a set of ns3::Object pointers.
virtual void DoDispose(void)
Destructor implementation.
a unique identifier for an interface.
Definition: type-id.h:58
void RegisterProtocolHandler(Node::ProtocolHandler handler, uint16_t protocolType, Ptr< NetDevice > device)
Register an IN handler.
Ptr< QueueDisc > GetRootQueueDiscOnDeviceByIndex(uint32_t index) const
Required by the object map accessor.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:827