A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lollipop-counter.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Universita' di Firenze, Italy
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: Tommaso Pecorella <tommaso.pecorella@unifi.it>
18 */
19
20#ifndef LOLLIPOP_COUNTER_H
21#define LOLLIPOP_COUNTER_H
22
23#include "ns3/abort.h"
24
25#include <limits>
26
27namespace ns3
28{
29
30/**
31 * \ingroup seq-counters
32 * \class LollipopCounter
33 *
34 * \brief Template class implementing a Lollipop counter as defined in \RFC{8505}, \RFC{6550}, and
35 * [Perlman83].
36 *
37 * A Lollipop counter is a counter that solves initialization and
38 * out-of-order problems often occurring in Internet protocols.
39 *
40 * The counter is split in two regions, an initializing region, and a circular region, having the
41 * same size. Assuming a counter using an uint8_t (max value 255), values from 128 and greater are
42 * used as a linear sequence to indicate a restart and bootstrap the counter, and the values less
43 * than or equal to 127 are used as a circular sequence number space of
44 * size 128 as mentioned in \RFC{1982}.
45 *
46 * In both regions, the comparison between two counters is allowed only if both counters are inside
47 * a Sequence Window. The default value for the Sequence Window is equal to 2^N where N is half the
48 * number of digits of the underlying type. For an uint8_t the Sequence Window is 16.
49 *
50 * The counter, by default, is initialized to the maximum counter value minus the Sequence Window
51 * plus one, e.g., in case of a uint8_t, to 240.
52 *
53 * This implementation extends the case presented in RFCs, allowing to use a
54 * larger underlying type and to change the Sequence Window size.
55 *
56 * Warning: two Lollipop counters can be compared only if they are of the same type (same underlying
57 * type, and same Sequence Window).
58 *
59 * References:
60 * [Perlman83] Perlman, R., "Fault-Tolerant Broadcast of Routing Information", North-Holland
61 * Computer Networks 7: pp. 395-405, DOI 10.1016/0376-5075(83)90034-X, 1983,
62 * <https://web.archive.org/web/20180723135334/http://pbg.cs.illinois.edu/courses/cs598fa09/readings/p83.pdf>.
63 *
64 * \tparam T \explicit The type being used for the counter.
65 */
66template <class T>
68{
69 public:
70 /**
71 * Builds a Lollipop counter with a default initial value.
72 *
73 * The Sequence Window is set to the default value.
74 * The initial value is set to the maximum counter value minus the Sequence Window plus one.
75 */
77 {
78 NS_ABORT_MSG_UNLESS(std::is_unsigned<T>::value,
79 "Lollipop counters must be defined on unsigned integer types");
80
81 uint16_t numberofDigits = std::numeric_limits<T>::digits;
82 m_sequenceWindow = 1 << (numberofDigits / 2);
83
85 }
86
87 /**
88 * Builds a Lollipop counter with a specific initial value.
89 *
90 * The Sequence Window is set to the default value.
91 *
92 * \param val the initial value of the Lollipop Counter
93 * \tparam T \deduced The type being used for the counter.
94 */
96 {
97 uint16_t numberofDigits = std::numeric_limits<T>::digits;
98 m_sequenceWindow = 1 << (numberofDigits / 2);
99
100 m_value = val;
101 }
102
103 /**
104 * Assignment.
105 *
106 * \param [in] o Value to assign to this LollipopCounter.
107 * \returns This LollipopCounter.
108 */
110 {
111 m_value = o.m_value;
112 return *this;
113 }
114
115 /**
116 * Resets the counter to its initial value.
117 */
118 void Reset()
119 {
121 }
122
123 /**
124 * Set the Sequence Window Size and resets the counter.
125 *
126 * The sequence window is equal to 2^numberOfBits.
127 * The counter is reset to maxValue - m_sequenceWindow +1, where
128 * maxValue is the maximum number allowed by the underlying type.
129 *
130 * \param numberOfBits number of bits to use in the Sequence Window
131 */
132 void SetSequenceWindowSize(uint16_t numberOfBits)
133 {
134 uint16_t numberofDigits = std::numeric_limits<T>::digits;
135
137 numberOfBits >= numberofDigits,
138 "The size of the Sequence Window should be less than the counter size (which is "
139 << +m_maxValue << ")");
140
141 m_sequenceWindow = 1 << numberOfBits;
142
144 }
145
146 /**
147 * Checks if the counter is comparable with another counter (i.e., not desynchronized).
148 *
149 * If the absolute magnitude of difference of the two
150 * sequence counters is greater than Sequence Window, then a
151 * desynchronization has occurred and the two sequence
152 * numbers are not comparable.
153 *
154 * Sequence Window is equal to 2^N where N is (by default) half the number
155 * of digits of the underlying type.
156 *
157 * \param val counter to compare
158 * \returns true if the counters are comparable.
159 */
160 bool IsComparable(const LollipopCounter& val) const
161 {
163 "Can not compare two Lollipop Counters with different sequence windows");
164
167 {
168 // They are desynchronized - comparison is impossible.
169 T absDiff = AbsoluteMagnitudeOfDifference(val);
170 if (absDiff > m_sequenceWindow)
171 {
172 return false;
173 }
174 }
175 return true;
176 }
177
178 /**
179 * Checks if a counter is in its starting region.
180 *
181 * \returns true if a counter is in its starting region.
182 */
183 bool IsInit() const
184 {
185 return m_value > m_circularRegion;
186 }
187
188 /**
189 * Arithmetic operator equal-to
190 * \param [in] lhs Left hand argument
191 * \param [in] rhs Right hand argument
192 * \return The result of the operator.
193 */
194 friend bool operator==(const LollipopCounter& lhs, const LollipopCounter& rhs)
195 {
197 "Can not compare two Lollipop Counters with different sequence windows");
198
199 return lhs.m_value == rhs.m_value;
200 }
201
202 /**
203 * Arithmetic operator greater-than
204 * \param [in] lhs Left hand argument
205 * \param [in] rhs Right hand argument
206 * \return The result of the operator.
207 */
208 friend bool operator>(const LollipopCounter& lhs, const LollipopCounter& rhs)
209 {
211 "Can not compare two Lollipop Counters with different sequence windows");
212
213 if (lhs.m_value == rhs.m_value)
214 {
215 return false;
216 }
217
218 if ((lhs.m_value <= m_circularRegion && rhs.m_value <= m_circularRegion) ||
220 {
221 // both counters are in the same region
222
223 T absDiff = lhs.AbsoluteMagnitudeOfDifference(rhs);
224 if (absDiff > lhs.m_sequenceWindow)
225 {
226 // They are desynchronized - comparison is impossible.
227 // return false because we can not return anything else.
228 return false;
229 }
230
231 // They are synchronized - comparison according to RFC1982.
232 T serialRegion = ((m_circularRegion >> 1) + 1);
233 return (((lhs.m_value < rhs.m_value) && ((rhs.m_value - lhs.m_value) > serialRegion)) ||
234 ((lhs.m_value > rhs.m_value) && ((lhs.m_value - rhs.m_value) < serialRegion)));
235 }
236
237 // One counter is in the "high" region and the other is in the in the "lower" region
238 bool lhsIsHigher;
239 T difference;
240
242 {
243 lhsIsHigher = true;
244 // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
245 difference = lhs.m_value - rhs.m_value;
246 }
247 else
248 {
249 lhsIsHigher = false;
250 // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
251 difference = rhs.m_value - lhs.m_value;
252 }
253
254 T distance = (m_maxValue - difference) +
255 1; // this is guaranteed to be positive and between [1...m_lollipopMaxValue].
256 if (distance > lhs.m_sequenceWindow)
257 {
258 return lhsIsHigher;
259 }
260 else
261 {
262 return !lhsIsHigher;
263 }
264
265 // this should never be reached.
266 return false;
267 }
268
269 /**
270 * Arithmetic operator less-than
271 * \param [in] lhs Left hand argument
272 * \param [in] rhs Right hand argument
273 * \return The result of the operator.
274 */
275 friend bool operator<(const LollipopCounter& lhs, const LollipopCounter& rhs)
276 {
277 if (!lhs.IsComparable(rhs))
278 {
279 return false;
280 }
281
282 if (lhs > rhs)
283 {
284 return false;
285 }
286 else if (lhs == rhs)
287 {
288 return false;
289 }
290
291 return true;
292 }
293
294 /**
295 * Prefix increment operator
296 * \param [in] val LollipopCounter to be incremented
297 * \return The result of the Prefix increment.
298 */
300 {
301 val.m_value++;
302
303 if (val.m_value == val.m_circularRegion + 1)
304 {
305 val.m_value = 0;
306 }
307
308 return val;
309 }
310
311 /**
312 * Postfix increment operator
313 * \param [in] val LollipopCounter to be incremented
314 * \param [in] noop ignored argument (used to mark it as a postfix, blame c++).
315 * \return The result of the Postfix increment.
316 */
317 friend LollipopCounter operator++(LollipopCounter& val, int noop) // postfix ++
318 {
319 LollipopCounter ans = val;
320 ++(val); // or just call operator++()
321 return ans;
322 }
323
324 /**
325 * Get the counter value.
326 *
327 * \return the counter value.
328 */
329 T GetValue() const
330 {
331 return m_value;
332 }
333
334 /**
335 * Output streamer for LollipopCounter.
336 *
337 * \param [in,out] os The output stream.
338 * \param [in] counter The LollipopCounter to print.
339 * \returns The stream.
340 */
341 friend std::ostream& operator<<(std::ostream& os, const LollipopCounter& counter)
342 {
343 os << +counter.m_value;
344 return os;
345 }
346
347 private:
348 /**
349 * Compute the Absolute Magnitude Of Difference between two counters.
350 *
351 * The Absolute Magnitude Of Difference is considered to
352 * be on a circular region, and it is represented by
353 * the smallest circular distance between two numbers.
354 *
355 * Arithmetic operator.
356 * \param [in] val Counter to compute the difference against
357 * \return The result of the difference.
358 */
360 {
361 // useless because it is computed always on counters on their respective regions.
362 // Left (commented) for debugging purposes in case there is a code change.
363 // NS_ASSERT_MSG ((m_value <= m_circularRegion && val.m_value <= m_circularRegion) ||
364 // (m_value > m_circularRegion && val.m_value > m_circularRegion),
365 // "Absolute Magnitude Of Difference can be computed only on two values in
366 // the circular region " << +m_value << " - " << +val.m_value);
367
368 T absDiffDirect = std::max(m_value, val.m_value) - std::min(m_value, val.m_value);
369 T absDiffWrapped = (std::min(m_value, val.m_value) + m_circularRegion + 1) -
370 std::max(m_value, val.m_value);
371 T absDiff = std::min(absDiffDirect, absDiffWrapped);
372 return absDiff;
373 }
374
375 T m_value; //!< Value of the Lollipop Counter.
376 T m_sequenceWindow; //!< Sequence window used for comparing two counters.
377 static constexpr T m_maxValue =
378 std::numeric_limits<T>::max(); //!< Maximum value of the counter.
379 static constexpr T m_circularRegion = m_maxValue >> 1; //!< Circular region of the counter.
380};
381
382/**
383 * \ingroup seq-counters
384 * 8 bit Lollipop Counter.
385 */
387/**
388 * \ingroup seq-counters
389 * 16 bit Lollipop Counter.
390 */
392
393} /* namespace ns3 */
394
395#endif /* LOLLIPOP_COUNTER_H */
Template class implementing a Lollipop counter as defined in RFC 8505, RFC 6550, and [Perlman83].
static constexpr T m_maxValue
Maximum value of the counter.
friend LollipopCounter operator++(LollipopCounter &val, int noop)
Postfix increment operator.
T AbsoluteMagnitudeOfDifference(const LollipopCounter &val) const
Compute the Absolute Magnitude Of Difference between two counters.
T m_value
Value of the Lollipop Counter.
LollipopCounter()
Builds a Lollipop counter with a default initial value.
friend LollipopCounter operator++(LollipopCounter &val)
Prefix increment operator.
friend std::ostream & operator<<(std::ostream &os, const LollipopCounter &counter)
Output streamer for LollipopCounter.
T GetValue() const
Get the counter value.
T m_sequenceWindow
Sequence window used for comparing two counters.
friend bool operator<(const LollipopCounter &lhs, const LollipopCounter &rhs)
Arithmetic operator less-than.
bool IsInit() const
Checks if a counter is in its starting region.
static constexpr T m_circularRegion
Circular region of the counter.
LollipopCounter(T val)
Builds a Lollipop counter with a specific initial value.
LollipopCounter & operator=(const LollipopCounter &o)
Assignment.
friend bool operator==(const LollipopCounter &lhs, const LollipopCounter &rhs)
Arithmetic operator equal-to.
void SetSequenceWindowSize(uint16_t numberOfBits)
Set the Sequence Window Size and resets the counter.
bool IsComparable(const LollipopCounter &val) const
Checks if the counter is comparable with another counter (i.e., not desynchronized).
friend bool operator>(const LollipopCounter &lhs, const LollipopCounter &rhs)
Arithmetic operator greater-than.
void Reset()
Resets the counter to its initial value.
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
LollipopCounter< uint8_t > LollipopCounter8
8 bit Lollipop Counter.
LollipopCounter< uint16_t > LollipopCounter16
16 bit Lollipop Counter.
Every class exported by the ns3 library is enclosed in the ns3 namespace.