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 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
20
21#include "queue-disc.h"
22
23#include "ns3/log.h"
24#include "ns3/net-device-queue-interface.h"
25#include "ns3/object-map.h"
26#include "ns3/packet.h"
27#include "ns3/socket.h"
28
29#include <tuple>
30
31namespace ns3
32{
33
34NS_LOG_COMPONENT_DEFINE("TrafficControlLayer");
35
36NS_OBJECT_ENSURE_REGISTERED(TrafficControlLayer);
37
38TypeId
40{
41 static TypeId tid =
42 TypeId("ns3::TrafficControlLayer")
44 .SetGroupName("TrafficControl")
45 .AddConstructor<TrafficControlLayer>()
46 .AddAttribute(
47 "RootQueueDiscList",
48 "The list of root queue discs associated to this Traffic Control layer.",
52 MakeObjectMapChecker<QueueDisc>())
53 .AddTraceSource("TcDrop",
54 "Trace source indicating a packet has been dropped by the Traffic "
55 "Control layer because no queue disc is installed on the device, the "
56 "device supports flow control and the device queue is stopped",
58 "ns3::Packet::TracedCallback");
59 return tid;
60}
61
64{
65 return GetTypeId();
66}
67
69 : Object()
70{
71 NS_LOG_FUNCTION(this);
72}
73
75{
76 NS_LOG_FUNCTION(this);
77}
78
79void
81{
82 NS_LOG_FUNCTION(this);
83 m_node = nullptr;
84 m_handlers.clear();
85 m_netDevices.clear();
87}
88
89void
91{
92 NS_LOG_FUNCTION(this);
93
95
96 // initialize the root queue discs
97 for (auto& ndi : m_netDevices)
98 {
99 if (ndi.second.m_rootQueueDisc)
100 {
101 ndi.second.m_rootQueueDisc->Initialize();
102 }
103 }
104
106}
107
108void
110 uint16_t protocolType,
111 Ptr<NetDevice> device)
112{
113 NS_LOG_FUNCTION(this << protocolType << device);
114
116 entry.handler = handler;
117 entry.protocol = protocolType;
118 entry.device = device;
119 entry.promiscuous = false;
120
121 m_handlers.push_back(entry);
122
123 NS_LOG_DEBUG("Handler for NetDevice: " << device << " registered for protocol " << protocolType
124 << ".");
125}
126
127void
129{
130 NS_LOG_FUNCTION(this);
131
132 NS_ASSERT_MSG(m_node, "Cannot run ScanDevices without an aggregated node");
133
134 NS_LOG_DEBUG("Scanning devices on node " << m_node->GetId());
135 for (uint32_t i = 0; i < m_node->GetNDevices(); i++)
136 {
137 NS_LOG_DEBUG("Scanning devices on node " << m_node->GetId());
139 NS_LOG_DEBUG("Checking device " << i << " with pointer " << dev << " of type "
140 << dev->GetInstanceTypeId().GetName());
141
142 // note: there may be no NetDeviceQueueInterface aggregated to the device
144 NS_LOG_DEBUG("Pointer to NetDeviceQueueInterface: " << ndqi);
145
146 auto ndi = m_netDevices.find(dev);
147
148 if (ndi != m_netDevices.end())
149 {
150 NS_LOG_DEBUG("Device entry found; installing NetDeviceQueueInterface pointer "
151 << ndqi << " to internal map");
152 ndi->second.m_ndqi = ndqi;
153 }
154 else if (ndqi)
155 // if no entry for the device is found, it means that no queue disc has been
156 // installed. Nonetheless, create an entry for the device and store a pointer
157 // to the NetDeviceQueueInterface object if the latter is not null, because
158 // the Traffic Control layer checks whether the device queue is stopped even
159 // when there is no queue disc.
160 {
161 NS_LOG_DEBUG("No device entry found; create entry for device and store pointer to "
162 "NetDeviceQueueInterface: "
163 << ndqi);
164 m_netDevices[dev] = {nullptr, ndqi, QueueDiscVector()};
165 ndi = m_netDevices.find(dev);
166 }
167
168 // if a queue disc is installed, set the wake callbacks on netdevice queues
169 if (ndi != m_netDevices.end() && ndi->second.m_rootQueueDisc)
170 {
171 NS_LOG_DEBUG("Setting the wake callbacks on NetDevice queues");
172 ndi->second.m_queueDiscsToWake.clear();
173
174 if (ndqi)
175 {
176 for (std::size_t i = 0; i < ndqi->GetNTxQueues(); i++)
177 {
179
180 if (ndi->second.m_rootQueueDisc->GetWakeMode() == QueueDisc::WAKE_ROOT)
181 {
182 qd = ndi->second.m_rootQueueDisc;
183 }
184 else if (ndi->second.m_rootQueueDisc->GetWakeMode() == QueueDisc::WAKE_CHILD)
185 {
186 NS_ABORT_MSG_IF(ndi->second.m_rootQueueDisc->GetNQueueDiscClasses() !=
187 ndqi->GetNTxQueues(),
188 "The number of child queue discs does not match the number "
189 "of netdevice queues");
190
191 qd = ndi->second.m_rootQueueDisc->GetQueueDiscClass(i)->GetQueueDisc();
192 }
193 else
194 {
195 NS_ABORT_MSG("Invalid wake mode");
196 }
197
198 ndqi->GetTxQueue(i)->SetWakeCallback(MakeCallback(&QueueDisc::Run, qd));
199 ndi->second.m_queueDiscsToWake.push_back(qd);
200 }
201 }
202 else
203 {
204 ndi->second.m_queueDiscsToWake.push_back(ndi->second.m_rootQueueDisc);
205 }
206
207 // set the NetDeviceQueueInterface object and the SendCallback on the queue discs
208 // into which packets are enqueued and dequeued by calling Run
209 for (auto& q : ndi->second.m_queueDiscsToWake)
210 {
211 q->SetNetDeviceQueueInterface(ndqi);
212 q->SetSendCallback([dev](Ptr<QueueDiscItem> item) {
213 dev->Send(item->GetPacket(), item->GetAddress(), item->GetProtocol());
214 });
215 }
216 }
217 }
218}
219
220void
222{
223 NS_LOG_FUNCTION(this << device << qDisc);
224
225 auto ndi = m_netDevices.find(device);
226
227 if (ndi == m_netDevices.end())
228 {
229 // No entry found for this device. Create one.
230 m_netDevices[device] = {qDisc, nullptr, QueueDiscVector()};
231 }
232 else
233 {
234 NS_ABORT_MSG_IF(ndi->second.m_rootQueueDisc,
235 "Cannot install a root queue disc on a device already having one. "
236 "Delete the existing queue disc first.");
237
238 ndi->second.m_rootQueueDisc = qDisc;
239 }
240}
241
244{
245 NS_LOG_FUNCTION(this << device);
246
247 auto ndi = m_netDevices.find(device);
248
249 if (ndi == m_netDevices.end())
250 {
251 return nullptr;
252 }
253 return ndi->second.m_rootQueueDisc;
254}
255
258{
259 NS_LOG_FUNCTION(this << index);
261}
262
263void
265{
266 NS_LOG_FUNCTION(this << device);
267
268 auto ndi = m_netDevices.find(device);
269
270 NS_ASSERT_MSG(ndi != m_netDevices.end() && ndi->second.m_rootQueueDisc,
271 "No root queue disc installed on device " << device);
272
273 // remove the root queue disc
274 ndi->second.m_rootQueueDisc = nullptr;
275 for (auto& q : ndi->second.m_queueDiscsToWake)
276 {
277 q->SetNetDeviceQueueInterface(nullptr);
278 q->SetSendCallback(nullptr);
279 }
280 ndi->second.m_queueDiscsToWake.clear();
281
282 Ptr<NetDeviceQueueInterface> ndqi = ndi->second.m_ndqi;
283 if (ndqi)
284 {
285 // remove configured callbacks, if any
286 for (std::size_t i = 0; i < ndqi->GetNTxQueues(); i++)
287 {
288 ndqi->GetTxQueue(i)->SetWakeCallback(MakeNullCallback<void>());
289 }
290 }
291 else
292 {
293 // remove the empty entry
294 m_netDevices.erase(ndi);
295 }
296}
297
298void
300{
301 NS_LOG_FUNCTION(this << node);
302 m_node = node;
303}
304
305void
307{
308 NS_LOG_FUNCTION(this);
309 if (!m_node)
310 {
311 Ptr<Node> node = this->GetObject<Node>();
312 // verify that it's a valid node and that
313 // the node was not set before
314 if (node)
315 {
316 this->SetNode(node);
317 }
318 }
320}
321
324{
325 return m_node->GetNDevices();
326}
327
328void
331 uint16_t protocol,
332 const Address& from,
333 const Address& to,
334 NetDevice::PacketType packetType)
335{
336 NS_LOG_FUNCTION(this << device << p << protocol << from << to << packetType);
337
338 bool found = false;
339
340 for (auto i = m_handlers.begin(); i != m_handlers.end(); i++)
341 {
342 if (!i->device || (i->device == device))
343 {
344 if (i->protocol == 0 || i->protocol == protocol)
345 {
346 NS_LOG_DEBUG("Found handler for packet " << p << ", protocol " << protocol
347 << " and NetDevice " << device
348 << ". Send packet up");
349 i->handler(device, p, protocol, from, to, packetType);
350 found = true;
351 }
352 }
353 }
354
355 NS_ABORT_MSG_IF(!found,
356 "Handler for protocol " << p << " and device " << device
357 << " not found. It isn't forwarded up; it dies here.");
358}
359
360void
362{
363 NS_LOG_FUNCTION(this << device << item);
364
365 NS_LOG_DEBUG("Send packet to device " << device << " protocol number " << item->GetProtocol());
366
367 Ptr<NetDeviceQueueInterface> devQueueIface;
368 auto ndi = m_netDevices.find(device);
369
370 if (ndi != m_netDevices.end())
371 {
372 devQueueIface = ndi->second.m_ndqi;
373 }
374
375 // determine the transmission queue of the device where the packet will be enqueued
376 std::size_t txq = 0;
377 if (devQueueIface && devQueueIface->GetNTxQueues() > 1)
378 {
379 txq = devQueueIface->GetSelectQueueCallback()(item);
380 // otherwise, Linux determines the queue index by using a hash function
381 // and associates such index to the socket which the packet belongs to,
382 // so that subsequent packets of the same socket will be mapped to the
383 // same tx queue (__netdev_pick_tx function in net/core/dev.c). It is
384 // pointless to implement this in ns-3 because currently the multi-queue
385 // devices provide a select queue callback
386 }
387
388 NS_ASSERT(!devQueueIface || txq < devQueueIface->GetNTxQueues());
389
390 if (ndi == m_netDevices.end() || !ndi->second.m_rootQueueDisc)
391 {
392 // The device has no attached queue disc, thus add the header to the packet and
393 // send it directly to the device if the selected queue is not stopped
394 item->AddHeader();
395 if (!devQueueIface || !devQueueIface->GetTxQueue(txq)->IsStopped())
396 {
397 // a single queue device makes no use of the priority tag
398 if (!devQueueIface || devQueueIface->GetNTxQueues() == 1)
399 {
400 SocketPriorityTag priorityTag;
401 item->GetPacket()->RemovePacketTag(priorityTag);
402 }
403 device->Send(item->GetPacket(), item->GetAddress(), item->GetProtocol());
404 }
405 else
406 {
407 m_dropped(item->GetPacket());
408 }
409 }
410 else
411 {
412 // Enqueue the packet in the queue disc associated with the netdevice queue
413 // selected for the packet and try to dequeue packets from such queue disc
414 item->SetTxQueueIndex(txq);
415
416 Ptr<QueueDisc> qDisc = ndi->second.m_queueDiscsToWake[txq];
417 NS_ASSERT(qDisc);
418 qDisc->Enqueue(item);
419 qDisc->Run();
420 }
421}
422
423} // namespace ns3
a polymophic address class
Definition: address.h:101
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:300
Network device transmission queue interface.
uint32_t GetNDevices() const
Definition: node.cc:162
uint32_t GetId() const
Definition: node.cc:117
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:152
A base class which provides memory management and object aggregation.
Definition: object.h:89
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:423
virtual void DoInitialize()
Initialize() implementation.
Definition: object.cc:451
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:444
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
void Run()
Modelled after the Linux function __qdisc_run (net/sched/sch_generic.c) Dequeues multiple packets,...
Definition: queue-disc.cc:945
indicates whether the socket has a priority set.
Definition: socket.h:1318
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:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#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:86
ObjectPtrContainerValue ObjectMapValue
ObjectMapValue is an alias for ObjectPtrContainerValue.
Definition: object-map.h:40
Ptr< const AttributeAccessor > MakeObjectMapAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-map.h:76
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#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:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:46
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:704
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