diff --git a/src/wifi/model/wifi-mpdu.cc b/src/wifi/model/wifi-mpdu.cc index e48da53d7..5a53c7ba0 100644 --- a/src/wifi/model/wifi-mpdu.cc +++ b/src/wifi/model/wifi-mpdu.cc @@ -36,24 +36,67 @@ namespace ns3 NS_LOG_COMPONENT_DEFINE("WifiMpdu"); WifiMpdu::WifiMpdu(Ptr p, const WifiMacHeader& header) - : m_packet(p), - m_header(header) + : m_header(header) { + auto& original = std::get(m_instanceInfo); + original.m_packet = p; + if (header.IsQosData() && header.IsQosAmsdu()) { - m_msduList = MsduAggregator::Deaggregate(p->Copy()); + original.m_msduList = MsduAggregator::Deaggregate(p->Copy()); } m_inFlight = false; } WifiMpdu::~WifiMpdu() { + // Aliases can be queued (i.e., the original copy is queued) when destroyed + NS_ASSERT(std::holds_alternative>(m_instanceInfo) || !IsQueued()); +} + +bool +WifiMpdu::IsOriginal() const +{ + return std::holds_alternative(m_instanceInfo); +} + +Ptr +WifiMpdu::GetOriginal() const +{ + if (std::holds_alternative(m_instanceInfo)) + { + return this; + } + return std::get(m_instanceInfo); +} + +Ptr +WifiMpdu::CreateAlias(uint8_t linkId) const +{ + NS_LOG_FUNCTION(this << +linkId); + NS_ABORT_MSG_IF(!std::holds_alternative(m_instanceInfo), + "This method can only be called on the original version of the MPDU"); + NS_ABORT_MSG_IF(!IsQueued(), + "This method can only be called if the MPDU is stored in a MAC queue"); + + auto alias = Ptr(new WifiMpdu, false); + + alias->m_header = m_header; // copy the MAC header + alias->m_instanceInfo = Ptr(const_cast(this)); + NS_ASSERT(alias->m_instanceInfo.index() == ALIAS); + + return alias; } Ptr WifiMpdu::GetPacket() const { - return m_packet; + if (auto original = std::get_if(&m_instanceInfo)) + { + return original->m_packet; + } + const auto& origInstanceInfo = std::get>(m_instanceInfo)->m_instanceInfo; + return std::get(origInstanceInfo).m_packet; } const WifiMacHeader& @@ -77,7 +120,7 @@ WifiMpdu::GetDestinationAddress() const uint32_t WifiMpdu::GetPacketSize() const { - return m_packet->GetSize(); + return GetPacket()->GetSize(); } uint32_t @@ -95,7 +138,7 @@ WifiMpdu::IsFragment() const Ptr WifiMpdu::GetProtocolDataUnit() const { - Ptr mpdu = m_packet->Copy(); + Ptr mpdu = GetPacket()->Copy(); mpdu->AddHeader(m_header); AddWifiMacTrailer(mpdu); return mpdu; @@ -108,12 +151,16 @@ WifiMpdu::Aggregate(Ptr msdu) NS_LOG_FUNCTION(this << *msdu); NS_ABORT_MSG_IF(!msdu->GetHeader().IsQosData() || msdu->GetHeader().IsQosAmsdu(), "Only QoS data frames that do not contain an A-MSDU can be aggregated"); + NS_ABORT_MSG_IF(!std::holds_alternative(m_instanceInfo), + "This method can only be called on the original version of the MPDU"); - if (m_msduList.empty()) + auto& original = std::get(m_instanceInfo); + + if (original.m_msduList.empty()) { // An MSDU is going to be aggregated to this MPDU, hence this has to be an A-MSDU now Ptr firstMsdu = Create(*this); - m_packet = Create(); + original.m_packet = Create(); DoAggregate(firstMsdu); m_header.SetQosAmsdu(); @@ -159,16 +206,18 @@ WifiMpdu::DoAggregate(Ptr msdu) : msdu->GetHeader().GetAddr4())); hdr.SetLength(static_cast(msdu->GetPacket()->GetSize())); - m_msduList.emplace_back(msdu->GetPacket(), hdr); + auto& original = std::get(m_instanceInfo); + + original.m_msduList.push_back({msdu->GetPacket(), hdr}); // build the A-MSDU - NS_ASSERT(m_packet); - Ptr amsdu = m_packet->Copy(); + NS_ASSERT(original.m_packet); + Ptr amsdu = original.m_packet->Copy(); // pad the previous A-MSDU subframe if the A-MSDU is not empty - if (m_packet->GetSize() > 0) + if (original.m_packet->GetSize() > 0) { - uint8_t padding = MsduAggregator::CalculatePadding(m_packet->GetSize()); + uint8_t padding = MsduAggregator::CalculatePadding(original.m_packet->GetSize()); if (padding) { @@ -180,40 +229,58 @@ WifiMpdu::DoAggregate(Ptr msdu) Ptr amsduSubframe = msdu->GetPacket()->Copy(); amsduSubframe->AddHeader(hdr); amsdu->AddAtEnd(amsduSubframe); - m_packet = amsdu; + original.m_packet = amsdu; } bool WifiMpdu::IsQueued() const { - return m_queueIt.has_value(); + if (auto original = std::get_if(&m_instanceInfo)) + { + return original->m_queueIt.has_value(); + } + const auto& origInstanceInfo = std::get>(m_instanceInfo)->m_instanceInfo; + return std::get(origInstanceInfo).m_queueIt.has_value(); } void WifiMpdu::SetQueueIt(std::optional queueIt, WmqIteratorTag tag) { - m_queueIt = queueIt; + NS_ABORT_MSG_IF(!std::holds_alternative(m_instanceInfo), + "This method can only be called on the original version of the MPDU"); + + auto& original = std::get(m_instanceInfo); + original.m_queueIt = queueIt; } WifiMpdu::Iterator WifiMpdu::GetQueueIt(WmqIteratorTag tag) const +{ + return GetQueueIt(); +} + +WifiMpdu::Iterator +WifiMpdu::GetQueueIt() const { NS_ASSERT(IsQueued()); - return m_queueIt.value(); + if (auto original = std::get_if(&m_instanceInfo)) + { + return original->m_queueIt.value(); + } + auto& origInstanceInfo = std::get>(m_instanceInfo)->m_instanceInfo; + return std::get(origInstanceInfo).m_queueIt.value(); } AcIndex WifiMpdu::GetQueueAc() const { - NS_ASSERT(IsQueued()); - return (*m_queueIt)->ac; + return GetQueueIt()->ac; } Time WifiMpdu::GetExpiryTime() const { - NS_ASSERT(IsQueued()); - return (*m_queueIt)->expiryTime; + return GetQueueIt()->expiryTime; } void @@ -237,13 +304,23 @@ WifiMpdu::IsInFlight() const WifiMpdu::DeaggregatedMsdusCI WifiMpdu::begin() const { - return m_msduList.cbegin(); + if (auto original = std::get_if(&m_instanceInfo)) + { + return original->m_msduList.cbegin(); + } + auto& origInstanceInfo = std::get>(m_instanceInfo)->m_instanceInfo; + return std::get(origInstanceInfo).m_msduList.cbegin(); } WifiMpdu::DeaggregatedMsdusCI WifiMpdu::end() const { - return m_msduList.cend(); + if (auto original = std::get_if(&m_instanceInfo)) + { + return original->m_msduList.cend(); + } + auto& origInstanceInfo = std::get>(m_instanceInfo)->m_instanceInfo; + return std::get(origInstanceInfo).m_msduList.cend(); } void @@ -274,7 +351,7 @@ WifiMpdu::Print(std::ostream& os) const os << ", residualLifetime=" << (GetExpiryTime() - Simulator::Now()).As(Time::US) << ", inflight=" << IsInFlight(); } - os << ", packet=" << m_packet; + os << ", packet=" << GetPacket(); } std::ostream& diff --git a/src/wifi/model/wifi-mpdu.h b/src/wifi/model/wifi-mpdu.h index 999a258a8..51cfe158c 100644 --- a/src/wifi/model/wifi-mpdu.h +++ b/src/wifi/model/wifi-mpdu.h @@ -31,6 +31,7 @@ #include #include +#include namespace ns3 { @@ -50,8 +51,10 @@ class WmqIteratorTag /** * \ingroup wifi * - * WifiMpdu stores (const) packets along with their Wifi MAC headers - * and the time when they were enqueued. + * WifiMpdu stores a (const) packet along with a MAC header. To support 802.11be + * Multi-Link Operation (MLO), a WifiMpdu variant, referred to as WifiMpdu alias, + * is added. A WifiMpdu alias stores its own MAC header and a pointer to the original + * copy of the WifiMpdu. */ class WifiMpdu : public SimpleRefCount { @@ -65,6 +68,16 @@ class WifiMpdu : public SimpleRefCount virtual ~WifiMpdu(); + /** + * \return whether this is the original version of the MPDU + */ + bool IsOriginal() const; + + /** + * \return the original version of this MPDU + */ + Ptr GetOriginal() const; + /** * \brief Get the packet stored in this item * \return the packet stored in this item. @@ -196,6 +209,16 @@ class WifiMpdu : public SimpleRefCount */ bool IsInFlight() const; + /** + * Create an alias for this MPDU (which must be an original copy) for transmission + * on the link with the given ID. Aliases have their own copy of the MAC header and + * cannot be used to perform non-const operations on the frame body. + * + * \param linkId the ID of the given link + * \return an alias for this MPDU + */ + Ptr CreateAlias(uint8_t linkId) const; + /** * \brief Print the item contents. * \param os output stream in which the data should be printed. @@ -211,11 +234,39 @@ class WifiMpdu : public SimpleRefCount */ void DoAggregate(Ptr msdu); - Ptr m_packet; //!< The packet (MSDU or A-MSDU) contained in this queue item - WifiMacHeader m_header; //!< Wifi MAC header associated with the packet - DeaggregatedMsdus m_msduList; //!< The list of aggregated MSDUs included in this MPDU - std::optional m_queueIt; //!< Queue iterator pointing to this MPDU, if queued - bool m_inFlight; //!< whether the MPDU is in flight + /** + * \return the queue iterator stored by this object + */ + Iterator GetQueueIt() const; + + /** + * Private default constructor (used to construct aliases). + */ + WifiMpdu() = default; + + /** + * Information stored by both the original copy and the aliases + */ + WifiMacHeader m_header; //!< Wifi MAC header associated with the packet + bool m_inFlight; //!< whether the MPDU is in flight + + /** + * Information stored by the original copy only. + */ + struct OriginalInfo + { + Ptr m_packet; //!< MSDU or A-MSDU contained in this queue item + DeaggregatedMsdus m_msduList; //!< list of aggregated MSDUs included in this MPDU + std::optional m_queueIt; //!< Queue iterator pointing to this MPDU, if queued + }; + + /// Information stored by the original copy and an alias, respectively + using InstanceInfo = std::variant>; + + InstanceInfo m_instanceInfo; //!< information associated with the instance type + static constexpr std::size_t ORIGINAL = + 0; //!< index of original copy in the InstanceInfo variant + static constexpr std::size_t ALIAS = 1; //!< index of an alias in the InstanceInfo variant }; /**