wifi: Extend EMLSR test case to check main PHY switch interruption when aux PHY gains channel access

This commit is contained in:
Stefano Avallone
2025-03-19 11:46:37 +01:00
parent 9c134bbc45
commit 6ff7c27987
2 changed files with 142 additions and 24 deletions

View File

@@ -641,6 +641,12 @@ EmlsrOperationsTestBase::SetSsid(std::size_t count)
StartTraffic();
// stop generation of beacon frames in order to avoid interference
m_apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
// Set the short slot time on the 2.4 GHz link because it is not updated automatically given
// that no more Beacon frames are sent
for (std::size_t id = 0; id < m_nEmlsrStations + m_nNonEmlsrStations; ++id)
{
m_staMacs[id]->GetDevice()->GetPhy(0)->SetSlot(MicroSeconds(9));
}
// disconnect callbacks
m_apMac->TraceDisconnectWithoutContext(
"AssociatedSta",
@@ -5510,7 +5516,7 @@ EmlsrSwitchMainPhyBackTest::EmlsrSwitchMainPhyBackTest()
m_paddingDelay = {MicroSeconds(64)};
m_transitionDelay = {MicroSeconds(64)};
m_establishBaDl = {0};
m_establishBaUl = {0};
m_establishBaUl = {0, 4};
m_duration = Seconds(0.5);
}
@@ -5522,7 +5528,8 @@ EmlsrSwitchMainPhyBackTest::DoSetup()
Config::SetDefault("ns3::DefaultEmlsrManager::SwitchAuxPhy", BooleanValue(false));
Config::SetDefault("ns3::EmlsrManager::AuxPhyTxCapable", BooleanValue(false));
// Use only link 1 for DL and UL traffic
std::string mapping = "0 " + std::to_string(m_linkIdForTid0);
std::string mapping =
"0 " + std::to_string(m_linkIdForTid0) + "; 4 " + std::to_string(m_linkIdForTid4);
Config::SetDefault("ns3::EhtConfiguration::TidToLinkMappingDl", StringValue(mapping));
Config::SetDefault("ns3::EhtConfiguration::TidToLinkMappingUl", StringValue(mapping));
Config::SetDefault("ns3::EmlsrManager::AuxPhyMaxModClass", StringValue("HT"));
@@ -5621,6 +5628,33 @@ EmlsrSwitchMainPhyBackTest::MainPhySwitchInfoCallback(std::size_t index,
return;
}
// lambda to generate a frame with TID 4 and to handle the corresponding frames
auto genTid4Frame = [=, this]() {
m_dlPktDone = true;
// in 5 microseconds, while still switching, generate a packet with TID 4, which causes a
// channel access request on link 0; if switching can be interrupted, the main PHY starts
// switching to link 0 as soon as channel access is gained on link 0
Simulator::Schedule(MicroSeconds(5), [=, this]() {
m_staMacs[0]->GetDevice()->GetNode()->AddApplication(
GetApplication(UPLINK, 0, 1, 500, 4));
// channel access can be obtained within a slot due to slot alignment
Simulator::Schedule(m_apMac->GetWifiPhy(m_linkIdForTid4)->GetSlot(), [=, this]() {
auto advEmlsrMgr =
DynamicCast<AdvancedEmlsrManager>(m_staMacs[0]->GetEmlsrManager());
NS_TEST_EXPECT_MSG_EQ(advEmlsrMgr->m_mainPhySwitchInfo.disconnected,
true,
"Expected the main PHY to be switching");
NS_TEST_EXPECT_MSG_EQ(
+advEmlsrMgr->m_mainPhySwitchInfo.to,
+(advEmlsrMgr->m_interruptSwitching ? m_linkIdForTid4 : m_mainPhyId),
"Main PHY is switching to wrong link");
});
});
InsertEventsForQosTid4();
};
if (m_expectedMainPhySwitchBackTime == Simulator::Now() &&
info.GetName() == "TxopNotGainedOnAuxPhyLink")
{
@@ -5704,7 +5738,8 @@ EmlsrSwitchMainPhyBackTest::MainPhySwitchInfoCallback(std::size_t index,
default:
NS_TEST_ASSERT_MSG_EQ(true, false, "Unexpected scenario: " << +m_testIndex);
}
m_dlPktDone = true;
genTid4Frame();
}
if (m_expectedMainPhySwitchBackTime == Simulator::Now() && info.GetName() == "TxopEnded")
@@ -5715,10 +5750,75 @@ EmlsrSwitchMainPhyBackTest::MainPhySwitchInfoCallback(std::size_t index,
+static_cast<uint8_t>(NON_HT_PPDU_DONT_USE_MAC_HDR),
"Unexpected TxopEnded reason for switching main PHY back");
m_dlPktDone = true;
genTid4Frame();
}
}
void
EmlsrSwitchMainPhyBackTest::InsertEventsForQosTid4()
{
const auto testIndex = static_cast<TestScenario>(m_testIndex);
std::list<Events> events;
events.emplace_back(
WIFI_MAC_QOSDATA,
[=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, uint8_t linkId) {
NS_TEST_EXPECT_MSG_EQ(+linkId,
+m_linkIdForTid4,
"Unicast frame with TID 4 transmitted on wrong link");
NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr1(),
m_apMac->GetFrameExchangeManager(linkId)->GetAddress(),
"Unexpected RA for the unicast frame with TID 4");
NS_TEST_EXPECT_MSG_EQ(psdu->GetAddr2(),
m_staMacs[0]->GetFrameExchangeManager(linkId)->GetAddress(),
"Unexpected TA for the unicast frame with TID 4");
NS_TEST_EXPECT_MSG_EQ(+(*psdu->GetTids().cbegin()),
4,
"Expected a unicast frame with TID 4");
// if switching can be interrupted, the frame with TID 4 is transmitted as soon as
// the main PHY completes the switching to link 0
if (auto advEmlsrMgr =
DynamicCast<AdvancedEmlsrManager>(m_staMacs[0]->GetEmlsrManager());
advEmlsrMgr->m_interruptSwitching)
{
auto mainPhy = m_staMacs[0]->GetDevice()->GetPhy(m_mainPhyId);
NS_TEST_EXPECT_MSG_EQ(advEmlsrMgr->m_mainPhySwitchInfo.start +
mainPhy->GetChannelSwitchDelay(),
Simulator::Now(),
"Expected TX to start at main PHY switch end");
}
});
events.emplace_back(WIFI_MAC_CTL_ACK);
events.emplace_back(
WIFI_MAC_CTL_END,
[=, this](Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector, uint8_t linkId) {
if (testIndex == NON_HT_PPDU_DONT_USE_MAC_HDR)
{
Simulator::Schedule(MilliSeconds(2), [=, this]() {
// check that trace infos have been received
NS_TEST_EXPECT_MSG_EQ(m_dlPktDone,
true,
"Did not receive the expected trace infos");
NS_TEST_EXPECT_MSG_EQ(m_events.empty(), true, "Not all events took place");
if (++m_testIndex < static_cast<uint8_t>(COUNT))
{
RunOne();
}
});
}
});
// In the NON_HT_PPDU_DONT_USE_MAC_HDR scenario, the main PHY does not switch back to the
// preferred link after the transmission of the broadcast frame, so the QoS data frame with
// TID 0 is transmitted (on link 1) before the QoS data frame with TID 4 (on link 0)
const auto pos =
(testIndex == NON_HT_PPDU_DONT_USE_MAC_HDR ? m_events.cend() : m_events.cbegin());
m_events.splice(pos, events);
}
void
EmlsrSwitchMainPhyBackTest::RunOne()
{
@@ -5745,7 +5845,9 @@ EmlsrSwitchMainPhyBackTest::RunOne()
m_switchMainPhyBackDelay -= MicroSeconds(250);
}
const auto interruptSwitch = (testIndex == RXSTART_WHILE_SWITCH_INTERRUPT);
const auto interruptSwitch =
(testIndex == RXSTART_WHILE_SWITCH_INTERRUPT || testIndex == NON_HT_PPDU_DONT_USE_MAC_HDR ||
testIndex == LONG_SWITCH_BACK_DELAY_USE_MAC_HDR);
const auto useMacHeader =
(testIndex == NON_HT_PPDU_USE_MAC_HDR || testIndex == LONG_SWITCH_BACK_DELAY_USE_MAC_HDR);
@@ -5755,6 +5857,9 @@ EmlsrSwitchMainPhyBackTest::RunOne()
TimeValue(m_switchMainPhyBackDelay));
m_staMacs[0]->GetEmlsrManager()->SetAttribute("InterruptSwitch", BooleanValue(interruptSwitch));
m_staMacs[0]->GetEmlsrManager()->SetAttribute("UseNotifiedMacHdr", BooleanValue(useMacHeader));
m_staMacs[0]->GetEmlsrManager()->SetAttribute("CheckAccessOnMainPhyLink", BooleanValue(false));
// no in-device interference, just to avoid starting MSD timer causing RTS-CTS exchanges
m_staMacs[0]->GetEmlsrManager()->SetAttribute("InDeviceInterference", BooleanValue(false));
NS_LOG_INFO("Starting test #" << +m_testIndex << "\n");
m_dlPktDone = false;
@@ -6062,19 +6167,21 @@ EmlsrSwitchMainPhyBackTest::RunOne()
// main PHY is expected to switch back when the UL TXOP ends
m_expectedMainPhySwitchBackTime = Simulator::Now() + txDuration;
}
else
{
Simulator::Schedule(MilliSeconds(2), [=, this]() {
// check that trace infos have been received
NS_TEST_EXPECT_MSG_EQ(m_dlPktDone,
true,
"Did not receive the expected trace infos");
NS_TEST_EXPECT_MSG_EQ(m_events.empty(), true, "Not all events took place");
Simulator::Schedule(MilliSeconds(2), [=, this]() {
// check that trace infos have been received
NS_TEST_EXPECT_MSG_EQ(m_dlPktDone,
true,
"Did not receive the expected trace infos");
NS_TEST_EXPECT_MSG_EQ(m_events.empty(), true, "Not all events took place");
if (++m_testIndex < static_cast<uint8_t>(COUNT))
{
RunOne();
}
});
if (++m_testIndex < static_cast<uint8_t>(COUNT))
{
RunOne();
}
});
}
});
}

