libDwm-0.9.45
DwmIpv4PrefixMap.hh
Go to the documentation of this file.
1//===========================================================================
2// @(#) $DwmPath$
3//===========================================================================
4// Copyright (c) Daniel W. McRobb 2021
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
10//
11// 1. Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// 2. Redistributions in binary form must reproduce the above copyright
14// notice, this list of conditions and the following disclaimer in the
15// documentation and/or other materials provided with the distribution.
16// 3. The names of the authors and copyright holders may not be used to
17// endorse or promote products derived from this software without
18// specific prior written permission.
19//
20// IN NO EVENT SHALL DANIEL W. MCROBB BE LIABLE TO ANY PARTY FOR
21// DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
22// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE,
23// EVEN IF DANIEL W. MCROBB HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
24// DAMAGE.
25//
26// THE SOFTWARE PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND
27// DANIEL W. MCROBB HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
28// UPDATES, ENHANCEMENTS, OR MODIFICATIONS. DANIEL W. MCROBB MAKES NO
29// REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER
30// IMPLIED OR EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31// WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE,
32// OR THAT THE USE OF THIS SOFTWARE WILL NOT INFRINGE ANY PATENT,
33// TRADEMARK OR OTHER RIGHTS.
34//===========================================================================
35
36//---------------------------------------------------------------------------
40//---------------------------------------------------------------------------
41
42#ifndef _DWMIPV4PREFIXMAP_HH_
43#define _DWMIPV4PREFIXMAP_HH_
44
45#include <cassert>
46#include <map>
47#include <mutex>
48#include <shared_mutex>
49#include <unordered_map>
50#include <vector>
51
52// #include "DwmIpv4AddrMap.hh"
53#include "DwmIpv4Prefix.hh"
54
55namespace Dwm {
56
57 //--------------------------------------------------------------------------
59 //--------------------------------------------------------------------------
60 struct OurIpv4PrefixHash
61 {
62 inline size_t operator () (const Dwm::Ipv4Prefix & pfx) const
63 {
64 return pfx.NetworkRaw();
65 }
66 };
67
68 //--------------------------------------------------------------------------
70 //--------------------------------------------------------------------------
71 template <typename T, typename Hash = OurIpv4PrefixHash>
72 class Ipv4PrefixMap
73 {
74 public:
75 //------------------------------------------------------------------------
77 //------------------------------------------------------------------------
78 using MapType = std::unordered_map<Ipv4Prefix,T,Hash>;
79
80 //------------------------------------------------------------------------
82 //------------------------------------------------------------------------
83 Ipv4PrefixMap()
84 : _mtx(), _map(), _lengthCounters()
85 {
86 _map.max_load_factor(.15);
87 }
88
89 //------------------------------------------------------------------------
91 //------------------------------------------------------------------------
92 void Add(const Ipv4Prefix & pfx, const T & value)
93 {
94 std::unique_lock lck(_mtx);
95 return Add(lck, pfx, value);
96 }
97
98 //------------------------------------------------------------------------
100 //------------------------------------------------------------------------
101 void Add(std::unique_lock<std::shared_mutex> & lck,
102 const Ipv4Prefix & pfx, const T & value)
103 {
104 assert((lck.mutex() == &_mtx) && lck.owns_lock());
105 if (_map.insert_or_assign(pfx, value).second) {
106 _lengthCounters[pfx.MaskLength()]++;
107 }
108 return;
109 }
110
111 //------------------------------------------------------------------------
113 //------------------------------------------------------------------------
114 bool Find(const Ipv4Prefix & pfx, T & value) const
115 {
116 std::shared_lock lck(_mtx);
117 return Find(lck, pfx, value);
118 }
119
120 //------------------------------------------------------------------------
122 //------------------------------------------------------------------------
123 bool Find(std::shared_lock<std::shared_mutex> & lck,
124 const Ipv4Prefix & pfx, T & value) const
125 {
126 assert((lck.mutex() == &_mtx) && lck.owns_lock());
127 return FindNoLock(pfx, value);
128 }
129
130 //------------------------------------------------------------------------
132 //------------------------------------------------------------------------
133 bool Find(std::unique_lock<std::shared_mutex> & lck,
134 const Ipv4Prefix & pfx, T & value)
135 {
136 assert((lck.mutex() == &_mtx) && lck.owns_lock());
137 return FindNoLock(pfx, value);
138 }
139
140 //------------------------------------------------------------------------
142 //------------------------------------------------------------------------
143 bool FindLongest(const Ipv4Address & addr,
144 std::pair<Ipv4Prefix,T> & value) const
145 {
146 std::shared_lock lck(_mtx);
147 return FindLongest(lck, addr, value);
148 }
149
150 //------------------------------------------------------------------------
152 //------------------------------------------------------------------------
153 bool FindLongest(std::shared_lock<std::shared_mutex> & lck,
154 const Ipv4Address & addr,
155 std::pair<Ipv4Prefix,T> & value) const
156 {
157 assert((lck.mutex() == &_mtx) && lck.owns_lock());
158 return FindLongestNoLock(addr, value);
159 }
160
161 //------------------------------------------------------------------------
163 //------------------------------------------------------------------------
164 bool FindLongest(std::unique_lock<std::shared_mutex> & lck,
165 const Ipv4Address & addr,
166 std::pair<Ipv4Prefix,T> & value)
167 {
168 assert((lck.mutex() == &_mtx) && lck.owns_lock());
169 return FindLongestNoLock(addr, value);
170 }
171
172 //------------------------------------------------------------------------
174 //------------------------------------------------------------------------
175 bool FindMatches(const Ipv4Address & addr,
176 std::vector<std::pair<Ipv4Prefix,T>> & values) const
177 {
178 std::shared_lock lck(_mtx);
179 return FindMatches(lck, addr, values);
180 }
181
182 //------------------------------------------------------------------------
184 //------------------------------------------------------------------------
185 bool FindMatches(std::shared_lock<std::shared_mutex> & lck,
186 const Ipv4Address & addr,
187 std::vector<std::pair<Ipv4Prefix,T>> & values) const
188 {
189 assert((lck.mutex() == &_mtx) && lck.owns_lock());
190 return FindMatchesNoLock(addr, values);
191 }
192
193 //------------------------------------------------------------------------
195 //------------------------------------------------------------------------
196 bool FindMatches(std::unique_lock<std::shared_mutex> & lck,
197 const Ipv4Address & addr,
198 std::vector<std::pair<Ipv4Prefix,T>> & values)
199 {
200 assert((lck.mutex() == &_mtx) && lck.owns_lock());
201 return FindMatchesNoLock(addr, values);
202 }
203
204 //------------------------------------------------------------------------
206 //------------------------------------------------------------------------
207 bool Remove(const Ipv4Prefix & pfx)
208 {
209 std::unique_lock lck(_mtx);
210 return Remove(lck, pfx);
211 }
212
213 //------------------------------------------------------------------------
215 //------------------------------------------------------------------------
216 bool Remove(std::unique_lock<std::shared_mutex> & lck,
217 const Ipv4Prefix & pfx)
218 {
219 bool rc = false;
220 auto it = _map.find(pfx);
221 if (it != _map.end()) {
222 _map.erase(it);
223 auto lit = _lengthCounters.find(pfx.MaskLength());
224 lit->second--;
225 if (0 == lit->second) {
226 _lengthCounters.erase(lit);
227 }
228 rc = true;
229 }
230 return rc;
231 }
232
233 //------------------------------------------------------------------------
235 //------------------------------------------------------------------------
236 void Rehash(typename MapType::size_type count)
237 {
238 _map.rehash(count);
239 }
240
241 //------------------------------------------------------------------------
243 //------------------------------------------------------------------------
244 std::shared_lock<std::shared_mutex> SharedLock() const
245 {
246 return std::shared_lock(_mtx);
247 }
248
249 //------------------------------------------------------------------------
251 //------------------------------------------------------------------------
252 std::unique_lock<std::shared_mutex> UniqueLock()
253 {
254 return std::unique_lock(_mtx);
255 }
256
257 private:
258 mutable std::shared_mutex _mtx;
259 MapType _map;
260 std::map<uint8_t,uint64_t> _lengthCounters;
261
262 //------------------------------------------------------------------------
264 //------------------------------------------------------------------------
265 bool FindNoLock(const Ipv4Prefix & pfx, T & value) const
266 {
267 bool rc = false;
268 auto it = _map.find(pfx);
269 if (it != _map.end()) {
270 value = it->second;
271 rc = true;
272 }
273 return rc;
274 }
275
276 //------------------------------------------------------------------------
278 //------------------------------------------------------------------------
279 bool FindLongestNoLock(const Ipv4Address & addr,
280 std::pair<Ipv4Prefix,T> & value) const
281 {
282 bool rc = false;
283 Ipv4Prefix pfx(addr, 32);
284 for (auto lit = _lengthCounters.rbegin();
285 lit != _lengthCounters.rend(); ++lit) {
286 pfx.MaskLength(lit->first);
287 auto it = _map.find(pfx);
288 if (it != _map.end()) {
289 value.first = pfx;
290 value.second = it->second;
291 rc = true;
292 break;
293 }
294 }
295 return rc;
296 }
297
298 //------------------------------------------------------------------------
300 //------------------------------------------------------------------------
301 bool
302 FindMatchesNoLock(const Ipv4Address & addr,
303 std::vector<std::pair<Ipv4Prefix,T>> & values) const
304 {
305 values.clear();
306 std::pair<Ipv4Prefix,T> value;
307 for (auto lit = _lengthCounters.rbegin();
308 lit != _lengthCounters.rend(); ++lit) {
309 Ipv4Prefix pfx(addr, lit->first);
310 auto it = _map.find(pfx);
311 if (it != _map.end()) {
312 value.first = pfx;
313 value.second = it->second;
314 values.push_back(value);
315 }
316 }
317 return (! values.empty());
318 }
319
320 };
321
322} // namespace Dwm
323
324#endif // _DWMIPV4PREFIXMAP_HH_
Dwm::Ipv4Prefix class definition.
This class encapsulates an IPv4 address and netmask.
Definition DwmIpv4Prefix.hh:59