wifi: BlockAckManager returns a const reference to Originator BA agreements

This is a cleanup of the API in preparation for moving Recipient BA
agreements to the BlockAckManager.
This commit is contained in:
Stefano Avallone
2022-10-19 14:48:51 +02:00
committed by Stefano Avallone
parent 7b5cb3b3e4
commit c8ad2f4d45
4 changed files with 126 additions and 200 deletions

View File

@@ -92,39 +92,16 @@ BlockAckManager::SetBlockAckManagerMap(const std::map<AcIndex, Ptr<BlockAckManag
m_bamMap = bamMap;
}
bool
BlockAckManager::ExistsAgreement(Mac48Address recipient, uint8_t tid) const
BlockAckManager::OriginatorAgreementOptConstRef
BlockAckManager::GetAgreementAsOriginator(Mac48Address recipient, uint8_t tid) const
{
NS_LOG_FUNCTION(this << recipient << +tid);
return (m_agreements.find(std::make_pair(recipient, tid)) != m_agreements.end());
}
bool
BlockAckManager::ExistsAgreementInState(Mac48Address recipient,
uint8_t tid,
OriginatorBlockAckAgreement::State state) const
{
AgreementsCI it;
it = m_agreements.find(std::make_pair(recipient, tid));
if (it != m_agreements.end())
if (auto it = m_agreements.find({recipient, tid}); it != m_agreements.end())
{
switch (state)
{
case OriginatorBlockAckAgreement::ESTABLISHED:
return it->second.first.IsEstablished();
case OriginatorBlockAckAgreement::PENDING:
return it->second.first.IsPending();
case OriginatorBlockAckAgreement::REJECTED:
return it->second.first.IsRejected();
case OriginatorBlockAckAgreement::NO_REPLY:
return it->second.first.IsNoReply();
case OriginatorBlockAckAgreement::RESET:
return it->second.first.IsReset();
default:
NS_FATAL_ERROR("Invalid state for block ack agreement");
}
return std::cref(it->second.first);
}
return false;
return std::nullopt;
}
void
@@ -133,8 +110,8 @@ BlockAckManager::CreateAgreement(const MgtAddBaRequestHeader* reqHdr,
bool htSupported)
{
NS_LOG_FUNCTION(this << reqHdr << recipient << htSupported);
std::pair<Mac48Address, uint8_t> key(recipient, reqHdr->GetTid());
OriginatorBlockAckAgreement agreement(recipient, reqHdr->GetTid());
const uint8_t tid = reqHdr->GetTid();
OriginatorBlockAckAgreement agreement(recipient, tid);
agreement.SetStartingSequence(reqHdr->GetStartingSequence());
/* For now we assume that originator doesn't use this field. Use of this field
is mandatory only for recipient */
@@ -150,19 +127,16 @@ BlockAckManager::CreateAgreement(const MgtAddBaRequestHeader* reqHdr,
{
agreement.SetDelayedBlockAck();
}
uint8_t tid = reqHdr->GetTid();
m_agreementState(Simulator::Now(), recipient, tid, OriginatorBlockAckAgreement::PENDING);
agreement.SetState(OriginatorBlockAckAgreement::PENDING);
PacketQueue queue;
std::pair<OriginatorBlockAckAgreement, PacketQueue> value(agreement, queue);
if (ExistsAgreement(recipient, tid))
m_agreementState(Simulator::Now(), recipient, tid, OriginatorBlockAckAgreement::PENDING);
if (auto existingAgreement = GetAgreementAsOriginator(recipient, tid))
{
// Delete agreement if it exists and in RESET state
NS_ASSERT(ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::RESET));
m_agreements.erase(key);
NS_ASSERT_MSG(existingAgreement->get().IsReset(),
"Existing agreement must be in RESET state");
}
m_agreements.insert(std::make_pair(key, value));
m_blockPackets(recipient, reqHdr->GetTid());
m_agreements.insert_or_assign({recipient, tid},
std::make_pair(std::move(agreement), PacketQueue{}));
m_blockPackets(recipient, tid);
}
void
@@ -436,10 +410,10 @@ BlockAckManager::NotifyGotAck(uint8_t linkId, Ptr<const WifiMpdu> mpdu)
Mac48Address recipient = mpdu->GetHeader().GetAddr1();
uint8_t tid = mpdu->GetHeader().GetQosTid();
NS_ASSERT(ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED));
AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
AgreementsI it = m_agreements.find({recipient, tid});
NS_ASSERT(it != m_agreements.end());
NS_ASSERT(it->second.first.IsEstablished());
it->second.first.NotifyAckedMpdu(mpdu);
@@ -463,10 +437,10 @@ BlockAckManager::NotifyMissedAck(uint8_t linkId, Ptr<WifiMpdu> mpdu)
Mac48Address recipient = mpdu->GetHeader().GetAddr1();
uint8_t tid = mpdu->GetHeader().GetQosTid();
NS_ASSERT(ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED));
AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
NS_ASSERT(it != m_agreements.end());
NS_ASSERT(it->second.first.IsEstablished());
// remove the frame from the queue of outstanding packets (it will be re-inserted
// if retransmitted)
@@ -488,8 +462,6 @@ BlockAckManager::NotifyGotBlockAck(uint8_t linkId,
size_t index)
{
NS_LOG_FUNCTION(this << linkId << blockAck << recipient << index);
uint16_t nSuccessfulMpdus = 0;
uint16_t nFailedMpdus = 0;
NS_ABORT_MSG_IF(blockAck.IsBasic(), "Basic Block Ack is not supported");
NS_ABORT_MSG_IF(blockAck.IsMultiTid(), "Multi-TID Block Ack is not supported");
@@ -502,65 +474,66 @@ BlockAckManager::NotifyGotBlockAck(uint8_t linkId,
NS_ASSERT(blockAck.GetAckType(index) && tids.size() == 1);
tid = *tids.begin();
}
if (ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
AgreementsI it = m_agreements.find({recipient, tid});
if (it == m_agreements.end() || !it->second.first.IsEstablished())
{
AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
return {0, 0};
}
if (it->second.first.m_inactivityEvent.IsRunning())
uint16_t nSuccessfulMpdus = 0;
uint16_t nFailedMpdus = 0;
if (it->second.first.m_inactivityEvent.IsRunning())
{
/* Upon reception of a BlockAck frame, the inactivity timer at the
originator must be reset.
For more details see section 11.5.3 in IEEE802.11e standard */
it->second.first.m_inactivityEvent.Cancel();
Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
it->second.first.m_inactivityEvent =
Simulator::Schedule(timeout, &BlockAckManager::InactivityTimeout, this, recipient, tid);
}
NS_ASSERT(blockAck.IsCompressed() || blockAck.IsExtendedCompressed() || blockAck.IsMultiSta());
Time now = Simulator::Now();
std::list<Ptr<const WifiMpdu>> acked;
for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
{
uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
NS_LOG_DEBUG("Current seq=" << currentSeq);
if (blockAck.IsPacketReceived(currentSeq, index))
{
/* Upon reception of a BlockAck frame, the inactivity timer at the
originator must be reset.
For more details see section 11.5.3 in IEEE802.11e standard */
it->second.first.m_inactivityEvent.Cancel();
Time timeout = MicroSeconds(1024 * it->second.first.GetTimeout());
it->second.first.m_inactivityEvent =
Simulator::Schedule(timeout,
&BlockAckManager::InactivityTimeout,
this,
recipient,
tid);
it->second.first.NotifyAckedMpdu(*queueIt);
nSuccessfulMpdus++;
if (!m_txOkCallback.IsNull())
{
m_txOkCallback(*queueIt);
}
acked.emplace_back(*queueIt);
queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now);
}
NS_ASSERT(blockAck.IsCompressed() || blockAck.IsExtendedCompressed() ||
blockAck.IsMultiSta());
Time now = Simulator::Now();
std::list<Ptr<const WifiMpdu>> acked;
for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
else
{
uint16_t currentSeq = (*queueIt)->GetHeader().GetSequenceNumber();
NS_LOG_DEBUG("Current seq=" << currentSeq);
if (blockAck.IsPacketReceived(currentSeq, index))
{
it->second.first.NotifyAckedMpdu(*queueIt);
nSuccessfulMpdus++;
if (!m_txOkCallback.IsNull())
{
m_txOkCallback(*queueIt);
}
acked.emplace_back(*queueIt);
queueIt = HandleInFlightMpdu(linkId, queueIt, ACKNOWLEDGED, it, now);
}
else
{
++queueIt;
}
}
// Dequeue all acknowledged MPDUs at once
m_queue->DequeueIfQueued(acked);
// Remaining outstanding MPDUs have not been acknowledged
for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
{
nFailedMpdus++;
if (!m_txFailedCallback.IsNull())
{
m_txFailedCallback(*queueIt);
}
queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now);
++queueIt;
}
}
// Dequeue all acknowledged MPDUs at once
m_queue->DequeueIfQueued(acked);
// Remaining outstanding MPDUs have not been acknowledged
for (auto queueIt = it->second.second.begin(); queueIt != it->second.second.end();)
{
nFailedMpdus++;
if (!m_txFailedCallback.IsNull())
{
m_txFailedCallback(*queueIt);
}
queueIt = HandleInFlightMpdu(linkId, queueIt, TO_RETRANSMIT, it, now);
}
return {nSuccessfulMpdus, nFailedMpdus};
}
@@ -568,17 +541,20 @@ void
BlockAckManager::NotifyMissedBlockAck(uint8_t linkId, Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION(this << linkId << recipient << +tid);
if (ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
{
AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
Time now = Simulator::Now();
// remove all packets from the queue of outstanding packets (they will be
// re-inserted if retransmitted)
for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
{
mpduIt = HandleInFlightMpdu(linkId, mpduIt, TO_RETRANSMIT, it, now);
}
auto it = m_agreements.find({recipient, tid});
if (it == m_agreements.end() || !it->second.first.IsEstablished())
{
return;
}
Time now = Simulator::Now();
// remove all packets from the queue of outstanding packets (they will be
// re-inserted if retransmitted)
for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
{
mpduIt = HandleInFlightMpdu(linkId, mpduIt, TO_RETRANSMIT, it, now);
}
}
@@ -601,13 +577,13 @@ BlockAckManager::NotifyDiscardedMpdu(Ptr<const WifiMpdu> mpdu)
Mac48Address recipient = mpdu->GetHeader().GetAddr1();
uint8_t tid = mpdu->GetHeader().GetQosTid();
if (!ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
AgreementsI it = m_agreements.find({recipient, tid});
if (it == m_agreements.end() || !it->second.first.IsEstablished())
{
NS_LOG_DEBUG("No established Block Ack agreement");
return;
}
AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
uint16_t currStartingSeq = it->second.first.GetStartingSequence();
if (QosUtilsIsOldPacket(currStartingSeq, mpdu->GetHeader().GetSequenceNumber()))
{
@@ -795,50 +771,31 @@ BlockAckManager::SetQueue(const Ptr<WifiMacQueue> queue)
}
bool
BlockAckManager::SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq)
BlockAckManager::NeedBarRetransmission(uint8_t tid, Mac48Address recipient)
{
NS_LOG_FUNCTION(this << recipient << +tid << startingSeq);
NS_ASSERT(!ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::PENDING));
if (!ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::REJECTED) &&
ExistsAgreement(recipient, tid))
AgreementsI it = m_agreements.find({recipient, tid});
if (it == m_agreements.end() || !it->second.first.IsEstablished())
{
WifiContainerQueueId queueId{WIFI_QOSDATA_UNICAST_QUEUE, recipient, tid};
uint32_t packets = m_queue->GetNPackets(queueId) + GetNBufferedPackets(recipient, tid);
if (packets >= m_blockAckThreshold)
// If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
// has destroyed the agreement, hence we get here and correctly return false
return false;
}
Time now = Simulator::Now();
// A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
{
// remove MPDU if old or with expired lifetime
mpduIt = HandleInFlightMpdu(SINGLE_LINK_OP_ID, mpduIt, STAY_INFLIGHT, it, now);
if (mpduIt != it->second.second.begin())
{
NotifyAgreementEstablished(recipient, tid, startingSeq);
// the MPDU has not been removed
return true;
}
}
return false;
}
bool
BlockAckManager::NeedBarRetransmission(uint8_t tid, Mac48Address recipient)
{
if (ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::ESTABLISHED))
{
AgreementsI it = m_agreements.find(std::make_pair(recipient, tid));
NS_ASSERT(it != m_agreements.end());
Time now = Simulator::Now();
// A BAR needs to be retransmitted if there is at least a non-expired in flight MPDU
for (auto mpduIt = it->second.second.begin(); mpduIt != it->second.second.end();)
{
// remove MPDU if old or with expired lifetime
mpduIt = HandleInFlightMpdu(SINGLE_LINK_OP_ID, mpduIt, STAY_INFLIGHT, it, now);
if (mpduIt != it->second.second.begin())
{
// the MPDU has not been removed
return true;
}
}
}
// If the inactivity timer has expired, QosTxop::SendDelbaFrame has been called and
// has destroyed the agreement, hence we get here and correctly return false
return false;
}