View File

@@ -1230,11 +1230,11 @@ class EmlsrIcfSentDuringMainPhySwitchTest : public EmlsrOperationsTestBase
* An AP MLD and an EMLSR client, both having 3 links, are considered in this test. Aux PHYs are
* not TX capable, do not switch links and support up to the HT modulation class; the preferred link
* is link 2. In order to control link switches, a TID-to-Link mapping is configured so that TID 0
* is mapped onto link 1 for both DL and UL. In this test, the main PHY switches to link 1 to start
* an UL TXOP but, while the main PHY is switching or shortly after the channel switch ends, the AP
* MLD transmits a QoS Data broadcast frame on link 1 using a modulation supported by the aux PHYs.
* Different situations are tested and it is verified that the main PHY switches back to the
* preferred link as expected. Scenarios:
* is mapped onto link 1 and TID 4 is mapped onto link 0 (for both DL and UL). In this test, the
* main PHY switches to link 1 to start an UL TXOP but, while the main PHY is switching or shortly
* after the channel switch ends, the AP MLD transmits a QoS Data broadcast frame on link 1 using a
* modulation supported by the aux PHYs. Different situations are tested and it is verified that
* the main PHY switches back to the preferred link as expected. Scenarios:
*
* - RXSTART_WHILE_SWITCH_NO_INTERRUPT: the AP MLD transmits an HT PPDU while the main PHY is
* switching; at the end of the PHY header reception (while the main PHY is still switching), the
@@ -1282,8 +1282,15 @@ class EmlsrIcfSentDuringMainPhySwitchTest : public EmlsrOperationsTestBase
* end of the switch main PHY back timer plus a channel switch delay and the main PHY switches
* back to the preferred link (with reason BACKOFF_END).
*
* In all the cases, it is verified that, after the reception of the broadcast data frame, the EMLSR
* client transmits the data frame and receives the acknowledgment.
* Except for the NON_HT_PPDU_DONT_USE_MAC_HDR case, in which the main PHY stays on link 1 and
* transmits a data frame, receives the Ack and switches back to the preferred link at the TXOP end,
* in all other cases the main PHY switches back to the preferred link without sending a frame on
* link 1. A few microseconds after starting the switch to the preferred link, a frame with TID 4
* is queued. If interrupt switching is enabled, the switch to the preferred link is interrupted
* and the main PHY switches to link 0, where it transmits the data frame with TID 4 as soon as
* completing the switch. Afterwards, the main PHY switches back to the preferred link and, except
* for the NON_HT_PPDU_DONT_USE_MAC_HDR case, it switches to link 1 to transmit the queued frame
* with TID 0.
*/
class EmlsrSwitchMainPhyBackTest : public EmlsrOperationsTestBase
{
@@ -1316,6 +1323,9 @@ class EmlsrSwitchMainPhyBackTest : public EmlsrOperationsTestBase
double txPowerW) override;
void MainPhySwitchInfoCallback(std::size_t index, const EmlsrMainPhySwitchTrace& info) override;
/// Insert events corresponding to the UL TXOP to transmit the QoS Data frame with TID 4
void InsertEventsForQosTid4();
/// Runs a test case and invokes itself for the next test case
void RunOne();
@@ -1349,6 +1359,7 @@ class EmlsrSwitchMainPhyBackTest : public EmlsrOperationsTestBase
std::list<Events> m_events; //!< list of events for a test run
std::size_t m_processedEvents{0}; //!< number of processed events
const uint8_t m_linkIdForTid0{1}; //!< ID of the link on which TID 0 is mapped
const uint8_t m_linkIdForTid4{0}; //!< ID of the link on which TID 4 is mapped
Ptr<WifiMpdu> m_bcastFrame; //!< the broadcast frame sent by the AP MLD
Time m_switchMainPhyBackDelay; //!< the switch main PHY back delay
Time m_expectedMainPhySwitchBackTime; //!< expected main PHY switch back time