wifi: Default EMLSR Manager switches main PHY back to its previous link

...when a TXOP ends, if the aux PHYs do not switch link
This commit is contained in:
Stefano Avallone
2023-06-14 17:58:50 +02:00
committed by Stefano Avallone
parent f38712dc3c
commit 4fc5162f97
4 changed files with 89 additions and 58 deletions

View File

@@ -42,7 +42,10 @@ DefaultEmlsrManager::GetTypeId()
.AddConstructor<DefaultEmlsrManager>()
.AddAttribute("SwitchAuxPhy",
"Whether Aux PHY should switch channel to operate on the link on which "
"the Main PHY was operating before moving to the link of the Aux PHY.",
"the Main PHY was operating before moving to the link of the Aux PHY. "
"Note that, if the Aux PHY does not switch channel, the main PHY will "
"switch back to its previous link once the TXOP terminates (otherwise, "
"no PHY will be listening on that EMLSR link).",
BooleanValue(true),
MakeBooleanAccessor(&DefaultEmlsrManager::m_switchAuxPhy),
MakeBooleanChecker());
@@ -96,7 +99,10 @@ DefaultEmlsrManager::NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId)
if (!m_switchAuxPhy)
{
return; // nothing to do
// record that the main PHY will have to switch back to its current link
m_linkIdForMainPhyAfterTxop = currLinkId;
m_auxPhyToReconnect = GetStaMac()->GetWifiPhy(nextLinkId);
return;
}
// switch channel on Aux PHY so that it operates on the link on which the main PHY was operating
@@ -119,6 +125,16 @@ void
DefaultEmlsrManager::DoNotifyTxopEnd(uint8_t linkId)
{
NS_LOG_FUNCTION(this << linkId);
// switch main PHY to the previous link, if needed
if (m_linkIdForMainPhyAfterTxop && linkId != m_linkIdForMainPhyAfterTxop)
{
auto phy = m_auxPhyToReconnect;
SwitchMainPhy(*m_linkIdForMainPhyAfterTxop, false);
// Reconnect the aux PHY to its original link
Simulator::ScheduleNow(&StaWifiMac::NotifySwitchingEmlsrLink, GetStaMac(), phy, linkId);
}
m_linkIdForMainPhyAfterTxop.reset();
}
} // namespace ns3

View File

@@ -58,6 +58,12 @@ class DefaultEmlsrManager : public EmlsrManager
bool m_switchAuxPhy; /**< whether Aux PHY should switch channel to operate on the link on which
the Main PHY was operating before moving to the link of the Aux PHY */
std::optional<uint8_t>
m_linkIdForMainPhyAfterTxop; //!< ID of the link the main PHY has to switch to once
//!< the current TXOP terminates
Ptr<WifiPhy> m_auxPhyToReconnect; //!< Aux PHY the ChannelAccessManager of the link on which
//!< the main PHY is operating has to connect a listener to
//!< when the main PHY is back operating on its previous link
};
} // namespace ns3

View File

