A Discrete-Event Network Simulator
API
wifi-mac-queue-scheduler-impl.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Stefano Avallone <stavallo@unina.it>
18 */
19
20#ifndef WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
21#define WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
22
24#include "wifi-mac-queue.h"
25#include "wifi-mac.h"
26
27#include <functional>
28#include <list>
29#include <map>
30#include <numeric>
31#include <unordered_map>
32#include <vector>
33
35
36namespace ns3
37{
38
39class WifiMpdu;
40class WifiMacQueue;
41
49template <class Priority, class Compare = std::less<Priority>>
51{
52 public:
54 friend class ::WifiMacQueueDropOldestTest;
55
60 static TypeId GetTypeId();
61
66
70 std::optional<WifiContainerQueueId> GetNext(AcIndex ac, uint8_t linkId) final;
72 std::optional<WifiContainerQueueId> GetNext(AcIndex ac,
73 uint8_t linkId,
74 const WifiContainerQueueId& prevQueueId) final;
76 std::list<uint8_t> GetLinkIds(AcIndex ac, const WifiContainerQueueId& queueId) final;
79 const WifiContainerQueueId& queueId,
80 const std::list<uint8_t>& linkIds) final;
84 void NotifyEnqueue(AcIndex ac, Ptr<WifiMpdu> mpdu) final;
86 void NotifyDequeue(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) final;
88 void NotifyRemove(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) final;
89
90 protected:
92 void DoDispose() override;
93
101 void SetPriority(AcIndex ac, const WifiContainerQueueId& queueId, const Priority& priority);
102
103 struct QueueInfo;
104
111 using QueueInfoMap = std::unordered_map<WifiContainerQueueId, QueueInfo>;
112
114 using QueueInfoPair = std::pair<const WifiContainerQueueId, QueueInfo>;
115
125 using SortedQueues = std::multimap<Priority, std::reference_wrapper<QueueInfoPair>, Compare>;
126
131 {
132 std::optional<typename SortedQueues::iterator>
135 std::list<uint8_t> linkIds;
138 };
139
144 {
148 };
149
159
167
168 private:
179 typename QueueInfoMap::iterator InitQueueInfo(AcIndex ac, const WifiContainerQueueId& queueId);
180
191 std::optional<WifiContainerQueueId> DoGetNext(AcIndex ac,
192 uint8_t linkId,
193 typename SortedQueues::iterator sortedQueuesIt);
194
211 virtual void DoNotifyEnqueue(AcIndex ac, Ptr<WifiMpdu> mpdu) = 0;
220 virtual void DoNotifyDequeue(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) = 0;
229 virtual void DoNotifyRemove(AcIndex ac, const std::list<Ptr<WifiMpdu>>& mpdus) = 0;
230
231 std::vector<PerAcInfo> m_perAcInfo{AC_UNDEF};
233};
234
239template <class Priority, class Compare>
241 : NS_LOG_TEMPLATE_DEFINE("WifiMacQueueScheduler")
242{
243}
244
245template <class Priority, class Compare>
246TypeId
248{
249 static TypeId tid = TypeId("ns3::WifiMacQueueSchedulerImpl")
251 .SetGroupName("Wifi");
252 return tid;
253}
254
255template <class Priority, class Compare>
256void
258{
259 m_perAcInfo.clear();
261}
262
263template <class Priority, class Compare>
264void
266{
267 for (auto ac : {AC_BE, AC_BK, AC_VI, AC_VO, AC_BE_NQOS, AC_BEACON})
268 {
269 if (auto queue = mac->GetTxopQueue(ac); queue != nullptr)
270 {
271 m_perAcInfo.at(ac).wifiMacQueue = queue;
272 queue->SetScheduler(this);
273 }
274 }
276}
277
278template <class Priority, class Compare>
281{
282 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
283 return m_perAcInfo.at(ac).wifiMacQueue;
284}
285
286template <class Priority, class Compare>
289{
290 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
291 return m_perAcInfo.at(ac).sortedQueues;
292}
293
294template <class Priority, class Compare>
297 const WifiContainerQueueId& queueId)
298{
299 NS_LOG_FUNCTION(this);
300
301 // insert queueId in the queue info map if not present yet
302 auto [queueInfoIt, ret] = m_perAcInfo[ac].queueInfoMap.insert({queueId, QueueInfo()});
303
304 if (ret)
305 {
306 // The given queueid has just been inserted in the queue info map.
307 // Initialize the set of link IDs depending on the container queue type
308 auto queueType = std::get<WifiContainerQueueType>(queueId);
309
310 if (queueType == WIFI_MGT_QUEUE || queueType == WIFI_QOSDATA_BROADCAST_QUEUE)
311 {
312 // these queue types are associated with just one link
313 NS_ASSERT(GetMac());
314 auto linkId = GetMac()->GetLinkIdByAddress(std::get<Mac48Address>(queueId));
315 NS_ASSERT(linkId.has_value());
316 queueInfoIt->second.linkIds = {*linkId};
317 }
318 }
319 return queueInfoIt;
320}
321
322template <class Priority, class Compare>
323void
325 const WifiContainerQueueId& queueId,
326 const Priority& priority)
327{
328 NS_LOG_FUNCTION(this << +ac);
329 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
330
331 NS_ABORT_MSG_IF(GetWifiMacQueue(ac)->GetNBytes(queueId) == 0,
332 "Cannot set the priority of an empty queue");
333
334 // insert queueId in the queue info map if not present yet
335 auto queueInfoIt = InitQueueInfo(ac, queueId);
336 typename SortedQueues::iterator sortedQueuesIt;
337
338 if (queueInfoIt->second.priorityIt.has_value())
339 {
340 // an element for queueId is present in the set of sorted queues. If the priority
341 // has not changed, do nothing. Otherwise, unlink the node containing such element,
342 // change the priority and insert it back
343 if (queueInfoIt->second.priorityIt.value()->first == priority)
344 {
345 return;
346 }
347
348 auto handle = m_perAcInfo[ac].sortedQueues.extract(queueInfoIt->second.priorityIt.value());
349 handle.key() = priority;
350 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert(std::move(handle));
351 }
352 else
353 {
354 // an element for queueId is not present in the set of sorted queues
355 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert({priority, std::ref(*queueInfoIt)});
356 }
357 // update the stored iterator
358 queueInfoIt->second.priorityIt = sortedQueuesIt;
359}
360
361template <class Priority, class Compare>
362std::list<uint8_t>
364 const WifiContainerQueueId& queueId)
365{
366 auto queueInfoIt = InitQueueInfo(ac, queueId);
367
368 if (queueInfoIt->second.linkIds.empty())
369 {
370 // return the IDs of all available links
371 NS_ASSERT(GetMac() != nullptr);
372 std::list<uint8_t> linkIds(GetMac()->GetNLinks());
373 std::iota(linkIds.begin(), linkIds.end(), 0);
374 return linkIds;
375 }
376 return queueInfoIt->second.linkIds;
377}
378
379template <class Priority, class Compare>
380void
382 const WifiContainerQueueId& queueId,
383 const std::list<uint8_t>& linkIds)
384{
385 NS_LOG_FUNCTION(this << +ac);
386 auto [queueInfoIt, ret] = m_perAcInfo[ac].queueInfoMap.insert({queueId, QueueInfo()});
387 queueInfoIt->second.linkIds = linkIds;
388}
389
390template <class Priority, class Compare>
391std::optional<WifiContainerQueueId>
393{
394 NS_LOG_FUNCTION(this << +ac << +linkId);
395 return DoGetNext(ac, linkId, m_perAcInfo[ac].sortedQueues.begin());
396}
397
398template <class Priority, class Compare>
399std::optional<WifiContainerQueueId>
401 uint8_t linkId,
402 const WifiContainerQueueId& prevQueueId)
403{
404 NS_LOG_FUNCTION(this << +ac << +linkId);
405
406 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
407 NS_ABORT_IF(queueInfoIt == m_perAcInfo[ac].queueInfoMap.end() ||
408 !queueInfoIt->second.priorityIt.has_value());
409
410 auto sortedQueuesIt = queueInfoIt->second.priorityIt.value();
411 NS_ABORT_IF(sortedQueuesIt == m_perAcInfo[ac].sortedQueues.end());
412
413 return DoGetNext(ac, linkId, ++sortedQueuesIt);
414}
415
416template <class Priority, class Compare>
417std::optional<WifiContainerQueueId>
419 AcIndex ac,
420 uint8_t linkId,
421 typename SortedQueues::iterator sortedQueuesIt)
422{
423 NS_LOG_FUNCTION(this << +ac << +linkId);
424 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
425
426 while (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
427 {
428 const auto& queueInfoPair = sortedQueuesIt->second.get();
429 const auto& linkIds = queueInfoPair.second.linkIds;
430
431 if (linkIds.empty() || std::find(linkIds.begin(), linkIds.end(), linkId) != linkIds.end())
432 {
433 // Packets in this queue can be sent over the link we got channel access on.
434 // Now remove packets with expired lifetime from this queue.
435 // In case the queue becomes empty, the queue is removed from the sorted
436 // list and sortedQueuesIt is invalidated; thus, store an iterator to the
437 // previous queue in the sorted list (if any) to resume the search afterwards.
438 std::optional<typename SortedQueues::iterator> prevQueueIt;
439 if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.begin())
440 {
441 prevQueueIt = std::prev(sortedQueuesIt);
442 }
443
444 GetWifiMacQueue(ac)->ExtractExpiredMpdus(queueInfoPair.first);
445
446 if (GetWifiMacQueue(ac)->GetNBytes(queueInfoPair.first) == 0)
447 {
448 sortedQueuesIt = (prevQueueIt.has_value() ? std::next(prevQueueIt.value())
449 : m_perAcInfo[ac].sortedQueues.begin());
450 continue;
451 }
452 break;
453 }
454
455 sortedQueuesIt++;
456 }
457
458 std::optional<WifiContainerQueueId> queueId;
459
460 if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
461 {
462 queueId = sortedQueuesIt->second.get().first;
463 }
464 return queueId;
465}
466
467template <class Priority, class Compare>
470{
471 NS_LOG_FUNCTION(this << +ac << *mpdu);
472 return HasToDropBeforeEnqueuePriv(ac, mpdu);
473}
474
475template <class Priority, class Compare>
476void
478{
479 NS_LOG_FUNCTION(this << +ac << *mpdu);
480 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
481
482 DoNotifyEnqueue(ac, mpdu);
483
484 if (auto queueInfoIt =
485 m_perAcInfo[ac].queueInfoMap.find(WifiMacQueueContainer::GetQueueId(mpdu));
486 queueInfoIt == m_perAcInfo[ac].queueInfoMap.end() ||
487 !queueInfoIt->second.priorityIt.has_value())
488 {
490 "No info for the queue the MPDU was stored into (forgot to call SetPriority()?)");
491 }
492}
493
494template <class Priority, class Compare>
495void
497 const std::list<Ptr<WifiMpdu>>& mpdus)
498{
499 NS_LOG_FUNCTION(this << +ac);
500 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
501
502 DoNotifyDequeue(ac, mpdus);
503
504 std::list<WifiContainerQueueId> queueIds;
505
506 for (const auto& mpdu : mpdus)
507 {
508 queueIds.push_back(WifiMacQueueContainer::GetQueueId(mpdu));
509 }
510
511 for (const auto& queueId : queueIds)
512 {
513 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
514 {
515 // The queue has now become empty and needs to be removed from the sorted
516 // list kept by the scheduler
517 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
518 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
519 if (queueInfoIt->second.priorityIt.has_value())
520 {
521 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
522 queueInfoIt->second.priorityIt.reset();
523 }
524 }
525 }
526}
527
528template <class Priority, class Compare>
529void
531 const std::list<Ptr<WifiMpdu>>& mpdus)
532{
533 NS_LOG_FUNCTION(this << +ac);
534 NS_ASSERT(static_cast<uint8_t>(ac) < AC_UNDEF);
535
536 DoNotifyRemove(ac, mpdus);
537
538 std::list<WifiContainerQueueId> queueIds;
539
540 for (const auto& mpdu : mpdus)
541 {
542 queueIds.push_back(WifiMacQueueContainer::GetQueueId(mpdu));
543 }
544
545 for (const auto& queueId : queueIds)
546 {
547 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
548 {
549 // The queue has now become empty and needs to be removed from the sorted
550 // list kept by the scheduler
551 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
552 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
553 if (queueInfoIt->second.priorityIt.has_value())
554 {
555 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
556 queueInfoIt->second.priorityIt.reset();
557 }
558 }
559 }
560}
561
562} // namespace ns3
563
564#endif /* WIFI_MAC_QUEUE_SCHEDULER_IMPL_H */
Test DROP_OLDEST setting.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
static WifiContainerQueueId GetQueueId(Ptr< const WifiMpdu > mpdu)
Return the QueueId identifying the container queue in which the given MPDU is (or is to be) enqueued.
WifiMacQueueScheduler is an abstract base class defining the public interface for a wifi MAC queue sc...
virtual void SetWifiMac(Ptr< WifiMac > mac)
Set the wifi MAC.
void DoDispose() override
Destructor implementation.
WifiMacQueueSchedulerImpl is a template class enabling the definition of different types of priority ...
std::pair< const WifiContainerQueueId, QueueInfo > QueueInfoPair
typedef for a QueueInfoMap element
void SetWifiMac(Ptr< WifiMac > mac) final
Set the wifi MAC.
void DoDispose() override
Destructor implementation.
void NotifyDequeue(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
Notify the scheduler that the given list of MPDUs have been dequeued by the given Access Category.
std::unordered_map< WifiContainerQueueId, QueueInfo > QueueInfoMap
Map identifiers (QueueIds) to information associated with container queues.
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, uint8_t linkId, const WifiContainerQueueId &prevQueueId) final
Get the next queue to serve after the given one.
void NotifyEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) final
Notify the scheduler that the given MPDU has been enqueued by the given Access Category.
QueueInfoMap::iterator InitQueueInfo(AcIndex ac, const WifiContainerQueueId &queueId)
Add the information associated with the given container queue (if not already present) to the map cor...
virtual void DoNotifyDequeue(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus)=0
Notify the scheduler that the given list of MPDUs have been dequeued by the given Access Category.
virtual void DoNotifyEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu)=0
Notify the scheduler that the given MPDU has been enqueued by the given Access Category.
Ptr< WifiMacQueue > GetWifiMacQueue(AcIndex ac) const
Get the wifi MAC queue associated with the given Access Category.
void SetLinkIds(AcIndex ac, const WifiContainerQueueId &queueId, const std::list< uint8_t > &linkIds) final
Set the list of the IDs of the links the given container queue (belonging to the given Access Categor...
static TypeId GetTypeId()
Get the type ID.
std::optional< WifiContainerQueueId > DoGetNext(AcIndex ac, uint8_t linkId, typename SortedQueues::iterator sortedQueuesIt)
Get the next queue to serve.
std::vector< PerAcInfo > m_perAcInfo
vector of per-AC information
const SortedQueues & GetSortedQueues(AcIndex ac) const
Get a const reference to the sorted list of container queues for the given Access Category.
Ptr< WifiMpdu > HasToDropBeforeEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) final
Check whether an MPDU has to be dropped before enqueuing the given MPDU.
std::list< uint8_t > GetLinkIds(AcIndex ac, const WifiContainerQueueId &queueId) final
Get the list of the IDs of the links the given container queue (belonging to the given Access Categor...
void NotifyRemove(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
Notify the scheduler that the given list of MPDUs have been removed by the given Access Category.
virtual Ptr< WifiMpdu > HasToDropBeforeEnqueuePriv(AcIndex ac, Ptr< WifiMpdu > mpdu)=0
Check whether an MPDU has to be dropped before enqueuing the given MPDU.
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, uint8_t linkId) final
Get the next queue to serve, which is guaranteed to contain at least an MPDU whose lifetime has not e...
std::multimap< Priority, std::reference_wrapper< QueueInfoPair >, Compare > SortedQueues
List of container queues sorted in decreasing order of priority.
virtual void DoNotifyRemove(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus)=0
Notify the scheduler that the given list of MPDUs have been removed by the given Access Category.
void SetPriority(AcIndex ac, const WifiContainerQueueId &queueId, const Priority &priority)
Set the priority for the given container queue belonging to the given Access Category.
#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_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_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition: abort.h:76
#define NS_LOG_TEMPLATE_DEFINE(name)
Initialize a reference to a Log component.
Definition: log.h:236
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition: qos-utils.h:74
@ AC_BE_NQOS
Non-QoS.
Definition: qos-utils.h:84
@ AC_BE
Best Effort.
Definition: qos-utils.h:76
@ AC_VO
Voice.
Definition: qos-utils.h:82
@ AC_VI
Video.
Definition: qos-utils.h:80
@ AC_BK
Background.
Definition: qos-utils.h:78
@ AC_UNDEF
Total number of ACs.
Definition: qos-utils.h:88
@ AC_BEACON
Beacon queue.
Definition: qos-utils.h:86
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::tuple< WifiContainerQueueType, Mac48Address, uint8_t > WifiContainerQueueId
Tuple (queue type, Address, TID) identifying a container queue.
@ WIFI_QOSDATA_BROADCAST_QUEUE
mac
Definition: third.py:85
#define list
Information specific to a wifi MAC queue.
SortedQueues sortedQueues
sorted list of container queues
Ptr< WifiMacQueue > wifiMacQueue
pointer to the WifiMacQueue object
QueueInfoMap queueInfoMap
information associated with container queues
Information associated with a container queue.
std::list< uint8_t > linkIds
IDs of the links over which packets contained in this queue can be sent over.
std::optional< typename SortedQueues::iterator > priorityIt
iterator pointing to the entry for this queue in the sorted list
uint32_t prev