wifi: Queue scheduler uses per-destination mgt and control queues

This commit is contained in:
Stefano Avallone
2023-02-11 18:47:40 +01:00
parent 2a8ea316c4
commit 19454e862f
9 changed files with 141 additions and 141 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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));

View File

@@ -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() &&

View File

@@ -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];

View File

@@ -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

View File

@@ -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())

View File

@@ -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), [&]() {
/**