View File

@@ -40,8 +40,6 @@ class MgtAddBaRequestHeader;
class CtrlBAckResponseHeader;
class CtrlBAckRequestHeader;
class WifiMacQueue;
class WifiMode;
class Packet;
/**
* \ingroup wifi
@@ -101,29 +99,21 @@ class BlockAckManager : public Object
* \param bamMap an AC-indexed map of all the Block Ack Managers installed on this device
*/
void SetBlockAckManagerMap(const std::map<AcIndex, Ptr<BlockAckManager>>& bamMap);
/// optional const reference to OriginatorBlockAckAgreement
using OriginatorAgreementOptConstRef =
std::optional<std::reference_wrapper<const OriginatorBlockAckAgreement>>;
/**
* \param recipient Address of peer station involved in block ack mechanism.
* \param tid Traffic ID.
* \param recipient MAC address of the recipient
* \param tid Traffic ID
*
* \return true if a block ack agreement exists, false otherwise
* \return a const reference to the block ack agreement with the given recipient, if it exists
*
* Checks if a block ack agreement exists with station addressed by
* <i>recipient</i> for TID <i>tid</i>.
* Check if we are the originator of an existing block ack agreement with the given recipient.
*/
bool ExistsAgreement(Mac48Address recipient, uint8_t tid) const;
/**
* \param recipient Address of peer station involved in block ack mechanism.
* \param tid Traffic ID.
* \param state The state for block ack agreement
*
* \return true if a block ack agreement exists, false otherwise
*
* Checks if a block ack agreement with a state equals to <i>state</i> exists with
* station addressed by <i>recipient</i> for TID <i>tid</i>.
*/
bool ExistsAgreementInState(Mac48Address recipient,
uint8_t tid,
OriginatorBlockAckAgreement::State state) const;
OriginatorAgreementOptConstRef GetAgreementAsOriginator(Mac48Address recipient,
uint8_t tid) const;
/**
* \param reqHdr Relative Add block ack request (action frame).
* \param recipient Address of peer station involved in block ack mechanism.
@@ -302,20 +292,6 @@ class BlockAckManager : public Object
*/
void SetUnblockDestinationCallback(Callback<void, Mac48Address, uint8_t> callback);
/**
* \param recipient the destination address
* \param tid the Traffic ID
* \param startingSeq the starting sequence number
*
* \return true if there are packets in the queue that could be sent under block ack,
* false otherwise
*
* Checks if there are in the queue other packets that could be send under block ack.
* If yes adds these packets in current block ack exchange.
* However, number of packets exchanged in the current block ack, will not exceed
* the value of BufferSize in the corresponding OriginatorBlockAckAgreement object.
*/
bool SwitchToBlockAckIfNeeded(Mac48Address recipient, uint8_t tid, uint16_t startingSeq);
/**
* This function returns true if a block ack agreement is established with the
* given recipient for the given TID and there is at least an outstanding MPDU

View File

@@ -113,10 +113,8 @@ HtFrameExchangeManager::NeedSetupBlockAck(Mac48Address recipient, uint8_t tid)
{
establish = false;
}
else if (qosTxop->GetBaManager()->ExistsAgreement(recipient, tid) &&
!qosTxop->GetBaManager()->ExistsAgreementInState(recipient,
tid,
OriginatorBlockAckAgreement::RESET))
else if (auto agreement = qosTxop->GetBaManager()->GetAgreementAsOriginator(recipient, tid);
agreement && !agreement->get().IsReset())
{
establish = false;
}
@@ -700,9 +698,8 @@ HtFrameExchangeManager::NotifyPacketDiscarded(Ptr<const WifiMpdu> mpdu)
{
recipient = *mldAddr;
}
if (GetBaManager(tid)->ExistsAgreementInState(recipient,
tid,
OriginatorBlockAckAgreement::PENDING))
if (auto agreement = GetBaManager(tid)->GetAgreementAsOriginator(recipient, tid);
agreement && agreement->get().IsPending())
{
NS_LOG_DEBUG("No ACK after ADDBA request");
Ptr<QosTxop> qosTxop = m_mac->GetQosTxop(tid);
@@ -1279,9 +1276,7 @@ HtFrameExchangeManager::MissedBlockAck(Ptr<WifiPsdu> psdu,
// if a BA agreement exists, we can get here if there is no outstanding
// MPDU whose lifetime has not expired yet.
GetWifiRemoteStationManager()->ReportFinalDataFailed(*psdu->begin());
if (GetBaManager(tid)->ExistsAgreementInState(recipient,
tid,
OriginatorBlockAckAgreement::ESTABLISHED))
if (edca->GetBaAgreementEstablished(recipient, tid))
{
// schedule a BlockAckRequest with skipIfNoDataQueued set to true, so that the
// BlockAckRequest is only sent if there are data frames queued for this recipient.

View File

@@ -266,9 +266,8 @@ QosTxop::GetBaManager()
bool
QosTxop::GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
{
return m_baManager->ExistsAgreementInState(address,
tid,
OriginatorBlockAckAgreement::ESTABLISHED);
auto agreement = m_baManager->GetAgreementAsOriginator(address, tid);
return agreement && agreement->get().IsEstablished();
}
uint16_t
@@ -728,7 +727,8 @@ QosTxop::AddBaResponseTimeout(Mac48Address recipient, uint8_t tid)
{
NS_LOG_FUNCTION(this << recipient << +tid);
// If agreement is still pending, ADDBA response is not received
if (m_baManager->ExistsAgreementInState(recipient, tid, OriginatorBlockAckAgreement::PENDING))
if (auto agreement = m_baManager->GetAgreementAsOriginator(recipient, tid);
agreement && agreement->get().IsPending())
{
NotifyAgreementNoReply(recipient, tid);
Simulator::Schedule(m_failedAddBaTimeout, &QosTxop::ResetBa, this, recipient, tid);
@@ -743,10 +743,8 @@ QosTxop::ResetBa(Mac48Address recipient, uint8_t tid)
// before this function is called, a DELBA request may arrive, which causes
// the agreement to be deleted. Hence, check if an agreement exists before
// notifying that the agreement has to be reset.
if (m_baManager->ExistsAgreement(recipient, tid) &&
!m_baManager->ExistsAgreementInState(recipient,
tid,
OriginatorBlockAckAgreement::ESTABLISHED))
if (auto agreement = m_baManager->GetAgreementAsOriginator(recipient, tid);
agreement && !agreement->get().IsEstablished())
{
m_baManager->NotifyAgreementReset(recipient, tid);
}