9#ifndef WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
10#define WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
24#include <unordered_map>
43template <
class Priority,
class Compare = std::less<Priority>>
48 friend class ::WifiMacQueueDropOldestTest;
49 friend class ::WifiMacQueueFlushTest;
66 std::optional<uint8_t> linkId,
67 bool skipBlockedQueues =
true) final;
73 std::optional<uint8_t> linkId,
75 bool skipBlockedQueues = true) final;
86 const
std::set<uint8_t>& tids,
87 const
std::set<uint8_t>& linkIds) final;
94 const
std::set<uint8_t>& tids,
95 const
std::set<uint8_t>& linkIds) final;
98 const
std::set<uint8_t>& linkIds,
102 const
std::set<uint8_t>& linkIds,
111 uint8_t linkId) final;
163 std::optional<typename SortedQueues::iterator>
229 std::optional<uint8_t> linkId,
230 typename SortedQueues::iterator sortedQueuesIt,
231 bool skipBlockedQueues);
286 const std::list<WifiContainerQueueType>& types,
289 const std::set<uint8_t>& tids,
290 const std::set<uint8_t>& linkIds);
303 const std::set<WifiRcvAddr>& addrTypes,
304 const std::set<uint8_t>& linkIds);
325template <
class Priority,
class Compare>
331template <
class Priority,
class Compare>
335 static TypeId tid =
TypeId(
"ns3::WifiMacQueueSchedulerImpl")
337 .SetGroupName(
"Wifi");
341template <
class Priority,
class Compare>
349template <
class Priority,
class Compare>
355 if (
auto queue = mac->GetTxopQueue(ac); queue !=
nullptr)
358 queue->SetScheduler(
this);
364template <
class Priority,
class Compare>
372template <
class Priority,
class Compare>
380template <
class Priority,
class Compare>
381typename WifiMacQueueSchedulerImpl<Priority, Compare>::QueueInfoMap::iterator
392 mpdu->GetHeader().GetAddr2() ==
GetMac()->GetAddress())
396 const auto rxAddr = mpdu->GetHeader().GetAddr1();
401 "Address 1 (" << rxAddr <<
") is not an MLD address");
406 "Cannot forward frame to " << rxAddr
407 <<
"; check that the receiver is associated");
412 if (rxAddr.IsGroup() ||
413 GetMac()->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(rxAddr))
416 auto [it, inserted] = queueInfoIt->second.linkIds.try_emplace(linkId);
421 for (
const auto& [reason, linkIds] :
422 m_blockAllInfo[
static_cast<std::size_t
>(std::get<WifiRcvAddr>(queueId))])
424 if (linkIds.contains(linkId))
426 it->second.set(
static_cast<std::size_t
>(reason),
true);
434 queueInfoIt->second.linkIds.erase(linkId);
442 auto linkId =
GetMac() ?
GetMac()->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2())
445 auto& linkIdsMap = queueInfoIt->second.linkIds;
447 "At most one link can be associated with this container queue");
451 if (linkIdsMap.empty() || linkIdsMap.cbegin()->first != *linkId)
454 for (
const auto& [reason, linkIds] :
455 m_blockAllInfo[
static_cast<std::size_t
>(std::get<WifiRcvAddr>(queueId))])
457 if (linkIds.contains(*linkId))
459 mask.set(
static_cast<std::size_t
>(reason),
true);
463 linkIdsMap = {{*linkId, mask}};
470template <
class Priority,
class Compare>
474 const Priority& priority)
480 "Cannot set the priority of an empty queue");
482 auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(queueId);
484 "No queue info for the given container queue");
485 typename SortedQueues::iterator sortedQueuesIt;
487 if (queueInfoIt->second.priorityIt.has_value())
492 if (queueInfoIt->second.priorityIt.value()->first == priority)
497 auto handle =
m_perAcInfo[ac].sortedQueues.extract(queueInfoIt->second.priorityIt.value());
498 handle.key() = priority;
499 sortedQueuesIt =
m_perAcInfo[ac].sortedQueues.insert(std::move(handle));
504 sortedQueuesIt =
m_perAcInfo[ac].sortedQueues.insert({priority, std::ref(*queueInfoIt)});
507 queueInfoIt->second.priorityIt = sortedQueuesIt;
510template <
class Priority,
class Compare>
515 const std::list<WifiQueueBlockedReason>& ignoredReasons)
518 std::list<uint8_t> linkIds;
521 for (
auto [linkId, mask] : queueInfoIt->second.linkIds)
524 for (
const auto reason : ignoredReasons)
526 mask.reset(
static_cast<std::size_t
>(reason));
531 linkIds.emplace_back(linkId);
538template <
class Priority,
class Compare>
544 const std::list<WifiContainerQueueType>& types,
547 const std::set<uint8_t>& tids,
548 const std::set<uint8_t>& linkIds)
550 std::stringstream ss;
553 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss,
" "));
555 NS_LOG_FUNCTION(
this << block << reason << ac << rxAddress << txAddress << ss.str());
556 std::list<WifiMacHeader> headers;
558 for (
const auto queueType : types)
570 "TID must be specified for queues containing QoS data frames");
571 for (
const auto tid : tids)
574 headers.back().SetQosTid(tid);
582 for (
auto& hdr : headers)
584 hdr.SetAddr1(rxAddress);
585 hdr.SetAddr2(txAddress);
588 for (
auto& [linkId, mask] : queueInfoIt->second.linkIds)
590 if (linkIds.empty() || linkIds.contains(linkId))
592 mask.set(
static_cast<std::size_t
>(reason), block);
598template <
class Priority,
class Compare>
603 const std::list<WifiContainerQueueType>& types,
606 const std::set<uint8_t>& tids,
607 const std::set<uint8_t>& linkIds)
609 DoBlockQueues(
true, reason, ac, types, rxAddress, txAddress, tids, linkIds);
612template <
class Priority,
class Compare>
617 const std::list<WifiContainerQueueType>& types,
620 const std::set<uint8_t>& tids,
621 const std::set<uint8_t>& linkIds)
623 DoBlockQueues(
false, reason, ac, types, rxAddress, txAddress, tids, linkIds);
626template <
class Priority,
class Compare>
631 const std::set<WifiRcvAddr>& addrTypes,
632 const std::set<uint8_t>& linkIds)
636 for (
const auto ac : acList)
638 for (
auto& [queueId, queueInfo] :
m_perAcInfo[ac].queueInfoMap)
640 if (addrTypes.empty() || addrTypes.contains(std::get<WifiRcvAddr>(queueId)))
642 for (
auto& [linkId, mask] : queueInfo.linkIds)
644 if (linkIds.empty() || linkIds.contains(linkId))
646 mask.set(
static_cast<std::size_t
>(reason), block);
654template <
class Priority,
class Compare>
657 const std::set<uint8_t>& linkIds,
658 const std::set<WifiRcvAddr>& addrTypes)
662 const auto rcvAddrTypes =
667 for (
const auto addrType : rcvAddrTypes)
669 const auto index =
static_cast<std::size_t
>(addrType);
681template <
class Priority,
class Compare>
685 const std::set<uint8_t>& linkIds,
686 const std::set<WifiRcvAddr>& addrTypes)
690 const auto rcvAddrTypes =
695 for (
const auto addrType : rcvAddrTypes)
697 auto& blockAllInfo =
m_blockAllInfo[
static_cast<std::size_t
>(addrType)];
698 auto infoIt = blockAllInfo.find(reason);
700 if (infoIt == blockAllInfo.end())
704 std::erase_if(infoIt->second,
705 [&](uint8_t
id) { return linkIds.empty() || linkIds.contains(id); });
707 if (infoIt->second.empty())
710 blockAllInfo.erase(infoIt);
715template <
class Priority,
class Compare>
722 const auto rcvAddrTypes =
725 : std::set{addrType});
728 rcvAddrTypes.cbegin(),
732 [=,
this](
const auto rcvAddrType) {
733 for (const auto& [r, linkIds] : m_blockAllInfo[static_cast<std::size_t>(rcvAddrType)])
735 if ((reason == WifiQueueBlockedReason::REASONS_COUNT || reason == r) &&
736 linkIds.contains(linkId))
745template <
class Priority,
class Compare>
746std::optional<WifiMacQueueScheduler::Mask>
753 const auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(queueId);
755 if (queueInfoIt ==
m_perAcInfo[ac].queueInfoMap.cend())
761 const auto& linkIds = queueInfoIt->second.linkIds;
762 if (
const auto linkIt = linkIds.find(linkId); linkIt != linkIds.cend())
764 return linkIt->second;
770template <
class Priority,
class Compare>
771std::optional<WifiContainerQueueId>
773 std::optional<uint8_t> linkId,
774 bool skipBlockedQueues)
776 NS_LOG_FUNCTION(
this << +ac << linkId.has_value() << skipBlockedQueues);
780template <
class Priority,
class Compare>
781std::optional<WifiContainerQueueId>
783 std::optional<uint8_t> linkId,
785 bool skipBlockedQueues)
787 NS_LOG_FUNCTION(
this << +ac << linkId.has_value() << skipBlockedQueues);
789 auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
791 !queueInfoIt->second.priorityIt.has_value());
793 auto sortedQueuesIt = queueInfoIt->second.priorityIt.value();
796 return DoGetNext(ac, linkId, ++sortedQueuesIt, skipBlockedQueues);
799template <
class Priority,
class Compare>
800std::optional<WifiContainerQueueId>
803 std::optional<uint8_t> linkId,
804 typename SortedQueues::iterator sortedQueuesIt,
805 bool skipBlockedQueues)
807 NS_LOG_FUNCTION(
this << +ac << linkId.has_value() << skipBlockedQueues);
810 while (sortedQueuesIt !=
m_perAcInfo[ac].sortedQueues.end())
812 const auto& queueInfoPair = sortedQueuesIt->second.get();
813 const auto& linkIds = queueInfoPair.second.linkIds;
814 typename std::decay_t<
decltype(linkIds)>::const_iterator linkIt;
816 if (!skipBlockedQueues ||
817 std::any_of(linkIds.cbegin(), linkIds.cend(), [&linkId](
const auto& linkIdMask) {
818 return (!linkId.has_value() || linkId == linkIdMask.first) &&
819 linkIdMask.second.none();
826 std::optional<typename SortedQueues::iterator> prevQueueIt;
827 if (sortedQueuesIt !=
m_perAcInfo[ac].sortedQueues.begin())
829 prevQueueIt = std::prev(sortedQueuesIt);
832 const auto queueId = queueInfoPair.first;
837 auto nextQueueIt = (prevQueueIt.has_value() ? std::next(prevQueueIt.value())
844 if (nextQueueIt !=
m_perAcInfo[ac].sortedQueues.end() &&
845 nextQueueIt->second.get().first == queueId)
847 sortedQueuesIt = std::next(nextQueueIt);
851 sortedQueuesIt = nextQueueIt;
855 return queueInfoPair.first;
863template <
class Priority,
class Compare>
871template <
class Priority,
class Compare>
883 if (!queueInfoIt->second.priorityIt.has_value())
886 "No info for the queue the MPDU was stored into (forgot to call SetPriority()?)");
890template <
class Priority,
class Compare>
900 std::list<WifiContainerQueueId> queueIds;
902 for (
const auto& mpdu : mpdus)
907 for (
const auto& queueId : queueIds)
913 auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(queueId);
915 if (queueInfoIt->second.priorityIt.has_value())
917 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
918 queueInfoIt->second.priorityIt.reset();
924template <
class Priority,
class Compare>
934 std::list<WifiContainerQueueId> queueIds;
936 for (
const auto& mpdu : mpdus)
941 for (
const auto& queueId : queueIds)
947 auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(queueId);
949 if (queueInfoIt->second.priorityIt.has_value())
951 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
952 queueInfoIt->second.priorityIt.reset();
Test DROP_OLDEST setting.
Test that a wifi MAC queue is correctly flushed even if (at least) a container queue is blocked.
Smart pointer class similar to boost::intrusive_ptr.
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.
This queue implements the timeout procedure described in (Section 9.19.2.6 "Retransmit procedures" pa...
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.
Ptr< WifiMac > GetMac() const
Get 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.
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 DoBlockAllQueues(bool block, WifiQueueBlockedReason reason, const std::set< WifiRcvAddr > &addrTypes, const std::set< uint8_t > &linkIds)
Block or unblock the given set of links for all the container queues of the given receiver address ty...
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
std::optional< WifiContainerQueueId > DoGetNext(AcIndex ac, std::optional< uint8_t > linkId, typename SortedQueues::iterator sortedQueuesIt, bool skipBlockedQueues)
Get the next queue to serve.
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
std::map< WifiQueueBlockedReason, std::set< uint8_t > > ReasonLinksMap
Map a given reason to the set of links to be (un)blocked for that reason.
void SetWifiMac(Ptr< WifiMac > mac) final
Set the wifi MAC.
bool GetAllQueuesBlockedOnLink(uint8_t linkId, WifiRcvAddr addrType, WifiQueueBlockedReason reason) final
void DoDispose() override
void BlockAllQueues(WifiQueueBlockedReason reason, const std::set< uint8_t > &linkIds, const std::set< WifiRcvAddr > &addrTypes) final
void NotifyDequeue(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
std::unordered_map< WifiContainerQueueId, QueueInfo > QueueInfoMap
Map identifiers (QueueIds) to information associated with container queues.
std::optional< WifiContainerQueueId > GetNext(AcIndex ac, std::optional< uint8_t > linkId, bool skipBlockedQueues=true) final
Get the next queue to serve, which is guaranteed to contain at least an MPDU whose lifetime has not e...
void NotifyEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) final
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 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
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.
std::array< ReasonLinksMap, static_cast< std::size_t >(WifiRcvAddr::COUNT)> m_blockAllInfo
When it is requested to block all the queues of given receiver address types, the reason and the IDs ...
static TypeId GetTypeId()
Get the type ID.
void UnblockAllQueues(WifiQueueBlockedReason reason, const std::set< uint8_t > &linkIds, const std::set< WifiRcvAddr > &addrTypes) final
std::vector< PerAcInfo > m_perAcInfo
vector of per-AC information
std::list< uint8_t > GetLinkIds(AcIndex ac, Ptr< const WifiMpdu > mpdu, const std::list< WifiQueueBlockedReason > &ignoredReasons) final
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
void NotifyRemove(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
virtual Ptr< WifiMpdu > HasToDropBeforeEnqueuePriv(AcIndex ac, Ptr< WifiMpdu > mpdu)=0
Check whether an MPDU has to be dropped before enqueuing the given MPDU.
WifiMacQueueSchedulerImpl()
Constructor.
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::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 FcfsPrio &priority)
WifiMpdu stores a (const) packet along with a MAC header.
#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 ",...
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
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.
const std::list< AcIndex > edcaAcIndices
List of the Access Categories corresponding to the four EDCA functions.
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...
WifiRcvAddr
enumeration of frame types based on receiver address
WifiContainerQueueType
enumeration of container queue types
std::tuple< WifiContainerQueueType, WifiRcvAddr, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
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