wifi: Add support to WifiMac for swapping links
This commit is contained in:
committed by
Stefano Avallone
parent
f8d9a43ad3
commit
990fcc72f0
@@ -59,6 +59,14 @@ EhtFrameExchangeManager::~EhtFrameExchangeManager()
|
||||
void
|
||||
EhtFrameExchangeManager::SetLinkId(uint8_t linkId)
|
||||
{
|
||||
if (auto protectionManager = GetProtectionManager())
|
||||
{
|
||||
protectionManager->SetLinkId(linkId);
|
||||
}
|
||||
if (auto ackManager = GetAckManager())
|
||||
{
|
||||
ackManager->SetLinkId(linkId);
|
||||
}
|
||||
m_msduAggregator->SetLinkId(linkId);
|
||||
m_mpduAggregator->SetLinkId(linkId);
|
||||
HeFrameExchangeManager::SetLinkId(linkId);
|
||||
|
||||
@@ -934,6 +934,22 @@ WifiMac::GetNLinks() const
|
||||
return m_links.size();
|
||||
}
|
||||
|
||||
void
|
||||
WifiMac::UpdateLinkId(uint8_t id)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << id);
|
||||
|
||||
auto& link = GetLink(id);
|
||||
if (link.feManager)
|
||||
{
|
||||
link.feManager->SetLinkId(id);
|
||||
}
|
||||
if (link.channelAccessManager)
|
||||
{
|
||||
link.channelAccessManager->SetLinkId(id);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<uint8_t>
|
||||
WifiMac::GetLinkIdByAddress(const Mac48Address& address) const
|
||||
{
|
||||
@@ -947,6 +963,58 @@ WifiMac::GetLinkIdByAddress(const Mac48Address& address) const
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void
|
||||
WifiMac::SwapLinks(std::map<uint8_t, uint8_t> links)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
while (!links.empty())
|
||||
{
|
||||
auto from = links.cbegin()->first;
|
||||
auto to = links.cbegin()->second;
|
||||
|
||||
if (from == to)
|
||||
{
|
||||
// nothing to do
|
||||
links.erase(links.cbegin());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<LinkEntity> linkToMove;
|
||||
NS_ASSERT(m_links.find(from) != m_links.cend());
|
||||
linkToMove.swap(m_links.at(from)); // from is now out of m_links
|
||||
auto empty = from; // track empty cell in m_links
|
||||
|
||||
do
|
||||
{
|
||||
auto [it, inserted] =
|
||||
m_links.emplace(to, nullptr); // insert an element with key to if not present
|
||||
m_links[to].swap(linkToMove); // to is the link to move now
|
||||
UpdateLinkId(to);
|
||||
links.erase(from);
|
||||
if (!linkToMove)
|
||||
{
|
||||
if (inserted)
|
||||
{
|
||||
m_links.erase(empty);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
auto nextTo = links.find(to);
|
||||
if (nextTo == links.cend())
|
||||
{
|
||||
// no new position specified for 'to', use the current empty cell
|
||||
m_links[empty].swap(linkToMove);
|
||||
break;
|
||||
}
|
||||
|
||||
from = to;
|
||||
to = nextTo->second;
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WifiMac::SetWifiPhys(const std::vector<Ptr<WifiPhy>>& phys)
|
||||
{
|
||||
|
||||
@@ -752,6 +752,16 @@ class WifiMac : public Object
|
||||
*/
|
||||
virtual void DeaggregateAmsduAndForward(Ptr<const WifiMpdu> mpdu);
|
||||
|
||||
/**
|
||||
* Swap the links based on the information included in the given map. This method
|
||||
* is normally called by a non-AP MLD upon completing ML setup to have its link IDs
|
||||
* match AP MLD's link IDs.
|
||||
*
|
||||
* \param links a set of pairs (from, to) each mapping a current link ID to the
|
||||
* link ID it has to become (i.e., link 'from' becomes link 'to')
|
||||
*/
|
||||
void SwapLinks(std::map<uint8_t, uint8_t> links);
|
||||
|
||||
/**
|
||||
* Structure holding information specific to a single link. Here, the meaning of
|
||||
* "link" is that of the 11be amendment which introduced multi-link devices. For
|
||||
@@ -841,6 +851,15 @@ class WifiMac : public Object
|
||||
*/
|
||||
virtual std::unique_ptr<LinkEntity> CreateLinkEntity() const;
|
||||
|
||||
/**
|
||||
* This method is intended to be called when a link changes ID in order to update the
|
||||
* link ID stored by the Frame Exchange Manager and the Channel Access Manager operating
|
||||
* on that link.
|
||||
*
|
||||
* \param id the (new) ID of the link that has changed ID
|
||||
*/
|
||||
void UpdateLinkId(uint8_t id);
|
||||
|
||||
/**
|
||||
* This method is called if this device is an MLD to determine the MAC address of
|
||||
* the affiliated STA used to communicate with the single link device having the
|
||||
|
||||
@@ -189,6 +189,121 @@ GetRnrLinkInfoTest::DoRun()
|
||||
"Unexpected tbtt ID of the second reported AP");
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
*
|
||||
* Test the WifiMac::SwapLinks() method.
|
||||
*/
|
||||
class MldSwapLinksTest : public TestCase
|
||||
{
|
||||
/**
|
||||
* Test WifiMac subclass used to access the SwapLinks method.
|
||||
*/
|
||||
class TestWifiMac : public WifiMac
|
||||
{
|
||||
public:
|
||||
~TestWifiMac() override = default;
|
||||
|
||||
using WifiMac::GetLinks;
|
||||
using WifiMac::SwapLinks;
|
||||
|
||||
bool CanForwardPacketsTo(Mac48Address to) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Enqueue(Ptr<Packet> packet, Mac48Address to) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
MldSwapLinksTest();
|
||||
~MldSwapLinksTest() override = default;
|
||||
|
||||
protected:
|
||||
void DoRun() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Run a single test case.
|
||||
*
|
||||
* \param text string identifying the test case
|
||||
* \param nLinks the number of links of the MLD
|
||||
* \param links a set of pairs (from, to) each mapping a current link ID to the
|
||||
* link ID it has to become (i.e., link 'from' becomes link 'to')
|
||||
* \param expected maps each link ID to the id of the PHY that is expected
|
||||
* to operate on that link after the swap
|
||||
*/
|
||||
void RunOne(std::string text,
|
||||
std::size_t nLinks,
|
||||
const std::map<uint8_t, uint8_t>& links,
|
||||
const std::map<uint8_t, uint8_t>& expected);
|
||||
};
|
||||
|
||||
MldSwapLinksTest::MldSwapLinksTest()
|
||||
: TestCase("Test the WifiMac::SwapLinks() method")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MldSwapLinksTest::RunOne(std::string text,
|
||||
std::size_t nLinks,
|
||||
const std::map<uint8_t, uint8_t>& links,
|
||||
const std::map<uint8_t, uint8_t>& expected)
|
||||
{
|
||||
TestWifiMac mac;
|
||||
|
||||
std::vector<Ptr<WifiPhy>> phys;
|
||||
for (std::size_t i = 0; i < nLinks; i++)
|
||||
{
|
||||
phys.emplace_back(CreateObject<SpectrumWifiPhy>());
|
||||
}
|
||||
mac.SetWifiPhys(phys); // create links containing the given PHYs
|
||||
|
||||
mac.SwapLinks(links);
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(mac.GetNLinks(), nLinks, "Number of links changed after swapping");
|
||||
|
||||
for (const auto& [linkId, phyId] : expected)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(mac.GetLinks().count(linkId),
|
||||
1,
|
||||
"Link ID " << +linkId << " does not exist");
|
||||
|
||||
NS_TEST_ASSERT_MSG_LT(+phyId, nLinks, "Invalid PHY ID");
|
||||
|
||||
// the id of the PHY operating on a link is the original ID of the link
|
||||
NS_TEST_EXPECT_MSG_EQ(mac.GetWifiPhy(linkId),
|
||||
phys.at(phyId),
|
||||
text << ": Link " << +phyId << " has not been moved to link "
|
||||
<< +linkId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MldSwapLinksTest::DoRun()
|
||||
{
|
||||
RunOne("No change needed", 3, {{0, 0}, {1, 1}, {2, 2}}, {{0, 0}, {1, 1}, {2, 2}});
|
||||
RunOne("Circular swapping", 3, {{0, 2}, {1, 0}, {2, 1}}, {{0, 1}, {1, 2}, {2, 0}});
|
||||
RunOne("Swapping two links, one unchanged", 3, {{0, 2}, {2, 0}}, {{0, 2}, {1, 1}, {2, 0}});
|
||||
RunOne("Non-circular swapping, autodetect how to close the loop",
|
||||
3,
|
||||
{{0, 2}, {2, 1}},
|
||||
{{0, 1}, {1, 2}, {2, 0}});
|
||||
RunOne("One move only, autodetect how to complete the swapping",
|
||||
3,
|
||||
{{2, 0}},
|
||||
{{0, 2}, {1, 1}, {2, 0}});
|
||||
RunOne("Create a new link ID (2), remove the unused one (0)",
|
||||
2,
|
||||
{{0, 1}, {1, 2}},
|
||||
{{1, 0}, {2, 1}});
|
||||
RunOne("One move only that creates a new link ID (2)", 2, {{0, 2}}, {{1, 1}, {2, 0}});
|
||||
RunOne("Move all links to a new set of IDs", 2, {{0, 2}, {1, 3}}, {{2, 0}, {3, 1}});
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup wifi-test
|
||||
* \ingroup tests
|
||||
@@ -2632,6 +2747,7 @@ WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
|
||||
std::vector<uint8_t>>; // IDs of link that cannot change PHY band
|
||||
|
||||
AddTestCase(new GetRnrLinkInfoTest(), TestCase::QUICK);
|
||||
AddTestCase(new MldSwapLinksTest(), TestCase::QUICK);
|
||||
|
||||
for (const auto& [staChannels, apChannels, setupLinks, fixedPhyBands] :
|
||||
{// matching channels: setup all links
|
||||
|
||||
Reference in New Issue
Block a user