diff --git a/src/wifi/test/wifi-mac-queue-test.cc b/src/wifi/test/wifi-mac-queue-test.cc index f05d1ddcc..d4a7f9a7b 100644 --- a/src/wifi/test/wifi-mac-queue-test.cc +++ b/src/wifi/test/wifi-mac-queue-test.cc @@ -22,6 +22,8 @@ #include "ns3/test.h" #include "ns3/wifi-mac-queue.h" +#include + using namespace ns3; /** @@ -120,6 +122,312 @@ WifiMacQueueDropOldestTest::DoRun() Simulator::Destroy(); } +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Test extraction of expired MPDUs from MAC queue container + * + * This test verifies the correctness of the WifiMacQueueContainer methods + * (ExtractExpiredMpdus and ExtractAllExpiredMpdus) that extract MPDUs with + * expired lifetime from the MAC queue container. + */ +class WifiExtractExpiredMpdusTest : public TestCase +{ + public: + WifiExtractExpiredMpdusTest(); + + private: + void DoRun() override; + + /** + * Enqueue a new MPDU into the container. + * + * \param rxAddr Receiver Address of the MPDU + * \param inflight whether the MPDU is inflight + * \param expiryTime the expity time for the MPDU + */ + void Enqueue(Mac48Address rxAddr, bool inflight, Time expiryTime); + + WifiMacQueueContainer m_container; //!< MAC queue container + uint16_t m_currentSeqNo{0}; //!< sequence number of current MPDU + Mac48Address m_txAddr; //!< Transmitter Address of MPDUs +}; + +WifiExtractExpiredMpdusTest::WifiExtractExpiredMpdusTest() + : TestCase("Test extraction of expired MPDUs from MAC queue container") +{ +} + +void +WifiExtractExpiredMpdusTest::Enqueue(Mac48Address rxAddr, bool inflight, Time expiryTime) +{ + WifiMacHeader header(WIFI_MAC_QOSDATA); + header.SetAddr1(rxAddr); + header.SetAddr2(m_txAddr); + header.SetQosTid(0); + header.SetSequenceNumber(m_currentSeqNo++); + auto mpdu = Create(Create(), header); + + auto queueId = WifiMacQueueContainer::GetQueueId(mpdu); + auto elemIt = m_container.insert(m_container.GetQueue(queueId).cend(), mpdu); + elemIt->expiryTime = expiryTime; + if (inflight) + { + elemIt->inflights.emplace(0, mpdu); + } + elemIt->deleter = [](auto mpdu) {}; +} + +void +WifiExtractExpiredMpdusTest::DoRun() +{ + m_txAddr = Mac48Address::Allocate(); + auto rxAddr1 = Mac48Address::Allocate(); + auto rxAddr2 = Mac48Address::Allocate(); + + /** + * At simulation time 25ms: + * + * Container queue for rxAddr1 + * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ + * │Exp│Exp│Exp│Exp│ │ │ │ │ │ │ │ + * │Inf│ │Inf│ │Inf│ │Inf│ │ │ │ │ + * │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │10 │ + * └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ + * + * Container queue for rxAddr2 + * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┐ + * │Exp│Exp│Exp│ │ │ │ │ │ │ + * │ │Inf│Inf│ │Inf│Inf│ │ │ │ + * │11 │12 │13 │14 │15 │16 │17 │18 │19 │ + * └───┴───┴───┴───┴───┴───┴───┴───┴───┘ + */ + Enqueue(rxAddr1, true, MilliSeconds(10)); + Enqueue(rxAddr1, false, MilliSeconds(10)); + Enqueue(rxAddr1, true, MilliSeconds(12)); + Enqueue(rxAddr1, false, MilliSeconds(15)); + Enqueue(rxAddr1, true, MilliSeconds(30)); + Enqueue(rxAddr1, false, MilliSeconds(30)); + Enqueue(rxAddr1, true, MilliSeconds(35)); + Enqueue(rxAddr1, false, MilliSeconds(35)); + Enqueue(rxAddr1, false, MilliSeconds(40)); + Enqueue(rxAddr1, false, MilliSeconds(75)); + Enqueue(rxAddr1, false, MilliSeconds(75)); + + Enqueue(rxAddr2, false, MilliSeconds(11)); + Enqueue(rxAddr2, true, MilliSeconds(11)); + Enqueue(rxAddr2, true, MilliSeconds(13)); + Enqueue(rxAddr2, false, MilliSeconds(30)); + Enqueue(rxAddr2, true, MilliSeconds(35)); + Enqueue(rxAddr2, true, MilliSeconds(40)); + Enqueue(rxAddr2, false, MilliSeconds(40)); + Enqueue(rxAddr2, false, MilliSeconds(70)); + Enqueue(rxAddr2, false, MilliSeconds(75)); + + WifiContainerQueueId queueId1{WIFI_QOSDATA_UNICAST_QUEUE, rxAddr1, 0}; + WifiContainerQueueId queueId2{WIFI_QOSDATA_UNICAST_QUEUE, rxAddr2, 0}; + + Simulator::Schedule(MilliSeconds(25), [&]() { + /** + * Extract expired MPDUs from container queue 1 + */ + auto [first1, last1] = m_container.ExtractExpiredMpdus(queueId1); + // MPDU 0 not extracted because inflight, MPDU 1 extracted + NS_TEST_EXPECT_MSG_EQ((first1 != last1), true, "Expected one MPDU extracted"); + NS_TEST_EXPECT_MSG_EQ(first1->mpdu->GetHeader().GetSequenceNumber(), + 1, + "Unexpected extracted MPDU"); + first1++; + // MPDU 2 not extracted because inflight, MPDU 3 extracted + NS_TEST_EXPECT_MSG_EQ((first1 != last1), true, "Expected two MPDUs extracted"); + NS_TEST_EXPECT_MSG_EQ(first1->mpdu->GetHeader().GetSequenceNumber(), + 3, + "Unexpected extracted MPDU"); + first1++; + // No other expired MPDU + NS_TEST_EXPECT_MSG_EQ((first1 == last1), true, "Did not expect other expired MPDUs"); + + // If we try to extract expired MPDUs again, the returned set is empty + { + auto [first, last] = m_container.ExtractExpiredMpdus(queueId1); + NS_TEST_EXPECT_MSG_EQ((first == last), true, "Did not expect other expired MPDUs"); + } + + /** + * Extract expired MPDUs from container queue 2 + */ + auto [first2, last2] = m_container.ExtractExpiredMpdus(queueId2); + // MPDU 11 extracted + NS_TEST_EXPECT_MSG_EQ((first2 != last2), true, "Expected one MPDU extracted"); + NS_TEST_EXPECT_MSG_EQ(first2->mpdu->GetHeader().GetSequenceNumber(), + 11, + "Unexpected extracted MPDU"); + first2++; + // MPDU 12 and 13 not extracted because inflight, no other expired MPDU + NS_TEST_EXPECT_MSG_EQ((first2 == last2), true, "Did not expect other expired MPDUs"); + + // If we try to extract expired MPDUs again, the returned set is empty + { + auto [first, last] = m_container.ExtractExpiredMpdus(queueId2); + NS_TEST_EXPECT_MSG_EQ((first == last), true, "Did not expect other expired MPDUs"); + } + }); + + /** + * At simulation time 50ms: + * + * Container queue for rxAddr1 + * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┐ + * │Exp│Exp│Exp│Exp│Exp│Exp│Exp│ │ │ + * │Inf│Inf│Inf│ │Inf│ │ │ │ │ + * │ 0 │ 2 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │10 │ + * └───┴───┴───┴───┴───┴───┴───┴───┴───┘ + * + * Container queue for rxAddr2 + * ┌───┬───┬───┬───┬───┬───┬───┬───┐ + * │Exp│Exp│Exp│Exp│Exp│Exp│ │ │ + * │Inf│Inf│ │Inf│Inf│ │ │ │ + * │12 │13 │14 │15 │16 │17 │18 │19 │ + * └───┴───┴───┴───┴───┴───┴───┴───┘ + */ + Simulator::Schedule(MilliSeconds(50), [&]() { + /** + * Extract all expired MPDUs (from container queue 1 and 2) + */ + auto [first, last] = m_container.ExtractAllExpiredMpdus(); + + std::set expectedSeqNo{5, 7, 8, 14, 17}; + std::set actualSeqNo; + + std::transform(first, last, std::inserter(actualSeqNo, actualSeqNo.end()), [](auto& elem) { + return elem.mpdu->GetHeader().GetSequenceNumber(); + }); + + NS_TEST_EXPECT_MSG_EQ(expectedSeqNo.size(), + actualSeqNo.size(), + "Unexpected number of MPDUs extracted"); + + for (auto expectedIt = expectedSeqNo.begin(), actualIt = actualSeqNo.begin(); + expectedIt != expectedSeqNo.end(); + ++expectedIt, ++actualIt) + { + NS_TEST_EXPECT_MSG_EQ(*expectedIt, *actualIt, "Unexpected extracted MPDU"); + } + + // If we try to extract expired MPDUs again, the returned set is empty + { + auto [first, last] = m_container.ExtractAllExpiredMpdus(); + NS_TEST_EXPECT_MSG_EQ((first == last), true, "Did not expect other expired MPDUs"); + } + + /** + * Check MPDUs remaining in container queue 1 + */ + auto elemIt = m_container.GetQueue(queueId1).begin(); + auto endIt = m_container.GetQueue(queueId1).end(); + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 1"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 0, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 1"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 2, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 1"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 4, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 1"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 6, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 1"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 9, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 1"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 10, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt == endIt), + true, + "There should be no other MPDU in container queue 1"); + + /** + * Check MPDUs remaining in container queue 2 + */ + elemIt = m_container.GetQueue(queueId2).begin(); + endIt = m_container.GetQueue(queueId2).end(); + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 2"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 12, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 2"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 13, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 2"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 15, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 2"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 16, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 2"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 18, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt != endIt), + true, + "There should be other MPDU(s) in container queue 2"); + NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(), + 19, + "Unexpected queued MPDU"); + elemIt++; + NS_TEST_EXPECT_MSG_EQ((elemIt == endIt), + true, + "There should be no other MPDU in container queue 2"); + }); + + Simulator::Run(); + Simulator::Destroy(); +} + /** * \ingroup wifi-test * \ingroup tests @@ -136,6 +444,7 @@ WifiMacQueueTestSuite::WifiMacQueueTestSuite() : TestSuite("wifi-mac-queue", UNIT) { AddTestCase(new WifiMacQueueDropOldestTest, TestCase::QUICK); + AddTestCase(new WifiExtractExpiredMpdusTest, TestCase::QUICK); } static WifiMacQueueTestSuite g_wifiMacQueueTestSuite; ///< the test suite