wifi: Extend EMLSR test to check UL TXOP with aux PHY switch true

This commit is contained in:
Stefano Avallone
2024-03-05 12:35:07 +01:00
parent ee4f63a54a
commit 5224d5c24c
2 changed files with 214 additions and 49 deletions

View File

@@ -3487,6 +3487,8 @@ EmlsrLinkSwitchTest::EmlsrLinkSwitchTest(const Params& params)
m_resetCamState(params.resetCamState),
m_auxPhyMaxChWidth(params.auxPhyMaxChWidth),
m_countQoSframes(0),
m_countIcfFrames(0),
m_countRtsFrames(0),
m_txPsdusPos(0)
{
m_nEmlsrStations = 1;
@@ -3497,7 +3499,7 @@ EmlsrLinkSwitchTest::EmlsrLinkSwitchTest(const Params& params)
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)};
m_transitionDelay = {MicroSeconds(128)};
}
void
@@ -3547,12 +3549,6 @@ EmlsrLinkSwitchTest::Transmit(Ptr<WifiMac> mac,
{0},
linksToBlock);
}
else if (category == WifiActionHeader::BLOCK_ACK &&
action.blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_RESPONSE)
{
// store the current number of transmitted frame
m_txPsdusPos = m_txPsdus.size() - 1;
}
}
break;
@@ -3564,6 +3560,27 @@ EmlsrLinkSwitchTest::Transmit(Ptr<WifiMac> mac,
CheckQosFrames(psduMap, txVector, linkId);
break;
case WIFI_MAC_CTL_RTS:
// corrupt the first RTS frame (sent by the EMLSR client)
if (++m_countRtsFrames == 1)
{
m_errorModel->SetList({psdu->GetPacket()->GetUid()});
}
// block transmissions on all other links at non-AP MLD side
{
std::set<uint8_t> links{0, 1, 2};
links.erase(linkId);
m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(
WifiQueueBlockedReason::TID_NOT_MAPPED,
AC_BE,
{WIFI_QOSDATA_QUEUE},
m_apMac->GetAddress(),
m_staMacs[0]->GetAddress(),
{0},
links);
}
break;
default:;
}
}
@@ -3575,9 +3592,16 @@ EmlsrLinkSwitchTest::DoSetup()
Config::SetDefault("ns3::EmlsrManager::ResetCamState", BooleanValue(m_resetCamState));
Config::SetDefault("ns3::EmlsrManager::AuxPhyChannelWidth", UintegerValue(m_auxPhyMaxChWidth));
Config::SetDefault("ns3::WifiPhy::ChannelSwitchDelay", TimeValue(MicroSeconds(75)));
Config::SetDefault("ns3::EhtConfiguration::MediumSyncDuration", TimeValue(Time{0}));
EmlsrOperationsTestBase::DoSetup();
m_errorModel = CreateObject<ListErrorModel>();
for (std::size_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
{
m_apMac->GetWifiPhy(linkId)->SetPostReceptionErrorModel(m_errorModel);
}
// use channels of different widths
for (auto mac : std::initializer_list<Ptr<WifiMac>>{m_apMac, m_staMacs[0]})
{
@@ -3665,18 +3689,59 @@ EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
// hence triggering yet another link switching on the EMLSR client
m_apMac->GetDevice()->GetNode()->AddApplication(GetApplication(DOWNLINK, 0, 2, 1000));
break;
case 4:
// block transmissions on all links at non-AP MLD side
m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
AC_BE,
{WIFI_QOSDATA_QUEUE},
m_apMac->GetAddress(),
m_staMacs[0]->GetAddress(),
{0},
{0, 1, 2});
// unblock transmissions on the link used for ML setup (non-AP MLD side)
m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
AC_BE,
{WIFI_QOSDATA_QUEUE},
m_apMac->GetAddress(),
m_staMacs[0]->GetAddress(),
{0},
{m_mainPhyId});
// trigger establishment of BA agreement with AP as recipient
m_staMacs[0]->GetDevice()->GetNode()->AddApplication(GetApplication(UPLINK, 0, 4, 1000));
break;
case 5:
// unblock transmissions on all links at non-AP MLD side
m_staMacs[0]->GetMacQueueScheduler()->UnblockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
AC_BE,
{WIFI_QOSDATA_QUEUE},
m_apMac->GetAddress(),
m_staMacs[0]->GetAddress(),
{0},
{0, 1, 2});
// block transmissions on the link used for ML setup (non-AP MLD side)
m_staMacs[0]->GetMacQueueScheduler()->BlockQueues(WifiQueueBlockedReason::TID_NOT_MAPPED,
AC_BE,
{WIFI_QOSDATA_QUEUE},
m_apMac->GetAddress(),
m_staMacs[0]->GetAddress(),
{0},
{m_mainPhyId});
// generate a new data packet, which will be sent on a link other than the one
// used for ML setup, hence triggering a link switching on the EMLSR client
m_staMacs[0]->GetDevice()->GetNode()->AddApplication(GetApplication(UPLINK, 0, 2, 1000));
break;
}
}
/**
* AUX PHY switching enabled
* AUX PHY switching enabled (X = channel switch delay)
*
* |--------- aux PHY A ---------|------ main PHY ------|-------------- aux PHY B -------------
* ┌───┐ ┌───┐
* │ICF│ │QoS│
* ──────────────────────────┴───┴┬───┬┴───┴┬──┬────────────────────────────────────────────────
* [link 0] │CTS│ │BA│
* └───┘ └──┘
* [link 0] │CTS│ │BA│
* └───┘ └──┘
*
*
* |--------- main PHY ----------|------------------ aux PHY A ----------------|--- main PHY ---
@@ -3694,8 +3759,28 @@ EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
* [link 2] │CTS│ │BA│
* └───┘ └──┘
*
* ... continued ...
*
* AUX PHY switching disabled (X = main PHY channel switch delay)
* |----------------------------------------- aux PHY B ---------------------------------------
* ─────────────────────────────────────────────────────────────────────────────────────────────
* [link 0]
*
* |--------- main PHY ----------|X|X|------------------------ aux PHY A ----------------------
* ┌───┐
* │ACK│
* ──────────┬───┬┴───┴────────────────────────────────────────────────────────────────────────
* [link 1] │QoS│
* └───┘
*
* |-------- aux PHY A ----------|X|---------------------- main PHY ---------------------------
* ┌──┐
* │BA│
* ────────────────────────┬───X──────┬───┬┴──┴────────────────────────────────────────────────
* [link 2] │RTS│ │QoS│
* └───┘ └───┘
************************************************************************************************
*
* AUX PHY switching disabled (X = channel switch delay)
*
* |------------------------------------------ aux PHY A ---------------------------------------
* |-- main PHY --|X|
@@ -3721,6 +3806,28 @@ EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
* ─────────────────────────────────────────────────┴───┴┬───┬┴───┴┬──┬─────────────────────────
* [link 2] │CTS│ │BA│
* └───┘ └──┘
*
* ... continued ...
*
* |----------------------------------------- aux PHY A ---------------------------------------
* ─────────────────────────────────────────────────────────────────────────────────────────────
* [link 0]
*
* |-------- main PHY --------| |--- main PHY ---|
* ┌───┐
* │ACK│
* ──────────┬───┬┴───┴────────────────────────────────────────────────────────────────────────
* [link 1] │QoS│
* └───┘
*
* |------------------------------------------ aux PHY B --------------------------------------
* |X||X| |X|-------------- main PHY --------------
* ┌───┐ ┌──┐
* │CTS│ │BA│
* ────────────────────────┬───X───────────────┬───┬┴───┴┬───┬┴──┴─────────────────────────────
* [link 2] │RTS│ │RTS│ │QoS│
* └───┘ └───┘ └───┘
*
*/
void
@@ -3728,14 +3835,16 @@ EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
const WifiTxVector& txVector,
uint8_t linkId)
{
if (m_txPsdusPos == 0)
if (++m_countIcfFrames == 1)
{
// the iterator has not been set yet, thus we are not done with the establishment of
// the BA agreement
return;
m_txPsdusPos = m_txPsdus.size() - 1;
}
NS_TEST_EXPECT_MSG_LT(m_countQoSframes, 4, "Unexpected number of ICFs");
// the first ICF is sent to protect ADDBA_REQ for DL BA agreement, then one ICF is sent before
// each of the 4 DL QoS Data frames; finally, another ICF is sent before the ADDBA_RESP for UL
// BA agreement. Hence, at any time the number of ICF sent is always greater than or equal to
// the number of QoS data frames sent.
NS_TEST_EXPECT_MSG_GT_OR_EQ(m_countIcfFrames, m_countQoSframes, "Unexpected number of ICFs");
auto mainPhy = m_staMacs[0]->GetDevice()->GetPhy(m_mainPhyId);
auto phyRecvIcf = m_staMacs[0]->GetWifiPhy(linkId); // PHY receiving the ICF
@@ -3757,10 +3866,12 @@ EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
<< 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
// the first two ICFs (before ADDBA_REQ and before first DL QoS Data) and the ICF before the
// ADDBA_RESP are received by the main PHY. If aux PHYs do not switch links, the ICF before
// the last DL QoS Data is also received by the main PHY
NS_TEST_EXPECT_MSG_EQ((phyRecvIcf == mainPhy),
(m_countQoSframes == 0 || (!m_switchAuxPhy && m_countQoSframes == 3)),
(m_countIcfFrames == 1 || m_countIcfFrames == 2 ||
(!m_switchAuxPhy && m_countIcfFrames == 5) || m_countIcfFrames == 6),
"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
@@ -3815,36 +3926,86 @@ EmlsrLinkSwitchTest::CheckResults()
{
NS_TEST_ASSERT_MSG_NE(m_txPsdusPos, 0, "BA agreement establishment not completed");
const std::size_t nRxOk = 4; // successfully received ICFs
// Expected frame exchanges after ML setup and EML OMN exchange:
// 1. (DL) ICF + CTS + ADDBA_REQ + ACK
// 2. (UL) ADDBA_RESP + ACK
// 3. (DL) ICF + CTS + DATA + BA
// 4. (DL) ICF + CTS + DATA + BA
// 5. (DL) ICF + CTS + DATA + BA
// 6. (DL) ICF + CTS + DATA + BA
// 7. (UL) ADDBA_REQ + ACK
// 8. (DL) ICF + CTS + ADDBA_RESP + ACK
// 9. (UL) DATA + BA
// 10. (UL) RTS - CTS timeout
// 11. (UL) (RTS + CTS if SwitchAuxPhy is false + ) DATA + BA
NS_TEST_EXPECT_MSG_EQ(m_countIcfFrames, 6, "Unexpected number of ICFs sent");
// frame exchanges without RTS because the EMLSR client sent the initial frame through main PHY
const std::size_t nFrameExchNoRts = m_switchAuxPhy ? 4 : 3;
const std::size_t nFrameExchWithRts = m_switchAuxPhy ? 0 : 1;
NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(),
m_txPsdusPos + 2 + nRxOk * 4,
m_txPsdusPos +
m_countIcfFrames * 4 + /* frames in frame exchange with ICF */
nFrameExchNoRts * 2 + /* frames in frame exchange without RTS */
nFrameExchWithRts * 4 + /* frames in frame exchange with RTS */
1, /* corrupted RTS */
"Insufficient number of TX PSDUs");
// m_txPsdusPos points to ADDBA_RESPONSE, then ACK and then ICF
auto psduIt = std::next(m_txPsdus.cbegin(), m_txPsdusPos + 2);
// m_txPsdusPos points to the first ICF
auto psduIt = std::next(m_txPsdus.cbegin(), m_txPsdusPos);
for (std::size_t i = 0; i < nRxOk; i++)
const std::size_t nFrameExchanges =
m_countIcfFrames + nFrameExchNoRts + nFrameExchWithRts + 1 /* corrupted RTS */;
for (std::size_t i = 1; i <= nFrameExchanges; ++i)
{
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsTrigger()),
true,
"Expected a Trigger Frame (ICF)");
psduIt++;
NS_TEST_EXPECT_MSG_EQ(
(psduIt->psduMap.size() == 1 && psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsCts()),
true,
"Expected a CTS");
psduIt++;
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsQosData()),
true,
"Expected a QoS Data frame");
psduIt++;
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsBlockAck()),
true,
"Expected a BlockAck");
if (i == 1 || (i >= 3 && i <= 6) || i == 8 || i == 10 || (i == 11 && !m_switchAuxPhy))
{
// frame exchanges with protection
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
(i < 9 ? psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsTrigger()
: psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsRts())),
true,
"Expected a Trigger Frame (ICF)");
psduIt++;
if (i == 10)
{
continue; // corrupted RTS
}
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsCts()),
true,
"Expected a CTS");
psduIt++;
}
if (i == 1 || i == 2 || i == 7 || i == 8) // frame exchanges with ADDBA REQ/RESP frames
{
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsMgt()),
true,
"Expected a management frame");
psduIt++;
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsAck()),
true,
"Expected a Normal Ack");
}
else
{
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsQosData()),
true,
"Expected a QoS Data frame");
psduIt++;
NS_TEST_EXPECT_MSG_EQ((psduIt->psduMap.size() == 1 &&
psduIt->psduMap.at(SU_STA_ID)->GetHeader(0).IsBlockAck()),
true,
"Expected a BlockAck");
}
psduIt++;
}
}

