wifi: Add unit test to check TX window stalled with non-zero BA threshold
This commit is contained in:
@@ -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 <list>
|
||||
|
||||
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<ListErrorModel> m_errorModel; ///< error rate model to corrupt packets
|
||||
Ptr<WifiNetDevice> 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<uint64_t> 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<MultiModelSpectrumChannel>();
|
||||
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<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
|
||||
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<WifiNetDevice>(apDevices.Get(0));
|
||||
m_staDevice = DynamicCast<WifiNetDevice>(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<ListErrorModel>();
|
||||
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<PacketSocketClient>();
|
||||
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<PacketSocketServer>();
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user