wifi: Queue scheduler uses per-destination mgt and control queues
This commit is contained in:
@@ -669,7 +669,10 @@ BlockAckManager::ScheduleBar(Ptr<WifiMpdu> bar)
|
||||
bar->GetPacket()->PeekHeader(reqHdr);
|
||||
uint8_t tid = reqHdr.GetTidInfo();
|
||||
|
||||
WifiContainerQueueId queueId(WIFI_CTL_QUEUE, bar->GetHeader().GetAddr2(), std::nullopt);
|
||||
WifiContainerQueueId queueId(WIFI_CTL_QUEUE,
|
||||
WIFI_UNICAST,
|
||||
bar->GetHeader().GetAddr1(),
|
||||
std::nullopt);
|
||||
Ptr<WifiMpdu> item = nullptr;
|
||||
|
||||
// if a BAR for the given agreement is present, replace it with the new one
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
#include "ht-frame-exchange-manager.h"
|
||||
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/ctrl-headers.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/mgt-headers.h"
|
||||
#include "ns3/qos-blocked-destinations.h"
|
||||
#include "ns3/recipient-block-ack-agreement.h"
|
||||
#include "ns3/snr-tag.h"
|
||||
#include "ns3/wifi-mac-queue.h"
|
||||
@@ -118,7 +120,7 @@ HtFrameExchangeManager::NeedSetupBlockAck(Mac48Address recipient, uint8_t tid)
|
||||
}
|
||||
else
|
||||
{
|
||||
WifiContainerQueueId queueId{WIFI_QOSDATA_UNICAST_QUEUE, recipient, tid};
|
||||
WifiContainerQueueId queueId{WIFI_QOSDATA_QUEUE, WIFI_UNICAST, recipient, tid};
|
||||
uint32_t packets = qosTxop->GetWifiMacQueue()->GetNPackets(queueId);
|
||||
establish =
|
||||
((qosTxop->GetBlockAckThreshold() > 0 && packets >= qosTxop->GetBlockAckThreshold()) ||
|
||||
@@ -417,110 +419,99 @@ HtFrameExchangeManager::GetBar(AcIndex ac,
|
||||
auto queue = m_mac->GetTxopQueue(ac);
|
||||
queue->WipeAllExpiredMpdus();
|
||||
|
||||
// in case of MLD, we need to check both the queue of control frames that need to be sent
|
||||
// on our link and the queue of control frames that can be sent on any link. We start with
|
||||
// the former, but we check the latter even if a suitable frame is found in the former
|
||||
// (because a BAR that can be sent on any link to a recipient is no longer needed after
|
||||
// sending a BAR to that recipient on our link).
|
||||
|
||||
std::list<WifiContainerQueueId> queueIds{{WIFI_CTL_QUEUE, m_self, std::nullopt}};
|
||||
if (m_self != m_mac->GetAddress())
|
||||
{
|
||||
// add the MLD address
|
||||
queueIds.emplace_back(WIFI_CTL_QUEUE, m_mac->GetAddress(), std::nullopt);
|
||||
}
|
||||
Ptr<WifiMpdu> bar;
|
||||
Ptr<WifiMpdu> prevBar;
|
||||
Ptr<WifiMpdu> selectedBar;
|
||||
uint8_t selectedTid = 0;
|
||||
|
||||
for (const auto& queueId : queueIds)
|
||||
// we could iterate over all the scheduler's queues and ignore those that do not contain
|
||||
// control frames, but it's more efficient to peek frames until we get frames that are
|
||||
// not control frames, given that control frames have the highest priority
|
||||
while ((bar = queue->PeekFirstAvailable(m_linkId, nullptr, prevBar)) && bar &&
|
||||
bar->GetHeader().IsCtl())
|
||||
{
|
||||
Ptr<WifiMpdu> bar;
|
||||
Ptr<WifiMpdu> prevBar;
|
||||
|
||||
while ((bar = queue->PeekByQueueId(queueId, prevBar)))
|
||||
if (bar->GetHeader().IsBlockAckReq())
|
||||
{
|
||||
if (bar->GetHeader().IsBlockAckReq())
|
||||
{
|
||||
CtrlBAckRequestHeader reqHdr;
|
||||
bar->GetPacket()->PeekHeader(reqHdr);
|
||||
auto tid = reqHdr.GetTidInfo();
|
||||
Mac48Address recipient = bar->GetHeader().GetAddr1();
|
||||
CtrlBAckRequestHeader reqHdr;
|
||||
bar->GetPacket()->PeekHeader(reqHdr);
|
||||
auto tid = reqHdr.GetTidInfo();
|
||||
Mac48Address recipient = bar->GetHeader().GetAddr1();
|
||||
auto recipientMld = m_mac->GetMldAddress(recipient);
|
||||
|
||||
if (selectedBar)
|
||||
// the scheduler should not return a BlockAckReq that cannot be sent on this link:
|
||||
// either the TA address is the address of this link or it is the MLD address and
|
||||
// the RA field is the MLD address of a device we can communicate with on this link
|
||||
NS_ASSERT_MSG(bar->GetHeader().GetAddr2() == m_self ||
|
||||
(bar->GetHeader().GetAddr2() == m_mac->GetAddress() && recipientMld &&
|
||||
GetWifiRemoteStationManager()->GetAffiliatedStaAddress(recipient)),
|
||||
"Cannot use link " << +m_linkId << " to send BAR: " << *bar);
|
||||
|
||||
if (optAddress &&
|
||||
(GetWifiRemoteStationManager()->GetMldAddress(*optAddress).value_or(*optAddress) !=
|
||||
GetWifiRemoteStationManager()->GetMldAddress(recipient).value_or(recipient) ||
|
||||
optTid != tid))
|
||||
{
|
||||
NS_LOG_DEBUG("BAR " << *bar
|
||||
<< " cannot be returned because it is not addressed"
|
||||
" to the given station for the given TID");
|
||||
prevBar = bar;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid);
|
||||
if (!agreement)
|
||||
{
|
||||
NS_LOG_DEBUG("BA agreement with " << recipient << " for TID=" << +tid
|
||||
<< " was torn down");
|
||||
queue->Remove(bar);
|
||||
continue;
|
||||
}
|
||||
// update BAR if the starting sequence number changed
|
||||
if (auto seqNo = agreement->get().GetStartingSequence();
|
||||
reqHdr.GetStartingSequence() != seqNo)
|
||||
{
|
||||
reqHdr.SetStartingSequence(seqNo);
|
||||
Ptr<Packet> packet = Create<Packet>();
|
||||
packet->AddHeader(reqHdr);
|
||||
auto updatedBar = Create<WifiMpdu>(packet, bar->GetHeader(), bar->GetTimestamp());
|
||||
queue->Replace(bar, updatedBar);
|
||||
bar = updatedBar;
|
||||
}
|
||||
// bar is the BlockAckReq to send
|
||||
selectedBar = bar;
|
||||
|
||||
// if the selected BAR is intended to be sent on this specific link and the recipient
|
||||
// is an MLD, remove the BAR (if any) for this BA agreement that can be sent on any
|
||||
// link (because a BAR that can be sent on any link to a recipient is no longer
|
||||
// needed after sending a BAR to that recipient on this link)
|
||||
if (bar->GetHeader().GetAddr2() == m_self && recipientMld)
|
||||
{
|
||||
WifiContainerQueueId queueId{WIFI_CTL_QUEUE,
|
||||
WIFI_UNICAST,
|
||||
*recipientMld,
|
||||
std::nullopt};
|
||||
Ptr<WifiMpdu> otherBar;
|
||||
while ((otherBar = queue->PeekByQueueId(queueId, otherBar)))
|
||||
{
|
||||
NS_ASSERT_MSG(std::get<Mac48Address>(queueId) != m_self,
|
||||
"We shall not keep iterating over the control frames that need"
|
||||
"to be sent on a specific link after selecting a BAR to send");
|
||||
// if this BlockAckReq is addressed to the same recipient as the selected BAR,
|
||||
// remove it from the queue and stop iterating over this queue; otherwise,
|
||||
// move on to the next frame in the queue
|
||||
if (GetWifiRemoteStationManager()->GetAffiliatedStaAddress(recipient) ==
|
||||
selectedBar->GetHeader().GetAddr1() &&
|
||||
selectedTid == tid)
|
||||
if (otherBar->GetHeader().IsBlockAckReq())
|
||||
{
|
||||
queue->Remove(bar);
|
||||
break;
|
||||
CtrlBAckRequestHeader otherReqHdr;
|
||||
otherBar->GetPacket()->PeekHeader(otherReqHdr);
|
||||
if (otherReqHdr.GetTidInfo() == tid)
|
||||
{
|
||||
queue->Remove(otherBar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
prevBar = bar;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if this BlockAckReq can be sent on any link, we have to check that this link
|
||||
// has been setup with the recipient (this may happen, e.g., if we are an AP MLD
|
||||
// and we have setup a subset of our links with a non-AP MLD)
|
||||
if (bar->GetHeader().GetAddr2() != m_self && m_mac->GetMldAddress(recipient) &&
|
||||
!GetWifiRemoteStationManager()->GetAffiliatedStaAddress(recipient))
|
||||
{
|
||||
prevBar = bar;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (optAddress &&
|
||||
(GetWifiRemoteStationManager()
|
||||
->GetMldAddress(*optAddress)
|
||||
.value_or(*optAddress) !=
|
||||
GetWifiRemoteStationManager()->GetMldAddress(recipient).value_or(
|
||||
recipient) ||
|
||||
optTid != tid))
|
||||
{
|
||||
NS_LOG_DEBUG("BAR " << *bar
|
||||
<< " cannot be returned because it is not addressed"
|
||||
" to the given station for the given TID");
|
||||
prevBar = bar;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto agreement = m_mac->GetBaAgreementEstablishedAsOriginator(recipient, tid);
|
||||
if (!agreement)
|
||||
{
|
||||
NS_LOG_DEBUG("BA agreement with " << recipient << " for TID=" << +tid
|
||||
<< " was torn down");
|
||||
queue->Remove(bar);
|
||||
continue;
|
||||
}
|
||||
// update BAR if the starting sequence number changed
|
||||
if (auto seqNo = agreement->get().GetStartingSequence();
|
||||
reqHdr.GetStartingSequence() != seqNo)
|
||||
{
|
||||
reqHdr.SetStartingSequence(seqNo);
|
||||
Ptr<Packet> packet = Create<Packet>();
|
||||
packet->AddHeader(reqHdr);
|
||||
auto updatedBar = Create<WifiMpdu>(packet, bar->GetHeader());
|
||||
queue->Replace(bar, updatedBar);
|
||||
bar = updatedBar;
|
||||
}
|
||||
// bar is the BlockAckReq to send
|
||||
selectedBar = bar;
|
||||
selectedTid = tid;
|
||||
break;
|
||||
}
|
||||
if (bar->GetHeader().IsTrigger() && !optAddress && !selectedBar)
|
||||
{
|
||||
return bar;
|
||||
}
|
||||
// not a BAR nor a Trigger Frame, continue
|
||||
prevBar = bar;
|
||||
break;
|
||||
}
|
||||
if (bar->GetHeader().IsTrigger() && !optAddress && !selectedBar)
|
||||
{
|
||||
return bar;
|
||||
}
|
||||
// not a BAR nor a Trigger Frame, continue
|
||||
prevBar = bar;
|
||||
}
|
||||
|
||||
if (!selectedBar)
|
||||
|
||||
@@ -153,7 +153,7 @@ QosTxop::GetLink(uint8_t linkId) const
|
||||
uint8_t
|
||||
QosTxop::GetQosQueueSize(uint8_t tid, Mac48Address receiver) const
|
||||
{
|
||||
WifiContainerQueueId queueId{WIFI_QOSDATA_UNICAST_QUEUE, receiver, tid};
|
||||
WifiContainerQueueId queueId{WIFI_QOSDATA_QUEUE, WIFI_UNICAST, receiver, tid};
|
||||
uint32_t bufferSize = m_queue->GetNBytes(queueId);
|
||||
// A queue size value of 254 is used for all sizes greater than 64 768 octets.
|
||||
uint8_t queueSize = static_cast<uint8_t>(std::ceil(std::min(bufferSize, 64769U) / 256.0));
|
||||
|
||||
@@ -157,7 +157,7 @@ WifiDefaultAckManager::IsResponseNeeded(Ptr<const WifiMpdu> mpdu,
|
||||
if (m_baThreshold > 0 &&
|
||||
GetMaxDistFromStartingSeq(mpdu, txParams) <
|
||||
m_baThreshold * edca->GetBaBufferSize(receiver, tid) &&
|
||||
(edca->GetWifiMacQueue()->GetNPackets({WIFI_QOSDATA_UNICAST_QUEUE, receiver, tid}) -
|
||||
(edca->GetWifiMacQueue()->GetNPackets({WIFI_QOSDATA_QUEUE, WIFI_UNICAST, receiver, tid}) -
|
||||
edca->GetBaManager()->GetNBufferedPackets(receiver, tid) >
|
||||
1) &&
|
||||
!(edca->GetTxopLimit(m_linkId).IsStrictlyPositive() &&
|
||||
|
||||
@@ -79,23 +79,22 @@ WifiMacQueueContainer::GetQueueId(Ptr<const WifiMpdu> mpdu)
|
||||
{
|
||||
const WifiMacHeader& hdr = mpdu->GetHeader();
|
||||
|
||||
auto addrType = hdr.GetAddr1().IsGroup() ? WIFI_BROADCAST : WIFI_UNICAST;
|
||||
auto address = hdr.GetAddr1().IsGroup() ? hdr.GetAddr2() : hdr.GetAddr1();
|
||||
|
||||
if (hdr.IsCtl())
|
||||
{
|
||||
return {WIFI_CTL_QUEUE, hdr.GetAddr2(), std::nullopt};
|
||||
return {WIFI_CTL_QUEUE, addrType, address, std::nullopt};
|
||||
}
|
||||
if (hdr.IsMgt())
|
||||
{
|
||||
return {WIFI_MGT_QUEUE, hdr.GetAddr2(), std::nullopt};
|
||||
return {WIFI_MGT_QUEUE, addrType, address, std::nullopt};
|
||||
}
|
||||
if (hdr.IsQosData())
|
||||
{
|
||||
if (hdr.GetAddr1().IsGroup())
|
||||
{
|
||||
return {WIFI_QOSDATA_BROADCAST_QUEUE, hdr.GetAddr2(), hdr.GetQosTid()};
|
||||
}
|
||||
return {WIFI_QOSDATA_UNICAST_QUEUE, hdr.GetAddr1(), hdr.GetQosTid()};
|
||||
return {WIFI_QOSDATA_QUEUE, addrType, address, hdr.GetQosTid()};
|
||||
}
|
||||
return {WIFI_DATA_QUEUE, hdr.GetAddr1(), std::nullopt};
|
||||
return {WIFI_DATA_QUEUE, addrType, address, std::nullopt};
|
||||
}
|
||||
|
||||
const WifiMacQueueContainer::ContainerQueue&
|
||||
@@ -207,7 +206,7 @@ WifiMacQueueContainer::GetAllExpiredMpdus() const
|
||||
std::size_t
|
||||
std::hash<ns3::WifiContainerQueueId>::operator()(ns3::WifiContainerQueueId queueId) const
|
||||
{
|
||||
auto [type, address, tid] = queueId;
|
||||
auto [type, addrType, address, tid] = queueId;
|
||||
const std::size_t size = tid.has_value() ? 8 : 7;
|
||||
|
||||
uint8_t buffer[size];
|
||||
|
||||
@@ -37,37 +37,46 @@ enum WifiContainerQueueType
|
||||
{
|
||||
WIFI_CTL_QUEUE = 0,
|
||||
WIFI_MGT_QUEUE = 1,
|
||||
WIFI_QOSDATA_UNICAST_QUEUE = 2,
|
||||
WIFI_QOSDATA_BROADCAST_QUEUE = 3,
|
||||
WIFI_DATA_QUEUE = 4
|
||||
WIFI_QOSDATA_QUEUE = 2,
|
||||
WIFI_DATA_QUEUE = 3
|
||||
};
|
||||
|
||||
/// enumeration of frame directions
|
||||
enum WifiReceiverAddressType : uint8_t
|
||||
{
|
||||
WIFI_UNICAST = 0,
|
||||
WIFI_BROADCAST
|
||||
};
|
||||
|
||||
/**
|
||||
* Tuple (queue type, Address, TID) identifying a container queue.
|
||||
* Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
|
||||
*
|
||||
* \note that Address has a different meaning depending on container queue type:
|
||||
* - if container queue type is WIFI_CTL_QUEUE, Address is the Transmitter Address
|
||||
* (TA) of the frames stored in the queue. We have distinct control queues
|
||||
* depending on TA to distinguish among control frames that need to be sent
|
||||
* over different links by 11be MLDs. MLD address as TA indicates that the frames
|
||||
* can be sent on any link. TID is ignored.
|
||||
* - if container queue type is WIFI_MGT_QUEUE, Address is the Transmitter Address
|
||||
* (TA) of the frames stored in the queue. We have distinct management queues
|
||||
* depending on TA to distinguish among management frames that need to be sent
|
||||
* over different links by 11be MLDs. TID is ignored.
|
||||
* - if container queue type is WIFI_QOSDATA_UNICAST_QUEUE, Address is the Receiver
|
||||
* Address (RA) of the frames stored in the queue.
|
||||
* - if container queue type is WIFI_QOSDATA_BROADCAST_QUEUE, Address is the
|
||||
* Transmitter Address (TA) of the frames stored in the queue. We have distinct
|
||||
* broadcast QoS queues depending on TA to distinguish among broadcast QoS Data
|
||||
* frames that need to be sent over different links by 11be MLDs.
|
||||
* - if container queue type is WIFI_DATA_QUEUE, Address is the Receiver Address
|
||||
* (RA) of the frames stored in the queue. We do not need to consider the
|
||||
* Transmitter Address (TA) because 11be stations are QoS stations and hence do
|
||||
* not send non-QoS Data frames. TID is ignored.
|
||||
*
|
||||
* - for container queue types holding unicast frames, Address is the Receiver Address (RA)
|
||||
* of the frames stored in the queue. For 11be MLDs, it is expected that:
|
||||
* + the RA of unicast management frames are link addresses (indicating the link on which
|
||||
* they must be sent)
|
||||
* + the RA of unicast QoS data frames are MLD addresses (indicating that they can be sent
|
||||
* on any link)
|
||||
* + if the RA of a unicast control frame is a link address, that control frame can only be
|
||||
* sent on the corresponding link; if the RA is an MLD address, that control frame can be
|
||||
* sent on any link
|
||||
*
|
||||
* - for container queue types holding broadcast frames, Address is the Transmitter Address (TA)
|
||||
* of the frames stored in the queue. For 11be MLDs, it is expected that:
|
||||
* + the TA of broadcast management frames are link addresses (indicating the link on which
|
||||
* they must be sent)
|
||||
* + the TA of broadcast QoS data frames are MLD addresses (indicating that they can be sent
|
||||
* on any link)
|
||||
* + if the TA of a broadcast control frame is a link address, that control frame can only be
|
||||
* sent on the corresponding link; if the TA is an MLD address, that control frame can be
|
||||
* sent on any link
|
||||
*
|
||||
* The TID is only specified for container queue types holding QoS data frames.
|
||||
*/
|
||||
using WifiContainerQueueId =
|
||||
std::tuple<WifiContainerQueueType, Mac48Address, std::optional<uint8_t>>;
|
||||
using WifiContainerQueueId = std::
|
||||
tuple<WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional<uint8_t>>;
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ WifiMacQueue::PeekByTidAndAddress(uint8_t tid, Mac48Address dest, Ptr<const Wifi
|
||||
{
|
||||
NS_LOG_FUNCTION(this << +tid << dest << item);
|
||||
NS_ABORT_IF(dest.IsGroup());
|
||||
WifiContainerQueueId queueId(WIFI_QOSDATA_UNICAST_QUEUE, dest, tid);
|
||||
WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, dest, tid);
|
||||
return PeekByQueueId(queueId, item);
|
||||
}
|
||||
|
||||
@@ -363,17 +363,15 @@ WifiMacQueue::PeekFirstAvailable(uint8_t linkId,
|
||||
queueId = m_scheduler->GetNext(m_ac, linkId);
|
||||
}
|
||||
|
||||
NS_ASSERT(!queueId || std::get<0>(*queueId) != WIFI_QOSDATA_UNICAST_QUEUE ||
|
||||
std::get<2>(*queueId));
|
||||
NS_ASSERT(!queueId || std::get<0>(*queueId) != WIFI_QOSDATA_QUEUE || std::get<3>(*queueId));
|
||||
|
||||
while (queueId.has_value() && blockedPackets &&
|
||||
std::get<0>(queueId.value()) == WIFI_QOSDATA_UNICAST_QUEUE &&
|
||||
blockedPackets->IsBlocked(std::get<1>(queueId.value()), *std::get<2>(queueId.value())))
|
||||
std::get<0>(queueId.value()) == WIFI_QOSDATA_QUEUE &&
|
||||
blockedPackets->IsBlocked(std::get<2>(queueId.value()), *std::get<3>(queueId.value())))
|
||||
{
|
||||
queueId = m_scheduler->GetNext(m_ac, linkId, queueId.value());
|
||||
|
||||
NS_ASSERT(!queueId || std::get<0>(*queueId) != WIFI_QOSDATA_UNICAST_QUEUE ||
|
||||
std::get<2>(*queueId));
|
||||
NS_ASSERT(!queueId || std::get<0>(*queueId) != WIFI_QOSDATA_QUEUE || std::get<3>(*queueId));
|
||||
}
|
||||
|
||||
if (!queueId.has_value())
|
||||
|
||||
@@ -225,8 +225,8 @@ WifiExtractExpiredMpdusTest::DoRun()
|
||||
Enqueue(rxAddr2, false, MilliSeconds(70));
|
||||
Enqueue(rxAddr2, false, MilliSeconds(75));
|
||||
|
||||
WifiContainerQueueId queueId1{WIFI_QOSDATA_UNICAST_QUEUE, rxAddr1, 0};
|
||||
WifiContainerQueueId queueId2{WIFI_QOSDATA_UNICAST_QUEUE, rxAddr2, 0};
|
||||
WifiContainerQueueId queueId1{WIFI_QOSDATA_QUEUE, WIFI_UNICAST, rxAddr1, 0};
|
||||
WifiContainerQueueId queueId2{WIFI_QOSDATA_QUEUE, WIFI_UNICAST, rxAddr2, 0};
|
||||
|
||||
Simulator::Schedule(MilliSeconds(25), [&]() {
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user