A Discrete-Event Network Simulator
API
wifi-mac-queue-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 IITP RAS
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Alexander Krotov <krotov@iitp.ru>
18  */
19 
20 #include "ns3/fcfs-wifi-queue-scheduler.h"
21 #include "ns3/simulator.h"
22 #include "ns3/test.h"
23 #include "ns3/wifi-mac-queue.h"
24 
25 #include <algorithm>
26 
27 using namespace ns3;
28 
40 {
41  public:
46 
47  void DoRun() override;
48 };
49 
51  : TestCase("Test DROP_OLDEST setting")
52 {
53 }
54 
55 void
57 {
58  auto wifiMacQueue = CreateObject<WifiMacQueue>(AC_BE);
59  wifiMacQueue->SetMaxSize(QueueSize("5p"));
60  auto wifiMacScheduler = CreateObject<FcfsWifiQueueScheduler>();
61  wifiMacScheduler->SetAttribute("DropPolicy", EnumValue(FcfsWifiQueueScheduler::DROP_OLDEST));
62  wifiMacScheduler->m_perAcInfo[AC_BE].wifiMacQueue = wifiMacQueue;
63  wifiMacQueue->SetScheduler(wifiMacScheduler);
64 
65  Mac48Address addr1 = Mac48Address::Allocate();
66 
67  // Initialize the queue with 5 packets.
68  std::list<uint64_t> packetUids;
69  for (uint32_t i = 0; i < 5; i++)
70  {
71  WifiMacHeader header;
72  header.SetType(WIFI_MAC_QOSDATA);
73  header.SetAddr1(addr1);
74  header.SetQosTid(0);
75  auto packet = Create<Packet>();
76  auto item = Create<WifiMpdu>(packet, header);
77  wifiMacQueue->Enqueue(item);
78 
79  packetUids.push_back(packet->GetUid());
80  }
81 
82  // Check that all elements are inserted successfully.
83  auto mpdu = wifiMacQueue->PeekByTidAndAddress(0, addr1);
84  NS_TEST_EXPECT_MSG_EQ(wifiMacQueue->GetNPackets(),
85  5,
86  "Queue has unexpected number of elements");
87  for (auto packetUid : packetUids)
88  {
89  NS_TEST_EXPECT_MSG_EQ(mpdu->GetPacket()->GetUid(),
90  packetUid,
91  "Stored packet is not the expected one");
92  mpdu = wifiMacQueue->PeekByTidAndAddress(0, addr1, mpdu);
93  }
94 
95  // Push another element into the queue.
96  WifiMacHeader header;
97  header.SetType(WIFI_MAC_QOSDATA);
98  header.SetAddr1(addr1);
99  header.SetQosTid(0);
100  auto packet = Create<Packet>();
101  auto item = Create<WifiMpdu>(packet, header);
102  wifiMacQueue->Enqueue(item);
103 
104  // Update the list of expected packet UIDs.
105  packetUids.pop_front();
106  packetUids.push_back(packet->GetUid());
107 
108  // Check that front packet was replaced correctly.
109  mpdu = wifiMacQueue->PeekByTidAndAddress(0, addr1);
110  NS_TEST_EXPECT_MSG_EQ(wifiMacQueue->GetNPackets(),
111  5,
112  "Queue has unexpected number of elements");
113  for (auto packetUid : packetUids)
114  {
115  NS_TEST_EXPECT_MSG_EQ(mpdu->GetPacket()->GetUid(),
116  packetUid,
117  "Stored packet is not the expected one");
118  mpdu = wifiMacQueue->PeekByTidAndAddress(0, addr1, mpdu);
119  }
120 
121  wifiMacScheduler->Dispose();
122  Simulator::Destroy();
123 }
124 
136 {
137  public:
139 
140  private:
141  void DoRun() override;
142 
150  void Enqueue(Mac48Address rxAddr, bool inflight, Time expiryTime);
151 
153  uint16_t m_currentSeqNo{0};
155 };
156 
158  : TestCase("Test extraction of expired MPDUs from MAC queue container")
159 {
160 }
161 
162 void
163 WifiExtractExpiredMpdusTest::Enqueue(Mac48Address rxAddr, bool inflight, Time expiryTime)
164 {
166  header.SetAddr1(rxAddr);
167  header.SetAddr2(m_txAddr);
168  header.SetQosTid(0);
170  auto mpdu = Create<WifiMpdu>(Create<Packet>(), header);
171 
172  auto queueId = WifiMacQueueContainer::GetQueueId(mpdu);
173  auto elemIt = m_container.insert(m_container.GetQueue(queueId).cend(), mpdu);
174  elemIt->expiryTime = expiryTime;
175  if (inflight)
176  {
177  elemIt->inflights.emplace(0, mpdu);
178  }
179  elemIt->deleter = [](auto mpdu) {};
180 }
181 
182 void
184 {
185  m_txAddr = Mac48Address::Allocate();
186  auto rxAddr1 = Mac48Address::Allocate();
187  auto rxAddr2 = Mac48Address::Allocate();
188 
206  Enqueue(rxAddr1, true, MilliSeconds(10));
207  Enqueue(rxAddr1, false, MilliSeconds(10));
208  Enqueue(rxAddr1, true, MilliSeconds(12));
209  Enqueue(rxAddr1, false, MilliSeconds(15));
210  Enqueue(rxAddr1, true, MilliSeconds(30));
211  Enqueue(rxAddr1, false, MilliSeconds(30));
212  Enqueue(rxAddr1, true, MilliSeconds(35));
213  Enqueue(rxAddr1, false, MilliSeconds(35));
214  Enqueue(rxAddr1, false, MilliSeconds(40));
215  Enqueue(rxAddr1, false, MilliSeconds(75));
216  Enqueue(rxAddr1, false, MilliSeconds(75));
217 
218  Enqueue(rxAddr2, false, MilliSeconds(11));
219  Enqueue(rxAddr2, true, MilliSeconds(11));
220  Enqueue(rxAddr2, true, MilliSeconds(13));
221  Enqueue(rxAddr2, false, MilliSeconds(30));
222  Enqueue(rxAddr2, true, MilliSeconds(35));
223  Enqueue(rxAddr2, true, MilliSeconds(40));
224  Enqueue(rxAddr2, false, MilliSeconds(40));
225  Enqueue(rxAddr2, false, MilliSeconds(70));
226  Enqueue(rxAddr2, false, MilliSeconds(75));
227 
230 
231  Simulator::Schedule(MilliSeconds(25), [&]() {
235  auto [first1, last1] = m_container.ExtractExpiredMpdus(queueId1);
236  // MPDU 0 not extracted because inflight, MPDU 1 extracted
237  NS_TEST_EXPECT_MSG_EQ((first1 != last1), true, "Expected one MPDU extracted");
238  NS_TEST_EXPECT_MSG_EQ(first1->mpdu->GetHeader().GetSequenceNumber(),
239  1,
240  "Unexpected extracted MPDU");
241  first1++;
242  // MPDU 2 not extracted because inflight, MPDU 3 extracted
243  NS_TEST_EXPECT_MSG_EQ((first1 != last1), true, "Expected two MPDUs extracted");
244  NS_TEST_EXPECT_MSG_EQ(first1->mpdu->GetHeader().GetSequenceNumber(),
245  3,
246  "Unexpected extracted MPDU");
247  first1++;
248  // No other expired MPDU
249  NS_TEST_EXPECT_MSG_EQ((first1 == last1), true, "Did not expect other expired MPDUs");
250 
251  // If we try to extract expired MPDUs again, the returned set is empty
252  {
253  auto [first, last] = m_container.ExtractExpiredMpdus(queueId1);
254  NS_TEST_EXPECT_MSG_EQ((first == last), true, "Did not expect other expired MPDUs");
255  }
256 
260  auto [first2, last2] = m_container.ExtractExpiredMpdus(queueId2);
261  // MPDU 11 extracted
262  NS_TEST_EXPECT_MSG_EQ((first2 != last2), true, "Expected one MPDU extracted");
263  NS_TEST_EXPECT_MSG_EQ(first2->mpdu->GetHeader().GetSequenceNumber(),
264  11,
265  "Unexpected extracted MPDU");
266  first2++;
267  // MPDU 12 and 13 not extracted because inflight, no other expired MPDU
268  NS_TEST_EXPECT_MSG_EQ((first2 == last2), true, "Did not expect other expired MPDUs");
269 
270  // If we try to extract expired MPDUs again, the returned set is empty
271  {
272  auto [first, last] = m_container.ExtractExpiredMpdus(queueId2);
273  NS_TEST_EXPECT_MSG_EQ((first == last), true, "Did not expect other expired MPDUs");
274  }
275  });
276 
294  Simulator::Schedule(MilliSeconds(50), [&]() {
298  auto [first, last] = m_container.ExtractAllExpiredMpdus();
299 
300  std::set<uint16_t> expectedSeqNo{5, 7, 8, 14, 17};
301  std::set<uint16_t> actualSeqNo;
302 
303  std::transform(first, last, std::inserter(actualSeqNo, actualSeqNo.end()), [](auto& elem) {
304  return elem.mpdu->GetHeader().GetSequenceNumber();
305  });
306 
307  NS_TEST_EXPECT_MSG_EQ(expectedSeqNo.size(),
308  actualSeqNo.size(),
309  "Unexpected number of MPDUs extracted");
310 
311  for (auto expectedIt = expectedSeqNo.begin(), actualIt = actualSeqNo.begin();
312  expectedIt != expectedSeqNo.end();
313  ++expectedIt, ++actualIt)
314  {
315  NS_TEST_EXPECT_MSG_EQ(*expectedIt, *actualIt, "Unexpected extracted MPDU");
316  }
317 
318  // If we try to extract expired MPDUs again, the returned set is empty
319  {
320  auto [first, last] = m_container.ExtractAllExpiredMpdus();
321  NS_TEST_EXPECT_MSG_EQ((first == last), true, "Did not expect other expired MPDUs");
322  }
323 
327  auto elemIt = m_container.GetQueue(queueId1).begin();
328  auto endIt = m_container.GetQueue(queueId1).end();
329  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
330  true,
331  "There should be other MPDU(s) in container queue 1");
332  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
333  0,
334  "Unexpected queued MPDU");
335  elemIt++;
336  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
337  true,
338  "There should be other MPDU(s) in container queue 1");
339  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
340  2,
341  "Unexpected queued MPDU");
342  elemIt++;
343  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
344  true,
345  "There should be other MPDU(s) in container queue 1");
346  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
347  4,
348  "Unexpected queued MPDU");
349  elemIt++;
350  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
351  true,
352  "There should be other MPDU(s) in container queue 1");
353  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
354  6,
355  "Unexpected queued MPDU");
356  elemIt++;
357  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
358  true,
359  "There should be other MPDU(s) in container queue 1");
360  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
361  9,
362  "Unexpected queued MPDU");
363  elemIt++;
364  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
365  true,
366  "There should be other MPDU(s) in container queue 1");
367  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
368  10,
369  "Unexpected queued MPDU");
370  elemIt++;
371  NS_TEST_EXPECT_MSG_EQ((elemIt == endIt),
372  true,
373  "There should be no other MPDU in container queue 1");
374 
378  elemIt = m_container.GetQueue(queueId2).begin();
379  endIt = m_container.GetQueue(queueId2).end();
380  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
381  true,
382  "There should be other MPDU(s) in container queue 2");
383  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
384  12,
385  "Unexpected queued MPDU");
386  elemIt++;
387  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
388  true,
389  "There should be other MPDU(s) in container queue 2");
390  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
391  13,
392  "Unexpected queued MPDU");
393  elemIt++;
394  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
395  true,
396  "There should be other MPDU(s) in container queue 2");
397  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
398  15,
399  "Unexpected queued MPDU");
400  elemIt++;
401  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
402  true,
403  "There should be other MPDU(s) in container queue 2");
404  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
405  16,
406  "Unexpected queued MPDU");
407  elemIt++;
408  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
409  true,
410  "There should be other MPDU(s) in container queue 2");
411  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
412  18,
413  "Unexpected queued MPDU");
414  elemIt++;
415  NS_TEST_EXPECT_MSG_EQ((elemIt != endIt),
416  true,
417  "There should be other MPDU(s) in container queue 2");
418  NS_TEST_EXPECT_MSG_EQ(elemIt->mpdu->GetHeader().GetSequenceNumber(),
419  19,
420  "Unexpected queued MPDU");
421  elemIt++;
422  NS_TEST_EXPECT_MSG_EQ((elemIt == endIt),
423  true,
424  "There should be no other MPDU in container queue 2");
425  });
426 
427  Simulator::Run();
428  Simulator::Destroy();
429 }
430 
438 {
439  public:
441 };
442 
444  : TestSuite("wifi-mac-queue", UNIT)
445 {
446  AddTestCase(new WifiMacQueueDropOldestTest, TestCase::QUICK);
447  AddTestCase(new WifiExtractExpiredMpdusTest, TestCase::QUICK);
448 }
449 
Test extraction of expired MPDUs from MAC queue container.
uint16_t m_currentSeqNo
sequence number of current MPDU
Mac48Address m_txAddr
Transmitter Address of MPDUs.
WifiMacQueueContainer m_container
MAC queue container.
void DoRun() override
Implementation to actually run this TestCase.
void Enqueue(Mac48Address rxAddr, bool inflight, Time expiryTime)
Enqueue a new MPDU into the container.
Test DROP_OLDEST setting.
void DoRun() override
Implementation to actually run this TestCase.
Wifi MAC Queue Test Suite.
Hold variables of type enum.
Definition: enum.h:62
an EUI-48 address
Definition: mac48-address.h:46
Class for representing queue sizes.
Definition: queue-size.h:96
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
Implements the IEEE 802.11 MAC header.
void SetSequenceNumber(uint16_t seq)
Set 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.
Class for the container used by WifiMacQueue.
const ContainerQueue & GetQueue(const WifiContainerQueueId &queueId) const
Get a const reference to the container queue identified by the given QueueId.
std::pair< iterator, iterator > ExtractAllExpiredMpdus() const
Transfer non-inflight MPDUs with expired lifetime in all the container queues to the container queue ...
iterator insert(const_iterator pos, Ptr< WifiMpdu > item)
Insert the given item at the specified location in the container.
std::pair< iterator, iterator > ExtractExpiredMpdus(const WifiContainerQueueId &queueId) const
Transfer non-inflight MPDUs with expired lifetime in the container queue identified by the given Queu...
#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:251
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
@ AC_BE
Best Effort.
Definition: qos-utils.h:75
Definition: first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::tuple< WifiContainerQueueType, WifiReceiverAddressType, Mac48Address, std::optional< uint8_t > > WifiContainerQueueId
Tuple (queue type, receiver address type, Address, TID) identifying a container queue.
@ WIFI_MAC_QOSDATA
static WifiMacQueueTestSuite g_wifiMacQueueTestSuite
the test suite