From c8ad2f4d452227a147ef40a612bf606ba33db576 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Wed, 19 Oct 2022 14:48:51 +0200 Subject: [PATCH] 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. --- src/wifi/model/block-ack-manager.cc | 251 ++++++++---------- src/wifi/model/block-ack-manager.h | 46 +--- .../model/ht/ht-frame-exchange-manager.cc | 15 +- src/wifi/model/qos-txop.cc | 14 +- 4 files changed, 126 insertions(+), 200 deletions(-) diff --git a/src/wifi/model/block-ack-manager.cc b/src/wifi/model/block-ack-manager.cc index 91ca02f04..4ea7365de 100644 --- a/src/wifi/model/block-ack-manager.cc +++ b/src/wifi/model/block-ack-manager.cc @@ -92,39 +92,16 @@ BlockAckManager::SetBlockAckManagerMap(const std::mapsecond.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 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 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 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 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> 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> 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 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 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; } diff --git a/src/wifi/model/block-ack-manager.h b/src/wifi/model/block-ack-manager.h index d8fe1d7e0..9faf79809 100644 --- a/src/wifi/model/block-ack-manager.h +++ b/src/wifi/model/block-ack-manager.h @@ -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>& bamMap); + + /// optional const reference to OriginatorBlockAckAgreement + using OriginatorAgreementOptConstRef = + std::optional>; + /** - * \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 - * recipient for TID tid. + * 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 state exists with - * station addressed by recipient for TID tid. - */ - 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 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 diff --git a/src/wifi/model/ht/ht-frame-exchange-manager.cc b/src/wifi/model/ht/ht-frame-exchange-manager.cc index 0233116f6..c26d3376a 100644 --- a/src/wifi/model/ht/ht-frame-exchange-manager.cc +++ b/src/wifi/model/ht/ht-frame-exchange-manager.cc @@ -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 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 = m_mac->GetQosTxop(tid); @@ -1279,9 +1276,7 @@ HtFrameExchangeManager::MissedBlockAck(Ptr 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. diff --git a/src/wifi/model/qos-txop.cc b/src/wifi/model/qos-txop.cc index a674d1010..cfec8eacd 100644 --- a/src/wifi/model/qos-txop.cc +++ b/src/wifi/model/qos-txop.cc @@ -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); }