A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-mac-queue-container.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
10
11#include "ctrl-headers.h"
12#include "wifi-mpdu.h"
13
14#include "ns3/mac48-address.h"
15#include "ns3/simulator.h"
16
17#include <vector>
18
19namespace ns3
20{
21
22void
24{
25 m_queues.clear();
26 m_expiredQueue.clear();
27 m_nBytesPerQueue.clear();
28}
29
32{
33 WifiContainerQueueId queueId = GetQueueId(item);
34
35 NS_ABORT_MSG_UNLESS(pos == m_queues[queueId].cend() || GetQueueId(pos->mpdu) == queueId,
36 "pos iterator does not point to the correct container queue");
37 NS_ABORT_MSG_IF(!item->IsOriginal(), "Only the original copy of an MPDU can be inserted");
38
39 auto [it, ret] = m_nBytesPerQueue.insert({queueId, 0});
40 it->second += item->GetSize();
41
42 return m_queues[queueId].emplace(pos, item);
43}
44
47{
48 if (pos->expired)
49 {
50 return m_expiredQueue.erase(pos);
51 }
52
53 WifiContainerQueueId queueId = GetQueueId(pos->mpdu);
54 auto it = m_nBytesPerQueue.find(queueId);
55 NS_ASSERT(it != m_nBytesPerQueue.end());
56 NS_ASSERT(it->second >= pos->mpdu->GetSize());
57 it->second -= pos->mpdu->GetSize();
58
59 return m_queues[queueId].erase(pos);
60}
61
64{
65 return it->mpdu;
66}
67
70{
71 // the given MPDU may be an alias and we need its original version to correctly identify the
72 // container queue in which the MPDU is enqueued
73 const auto& hdr = mpdu->GetOriginal()->GetHeader();
74
75 WifiRcvAddr addrType;
76 std::optional<Mac48Address> addr1;
77 std::optional<Mac48Address> addr2;
78
79 if (hdr.GetAddr1().IsBroadcast())
80 {
81 addrType = WifiRcvAddr::BROADCAST;
82 addr2 = hdr.GetAddr2();
83 }
84 else if (hdr.GetAddr1().IsGroup())
85 {
86 addrType = WifiRcvAddr::GROUPCAST;
87 addr1 = hdr.IsQosAmsdu() ? mpdu->begin()->second.GetDestinationAddr() : hdr.GetAddr1();
88 addr2 = hdr.GetAddr2();
89 }
90 else
91 {
92 addrType = WifiRcvAddr::UNICAST;
93 addr1 = hdr.GetAddr1();
94 }
95
96 if (hdr.IsCtl())
97 {
98 return {WIFI_CTL_QUEUE, addrType, addr1, addr2, std::nullopt};
99 }
100 if (hdr.IsMgt())
101 {
102 return {WIFI_MGT_QUEUE, addrType, addr1, addr2, std::nullopt};
103 }
104 if (hdr.IsQosData())
105 {
106 return {WIFI_QOSDATA_QUEUE, addrType, addr1, addr2, hdr.GetQosTid()};
107 }
108 return {WIFI_DATA_QUEUE, addrType, addr1, addr2, std::nullopt};
109}
110
113{
114 return m_queues[queueId];
115}
116
119{
120 if (auto it = m_queues.find(queueId); it == m_queues.end() || it->second.empty())
121 {
122 return 0;
123 }
124 return m_nBytesPerQueue.at(queueId);
125}
126
127std::pair<WifiMacQueueContainer::iterator, WifiMacQueueContainer::iterator>
132
133std::pair<WifiMacQueueContainer::iterator, WifiMacQueueContainer::iterator>
135{
136 std::optional<std::pair<WifiMacQueueContainer::iterator, WifiMacQueueContainer::iterator>> ret;
137 auto firstExpiredIt = queue.begin();
138 auto lastExpiredIt = firstExpiredIt;
139 Time now = Simulator::Now();
140
141 do
142 {
143 // advance firstExpiredIt and lastExpiredIt to skip all inflight MPDUs
144 for (firstExpiredIt = lastExpiredIt;
145 firstExpiredIt != queue.end() && !firstExpiredIt->inflights.empty();
146 ++firstExpiredIt, ++lastExpiredIt)
147 {
148 }
149
150 if (!ret)
151 {
152 // we get here in the first iteration only
153 ret = std::make_pair(firstExpiredIt, lastExpiredIt);
154 }
155
156 // advance lastExpiredIt as we encounter MPDUs with expired lifetime that are not inflight
157 while (lastExpiredIt != queue.end() && lastExpiredIt->expiryTime <= now &&
158 lastExpiredIt->inflights.empty())
159 {
160 lastExpiredIt->expired = true;
161 // this MPDU is no longer queued
162 lastExpiredIt->ac = AC_UNDEF;
163 lastExpiredIt->deleter(lastExpiredIt->mpdu);
164
165 WifiContainerQueueId queueId = GetQueueId(lastExpiredIt->mpdu);
166 auto it = m_nBytesPerQueue.find(queueId);
167 NS_ASSERT(it != m_nBytesPerQueue.end());
168 NS_ASSERT(it->second >= lastExpiredIt->mpdu->GetSize());
169 it->second -= lastExpiredIt->mpdu->GetSize();
170
171 ++lastExpiredIt;
172 }
173
174 if (lastExpiredIt == firstExpiredIt)
175 {
176 break;
177 }
178
179 // transfer non-inflight MPDUs with expired lifetime to the tail of m_expiredQueue
180 m_expiredQueue.splice(m_expiredQueue.end(), queue, firstExpiredIt, lastExpiredIt);
181 ret->second = m_expiredQueue.end();
182
183 } while (true);
184
185 return *ret;
186}
187
188std::pair<WifiMacQueueContainer::iterator, WifiMacQueueContainer::iterator>
190{
191 std::optional<WifiMacQueueContainer::iterator> firstExpiredIt;
192
193 for (auto& queue : m_queues)
194 {
195 auto [firstIt, lastIt] = DoExtractExpiredMpdus(queue.second);
196
197 if (firstIt != lastIt && !firstExpiredIt)
198 {
199 // this is the first queue with MPDUs with expired lifetime
200 firstExpiredIt = firstIt;
201 }
202 }
203 return std::make_pair(firstExpiredIt ? *firstExpiredIt : m_expiredQueue.end(),
204 m_expiredQueue.end());
205}
206
207std::pair<WifiMacQueueContainer::iterator, WifiMacQueueContainer::iterator>
209{
210 return {m_expiredQueue.begin(), m_expiredQueue.end()};
211}
212
213std::ostream&
214operator<<(std::ostream& os, WifiContainerQueueType queueType)
215{
216 switch (queueType)
217 {
218 case WIFI_CTL_QUEUE:
219 return os << "CTL_QUEUE";
220 case WIFI_MGT_QUEUE:
221 return os << "MGT_QUEUE";
223 return os << "QOSDATA_QUEUE";
224 case WIFI_DATA_QUEUE:
225 return os << "DATA_QUEUE";
226 }
227 return os << "UNKNOWN(" << static_cast<uint16_t>(queueType) << ")";
228}
229
230std::ostream&
231operator<<(std::ostream& os, WifiRcvAddr rcvAddrType)
232{
233 switch (rcvAddrType)
234 {
236 return os << "UNICAST";
238 return os << "BROADCAST";
240 return os << "GROUPCAST";
242 return os << "COUNT";
243 }
244 return os << "UNKNOWN(" << static_cast<uint16_t>(rcvAddrType) << ")";
245}
246
247std::ostream&
248operator<<(std::ostream& os, const WifiContainerQueueId& queueId)
249{
250 os << "{" << queueId.type << ", " << queueId.addrType;
251 if (const auto& addr1 = queueId.addr1)
252 {
253 os << ", addr1=" << addr1.value();
254 }
255 if (const auto& addr2 = queueId.addr2)
256 {
257 os << ", addr2=" << addr2.value();
258 }
259 if (const auto& tid = queueId.tid)
260 {
261 os << ", tid=" << +tid.value();
262 }
263 return os << "}";
264}
265
266} // namespace ns3
267
268/****************************************************
269 * Global Functions (outside namespace ns3)
270 ***************************************************/
271
272std::size_t
274{
275 std::vector<uint8_t> buffer;
276 buffer.reserve(1 + 1 + 6 + 6 + 1); // reserve the maximum possible size of the buffer
277 buffer.emplace_back(queueId.type);
278 buffer.emplace_back(static_cast<uint8_t>(queueId.addrType));
279 if (queueId.addr1.has_value())
280 {
281 const auto size = buffer.size();
282 buffer.resize(size + 6);
283 queueId.addr1.value().CopyTo(&buffer[size]);
284 }
285 if (queueId.addr2.has_value())
286 {
287 const auto size = buffer.size();
288 buffer.resize(size + 6);
289 queueId.addr2.value().CopyTo(&buffer[size]);
290 }
291 if (queueId.tid.has_value())
292 {
293 buffer.emplace_back(*queueId.tid);
294 }
295
296 std::string s(buffer.begin(), buffer.end());
297 return std::hash<std::string>{}(s);
298}
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
const ContainerQueue & GetQueue(const WifiContainerQueueId &queueId) const
Get a const reference to the container queue identified by the given QueueId.
void clear()
Erase all elements from the container.
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.
ContainerQueue::iterator iterator
iterator over elements in a container queue
std::unordered_map< WifiContainerQueueId, uint32_t > m_nBytesPerQueue
size in bytes of the container queues
uint32_t GetNBytes(const WifiContainerQueueId &queueId) const
Get the total size of the MPDUs stored in the queue identified by the given QueueId.
Ptr< WifiMpdu > GetItem(const const_iterator it) const
Return the WifiMpdu included in the element pointed to by the given iterator.
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::unordered_map< WifiContainerQueueId, ContainerQueue > m_queues
the container queues
std::list< WifiMacQueueElem > ContainerQueue
Type of a queue held by the container.
iterator erase(const_iterator pos)
Erase the specified elements from the container.
std::pair< iterator, iterator > GetAllExpiredMpdus() const
Get the range [first, last) of iterators pointing to all the MPDUs queued in the container queue stor...
ContainerQueue::const_iterator const_iterator
const iterator over elements in a container queue
ContainerQueue m_expiredQueue
queue storing MPDUs with expired lifetime
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...
std::pair< iterator, iterator > DoExtractExpiredMpdus(ContainerQueue &queue) const
Transfer non-inflight MPDUs with expired lifetime in the given container queue to the container queue...
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
@ AC_UNDEF
Total number of ACs.
Definition qos-utils.h:78
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
WifiRcvAddr
enumeration of frame types based on receiver address
WifiContainerQueueType
enumeration of container queue types
Structure identifying a container queue.
std::optional< Mac48Address > addr1
the receiver address for unicast and groupcast queues, or nullopt otherwise
std::optional< Mac48Address > addr2
the transmitter address for broadcast and groupcast queues, or nullopt otherwise
std::optional< tid_t > tid
the TID for QoS data queues, or nullopt otherwise
WifiContainerQueueType type
the container queue type
WifiRcvAddr addrType
the type of receiver address
std::size_t operator()(ns3::WifiContainerQueueId queueId) const
The functor.