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
25NS_OBJECT_ENSURE_REGISTERED(TrafficControlLayer);
26
27TypeId
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
62
67
68void
70{
71 NS_LOG_FUNCTION(this);
72 m_node = nullptr;
73 m_handlers.clear();
74 m_netDevices.clear();
76}
77
78void
80{
81 NS_LOG_FUNCTION(this);
82
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
97void
99 uint16_t protocolType,
100 Ptr<NetDevice> device)
101{
102 NS_LOG_FUNCTION(this << protocolType << device);
103
105 entry.handler = handler;
106 entry.protocol = protocolType;
107 entry.device = device;
108 entry.promiscuous = false;
109
110 m_handlers.push_back(entry);
111
112 NS_LOG_DEBUG("Handler for NetDevice: " << device << " registered for protocol " << protocolType
113 << ".");
114}
115
116void
118{
119 NS_LOG_FUNCTION(this);
120
121 NS_ASSERT_MSG(m_node, "Cannot run ScanDevices without an aggregated node");
122
123 NS_LOG_DEBUG("Scanning devices on node " << m_node->GetId());
124 for (uint32_t i = 0; i < m_node->GetNDevices(); i++)
125 {
126 NS_LOG_DEBUG("Scanning devices on node " << m_node->GetId());
128 NS_LOG_DEBUG("Checking device " << i << " with pointer " << dev << " of type "
129 << dev->GetInstanceTypeId().GetName());
130
131 // note: there may be no NetDeviceQueueInterface aggregated to the device
133 NS_LOG_DEBUG("Pointer to NetDeviceQueueInterface: " << ndqi);
134
135 auto ndi = m_netDevices.find(dev);
136
137 if (ndi != m_netDevices.end())
138 {
139 NS_LOG_DEBUG("Device entry found; installing NetDeviceQueueInterface pointer "
140 << ndqi << " to internal map");
141 ndi->second.m_ndqi = ndqi;
142 }
143 else if (ndqi)
144 // if no entry for the device is found, it means that no queue disc has been
145 // installed. Nonetheless, create an entry for the device and store a pointer
146 // to the NetDeviceQueueInterface object if the latter is not null, because
147 // the Traffic Control layer checks whether the device queue is stopped even
148 // when there is no queue disc.
149 {
150 NS_LOG_DEBUG("No device entry found; create entry for device and store pointer to "
151 "NetDeviceQueueInterface: "
152 << ndqi);
153 m_netDevices[dev] = {nullptr, ndqi, QueueDiscVector()};
154 ndi = m_netDevices.find(dev);
155 }
156
157 // if a queue disc is installed, set the wake callbacks on netdevice queues
158 if (ndi != m_netDevices.end() && ndi->second.m_rootQueueDisc)
159 {
160 NS_LOG_DEBUG("Setting the wake callbacks on NetDevice queues");
161 ndi->second.m_queueDiscsToWake.clear();
162
163 if (ndqi)
164 {
165 for (std::size_t i = 0; i < ndqi->GetNTxQueues(); i++)
166 {
168
169 if (ndi->second.m_rootQueueDisc->GetWakeMode() == QueueDisc::WAKE_ROOT)
170 {
171 qd = ndi->second.m_rootQueueDisc;
172 }
173 else if (ndi->second.m_rootQueueDisc->GetWakeMode() == QueueDisc::WAKE_CHILD)
174 {
175 NS_ABORT_MSG_IF(ndi->second.m_rootQueueDisc->GetNQueueDiscClasses() !=
176 ndqi->GetNTxQueues(),
177 "The number of child queue discs does not match the number "
178 "of netdevice queues");
179
180 qd = ndi->second.m_rootQueueDisc->GetQueueDiscClass(i)->GetQueueDisc();
181 }
182 else
183 {
184 NS_ABORT_MSG("Invalid wake mode");
185 }
186
187 ndqi->GetTxQueue(i)->SetWakeCallback(MakeCallback(&QueueDisc::Run, qd));
188 ndi->second.m_queueDiscsToWake.push_back(qd);
189 }
190 }
191 else
192 {
193 ndi->second.m_queueDiscsToWake.push_back(ndi->second.m_rootQueueDisc);
194 }
195
196 // set the NetDeviceQueueInterface object and the SendCallback on the queue discs
197 // into which packets are enqueued and dequeued by calling Run
198 for (auto& q : ndi->second.m_queueDiscsToWake)
199 {
200 q->SetNetDeviceQueueInterface(ndqi);
201 q->SetSendCallback([dev](Ptr<QueueDiscItem> item) {
202 dev->Send(item->GetPacket(), item->GetAddress(), item->GetProtocol());
203 });
204 }
205 }
206 }
207}
208
209void
211{
212 NS_LOG_FUNCTION(this << device << qDisc);
213
214 auto ndi = m_netDevices.find(device);
215
216 if (ndi == m_netDevices.end())
217 {
218 // No entry found for this device. Create one.
219 m_netDevices[device] = {qDisc, nullptr, QueueDiscVector()};
220 }
221 else
222 {
223 NS_ABORT_MSG_IF(ndi->second.m_rootQueueDisc,
224 "Cannot install a root queue disc on a device already having one. "
225 "Delete the existing queue disc first.");
226
227 ndi->second.m_rootQueueDisc = qDisc;
228 }
229}
230
233{
234 NS_LOG_FUNCTION(this << device);
235
236 auto ndi = m_netDevices.find(device);
237
238 if (ndi == m_netDevices.end())
239 {
240 return nullptr;
241 }
242 return ndi->second.m_rootQueueDisc;
243}
244
251
252void
254{
255 NS_LOG_FUNCTION(this << device);
256
257 auto ndi = m_netDevices.find(device);
258
259 NS_ASSERT_MSG(ndi != m_netDevices.end() && ndi->second.m_rootQueueDisc,
260 "No root queue disc installed on device " << device);
261
262 // remove the root queue disc
263 ndi->second.m_rootQueueDisc = nullptr;
264 for (auto& q : ndi->second.m_queueDiscsToWake)
265 {
266 q->SetNetDeviceQueueInterface(nullptr);
267 q->SetSendCallback(nullptr);
268 }
269 ndi->second.m_queueDiscsToWake.clear();
270
271 Ptr<NetDeviceQueueInterface> ndqi = ndi->second.m_ndqi;
272 if (ndqi)
273 {
274 // remove configured callbacks, if any
275 for (std::size_t i = 0; i < ndqi->GetNTxQueues(); i++)
276 {
277 ndqi->GetTxQueue(i)->SetWakeCallback(MakeNullCallback<void>());
278 }
279 }
280 else
281 {
282 // remove the empty entry
283 m_netDevices.erase(ndi);
284 }
285}
286
287void
289{
290 NS_LOG_FUNCTION(this << node);
291 m_node = node;
292}
293
294void
296{
297 NS_LOG_FUNCTION(this);
298 if (!m_node)
299 {
300 Ptr<Node> node = this->GetObject<Node>();
301 // verify that it's a valid node and that
302 // the node was not set before
303 if (node)
304 {
305 this->SetNode(node);
306 }
307 }
309}
310
313{
314 return m_node->GetNDevices();
315}
316
317void
320 uint16_t protocol,
321 const Address& from,
322 const Address& to,
323 NetDevice::PacketType packetType)
324{
325 NS_LOG_FUNCTION(this << device << p << protocol << from << to << packetType);
326
327 bool found = false;
328
329 for (auto i = m_handlers.begin(); i != m_handlers.end(); i++)
330 {
331 if (!i->device || (i->device == device))
332 {
333 if (i->protocol == 0 || i->protocol == protocol)
334 {
335 NS_LOG_DEBUG("Found handler for packet " << p << ", protocol " << protocol
336 << " and NetDevice " << device
337 << ". Send packet up");
338 i->handler(device, p, protocol, from, to, packetType);
339 found = true;
340 }
341 }
342 }
343
344 NS_ABORT_MSG_IF(!found,
345 "Handler for protocol " << p << " and device " << device
346 << " not found. It isn't forwarded up; it dies here.");
347}
348
349void
351{
352 NS_LOG_FUNCTION(this << device << item);
353
354 NS_LOG_DEBUG("Send packet to device " << device << " protocol number " << item->GetProtocol());
355
356 Ptr<NetDeviceQueueInterface> devQueueIface;
357 auto ndi = m_netDevices.find(device);
358
359 if (ndi != m_netDevices.end())
360 {
361 devQueueIface = ndi->second.m_ndqi;
362 }
363
364 // determine the transmission queue of the device where the packet will be enqueued
365 std::size_t txq = 0;
366 if (devQueueIface && devQueueIface->GetNTxQueues() > 1)
367 {
368 txq = devQueueIface->GetSelectQueueCallback()(item);
369 // otherwise, Linux determines the queue index by using a hash function
370 // and associates such index to the socket which the packet belongs to,
371 // so that subsequent packets of the same socket will be mapped to the
372 // same tx queue (__netdev_pick_tx function in net/core/dev.c). It is
373 // pointless to implement this in ns-3 because currently the multi-queue
374 // devices provide a select queue callback
375 }
376
377 NS_ASSERT(!devQueueIface || txq < devQueueIface->GetNTxQueues());
378
379 if (ndi == m_netDevices.end() || !ndi->second.m_rootQueueDisc)
380 {
381 // The device has no attached queue disc, thus add the header to the packet and
382 // send it directly to the device if the selected queue is not stopped
383 item->AddHeader();
384 if (!devQueueIface || !devQueueIface->GetTxQueue(txq)->IsStopped())
385 {
386 // a single queue device makes no use of the priority tag
387 if (!devQueueIface || devQueueIface->GetNTxQueues() == 1)
388 {
389 SocketPriorityTag priorityTag;
390 item->GetPacket()->RemovePacketTag(priorityTag);
391 }
392 device->Send(item->GetPacket(), item->GetAddress(), item->GetProtocol());
393 }
394 else
395 {
396 m_dropped(item->GetPacket());
397 }
398 }
399 else
400 {
401 // Enqueue the packet in the queue disc associated with the netdevice queue
402 // selected for the packet and try to dequeue packets from such queue disc
403 item->SetTxQueueIndex(txq);
404
405 Ptr<QueueDisc> qDisc = ndi->second.m_queueDiscsToWake[txq];
406 NS_ASSERT(qDisc);
407 qDisc->Enqueue(item);
408 qDisc->Run();
409 }
410}
411
412} // namespace ns3
a polymophic address class
Definition address.h:90
PacketType
Packet types are used as they are in Linux.
Definition net-device.h:289
Network device transmission queue interface.
uint32_t GetNDevices() const
Definition node.cc:147
uint32_t GetId() const
Definition node.cc:106
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition node.cc:138
A base class which provides memory management and object aggregation.
Definition object.h:78
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition object.cc:412
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
virtual void DoInitialize()
Initialize() implementation.
Definition object.cc:440
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Smart pointer class similar to boost::intrusive_ptr.
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:1307
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.
TypeId GetInstanceTypeId() const override
Get the type ID for the instance.
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:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#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
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
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#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:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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.
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:684
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