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
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:353
uint32_t GetNDevices(void) const
Required by the object map accessor.
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.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
uint32_t GetId(void) const
Definition: node.cc:107
bool Enqueue(Ptr< QueueDiscItem > item)
Pass a packet to store to the queue discipline.
Definition: queue-disc.cc:853
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
NS_ASSERT_MSG(false, "Ipv4AddressGenerator::MaskToIndex(): Impossible")
Introspection did not find any typical Config paths.
ProtocolHandlerList m_handlers
List of upper-layer handlers.
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:142
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:204
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
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.
indicates whether the socket has a priority set.
Definition: socket.h:1307
void Run(void)
Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) Dequeues multiple packets...
Definition: queue-disc.cc:947
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
Network device transmission queue interface.
std::vector< Ptr< QueueDisc > > QueueDiscVector
Typedef for queue disc vector.
Ptr< NetDevice > device
the NetDevice
Every class exported by the ns3 library is enclosed in the ns3 namespace.
virtual TypeId GetInstanceTypeId(void) const
Get the type ID for the instance.
static TypeId GetTypeId(void)
Get the type ID.
virtual void Send(Ptr< NetDevice > device, Ptr< QueueDiscItem > item)
Called from upper layer to queue a packet for the transmission.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
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. ...
Protocol handler entry.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:272
Information to store for each device.
Ptr< const AttributeAccessor > MakeObjectMapAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-map.h:80
Ptr< QueueDisc > GetRootQueueDiscOnDeviceByIndex(uint32_t index) const
Required by the object map accessor.
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:325
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:296
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.
virtual Ptr< QueueDisc > GetRootQueueDiscOnDevice(Ptr< NetDevice > device) const
This method can be used to get the root queue disc installed on a device.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:915
virtual void ScanDevices(void)
Collect information needed to determine how to handle packets destined to each of the NetDevices of t...
uint32_t GetNDevices(void) const
Definition: node.cc:150