From e9361ef6c8c4482ce481be583cfb708a08f0ae94 Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Mon, 1 Jul 2024 13:51:45 +0200 Subject: [PATCH] wifi: Add unit test to check TX window stalled with non-zero BA threshold --- src/wifi/test/block-ack-test-suite.cc | 243 ++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) diff --git a/src/wifi/test/block-ack-test-suite.cc b/src/wifi/test/block-ack-test-suite.cc index 38af5a604..ca1477c6d 100644 --- a/src/wifi/test/block-ack-test-suite.cc +++ b/src/wifi/test/block-ack-test-suite.cc @@ -12,8 +12,10 @@ #include "ns3/config.h" #include "ns3/ctrl-headers.h" #include "ns3/double.h" +#include "ns3/frame-exchange-manager.h" #include "ns3/mac-rx-middle.h" #include "ns3/mobility-helper.h" +#include "ns3/multi-model-spectrum-channel.h" #include "ns3/originator-block-ack-agreement.h" #include "ns3/packet-socket-client.h" #include "ns3/packet-socket-helper.h" @@ -23,17 +25,23 @@ #include "ns3/qos-txop.h" #include "ns3/qos-utils.h" #include "ns3/recipient-block-ack-agreement.h" +#include "ns3/spectrum-wifi-helper.h" #include "ns3/string.h" #include "ns3/test.h" +#include "ns3/wifi-default-ack-manager.h" #include "ns3/wifi-mac-header.h" +#include "ns3/wifi-mac-queue.h" #include "ns3/wifi-mpdu.h" #include "ns3/wifi-net-device.h" +#include "ns3/wifi-phy.h" #include "ns3/yans-wifi-helper.h" #include using namespace ns3; +NS_LOG_COMPONENT_DEFINE("WifiBlockAckTest"); + /** * \ingroup wifi-test * \ingroup tests @@ -1999,6 +2007,239 @@ BlockAckAggregationDisabledTest::DoRun() } } +/** + * \ingroup wifi-test + * \ingroup tests + * + * \brief Test for Block Ack Policy with non-null BA threshold and TX window blocked. + * + * An EHT device establishes a Block Ack agreement (for TID 0) with the AP and uses a Block Ack + * threshold of 0.125 (i.e., Block Ack is requested if there are at least 64 * 0.125 = 8 MPDUs + * to be acknowledged, where 64 is the Block Ack buffer size). An application installed on the + * non-AP node generates 70 packets, hence an A-MPDU containing the first 64 MPDUs is transmitted. + * The first 5 MPDUs in that A-MPDU are corrupted. We check that: + * + * - the first A-MPDU contains MPDUs with sequence numbers from 0 to 63 + * - the second A-MPDU contains the 5 retransmitted MPDUs (with sequence numbers from 0 to 4) only, + * because the TX window is blocked + * - the third A-MPDU contains the remaining 6 MPDUs (with sequence numbers from 64 to 69) + * - 3 A-MPDUs and 3 BlockAck frames are transmitted during the simulation + * - the MAC queue is empty at the end of simulation (meaning that all MPDUs were acknowledged) + */ +class OrigBlockAckWindowStalled : public TestCase +{ + public: + /** + * \param mld whether the non-AP device is a multi-link device + */ + OrigBlockAckWindowStalled(bool mld); + + /** + * Callback invoked when a FEM passes PSDUs to the PHY. + * + * \param psduMap the PSDU map + * \param txVector the TX vector + * \param txPowerW the tx power in Watts + */ + void Transmit(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW); + + private: + void DoSetup() override; + void DoRun() override; + + const uint8_t m_nLinks; ///< number of links + const double m_baThreshold{0.125}; ///< BA threshold used by ack manager + const std::size_t m_nPkts{70}; ///< number of generated packets + Ptr m_errorModel; ///< error rate model to corrupt packets + Ptr m_staDevice; ///< station WifiNetDevice + std::size_t m_qosCount{0}; ///< counter for transmitted QoS data frames + std::size_t m_baCount{0}; ///< counter for transmitted BlockAck frames +}; + +OrigBlockAckWindowStalled::OrigBlockAckWindowStalled(bool mld) + : TestCase("Test case for originator Block Ack window stalled"), + m_nLinks(mld ? 2 : 1) +{ +} + +void +OrigBlockAckWindowStalled::Transmit(WifiConstPsduMap psduMap, + WifiTxVector txVector, + double txPowerW) +{ + for (const auto& [aid, psdu] : psduMap) + { + std::stringstream ss; + ss << " #MPDUs " << psdu->GetNMpdus(); + for (const auto& mpdu : *PeekPointer(psdu)) + { + ss << "\n" << *mpdu; + } + + if (const auto& hdr = (*psdu->begin())->GetHeader(); hdr.IsQosData()) + { + // check sequence numbers in the transmitted A-MPDU + uint16_t startSeqN{0}; + std::size_t count{0}; + + switch (++m_qosCount) + { + case 1: + startSeqN = 0; + count = 64; + break; + case 2: + startSeqN = 0; + count = 5; + break; + case 3: + startSeqN = 64; + count = 6; + break; + default:; + } + + NS_TEST_EXPECT_MSG_EQ(psdu->GetNMpdus(), + count, + "Unexpected number of MPDUs in A-MPDU #" << m_qosCount); + + for (const auto& mpdu : *PeekPointer(psdu)) + { + NS_TEST_EXPECT_MSG_GT_OR_EQ(mpdu->GetHeader().GetSequenceNumber(), + startSeqN, + "Unexpected SeqN in A-MPDU #" << m_qosCount); + NS_TEST_EXPECT_MSG_LT(mpdu->GetHeader().GetSequenceNumber(), + startSeqN + count, + "Unexpected SeqN in A-MPDU #" << m_qosCount); + } + + // reset UIDs to corrupt + m_errorModel->SetList({}); + + // corrupt the first 5 MPDUs of the second QoS data frame + if (m_qosCount == 1) + { + auto mpduIt = psdu->begin(); + std::list uids; + ss << "\nCORRUPTED"; + for (std::size_t i = 0; i < 5; ++i, ++mpduIt) + { + uids.push_back((*mpduIt)->GetPacket()->GetUid()); + ss << " " << (*mpduIt)->GetHeader().GetSequenceNumber(); + } + m_errorModel->SetList(uids); + } + } + else if (hdr.IsBlockAck()) + { + ++m_baCount; + } + + NS_LOG_INFO(ss.str()); + } + NS_LOG_INFO("TXVECTOR = " << txVector << "\n"); +} + +void +OrigBlockAckWindowStalled::DoSetup() +{ + NodeContainer wifiStaNode(1); + NodeContainer wifiApNode(1); + + auto channel = CreateObject(); + SpectrumWifiPhyHelper phy(m_nLinks); + phy.Set(0, "ChannelSettings", StringValue("{36, 0, BAND_5GHZ, 0}")); + if (m_nLinks > 1) + { + phy.Set(1, "ChannelSettings", StringValue("{100, 0, BAND_5GHZ, 0}")); + } + phy.SetChannel(channel); + + WifiHelper wifi; + wifi.SetStandard(WIFI_STANDARD_80211be); + wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager", + "DataMode", + StringValue("EhtMcs7"), + "ControlMode", + StringValue("EhtMcs0")); + + WifiMacHelper mac; + mac.SetAckManager("ns3::WifiDefaultAckManager", "BaThreshold", DoubleValue(m_baThreshold)); + mac.SetType("ns3::StaWifiMac", "MpduBufferSize", UintegerValue(64)); + + auto staDevices = wifi.Install(phy, mac, wifiStaNode); + + mac.SetType("ns3::ApWifiMac"); + + auto apDevices = wifi.Install(phy, mac, wifiApNode); + + Ptr positionAlloc = CreateObject(); + positionAlloc->Add(Vector(0.0, 0.0, 0.0)); + positionAlloc->Add(Vector(1.0, 0.0, 0.0)); + + MobilityHelper mobility; + mobility.SetPositionAllocator(positionAlloc); + mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel"); + mobility.Install(wifiApNode); + mobility.Install(wifiStaNode); + + auto apDevice = DynamicCast(apDevices.Get(0)); + m_staDevice = DynamicCast(staDevices.Get(0)); + + Config::ConnectWithoutContext( + "/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phys/*/PhyTxPsduBegin", + MakeCallback(&OrigBlockAckWindowStalled::Transmit, this)); + + // install post reception error model on AP + m_errorModel = CreateObject(); + apDevice->GetPhy(0)->SetPostReceptionErrorModel(m_errorModel); + if (m_nLinks > 1) + { + apDevice->GetPhy(1)->SetPostReceptionErrorModel(m_errorModel); + } + + PacketSocketAddress socket; + socket.SetSingleDevice(m_staDevice->GetIfIndex()); + socket.SetPhysicalAddress(apDevice->GetAddress()); + socket.SetProtocol(1); + + // give packet socket powers to nodes. + PacketSocketHelper packetSocket; + packetSocket.Install(wifiStaNode); + packetSocket.Install(wifiApNode); + + auto client = CreateObject(); + client->SetAttribute("PacketSize", UintegerValue(100)); + client->SetAttribute("MaxPackets", UintegerValue(m_nPkts)); + client->SetAttribute("Interval", TimeValue(Time{0})); + client->SetRemote(socket); + wifiStaNode.Get(0)->AddApplication(client); + client->SetStartTime(Seconds(0.5)); + client->SetStopTime(Seconds(3.0)); + + auto server = CreateObject(); + server->SetLocal(socket); + wifiApNode.Get(0)->AddApplication(server); + server->SetStartTime(Seconds(0.0)); + server->SetStopTime(Seconds(4.0)); +} + +void +OrigBlockAckWindowStalled::DoRun() +{ + Simulator::Stop(Seconds(3)); + Simulator::Run(); + + NS_TEST_EXPECT_MSG_EQ(m_qosCount, 3, "Unexpected number of transmitted QoS data frames"); + NS_TEST_EXPECT_MSG_EQ(m_baCount, 3, "Unexpected number of transmitted BlockAck frames"); + + NS_TEST_EXPECT_MSG_EQ(m_staDevice->GetMac()->GetTxopQueue(AC_BE)->IsEmpty(), + true, + "Expected no packet in STA queue"); + + Simulator::Destroy(); +} + /** * \ingroup wifi-test * \ingroup tests @@ -2023,6 +2264,8 @@ BlockAckTestSuite::BlockAckTestSuite() AddTestCase(new MultiStaCtrlBAckResponseHeaderTest, TestCase::Duration::QUICK); AddTestCase(new BlockAckAggregationDisabledTest(false), TestCase::Duration::QUICK); AddTestCase(new BlockAckAggregationDisabledTest(true), TestCase::Duration::QUICK); + AddTestCase(new OrigBlockAckWindowStalled(false), TestCase::Duration::QUICK); + AddTestCase(new OrigBlockAckWindowStalled(true), TestCase::Duration::QUICK); } static BlockAckTestSuite g_blockAckTestSuite; ///< the test suite