wifi: Add DL OFDMA support to the WifiDefaultAckManager

This commit is contained in:
Stefano Avallone
2021-01-07 23:02:26 +01:00
parent 662c6a8a21
commit 47eb2b1fbf
2 changed files with 378 additions and 2 deletions

View File

@@ -25,9 +25,9 @@
#include "qos-utils.h"
#include "wifi-mac-queue.h"
#include "wifi-protection.h"
#include "regular-wifi-mac.h"
#include "ap-wifi-mac.h"
#include "ctrl-headers.h"
#include "wifi-phy.h"
#include "ns3/he-phy.h"
namespace ns3 {
@@ -58,6 +58,20 @@ WifiDefaultAckManager::GetTypeId (void)
DoubleValue (0.0),
MakeDoubleAccessor (&WifiDefaultAckManager::m_baThreshold),
MakeDoubleChecker<double> (0.0, 1.0))
.AddAttribute ("DlMuAckSequenceType",
"Type of the acknowledgment sequence for DL MU PPDUs.",
EnumValue (WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE),
MakeEnumAccessor (&WifiDefaultAckManager::m_dlMuAckType),
MakeEnumChecker (WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE, "DL_MU_BAR_BA_SEQUENCE",
WifiAcknowledgment::DL_MU_TF_MU_BAR, "DL_MU_TF_MU_BAR",
WifiAcknowledgment::DL_MU_AGGREGATE_TF, "DL_MU_AGGREGATE_TF"))
.AddAttribute ("MaxBlockAckMcs",
"The MCS used to send a BlockAck in a TB PPDU is the minimum between "
"the MCS used for the PSDU sent in the preceding DL MU PPDU and the "
"value of this attribute.",
UintegerValue (5),
MakeUintegerAccessor (&WifiDefaultAckManager::m_maxMcsForBlockAckInTbPpdu),
MakeUintegerChecker<uint8_t> (0, 11))
;
return tid;
}
@@ -154,6 +168,23 @@ WifiDefaultAckManager::TryAddMpdu (Ptr<const WifiMacQueueItem> mpdu,
{
NS_LOG_FUNCTION (this << *mpdu << &txParams);
// If the TXVECTOR indicates a DL MU PPDU, call a separate method
if (txParams.m_txVector.IsDlMu ())
{
switch (m_dlMuAckType)
{
case WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE:
return GetAckInfoIfBarBaSequence (mpdu, txParams);
case WifiAcknowledgment::DL_MU_TF_MU_BAR:
return GetAckInfoIfTfMuBar (mpdu, txParams);
case WifiAcknowledgment::DL_MU_AGGREGATE_TF:
return GetAckInfoIfAggregatedMuBar (mpdu, txParams);
default:
NS_ABORT_MSG ("Unknown DL acknowledgment method");
return nullptr;
}
}
const WifiMacHeader& hdr = mpdu->GetHeader ();
Mac48Address receiver = hdr.GetAddr1 ();
@@ -264,4 +295,300 @@ WifiDefaultAckManager::TryAggregateMsdu (Ptr<const WifiMacQueueItem> msdu,
return nullptr;
}
std::unique_ptr<WifiAcknowledgment>
WifiDefaultAckManager::GetAckInfoIfBarBaSequence (Ptr<const WifiMacQueueItem> mpdu,
const WifiTxParameters& txParams)
{
NS_LOG_FUNCTION (this << *mpdu << &txParams);
NS_ASSERT (txParams.m_txVector.IsDlMu ());
NS_ASSERT (m_dlMuAckType == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
const WifiMacHeader& hdr = mpdu->GetHeader ();
Mac48Address receiver = hdr.GetAddr1 ();
const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo (receiver);
NS_ABORT_MSG_IF (!hdr.IsQosData (),
"QoS data frames only can be aggregated when transmitting a "
"DL MU PPDU acknowledged via a sequence of BAR and BA frames");
uint8_t tid = hdr.GetQosTid ();
Ptr<QosTxop> edca = m_mac->GetQosTxop (QosUtilsMapTidToAc (tid));
NS_ASSERT (!txParams.m_acknowledgment
|| txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
WifiDlMuBarBaSequence* acknowledgment = nullptr;
if (txParams.m_acknowledgment)
{
acknowledgment = static_cast<WifiDlMuBarBaSequence*> (txParams.m_acknowledgment.get ());
}
if (psduInfo != nullptr)
{
// an MPDU addressed to the same receiver has been already added
NS_ASSERT (acknowledgment != nullptr);
if ((acknowledgment->stationsSendBlockAckReqTo.find (receiver)
!= acknowledgment->stationsSendBlockAckReqTo.end ())
|| (acknowledgment->stationsReplyingWithBlockAck.find (receiver)
!= acknowledgment->stationsReplyingWithBlockAck.end ()))
{
// the receiver either is already listed among the stations that will
// receive a BlockAckReq frame or is the station that will immediately
// respond with a BlockAck frame, hence no change is needed
return nullptr;
}
// the receiver was scheduled for responding immediately with a Normal Ack.
// Given that we are adding an MPDU, the receiver must be scheduled for
// responding immediately with a Block Ack
NS_ASSERT (acknowledgment->stationsReplyingWithNormalAck.size () == 1
&& acknowledgment->stationsReplyingWithNormalAck.begin ()->first == receiver);
// acknowledgment points to the m_acknowledgment member of txParams, which is
// passed as const reference because it must not be modified. Therefore, we
// make a copy of the object pointed to by acknowledgment and make changes to
// the copy
acknowledgment = new WifiDlMuBarBaSequence (*acknowledgment);
acknowledgment->stationsReplyingWithNormalAck.clear ();
acknowledgment->stationsReplyingWithBlockAck.emplace
(receiver,
WifiDlMuBarBaSequence::BlockAckInfo
{
m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, txParams.m_txVector),
edca->GetBlockAckType (receiver, tid)
});
return std::unique_ptr<WifiDlMuBarBaSequence> (acknowledgment);
}
// we get here if this is the first MPDU for this receiver
if (edca->GetBaManager ()->GetBar (true, tid, receiver) != 0
|| (acknowledgment != nullptr
&& (!acknowledgment->stationsReplyingWithNormalAck.empty ()
|| !acknowledgment->stationsReplyingWithBlockAck.empty ())))
{
// there is a pending BlockAckReq for this receiver or another receiver
// was selected for immediate response.
// Add this receiver to the list of stations receiving a BlockAckReq.
if (acknowledgment != nullptr)
{
// txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
// We have to return a copy of this object including the needed changes
acknowledgment = new WifiDlMuBarBaSequence (*acknowledgment);
}
else
{
// we have to create a new WifiDlMuBarBaSequence object
acknowledgment = new WifiDlMuBarBaSequence;
}
NS_LOG_DEBUG ("Adding STA " << receiver << " to the list of stations receiving a BlockAckReq");
acknowledgment->stationsSendBlockAckReqTo.emplace
(receiver,
WifiDlMuBarBaSequence::BlockAckReqInfo
{
m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, txParams.m_txVector),
edca->GetBlockAckReqType (receiver, tid),
m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (receiver, txParams.m_txVector),
edca->GetBlockAckType (receiver, tid)
});
acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::BLOCK_ACK);
return std::unique_ptr<WifiDlMuBarBaSequence> (acknowledgment);
}
// Add the receiver as the station that will immediately reply with a Normal Ack
if (acknowledgment != nullptr)
{
// txParams.m_acknowledgment points to an existing WifiDlMuBarBaSequence object.
// We have to return a copy of this object including the needed changes
acknowledgment = new WifiDlMuBarBaSequence (*acknowledgment);
}
else
{
// we have to create a new WifiDlMuBarBaSequence object
acknowledgment = new WifiDlMuBarBaSequence;
}
NS_LOG_DEBUG ("Adding STA " << receiver << " as the station that will immediately reply with a Normal Ack");
acknowledgment->stationsReplyingWithNormalAck.emplace
(receiver,
WifiDlMuBarBaSequence::AckInfo
{
m_mac->GetWifiRemoteStationManager ()->GetAckTxVector (receiver, txParams.m_txVector)
});
acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::NORMAL_ACK);
return std::unique_ptr<WifiDlMuBarBaSequence> (acknowledgment);
}
std::unique_ptr<WifiAcknowledgment>
WifiDefaultAckManager::GetAckInfoIfTfMuBar (Ptr<const WifiMacQueueItem> mpdu,
const WifiTxParameters& txParams)
{
NS_LOG_FUNCTION (this << *mpdu << &txParams);
NS_ASSERT (txParams.m_txVector.IsDlMu ());
NS_ASSERT (m_dlMuAckType == WifiAcknowledgment::DL_MU_TF_MU_BAR);
const WifiMacHeader& hdr = mpdu->GetHeader ();
Mac48Address receiver = hdr.GetAddr1 ();
const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo (receiver);
NS_ASSERT (!txParams.m_acknowledgment
|| txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR);
WifiDlMuTfMuBar* acknowledgment = nullptr;
if (txParams.m_acknowledgment)
{
acknowledgment = static_cast<WifiDlMuTfMuBar*> (txParams.m_acknowledgment.get ());
}
if (psduInfo == nullptr)
{
// we get here if this is the first MPDU for this receiver.
Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac> (m_mac);
NS_ABORT_MSG_IF (apMac == 0, "HE APs only can send DL MU PPDUs");
uint16_t staId = apMac->GetAssociationId (receiver);
NS_ABORT_MSG_IF (!hdr.IsQosData (),
"QoS data frames only can be aggregated when transmitting a "
"DL MU PPDU acknowledged via a MU-BAR sent as SU frame");
uint8_t tid = hdr.GetQosTid ();
// Add the receiver to the list of stations that will reply with a Block Ack
if (acknowledgment != nullptr)
{
// txParams.m_acknowledgment points to an existing WifiDlMuTfMuBar object.
// We have to return a copy of this object including the needed changes
acknowledgment = new WifiDlMuTfMuBar (*acknowledgment);
}
else
{
// we have to create a new WifiDlMuTfMuBar object
acknowledgment = new WifiDlMuTfMuBar;
}
// determine the TX vector used to send the BlockAck frame
WifiTxVector blockAckTxVector;
blockAckTxVector.SetPreambleType (WifiPreamble::WIFI_PREAMBLE_HE_TB);
blockAckTxVector.SetChannelWidth (txParams.m_txVector.GetChannelWidth ());
blockAckTxVector.SetGuardInterval (txParams.m_txVector.GetGuardInterval ());
const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo (staId);
blockAckTxVector.SetHeMuUserInfo (staId, {userInfo.ru,
HePhy::GetHeMcs (std::min (userInfo.mcs.GetMcsValue (),
m_maxMcsForBlockAckInTbPpdu)),
userInfo.nss});
NS_LOG_DEBUG ("Adding STA " << receiver << " to the list of stations that will be solicited by the MU-BAR");
Ptr<QosTxop> edca = m_mac->GetQosTxop (QosUtilsMapTidToAc (tid));
acknowledgment->stationsReplyingWithBlockAck.emplace
(receiver,
WifiDlMuTfMuBar::BlockAckInfo
{
edca->GetBaManager ()->GetBlockAckReqHeader (receiver, tid),
blockAckTxVector,
edca->GetBlockAckType (receiver, tid)
});
acknowledgment->barTypes.push_back (edca->GetBlockAckReqType (receiver, tid));
acknowledgment->muBarTxVector = m_mac->GetWifiRemoteStationManager ()->GetRtsTxVector (receiver);
acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::BLOCK_ACK);
return std::unique_ptr<WifiDlMuTfMuBar> (acknowledgment);
}
// an MPDU addressed to the same receiver has been already added
NS_ASSERT (acknowledgment != nullptr);
NS_ABORT_MSG_IF (!hdr.IsQosData (),
"QoS data frames only can be aggregated when transmitting a DL MU PPDU");
// no change is needed
return nullptr;
}
std::unique_ptr<WifiAcknowledgment>
WifiDefaultAckManager::GetAckInfoIfAggregatedMuBar (Ptr<const WifiMacQueueItem> mpdu,
const WifiTxParameters& txParams)
{
NS_LOG_FUNCTION (this << *mpdu << &txParams);
NS_ASSERT (txParams.m_txVector.IsDlMu ());
NS_ASSERT (m_dlMuAckType == WifiAcknowledgment::DL_MU_AGGREGATE_TF);
const WifiMacHeader& hdr = mpdu->GetHeader ();
Mac48Address receiver = hdr.GetAddr1 ();
const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo (receiver);
NS_ASSERT (!txParams.m_acknowledgment
|| txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF);
WifiDlMuAggregateTf* acknowledgment = nullptr;
if (txParams.m_acknowledgment)
{
acknowledgment = static_cast<WifiDlMuAggregateTf*> (txParams.m_acknowledgment.get ());
}
if (psduInfo == nullptr)
{
// we get here if this is the first MPDU for this receiver.
Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac> (m_mac);
NS_ABORT_MSG_IF (apMac == 0, "HE APs only can send DL MU PPDUs");
uint16_t staId = apMac->GetAssociationId (receiver);
NS_ABORT_MSG_IF (!hdr.IsQosData (),
"QoS data frames only can be aggregated when transmitting a "
"DL MU PPDU acknowledged via a sequence of BAR and BA frames");
uint8_t tid = hdr.GetQosTid ();
// Add the receiver to the list of stations that will reply with a Block Ack
if (acknowledgment != nullptr)
{
// txParams.m_acknowledgment points to an existing WifiDlMuAggregateTf object.
// We have to return a copy of this object including the needed changes
acknowledgment = new WifiDlMuAggregateTf (*acknowledgment);
}
else
{
// we have to create a new WifiDlMuAggregateTf object
acknowledgment = new WifiDlMuAggregateTf;
}
// determine the TX vector used to send the BlockAck frame
WifiTxVector blockAckTxVector;
blockAckTxVector.SetPreambleType (WifiPreamble::WIFI_PREAMBLE_HE_TB);
blockAckTxVector.SetChannelWidth (txParams.m_txVector.GetChannelWidth ());
blockAckTxVector.SetGuardInterval (txParams.m_txVector.GetGuardInterval ());
const auto& userInfo = txParams.m_txVector.GetHeMuUserInfo (staId);
blockAckTxVector.SetHeMuUserInfo (staId, {userInfo.ru,
HePhy::GetHeMcs (std::min (userInfo.mcs.GetMcsValue (),
m_maxMcsForBlockAckInTbPpdu)),
userInfo.nss});
NS_LOG_DEBUG ("Adding STA " << receiver << " to the list of stations that will reply with a Block Ack");
Ptr<QosTxop> edca = m_mac->GetQosTxop (QosUtilsMapTidToAc (tid));
acknowledgment->stationsReplyingWithBlockAck.emplace
(receiver,
WifiDlMuAggregateTf::BlockAckInfo
{
GetMuBarSize ({edca->GetBlockAckReqType (receiver, tid)}),
edca->GetBaManager ()->GetBlockAckReqHeader (receiver, tid),
blockAckTxVector,
edca->GetBlockAckType (receiver, tid)
});
acknowledgment->SetQosAckPolicy (receiver, tid, WifiMacHeader::NO_EXPLICIT_ACK);
return std::unique_ptr<WifiDlMuAggregateTf> (acknowledgment);
}
// an MPDU addressed to the same receiver has been already added
NS_ASSERT (acknowledgment != nullptr);
NS_ABORT_MSG_IF (!hdr.IsQosData (),
"QoS data and MU-BAR Trigger frames only can be aggregated when transmitting a DL MU PPDU");
// no change is needed
return nullptr;
}
} //namespace ns3

