A Discrete-Event Network Simulator
API
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/net-device-queue-interface.h"
22 #include "ns3/log.h"
23 #include "ns3/object-map.h"
24 #include "ns3/packet.h"
25 #include "ns3/socket.h"
26 #include "ns3/queue-disc.h"
27 #include <tuple>
28 
29 namespace ns3 {
30 
31 NS_LOG_COMPONENT_DEFINE ("TrafficControlLayer");
32 
33 NS_OBJECT_ENSURE_REGISTERED (TrafficControlLayer);
34 
35 TypeId
37 {
38  static TypeId tid = TypeId ("ns3::TrafficControlLayer")
39  .SetParent<Object> ()
40  .SetGroupName ("TrafficControl")
41  .AddConstructor<TrafficControlLayer> ()
42  .AddAttribute ("RootQueueDiscList", "The list of root queue discs associated to this Traffic Control layer.",
43  ObjectMapValue (),
46  MakeObjectMapChecker<QueueDisc> ())
47  ;
48  return tid;
49 }
50 
51 TypeId
53 {
54  return GetTypeId ();
55 }
56 
58  : Object ()
59 {
60  NS_LOG_FUNCTION (this);
61 }
62 
64 {
65  NS_LOG_FUNCTION (this);
66 }
67 
68 void
70 {
71  NS_LOG_FUNCTION (this);
72  m_node = 0;
73  m_handlers.clear ();
74  m_netDevices.clear ();
76 }
77 
78 void
80 {
81  NS_LOG_FUNCTION (this);
82 
83  ScanDevices ();
84 
85  // initialize the root queue discs
86  for (auto& ndi : m_netDevices)
87  {
88  if (ndi.second.m_rootQueueDisc)
89  {
90  ndi.second.m_rootQueueDisc->Initialize ();
91  }
92  }
93 
95 }
96 
97 void
99  uint16_t protocolType, Ptr<NetDevice> device)
100 {
101  NS_LOG_FUNCTION (this << protocolType << device);
102 
103  struct ProtocolHandlerEntry entry;
104  entry.handler = handler;
105  entry.protocol = protocolType;
106  entry.device = device;
107  entry.promiscuous = false;
108 
109  m_handlers.push_back (entry);
110 
111  NS_LOG_DEBUG ("Handler for NetDevice: " << device << " registered for protocol " <<
112  protocolType << ".");
113 }
114 
115 void
117 {
118  NS_LOG_FUNCTION (this);
119 
120  NS_ASSERT_MSG (m_node, "Cannot run ScanDevices without an aggregated node");
121 
122  NS_LOG_DEBUG ("Scanning devices on node " << m_node->GetId ());
123  for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
124  {
125  NS_LOG_DEBUG ("Scanning devices on node " << m_node->GetId ());
126  Ptr<NetDevice> dev = m_node->GetDevice (i);
127  NS_LOG_DEBUG ("Checking device " << i << " with pointer " << dev << " of type " << dev->GetInstanceTypeId ().GetName ());
128 
129  // note: there may be no NetDeviceQueueInterface aggregated to the device
130  Ptr<NetDeviceQueueInterface> ndqi = dev->GetObject<NetDeviceQueueInterface> ();
131  NS_LOG_DEBUG ("Pointer to NetDeviceQueueInterface: " << ndqi);
132 
133  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (dev);
134 
135  if (ndi != m_netDevices.end ())
136  {
137  NS_LOG_DEBUG ("Device entry found; installing NetDeviceQueueInterface pointer " << ndqi << " to internal map");
138  ndi->second.m_ndqi = ndqi;
139  }
140  else if (ndqi)
141  // if no entry for the device is found, it means that no queue disc has been
142  // installed. Nonetheless, create an entry for the device and store a pointer
143  // to the NetDeviceQueueInterface object if the latter is not null, because
144  // the Traffic Control layer checks whether the device queue is stopped even
145  // when there is no queue disc.
146  {
147  NS_LOG_DEBUG ("No device entry found; create entry for device and store pointer to NetDeviceQueueInterface: " << ndqi);
148  m_netDevices[dev] = {nullptr, ndqi, QueueDiscVector ()};
149  ndi = m_netDevices.find (dev);
150  }
151 
152  // if a queue disc is installed, set the wake callbacks on netdevice queues
153  if (ndi != m_netDevices.end () && ndi->second.m_rootQueueDisc)
154  {
155  NS_LOG_DEBUG ("Setting the wake callbacks on NetDevice queues");
156  ndi->second.m_queueDiscsToWake.clear ();
157 
158  if (ndqi)
159  {
160  for (uint16_t i = 0; i < ndqi->GetNTxQueues (); i++)
161  {
162  Ptr<QueueDisc> qd;
163 
164  if (ndi->second.m_rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_ROOT)
165  {
166  qd = ndi->second.m_rootQueueDisc;
167  }
168  else if (ndi->second.m_rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_CHILD)
169  {
170  NS_ABORT_MSG_IF (ndi->second.m_rootQueueDisc->GetNQueueDiscClasses () != ndqi->GetNTxQueues (),
171  "The number of child queue discs does not match the number of netdevice queues");
172 
173  qd = ndi->second.m_rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ();
174  }
175  else
176  {
177  NS_ABORT_MSG ("Invalid wake mode");
178  }
179 
180  ndqi->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run, qd));
181  ndi->second.m_queueDiscsToWake.push_back (qd);
182  }
183  }
184  else
185  {
186  ndi->second.m_queueDiscsToWake.push_back (ndi->second.m_rootQueueDisc);
187  }
188 
189  // set the NetDeviceQueueInterface object and the SendCallback on the queue discs
190  // into which packets are enqueued and dequeued by calling Run
191  for (auto& q : ndi->second.m_queueDiscsToWake)
192  {
193  q->SetNetDeviceQueueInterface (ndqi);
194  q->SetSendCallback ([dev] (Ptr<QueueDiscItem> item)
195  { dev->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ()); });
196  }
197  }
198  }
199 }
200 
201 void
203 {
204  NS_LOG_FUNCTION (this << device << qDisc);
205 
206  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
207 
208  if (ndi == m_netDevices.end ())
209  {
210  // No entry found for this device. Create one.
211  m_netDevices[device] = {qDisc, nullptr, QueueDiscVector ()};
212  }
213  else
214  {
215  NS_ABORT_MSG_IF (ndi->second.m_rootQueueDisc,
216  "Cannot install a root queue disc on a device already having one. "
217  "Delete the existing queue disc first.");
218 
219  ndi->second.m_rootQueueDisc = qDisc;
220  }
221 }
222 
225 {
226  NS_LOG_FUNCTION (this << device);
227 
228  std::map<Ptr<NetDevice>, NetDeviceInfo>::const_iterator ndi = m_netDevices.find (device);
229 
230  if (ndi == m_netDevices.end ())
231  {
232  return 0;
233  }
234  return ndi->second.m_rootQueueDisc;
235 }
236 
239 {
240  NS_LOG_FUNCTION (this << index);
241  return GetRootQueueDiscOnDevice (m_node->GetDevice (index));
242 }
243 
244 void
246 {
247  NS_LOG_FUNCTION (this << device);
248 
249  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
250 
251  NS_ASSERT_MSG (ndi != m_netDevices.end () && ndi->second.m_rootQueueDisc != 0,
252  "No root queue disc installed on device " << device);
253 
254  // remove the root queue disc
255  ndi->second.m_rootQueueDisc = 0;
256  for (auto& q : ndi->second.m_queueDiscsToWake)
257  {
258  q->SetNetDeviceQueueInterface (nullptr);
259  q->SetSendCallback (nullptr);
260  }
261  ndi->second.m_queueDiscsToWake.clear ();
262 
263  Ptr<NetDeviceQueueInterface> ndqi = ndi->second.m_ndqi;
264  if (ndqi)
265  {
266  // remove configured callbacks, if any
267  for (uint16_t i = 0; i < ndqi->GetNTxQueues (); i++)
268  {
269  ndqi->GetTxQueue (i)->SetWakeCallback (MakeNullCallback <void> ());
270  }
271  }
272  else
273  {
274  // remove the empty entry
275  m_netDevices.erase (ndi);
276  }
277 }
278 
279 void
281 {
282  NS_LOG_FUNCTION (this << node);
283  m_node = node;
284 }
285 
286 void
288 {
289  NS_LOG_FUNCTION (this);
290  if (m_node == 0)
291  {
292  Ptr<Node> node = this->GetObject<Node> ();
293  //verify that it's a valid node and that
294  //the node was not set before
295  if (node != 0)
296  {
297  this->SetNode (node);
298  }
299  }
301 }
302 
303 uint32_t
305 {
306  return m_node->GetNDevices ();
307 }
308 
309 
310 void
312  uint16_t protocol, const Address &from, const Address &to,
313  NetDevice::PacketType packetType)
314 {
315  NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType);
316 
317  bool found = false;
318 
319  for (ProtocolHandlerList::iterator i = m_handlers.begin ();
320  i != m_handlers.end (); i++)
321  {
322  if (i->device == 0
323  || (i->device != 0 && i->device == device))
324  {
325  if (i->protocol == 0
326  || i->protocol == protocol)
327  {
328  NS_LOG_DEBUG ("Found handler for packet " << p << ", protocol " <<
329  protocol << " and NetDevice " << device <<
330  ". Send packet up");
331  i->handler (device, p, protocol, from, to, packetType);
332  found = true;
333  }
334  }
335  }
336 
337  NS_ABORT_MSG_IF (!found, "Handler for protocol " << p << " and device " << device <<
338  " not found. It isn't forwarded up; it dies here.");
339 }
340 
341 void
343 {
344  NS_LOG_FUNCTION (this << device << item);
345 
346  NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " <<
347  item->GetProtocol ());
348 
349  Ptr<NetDeviceQueueInterface> devQueueIface;
350  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
351 
352  if (ndi != m_netDevices.end ())
353  {
354  devQueueIface = ndi->second.m_ndqi;
355  }
356 
357  // determine the transmission queue of the device where the packet will be enqueued
358  std::size_t txq = 0;
359  if (devQueueIface && devQueueIface->GetNTxQueues () > 1)
360  {
361  txq = devQueueIface->GetSelectQueueCallback () (item);
362  // otherwise, Linux determines the queue index by using a hash function
363  // and associates such index to the socket which the packet belongs to,
364  // so that subsequent packets of the same socket will be mapped to the
365  // same tx queue (__netdev_pick_tx function in net/core/dev.c). It is
366  // pointless to implement this in ns-3 because currently the multi-queue
367  // devices provide a select queue callback
368  }
369 
370  NS_ASSERT (!devQueueIface || txq < devQueueIface->GetNTxQueues ());
371 
372  if (ndi == m_netDevices.end () || ndi->second.m_rootQueueDisc == 0)
373  {
374  // The device has no attached queue disc, thus add the header to the packet and
375  // send it directly to the device if the selected queue is not stopped
376  if (!devQueueIface || !devQueueIface->GetTxQueue (txq)->IsStopped ())
377  {
378  item->AddHeader ();
379  // a single queue device makes no use of the priority tag
380  if (!devQueueIface || devQueueIface->GetNTxQueues () == 1)
381  {
382  SocketPriorityTag priorityTag;
383  item->GetPacket ()->RemovePacketTag (priorityTag);
384  }
385  device->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ());
386  }
387  }
388  else
389  {
390  // Enqueue the packet in the queue disc associated with the netdevice queue
391  // selected for the packet and try to dequeue packets from such queue disc
392  item->SetTxQueueIndex (txq);
393 
394  Ptr<QueueDisc> qDisc = ndi->second.m_queueDiscsToWake[txq];
395  NS_ASSERT (qDisc);
396  qDisc->Enqueue (item);
397  qDisc->Run ();
398  }
399 }
400 
401 } // namespace ns3
a polymophic address class
Definition: address.h:91
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:297
Network device transmission queue interface.
uint32_t GetId(void) const
Definition: node.cc:109
uint32_t GetNDevices(void) const
Definition: node.cc:152
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:144
A base class which provides memory management and object aggregation.
Definition: object.h:88
virtual void NotifyNewAggregate(void)
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:325
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
virtual void DoInitialize(void)
Initialize() implementation.
Definition: object.cc:353
Container for a set of ns3::Object pointers.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
void Run(void)
Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) Dequeues multiple packets,...
Definition: queue-disc.cc:955
Ptr< QueueDiscClass > GetQueueDiscClass(std::size_t i) const
Get the i-th queue disc class.
Definition: queue-disc.cc:662
bool Enqueue(Ptr< QueueDiscItem > item)
Pass a packet to store to the queue discipline.
Definition: queue-disc.cc:861
indicates whether the socket has a priority set.
Definition: socket.h:1309
Introspection did not find any typical Config paths.
Ptr< QueueDisc > GetRootQueueDiscOnDeviceByIndex(uint32_t index) const
Required by the object map accessor.
virtual void ScanDevices(void)
Collect information needed to determine how to handle packets destined to each of the NetDevices of t...
ProtocolHandlerList m_handlers
List of upper-layer handlers.
virtual TypeId GetInstanceTypeId(void) const
Get the type ID for the instance.
uint32_t GetNDevices(void) const
Required by the object map accessor.
static TypeId GetTypeId(void)
Get the type ID.
Ptr< Node > m_node
The node this TrafficControlLayer object is aggregated to.
std::map< Ptr< NetDevice >, NetDeviceInfo > m_netDevices
Map storing the required information for each device with a queue disc installed.
virtual void DeleteRootQueueDiscOnDevice(Ptr< NetDevice > device)
This method can be used to remove the root queue disc (and associated filters, classes and queues) in...
std::vector< Ptr< QueueDisc > > QueueDiscVector
Typedef for queue disc vector.
virtual void Send(Ptr< NetDevice > device, Ptr< QueueDiscItem > item)
Called from upper layer to queue a packet for the transmission.
void SetNode(Ptr< Node > node)
Set node associated with this stack.
virtual Ptr< QueueDisc > GetRootQueueDiscOnDevice(Ptr< NetDevice > device) const
This method can be used to get the root queue disc installed on a device.
virtual void DoDispose(void)
Destructor implementation.
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.
virtual void NotifyNewAggregate(void)
Notify all Objects aggregated to this one of a new Object being aggregated.
virtual void DoInitialize(void)
Initialize() implementation.
virtual void SetRootQueueDiscOnDevice(Ptr< NetDevice > device, Ptr< QueueDisc > qDisc)
This method can be used to set the root queue disc installed on a device.
void RegisterProtocolHandler(Node::ProtocolHandler handler, uint16_t protocolType, Ptr< NetDevice > device)
Register an IN handler.
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
#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
#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:88
Ptr< const AttributeAccessor > MakeObjectMapAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-map.h:80
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1642
Information to store for each device.
Protocol handler entry.
Node::ProtocolHandler handler
the protocol handler
bool promiscuous
true if it is a promiscuous handler
uint16_t protocol
the protocol number
Ptr< NetDevice > device
the NetDevice