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 (uint8_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 (uint8_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
uint32_t GetNDevices(void) const
Required by the object map accessor.
#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:844
#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:202
#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:1307
void Run(void)
Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) Dequeues multiple packets...
Definition: queue-disc.cc:938
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.
Information to store for each device.
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.
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:270
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
uint32_t GetNDevices(void) const
Definition: node.cc:150