View File

@@ -81,8 +81,57 @@ protected:
bool IsResponseNeeded (Ptr<const WifiMacQueueItem> mpdu,
const WifiTxParameters& txParams) const;
private:
/**
* Compute the information about the acknowledgment of the current multi-user frame
* (as described by the given TX parameters) if the given MPDU is added. If the
* computed information is the same as the current one, a null pointer is returned.
* Otherwise, the computed information is returned.
* This method can only be called if the selected acknowledgment method for DL
* multi-user frames consists of a sequence of BlockAckReq and BlockAck frames.
*
* \param mpdu the given MPDU
* \param txParams the TX parameters describing the current multi-user frame
* \return the new acknowledgment method or a null pointer if the acknowledgment method
* is unchanged
*/
virtual std::unique_ptr<WifiAcknowledgment> GetAckInfoIfBarBaSequence (Ptr<const WifiMacQueueItem> mpdu,
const WifiTxParameters& txParams);
/**
* Compute the information about the acknowledgment of the current multi-user frame
* (as described by the given TX parameters) if the given MPDU is added. If the
* computed information is the same as the current one, a null pointer is returned.
* Otherwise, the computed information is returned.
* This method can only be called if the selected acknowledgment method for DL
* multi-user frames consists of a MU-BAR Trigger Frame sent as single-user frame.
*
* \param mpdu the given MPDU
* \param txParams the TX parameters describing the current multi-user frame
* \return the new acknowledgment method or a null pointer if the acknowledgment method
* is unchanged
*/
virtual std::unique_ptr<WifiAcknowledgment> GetAckInfoIfTfMuBar (Ptr<const WifiMacQueueItem> mpdu,
const WifiTxParameters& txParams);
/**
* Compute the information about the acknowledgment of the current multi-user frame
* (as described by the given TX parameters) if the given MPDU is added. If the
* computed information is the same as the current one, a null pointer is returned.
* Otherwise, the computed information is returned.
* This method can only be called if the selected acknowledgment method for DL
* multi-user frames consists of MU-BAR Trigger Frames aggregated to the PSDUs of
* the MU PPDU.
*
* \param mpdu the given MPDU
* \param txParams the TX parameters describing the current multi-user frame
* \return the new acknowledgment method or a null pointer if the acknowledgment method
* is unchanged
*/
virtual std::unique_ptr<WifiAcknowledgment> GetAckInfoIfAggregatedMuBar (Ptr<const WifiMacQueueItem> mpdu,
const WifiTxParameters& txParams);
bool m_useExplicitBar; //!< true for sending BARs, false for using Implicit BAR policy
double m_baThreshold; //!< Threshold to determine when a BlockAck must be requested
WifiAcknowledgment::Method m_dlMuAckType; //!< Type of the ack sequence for DL MU PPDUs
uint8_t m_maxMcsForBlockAckInTbPpdu; //!< Max MCS used to send a BlockAck in a TB PPDU
};