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 
80  QueueDiscVector queueDiscsToWake,
81  SelectQueueCallback selectQueueCallback)
82  : m_rootQueueDisc (rootQueueDisc),
83  m_ndqi (ndqi),
84  m_queueDiscsToWake (queueDiscsToWake),
85  m_selectQueueCallback (selectQueueCallback)
86 {
87 }
88 
90 {
91  NS_LOG_FUNCTION (this);
92 }
93 
94 void
96 {
97  NS_LOG_FUNCTION (this);
98  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi;
99  for (ndi = m_netDevices.begin (); ndi != m_netDevices.end (); ndi++)
100  {
101  Ptr<NetDeviceQueueInterface> devQueueIface = ndi->second.m_ndqi;
102  NS_ASSERT (devQueueIface);
103 
104  if (ndi->second.m_rootQueueDisc)
105  {
106  // set the wake callbacks on netdevice queues
107  if (ndi->second.m_rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_ROOT)
108  {
109  for (uint32_t i = 0; i < devQueueIface->GetNTxQueues (); i++)
110  {
111  devQueueIface->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run, ndi->second.m_rootQueueDisc));
112  ndi->second.m_queueDiscsToWake.push_back (ndi->second.m_rootQueueDisc);
113  }
114  }
115  else if (ndi->second.m_rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_CHILD)
116  {
117  NS_ASSERT_MSG (ndi->second.m_rootQueueDisc->GetNQueueDiscClasses () == devQueueIface->GetNTxQueues (),
118  "The number of child queue discs does not match the number of netdevice queues");
119  for (uint32_t i = 0; i < devQueueIface->GetNTxQueues (); i++)
120  {
121  devQueueIface->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run,
122  ndi->second.m_rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ()));
123  ndi->second.m_queueDiscsToWake.push_back (ndi->second.m_rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ());
124  }
125  }
126 
127  // initialize the queue disc
128  ndi->second.m_rootQueueDisc->Initialize ();
129  }
130  }
132 }
133 
134 void
136 {
137  NS_LOG_FUNCTION (this << device);
138 
139  // ensure this setup is done just once. SetupDevice is called by Ipv4L3Protocol
140  // and Ipv6L3Protocol when they add an interface, thus it might be called twice
141  // in case of dual stack nodes. Also, SetupDevice might be called twice if the
142  // tc helper is invoked (to install a queue disc) before the creation of the
143  // Ipv{4,6}Interface, since SetRootQueueDiscOnDevice calls SetupDevice
144  if (device->GetObject<NetDeviceQueueInterface> ())
145  {
146  NS_LOG_DEBUG ("The setup for this device has been already done.");
147  return;
148  }
149 
150  // create a NetDeviceQueueInterface object and aggregate it to the device
151  Ptr<NetDeviceQueueInterface> devQueueIface = CreateObject<NetDeviceQueueInterface> ();
152  device->AggregateObject (devQueueIface);
153 
154  // Create the TX queues if the device has not done so and has not set the
155  // late TX queues creation flag in the NotifyNewAggregate method
156  if (devQueueIface->GetNTxQueues () == 0 && !devQueueIface->GetLateTxQueuesCreation ())
157  {
158  devQueueIface->CreateTxQueues ();
159  }
160 
161  // devices can set a select queue callback in their NotifyNewAggregate method
162  SelectQueueCallback cb = devQueueIface->GetSelectQueueCallback ();
163 
164  // create an entry in the m_netDevices map for this device
165  NS_ASSERT_MSG (m_netDevices.find (device) == m_netDevices.end (), "This is a bug,"
166  << " SetupDevice only can insert an entry in the m_netDevices map");
167 
168  m_netDevices.emplace (std::piecewise_construct,
169  std::forward_as_tuple (device),
170  std::forward_as_tuple ((Ptr<QueueDisc>) 0, devQueueIface, QueueDiscVector (), cb));
171 }
172 
173 void
175  uint16_t protocolType, Ptr<NetDevice> device)
176 {
177  NS_LOG_FUNCTION (this << protocolType << device);
178 
179  struct ProtocolHandlerEntry entry;
180  entry.handler = handler;
181  entry.protocol = protocolType;
182  entry.device = device;
183  entry.promiscuous = false;
184 
185  m_handlers.push_back (entry);
186 
187  NS_LOG_DEBUG ("Handler for NetDevice: " << device << " registered for protocol " <<
188  protocolType << ".");
189 }
190 
191 void
193 {
194  NS_LOG_FUNCTION (this << device << qDisc);
195 
196  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
197 
198  if (ndi == m_netDevices.end ())
199  {
200  // SetupDevice has not been called yet. This may happen when the tc helper is
201  // invoked (to install a queue disc) before the creation of the Ipv{4,6}Interface.
202  // Since queue discs require that a netdevice queue interface is aggregated
203  // to the device, call SetupDevice
204  SetupDevice (device);
205  ndi = m_netDevices.find (device);
206  NS_ASSERT (ndi != m_netDevices.end ());
207  }
208 
209  NS_ASSERT_MSG (ndi->second.m_rootQueueDisc == 0, "Cannot install a root queue disc on a "
210  << "device already having one. Delete the existing queue disc first.");
211  ndi->second.m_rootQueueDisc = qDisc;
212 }
213 
216 {
217  NS_LOG_FUNCTION (this << device);
218 
219  std::map<Ptr<NetDevice>, NetDeviceInfo>::const_iterator ndi = m_netDevices.find (device);
220 
221  if (ndi == m_netDevices.end ())
222  {
223  return 0;
224  }
225  return ndi->second.m_rootQueueDisc;
226 }
227 
230 {
231  NS_LOG_FUNCTION (this << index);
232  return GetRootQueueDiscOnDevice (m_node->GetDevice (index));
233 }
234 
235 void
237 {
238  NS_LOG_FUNCTION (this << device);
239 
240  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
241 
242  NS_ASSERT_MSG (ndi != m_netDevices.end () && ndi->second.m_rootQueueDisc != 0, "No root queue disc"
243  << " installed on device " << device);
244 
245  // remove the root queue disc
246  ndi->second.m_rootQueueDisc = 0;
247  ndi->second.m_queueDiscsToWake.clear ();
248 }
249 
250 void
252 {
253  NS_LOG_FUNCTION (this << node);
254  m_node = node;
255 }
256 
257 void
259 {
260  NS_LOG_FUNCTION (this);
261  if (m_node == 0)
262  {
263  Ptr<Node> node = this->GetObject<Node> ();
264  //verify that it's a valid node and that
265  //the node was not set before
266  if (node != 0)
267  {
268  this->SetNode (node);
269  }
270  }
272 }
273 
274 uint32_t
276 {
277  return m_node->GetNDevices ();
278 }
279 
280 
281 void
283  uint16_t protocol, const Address &from, const Address &to,
284  NetDevice::PacketType packetType)
285 {
286  NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType);
287 
288  bool found = false;
289 
290  for (ProtocolHandlerList::iterator i = m_handlers.begin ();
291  i != m_handlers.end (); i++)
292  {
293  if (i->device == 0
294  || (i->device != 0 && i->device == device))
295  {
296  if (i->protocol == 0
297  || i->protocol == protocol)
298  {
299  NS_LOG_DEBUG ("Found handler for packet " << p << ", protocol " <<
300  protocol << " and NetDevice " << device <<
301  ". Send packet up");
302  i->handler (device, p, protocol, from, to, packetType);
303  found = true;
304  }
305  }
306  }
307 
308  if (! found)
309  {
310  NS_FATAL_ERROR ("Handler for protocol " << p << " and device " << device <<
311  " not found. It isn't forwarded up; it dies here.");
312  }
313 }
314 
315 void
317 {
318  NS_LOG_FUNCTION (this << device << item);
319 
320  NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " <<
321  item->GetProtocol ());
322 
323  std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
324  NS_ASSERT (ndi != m_netDevices.end ());
325  Ptr<NetDeviceQueueInterface> devQueueIface = ndi->second.m_ndqi;
326  NS_ASSERT (devQueueIface);
327 
328  // determine the transmission queue of the device where the packet will be enqueued
329  uint8_t txq = 0;
330  if (devQueueIface->GetNTxQueues () > 1)
331  {
332  if (!ndi->second.m_selectQueueCallback.IsNull ())
333  {
334  txq = ndi->second.m_selectQueueCallback (item);
335  }
336  // otherwise, Linux determines the queue index by using a hash function
337  // and associates such index to the socket which the packet belongs to,
338  // so that subsequent packets of the same socket will be mapped to the
339  // same tx queue (__netdev_pick_tx function in net/core/dev.c). It is
340  // pointless to implement this in ns-3 because currently the multi-queue
341  // devices provide a select queue callback
342  }
343 
344  NS_ASSERT (txq < devQueueIface->GetNTxQueues ());
345 
346  if (ndi->second.m_rootQueueDisc == 0)
347  {
348  // The device has no attached queue disc, thus add the header to the packet and
349  // send it directly to the device if the selected queue is not stopped
350  if (!devQueueIface->GetTxQueue (txq)->IsStopped ())
351  {
352  item->AddHeader ();
353  // a single queue device makes no use of the priority tag
354  if (devQueueIface->GetNTxQueues () == 1)
355  {
356  SocketPriorityTag priorityTag;
357  item->GetPacket ()->RemovePacketTag (priorityTag);
358  }
359  device->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ());
360  }
361  }
362  else
363  {
364  // Enqueue the packet in the queue disc associated with the netdevice queue
365  // selected for the packet and try to dequeue packets from such queue disc
366  item->SetTxQueueIndex (txq);
367 
368  Ptr<QueueDisc> qDisc = ndi->second.m_queueDiscsToWake[txq];
369  NS_ASSERT (qDisc);
370  qDisc->Enqueue (item);
371  qDisc->Run ();
372  }
373 }
374 
375 } // 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
#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:730
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Introspection did not find any typical Config paths.
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
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:296
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: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:1303
void Run(void)
Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) Dequeues multiple packets...
Definition: queue-disc.cc:785
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.
std::vector< Ptr< QueueDisc > > QueueDiscVector
Typedef for queue disc vector.
Ptr< NetDevice > device
the NetDevice
uint32_t GetNDevices(void) const
Definition: node.cc:150
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static TypeId GetTypeId(void)
Get the type ID.
Information to store for each device.
#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. ...
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:269
uint32_t GetNDevices(void) const
Required by the object map accessor.
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:325
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:914