A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
traffic-control-layer.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015 Natale Patriciello <natale.patriciello@gmail.com>
3 * 2016 Stefano Avallone <stavallo@unina.it>
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 */
7
9
10#include "queue-disc.h"
11
12#include "ns3/log.h"
13#include "ns3/net-device-queue-interface.h"
14#include "ns3/object-map.h"
15#include "ns3/packet.h"
16#include "ns3/socket.h"
17
18#include <tuple>
19
20namespace ns3
21{
22
23NS_LOG_COMPONENT_DEFINE("TrafficControlLayer");
24
26
29{
30 static TypeId tid =
31 TypeId("ns3::TrafficControlLayer")
33 .SetGroupName("TrafficControl")
34 .AddConstructor<TrafficControlLayer>()
35 .AddAttribute(
36 "RootQueueDiscList",
37 "The list of root queue discs associated to this Traffic Control layer.",
42 .AddTraceSource("TcDrop",
43 "Trace source indicating a packet has been dropped by the Traffic "
44 "Control layer because no queue disc is installed on the device, the "
45 "device supports flow control and the device queue is stopped",
47 "ns3::Packet::TracedCallback");
48 return tid;
49}
50
56
61
62void
64{
65 NS_LOG_FUNCTION(this);
66 m_node = nullptr;
67 m_handlers.clear();
68 m_netDevices.clear();
70}
71
72void
74{
75 NS_LOG_FUNCTION(this);
76
78
79 // initialize the root queue discs
80 for (auto& ndi : m_netDevices)
81 {
82 if (ndi.second.m_rootQueueDisc)
83 {
84 ndi.second.m_rootQueueDisc->Initialize();
85 }
86 }
87
89}
90
91void
93 uint16_t protocolType,
94 Ptr<NetDevice> device)
95{
96 NS_LOG_FUNCTION(this << protocolType << device);
97
99 entry.handler = handler;
100 entry.protocol = protocolType;
101 entry.device = device;
102 entry.promiscuous = false;
103
104 m_handlers.push_back(entry);
105
106 NS_LOG_DEBUG("Handler for NetDevice: " << device << " registered for protocol " << protocolType
107 << ".");
108}
109
110void
112{
113 NS_LOG_FUNCTION(this);
114
115 NS_ASSERT_MSG(m_node, "Cannot run ScanDevices without an aggregated node");
116
117 NS_LOG_DEBUG("Scanning devices on node " << m_node->GetId());
118 for (uint32_t i = 0; i < m_node->GetNDevices(); i++)
119 {
120 NS_LOG_DEBUG("Scanning devices on node " << m_node->GetId());
121 Ptr<NetDevice> dev = m_node->GetDevice(i);
122 NS_LOG_DEBUG("Checking device " << i << " with pointer " << dev << " of type "
123 << dev->GetInstanceTypeId().GetName());
124
125 // note: there may be no NetDeviceQueueInterface aggregated to the device
127 NS_LOG_DEBUG("Pointer to NetDeviceQueueInterface: " << ndqi);
128
129 auto ndi = m_netDevices.find(dev);
130
131 if (ndi != m_netDevices.end())
132 {
133 NS_LOG_DEBUG("Device entry found; installing NetDeviceQueueInterface pointer "
134 << ndqi << " to internal map");
135 ndi->second.m_ndqi = ndqi;
136 }
137 else if (ndqi)
138 // if no entry for the device is found, it means that no queue disc has been
139 // installed. Nonetheless, create an entry for the device and store a pointer
140 // to the NetDeviceQueueInterface object if the latter is not null, because
141 // the Traffic Control layer checks whether the device queue is stopped even
142 // when there is no queue disc.
143 {
144 NS_LOG_DEBUG("No device entry found; create entry for device and store pointer to "
145 "NetDeviceQueueInterface: "
146 << ndqi);
147 m_netDevices[dev] = {nullptr, ndqi, QueueDiscVector()};
148 ndi = m_netDevices.find(dev);
149 }
150
151 // if a queue disc is installed, set the wake callbacks on netdevice queues
152 if (ndi != m_netDevices.end() && ndi->second.m_rootQueueDisc)
153 {
154 NS_LOG_DEBUG("Setting the wake callbacks on NetDevice queues");
155 ndi->second.m_queueDiscsToWake.clear();
156
157 if (ndqi)
158 {
159 for (std::size_t i = 0; i < ndqi->GetNTxQueues(); i++)
160 {
162
163 if (ndi->second.m_rootQueueDisc->GetWakeMode() == QueueDisc::WAKE_ROOT)
164 {
165 qd = ndi->second.m_rootQueueDisc;
166 }
167 else if (ndi->second.m_rootQueueDisc->GetWakeMode() == QueueDisc::WAKE_CHILD)
168 {
169 NS_ABORT_MSG_IF(ndi->second.m_rootQueueDisc->GetNQueueDiscClasses() !=
170 ndqi->GetNTxQueues(),
171 "The number of child queue discs does not match the number "
172 "of netdevice queues");
173
174 qd = ndi->second.m_rootQueueDisc->GetQueueDiscClass(i)->GetQueueDisc();
175 }
176 else
177 {
178 NS_ABORT_MSG("Invalid wake mode");
179 }
180
181 ndqi->GetTxQueue(i)->SetWakeCallback(MakeCallback(&QueueDisc::Run, qd));
182 ndi->second.m_queueDiscsToWake.push_back(qd);
183 }
184 }
185 else
186 {
187 ndi->second.m_queueDiscsToWake.push_back(ndi->second.m_rootQueueDisc);
188 }
189
190 // set the NetDeviceQueueInterface object and the SendCallback on the queue discs
191 // into which packets are enqueued and dequeued by calling Run
192 for (auto& q : ndi->second.m_queueDiscsToWake)
193 {
194 q->SetNetDeviceQueueInterface(ndqi);
195 q->SetSendCallback([dev](Ptr<QueueDiscItem> item) {
196 dev->Send(item->GetPacket(), item->GetAddress(), item->GetProtocol());
197 });
198 }
199 }
200 }
201}
202
203void
205{
206 NS_LOG_FUNCTION(this << device << qDisc);
207
208 auto ndi = m_netDevices.find(device);
209
210 if (ndi == m_netDevices.end())
211 {
212 // No entry found for this device. Create one.
213 m_netDevices[device] = {qDisc, nullptr, QueueDiscVector()};
214 }
215 else
216 {
217 NS_ABORT_MSG_IF(ndi->second.m_rootQueueDisc,
218 "Cannot install a root queue disc on a device already having one. "
219 "Delete the existing queue disc first.");
220
221 ndi->second.m_rootQueueDisc = qDisc;
222 }
223}
224
227{
228 NS_LOG_FUNCTION(this << device);
229
230 auto ndi = m_netDevices.find(device);
231
232 if (ndi == m_netDevices.end())
233 {
234 return nullptr;
235 }
236 return ndi->second.m_rootQueueDisc;
237}
238
241{
242 NS_LOG_FUNCTION(this << index);
243 return GetRootQueueDiscOnDevice(m_node->GetDevice(index));
244}
245
246void
248{
249 NS_LOG_FUNCTION(this << device);
250
251 auto ndi = m_netDevices.find(device);
252
253 NS_ASSERT_MSG(ndi != m_netDevices.end() && ndi->second.m_rootQueueDisc,
254 "No root queue disc installed on device " << device);
255
256 // remove the root queue disc
257 ndi->second.m_rootQueueDisc = nullptr;
258 for (auto& q : ndi->second.m_queueDiscsToWake)
259 {
260 q->SetNetDeviceQueueInterface(nullptr);
261 q->SetSendCallback(nullptr);
262 }
263 ndi->second.m_queueDiscsToWake.clear();
264
265 Ptr<NetDeviceQueueInterface> ndqi = ndi->second.m_ndqi;
266 if (ndqi)
267 {
268 // remove configured callbacks, if any
269 for (std::size_t i = 0; i < ndqi->GetNTxQueues(); i++)
270 {
271 ndqi->GetTxQueue(i)->SetWakeCallback(MakeNullCallback<void>());
272 }
273 }
274 else
275 {
276 // remove the empty entry
277 m_netDevices.erase(ndi);
278 }
279}
280
281void
283{
284 NS_LOG_FUNCTION(this << node);
285 m_node = node;
286}
287
288void
290{
291 NS_LOG_FUNCTION(this);
292 if (!m_node)
293 {
294 Ptr<Node> node = this->GetObject<Node>();
295 // verify that it's a valid node and that
296 // the node was not set before
297 if (node)
298 {
299 this->SetNode(node);
300 }
301 }
303}
304
307{
308 return m_node->GetNDevices();
309}
310
311void
314 uint16_t protocol,
315 const Address& from,
316 const Address& to,
317 NetDevice::PacketType packetType)
318{
319 NS_LOG_FUNCTION(this << device << p << protocol << from << to << packetType);
320
321 bool found = false;
322
323 for (auto i = m_handlers.begin(); i != m_handlers.end(); i++)
324 {
325 if (!i->device || (i->device == device))
326 {
327 if (i->protocol == 0 || i->protocol == protocol)
328 {
329 NS_LOG_DEBUG("Found handler for packet " << p << ", protocol " << protocol
330 << " and NetDevice " << device
331 << ". Send packet up");
332 i->handler(device, p, protocol, from, to, packetType);
333 found = true;
334 }
335 }
336 }
337
338 NS_ABORT_MSG_IF(!found,
339 "Handler for protocol " << p << " and device " << device
340 << " not found. It isn't forwarded up; it dies here.");
341}
342
343void
345{
346 NS_LOG_FUNCTION(this << device << item);
347
348 NS_LOG_DEBUG("Send packet to device " << device << " protocol number " << item->GetProtocol());
349
350 Ptr<NetDeviceQueueInterface> devQueueIface;
351 auto ndi = m_netDevices.find(device);
352
353 if (ndi != m_netDevices.end())
354 {
355 devQueueIface = ndi->second.m_ndqi;
356 }
357
358 // determine the transmission queue of the device where the packet will be enqueued
359 std::size_t txq = 0;
360 if (devQueueIface && devQueueIface->GetNTxQueues() > 1)
361 {
362 txq = devQueueIface->GetSelectQueueCallback()(item);
363 // otherwise, Linux determines the queue index by using a hash function
364 // and associates such index to the socket which the packet belongs to,
365 // so that subsequent packets of the same socket will be mapped to the
366 // same tx queue (__netdev_pick_tx function in net/core/dev.c). It is
367 // pointless to implement this in ns-3 because currently the multi-queue
368 // devices provide a select queue callback
369 }
370
371 NS_ASSERT(!devQueueIface || txq < devQueueIface->GetNTxQueues());
372
373 if (ndi == m_netDevices.end() || !ndi->second.m_rootQueueDisc)
374 {
375 // The device has no attached queue disc, thus add the header to the packet and
376 // send it directly to the device if the selected queue is not stopped
377 item->AddHeader();
378 if (!devQueueIface || !devQueueIface->GetTxQueue(txq)->IsStopped())
379 {
380 // a single queue device makes no use of the priority tag
381 if (!devQueueIface || devQueueIface->GetNTxQueues() == 1)
382 {
383 SocketPriorityTag priorityTag;
384 item->GetPacket()->RemovePacketTag(priorityTag);
385 }
386 device->Send(item->GetPacket(), item->GetAddress(), item->GetProtocol());
387 }
388 else
389 {
390 m_dropped(item->GetPacket());
391 }
392 }
393 else
394 {
395 // Enqueue the packet in the queue disc associated with the netdevice queue
396 // selected for the packet and try to dequeue packets from such queue disc
397 item->SetTxQueueIndex(txq);
398
399 Ptr<QueueDisc> qDisc = ndi->second.m_queueDiscsToWake[txq];
400 NS_ASSERT(qDisc);
401 qDisc->Enqueue(item);
402 qDisc->Run();
403 }
404}
405
406} // namespace ns3
uint32_t q
a polymophic address class
Definition address.h:114
PacketType
Packet types are used as they are in Linux.
Definition net-device.h:289
Network device transmission queue interface.
Callback< void, Ptr< NetDevice >, Ptr< const Packet >, uint16_t, const Address &, const Address &, NetDevice::PacketType > ProtocolHandler
A protocol handler.
Definition node.h:154
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition object.cc:409
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:518
virtual void DoInitialize()
Initialize() implementation.
Definition object.cc:437
Object()
Caller graph was not generated because of its size.
Definition object.cc:93
virtual void DoDispose()
Destructor implementation.
Definition object.cc:430
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
void Run()
Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) Dequeues multiple packets,...
indicates whether the socket has a priority set.
Definition socket.h:1308
The Traffic Control layer aims at introducing an equivalent of the Linux Traffic Control infrastructu...
void NotifyNewAggregate() override
Notify all Objects aggregated to this one of a new Object being aggregated.
static TypeId GetTypeId()
Get the type ID.
Ptr< QueueDisc > GetRootQueueDiscOnDeviceByIndex(uint32_t index) const
Required by the object map accessor.
void DoInitialize() override
Initialize() implementation.
void DoDispose() override
Destructor implementation.
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.
Ptr< Node > m_node
The node this TrafficControlLayer object is aggregated to.
uint32_t GetNDevices() const
Required by the object map accessor.
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 ScanDevices()
Collect information needed to determine how to handle packets destined to each of the NetDevices of t...
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 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 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:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:690
Callback< R, Args... > MakeNullCallback()
Build null Callbacks which take no arguments, for varying number of template arguments,...
Definition callback.h:734
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#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:35
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.
ObjectPtrContainerValue ObjectMapValue
ObjectMapValue is an alias for ObjectPtrContainerValue.
Definition object-map.h:29
Ptr< const AttributeAccessor > MakeObjectMapAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition object-map.h:65
Ptr< const AttributeChecker > MakeObjectMapChecker()
Definition object-map.h:110
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