A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-aggregation-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
7 */
8
9#include "ns3/config.h"
10#include "ns3/eht-configuration.h"
11#include "ns3/fcfs-wifi-queue-scheduler.h"
12#include "ns3/he-configuration.h"
13#include "ns3/ht-configuration.h"
14#include "ns3/ht-frame-exchange-manager.h"
15#include "ns3/interference-helper.h"
16#include "ns3/mac-tx-middle.h"
17#include "ns3/mgt-action-headers.h"
18#include "ns3/mobility-helper.h"
19#include "ns3/mpdu-aggregator.h"
20#include "ns3/msdu-aggregator.h"
21#include "ns3/multi-link-element.h"
22#include "ns3/node-container.h"
23#include "ns3/packet-socket-client.h"
24#include "ns3/packet-socket-helper.h"
25#include "ns3/packet-socket-server.h"
26#include "ns3/pointer.h"
27#include "ns3/simulator.h"
28#include "ns3/sta-wifi-mac.h"
29#include "ns3/string.h"
30#include "ns3/test.h"
31#include "ns3/vht-configuration.h"
32#include "ns3/wifi-default-ack-manager.h"
33#include "ns3/wifi-default-protection-manager.h"
34#include "ns3/wifi-mac-queue.h"
35#include "ns3/wifi-net-device.h"
36#include "ns3/wifi-psdu.h"
37#include "ns3/yans-wifi-helper.h"
38#include "ns3/yans-wifi-phy.h"
39#include <ns3/attribute-container.h>
40
41#include <algorithm>
42#include <iterator>
43#include <vector>
44
45using namespace ns3;
46
47/**
48 * \ingroup wifi-test
49 * \ingroup tests
50 *
51 * \brief Ampdu Aggregation Test
52 */
54{
55 public:
57
58 /// Test parameters
59 struct Params
60 {
61 WifiStandard standard; //!< the standard of the device
62 uint8_t nLinks; //!< number of links (>1 only for EHT)
63 std::string dataMode; //!< data mode
64 uint16_t bufferSize; //!< the size (in number of MPDUs) of the BlockAck buffer
65 uint16_t maxAmsduSize; //!< maximum A-MSDU size (bytes)
66 uint32_t maxAmpduSize; //!< maximum A-MPDU size (bytes)
67 Time txopLimit; //!< TXOP limit duration
68 };
69
70 /**
71 * Construct object with non-default test parameters
72 *
73 * \param name the name of the test case
74 * \param params the test parameters
75 */
76 AmpduAggregationTest(const std::string& name, const Params& params);
77
78 protected:
79 /**
80 * Establish a BlockAck agreement.
81 *
82 * \param recipient the recipient MAC address
83 */
84 void EstablishAgreement(const Mac48Address& recipient);
85
86 /**
87 * Enqueue the given number of packets addressed to the given station and of the given size.
88 *
89 * \param count the number of packets
90 * \param size the size (bytes) of each packet
91 * \param dest the destination address
92 */
93 void EnqueuePkts(std::size_t count, uint32_t size, const Mac48Address& dest);
94
95 /**
96 * \return the Best Effort QosTxop
97 */
99
100 /**
101 * Dequeue a PSDU.
102 *
103 * \param mpduList the MPDUs contained in the PSDU
104 */
105 void DequeueMpdus(const std::vector<Ptr<WifiMpdu>>& mpduList);
106
108 std::vector<Ptr<WifiPhy>> m_phys; ///< Phys
109 Params m_params; //!< test parameters
110
111 private:
112 /**
113 * Fired when the MAC discards an MPDU.
114 *
115 * \param reason the reason why the MPDU was discarded
116 * \param mpdu the discarded MPDU
117 */
119
120 void DoSetup() override;
121 void DoRun() override;
122 void DoTeardown() override;
123
124 Ptr<WifiNetDevice> m_device; ///< WifiNetDevice
125 std::vector<Ptr<WifiRemoteStationManager>> m_managers; ///< remote station managers
127 bool m_discarded; ///< whether the packet should be discarded
128};
129
131 : AmpduAggregationTest("Check the correctness of MPDU aggregation operations",
132 Params{.standard = WIFI_STANDARD_80211n,
133 .nLinks = 1,
134 .dataMode = "HtMcs7",
135 .bufferSize = 64,
136 .maxAmsduSize = 0,
137 .maxAmpduSize = 65535,
138 .txopLimit = Seconds(0)})
139{
140}
141
142AmpduAggregationTest::AmpduAggregationTest(const std::string& name, const Params& params)
143 : TestCase(name),
144 m_params(params),
145 m_discarded(false)
146{
147}
148
149void
154
155void
157{
158 /*
159 * Create device and attach HT configuration.
160 */
162 m_device->SetStandard(m_params.standard);
163 auto htConfiguration = CreateObject<HtConfiguration>();
164 m_device->SetHtConfiguration(htConfiguration);
166 {
167 auto vhtConfiguration = CreateObject<VhtConfiguration>();
168 m_device->SetVhtConfiguration(vhtConfiguration);
169 auto heConfiguration = CreateObject<HeConfiguration>();
170 m_device->SetHeConfiguration(heConfiguration);
171 }
173 {
174 auto ehtConfiguration = CreateObject<EhtConfiguration>();
175 m_device->SetEhtConfiguration(ehtConfiguration);
176 }
177
178 /*
179 * Create and configure phy layer.
180 */
181 for (uint8_t i = 0; i < m_params.nLinks; i++)
182 {
183 m_phys.emplace_back(CreateObject<YansWifiPhy>());
184 auto interferenceHelper = CreateObject<InterferenceHelper>();
185 m_phys.back()->SetInterferenceHelper(interferenceHelper);
186 m_phys.back()->SetDevice(m_device);
187 m_phys.back()->ConfigureStandard(m_params.standard);
188 }
189 m_device->SetPhys(m_phys);
190
191 /*
192 * Create and configure manager.
193 */
195 m_factory.SetTypeId("ns3::ConstantRateWifiManager");
197 for (uint8_t i = 0; i < m_params.nLinks; i++)
198 {
200 m_managers.back()->SetupPhy(m_phys.at(i));
201 }
202 m_device->SetRemoteStationManagers(m_managers);
203
204 /*
205 * Create and configure mac layer.
206 */
208 "QosSupported",
209 BooleanValue(true),
210 "BE_Txop",
212 "BK_Txop",
214 "VI_Txop",
216 "VO_Txop",
218 m_mac->SetDevice(m_device);
219 m_mac->SetWifiRemoteStationManagers(m_managers);
220 for (uint8_t i = 0; i < m_params.nLinks; i++)
221 {
222 m_managers.at(i)->SetupMac(m_mac);
223 }
224 m_mac->SetAddress(Mac48Address("00:00:00:00:00:01"));
225 m_device->SetMac(m_mac);
226 m_mac->SetWifiPhys(m_phys);
227 std::vector<Ptr<ChannelAccessManager>> caManagers;
228 for (uint8_t i = 0; i < m_params.nLinks; i++)
229 {
230 caManagers.emplace_back(CreateObject<ChannelAccessManager>());
231 }
232 m_mac->SetChannelAccessManagers(caManagers);
233 ObjectFactory femFactory;
235 std::vector<Ptr<FrameExchangeManager>> feManagers;
236 for (uint8_t i = 0; i < m_params.nLinks; i++)
237 {
238 auto fem = femFactory.Create<FrameExchangeManager>();
239 feManagers.emplace_back(fem);
240 auto protectionManager = CreateObject<WifiDefaultProtectionManager>();
241 protectionManager->SetWifiMac(m_mac);
242 fem->SetProtectionManager(protectionManager);
243 auto ackManager = CreateObject<WifiDefaultAckManager>();
244 ackManager->SetWifiMac(m_mac);
245 fem->SetAckManager(ackManager);
246 // here we should assign distinct link addresses in case of MLDs, but we don't actually use
247 // link addresses in this test
248 fem->SetAddress(m_mac->GetAddress());
249 }
250 m_mac->SetFrameExchangeManagers(feManagers);
251 m_mac->SetState(StaWifiMac::ASSOCIATED);
252 if (m_params.nLinks > 1)
253 {
254 // the bssid field of StaLinkEntity must hold a value
255 for (const auto& [id, link] : m_mac->GetLinks())
256 {
258 }
259 }
260 m_mac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
261
262 /*
263 * Configure A-MSDU and A-MPDU aggregation.
264 */
265 // Make sure that at least 1024 MPDUs are buffered (to test aggregation on EHT devices)
266 m_mac->GetTxopQueue(AC_BE)->SetAttribute("MaxSize", StringValue("2000p"));
267 m_mac->SetAttribute("BE_MaxAmsduSize", UintegerValue(m_params.maxAmsduSize));
268 m_mac->SetAttribute("BE_MaxAmpduSize", UintegerValue(m_params.maxAmpduSize));
270 "TxopLimits",
272
273 if (m_params.nLinks > 1)
274 {
275 auto mleCommonInfo2 = std::make_shared<CommonInfoBasicMle>();
276 mleCommonInfo2->m_mldMacAddress = Mac48Address("00:00:00:00:00:02");
277 for (uint8_t i = 0; i < m_params.nLinks; i++)
278 {
279 // we don't actually use the link addresses of the receiver, so we just use one address
280 // as both the MLD address and the link address of the receiver (the first argument in
281 // the call below should be the link address)
282 m_managers.at(i)->AddStationMleCommonInfo(mleCommonInfo2->m_mldMacAddress,
283 mleCommonInfo2);
284 }
285
286 auto mleCommonInfo3 = std::make_shared<CommonInfoBasicMle>();
287 mleCommonInfo3->m_mldMacAddress = Mac48Address("00:00:00:00:00:03");
288 for (uint8_t i = 0; i < m_params.nLinks; i++)
289 {
290 m_managers.at(i)->AddStationMleCommonInfo(mleCommonInfo3->m_mldMacAddress,
291 mleCommonInfo3);
292 }
293 }
294
295 for (uint8_t i = 0; i < m_params.nLinks; i++)
296 {
297 HtCapabilities htCapabilities;
298 htCapabilities.SetMaxAmsduLength(7935);
299 htCapabilities.SetMaxAmpduLength(65535);
300 m_managers.at(i)->AddStationHtCapabilities(Mac48Address("00:00:00:00:00:02"),
301 htCapabilities);
302 m_managers.at(i)->AddStationHtCapabilities(Mac48Address("00:00:00:00:00:03"),
303 htCapabilities);
304
306 {
307 VhtCapabilities vhtCapabilities;
308 vhtCapabilities.SetMaxMpduLength(11454);
309 m_managers.at(i)->AddStationVhtCapabilities(Mac48Address("00:00:00:00:00:02"),
310 vhtCapabilities);
311 }
313 {
314 HeCapabilities heCapabilities;
315 heCapabilities.SetMaxAmpduLength((1 << 23) - 1);
316 m_managers.at(i)->AddStationHeCapabilities(Mac48Address("00:00:00:00:00:02"),
317 heCapabilities);
318 }
320 {
321 EhtCapabilities ehtCapabilities;
322 ehtCapabilities.SetMaxMpduLength(11454);
323 ehtCapabilities.SetMaxAmpduLength((1 << 24) - 1);
324 m_managers.at(i)->AddStationEhtCapabilities(Mac48Address("00:00:00:00:00:02"),
325 ehtCapabilities);
326 }
327 }
328
329 /*
330 * Establish agreement.
331 */
332 EstablishAgreement(Mac48Address("00:00:00:00:00:02"));
333}
334
337{
338 return m_mac->GetBEQueue();
339}
340
341void
343{
344 std::list<Ptr<const WifiMpdu>> mpdus(mpduList.cbegin(), mpduList.cend());
345 m_mac->GetTxopQueue(AC_BE)->DequeueIfQueued(mpdus);
346}
347
348void
350{
352 reqHdr.SetImmediateBlockAck();
353 reqHdr.SetTid(0);
355 reqHdr.SetTimeout(0);
356 reqHdr.SetStartingSequence(0);
357 GetBeQueue()->GetBaManager()->CreateOriginatorAgreement(reqHdr, recipient);
358
360 StatusCode code;
361 code.SetSuccess();
362 respHdr.SetStatusCode(code);
363 respHdr.SetAmsduSupport(reqHdr.IsAmsduSupported());
364 respHdr.SetImmediateBlockAck();
365 respHdr.SetTid(reqHdr.GetTid());
367 respHdr.SetTimeout(reqHdr.GetTimeout());
368 GetBeQueue()->GetBaManager()->UpdateOriginatorAgreement(respHdr, recipient, 0);
369}
370
371void
372AmpduAggregationTest::EnqueuePkts(std::size_t count, uint32_t size, const Mac48Address& dest)
373{
374 for (std::size_t i = 0; i < count; i++)
375 {
376 auto pkt = Create<Packet>(size);
377 WifiMacHeader hdr;
378
379 hdr.SetAddr1(dest);
380 hdr.SetAddr2(Mac48Address("00:00:00:00:00:01"));
382 hdr.SetQosTid(0);
383
384 GetBeQueue()->GetWifiMacQueue()->Enqueue(Create<WifiMpdu>(pkt, hdr));
385 }
386}
387
388void
390{
391 /*
392 * Test behavior when no other packets are in the queue
393 */
394 auto fem = m_mac->GetFrameExchangeManager(SINGLE_LINK_OP_ID);
395 auto htFem = DynamicCast<HtFrameExchangeManager>(fem);
396 auto mpduAggregator = htFem->GetMpduAggregator();
397
398 /*
399 * Create a dummy packet of 1500 bytes and fill mac header fields.
400 */
401 EnqueuePkts(1, 1500, Mac48Address("00:00:00:00:00:02"));
402
403 auto peeked = GetBeQueue()->PeekNextMpdu(SINGLE_LINK_OP_ID);
404 WifiTxParameters txParams;
405 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
406 peeked->GetHeader(),
407 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
408 auto item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
409
410 auto mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
411
412 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), true, "a single packet should not result in an A-MPDU");
413
414 // the packet has not been "transmitted", release its sequence number
415 m_mac->m_txMiddle->SetSequenceNumberFor(&item->GetHeader());
416 item->UnassignSeqNo();
417
418 //---------------------------------------------------------------------------------------------
419
420 /*
421 * Test behavior when 2 more packets are in the queue
422 */
423 EnqueuePkts(2, 1500, Mac48Address("00:00:00:00:00:02"));
424
425 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
426 mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
427
428 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
429
430 auto psdu = Create<WifiPsdu>(mpduList);
431 DequeueMpdus(mpduList);
432
433 NS_TEST_EXPECT_MSG_EQ(psdu->GetSize(), 4606, "A-MPDU size is not correct");
434 NS_TEST_EXPECT_MSG_EQ(mpduList.size(), 3, "A-MPDU should contain 3 MPDUs");
435 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
436 0,
437 "queue should be empty");
438
439 for (uint32_t i = 0; i < psdu->GetNMpdus(); i++)
440 {
441 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(i).GetSequenceNumber(), i, "wrong sequence number");
442 }
443
444 //---------------------------------------------------------------------------------------------
445
446 /*
447 * Test behavior when the 802.11n station and another non-QoS station are associated to the AP.
448 * The AP sends an A-MPDU to the 802.11n station followed by the last retransmission of a
449 * non-QoS data frame to the non-QoS station. This is used to reproduce bug 2224.
450 */
451 EnqueuePkts(1, 1500, Mac48Address("00:00:00:00:00:02"));
452 EnqueuePkts(2, 1500, Mac48Address("00:00:00:00:00:03"));
453
455 txParams.Clear();
456 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
457 peeked->GetHeader(),
458 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
459 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
460
461 mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
462
463 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(),
464 true,
465 "a single packet for this destination should not result in an A-MPDU");
466 // dequeue the MPDU
467 DequeueMpdus({item});
468
470 txParams.Clear();
471 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
472 peeked->GetHeader(),
473 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
474 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
475
476 mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
477
478 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(),
479 true,
480 "no MPDU aggregation should be performed if there is no agreement");
481
483 ->SetMaxSsrc(
484 0); // set to 0 in order to fake that the maximum number of retries has been reached
485 m_mac->TraceConnectWithoutContext("DroppedMpdu",
487 htFem->m_dcf = GetBeQueue();
488 htFem->NormalAckTimeout(item, txParams.m_txVector);
489
490 NS_TEST_EXPECT_MSG_EQ(m_discarded, true, "packet should be discarded");
491 GetBeQueue()->GetWifiMacQueue()->Flush();
492}
493
494void
496{
498
499 for (auto manager : m_managers)
500 {
501 manager->Dispose();
502 }
503 m_managers.clear();
504
505 m_device->Dispose();
506 m_device = nullptr;
507}
508
509/**
510 * \ingroup wifi-test
511 * \ingroup tests
512 *
513 * \brief Two Level Aggregation Test
514 */
516{
517 public:
519
520 private:
521 void DoRun() override;
522};
523
525 : AmpduAggregationTest("Check the correctness of two-level aggregation operations",
526 Params{.standard = WIFI_STANDARD_80211n,
527 .nLinks = 1,
528 .dataMode = "HtMcs2", // 19.5Mbps
529 .bufferSize = 64,
530 .maxAmsduSize = 3050,
531 .maxAmpduSize = 65535,
532 .txopLimit = MicroSeconds(3008)})
533{
534}
535
536void
538{
539 /*
540 * Create dummy packets of 1500 bytes and fill mac header fields that will be used for the
541 * tests.
542 */
543 EnqueuePkts(3, 1500, Mac48Address("00:00:00:00:00:02"));
544
545 //---------------------------------------------------------------------------------------------
546
547 /*
548 * Test MSDU and MPDU aggregation. Three MSDUs are in the queue and the maximum A-MSDU size
549 * is such that only two MSDUs can be aggregated. Therefore, the first MPDU we get contains
550 * an A-MSDU of 2 MSDUs.
551 */
552 auto fem = m_mac->GetFrameExchangeManager(SINGLE_LINK_OP_ID);
553 auto htFem = DynamicCast<HtFrameExchangeManager>(fem);
554 auto msduAggregator = htFem->GetMsduAggregator();
555 auto mpduAggregator = htFem->GetMpduAggregator();
556
557 auto peeked = GetBeQueue()->PeekNextMpdu(SINGLE_LINK_OP_ID);
558 WifiTxParameters txParams;
559 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
560 peeked->GetHeader(),
561 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
562 htFem->TryAddMpdu(peeked, txParams, Time::Min());
563 auto item = msduAggregator->GetNextAmsdu(peeked, txParams, Time::Min());
564
565 bool result{item};
566 NS_TEST_EXPECT_MSG_EQ(result, true, "aggregation failed");
567 NS_TEST_EXPECT_MSG_EQ(item->GetPacketSize(), 3030, "wrong packet size");
568
569 // dequeue the MSDUs
570 DequeueMpdus({item});
571
572 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
573 1,
574 "Unexpected number of MSDUs left in the EDCA queue");
575
576 //---------------------------------------------------------------------------------------------
577
578 /*
579 * A-MSDU aggregation fails when there is just one MSDU in the queue.
580 */
581
583 txParams.Clear();
584 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
585 peeked->GetHeader(),
586 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
587 htFem->TryAddMpdu(peeked, txParams, Time::Min());
588 item = msduAggregator->GetNextAmsdu(peeked, txParams, Time::Min());
589
590 NS_TEST_EXPECT_MSG_EQ(item, nullptr, "A-MSDU aggregation did not fail");
591
592 DequeueMpdus({peeked});
593
594 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
595 0,
596 "queue should be empty");
597
598 //---------------------------------------------------------------------------------------------
599
600 /*
601 * Aggregation of MPDUs is stopped to prevent that the PPDU duration exceeds the TXOP limit.
602 * In this test, a TXOP limit of 3008 microseconds is used.
603 */
604
605 // Add 10 MSDUs to the EDCA queue
606 EnqueuePkts(10, 1300, Mac48Address("00:00:00:00:00:02"));
607
609 txParams.Clear();
610 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
611 peeked->GetHeader(),
612 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
613
614 // Compute the first MPDU to be aggregated in an A-MPDU. It must contain an A-MSDU
615 // aggregating two MSDUs
616 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, m_params.txopLimit, true);
617
618 NS_TEST_EXPECT_MSG_EQ(std::distance(item->begin(), item->end()),
619 2,
620 "There must be 2 MSDUs in the A-MSDU");
621
622 auto mpduList = mpduAggregator->GetNextAmpdu(item, txParams, m_params.txopLimit);
623
624 // The maximum number of bytes that can be transmitted in a TXOP is (approximately, as we
625 // do not consider that the preamble is transmitted at a different rate):
626 // 19.5 Mbps * 3.008 ms = 7332 bytes
627 // Given that the max A-MSDU size is set to 3050, an A-MSDU will contain two MSDUs and have
628 // a size of 2 * 1300 (MSDU size) + 2 * 14 (A-MSDU subframe header size) + 2 (one padding field)
629 // = 2630 bytes Hence, we expect that the A-MPDU will consist of:
630 // - 2 MPDUs containing each an A-MSDU. The size of each MPDU is 2630 (A-MSDU) + 30
631 // (header+trailer) = 2660
632 // - 1 MPDU containing a single MSDU. The size of such MPDU is 1300 (MSDU) + 30 (header+trailer)
633 // = 1330 The size of the A-MPDU is 4 + 2660 + 4 + 2660 + 4 + 1330 = 6662
634 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "aggregation failed");
635 NS_TEST_EXPECT_MSG_EQ(mpduList.size(), 3, "Unexpected number of MPDUs in the A-MPDU");
636 NS_TEST_EXPECT_MSG_EQ(mpduList.at(0)->GetSize(), 2660, "Unexpected size of the first MPDU");
637 NS_TEST_EXPECT_MSG_EQ(mpduList.at(0)->GetHeader().IsQosAmsdu(),
638 true,
639 "Expecting the first MPDU to contain an A-MSDU");
640 NS_TEST_EXPECT_MSG_EQ(mpduList.at(1)->GetSize(), 2660, "Unexpected size of the second MPDU");
641 NS_TEST_EXPECT_MSG_EQ(mpduList.at(1)->GetHeader().IsQosAmsdu(),
642 true,
643 "Expecting the second MPDU to contain an A-MSDU");
644 NS_TEST_EXPECT_MSG_EQ(mpduList.at(2)->GetSize(), 1330, "Unexpected size of the third MPDU");
645 NS_TEST_EXPECT_MSG_EQ(mpduList.at(2)->GetHeader().IsQosAmsdu(),
646 false,
647 "Expecting the third MPDU not to contain an A-MSDU");
648
649 auto psdu = Create<WifiPsdu>(mpduList);
650 NS_TEST_EXPECT_MSG_EQ(psdu->GetSize(), 6662, "Unexpected size of the A-MPDU");
651
652 // we now have two A-MSDUs and 6 MSDUs in the queue (5 MSDUs with no assigned sequence number)
653 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
654 8,
655 "Unexpected number of items left in the EDCA queue");
656
657 // prepare another A-MPDU (e.g., for transmission on another link)
658 peeked = GetBeQueue()->PeekNextMpdu(SINGLE_LINK_OP_ID, 0, psdu->GetAddr1(), mpduList.at(2));
659 txParams.Clear();
660 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
661 peeked->GetHeader(),
662 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
663
664 // Compute the first MPDU to be aggregated in an A-MPDU. It must contain an A-MSDU
665 // aggregating two MSDUs
666 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, m_params.txopLimit, true);
667
668 NS_TEST_EXPECT_MSG_EQ(std::distance(item->begin(), item->end()),
669 2,
670 "There must be 2 MSDUs in the A-MSDU");
671
672 auto mpduList2 = mpduAggregator->GetNextAmpdu(item, txParams, m_params.txopLimit);
673
674 // we now have two A-MSDUs, one MSDU, two A-MSDUs and one MSDU in the queue (all with assigned
675 // sequence number)
676 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
677 6,
678 "Unexpected number of items left in the EDCA queue");
679
680 // unassign sequence numbers for all MPDUs (emulates an RTS/CTS failure on both links)
681 mpduList.at(0)->UnassignSeqNo();
682 mpduList.at(1)->UnassignSeqNo();
683 mpduList.at(2)->UnassignSeqNo();
684 mpduList2.at(0)->UnassignSeqNo();
685 mpduList2.at(1)->UnassignSeqNo();
686 mpduList2.at(2)->UnassignSeqNo();
687
688 // set A-MSDU max size to a large value
689 m_mac->SetAttribute("BE_MaxAmsduSize", UintegerValue(7000));
690
691 // A-MSDU aggregation now fails because the first item in the queue contain A-MSDUs
693 txParams.Clear();
694 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
695 peeked->GetHeader(),
696 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
697
698 htFem->TryAddMpdu(peeked, txParams, Time::Min());
699 item = msduAggregator->GetNextAmsdu(peeked, txParams, Time::Min());
700
701 NS_TEST_EXPECT_MSG_EQ(item, nullptr, "Expecting not to be able to aggregate A-MSDUs");
702
703 // remove the first two items in the queue (containing A-MSDUs)
704 DequeueMpdus({mpduList.at(0), mpduList.at(1)});
705
706 // we now have one MSDU, two A-MSDUs and one MSDU in the queue
707 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
708 4,
709 "Unexpected number of items left in the EDCA queue");
710
712 txParams.Clear();
713 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
714 peeked->GetHeader(),
715 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
716
717 NS_TEST_EXPECT_MSG_EQ(peeked->GetHeader().IsQosAmsdu(),
718 false,
719 "Expecting the peeked MPDU not to contain an A-MSDU");
720
721 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
722
723 // A-MSDU aggregation is not attempted because the next item contains an A-MSDU
724 NS_TEST_EXPECT_MSG_EQ(item->GetHeader().IsQosAmsdu(),
725 false,
726 "Expecting the returned MPDU not to contain an A-MSDU");
727}
728
729/**
730 * \ingroup wifi-test
731 * \ingroup tests
732 *
733 * \brief 802.11ax aggregation test which permits 64 or 256 MPDUs in A-MPDU according to the
734 * negotiated buffer size.
735 */
737{
738 public:
739 /**
740 * Constructor.
741 *
742 * \param bufferSize the size (in number of MPDUs) of the BlockAck buffer
743 */
744 HeAggregationTest(uint16_t bufferSize);
745
746 private:
747 void DoRun() override;
748};
749
751 : AmpduAggregationTest("Check the correctness of 802.11ax aggregation operations, size=" +
752 std::to_string(bufferSize),
753 Params{.standard = WIFI_STANDARD_80211ax,
754 .nLinks = 1,
755 .dataMode = "HeMcs11",
756 .bufferSize = bufferSize,
757 .maxAmsduSize = 0,
758 .maxAmpduSize = 65535,
759 .txopLimit = Seconds(0)})
760{
761}
762
763void
765{
766 /*
767 * Test behavior when 300 packets are ready for transmission
768 */
769 EnqueuePkts(300, 100, Mac48Address("00:00:00:00:00:02"));
770
771 auto fem = m_mac->GetFrameExchangeManager(SINGLE_LINK_OP_ID);
772 auto htFem = DynamicCast<HtFrameExchangeManager>(fem);
773 auto mpduAggregator = htFem->GetMpduAggregator();
774
775 auto peeked = GetBeQueue()->PeekNextMpdu(SINGLE_LINK_OP_ID);
776 WifiTxParameters txParams;
777 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
778 peeked->GetHeader(),
779 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
780 auto item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
781
782 auto mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
783 DequeueMpdus(mpduList);
784
785 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
786 NS_TEST_EXPECT_MSG_EQ(mpduList.size(),
788 "A-MPDU contains an unexpected number of MPDUs");
789 uint16_t expectedRemainingPacketsInQueue = 300 - m_params.bufferSize;
790 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
791 expectedRemainingPacketsInQueue,
792 "Queue contains an unexpected number of MPDUs");
793}
794
795/**
796 * \ingroup wifi-test
797 * \ingroup tests
798 *
799 * \brief 802.11be aggregation test which permits up to 1024 MPDUs in A-MPDU according to the
800 * negotiated buffer size.
801 */
803{
804 public:
805 /**
806 * Constructor.
807 *
808 * \param bufferSize the size (in number of MPDUs) of the BlockAck buffer
809 */
810 EhtAggregationTest(uint16_t bufferSize);
811
812 private:
813 void DoRun() override;
814};
815
817 : AmpduAggregationTest("Check the correctness of 802.11be aggregation operations, size=" +
818 std::to_string(bufferSize),
819 Params{.standard = WIFI_STANDARD_80211be,
820 .nLinks = 2,
821 .dataMode = "EhtMcs13",
822 .bufferSize = bufferSize,
823 .maxAmsduSize = 0,
824 .maxAmpduSize = 102000,
825 .txopLimit = Seconds(0)})
826{
827}
828
829void
831{
832 /*
833 * Test behavior when 1200 packets of 100 bytes each are ready for transmission. The max
834 * A-MPDU size limit (102000 B) is computed to have at most 750 MPDUs aggregated in a single
835 * A-MPDU (each MPDU is 130 B, plus 4 B of A-MPDU subframe header, plus 2 B of padding).
836 */
837 EnqueuePkts(1200, 100, Mac48Address("00:00:00:00:00:02"));
838 const std::size_t maxNMpdus = 750;
839
840 for (uint8_t linkId = 0; linkId < m_params.nLinks; linkId++)
841 {
842 auto fem = m_mac->GetFrameExchangeManager(linkId);
843 auto htFem = DynamicCast<HtFrameExchangeManager>(fem);
844 auto mpduAggregator = htFem->GetMpduAggregator();
845 std::vector<Ptr<WifiMpdu>> mpduList;
846
847 auto peeked = GetBeQueue()->PeekNextMpdu(linkId);
848 if (peeked)
849 {
850 WifiTxParameters txParams;
851 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
852 peeked->GetHeader(),
853 m_phys.at(linkId)->GetChannelWidth());
854 auto item = GetBeQueue()->GetNextMpdu(linkId, peeked, txParams, Time::Min(), true);
855
856 mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
857 DequeueMpdus(mpduList);
858 }
859
860 uint16_t expectedRemainingPacketsInQueue;
861
862 if (m_params.bufferSize >= maxNMpdus)
863 {
864 // two A-MPDUs are transmitted concurrently on the two links and together saturate
865 // the transmit window
866 switch (linkId)
867 {
868 case 0:
869 // the first A-MPDU includes maxNMpdus MPDUs
870 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
871 NS_TEST_EXPECT_MSG_EQ(mpduList.size(),
872 maxNMpdus,
873 "A-MPDU contains an unexpected number of MPDUs");
874 expectedRemainingPacketsInQueue = 1200 - maxNMpdus;
875 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
876 expectedRemainingPacketsInQueue,
877 "Queue contains an unexpected number of MPDUs");
878 break;
879 case 1:
880 // the second A-MPDU includes bufferSize - maxNMpdus MPDUs
881 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
882 NS_TEST_EXPECT_MSG_EQ(mpduList.size(),
883 m_params.bufferSize - maxNMpdus,
884 "A-MPDU contains an unexpected number of MPDUs");
885 expectedRemainingPacketsInQueue = 1200 - m_params.bufferSize;
886 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
887 expectedRemainingPacketsInQueue,
888 "Queue contains an unexpected number of MPDUs");
889 break;
890 default:
891 NS_TEST_ASSERT_MSG_EQ(true, false, "Unexpected link ID " << +linkId);
892 }
893 }
894 else
895 {
896 // one A-MPDU is transmitted that saturates the transmit window
897 switch (linkId)
898 {
899 case 0:
900 // the first A-MPDU includes bufferSize MPDUs
901 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
902 NS_TEST_EXPECT_MSG_EQ(mpduList.size(),
904 "A-MPDU contains an unexpected number of MPDUs");
905 expectedRemainingPacketsInQueue = 1200 - m_params.bufferSize;
906 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
907 expectedRemainingPacketsInQueue,
908 "Queue contains an unexpected number of MPDUs");
909 break;
910 case 1:
911 // no more MPDUs can be sent, aggregation fails
912 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), true, "MPDU aggregation did not fail");
913 expectedRemainingPacketsInQueue = 1200 - m_params.bufferSize;
914 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
915 expectedRemainingPacketsInQueue,
916 "Queue contains an unexpected number of MPDUs");
917 break;
918 default:
919 NS_TEST_ASSERT_MSG_EQ(true, false, "Unexpected link ID " << +linkId);
920 }
921 }
922 }
923}
924
925/**
926 * \ingroup wifi-test
927 * \ingroup tests
928 *
929 * \brief Test for A-MSDU and A-MPDU aggregation
930 *
931 * This test aims to check that the packets passed to the MAC layer (on the sender
932 * side) are forwarded up to the upper layer (on the receiver side) when A-MSDU and
933 * A-MPDU aggregation are used. This test checks that no packet copies are performed,
934 * hence packets can be tracked by means of a pointer.
935 *
936 * In this test, an HT STA sends 8 packets (each of 1000 bytes) to an HT AP.
937 * The block ack threshold is set to 2, hence the first packet is sent as an MPDU
938 * containing a single MSDU because the establishment of a Block Ack agreement is
939 * not triggered yet. The maximum A-MSDU size is set to 4500 bytes and the
940 * maximum A-MPDU size is set to 7500 bytes, hence the remaining packets are sent
941 * in an A-MPDU containing two MPDUs, the first one including 4 MSDUs and the second
942 * one including 3 MPDUs.
943 *
944 * It is also checked that the MAC header of every MPDU is notified to the FrameExchangeManager
945 * while the PSDU is being transmitted.
946 */
948{
949 public:
950 /**
951 * Constructor.
952 *
953 * \param notifyMacHdrRxEnd whether notification of MAC header reception end is enabled
954 */
955 PreservePacketsInAmpdus(bool notifyMacHdrRxEnd);
956 ~PreservePacketsInAmpdus() override;
957
958 void DoRun() override;
959
960 private:
961 std::list<Ptr<const Packet>> m_packetList; ///< List of packets passed to the MAC
962 std::vector<std::size_t> m_nMpdus; ///< Number of MPDUs in PSDUs passed to the PHY
963 std::vector<std::size_t> m_nMsdus; ///< Number of MSDUs in MPDUs passed to the PHY
964 Ptr<const WifiPsdu> m_txPsdu; ///< PSDU being transmitted
965 std::vector<Ptr<WifiMpdu>>::const_iterator
966 m_expectedMpdu; ///< next MPDU expected to be received
967 std::size_t m_nMacHdrs{0}; ///< Number of notified MAC headers in QoS data frames
968 bool m_notifyMacHdrRxEnd; ///< whether notification of MAC header reception end is enabled
969
970 /**
971 * Callback invoked when an MSDU is passed to the MAC
972 * \param packet the MSDU to transmit
973 */
975 /**
976 * Callback invoked when the sender MAC passes a PSDU(s) to the PHY
977 * \param psduMap the PSDU map
978 * \param txVector the TX vector
979 * \param txPowerW the transmit power in Watts
980 */
981 void NotifyPsduForwardedDown(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
982 /**
983 * Callback invoked when the reception of the MAC header of an MPDU is completed.
984 * \param mac the MAC to which the reception of the MAC header is notified
985 * \param macHdr the MAC header of the MPDU being received
986 * \param txVector the TXVECTOR used to transmit the PSDU
987 * \param psduDuration the remaining duration of the PSDU
988 */
990 const WifiMacHeader& macHdr,
991 const WifiTxVector& txVector,
992 Time psduDuration);
993 /**
994 * Callback invoked when the receiver MAC forwards a packet up to the upper layer
995 * \param p the packet
996 */
998};
999
1001 : TestCase("Test case to check that the Wifi Mac forwards up the same packets received at "
1002 "sender side."),
1003 m_notifyMacHdrRxEnd(notifyMacHdrRxEnd)
1004{
1005}
1006
1010
1011void
1016
1017void
1019 WifiTxVector txVector,
1020 double txPowerW)
1021{
1022 NS_TEST_EXPECT_MSG_EQ((psduMap.size() == 1 && psduMap.begin()->first == SU_STA_ID),
1023 true,
1024 "No DL MU PPDU expected");
1025
1026 // m_txPsdu is reset when the MAC header of the last MPDU in the PSDU is notified. By
1027 // checking that m_txPsdu is nullptr when starting the transmission of a PSDU, we ensure
1028 // that MAC headers are notified to the FEM while receiving MPDUs.
1030 {
1032 nullptr,
1033 "Missing MAC header notification: m_txPsdu was not reset");
1034 }
1035
1036 m_txPsdu = psduMap.at(SU_STA_ID);
1038
1039 if (!psduMap[SU_STA_ID]->GetHeader(0).IsQosData())
1040 {
1041 return;
1042 }
1043
1044 m_nMpdus.push_back(psduMap[SU_STA_ID]->GetNMpdus());
1045
1046 for (auto& mpdu : *PeekPointer(psduMap[SU_STA_ID]))
1047 {
1048 std::size_t dist = std::distance(mpdu->begin(), mpdu->end());
1049 // the list of aggregated MSDUs is empty if the MPDU includes a non-aggregated MSDU
1050 m_nMsdus.push_back(dist > 0 ? dist : 1);
1051 }
1052}
1053
1054void
1056 const WifiMacHeader& macHdr,
1057 const WifiTxVector& txVector,
1058 Time psduDuration)
1059{
1061 nullptr,
1062 "Notified of MAC header RX end while no PSDU is being transmitted");
1063 // check that the FEM stores the expected MAC header (in a nanosecond, to avoid issues
1064 // with the ordering of the callbacks connected to the trace source)
1065 auto expectedHdr = (*m_expectedMpdu)->GetHeader();
1066 Simulator::Schedule(NanoSeconds(1), [=, this]() {
1067 auto macHdr = mac->GetFrameExchangeManager()->GetReceivedMacHdr();
1068 NS_TEST_ASSERT_MSG_EQ(macHdr.has_value(),
1069 true,
1070 "Expected the FEM to store the MAC header being received");
1072 expectedHdr.GetSequenceNumber(),
1073 "Wrong sequence number in the MAC header stored by the FEM");
1074 });
1075
1076 if (expectedHdr.IsQosData())
1077 {
1078 m_nMacHdrs++;
1079 }
1080
1081 if (++m_expectedMpdu == m_txPsdu->end())
1082 {
1083 m_txPsdu = nullptr;
1084 // check that the FEM stores no MAC header right after PSDU end
1085 Simulator::Schedule(psduDuration + NanoSeconds(1), [=, this]() {
1086 auto macHeader = mac->GetFrameExchangeManager()->GetReceivedMacHdr();
1087 NS_TEST_EXPECT_MSG_EQ(macHeader.has_value(),
1088 false,
1089 "Expected the FEM to store no MAC header");
1090 });
1091 }
1092}
1093
1094void
1096{
1097 auto it = std::find(m_packetList.begin(), m_packetList.end(), p);
1098 NS_TEST_EXPECT_MSG_EQ((it != m_packetList.end()), true, "Packet being forwarded up not found");
1099 m_packetList.erase(it);
1100}
1101
1102void
1104{
1105 Config::SetDefault("ns3::WifiPhy::NotifyMacHdrRxEnd", BooleanValue(m_notifyMacHdrRxEnd));
1106
1107 NodeContainer wifiStaNode;
1108 wifiStaNode.Create(1);
1109
1110 NodeContainer wifiApNode;
1111 wifiApNode.Create(1);
1112
1115 phy.SetChannel(channel.Create());
1116
1117 WifiHelper wifi;
1118 wifi.SetStandard(WIFI_STANDARD_80211n);
1119 wifi.SetRemoteStationManager("ns3::IdealWifiManager");
1120
1121 WifiMacHelper mac;
1122 Ssid ssid = Ssid("ns-3-ssid");
1123 mac.SetType("ns3::StaWifiMac",
1124 "BE_MaxAmsduSize",
1125 UintegerValue(4500),
1126 "BE_MaxAmpduSize",
1127 UintegerValue(7500),
1128 "Ssid",
1129 SsidValue(ssid),
1130 /* setting blockack threshold for sta's BE queue */
1131 "BE_BlockAckThreshold",
1132 UintegerValue(2),
1133 "ActiveProbing",
1134 BooleanValue(false));
1135
1136 NetDeviceContainer staDevices;
1137 staDevices = wifi.Install(phy, mac, wifiStaNode);
1138
1139 mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid), "BeaconGeneration", BooleanValue(true));
1140
1141 NetDeviceContainer apDevices;
1142 apDevices = wifi.Install(phy, mac, wifiApNode);
1143
1144 MobilityHelper mobility;
1146
1147 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
1148 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
1149 mobility.SetPositionAllocator(positionAlloc);
1150
1151 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
1152 mobility.Install(wifiApNode);
1153 mobility.Install(wifiStaNode);
1154
1155 Ptr<WifiNetDevice> ap_device = DynamicCast<WifiNetDevice>(apDevices.Get(0));
1156 Ptr<WifiNetDevice> sta_device = DynamicCast<WifiNetDevice>(staDevices.Get(0));
1157
1158 PacketSocketAddress socket;
1159 socket.SetSingleDevice(sta_device->GetIfIndex());
1160 socket.SetPhysicalAddress(ap_device->GetAddress());
1161 socket.SetProtocol(1);
1162
1163 // install packet sockets on nodes.
1164 PacketSocketHelper packetSocket;
1165 packetSocket.Install(wifiStaNode);
1166 packetSocket.Install(wifiApNode);
1167
1169 client->SetAttribute("PacketSize", UintegerValue(1000));
1170 client->SetAttribute("MaxPackets", UintegerValue(8));
1171 client->SetAttribute("Interval", TimeValue(Seconds(1)));
1172 client->SetRemote(socket);
1173 wifiStaNode.Get(0)->AddApplication(client);
1174 client->SetStartTime(Seconds(1));
1175 client->SetStopTime(Seconds(3.0));
1177 &PacketSocketClient::SetAttribute,
1178 client,
1179 "Interval",
1181
1183 server->SetLocal(socket);
1184 wifiApNode.Get(0)->AddApplication(server);
1185 server->SetStartTime(Seconds(0.0));
1186 server->SetStopTime(Seconds(4.0));
1187
1188 sta_device->GetMac()->TraceConnectWithoutContext(
1189 "MacTx",
1191 sta_device->GetPhy()->TraceConnectWithoutContext(
1192 "PhyTxPsduBegin",
1194 ap_device->GetPhy()->TraceConnectWithoutContext(
1195 "PhyRxMacHeaderEnd",
1197 .Bind(ap_device->GetMac()));
1198 ap_device->GetMac()->TraceConnectWithoutContext(
1199 "MacRx",
1201
1204
1206
1207 // Two packets are transmitted. The first one is an MPDU containing a single MSDU.
1208 // The second one is an A-MPDU containing two MPDUs: the first MPDU contains 4 MSDUs
1209 // and the second MPDU contains 3 MSDUs
1210 NS_TEST_EXPECT_MSG_EQ(m_nMpdus.size(), 2, "Unexpected number of transmitted packets");
1211 NS_TEST_EXPECT_MSG_EQ(m_nMsdus.size(), 3, "Unexpected number of transmitted MPDUs");
1212 NS_TEST_EXPECT_MSG_EQ(m_nMpdus[0], 1, "Unexpected number of MPDUs in the first A-MPDU");
1213 NS_TEST_EXPECT_MSG_EQ(m_nMsdus[0], 1, "Unexpected number of MSDUs in the first MPDU");
1214 NS_TEST_EXPECT_MSG_EQ(m_nMpdus[1], 2, "Unexpected number of MPDUs in the second A-MPDU");
1215 NS_TEST_EXPECT_MSG_EQ(m_nMsdus[1], 4, "Unexpected number of MSDUs in the second MPDU");
1216 NS_TEST_EXPECT_MSG_EQ(m_nMsdus[2], 3, "Unexpected number of MSDUs in the third MPDU");
1217 // Three MPDUs (of type QoS data) have been transmitted, so we expect that 3 MAC headers
1218 // have been notified to the FEM
1220 (m_notifyMacHdrRxEnd ? 3 : 0),
1221 "Unexpected number of MAC headers notified to the FEM");
1222 // All the packets must have been forwarded up at the receiver
1223 NS_TEST_EXPECT_MSG_EQ(m_packetList.empty(), true, "Some packets have not been forwarded up");
1224}
1225
1226/**
1227 * \ingroup wifi-test
1228 * \ingroup tests
1229 *
1230 * \brief Wifi Aggregation Test Suite
1231 */
1233{
1234 public:
1236};
1237
1239 : TestSuite("wifi-aggregation", Type::UNIT)
1240{
1241 AddTestCase(new AmpduAggregationTest, TestCase::Duration::QUICK);
1242 AddTestCase(new TwoLevelAggregationTest, TestCase::Duration::QUICK);
1243 AddTestCase(new HeAggregationTest(64), TestCase::Duration::QUICK);
1244 AddTestCase(new HeAggregationTest(256), TestCase::Duration::QUICK);
1245 AddTestCase(new EhtAggregationTest(512), TestCase::Duration::QUICK);
1246 AddTestCase(new EhtAggregationTest(1024), TestCase::Duration::QUICK);
1247 AddTestCase(new PreservePacketsInAmpdus(true), TestCase::Duration::QUICK);
1248 AddTestCase(new PreservePacketsInAmpdus(false), TestCase::Duration::QUICK);
1249}
1250
Ampdu Aggregation Test.
bool m_discarded
whether the packet should be discarded
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
Ptr< QosTxop > GetBeQueue() const
void DoSetup() override
Implementation to do any local setup required for this TestCase.
ObjectFactory m_factory
factory
Params m_params
test parameters
void EnqueuePkts(std::size_t count, uint32_t size, const Mac48Address &dest)
Enqueue the given number of packets addressed to the given station and of the given size.
std::vector< Ptr< WifiRemoteStationManager > > m_managers
remote station managers
void DoRun() override
Implementation to actually run this TestCase.
Ptr< WifiNetDevice > m_device
WifiNetDevice.
void DequeueMpdus(const std::vector< Ptr< WifiMpdu > > &mpduList)
Dequeue a PSDU.
void EstablishAgreement(const Mac48Address &recipient)
Establish a BlockAck agreement.
void MpduDiscarded(WifiMacDropReason reason, Ptr< const WifiMpdu > mpdu)
Fired when the MAC discards an MPDU.
std::vector< Ptr< WifiPhy > > m_phys
Phys.
Ptr< StaWifiMac > m_mac
Mac.
802.11be aggregation test which permits up to 1024 MPDUs in A-MPDU according to the negotiated buffer...
void DoRun() override
Implementation to actually run this TestCase.
EhtAggregationTest(uint16_t bufferSize)
Constructor.
802.11ax aggregation test which permits 64 or 256 MPDUs in A-MPDU according to the negotiated buffer ...
HeAggregationTest(uint16_t bufferSize)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
Test for A-MSDU and A-MPDU aggregation.
void DoRun() override
Implementation to actually run this TestCase.
void NotifyPsduForwardedDown(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when the sender MAC passes a PSDU(s) to the PHY.
void NotifyMacHeaderEndRx(Ptr< WifiMac > mac, const WifiMacHeader &macHdr, const WifiTxVector &txVector, Time psduDuration)
Callback invoked when the reception of the MAC header of an MPDU is completed.
std::list< Ptr< const Packet > > m_packetList
List of packets passed to the MAC.
PreservePacketsInAmpdus(bool notifyMacHdrRxEnd)
Constructor.
std::vector< std::size_t > m_nMsdus
Number of MSDUs in MPDUs passed to the PHY.
std::vector< std::size_t > m_nMpdus
Number of MPDUs in PSDUs passed to the PHY.
std::vector< Ptr< WifiMpdu > >::const_iterator m_expectedMpdu
next MPDU expected to be received
std::size_t m_nMacHdrs
Number of notified MAC headers in QoS data frames.
void NotifyMacForwardUp(Ptr< const Packet > p)
Callback invoked when the receiver MAC forwards a packet up to the upper layer.
void NotifyMacTransmit(Ptr< const Packet > packet)
Callback invoked when an MSDU is passed to the MAC.
bool m_notifyMacHdrRxEnd
whether notification of MAC header reception end is enabled
Ptr< const WifiPsdu > m_txPsdu
PSDU being transmitted.
Two Level Aggregation Test.
void DoRun() override
Implementation to actually run this TestCase.
Wifi Aggregation Test Suite.
A container for one type of attribute.
The IEEE 802.11be EHT Capabilities.
void SetMaxMpduLength(uint16_t length)
Set the maximum MPDU length.
void SetMaxAmpduLength(uint32_t maxAmpduLength)
Set the maximum A-MPDU length.
FrameExchangeManager is a base class handling the basic frame exchange sequences for non-QoS stations...
The IEEE 802.11ax HE Capabilities.
void SetMaxAmpduLength(uint32_t maxAmpduLength)
Set the maximum AMPDU length.
The HT Capabilities Information Element.
void SetMaxAmsduLength(uint16_t maxAmsduLength)
Set the maximum AMSDU length.
void SetMaxAmpduLength(uint32_t maxAmpduLength)
Set the maximum AMPDU length.
an EUI-48 address
static Mac48Address GetBroadcast()
Implement the header for management frames of type Add Block Ack request.
void SetBufferSize(uint16_t size)
Set buffer size.
void SetImmediateBlockAck()
Enable immediate BlockAck.
uint16_t GetTimeout() const
Return the timeout.
uint8_t GetTid() const
Return the Traffic ID (TID).
bool IsAmsduSupported() const
Return whether A-MSDU capability is supported.
void SetTimeout(uint16_t timeout)
Set timeout.
void SetTid(uint8_t tid)
Set Traffic ID (TID).
void SetStartingSequence(uint16_t seq)
Set the starting sequence number.
Implement the header for management frames of type Add Block Ack response.
void SetTid(uint8_t tid)
Set Traffic ID (TID).
void SetTimeout(uint16_t timeout)
Set timeout.
void SetBufferSize(uint16_t size)
Set buffer size.
void SetStatusCode(StatusCode code)
Set the status code.
void SetAmsduSupport(bool supported)
Enable or disable A-MSDU support.
void SetImmediateBlockAck()
Enable immediate BlockAck.
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
uint32_t AddApplication(Ptr< Application > application)
Associate an Application to this Node.
Definition node.cc:153
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
void Set(const std::string &name, const AttributeValue &value, Args &&... args)
Set an attribute to be set during construction.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
an address for a packet socket
void SetProtocol(uint16_t protocol)
Set the protocol.
void SetPhysicalAddress(const Address address)
Set the destination address.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
AttributeValue implementation for Pointer.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< BlockAckManager > GetBaManager()
Get the Block Ack Manager associated with this QosTxop.
Definition qos-txop.cc:278
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< const WifiMpdu > mpdu=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
Definition qos-txop.cc:374
Ptr< WifiMpdu > GetNextMpdu(uint8_t linkId, Ptr< WifiMpdu > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame)
Prepare the frame to transmit on the given link starting from the MPDU that has been previously peeke...
Definition qos-txop.cc:491
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
Status code for association response.
Definition status-code.h:21
void SetSuccess()
Set success bit to 0 (success).
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition nstime.h:276
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition txop.cc:264
Hold an unsigned integer type.
Definition uinteger.h:34
The IEEE 802.11ac VHT Capabilities.
void SetMaxMpduLength(uint16_t length)
Set the maximum MPDU length.
helps to create WifiNetDevice objects
Implements the IEEE 802.11 MAC header.
uint16_t GetSequenceNumber() const
Return the sequence number of the header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
create MAC layers for a ns3::WifiNetDevice.
std::vector< Ptr< WifiMpdu > >::const_iterator end() const
Return a const iterator to past-the-last MPDU.
Definition wifi-psdu.cc:334
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
Definition wifi-psdu.cc:322
hold a list of per-remote-station state.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void Clear()
Reset the TX parameters.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
manage and create wifi channel objects for the YANS model.
static YansWifiChannelHelper Default()
Create a channel helper in a default working state.
Make it easy to create and manage PHY objects for the YANS model.
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition test.h:656
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:241
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
WifiStandard
Identifies the IEEE 802.11 specifications that a Wifi device can be configured to use.
WifiMacDropReason
The reason why an MPDU was dropped.
Definition wifi-mac.h:70
@ WIFI_STANDARD_80211be
@ WIFI_STANDARD_80211n
@ WIFI_STANDARD_80211ax
@ WIFI_STANDARD_80211ac
@ AC_BE
Best Effort.
Definition qos-utils.h:64
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
std::string GetFrameExchangeManagerTypeIdName(WifiStandard standard, bool qosSupported)
Get the TypeId name for the FrameExchangeManager corresponding to the given standard.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:183
@ WIFI_MAC_QOSDATA
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
STL namespace.
uint8_t nLinks
number of links (>1 only for EHT)
uint32_t maxAmpduSize
maximum A-MPDU size (bytes)
uint16_t bufferSize
the size (in number of MPDUs) of the BlockAck buffer
WifiStandard standard
the standard of the device
uint16_t maxAmsduSize
maximum A-MSDU size (bytes)
Time txopLimit
TXOP limit duration.
static WifiAggregationTestSuite g_wifiAggregationTestSuite
the test suite