View File

@@ -669,9 +669,10 @@ class EmlsrUlTxopTest : public EmlsrOperationsTestBase
* - the first one on the link used for ML setup, hence no PHY switch occurs
* - the second one on another link, thus causing the main PHY to switch link
* - the third one on the remaining link, thus causing the main PHY to switch link again
* - the fourth one on the link used for ML setup; if the aux PHYs switches link, there is
* one aux PHY listening on such a link and the main PHY switches to this link, otherwise
* no PHY is listening on such a link and there is no response to the ICF sent by the AP MLD
* - the fourth one on the link used for ML setup
*
* Afterwards, the EMLSR client transmits 2 QoS data frames; the first one on the link used for
* ML setup (hence, no RTS is sent), the second one on another link.
*/
class EmlsrLinkSwitchTest : public EmlsrOperationsTestBase
{
@@ -741,9 +742,12 @@ class EmlsrLinkSwitchTest : public EmlsrOperationsTestBase
the Main PHY was operating before moving to the link of Aux PHY */
bool m_resetCamState; /**< whether to reset the state of the ChannelAccessManager associated
with the link on which the main PHY has just switched to */
MHz_u m_auxPhyMaxChWidth; //!< max channel width supported by aux PHYs
std::size_t m_countQoSframes; //!< counter for QoS data frames
std::size_t m_txPsdusPos; //!< a position in the vector of TX PSDUs
MHz_u m_auxPhyMaxChWidth; //!< max channel width supported by aux PHYs
std::size_t m_countQoSframes; //!< counter for QoS data frames
std::size_t m_countIcfFrames; //!< counter for ICF frames
std::size_t m_countRtsFrames; //!< counter for RTS frames
std::size_t m_txPsdusPos; //!< position in the vector of TX PSDUs of the first ICF
Ptr<ListErrorModel> m_errorModel; ///< error rate model to corrupt packets at AP MLD
};
/**