9#ifndef WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
10#define WIFI_MAC_QUEUE_SCHEDULER_IMPL_H
25#include <unordered_map>
77template <
class Priority,
class Compare = std::less<Priority>>
82 friend class ::WifiMacQueueDropOldestTest;
83 friend class ::WifiMacQueueFlushTest;
109 std::optional<uint8_t> linkId,
110 bool skipBlockedQueues =
true) final;
116 std::optional<uint8_t> linkId,
118 bool skipBlockedQueues = true) final;
129 const
std::set<uint8_t>& tids,
130 const
std::set<uint8_t>& linkIds) final;
137 const
std::set<uint8_t>& tids,
138 const
std::set<uint8_t>& linkIds) final;
141 const
std::set<uint8_t>& linkIds,
145 const
std::set<uint8_t>& linkIds,
154 uint8_t linkId) final;
206 std::optional<typename SortedQueues::iterator>
272 std::optional<uint8_t> linkId,
273 typename SortedQueues::iterator sortedQueuesIt,
274 bool skipBlockedQueues);
321 const std::list<WifiContainerQueueType>& types,
324 const std::set<uint8_t>& tids,
325 const std::set<uint8_t>& linkIds);
338 const std::set<WifiRcvAddr>& addrTypes,
339 const std::set<uint8_t>& linkIds);
368 return std::weak_ordering::less;
372 return std::weak_ordering::greater;
377 return std::weak_ordering::less;
381 return std::weak_ordering::greater;
388template <
class Priority,
class Compare>
394template <
class Priority,
class Compare>
401 .SetGroupName(
"Wifi")
402 .AddAttribute(
"DropPolicy",
403 "Upon enqueue with full queue, drop oldest (DropOldest) "
404 "or newest (DropNewest) packet",
412template <
class Priority,
class Compare>
420template <
class Priority,
class Compare>
426 if (
auto queue = mac->GetTxopQueue(ac); queue !=
nullptr)
434template <
class Priority,
class Compare>
444template <
class Priority,
class Compare>
452template <
class Priority,
class Compare>
460template <
class Priority,
class Compare>
461typename WifiMacQueueSchedulerImpl<Priority, Compare>::QueueInfoMap::iterator
472 mpdu->GetHeader().GetAddr2() ==
GetMac()->GetAddress())
476 const auto rxAddr = mpdu->GetHeader().GetAddr1();
481 "Address 1 (" << rxAddr <<
") is not an MLD address");
486 "Cannot forward frame to " << rxAddr
487 <<
"; check that the receiver is associated");
492 if (rxAddr.IsGroup() ||
493 GetMac()->GetWifiRemoteStationManager(linkId)->GetAffiliatedStaAddress(rxAddr))
496 auto [it, inserted] = queueInfoIt->second.linkIds.try_emplace(linkId);
501 for (
const auto& [reason, linkIds] :
504 if (linkIds.contains(linkId))
506 it->second.set(
static_cast<std::size_t
>(reason),
true);
514 queueInfoIt->second.linkIds.erase(linkId);
522 auto linkId =
GetMac() ?
GetMac()->GetLinkIdByAddress(mpdu->GetHeader().GetAddr2())
525 auto& linkIdsMap = queueInfoIt->second.linkIds;
527 "At most one link can be associated with this container queue");
531 if (linkIdsMap.empty() || linkIdsMap.cbegin()->first != *linkId)
534 for (
const auto& [reason, linkIds] :
537 if (linkIds.contains(*linkId))
539 mask.set(
static_cast<std::size_t
>(reason),
true);
543 linkIdsMap = {{*linkId, mask}};
550template <
class Priority,
class Compare>
554 const Priority& priority)
560 "Cannot set the priority of an empty queue");
562 auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(queueId);
564 "No queue info for the given container queue");
565 typename SortedQueues::iterator sortedQueuesIt;
567 if (queueInfoIt->second.priorityIt.has_value())
572 if (queueInfoIt->second.priorityIt.value()->first == priority)
577 auto handle =
m_perAcInfo[ac].sortedQueues.extract(queueInfoIt->second.priorityIt.value());
578 handle.key() = priority;
579 sortedQueuesIt =
m_perAcInfo[ac].sortedQueues.insert(std::move(handle));
584 sortedQueuesIt =
m_perAcInfo[ac].sortedQueues.insert({priority, std::ref(*queueInfoIt)});
587 queueInfoIt->second.priorityIt = sortedQueuesIt;
590template <
class Priority,
class Compare>
595 const std::list<WifiQueueBlockedReason>& ignoredReasons)
598 std::list<uint8_t> linkIds;
601 for (
auto [linkId, mask] : queueInfoIt->second.linkIds)
604 for (
const auto reason : ignoredReasons)
606 mask.reset(
static_cast<std::size_t
>(reason));
611 linkIds.emplace_back(linkId);
618template <
class Priority,
class Compare>
624 const std::list<WifiContainerQueueType>& types,
627 const std::set<uint8_t>& tids,
628 const std::set<uint8_t>& linkIds)
630 std::stringstream ss;
633 std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss,
" "));
635 NS_LOG_FUNCTION(
this << block << reason << ac << rxAddress << txAddress << ss.str());
636 std::list<WifiMacHeader> headers;
638 for (
const auto queueType : types)
650 "TID must be specified for queues containing QoS data frames");
651 for (
const auto tid : tids)
654 headers.back().SetQosTid(tid);
662 for (
auto& hdr : headers)
664 hdr.SetAddr1(rxAddress);
665 hdr.SetAddr2(txAddress);
668 for (
auto& [linkId, mask] : queueInfoIt->second.linkIds)
670 if (linkIds.empty() || linkIds.contains(linkId))
672 mask.set(
static_cast<std::size_t
>(reason), block);
678template <
class Priority,
class Compare>
683 const std::list<WifiContainerQueueType>& types,
686 const std::set<uint8_t>& tids,
687 const std::set<uint8_t>& linkIds)
689 DoBlockQueues(
true, reason, ac, types, rxAddress, txAddress, tids, linkIds);
692template <
class Priority,
class Compare>
697 const std::list<WifiContainerQueueType>& types,
700 const std::set<uint8_t>& tids,
701 const std::set<uint8_t>& linkIds)
703 DoBlockQueues(
false, reason, ac, types, rxAddress, txAddress, tids, linkIds);
706template <
class Priority,
class Compare>
711 const std::set<WifiRcvAddr>& addrTypes,
712 const std::set<uint8_t>& linkIds)
716 for (
const auto ac : acList)
718 for (
auto& [queueId, queueInfo] :
m_perAcInfo[ac].queueInfoMap)
720 if (addrTypes.empty() || addrTypes.contains(queueId.addrType))
722 for (
auto& [linkId, mask] : queueInfo.linkIds)
724 if (linkIds.empty() || linkIds.contains(linkId))
726 mask.set(
static_cast<std::size_t
>(reason), block);
734template <
class Priority,
class Compare>
737 const std::set<uint8_t>& linkIds,
738 const std::set<WifiRcvAddr>& addrTypes)
742 const auto rcvAddrTypes =
747 for (
const auto addrType : rcvAddrTypes)
749 const auto index =
static_cast<std::size_t
>(addrType);
761template <
class Priority,
class Compare>
765 const std::set<uint8_t>& linkIds,
766 const std::set<WifiRcvAddr>& addrTypes)
770 const auto rcvAddrTypes =
775 for (
const auto addrType : rcvAddrTypes)
777 auto& blockAllInfo =
m_blockAllInfo[
static_cast<std::size_t
>(addrType)];
778 auto infoIt = blockAllInfo.find(reason);
780 if (infoIt == blockAllInfo.end())
784 std::erase_if(infoIt->second,
785 [&](uint8_t
id) { return linkIds.empty() || linkIds.contains(id); });
787 if (infoIt->second.empty())
790 blockAllInfo.erase(infoIt);
795template <
class Priority,
class Compare>
802 const auto rcvAddrTypes =
805 : std::set{addrType});
808 rcvAddrTypes.cbegin(),
812 [=,
this](
const auto rcvAddrType) {
813 for (const auto& [r, linkIds] : m_blockAllInfo[static_cast<std::size_t>(rcvAddrType)])
815 if ((reason == WifiQueueBlockedReason::REASONS_COUNT || reason == r) &&
816 linkIds.contains(linkId))
825template <
class Priority,
class Compare>
826std::optional<WifiMacQueueScheduler::Mask>
833 const auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(queueId);
835 if (queueInfoIt ==
m_perAcInfo[ac].queueInfoMap.cend())
841 const auto& linkIds = queueInfoIt->second.linkIds;
842 if (
const auto linkIt = linkIds.find(linkId); linkIt != linkIds.cend())
844 return linkIt->second;
850template <
class Priority,
class Compare>
851std::optional<WifiContainerQueueId>
853 std::optional<uint8_t> linkId,
854 bool skipBlockedQueues)
856 NS_LOG_FUNCTION(
this << ac << linkId.has_value() << skipBlockedQueues);
860template <
class Priority,
class Compare>
861std::optional<WifiContainerQueueId>
863 std::optional<uint8_t> linkId,
865 bool skipBlockedQueues)
867 NS_LOG_FUNCTION(
this << ac << linkId.has_value() << skipBlockedQueues);
869 auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(prevQueueId);
871 !queueInfoIt->second.priorityIt.has_value());
873 auto sortedQueuesIt = queueInfoIt->second.priorityIt.value();
876 return DoGetNext(ac, linkId, ++sortedQueuesIt, skipBlockedQueues);
879template <
class Priority,
class Compare>
880std::optional<WifiContainerQueueId>
883 std::optional<uint8_t> linkId,
884 typename SortedQueues::iterator sortedQueuesIt,
885 bool skipBlockedQueues)
887 NS_LOG_FUNCTION(
this << ac << linkId.has_value() << skipBlockedQueues);
890 while (sortedQueuesIt !=
m_perAcInfo[ac].sortedQueues.end())
892 const auto& queueInfoPair = sortedQueuesIt->second.get();
893 const auto& linkIds = queueInfoPair.second.linkIds;
894 typename std::decay_t<
decltype(linkIds)>::const_iterator linkIt;
896 if (!skipBlockedQueues ||
897 std::any_of(linkIds.cbegin(), linkIds.cend(), [&linkId](
const auto& linkIdMask) {
898 return (!linkId.has_value() || linkId == linkIdMask.first) &&
899 linkIdMask.second.none();
906 std::optional<typename SortedQueues::iterator> prevQueueIt;
907 if (sortedQueuesIt !=
m_perAcInfo[ac].sortedQueues.begin())
909 prevQueueIt = std::prev(sortedQueuesIt);
912 const auto queueId = queueInfoPair.first;
917 auto nextQueueIt = (prevQueueIt.has_value() ? std::next(prevQueueIt.value())
924 if (nextQueueIt !=
m_perAcInfo[ac].sortedQueues.end() &&
925 nextQueueIt->second.get().first == queueId)
927 sortedQueuesIt = std::next(nextQueueIt);
931 sortedQueuesIt = nextQueueIt;
935 return queueInfoPair.first;
943template <
class Priority,
class Compare>
949 if (queue->QueueBase::GetNPackets() < queue->GetMaxSize().GetValue())
969 while ((item = queue->PeekByQueueId(queueInfo.get().first, item)))
971 if (!item->IsInFlight() && !item->GetHeader().IsRetry())
983template <
class Priority,
class Compare>
995 if (!queueInfoIt->second.priorityIt.has_value())
998 "No info for the queue the MPDU was stored into (forgot to call SetPriority()?)");
1002template <
class Priority,
class Compare>
1012 std::list<WifiContainerQueueId> queueIds;
1014 for (
const auto& mpdu : mpdus)
1019 for (
const auto& queueId : queueIds)
1025 auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(queueId);
1027 if (queueInfoIt->second.priorityIt.has_value())
1029 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
1030 queueInfoIt->second.priorityIt.reset();
1036template <
class Priority,
class Compare>
1046 std::list<WifiContainerQueueId> queueIds;
1048 for (
const auto& mpdu : mpdus)
1053 for (
const auto& queueId : queueIds)
1059 auto queueInfoIt =
m_perAcInfo[ac].queueInfoMap.find(queueId);
1061 if (queueInfoIt->second.priorityIt.has_value())
1063 m_perAcInfo[ac].sortedQueues.erase(queueInfoIt->second.priorityIt.value());
1064 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.
Hold variables of type enum.
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.
virtual void SetWifiMacQueue(AcIndex ac, Ptr< WifiMacQueue > queue)
Set the Wifi MAC queue associated with the given Access Category.
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.
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
DropPolicy m_dropPolicy
Drop behavior of queue.
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 ...
Ptr< WifiMpdu > HasToDropBeforeEnqueue(AcIndex ac, Ptr< WifiMpdu > mpdu) override
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.
void NotifyRemove(AcIndex ac, const std::list< Ptr< WifiMpdu > > &mpdus) final
WifiMacQueueSchedulerImpl()
Constructor.
void SetWifiMac(Ptr< WifiMac > mac) override
Set the wifi MAC.
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...
void SetWifiMacQueue(AcIndex ac, Ptr< WifiMacQueue > queue) override
Set the Wifi MAC queue associated with the given Access Category.
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 WifiSchedPrecedence< Time > &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_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#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.
std::string GetTemplateClassName()
Helper function to get the name (as a string) of the type of a template class.
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
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
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Structure identifying a container queue.
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
Definition of priority for container queues that can be specialized by subclasses by providing the ty...
std::weak_ordering operator<=>(const WifiSchedPrecedence< Prio > &other) const
Spaceship comparison operator.
WifiContainerQueueType type
bool operator==(const WifiSchedPrecedence< Prio > &) const =default
Equality operator, needed because equality testing never invokes the spaceship operator and the space...