@@ -177,6 +177,14 @@ class EmlsrManager : public Object
*/
const WifiPhyOperatingChannel& GetChannelForAuxPhy(uint8_t linkId) const;
/**
* Switch channel on the Main PHY so that it operates on the given link.
*
* \param linkId the ID of the link on which the main PHY has to operate
* \param noSwitchDelay whether switching delay should be zero
*/
void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay);
/**
* Switch channel on the Aux PHY operating on the given current link so that it operates
* on the given next link.
@@ -269,14 +277,6 @@ class EmlsrManager : public Object
*/
void ChangeEmlsrMode();
/**
* Switch channel on the Main PHY so that it operates on the given link.
*
* \param linkId the ID of the link on which the main PHY has to operate
* \param noSwitchDelay whether switching delay should be zero
*/
void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay);
/**
* Adjust the operating channel of all the aux PHYs to meet the constraint on the maximum
* channel width supported by aux PHYs.

View File

@@ -2217,6 +2217,9 @@ EmlsrLinkSwitchTest::EmlsrLinkSwitchTest(const Params& params)
m_mainPhyId = 1;
m_establishBaDl = true;
m_duration = Seconds(1.0);
// when aux PHYs do not switch link, the main PHY switches back to its previous link after
// a TXOP, hence the transition delay must exceed the channel switch delay (default: 250us)
m_transitionDelay = {MicroSeconds(256)};
}
void
@@ -2413,25 +2416,27 @@ EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
* └───┘ └──┘
*
*
* AUX PHY switching disabled
* AUX PHY switching disabled (X = main PHY channel switch delay)
*
* |--------- aux PHY A ---------|------ main PHY ------|
* |------------------------------------------ aux PHY A ---------------------------------------
* |-- main PHY --|X|
* ┌───┐ ┌───┐
* │ICF│ │QoS│
* ──────────────────────────┴───┴┬───┬┴───┴┬──┬────────────────────────────────────────────────
* [link 0] │CTS│ │BA│
* └───┘ └──┘
*
*
* |--------- main PHY ----------|
* ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐
* │ICF│ │QoS│ │ICF│ │ICF│ │ICF
* ───┴───┴┬───┬┴───┴┬──┬──────────────────────────────────────────────────┴───┴──┴───┴──┴───┴──
* [link 1]│CTS│ │BA│
* └───┘ └──┘
* |-main|
* |--------- main PHY ----------| |-PHY-| |------ main PHY ------
* ┌───┐ ┌───┐ ┌───┐ ┌───┐
* │ICF│ │QoS│ │ICF│ │QoS
* ───┴───┴┬───┬┴───┴┬──┬──────────────────────────────────────────────────┴───┴───┴───┴┬──┬──
* [link 1]│CTS│ │BA│ │CTS│ │BA│
* └───┘ └──┘ └───┘ └──┘
*
*
* |--------------------- aux PHY B --------------------|--------------- main PHY --------------
* |------------------------------------------ aux PHY B ---------------------------------------
* |-- main PHY --|X|
* ┌───┐ ┌───┐
* │ICF│ │QoS│
* ─────────────────────────────────────────────────┴───┴┬───┬┴───┴┬──┬─────────────────────────
@@ -2451,6 +2456,8 @@ EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
return;
}
NS_TEST_EXPECT_MSG_LT(m_countQoSframes, 4, "Unexpected number of ICFs");
auto mainPhy = m_staMacs[0]->GetDevice()->GetPhy(m_mainPhyId);
auto phyRecvIcf = m_staMacs[0]->GetWifiPhy(linkId); // PHY receiving the ICF
@@ -2458,66 +2465,68 @@ EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
NS_TEST_ASSERT_MSG_EQ(currMainPhyLinkId.has_value(),
true,
"Didn't find the link on which the Main PHY is operating");
NS_TEST_ASSERT_MSG_NE(phyRecvIcf,
nullptr,
"No PHY on the link where ICF " << m_countQoSframes << " was sent");
if (phyRecvIcf && phyRecvIcf != mainPhy)
if (phyRecvIcf != mainPhy)
{
NS_TEST_EXPECT_MSG_LT_OR_EQ(
phyRecvIcf->GetChannelWidth(),
m_auxPhyMaxChWidth,
"Aux PHY that received ICF is operating on a channel whose width exceeds the limit "
<< m_countQoSframes);
"Aux PHY that received ICF "
<< m_countQoSframes << " is operating on a channel whose width exceeds the limit");
}
// if aux PHYs switch links, only the first ICF is received by the main PHY; otherwise,
// the first ICF and the last ICF are received by the main PHY
NS_TEST_EXPECT_MSG_EQ((phyRecvIcf == mainPhy),
(m_countQoSframes == 0 || (!m_switchAuxPhy && m_countQoSframes == 3)),
"Expecting that the ICF was received by the main PHY");
// if aux PHYs do not switch links, the main PHY is operating on its original link when
// the transmission of an ICF starts
NS_TEST_EXPECT_MSG_EQ(m_switchAuxPhy || currMainPhyLinkId == m_mainPhyId,
true,
"Main PHY is operating on an unexpected link ("
<< +currMainPhyLinkId.value() << ", expected " << +m_mainPhyId
<< ")");
auto txDuration =
WifiPhy::CalculateTxDuration(psduMap, txVector, m_apMac->GetWifiPhy(linkId)->GetPhyBand());
// check that PHYs are operating on the expected link after the reception of the ICF
Simulator::Schedule(txDuration + NanoSeconds(1), [=]() {
std::size_t nRxOk = m_switchAuxPhy ? 4 : 3; // successfully received ICFs
if (m_countQoSframes < nRxOk)
{
// the main PHY must be operating on the link where ICF was sent
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(linkId),
mainPhy,
"PHY operating on link where ICF was sent is not the main PHY");
}
// the first ICF is received by the main PHY and no channel switch occurs
if (m_countQoSframes == 0)
{
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf,
mainPhy,
"PHY that received the ICF is not the main PHY");
return;
}
// the main PHY must be operating on the link where ICF was sent
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(linkId),
mainPhy,
"PHY operating on link where ICF was sent is not the main PHY");
// the behavior of Aux PHYs depends on whether they switch channel or not
if (m_switchAuxPhy)
{
NS_TEST_EXPECT_MSG_LT(m_countQoSframes, nRxOk, "Unexpected number of ICFs");
if (mainPhy != phyRecvIcf)
{
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf->IsStateSwitching(),
true,
"Aux PHY expected to switch channel");
}
Simulator::Schedule(phyRecvIcf->GetChannelSwitchDelay(), [=]() {
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
phyRecvIcf,
"PHY operating on link where Main PHY was before switching "
"channel is not the aux PHY that received the ICF");
"The Aux PHY that received the ICF is expected to operate "
"on the link where Main PHY was before switching channel");
});
}
else if (m_countQoSframes < nRxOk)
{
// the first 3 ICFs are actually received by some PHY
NS_TEST_EXPECT_MSG_NE(phyRecvIcf, nullptr, "Expected some PHY to receive the ICF");
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
nullptr,
"No PHY expected to operate on link where Main PHY was "
"before switching channel");
}
else
{
// no PHY received the ICF
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf,
nullptr,
"Expected no PHY to operate on link where ICF is sent");
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf->IsStateSwitching(),
false,
"Aux PHY is not expected to switch channel");
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf->GetPhyBand(),
mainPhy->GetPhyBand(),
"The Aux PHY that received the ICF is expected to operate "
"on the same band as the Main PHY");
}
});
}
@@ -2527,7 +2536,7 @@ EmlsrLinkSwitchTest::CheckResults()
{
NS_TEST_ASSERT_MSG_NE(m_txPsdusPos, 0, "BA agreement establishment not completed");
std::size_t nRxOk = m_switchAuxPhy ? 4 : 3; // successfully received ICFs
const std::size_t nRxOk = 4; // successfully received ICFs
NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(),
m_txPsdusPos + 3 + nRxOk * 4,