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 {
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  for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
123  {
124  Ptr<NetDevice> dev = m_node->GetDevice (i);
125 
126  // note: there may be no NetDeviceQueueInterface aggregated to the device
127  Ptr<NetDeviceQueueInterface> ndqi = dev->GetObject<NetDeviceQueueInterface> ();
128 
129  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (dev);
130 
131  if (ndi != m_netDevices.end ())
132  {
133  ndi->second.m_ndqi = ndqi;
134  }
135  else if (ndqi)
136  // if no entry for the device is found, it means that no queue disc has been
137  // installed. Nonetheless, create an entry for the device and store a pointer
138  // to the NetDeviceQueueInterface object if the latter is not null, because
139  // the Traffic Control layer checks whether the device queue is stopped even
140  // when there is no queue disc.
141  {
142  m_netDevices[dev] = {nullptr, ndqi, QueueDiscVector ()};
143  ndi = m_netDevices.find (dev);
144  }
145 
146  // if a queue disc is installed, set the wake callbacks on netdevice queues
147  if (ndi != m_netDevices.end () && ndi->second.m_rootQueueDisc)
148  {
149  ndi->second.m_queueDiscsToWake.clear ();
150 
151  if (ndqi)
152  {
153  for (uint16_t i = 0; i < ndqi->GetNTxQueues (); i++)
154  {
155  Ptr<QueueDisc> qd;
156 
157  if (ndi->second.m_rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_ROOT)
158  {
159  qd = ndi->second.m_rootQueueDisc;
160  }
161  else if (ndi->second.m_rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_CHILD)
162  {
163  NS_ABORT_MSG_IF (ndi->second.m_rootQueueDisc->GetNQueueDiscClasses () != ndqi->GetNTxQueues (),
164  "The number of child queue discs does not match the number of netdevice queues");
165 
166  qd = ndi->second.m_rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ();
167  }
168  else
169  {
170  NS_ABORT_MSG ("Invalid wake mode");
171  }
172 
173  ndqi->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run, qd));
174  ndi->second.m_queueDiscsToWake.push_back (qd);
175  }
176  }
177  else
178  {
179  ndi->second.m_queueDiscsToWake.push_back (ndi->second.m_rootQueueDisc);
180  }
181 
182  // set the NetDeviceQueueInterface object and the SendCallback on the queue discs
183  // into which packets are enqueued and dequeued by calling Run
184  for (auto& q : ndi->second.m_queueDiscsToWake)
185  {
186  q->SetNetDeviceQueueInterface (ndqi);
187  q->SetSendCallback ([dev] (Ptr<QueueDiscItem> item)
188  { dev->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ()); });
189  }
190  }
191  }
192 }
193 
194 void
196 {
197  NS_LOG_FUNCTION (this << device << qDisc);
198 
199  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
200 
201  if (ndi == m_netDevices.end ())
202  {
203  // No entry found for this device. Create one.
204  m_netDevices[device] = {qDisc, nullptr, QueueDiscVector ()};
205  }
206  else
207  {
208  NS_ABORT_MSG_IF (ndi->second.m_rootQueueDisc,
209  "Cannot install a root queue disc on a device already having one. "
210  "Delete the existing queue disc first.");
211 
212  ndi->second.m_rootQueueDisc = qDisc;
213  }
214 }
215 
218 {
219  NS_LOG_FUNCTION (this << device);
220 
221  std::map<Ptr<NetDevice>, NetDeviceInfo>::const_iterator ndi = m_netDevices.find (device);
222 
223  if (ndi == m_netDevices.end ())
224  {
225  return 0;
226  }
227  return ndi->second.m_rootQueueDisc;
228 }
229 
232 {
233  NS_LOG_FUNCTION (this << index);
234  return GetRootQueueDiscOnDevice (m_node->GetDevice (index));
235 }
236 
237 void
239 {
240  NS_LOG_FUNCTION (this << device);
241 
242  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
243 
244  NS_ASSERT_MSG (ndi != m_netDevices.end () && ndi->second.m_rootQueueDisc != 0,
245  "No root queue disc installed on device " << device);
246 
247  // remove the root queue disc
248  ndi->second.m_rootQueueDisc = 0;
249  for (auto& q : ndi->second.m_queueDiscsToWake)
250  {
251  q->SetNetDeviceQueueInterface (nullptr);
252  q->SetSendCallback (nullptr);
253  }
254  ndi->second.m_queueDiscsToWake.clear ();
255 
256  Ptr<NetDeviceQueueInterface> ndqi = ndi->second.m_ndqi;
257  if (ndqi)
258  {
259  // remove configured callbacks, if any
260  for (uint16_t i = 0; i < ndqi->GetNTxQueues (); i++)
261  {
262  ndqi->GetTxQueue (i)->SetWakeCallback (MakeNullCallback <void> ());
263  }
264  }
265  else
266  {
267  // remove the empty entry
268  m_netDevices.erase (ndi);
269  }
270 }
271 
272 void
274 {
275  NS_LOG_FUNCTION (this << node);
276  m_node = node;
277 }
278 
279 void
281 {
282  NS_LOG_FUNCTION (this);
283  if (m_node == 0)
284  {
285  Ptr<Node> node = this->GetObject<Node> ();
286  //verify that it's a valid node and that
287  //the node was not set before
288  if (node != 0)
289  {
290  this->SetNode (node);
291  }
292  }
294 }
295 
296 uint32_t
298 {
299  return m_node->GetNDevices ();
300 }
301 
302 
303 void
305  uint16_t protocol, const Address &from, const Address &to,
306  NetDevice::PacketType packetType)
307 {
308  NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType);
309 
310  bool found = false;
311 
312  for (ProtocolHandlerList::iterator i = m_handlers.begin ();
313  i != m_handlers.end (); i++)
314  {
315  if (i->device == 0
316  || (i->device != 0 && i->device == device))
317  {
318  if (i->protocol == 0
319  || i->protocol == protocol)
320  {
321  NS_LOG_DEBUG ("Found handler for packet " << p << ", protocol " <<
322  protocol << " and NetDevice " << device <<
323  ". Send packet up");
324  i->handler (device, p, protocol, from, to, packetType);
325  found = true;
326  }
327  }
328  }
329 
330  NS_ABORT_MSG_IF (!found, "Handler for protocol " << p << " and device " << device <<
331  " not found. It isn't forwarded up; it dies here.");
332 }
333 
334 void
336 {
337  NS_LOG_FUNCTION (this << device << item);
338 
339  NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " <<
340  item->GetProtocol ());
341 
342  Ptr<NetDeviceQueueInterface> devQueueIface;
343  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
344 
345  if (ndi != m_netDevices.end ())
346  {
347  devQueueIface = ndi->second.m_ndqi;
348  }
349 
350  // determine the transmission queue of the device where the packet will be enqueued
351  std::size_t txq = 0;
352  if (devQueueIface && devQueueIface->GetNTxQueues () > 1)
353  {
354  txq = devQueueIface->GetSelectQueueCallback () (item);
355  // otherwise, Linux determines the queue index by using a hash function
356  // and associates such index to the socket which the packet belongs to,
357  // so that subsequent packets of the same socket will be mapped to the
358  // same tx queue (__netdev_pick_tx function in net/core/dev.c). It is
359  // pointless to implement this in ns-3 because currently the multi-queue
360  // devices provide a select queue callback
361  }
362 
363  NS_ASSERT (!devQueueIface || txq < devQueueIface->GetNTxQueues ());
364 
365  if (ndi == m_netDevices.end () || ndi->second.m_rootQueueDisc == 0)
366  {
367  // The device has no attached queue disc, thus add the header to the packet and
368  // send it directly to the device if the selected queue is not stopped
369  if (!devQueueIface || !devQueueIface->GetTxQueue (txq)->IsStopped ())
370  {
371  item->AddHeader ();
372  // a single queue device makes no use of the priority tag
373  if (!devQueueIface || devQueueIface->GetNTxQueues () == 1)
374  {
375  SocketPriorityTag priorityTag;
376  item->GetPacket ()->RemovePacketTag (priorityTag);
377  }
378  device->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ());
379  }
380  }
381  else
382  {
383  // Enqueue the packet in the queue disc associated with the netdevice queue
384  // selected for the packet and try to dequeue packets from such queue disc
385  item->SetTxQueueIndex (txq);
386 
387  Ptr<QueueDisc> qDisc = ndi->second.m_queueDiscsToWake[txq];
388  NS_ASSERT (qDisc);
389  qDisc->Enqueue (item);
390  qDisc->Run ();
391  }
392 }
393 
394 } // 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
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
#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.
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.
Ptr< QueueDiscClass > GetQueueDiscClass(std::size_t i) const
Get the i-th queue disc class.
Definition: queue-disc.cc:654
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