A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
27using namespace ns3;
28
29/**
30 * \ingroup wifi-test
31 * \ingroup tests
32 *
33 * \brief Test DROP_OLDEST setting.
34 *
35 * This test verifies the correctness of DROP_OLDEST policy when packets
36 * are pushed into the front of the queue. This case is not handled
37 * by the underlying ns3::Queue<WifiMpdu>.
38 */
40{
41 public:
42 /**
43 * \brief Constructor
44 */
46
47 void DoRun() override;
48};
49
51 : TestCase("Test DROP_OLDEST setting")
52{
53}
54
55void
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
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;
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;
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();
123}
124
125/**
126 * \ingroup wifi-test
127 * \ingroup tests
128 *
129 * \brief Test extraction of expired MPDUs from MAC queue container
130 *
131 * This test verifies the correctness of the WifiMacQueueContainer methods
132 * (ExtractExpiredMpdus and ExtractAllExpiredMpdus) that extract MPDUs with
133 * expired lifetime from the MAC queue container.
134 */
136{
137 public:
139
140 private:
141 void DoRun() override;
142
143 /**
144 * Enqueue a new MPDU into the container.
145 *
146 * \param rxAddr Receiver Address of the MPDU
147 * \param inflight whether the MPDU is inflight
148 * \param expiryTime the expity time for the MPDU
149 */
150 void Enqueue(Mac48Address rxAddr, bool inflight, Time expiryTime);
151
152 WifiMacQueueContainer m_container; //!< MAC queue container
153 uint16_t m_currentSeqNo{0}; //!< sequence number of current MPDU
154 Mac48Address m_txAddr; //!< Transmitter Address of MPDUs
155};
156
158 : TestCase("Test extraction of expired MPDUs from MAC queue container")
159{
160}
161
162void
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
182void
184{
186 auto rxAddr1 = Mac48Address::Allocate();
187 auto rxAddr2 = Mac48Address::Allocate();
188
189 /**
190 * At simulation time 25ms:
191 *
192 * Container queue for rxAddr1
193 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
194 * │Exp│Exp│Exp│Exp│ │ │ │ │ │ │ │
195 * │Inf│ │Inf│ │Inf│ │Inf│ │ │ │ │
196 * │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │10 │
197 * └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
198 *
199 * Container queue for rxAddr2
200 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
201 * │Exp│Exp│Exp│ │ │ │ │ │ │
202 * │ │Inf│Inf│ │Inf│Inf│ │ │ │
203 * │11 │12 │13 │14 │15 │16 │17 │18 │19 │
204 * └───┴───┴───┴───┴───┴───┴───┴───┴───┘
205 */
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
232 /**
233 * Extract expired MPDUs from container queue 1
234 */
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
257 /**
258 * Extract expired MPDUs from container queue 2
259 */
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
277 /**
278 * At simulation time 50ms:
279 *
280 * Container queue for rxAddr1
281 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
282 * │Exp│Exp│Exp│Exp│Exp│Exp│Exp│ │ │
283 * │Inf│Inf│Inf│ │Inf│ │ │ │ │
284 * │ 0 │ 2 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │10 │
285 * └───┴───┴───┴───┴───┴───┴───┴───┴───┘
286 *
287 * Container queue for rxAddr2
288 * ┌───┬───┬───┬───┬───┬───┬───┬───┐
289 * │Exp│Exp│Exp│Exp│Exp│Exp│ │ │
290 * │Inf│Inf│ │Inf│Inf│ │ │ │
291 * │12 │13 │14 │15 │16 │17 │18 │19 │
292 * └───┴───┴───┴───┴───┴───┴───┴───┘
293 */
295 /**
296 * Extract all expired MPDUs (from container queue 1 and 2)
297 */
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 {
321 NS_TEST_EXPECT_MSG_EQ((first == last), true, "Did not expect other expired MPDUs");
322 }
323
324 /**
325 * Check MPDUs remaining in container queue 1
326 */
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
375 /**
376 * Check MPDUs remaining in container queue 2
377 */
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
429}
430
431/**
432 * \ingroup wifi-test
433 * \ingroup tests
434 *
435 * \brief Wifi MAC Queue Test Suite
436 */
438{
439 public:
441};
442
444 : TestSuite("wifi-mac-queue", Type::UNIT)
445{
446 AddTestCase(new WifiMacQueueDropOldestTest, TestCase::Duration::QUICK);
447 AddTestCase(new WifiExtractExpiredMpdusTest, TestCase::Duration::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
static Mac48Address Allocate()
Allocate a new Mac48Address.
Class for representing queue sizes.
Definition: queue-size.h:96
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static void Run()
Run the simulation.
Definition: simulator.cc:178
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
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.
static WifiContainerQueueId GetQueueId(Ptr< const WifiMpdu > mpdu)
Return the QueueId identifying the container queue in which the given MPDU is (or is to be) enqueued.
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:252
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