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/attribute-container.h"
10#include "ns3/config.h"
11#include "ns3/eht-configuration.h"
12#include "ns3/fcfs-wifi-queue-scheduler.h"
13#include "ns3/he-configuration.h"
14#include "ns3/ht-configuration.h"
15#include "ns3/ht-frame-exchange-manager.h"
16#include "ns3/interference-helper.h"
17#include "ns3/mac-tx-middle.h"
18#include "ns3/mgt-action-headers.h"
19#include "ns3/mobility-helper.h"
20#include "ns3/mpdu-aggregator.h"
21#include "ns3/msdu-aggregator.h"
22#include "ns3/multi-link-element.h"
23#include "ns3/node-container.h"
24#include "ns3/packet-socket-client.h"
25#include "ns3/packet-socket-helper.h"
26#include "ns3/packet-socket-server.h"
27#include "ns3/pointer.h"
28#include "ns3/simulator.h"
29#include "ns3/sta-wifi-mac.h"
30#include "ns3/string.h"
31#include "ns3/test.h"
32#include "ns3/vht-configuration.h"
33#include "ns3/wifi-default-ack-manager.h"
34#include "ns3/wifi-default-protection-manager.h"
35#include "ns3/wifi-mac-queue.h"
36#include "ns3/wifi-net-device.h"
37#include "ns3/wifi-psdu.h"
38#include "ns3/yans-wifi-helper.h"
39#include "ns3/yans-wifi-phy.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 caManagers.reserve(m_params.nLinks);
229 for (uint8_t i = 0; i < m_params.nLinks; i++)
230 {
231 caManagers.emplace_back(CreateObject<ChannelAccessManager>());
232 }
233 m_mac->SetChannelAccessManagers(caManagers);
234 ObjectFactory femFactory;
236 std::vector<Ptr<FrameExchangeManager>> feManagers;
237 for (uint8_t i = 0; i < m_params.nLinks; i++)
238 {
239 auto fem = femFactory.Create<FrameExchangeManager>();
240 feManagers.emplace_back(fem);
241 auto protectionManager = CreateObject<WifiDefaultProtectionManager>();
242 protectionManager->SetWifiMac(m_mac);
243 fem->SetProtectionManager(protectionManager);
244 auto ackManager = CreateObject<WifiDefaultAckManager>();
245 ackManager->SetWifiMac(m_mac);
246 fem->SetAckManager(ackManager);
247 // here we should assign distinct link addresses in case of MLDs, but we don't actually use
248 // link addresses in this test
249 fem->SetAddress(m_mac->GetAddress());
250 }
251 m_mac->SetFrameExchangeManagers(feManagers);
252 m_mac->SetState(StaWifiMac::ASSOCIATED);
253 if (m_params.nLinks > 1)
254 {
255 // the bssid field of StaLinkEntity must hold a value
256 for (const auto& [id, link] : m_mac->GetLinks())
257 {
259 }
260 }
261 m_mac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
262
263 /*
264 * Configure A-MSDU and A-MPDU aggregation.
265 */
266 // Make sure that at least 1024 MPDUs are buffered (to test aggregation on EHT devices)
267 m_mac->GetTxopQueue(AC_BE)->SetAttribute("MaxSize", StringValue("2000p"));
268 m_mac->SetAttribute("BE_MaxAmsduSize", UintegerValue(m_params.maxAmsduSize));
269 m_mac->SetAttribute("BE_MaxAmpduSize", UintegerValue(m_params.maxAmpduSize));
271 "TxopLimits",
273
274 if (m_params.nLinks > 1)
275 {
276 auto mleCommonInfo2 = std::make_shared<CommonInfoBasicMle>();
277 mleCommonInfo2->m_mldMacAddress = Mac48Address("00:00:00:00:00:02");
278 for (uint8_t i = 0; i < m_params.nLinks; i++)
279 {
280 // we don't actually use the link addresses of the receiver, so we just use one address
281 // as both the MLD address and the link address of the receiver (the first argument in
282 // the call below should be the link address)
283 m_managers.at(i)->AddStationMleCommonInfo(mleCommonInfo2->m_mldMacAddress,
284 mleCommonInfo2);
285 }
286
287 auto mleCommonInfo3 = std::make_shared<CommonInfoBasicMle>();
288 mleCommonInfo3->m_mldMacAddress = Mac48Address("00:00:00:00:00:03");
289 for (uint8_t i = 0; i < m_params.nLinks; i++)
290 {
291 m_managers.at(i)->AddStationMleCommonInfo(mleCommonInfo3->m_mldMacAddress,
292 mleCommonInfo3);
293 }
294 }
295
296 for (uint8_t i = 0; i < m_params.nLinks; i++)
297 {
298 HtCapabilities htCapabilities;
299 htCapabilities.SetMaxAmsduLength(7935);
300 htCapabilities.SetMaxAmpduLength(65535);
301 m_managers.at(i)->AddStationHtCapabilities(Mac48Address("00:00:00:00:00:02"),
302 htCapabilities);
303 m_managers.at(i)->AddStationHtCapabilities(Mac48Address("00:00:00:00:00:03"),
304 htCapabilities);
305
307 {
308 VhtCapabilities vhtCapabilities;
309 vhtCapabilities.SetMaxMpduLength(11454);
310 m_managers.at(i)->AddStationVhtCapabilities(Mac48Address("00:00:00:00:00:02"),
311 vhtCapabilities);
312 }
314 {
315 HeCapabilities heCapabilities;
316 heCapabilities.SetMaxAmpduLength((1 << 23) - 1);
317 m_managers.at(i)->AddStationHeCapabilities(Mac48Address("00:00:00:00:00:02"),
318 heCapabilities);
319 }
321 {
322 EhtCapabilities ehtCapabilities;
323 ehtCapabilities.SetMaxMpduLength(11454);
324 ehtCapabilities.SetMaxAmpduLength((1 << 24) - 1);
325 m_managers.at(i)->AddStationEhtCapabilities(Mac48Address("00:00:00:00:00:02"),
326 ehtCapabilities);
327 }
328 }
329
330 /*
331 * Establish agreement.
332 */
333 EstablishAgreement(Mac48Address("00:00:00:00:00:02"));
334}
335
338{
339 return m_mac->GetBEQueue();
340}
341
342void
344{
345 std::list<Ptr<const WifiMpdu>> mpdus(mpduList.cbegin(), mpduList.cend());
346 m_mac->GetTxopQueue(AC_BE)->DequeueIfQueued(mpdus);
347}
348
349void
351{
353 reqHdr.SetImmediateBlockAck();
354 reqHdr.SetTid(0);
356 reqHdr.SetTimeout(0);
357 reqHdr.SetStartingSequence(0);
358 GetBeQueue()->GetBaManager()->CreateOriginatorAgreement(reqHdr, recipient);
359
361 StatusCode code;
362 code.SetSuccess();
363 respHdr.SetStatusCode(code);
364 respHdr.SetAmsduSupport(reqHdr.IsAmsduSupported());
365 respHdr.SetImmediateBlockAck();
366 respHdr.SetTid(reqHdr.GetTid());
368 respHdr.SetTimeout(reqHdr.GetTimeout());
369 GetBeQueue()->GetBaManager()->UpdateOriginatorAgreement(respHdr, recipient, 0);
370}
371
372void
373AmpduAggregationTest::EnqueuePkts(std::size_t count, uint32_t size, const Mac48Address& dest)
374{
375 for (std::size_t i = 0; i < count; i++)
376 {
377 auto pkt = Create<Packet>(size);
378 WifiMacHeader hdr;
379
380 hdr.SetAddr1(dest);
381 hdr.SetAddr2(Mac48Address("00:00:00:00:00:01"));
383 hdr.SetQosTid(0);
384
385 GetBeQueue()->GetWifiMacQueue()->Enqueue(Create<WifiMpdu>(pkt, hdr));
386 }
387}
388
389void
391{
392 /*
393 * Test behavior when no other packets are in the queue
394 */
395 auto fem = m_mac->GetFrameExchangeManager(SINGLE_LINK_OP_ID);
396 auto htFem = DynamicCast<HtFrameExchangeManager>(fem);
397 auto mpduAggregator = htFem->GetMpduAggregator();
398
399 /*
400 * Create a dummy packet of 1500 bytes and fill mac header fields.
401 */
402 EnqueuePkts(1, 1500, Mac48Address("00:00:00:00:00:02"));
403
404 auto peeked = GetBeQueue()->PeekNextMpdu(SINGLE_LINK_OP_ID);
405 WifiTxParameters txParams;
406 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
407 peeked->GetHeader(),
408 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
409 auto item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
410
411 auto mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
412
413 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), true, "a single packet should not result in an A-MPDU");
414
415 // the packet has not been "transmitted", release its sequence number
416 m_mac->m_txMiddle->SetSequenceNumberFor(&item->GetHeader());
417 item->UnassignSeqNo();
418
419 //---------------------------------------------------------------------------------------------
420
421 /*
422 * Test behavior when 2 more packets are in the queue
423 */
424 EnqueuePkts(2, 1500, Mac48Address("00:00:00:00:00:02"));
425
426 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
427 mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
428
429 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
430
431 auto psdu = Create<WifiPsdu>(mpduList);
432 DequeueMpdus(mpduList);
433
434 NS_TEST_EXPECT_MSG_EQ(psdu->GetSize(), 4606, "A-MPDU size is not correct");
435 NS_TEST_EXPECT_MSG_EQ(mpduList.size(), 3, "A-MPDU should contain 3 MPDUs");
436 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
437 0,
438 "queue should be empty");
439
440 for (uint32_t i = 0; i < psdu->GetNMpdus(); i++)
441 {
442 NS_TEST_EXPECT_MSG_EQ(psdu->GetHeader(i).GetSequenceNumber(), i, "wrong sequence number");
443 }
444
445 //---------------------------------------------------------------------------------------------
446
447 /*
448 * Test behavior when the 802.11n station and another non-QoS station are associated to the AP.
449 * The AP sends an A-MPDU to the 802.11n station followed by the last retransmission of a
450 * non-QoS data frame to the non-QoS station. This is used to reproduce bug 2224.
451 */
452 EnqueuePkts(1, 1500, Mac48Address("00:00:00:00:00:02"));
453 EnqueuePkts(2, 1500, Mac48Address("00:00:00:00:00:03"));
454
456 txParams.Clear();
457 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
458 peeked->GetHeader(),
459 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
460 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
461
462 mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
463
464 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(),
465 true,
466 "a single packet for this destination should not result in an A-MPDU");
467 // dequeue the MPDU
468 DequeueMpdus({item});
469
471 txParams.Clear();
472 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
473 peeked->GetHeader(),
474 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
475 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
476
477 mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
478
479 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(),
480 true,
481 "no MPDU aggregation should be performed if there is no agreement");
482
483 m_mac->SetFrameRetryLimit(1); // fake that the maximum number of retries has been reached
484 m_mac->TraceConnectWithoutContext("DroppedMpdu",
486 htFem->m_dcf = GetBeQueue();
487 htFem->NormalAckTimeout(item, txParams.m_txVector);
488
489 NS_TEST_EXPECT_MSG_EQ(m_discarded, true, "packet should be discarded");
490 GetBeQueue()->GetWifiMacQueue()->Flush();
491}
492
493void
495{
497
498 for (auto manager : m_managers)
499 {
500 manager->Dispose();
501 }
502 m_managers.clear();
503
504 m_device->Dispose();
505 m_device = nullptr;
506}
507
508/**
509 * @ingroup wifi-test
510 * @ingroup tests
511 *
512 * @brief Two Level Aggregation Test
513 */
515{
516 public:
518
519 private:
520 void DoRun() override;
521};
522
524 : AmpduAggregationTest("Check the correctness of two-level aggregation operations",
525 Params{.standard = WIFI_STANDARD_80211n,
526 .nLinks = 1,
527 .dataMode = "HtMcs2", // 19.5Mbps
528 .bufferSize = 64,
529 .maxAmsduSize = 3050,
530 .maxAmpduSize = 65535,
531 .txopLimit = MicroSeconds(3008)})
532{
533}
534
535void
537{
538 /*
539 * Create dummy packets of 1500 bytes and fill mac header fields that will be used for the
540 * tests.
541 */
542 EnqueuePkts(3, 1500, Mac48Address("00:00:00:00:00:02"));
543
544 //---------------------------------------------------------------------------------------------
545
546 /*
547 * Test MSDU and MPDU aggregation. Three MSDUs are in the queue and the maximum A-MSDU size
548 * is such that only two MSDUs can be aggregated. Therefore, the first MPDU we get contains
549 * an A-MSDU of 2 MSDUs.
550 */
551 auto fem = m_mac->GetFrameExchangeManager(SINGLE_LINK_OP_ID);
552 auto htFem = DynamicCast<HtFrameExchangeManager>(fem);
553 auto msduAggregator = htFem->GetMsduAggregator();
554 auto mpduAggregator = htFem->GetMpduAggregator();
555
556 auto peeked = GetBeQueue()->PeekNextMpdu(SINGLE_LINK_OP_ID);
557 WifiTxParameters txParams;
558 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
559 peeked->GetHeader(),
560 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
561 htFem->TryAddMpdu(peeked, txParams, Time::Min());
562 auto item = msduAggregator->GetNextAmsdu(peeked, txParams, Time::Min());
563
564 bool result{item};
565 NS_TEST_EXPECT_MSG_EQ(result, true, "aggregation failed");
566 NS_TEST_EXPECT_MSG_EQ(item->GetPacketSize(), 3030, "wrong packet size");
567
568 // dequeue the MSDUs
569 DequeueMpdus({item});
570
571 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
572 1,
573 "Unexpected number of MSDUs left in the EDCA queue");
574
575 //---------------------------------------------------------------------------------------------
576
577 /*
578 * A-MSDU aggregation fails when there is just one MSDU in the queue.
579 */
580
582 txParams.Clear();
583 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
584 peeked->GetHeader(),
585 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
586 htFem->TryAddMpdu(peeked, txParams, Time::Min());
587 item = msduAggregator->GetNextAmsdu(peeked, txParams, Time::Min());
588
589 NS_TEST_EXPECT_MSG_EQ(item, nullptr, "A-MSDU aggregation did not fail");
590
591 DequeueMpdus({peeked});
592
593 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
594 0,
595 "queue should be empty");
596
597 //---------------------------------------------------------------------------------------------
598
599 /*
600 * Aggregation of MPDUs is stopped to prevent that the PPDU duration exceeds the TXOP limit.
601 * In this test, a TXOP limit of 3008 microseconds is used.
602 */
603
604 // Add 10 MSDUs to the EDCA queue
605 EnqueuePkts(10, 1300, Mac48Address("00:00:00:00:00:02"));
606
608 txParams.Clear();
609 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
610 peeked->GetHeader(),
611 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
612
613 // Compute the first MPDU to be aggregated in an A-MPDU. It must contain an A-MSDU
614 // aggregating two MSDUs
615 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, m_params.txopLimit, true);
616
617 NS_TEST_EXPECT_MSG_EQ(std::distance(item->begin(), item->end()),
618 2,
619 "There must be 2 MSDUs in the A-MSDU");
620
621 auto mpduList = mpduAggregator->GetNextAmpdu(item, txParams, m_params.txopLimit);
622
623 // The maximum number of bytes that can be transmitted in a TXOP is (approximately, as we
624 // do not consider that the preamble is transmitted at a different rate):
625 // 19.5 Mbps * 3.008 ms = 7332 bytes
626 // Given that the max A-MSDU size is set to 3050, an A-MSDU will contain two MSDUs and have
627 // a size of 2 * 1300 (MSDU size) + 2 * 14 (A-MSDU subframe header size) + 2 (one padding field)
628 // = 2630 bytes Hence, we expect that the A-MPDU will consist of:
629 // - 2 MPDUs containing each an A-MSDU. The size of each MPDU is 2630 (A-MSDU) + 30
630 // (header+trailer) = 2660
631 // - 1 MPDU containing a single MSDU. The size of such MPDU is 1300 (MSDU) + 30 (header+trailer)
632 // = 1330 The size of the A-MPDU is 4 + 2660 + 4 + 2660 + 4 + 1330 = 6662
633 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "aggregation failed");
634 NS_TEST_EXPECT_MSG_EQ(mpduList.size(), 3, "Unexpected number of MPDUs in the A-MPDU");
635 NS_TEST_EXPECT_MSG_EQ(mpduList.at(0)->GetSize(), 2660, "Unexpected size of the first MPDU");
636 NS_TEST_EXPECT_MSG_EQ(mpduList.at(0)->GetHeader().IsQosAmsdu(),
637 true,
638 "Expecting the first MPDU to contain an A-MSDU");
639 NS_TEST_EXPECT_MSG_EQ(mpduList.at(1)->GetSize(), 2660, "Unexpected size of the second MPDU");
640 NS_TEST_EXPECT_MSG_EQ(mpduList.at(1)->GetHeader().IsQosAmsdu(),
641 true,
642 "Expecting the second MPDU to contain an A-MSDU");
643 NS_TEST_EXPECT_MSG_EQ(mpduList.at(2)->GetSize(), 1330, "Unexpected size of the third MPDU");
644 NS_TEST_EXPECT_MSG_EQ(mpduList.at(2)->GetHeader().IsQosAmsdu(),
645 false,
646 "Expecting the third MPDU not to contain an A-MSDU");
647
648 auto psdu = Create<WifiPsdu>(mpduList);
649 NS_TEST_EXPECT_MSG_EQ(psdu->GetSize(), 6662, "Unexpected size of the A-MPDU");
650
651 // we now have two A-MSDUs and 6 MSDUs in the queue (5 MSDUs with no assigned sequence number)
652 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
653 8,
654 "Unexpected number of items left in the EDCA queue");
655
656 // prepare another A-MPDU (e.g., for transmission on another link)
657 peeked = GetBeQueue()->PeekNextMpdu(SINGLE_LINK_OP_ID, 0, psdu->GetAddr1(), mpduList.at(2));
658 txParams.Clear();
659 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
660 peeked->GetHeader(),
661 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
662
663 // Compute the first MPDU to be aggregated in an A-MPDU. It must contain an A-MSDU
664 // aggregating two MSDUs
665 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, m_params.txopLimit, true);
666
667 NS_TEST_EXPECT_MSG_EQ(std::distance(item->begin(), item->end()),
668 2,
669 "There must be 2 MSDUs in the A-MSDU");
670
671 auto mpduList2 = mpduAggregator->GetNextAmpdu(item, txParams, m_params.txopLimit);
672
673 // we now have two A-MSDUs, one MSDU, two A-MSDUs and one MSDU in the queue (all with assigned
674 // sequence number)
675 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
676 6,
677 "Unexpected number of items left in the EDCA queue");
678
679 // unassign sequence numbers for all MPDUs (emulates an RTS/CTS failure on both links)
680 mpduList.at(0)->UnassignSeqNo();
681 mpduList.at(1)->UnassignSeqNo();
682 mpduList.at(2)->UnassignSeqNo();
683 mpduList2.at(0)->UnassignSeqNo();
684 mpduList2.at(1)->UnassignSeqNo();
685 mpduList2.at(2)->UnassignSeqNo();
686
687 // set A-MSDU max size to a large value
688 m_mac->SetAttribute("BE_MaxAmsduSize", UintegerValue(7000));
689
690 // A-MSDU aggregation now fails because the first item in the queue contain A-MSDUs
692 txParams.Clear();
693 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
694 peeked->GetHeader(),
695 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
696
697 htFem->TryAddMpdu(peeked, txParams, Time::Min());
698 item = msduAggregator->GetNextAmsdu(peeked, txParams, Time::Min());
699
700 NS_TEST_EXPECT_MSG_EQ(item, nullptr, "Expecting not to be able to aggregate A-MSDUs");
701
702 // remove the first two items in the queue (containing A-MSDUs)
703 DequeueMpdus({mpduList.at(0), mpduList.at(1)});
704
705 // we now have one MSDU, two A-MSDUs and one MSDU in the queue
706 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
707 4,
708 "Unexpected number of items left in the EDCA queue");
709
711 txParams.Clear();
712 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
713 peeked->GetHeader(),
714 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
715
716 NS_TEST_EXPECT_MSG_EQ(peeked->GetHeader().IsQosAmsdu(),
717 false,
718 "Expecting the peeked MPDU not to contain an A-MSDU");
719
720 item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
721
722 // A-MSDU aggregation is not attempted because the next item contains an A-MSDU
723 NS_TEST_EXPECT_MSG_EQ(item->GetHeader().IsQosAmsdu(),
724 false,
725 "Expecting the returned MPDU not to contain an A-MSDU");
726}
727
728/**
729 * @ingroup wifi-test
730 * @ingroup tests
731 *
732 * @brief 802.11ax aggregation test which permits 64 or 256 MPDUs in A-MPDU according to the
733 * negotiated buffer size.
734 */
736{
737 public:
738 /**
739 * Constructor.
740 *
741 * @param bufferSize the size (in number of MPDUs) of the BlockAck buffer
742 */
743 HeAggregationTest(uint16_t bufferSize);
744
745 private:
746 void DoRun() override;
747};
748
750 : AmpduAggregationTest("Check the correctness of 802.11ax aggregation operations, size=" +
751 std::to_string(bufferSize),
752 Params{.standard = WIFI_STANDARD_80211ax,
753 .nLinks = 1,
754 .dataMode = "HeMcs11",
755 .bufferSize = bufferSize,
756 .maxAmsduSize = 0,
757 .maxAmpduSize = 65535,
758 .txopLimit = Seconds(0)})
759{
760}
761
762void
764{
765 /*
766 * Test behavior when 300 packets are ready for transmission
767 */
768 EnqueuePkts(300, 100, Mac48Address("00:00:00:00:00:02"));
769
770 auto fem = m_mac->GetFrameExchangeManager(SINGLE_LINK_OP_ID);
771 auto htFem = DynamicCast<HtFrameExchangeManager>(fem);
772 auto mpduAggregator = htFem->GetMpduAggregator();
773
774 auto peeked = GetBeQueue()->PeekNextMpdu(SINGLE_LINK_OP_ID);
775 WifiTxParameters txParams;
776 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
777 peeked->GetHeader(),
778 m_phys.at(SINGLE_LINK_OP_ID)->GetChannelWidth());
779 auto item = GetBeQueue()->GetNextMpdu(SINGLE_LINK_OP_ID, peeked, txParams, Time::Min(), true);
780
781 auto mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
782 DequeueMpdus(mpduList);
783
784 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
785 NS_TEST_EXPECT_MSG_EQ(mpduList.size(),
787 "A-MPDU contains an unexpected number of MPDUs");
788 uint16_t expectedRemainingPacketsInQueue = 300 - m_params.bufferSize;
789 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
790 expectedRemainingPacketsInQueue,
791 "Queue contains an unexpected number of MPDUs");
792}
793
794/**
795 * @ingroup wifi-test
796 * @ingroup tests
797 *
798 * @brief 802.11be aggregation test which permits up to 1024 MPDUs in A-MPDU according to the
799 * negotiated buffer size.
800 */
802{
803 public:
804 /**
805 * Constructor.
806 *
807 * @param bufferSize the size (in number of MPDUs) of the BlockAck buffer
808 */
809 EhtAggregationTest(uint16_t bufferSize);
810
811 private:
812 void DoRun() override;
813};
814
816 : AmpduAggregationTest("Check the correctness of 802.11be aggregation operations, size=" +
817 std::to_string(bufferSize),
818 Params{.standard = WIFI_STANDARD_80211be,
819 .nLinks = 2,
820 .dataMode = "EhtMcs13",
821 .bufferSize = bufferSize,
822 .maxAmsduSize = 0,
823 .maxAmpduSize = 102000,
824 .txopLimit = Seconds(0)})
825{
826}
827
828void
830{
831 /*
832 * Test behavior when 1200 packets of 100 bytes each are ready for transmission. The max
833 * A-MPDU size limit (102000 B) is computed to have at most 750 MPDUs aggregated in a single
834 * A-MPDU (each MPDU is 130 B, plus 4 B of A-MPDU subframe header, plus 2 B of padding).
835 */
836 EnqueuePkts(1200, 100, Mac48Address("00:00:00:00:00:02"));
837 const std::size_t maxNMpdus = 750;
838
839 for (uint8_t linkId = 0; linkId < m_params.nLinks; linkId++)
840 {
841 auto fem = m_mac->GetFrameExchangeManager(linkId);
842 auto htFem = DynamicCast<HtFrameExchangeManager>(fem);
843 auto mpduAggregator = htFem->GetMpduAggregator();
844 std::vector<Ptr<WifiMpdu>> mpduList;
845
846 auto peeked = GetBeQueue()->PeekNextMpdu(linkId);
847 if (peeked)
848 {
849 WifiTxParameters txParams;
850 txParams.m_txVector = m_mac->GetWifiRemoteStationManager()->GetDataTxVector(
851 peeked->GetHeader(),
852 m_phys.at(linkId)->GetChannelWidth());
853 auto item = GetBeQueue()->GetNextMpdu(linkId, peeked, txParams, Time::Min(), true);
854
855 mpduList = mpduAggregator->GetNextAmpdu(item, txParams, Time::Min());
856 DequeueMpdus(mpduList);
857 }
858
859 uint16_t expectedRemainingPacketsInQueue;
860
861 if (m_params.bufferSize >= maxNMpdus)
862 {
863 // two A-MPDUs are transmitted concurrently on the two links and together saturate
864 // the transmit window
865 switch (linkId)
866 {
867 case 0:
868 // the first A-MPDU includes maxNMpdus MPDUs
869 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
870 NS_TEST_EXPECT_MSG_EQ(mpduList.size(),
871 maxNMpdus,
872 "A-MPDU contains an unexpected number of MPDUs");
873 expectedRemainingPacketsInQueue = 1200 - maxNMpdus;
874 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
875 expectedRemainingPacketsInQueue,
876 "Queue contains an unexpected number of MPDUs");
877 break;
878 case 1:
879 // the second A-MPDU includes bufferSize - maxNMpdus MPDUs
880 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
881 NS_TEST_EXPECT_MSG_EQ(mpduList.size(),
882 m_params.bufferSize - maxNMpdus,
883 "A-MPDU contains an unexpected number of MPDUs");
884 expectedRemainingPacketsInQueue = 1200 - m_params.bufferSize;
885 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
886 expectedRemainingPacketsInQueue,
887 "Queue contains an unexpected number of MPDUs");
888 break;
889 default:
890 NS_TEST_ASSERT_MSG_EQ(true, false, "Unexpected link ID " << +linkId);
891 }
892 }
893 else
894 {
895 // one A-MPDU is transmitted that saturates the transmit window
896 switch (linkId)
897 {
898 case 0:
899 // the first A-MPDU includes bufferSize MPDUs
900 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), false, "MPDU aggregation failed");
901 NS_TEST_EXPECT_MSG_EQ(mpduList.size(),
903 "A-MPDU contains an unexpected number of MPDUs");
904 expectedRemainingPacketsInQueue = 1200 - m_params.bufferSize;
905 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
906 expectedRemainingPacketsInQueue,
907 "Queue contains an unexpected number of MPDUs");
908 break;
909 case 1:
910 // no more MPDUs can be sent, aggregation fails
911 NS_TEST_EXPECT_MSG_EQ(mpduList.empty(), true, "MPDU aggregation did not fail");
912 expectedRemainingPacketsInQueue = 1200 - m_params.bufferSize;
913 NS_TEST_EXPECT_MSG_EQ(GetBeQueue()->GetWifiMacQueue()->GetNPackets(),
914 expectedRemainingPacketsInQueue,
915 "Queue contains an unexpected number of MPDUs");
916 break;
917 default:
918 NS_TEST_ASSERT_MSG_EQ(true, false, "Unexpected link ID " << +linkId);
919 }
920 }
921 }
922}
923
924/**
925 * @ingroup wifi-test
926 * @ingroup tests
927 *
928 * @brief Test for A-MSDU and A-MPDU aggregation
929 *
930 * This test aims to check that the packets passed to the MAC layer (on the sender
931 * side) are forwarded up to the upper layer (on the receiver side) when A-MSDU and
932 * A-MPDU aggregation are used. This test checks that no packet copies are performed,
933 * hence packets can be tracked by means of a pointer.
934 *
935 * In this test, an HT STA sends 8 packets (each of 1000 bytes) to an HT AP.
936 * The block ack threshold is set to 2, hence the first packet is sent as an MPDU
937 * containing a single MSDU because the establishment of a Block Ack agreement is
938 * not triggered yet. The maximum A-MSDU size is set to 4500 bytes and the
939 * maximum A-MPDU size is set to 7500 bytes, hence the remaining packets are sent
940 * in an A-MPDU containing two MPDUs, the first one including 4 MSDUs and the second
941 * one including 3 MPDUs.
942 *
943 * It is also checked that the MAC header of every MPDU is notified to the FrameExchangeManager
944 * while the PSDU is being transmitted.
945 */
947{
948 public:
949 /**
950 * Constructor.
951 *
952 * @param notifyMacHdrRxEnd whether notification of MAC header reception end is enabled
953 */
954 PreservePacketsInAmpdus(bool notifyMacHdrRxEnd);
955 ~PreservePacketsInAmpdus() override;
956
957 void DoRun() override;
958
959 private:
960 std::list<Ptr<const Packet>> m_packetList; ///< List of packets passed to the MAC
961 std::vector<std::size_t> m_nMpdus; ///< Number of MPDUs in PSDUs passed to the PHY
962 std::vector<std::size_t> m_nMsdus; ///< Number of MSDUs in MPDUs passed to the PHY
963 Ptr<const WifiPsdu> m_txPsdu; ///< PSDU being transmitted
964 std::vector<Ptr<WifiMpdu>>::const_iterator
965 m_expectedMpdu; ///< next MPDU expected to be received
966 std::size_t m_nMacHdrs{0}; ///< Number of notified MAC headers in QoS data frames
967 bool m_notifyMacHdrRxEnd; ///< whether notification of MAC header reception end is enabled
968
969 /**
970 * Callback invoked when an MSDU is passed to the MAC
971 * @param packet the MSDU to transmit
972 */
974 /**
975 * Callback invoked when the sender MAC passes a PSDU(s) to the PHY
976 * @param psduMap the PSDU map
977 * @param txVector the TX vector
978 * @param txPowerW the transmit power in Watts
979 */
980 void NotifyPsduForwardedDown(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
981 /**
982 * Callback invoked when the reception of the MAC header of an MPDU is completed.
983 * @param mac the MAC to which the reception of the MAC header is notified
984 * @param macHdr the MAC header of the MPDU being received
985 * @param txVector the TXVECTOR used to transmit the PSDU
986 * @param psduDuration the remaining duration of the PSDU
987 */
989 const WifiMacHeader& macHdr,
990 const WifiTxVector& txVector,
991 Time psduDuration);
992 /**
993 * Callback invoked when the receiver MAC forwards a packet up to the upper layer
994 * @param p the packet
995 */
997};
998
1000 : TestCase("Test case to check that the Wifi Mac forwards up the same packets received at "
1001 "sender side."),
1002 m_notifyMacHdrRxEnd(notifyMacHdrRxEnd)
1003{
1004}
1005
1009
1010void
1015
1016void
1018 WifiTxVector txVector,
1019 double txPowerW)
1020{
1021 NS_TEST_EXPECT_MSG_EQ((psduMap.size() == 1 && psduMap.begin()->first == SU_STA_ID),
1022 true,
1023 "No DL MU PPDU expected");
1024
1025 // m_txPsdu is reset when the MAC header of the last MPDU in the PSDU is notified. By
1026 // checking that m_txPsdu is nullptr when starting the transmission of a PSDU, we ensure
1027 // that MAC headers are notified to the FEM while receiving MPDUs.
1029 {
1031 nullptr,
1032 "Missing MAC header notification: m_txPsdu was not reset");
1033 }
1034
1035 m_txPsdu = psduMap.at(SU_STA_ID);
1037
1038 if (!psduMap[SU_STA_ID]->GetHeader(0).IsQosData())
1039 {
1040 return;
1041 }
1042
1043 m_nMpdus.push_back(psduMap[SU_STA_ID]->GetNMpdus());
1044
1045 for (auto& mpdu : *PeekPointer(psduMap[SU_STA_ID]))
1046 {
1047 std::size_t dist = std::distance(mpdu->begin(), mpdu->end());
1048 // the list of aggregated MSDUs is empty if the MPDU includes a non-aggregated MSDU
1049 m_nMsdus.push_back(dist > 0 ? dist : 1);
1050 }
1051}
1052
1053void
1055 const WifiMacHeader& macHdr,
1056 const WifiTxVector& txVector,
1057 Time psduDuration)
1058{
1060 nullptr,
1061 "Notified of MAC header RX end while no PSDU is being transmitted");
1062 // check that the FEM stores the expected MAC header (in a nanosecond, to avoid issues
1063 // with the ordering of the callbacks connected to the trace source)
1064 auto expectedHdr = (*m_expectedMpdu)->GetHeader();
1065 Simulator::Schedule(NanoSeconds(1), [=, this]() {
1066 auto macHdr = mac->GetFrameExchangeManager()->GetReceivedMacHdr();
1067 NS_TEST_ASSERT_MSG_EQ(macHdr.has_value(),
1068 true,
1069 "Expected the FEM to store the MAC header being received");
1071 expectedHdr.GetSequenceNumber(),
1072 "Wrong sequence number in the MAC header stored by the FEM");
1073 });
1074
1075 if (expectedHdr.IsQosData())
1076 {
1077 m_nMacHdrs++;
1078 }
1079
1080 if (++m_expectedMpdu == m_txPsdu->end())
1081 {
1082 m_txPsdu = nullptr;
1083 // check that the FEM stores no MAC header right after PSDU end
1084 Simulator::Schedule(psduDuration + NanoSeconds(1), [=, this]() {
1085 auto macHeader = mac->GetFrameExchangeManager()->GetReceivedMacHdr();
1086 NS_TEST_EXPECT_MSG_EQ(macHeader.has_value(),
1087 false,
1088 "Expected the FEM to store no MAC header");
1089 });
1090 }
1091}
1092
1093void
1095{
1096 auto it = std::find(m_packetList.begin(), m_packetList.end(), p);
1097 NS_TEST_EXPECT_MSG_EQ((it != m_packetList.end()), true, "Packet being forwarded up not found");
1098 m_packetList.erase(it);
1099}
1100
1101void
1103{
1104 Config::SetDefault("ns3::WifiPhy::NotifyMacHdrRxEnd", BooleanValue(m_notifyMacHdrRxEnd));
1105
1106 NodeContainer wifiStaNode;
1107 wifiStaNode.Create(1);
1108
1109 NodeContainer wifiApNode;
1110 wifiApNode.Create(1);
1111
1114 phy.SetChannel(channel.Create());
1115
1116 WifiHelper wifi;
1117 wifi.SetStandard(WIFI_STANDARD_80211n);
1118 wifi.SetRemoteStationManager("ns3::IdealWifiManager");
1119
1120 WifiMacHelper mac;
1121 Ssid ssid = Ssid("ns-3-ssid");
1122 mac.SetType("ns3::StaWifiMac",
1123 "BE_MaxAmsduSize",
1124 UintegerValue(4500),
1125 "BE_MaxAmpduSize",
1126 UintegerValue(7500),
1127 "Ssid",
1128 SsidValue(ssid),
1129 /* setting blockack threshold for sta's BE queue */
1130 "BE_BlockAckThreshold",
1131 UintegerValue(2),
1132 "ActiveProbing",
1133 BooleanValue(false));
1134
1135 NetDeviceContainer staDevices;
1136 staDevices = wifi.Install(phy, mac, wifiStaNode);
1137
1138 mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid), "BeaconGeneration", BooleanValue(true));
1139
1140 NetDeviceContainer apDevices;
1141 apDevices = wifi.Install(phy, mac, wifiApNode);
1142
1143 MobilityHelper mobility;
1145
1146 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
1147 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
1148 mobility.SetPositionAllocator(positionAlloc);
1149
1150 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
1151 mobility.Install(wifiApNode);
1152 mobility.Install(wifiStaNode);
1153
1154 Ptr<WifiNetDevice> ap_device = DynamicCast<WifiNetDevice>(apDevices.Get(0));
1155 Ptr<WifiNetDevice> sta_device = DynamicCast<WifiNetDevice>(staDevices.Get(0));
1156
1157 PacketSocketAddress socket;
1158 socket.SetSingleDevice(sta_device->GetIfIndex());
1159 socket.SetPhysicalAddress(ap_device->GetAddress());
1160 socket.SetProtocol(1);
1161
1162 // install packet sockets on nodes.
1163 PacketSocketHelper packetSocket;
1164 packetSocket.Install(wifiStaNode);
1165 packetSocket.Install(wifiApNode);
1166
1168 client->SetAttribute("PacketSize", UintegerValue(1000));
1169 client->SetAttribute("MaxPackets", UintegerValue(8));
1170 client->SetAttribute("Interval", TimeValue(Seconds(1)));
1171 client->SetRemote(socket);
1172 wifiStaNode.Get(0)->AddApplication(client);
1173 client->SetStartTime(Seconds(1));
1174 client->SetStopTime(Seconds(3));
1176 &PacketSocketClient::SetAttribute,
1177 client,
1178 "Interval",
1180
1182 server->SetLocal(socket);
1183 wifiApNode.Get(0)->AddApplication(server);
1184 server->SetStartTime(Seconds(0));
1185 server->SetStopTime(Seconds(4));
1186
1187 sta_device->GetMac()->TraceConnectWithoutContext(
1188 "MacTx",
1190 sta_device->GetPhy()->TraceConnectWithoutContext(
1191 "PhyTxPsduBegin",
1193 ap_device->GetPhy()->TraceConnectWithoutContext(
1194 "PhyRxMacHeaderEnd",
1196 .Bind(ap_device->GetMac()));
1197 ap_device->GetMac()->TraceConnectWithoutContext(
1198 "MacRx",
1200
1203
1205
1206 // Two packets are transmitted. The first one is an MPDU containing a single MSDU.
1207 // The second one is an A-MPDU containing two MPDUs: the first MPDU contains 4 MSDUs
1208 // and the second MPDU contains 3 MSDUs
1209 NS_TEST_EXPECT_MSG_EQ(m_nMpdus.size(), 2, "Unexpected number of transmitted packets");
1210 NS_TEST_EXPECT_MSG_EQ(m_nMsdus.size(), 3, "Unexpected number of transmitted MPDUs");
1211 NS_TEST_EXPECT_MSG_EQ(m_nMpdus[0], 1, "Unexpected number of MPDUs in the first A-MPDU");
1212 NS_TEST_EXPECT_MSG_EQ(m_nMsdus[0], 1, "Unexpected number of MSDUs in the first MPDU");
1213 NS_TEST_EXPECT_MSG_EQ(m_nMpdus[1], 2, "Unexpected number of MPDUs in the second A-MPDU");
1214 NS_TEST_EXPECT_MSG_EQ(m_nMsdus[1], 4, "Unexpected number of MSDUs in the second MPDU");
1215 NS_TEST_EXPECT_MSG_EQ(m_nMsdus[2], 3, "Unexpected number of MSDUs in the third MPDU");
1216 // Three MPDUs (of type QoS data) have been transmitted, so we expect that 3 MAC headers
1217 // have been notified to the FEM
1219 (m_notifyMacHdrRxEnd ? 3 : 0),
1220 "Unexpected number of MAC headers notified to the FEM");
1221 // All the packets must have been forwarded up at the receiver
1222 NS_TEST_EXPECT_MSG_EQ(m_packetList.empty(), true, "Some packets have not been forwarded up");
1223}
1224
1225/**
1226 * @ingroup wifi-test
1227 * @ingroup tests
1228 *
1229 * @brief Wifi Aggregation Test Suite
1230 */
1232{
1233 public:
1235};
1236
1238 : TestSuite("wifi-aggregation", Type::UNIT)
1239{
1240 AddTestCase(new AmpduAggregationTest, TestCase::Duration::QUICK);
1241 AddTestCase(new TwoLevelAggregationTest, TestCase::Duration::QUICK);
1242 AddTestCase(new HeAggregationTest(64), TestCase::Duration::QUICK);
1243 AddTestCase(new HeAggregationTest(256), TestCase::Duration::QUICK);
1244 AddTestCase(new EhtAggregationTest(512), TestCase::Duration::QUICK);
1245 AddTestCase(new EhtAggregationTest(1024), TestCase::Duration::QUICK);
1246 AddTestCase(new PreservePacketsInAmpdus(true), TestCase::Duration::QUICK);
1247 AddTestCase(new PreservePacketsInAmpdus(false), TestCase::Duration::QUICK);
1248}
1249
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.
AttributeValue implementation for Boolean.
Definition boolean.h:26
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:285
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:385
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:520
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
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
AttributeValue implementation for Ssid.
Definition ssid.h:85
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
AttributeValue implementation for Time.
Definition nstime.h:1432
Ptr< WifiMacQueue > GetWifiMacQueue() const
Return the packet queue associated with this Txop.
Definition txop.cc:268
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:344
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
Definition wifi-psdu.cc:332
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:886
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:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
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:71
@ 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
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:272
@ WIFI_MAC_QOSDATA
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
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