wifi: Create MPDU aliases for transmission on multiple links

This commit is contained in:
Stefano Avallone
2022-09-13 13:22:02 +02:00
committed by Stefano Avallone
parent 8a98843763
commit 1f203aab9e
2 changed files with 159 additions and 31 deletions

View File

@@ -36,24 +36,67 @@ namespace ns3
NS_LOG_COMPONENT_DEFINE("WifiMpdu");
WifiMpdu::WifiMpdu(Ptr<const Packet> p, const WifiMacHeader& header)
: m_packet(p),
m_header(header)
: m_header(header)
{
auto& original = std::get<OriginalInfo>(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<Ptr<WifiMpdu>>(m_instanceInfo) || !IsQueued());
}
bool
WifiMpdu::IsOriginal() const
{
return std::holds_alternative<OriginalInfo>(m_instanceInfo);
}
Ptr<const WifiMpdu>
WifiMpdu::GetOriginal() const
{
if (std::holds_alternative<OriginalInfo>(m_instanceInfo))
{
return this;
}
return std::get<ALIAS>(m_instanceInfo);
}
Ptr<WifiMpdu>
WifiMpdu::CreateAlias(uint8_t linkId) const
{
NS_LOG_FUNCTION(this << +linkId);
NS_ABORT_MSG_IF(!std::holds_alternative<OriginalInfo>(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<WifiMpdu>(new WifiMpdu, false);
alias->m_header = m_header; // copy the MAC header
alias->m_instanceInfo = Ptr(const_cast<WifiMpdu*>(this));
NS_ASSERT(alias->m_instanceInfo.index() == ALIAS);
return alias;
}
Ptr<const Packet>
WifiMpdu::GetPacket() const
{
return m_packet;
if (auto original = std::get_if<ORIGINAL>(&m_instanceInfo))
{
return original->m_packet;
}
const auto& origInstanceInfo = std::get<Ptr<WifiMpdu>>(m_instanceInfo)->m_instanceInfo;
return std::get<OriginalInfo>(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<Packet>
WifiMpdu::GetProtocolDataUnit() const
{
Ptr<Packet> mpdu = m_packet->Copy();
Ptr<Packet> mpdu = GetPacket()->Copy();
mpdu->AddHeader(m_header);
AddWifiMacTrailer(mpdu);
return mpdu;
@@ -108,12 +151,16 @@ WifiMpdu::Aggregate(Ptr<const WifiMpdu> 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<OriginalInfo>(m_instanceInfo),
"This method can only be called on the original version of the MPDU");
if (m_msduList.empty())
auto& original = std::get<OriginalInfo>(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<const WifiMpdu> firstMsdu = Create<const WifiMpdu>(*this);
m_packet = Create<Packet>();
original.m_packet = Create<Packet>();
DoAggregate(firstMsdu);
m_header.SetQosAmsdu();
@@ -159,16 +206,18 @@ WifiMpdu::DoAggregate(Ptr<const WifiMpdu> msdu)
: msdu->GetHeader().GetAddr4()));
hdr.SetLength(static_cast<uint16_t>(msdu->GetPacket()->GetSize()));
m_msduList.emplace_back(msdu->GetPacket(), hdr);
auto& original = std::get<OriginalInfo>(m_instanceInfo);
original.m_msduList.push_back({msdu->GetPacket(), hdr});
// build the A-MSDU
NS_ASSERT(m_packet);
Ptr<Packet> amsdu = m_packet->Copy();
NS_ASSERT(original.m_packet);
Ptr<Packet> 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<const WifiMpdu> msdu)
Ptr<Packet> 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<ORIGINAL>(&m_instanceInfo))
{
return original->m_queueIt.has_value();
}
const auto& origInstanceInfo = std::get<Ptr<WifiMpdu>>(m_instanceInfo)->m_instanceInfo;
return std::get<OriginalInfo>(origInstanceInfo).m_queueIt.has_value();
}
void
WifiMpdu::SetQueueIt(std::optional<Iterator> queueIt, WmqIteratorTag tag)
{
m_queueIt = queueIt;
NS_ABORT_MSG_IF(!std::holds_alternative<OriginalInfo>(m_instanceInfo),
"This method can only be called on the original version of the MPDU");
auto& original = std::get<OriginalInfo>(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<ORIGINAL>(&m_instanceInfo))
{
return original->m_queueIt.value();
}
auto& origInstanceInfo = std::get<Ptr<WifiMpdu>>(m_instanceInfo)->m_instanceInfo;
return std::get<OriginalInfo>(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<ORIGINAL>(&m_instanceInfo))
{
return original->m_msduList.cbegin();
}
auto& origInstanceInfo = std::get<Ptr<WifiMpdu>>(m_instanceInfo)->m_instanceInfo;
return std::get<OriginalInfo>(origInstanceInfo).m_msduList.cbegin();
}
WifiMpdu::DeaggregatedMsdusCI
WifiMpdu::end() const
{
return m_msduList.cend();
if (auto original = std::get_if<ORIGINAL>(&m_instanceInfo))
{
return original->m_msduList.cend();
}
auto& origInstanceInfo = std::get<Ptr<WifiMpdu>>(m_instanceInfo)->m_instanceInfo;
return std::get<OriginalInfo>(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&

View File

@@ -31,6 +31,7 @@
#include <list>
#include <optional>
#include <variant>
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<WifiMpdu>
{
@@ -65,6 +68,16 @@ class WifiMpdu : public SimpleRefCount<WifiMpdu>
virtual ~WifiMpdu();
/**
* \return whether this is the original version of the MPDU
*/
bool IsOriginal() const;
/**
* \return the original version of this MPDU
*/
Ptr<const WifiMpdu> 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<WifiMpdu>
*/
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<WifiMpdu> 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<WifiMpdu>
*/
void DoAggregate(Ptr<const WifiMpdu> msdu);
Ptr<const Packet> 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<Iterator> 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<const Packet> m_packet; //!< MSDU or A-MSDU contained in this queue item
DeaggregatedMsdus m_msduList; //!< list of aggregated MSDUs included in this MPDU
std::optional<Iterator> m_queueIt; //!< Queue iterator pointing to this MPDU, if queued
};
/// Information stored by the original copy and an alias, respectively
using InstanceInfo = std::variant<OriginalInfo, Ptr<WifiMpdu>>;
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
};
/**