20 #ifndef WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
21 #define WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
32 #include <unordered_map>
50 template <
class Priority,
class Compare = std::less<Priority>>
55 friend class ::WifiMacQueueDropOldestTest;
71 std::optional<WifiContainerQueueId>
GetNext(
AcIndex ac, std::optional<uint8_t> linkId)
final;
77 std::optional<uint8_t> linkId,
84 const std::list<WifiContainerQueueType>& types,
87 const std::set<uint8_t>& tids,
88 const std::set<uint8_t>& linkIds)
final;
92 const std::list<WifiContainerQueueType>& types,
95 const std::set<uint8_t>& tids,
96 const std::set<uint8_t>& linkIds)
final;
100 uint8_t linkId)
final;
131 using QueueInfoMap = std::unordered_map<WifiContainerQueueId, QueueInfo>;
145 using SortedQueues = std::multimap<Priority, std::reference_wrapper<QueueInfoPair>, Compare>;
152 std::optional<typename SortedQueues::iterator>
215 std::optional<uint8_t> linkId,
216 typename SortedQueues::iterator sortedQueuesIt);
271 const std::list<WifiContainerQueueType>& types,
274 const std::set<uint8_t>& tids,
275 const std::set<uint8_t>& linkIds);
285 template <
class Priority,
class Compare>
291 template <
class Priority,
class Compare>
295 static TypeId tid =
TypeId(
"ns3::WifiMacQueueSchedulerImpl")
297 .SetGroupName(
"Wifi");
301 template <
class Priority,
class Compare>
309 template <
class Priority,
class Compare>
315 if (
auto queue =
mac->GetTxopQueue(ac); queue !=
nullptr)
317 m_perAcInfo.at(ac).wifiMacQueue = queue;
318 queue->SetScheduler(
this);
324 template <
class Priority,
class Compare>
329 return m_perAcInfo.at(ac).wifiMacQueue;
332 template <
class Priority,
class Compare>
337 return m_perAcInfo.at(ac).sortedQueues;
340 template <
class Priority,
class Compare>
348 auto [queueInfoIt, ret] = m_perAcInfo[ac].queueInfoMap.insert({queueId,
QueueInfo()});
351 if (GetMac() && GetMac()->GetNLinks() > 1 &&
352 mpdu->GetHeader().GetAddr2() == GetMac()->GetAddress())
356 const auto rxAddr = mpdu->GetHeader().GetAddr1();
360 NS_ASSERT_MSG(rxAddr.IsGroup() || GetMac()->GetMldAddress(rxAddr) == rxAddr,
361 "Address 1 (" << rxAddr <<
") is not an MLD address");
365 NS_ASSERT_MSG(GetMac()->CanForwardPacketsTo(rxAddr),
"Cannot forward frame to " << rxAddr);
368 for (
const auto linkId : GetMac()->GetLinkIds())
370 if (rxAddr.IsGroup() ||
371 GetMac()->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(rxAddr))
374 queueInfoIt->second.linkIds.emplace(linkId,
Mask{});
379 queueInfoIt->second.linkIds.erase(linkId);
387 auto linkId = GetMac() ? GetMac()->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2())
390 auto& linkIdsMap = queueInfoIt->second.linkIds;
392 "At most one link can be associated with this container queue");
396 if (linkIdsMap.empty() || linkIdsMap.cbegin()->first != *linkId)
398 linkIdsMap = {{*linkId,
Mask{}}};
405 template <
class Priority,
class Compare>
409 const Priority& priority)
415 "Cannot set the priority of an empty queue");
417 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
418 NS_ASSERT_MSG(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end(),
419 "No queue info for the given container queue");
420 typename SortedQueues::iterator sortedQueuesIt;
422 if (queueInfoIt->second.priorityIt.has_value())
427 if (queueInfoIt->second.priorityIt.value()->first == priority)
432 auto handle = m_perAcInfo[ac].sortedQueues.extract(queueInfoIt->second.priorityIt.value());
433 handle.key() = priority;
434 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert(std::move(handle));
439 sortedQueuesIt = m_perAcInfo[ac].sortedQueues.insert({priority, std::ref(*queueInfoIt)});
442 queueInfoIt->second.priorityIt = sortedQueuesIt;
445 template <
class Priority,
class Compare>
449 auto queueInfoIt = InitQueueInfo(ac, mpdu);
450 std::list<uint8_t> linkIds;
453 for (
const auto& [linkId, mask] : queueInfoIt->second.linkIds)
457 linkIds.emplace_back(linkId);
464 template <
class Priority,
class Compare>
470 const std::list<WifiContainerQueueType>& types,
473 const std::set<uint8_t>& tids,
474 const std::set<uint8_t>& linkIds)
476 NS_LOG_FUNCTION(
this << block << reason << ac << rxAddress << txAddress);
477 std::list<WifiMacHeader> headers;
479 for (
const auto queueType : types)
491 "TID must be specified for queues containing QoS data frames");
492 for (
const auto tid : tids)
495 headers.back().SetQosTid(tid);
503 for (
auto& hdr : headers)
505 hdr.SetAddr1(rxAddress);
506 hdr.SetAddr2(txAddress);
508 auto queueInfoIt = InitQueueInfo(ac, Create<WifiMpdu>(Create<Packet>(), hdr));
509 for (
auto& [linkId, mask] : queueInfoIt->second.linkIds)
511 if (linkIds.empty() || linkIds.count(linkId) > 0)
513 mask.set(
static_cast<std::size_t
>(reason), block);
519 template <
class Priority,
class Compare>
524 const std::list<WifiContainerQueueType>& types,
527 const std::set<uint8_t>& tids,
528 const std::set<uint8_t>& linkIds)
530 DoBlockQueues(
true, reason, ac, types, rxAddress, txAddress, tids, linkIds);
533 template <
class Priority,
class Compare>
538 const std::list<WifiContainerQueueType>& types,
541 const std::set<uint8_t>& tids,
542 const std::set<uint8_t>& linkIds)
544 DoBlockQueues(
false, reason, ac, types, rxAddress, txAddress, tids, linkIds);
547 template <
class Priority,
class Compare>
548 std::optional<WifiMacQueueScheduler::Mask>
555 const auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
557 if (queueInfoIt == m_perAcInfo[ac].queueInfoMap.cend())
563 const auto& linkIds = queueInfoIt->second.linkIds;
564 if (
const auto linkIt = linkIds.find(linkId); linkIt != linkIds.cend())
566 return linkIt->second;
572 template <
class Priority,
class Compare>
573 std::optional<WifiContainerQueueId>
577 return DoGetNext(ac, linkId, m_perAcInfo[ac].sortedQueues.begin());
580 template <
class Priority,
class Compare>
581 std::optional<WifiContainerQueueId>
583 std::optional<uint8_t> linkId,
588 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
589 NS_ABORT_IF(queueInfoIt == m_perAcInfo[ac].queueInfoMap.end() ||
590 !queueInfoIt->second.priorityIt.has_value());
592 auto sortedQueuesIt = queueInfoIt->second.priorityIt.value();
593 NS_ABORT_IF(sortedQueuesIt == m_perAcInfo[ac].sortedQueues.end());
595 return DoGetNext(ac, linkId, ++sortedQueuesIt);
598 template <
class Priority,
class Compare>
599 std::optional<WifiContainerQueueId>
602 std::optional<uint8_t> linkId,
603 typename SortedQueues::iterator sortedQueuesIt)
608 while (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
610 const auto& queueInfoPair = sortedQueuesIt->second.get();
611 const auto& linkIds = queueInfoPair.second.linkIds;
612 typename std::decay_t<decltype(linkIds)>::const_iterator linkIt;
614 if (!linkId.has_value() ||
615 ((linkIt = linkIds.find(*linkId)) != linkIds.cend() && linkIt->second.none()))
622 std::optional<typename SortedQueues::iterator> prevQueueIt;
623 if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.begin())
628 GetWifiMacQueue(ac)->ExtractExpiredMpdus(queueInfoPair.first);
630 if (GetWifiMacQueue(ac)->GetNBytes(queueInfoPair.first) == 0)
632 sortedQueuesIt = (prevQueueIt.has_value() ? std::next(prevQueueIt.value())
633 : m_perAcInfo[ac].sortedQueues.begin());
642 std::optional<WifiContainerQueueId> queueId;
644 if (sortedQueuesIt != m_perAcInfo[ac].sortedQueues.end())
646 queueId = sortedQueuesIt->second.get().first;
651 template <
class Priority,
class Compare>
656 return HasToDropBeforeEnqueuePriv(ac, mpdu);
659 template <
class Priority,
class Compare>
667 auto queueInfoIt = InitQueueInfo(ac, mpdu);
669 DoNotifyEnqueue(ac, mpdu);
671 if (!queueInfoIt->second.priorityIt.has_value())
674 "No info for the queue the MPDU was stored into (forgot to call SetPriority()?)");
678 template <
class Priority,
class Compare>
686 DoNotifyDequeue(ac, mpdus);
688 std::list<WifiContainerQueueId> queueIds;
690 for (
const auto& mpdu : mpdus)
695 for (
const auto& queueId : queueIds)
697 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
701 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
702 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
703 if (queueInfoIt->second.priorityIt.has_value())
705 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
706 queueInfoIt->second.priorityIt.reset();
712 template <
class Priority,
class Compare>
720 DoNotifyRemove(ac, mpdus);
722 std::list<WifiContainerQueueId> queueIds;
724 for (
const auto& mpdu : mpdus)
729 for (
const auto& queueId : queueIds)
731 if (GetWifiMacQueue(ac)->GetNBytes(queueId) == 0)
735 auto queueInfoIt = m_perAcInfo[ac].queueInfoMap.find(queueId);
736 NS_ASSERT(queueInfoIt != m_perAcInfo[ac].queueInfoMap.end());
737 if (queueInfoIt->second.priorityIt.has_value())
739 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
740 queueInfoIt->second.priorityIt.reset();
Test DROP_OLDEST setting.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
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.
std::bitset< static_cast< std::size_t >(WifiQueueBlockedReason::REASONS_COUNT)> Mask
Bitset identifying the reasons to block individual links for a container queue.
void DoDispose() override
Destructor implementation.
WifiMacQueueSchedulerImpl is a template class enabling the definition of different types of priority ...
void DoBlockQueues(bool block, WifiQueueBlockedReason reason, AcIndex ac, const std::list< WifiContainerQueueType > &types, const Mac48Address &rxAddress, const Mac48Address &txAddress, const std::set< uint8_t > &tids, const std::set< uint8_t > &linkIds)
Block or unblock the given set of links for the container queues of the given types and Access Catego...
void UnblockQueues(WifiQueueBlockedReason reason, AcIndex ac, const std::list< WifiContainerQueueType > &types, const Mac48Address &rxAddress, const Mac48Address &txAddress, const std::set< uint8_t > &tids, const std::set< uint8_t > &linkIds) final
Unblock the given set of links for the container queues of the given types and Access Category that h...
std::pair< const WifiContainerQueueId, QueueInfo > QueueInfoPair
typedef for a QueueInfoMap element
NS_LOG_TEMPLATE_DECLARE
the log component
std::optional< Mask > GetQueueLinkMask(AcIndex ac, const WifiContainerQueueId &queueId, uint8_t linkId) final
Get the mask associated with the given container queue indicating whether the given link is blocked a...
void SetWifiMac(Ptr< WifiMac > mac) final
Set the wifi MAC.
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.
void DoDispose() override
Destructor implementation.
std::unordered_map< WifiContainerQueueId, QueueInfo > QueueInfoMap
Map identifiers (QueueIds) to information associated with container queues.
void NotifyEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) final
Notify the scheduler that the given MPDU has been enqueued by the given Access Category.
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.
void BlockQueues(WifiQueueBlockedReason reason, AcIndex ac, const std::list< WifiContainerQueueType > &types, const Mac48Address &rxAddress, const Mac48Address &txAddress, const std::set< uint8_t > &tids, const std::set< uint8_t > &linkIds) final
Block the given set of links for the container queues of the given types and Access Category that hol...
virtual void DoNotifyEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu)=0
Notify the scheduler that the given MPDU has been enqueued 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.
Ptr< WifiMacQueue > GetWifiMacQueue(AcIndex ac) const
Get the wifi MAC queue associated with the given Access Category.
std::list< uint8_t > GetLinkIds(AcIndex ac, Ptr< const WifiMpdu > mpdu) final
Get the list of the IDs of the links the given MPDU (belonging to the given Access Category) can be s...
static TypeId GetTypeId()
Get the type ID.
std::vector< PerAcInfo > m_perAcInfo
vector of per-AC information
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, std::optional< uint8_t > linkId) final
Get the next queue to serve, which is guaranteed to contain at least an MPDU whose lifetime has not e...
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.
WifiMacQueueSchedulerImpl()
Constructor.
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 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.
QueueInfoMap::iterator InitQueueInfo(AcIndex ac, Ptr< const WifiMpdu > mpdu)
If no information for the container queue used to store the given MPDU of the given Access Category i...
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, std::optional< uint8_t > linkId, const WifiContainerQueueId &prevQueueId) 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.
std::optional< WifiContainerQueueId > DoGetNext(AcIndex ac, std::optional< uint8_t > linkId, typename SortedQueues::iterator sortedQueuesIt)
Get the next queue to serve.
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,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
#define NS_LOG_TEMPLATE_DEFINE(name)
Initialize a reference to a Log component.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
WifiQueueBlockedReason
Enumeration of the reasons to block container queues.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
@ AC_UNDEF
Total number of ACs.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
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::map< uint8_t, Mask > linkIds
Maps ID of each link on which packets contained in this queue can be sent to a bitset indicating whet...
std::optional< typename SortedQueues::iterator > priorityIt
iterator pointing to the entry for this queue in the sorted list