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
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
29namespace ns3 {
30
31NS_LOG_COMPONENT_DEFINE ("TrafficControlLayer");
32
33NS_OBJECT_ENSURE_REGISTERED (TrafficControlLayer);
34
35TypeId
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.",
46 MakeObjectMapChecker<QueueDisc> ())
47 .AddTraceSource ("TcDrop",
48 "Trace source indicating a packet has been dropped by the Traffic "
49 "Control layer because no queue disc is installed on the device, the "
50 "device supports flow control and the device queue is stopped",
52 "ns3::Packet::TracedCallback")
53 ;
54 return tid;
55}
56
59{
60 return GetTypeId ();
61}
62
64 : Object ()
65{
66 NS_LOG_FUNCTION (this);
67}
68
70{
71 NS_LOG_FUNCTION (this);
72}
73
74void
76{
77 NS_LOG_FUNCTION (this);
78 m_node = 0;
79 m_handlers.clear ();
80 m_netDevices.clear ();
82}
83
84void
86{
87 NS_LOG_FUNCTION (this);
88
89 ScanDevices ();
90
91 // initialize the root queue discs
92 for (auto& ndi : m_netDevices)
93 {
94 if (ndi.second.m_rootQueueDisc)
95 {
96 ndi.second.m_rootQueueDisc->Initialize ();
97 }
98 }
99
101}
102
103void
105 uint16_t protocolType, Ptr<NetDevice> device)
106{
107 NS_LOG_FUNCTION (this << protocolType << device);
108
109 struct ProtocolHandlerEntry entry;
110 entry.handler = handler;
111 entry.protocol = protocolType;
112 entry.device = device;
113 entry.promiscuous = false;
114
115 m_handlers.push_back (entry);
116
117 NS_LOG_DEBUG ("Handler for NetDevice: " << device << " registered for protocol " <<
118 protocolType << ".");
119}
120
121void
123{
124 NS_LOG_FUNCTION (this);
125
126 NS_ASSERT_MSG (m_node, "Cannot run ScanDevices without an aggregated node");
127
128 NS_LOG_DEBUG ("Scanning devices on node " << m_node->GetId ());
129 for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
130 {
131 NS_LOG_DEBUG ("Scanning devices on node " << m_node->GetId ());
133 NS_LOG_DEBUG ("Checking device " << i << " with pointer " << dev << " of type " << dev->GetInstanceTypeId ().GetName ());
134
135 // note: there may be no NetDeviceQueueInterface aggregated to the device
137 NS_LOG_DEBUG ("Pointer to NetDeviceQueueInterface: " << ndqi);
138
139 std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (dev);
140
141 if (ndi != m_netDevices.end ())
142 {
143 NS_LOG_DEBUG ("Device entry found; installing NetDeviceQueueInterface pointer " << ndqi << " to internal map");
144 ndi->second.m_ndqi = ndqi;
145 }
146 else if (ndqi)
147 // if no entry for the device is found, it means that no queue disc has been
148 // installed. Nonetheless, create an entry for the device and store a pointer
149 // to the NetDeviceQueueInterface object if the latter is not null, because
150 // the Traffic Control layer checks whether the device queue is stopped even
151 // when there is no queue disc.
152 {
153 NS_LOG_DEBUG ("No device entry found; create entry for device and store pointer to NetDeviceQueueInterface: " << ndqi);
154 m_netDevices[dev] = {nullptr, ndqi, QueueDiscVector ()};
155 ndi = m_netDevices.find (dev);
156 }
157
158 // if a queue disc is installed, set the wake callbacks on netdevice queues
159 if (ndi != m_netDevices.end () && ndi->second.m_rootQueueDisc)
160 {
161 NS_LOG_DEBUG ("Setting the wake callbacks on NetDevice queues");
162 ndi->second.m_queueDiscsToWake.clear ();
163
164 if (ndqi)
165 {
166 for (uint16_t i = 0; i < ndqi->GetNTxQueues (); i++)
167 {
169
170 if (ndi->second.m_rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_ROOT)
171 {
172 qd = ndi->second.m_rootQueueDisc;
173 }
174 else if (ndi->second.m_rootQueueDisc->GetWakeMode () == QueueDisc::WAKE_CHILD)
175 {
176 NS_ABORT_MSG_IF (ndi->second.m_rootQueueDisc->GetNQueueDiscClasses () != ndqi->GetNTxQueues (),
177 "The number of child queue discs does not match the number of netdevice queues");
178
179 qd = ndi->second.m_rootQueueDisc->GetQueueDiscClass (i)->GetQueueDisc ();
180 }
181 else
182 {
183 NS_ABORT_MSG ("Invalid wake mode");
184 }
185
186 ndqi->GetTxQueue (i)->SetWakeCallback (MakeCallback (&QueueDisc::Run, qd));
187 ndi->second.m_queueDiscsToWake.push_back (qd);
188 }
189 }
190 else
191 {
192 ndi->second.m_queueDiscsToWake.push_back (ndi->second.m_rootQueueDisc);
193 }
194
195 // set the NetDeviceQueueInterface object and the SendCallback on the queue discs
196 // into which packets are enqueued and dequeued by calling Run
197 for (auto& q : ndi->second.m_queueDiscsToWake)
198 {
199 q->SetNetDeviceQueueInterface (ndqi);
200 q->SetSendCallback ([dev] (Ptr<QueueDiscItem> item)
201 { dev->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ()); });
202 }
203 }
204 }
205}
206
207void
209{
210 NS_LOG_FUNCTION (this << device << qDisc);
211
212 std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
213
214 if (ndi == m_netDevices.end ())
215 {
216 // No entry found for this device. Create one.
217 m_netDevices[device] = {qDisc, nullptr, QueueDiscVector ()};
218 }
219 else
220 {
221 NS_ABORT_MSG_IF (ndi->second.m_rootQueueDisc,
222 "Cannot install a root queue disc on a device already having one. "
223 "Delete the existing queue disc first.");
224
225 ndi->second.m_rootQueueDisc = qDisc;
226 }
227}
228
231{
232 NS_LOG_FUNCTION (this << device);
233
234 std::map<Ptr<NetDevice>, NetDeviceInfo>::const_iterator ndi = m_netDevices.find (device);
235
236 if (ndi == m_netDevices.end ())
237 {
238 return 0;
239 }
240 return ndi->second.m_rootQueueDisc;
241}
242
245{
246 NS_LOG_FUNCTION (this << index);
247 return GetRootQueueDiscOnDevice (m_node->GetDevice (index));
248}
249
250void
252{
253 NS_LOG_FUNCTION (this << device);
254
255 std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
256
257 NS_ASSERT_MSG (ndi != m_netDevices.end () && ndi->second.m_rootQueueDisc != 0,
258 "No root queue disc installed on device " << device);
259
260 // remove the root queue disc
261 ndi->second.m_rootQueueDisc = 0;
262 for (auto& q : ndi->second.m_queueDiscsToWake)
263 {
264 q->SetNetDeviceQueueInterface (nullptr);
265 q->SetSendCallback (nullptr);
266 }
267 ndi->second.m_queueDiscsToWake.clear ();
268
269 Ptr<NetDeviceQueueInterface> ndqi = ndi->second.m_ndqi;
270 if (ndqi)
271 {
272 // remove configured callbacks, if any
273 for (uint16_t i = 0; i < ndqi->GetNTxQueues (); i++)
274 {
275 ndqi->GetTxQueue (i)->SetWakeCallback (MakeNullCallback <void> ());
276 }
277 }
278 else
279 {
280 // remove the empty entry
281 m_netDevices.erase (ndi);
282 }
283}
284
285void
287{
288 NS_LOG_FUNCTION (this << node);
289 m_node = node;
290}
291
292void
294{
295 NS_LOG_FUNCTION (this);
296 if (m_node == 0)
297 {
298 Ptr<Node> node = this->GetObject<Node> ();
299 //verify that it's a valid node and that
300 //the node was not set before
301 if (node != 0)
302 {
303 this->SetNode (node);
304 }
305 }
307}
308
311{
312 return m_node->GetNDevices ();
313}
314
315
316void
318 uint16_t protocol, const Address &from, const Address &to,
319 NetDevice::PacketType packetType)
320{
321 NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType);
322
323 bool found = false;
324
325 for (ProtocolHandlerList::iterator i = m_handlers.begin ();
326 i != m_handlers.end (); i++)
327 {
328 if (i->device == 0
329 || (i->device != 0 && i->device == device))
330 {
331 if (i->protocol == 0
332 || i->protocol == protocol)
333 {
334 NS_LOG_DEBUG ("Found handler for packet " << p << ", protocol " <<
335 protocol << " and NetDevice " << device <<
336 ". Send packet up");
337 i->handler (device, p, protocol, from, to, packetType);
338 found = true;
339 }
340 }
341 }
342
343 NS_ABORT_MSG_IF (!found, "Handler for protocol " << p << " and device " << device <<
344 " not found. It isn't forwarded up; it dies here.");
345}
346
347void
349{
350 NS_LOG_FUNCTION (this << device << item);
351
352 NS_LOG_DEBUG ("Send packet to device " << device << " protocol number " <<
353 item->GetProtocol ());
354
355 Ptr<NetDeviceQueueInterface> devQueueIface;
356 std::map<Ptr<NetDevice>, NetDeviceInfo>::iterator ndi = m_netDevices.find (device);
357
358 if (ndi != m_netDevices.end ())
359 {
360 devQueueIface = ndi->second.m_ndqi;
361 }
362
363 // determine the transmission queue of the device where the packet will be enqueued
364 std::size_t txq = 0;
365 if (devQueueIface && devQueueIface->GetNTxQueues () > 1)
366 {
367 txq = devQueueIface->GetSelectQueueCallback () (item);
368 // otherwise, Linux determines the queue index by using a hash function
369 // and associates such index to the socket which the packet belongs to,
370 // so that subsequent packets of the same socket will be mapped to the
371 // same tx queue (__netdev_pick_tx function in net/core/dev.c). It is
372 // pointless to implement this in ns-3 because currently the multi-queue
373 // devices provide a select queue callback
374 }
375
376 NS_ASSERT (!devQueueIface || txq < devQueueIface->GetNTxQueues ());
377
378 if (ndi == m_netDevices.end () || ndi->second.m_rootQueueDisc == 0)
379 {
380 // The device has no attached queue disc, thus add the header to the packet and
381 // send it directly to the device if the selected queue is not stopped
382 item->AddHeader ();
383 if (!devQueueIface || !devQueueIface->GetTxQueue (txq)->IsStopped ())
384 {
385 // a single queue device makes no use of the priority tag
386 if (!devQueueIface || devQueueIface->GetNTxQueues () == 1)
387 {
388 SocketPriorityTag priorityTag;
389 item->GetPacket ()->RemovePacketTag (priorityTag);
390 }
391 device->Send (item->GetPacket (), item->GetAddress (), item->GetProtocol ());
392 }
393 else
394 {
395 m_dropped (item->GetPacket ());
396 }
397 }
398 else
399 {
400 // Enqueue the packet in the queue disc associated with the netdevice queue
401 // selected for the packet and try to dequeue packets from such queue disc
402 item->SetTxQueueIndex (txq);
403
404 Ptr<QueueDisc> qDisc = ndi->second.m_queueDiscsToWake[txq];
405 NS_ASSERT (qDisc);
406 qDisc->Enqueue (item);
407 qDisc->Run ();
408 }
409}
410
411} // namespace ns3
a polymophic address class
Definition: address.h:91
virtual bool Send(Ptr< Packet > packet, const Address &dest, uint16_t protocolNumber)=0
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 TypeId GetInstanceTypeId(void) const
Get the most derived TypeId for this Object.
Definition: object.cc:79
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
virtual void DoInitialize(void)
Initialize() implementation.
Definition: object.cc:353
virtual void NotifyNewAggregate(void)
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:325
Container for a set of ns3::Object pointers.
void Run(void)
Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) Dequeues multiple packets,...
Definition: queue-disc.cc:953
Ptr< QueueDiscClass > GetQueueDiscClass(std::size_t i) const
Get the i-th queue disc class.
Definition: queue-disc.cc:660
bool Enqueue(Ptr< QueueDiscItem > item)
Pass a packet to store to the queue discipline.
Definition: queue-disc.cc:859
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...
TracedCallback< Ptr< const Packet > > m_dropped
The trace source fired when the Traffic Control layer drops a packet because no queue disc is install...
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:922
std::string GetName(void) const
Get the name.
Definition: type-id.cc:976
#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
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
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:1648
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