A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
cobalt-queue-disc.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 NITK Surathkal
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 * Cobalt, the CoDel - BLUE - Alternate Queueing discipline
18 * Based on linux code.
19 *
20 * Ported to ns-3 by: Vignesh Kannan <vignesh2496@gmail.com>
21 * Harsh Lara <harshapplefan@gmail.com>
22 * Jendaipou Palmei <jendaipoupalmei@gmail.com>
23 * Shefali Gupta <shefaligups11@gmail.com>
24 * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
25 */
26
27#include "cobalt-queue-disc.h"
28
29#include "ns3/abort.h"
30#include "ns3/drop-tail-queue.h"
31#include "ns3/enum.h"
32#include "ns3/log.h"
33#include "ns3/net-device-queue-interface.h"
34#include "ns3/object-factory.h"
35#include "ns3/uinteger.h"
36
37#include <climits>
38
39namespace ns3
40{
41
42NS_LOG_COMPONENT_DEFINE("CobaltQueueDisc");
43
44NS_OBJECT_ENSURE_REGISTERED(CobaltQueueDisc);
45
46TypeId
48{
49 static TypeId tid =
50 TypeId("ns3::CobaltQueueDisc")
52 .SetGroupName("TrafficControl")
53 .AddConstructor<CobaltQueueDisc>()
54 .AddAttribute(
55 "MaxSize",
56 "The maximum number of packets/bytes accepted by this queue disc.",
60 .AddAttribute("Interval",
61 "The Cobalt algorithm interval",
62 StringValue("100ms"),
65 .AddAttribute("Target",
66 "The Cobalt algorithm target queue delay",
67 StringValue("5ms"),
70 .AddAttribute("UseEcn",
71 "True to use ECN (packets are marked instead of being dropped)",
72 BooleanValue(false),
75 .AddAttribute("Pdrop",
76 "Marking Probability",
77 DoubleValue(0),
79 MakeDoubleChecker<double>())
80 .AddAttribute("Increment",
81 "Pdrop increment value",
82 DoubleValue(1. / 256),
84 MakeDoubleChecker<double>())
85 .AddAttribute("Decrement",
86 "Pdrop decrement Value",
87 DoubleValue(1. / 4096),
89 MakeDoubleChecker<double>())
90 .AddAttribute("CeThreshold",
91 "The CoDel CE threshold for marking packets",
95 .AddAttribute("UseL4s",
96 "True to use L4S (only ECT1 packets are marked at CE threshold)",
97 BooleanValue(false),
100 .AddAttribute("BlueThreshold",
101 "The Threshold after which Blue is enabled",
105 .AddTraceSource("Count",
106 "Cobalt count",
108 "ns3::TracedValueCallback::Uint32")
109 .AddTraceSource("DropState",
110 "Dropping state",
112 "ns3::TracedValueCallback::Bool")
113 .AddTraceSource("DropNext",
114 "Time until next packet drop",
116 "ns3::TracedValueCallback::Uint32");
117
118 return tid;
119}
120
121/**
122 * Performs a reciprocal divide, similar to the
123 * Linux kernel reciprocal_divide function
124 * \param A numerator
125 * \param R reciprocal of the denominator B
126 * \return the value of A/B
127 */
128/* borrowed from the linux kernel */
129static inline uint32_t
131{
132 return (uint32_t)(((uint64_t)A * R) >> 32);
133}
134
135/**
136 * Returns the current time translated in CoDel time representation
137 * \return the current time
138 */
139static int64_t
141{
142 Time time = Simulator::Now();
143 int64_t ns = time.GetNanoSeconds();
144
145 return ns;
146}
147
149 : QueueDisc()
150{
151 NS_LOG_FUNCTION(this);
153 m_uv = CreateObject<UniformRandomVariable>();
154}
155
156double
158{
159 return m_pDrop;
160}
161
163{
164 NS_LOG_FUNCTION(this);
165}
166
167int64_t
169{
170 NS_LOG_FUNCTION(this << stream);
171 m_uv->SetStream(stream);
172 return 1;
173}
174
175void
177{
178 // Cobalt parameters
179 NS_LOG_FUNCTION(this);
180 m_recInvSqrtCache[0] = ~0;
181 CacheInit();
182 m_count = 0;
183 m_dropping = false;
184 m_recInvSqrt = ~0U;
186 m_dropNext = 0;
187}
188
189bool
191{
192 return ((int64_t)(a) - (int64_t)(b) > 0);
193}
194
195bool
197{
198 return ((int64_t)(a) - (int64_t)(b) >= 0);
199}
200
201int64_t
203{
204 return (t.GetNanoSeconds());
205}
206
207Time
209{
210 return m_target;
211}
212
213Time
215{
216 return m_interval;
217}
218
219int64_t
221{
222 return m_dropNext;
223}
224
225void
227{
228 NS_LOG_FUNCTION(this);
229 uint32_t invsqrt = ((uint32_t)m_recInvSqrt);
230 uint32_t invsqrt2 = ((uint64_t)invsqrt * invsqrt) >> 32;
231 uint64_t val = (3LL << 32) - ((uint64_t)m_count * invsqrt2);
232
233 val >>= 2; /* avoid overflow */
234 val = (val * invsqrt) >> (32 - 2 + 1);
235 m_recInvSqrt = val;
236}
237
238void
240{
241 m_recInvSqrt = ~0U;
243
245 {
246 NewtonStep();
247 NewtonStep();
248 NewtonStep();
249 NewtonStep();
251 }
252}
253
254void
256{
258 {
260 }
261 else
262 {
263 NewtonStep();
264 }
265}
266
267int64_t
269{
270 NS_LOG_FUNCTION(this);
272}
273
274void
276{
277 NS_LOG_FUNCTION(this);
278 m_uv = nullptr;
280}
281
284{
285 NS_LOG_FUNCTION(this);
286 if (GetInternalQueue(0)->IsEmpty())
287 {
288 NS_LOG_LOGIC("Queue empty");
289 return nullptr;
290 }
291
293
294 NS_LOG_LOGIC("Number packets " << GetInternalQueue(0)->GetNPackets());
295 NS_LOG_LOGIC("Number bytes " << GetInternalQueue(0)->GetNBytes());
296
297 return item;
298}
299
300bool
302{
303 NS_LOG_FUNCTION(this);
304 if (GetNQueueDiscClasses() > 0)
305 {
306 NS_LOG_ERROR("CobaltQueueDisc cannot have classes");
307 return false;
308 }
309
310 if (GetNPacketFilters() > 0)
311 {
312 NS_LOG_ERROR("CobaltQueueDisc cannot have packet filters");
313 return false;
314 }
315
316 if (GetNInternalQueues() == 0)
317 {
321 }
322
323 if (GetNInternalQueues() != 1)
324 {
325 NS_LOG_ERROR("CobaltQueueDisc needs 1 internal queue");
326 return false;
327 }
328 return true;
329}
330
331bool
333{
334 NS_LOG_FUNCTION(this << item);
335 Ptr<Packet> p = item->GetPacket();
336 if (GetCurrentSize() + item > GetMaxSize())
337 {
338 NS_LOG_LOGIC("Queue full -- dropping pkt");
339 int64_t now = CoDelGetTime();
340 // Call this to update Blue's drop probability
341 CobaltQueueFull(now);
343 return false;
344 }
345
346 bool retval = GetInternalQueue(0)->Enqueue(item);
347
348 // If Queue::Enqueue fails, QueueDisc::Drop is called by the internal queue
349 // because QueueDisc::AddInternalQueue sets the drop callback
350
351 NS_LOG_LOGIC("Number packets " << GetInternalQueue(0)->GetNPackets());
352 NS_LOG_LOGIC("Number bytes " << GetInternalQueue(0)->GetNBytes());
353
354 return retval;
355}
356
359{
360 NS_LOG_FUNCTION(this);
361
362 while (true)
363 {
364 Ptr<QueueDiscItem> item = GetInternalQueue(0)->Dequeue();
365 if (!item)
366 {
367 // Leave dropping state when queue is empty (derived from Codel)
368 m_dropping = false;
369 NS_LOG_LOGIC("Queue empty");
370 int64_t now = CoDelGetTime();
371 // Call this to update Blue's drop probability
372 CobaltQueueEmpty(now);
373 return nullptr;
374 }
375
376 int64_t now = CoDelGetTime();
377
378 NS_LOG_LOGIC("Popped " << item);
379 NS_LOG_LOGIC("Number packets remaining " << GetInternalQueue(0)->GetNPackets());
380 NS_LOG_LOGIC("Number bytes remaining " << GetInternalQueue(0)->GetNBytes());
381
382 // Determine if item should be dropped
383 // ECN marking happens inside this function, so it need not be done here
384 bool drop = CobaltShouldDrop(item, now);
385
386 if (drop)
387 {
389 }
390 else
391 {
392 return item;
393 }
394 }
395}
396
397// Call this when a packet had to be dropped due to queue overflow.
398void
400{
401 NS_LOG_FUNCTION(this);
402 NS_LOG_LOGIC("Outside IF block");
404 {
405 NS_LOG_LOGIC("inside IF block");
406 m_pDrop = std::min(m_pDrop + m_increment, 1.0);
408 }
409 m_dropping = true;
410 m_dropNext = now;
411 if (!m_count)
412 {
413 m_count = 1;
414 }
415}
416
417// Call this when the queue was serviced but turned out to be empty.
418void
420{
421 NS_LOG_FUNCTION(this);
423 {
424 m_pDrop = std::max(m_pDrop - m_decrement, 0.0);
426 }
427 m_dropping = false;
428
429 if (m_count && CoDelTimeAfterEq((now - m_dropNext), 0))
430 {
431 m_count--;
432 InvSqrt();
434 }
435}
436
437// Determines if Cobalt should drop the packet
438bool
440{
441 NS_LOG_FUNCTION(this);
442 bool drop = false;
443
444 /* Simplified Codel implementation */
445 Time delta = Simulator::Now() - item->GetTimeStamp();
446 NS_LOG_INFO("Sojourn time " << delta.As(Time::S));
447 int64_t sojournTime = Time2CoDel(delta);
448 int64_t schedule = now - m_dropNext;
449 bool over_target = CoDelTimeAfter(sojournTime, Time2CoDel(m_target));
450 bool next_due = m_count && schedule >= 0;
451 bool isMarked = false;
452
453 // If L4S mode is enabled then check if the packet is ECT1 or CE and
454 // if sojourn time is greater than CE threshold then the packet is marked.
455 // If packet is marked successfully then the CoDel steps can be skipped.
456 if (item && m_useL4s)
457 {
458 uint8_t tosByte = 0;
459 if (item->GetUint8Value(QueueItem::IP_DSFIELD, tosByte) &&
460 (((tosByte & 0x3) == 1) || (tosByte & 0x3) == 3))
461 {
462 if ((tosByte & 0x3) == 1)
463 {
464 NS_LOG_DEBUG("ECT1 packet " << static_cast<uint16_t>(tosByte & 0x3));
465 }
466 else
467 {
468 NS_LOG_DEBUG("CE packet " << static_cast<uint16_t>(tosByte & 0x3));
469 }
470 if (CoDelTimeAfter(sojournTime, Time2CoDel(m_ceThreshold)) &&
472 {
473 NS_LOG_LOGIC("Marking due to CeThreshold " << m_ceThreshold.GetSeconds());
474 }
475 return false;
476 }
477 }
478
479 if (over_target)
480 {
481 if (!m_dropping)
482 {
483 m_dropping = true;
484 m_dropNext = ControlLaw(now);
485 }
486 if (!m_count)
487 {
488 m_count = 1;
489 }
490 }
491 else if (m_dropping)
492 {
493 m_dropping = false;
494 }
495
496 if (next_due && m_dropping)
497 {
498 /* Check for marking possibility only if BLUE decides NOT to drop. */
499 /* Check if router and packet, both have ECN enabled. Only if this is true, mark the packet.
500 */
501 isMarked = (m_useEcn && Mark(item, FORCED_MARK));
502 drop = !isMarked;
503
504 m_count = std::max(m_count, m_count + 1);
505
506 InvSqrt();
508 schedule = now - m_dropNext;
509 }
510 else
511 {
512 while (next_due)
513 {
514 m_count--;
515 InvSqrt();
517 schedule = now - m_dropNext;
518 next_due = m_count && schedule >= 0;
519 }
520 }
521
522 // If CE threshold is enabled then isMarked flag is used to determine whether
523 // packet is marked and if the packet is marked then a second attempt at marking should be
524 // suppressed. If UseL4S attribute is enabled then ECT0 packets should not be marked.
525 if (!isMarked && !m_useL4s && m_useEcn &&
526 CoDelTimeAfter(sojournTime, Time2CoDel(m_ceThreshold)) &&
528 {
529 NS_LOG_LOGIC("Marking due to CeThreshold " << m_ceThreshold.GetSeconds());
530 }
531
532 // Enable Blue Enhancement if sojourn time is greater than blueThreshold and its been m_target
533 // time until the last time blue was updated
534 if (CoDelTimeAfter(sojournTime, Time2CoDel(m_blueThreshold)) &&
536 {
537 m_pDrop = std::min(m_pDrop + m_increment, 1.0);
539 }
540
541 /* Simple BLUE implementation. Lack of ECN is deliberate. */
542 if (m_pDrop)
543 {
544 double u = m_uv->GetValue();
545 drop = drop || (u < m_pDrop);
546 }
547
548 /* Overload the drop_next field as an activity timeout */
549 if (!m_count)
550 {
552 }
553 else if (schedule > 0 && !drop)
554 {
555 m_dropNext = now;
556 }
557
558 return drop;
559}
560
561} // namespace ns3
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Cobalt packet queue disc.
Time m_ceThreshold
Threshold above which to CE mark.
uint32_t m_recInvSqrtCache[REC_INV_SQRT_CACHE]
Cache to maintain some initial values of InvSqrt.
Time m_target
target queue delay
static constexpr const char * CE_THRESHOLD_EXCEEDED_MARK
Sojourn time above CE threshold.
bool CheckConfig() override
Check whether the current configuration is correct.
void NewtonStep()
Calculate the reciprocal square root of m_count by using Newton's method http://en....
Time GetTarget() const
Get the target queue delay.
int64_t GetDropNext() const
Get the time for next packet drop while in the dropping state.
void InitializeParams() override
Initialize the queue parameters.
bool CoDelTimeAfterEq(int64_t a, int64_t b)
Check if CoDel time a is successive or equal to b.
void InvSqrt()
Updates the inverse square root.
double GetPdrop() const
Get the drop probability of Blue.
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
void DoDispose() override
Dispose of the object.
TracedValue< uint32_t > m_count
Number of packets dropped since entering drop state.
double m_increment
increment value for marking probability
void CobaltQueueFull(int64_t now)
Called when the queue becomes full to alter the drop probabilities of Blue.
Time m_interval
sliding minimum time window width
double m_decrement
decrement value for marking probability
bool CobaltShouldDrop(Ptr< QueueDiscItem > item, int64_t now)
Called to decide whether the current packet should be dropped based on decisions taken by Blue and Co...
static TypeId GetTypeId()
Get the type ID.
Ptr< QueueDiscItem > DoDequeue() override
This function actually extracts a packet from the queue disc.
void CacheInit()
There is a big difference in timing between the accurate values placed in the cache and the approxima...
~CobaltQueueDisc() override
Destructor.
static constexpr const char * TARGET_EXCEEDED_DROP
Sojourn time above target.
int64_t Time2CoDel(Time t) const
Return the unsigned 32-bit integer representation of the input Time object.
bool CoDelTimeAfter(int64_t a, int64_t b)
Check if CoDel time a is successive to b.
Time GetInterval() const
Get the interval.
double m_pDrop
Drop Probability.
CobaltQueueDisc()
CobaltQueueDisc Constructor.
int64_t ControlLaw(int64_t t)
Determine the time for next drop CoDel control law is t + m_interval/sqrt(m_count).
static constexpr const char * FORCED_MARK
forced marks by Codel on ECN-enabled
Time m_blueThreshold
Threshold to enable blue enhancement.
uint32_t m_recInvSqrt
Reciprocal inverse square root.
Ptr< UniformRandomVariable > m_uv
Rng stream.
uint32_t m_lastUpdateTimeBlue
Blue's last update time for drop probability.
static constexpr const char * OVERLIMIT_DROP
Overlimit dropped packet.
TracedValue< bool > m_dropping
True if in dropping state.
Ptr< const QueueDiscItem > DoPeek() override
Return a copy of the next packet the queue disc will extract.
bool m_useEcn
True if ECN is used (packets are marked instead of being dropped)
bool DoEnqueue(Ptr< QueueDiscItem > item) override
This function actually enqueues a packet into the queue disc.
TracedValue< int64_t > m_dropNext
Time to drop next packet.
void CobaltQueueEmpty(int64_t now)
Called when the queue becomes empty to alter the drop probabilities of Blue.
bool m_useL4s
True if L4S is used (ECT1 packets are marked at CE threshold)
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
A FIFO packet queue that drops tail-end packets on overflow.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
QueueDisc is an abstract base class providing the interface and implementing the operations common to...
Definition: queue-disc.h:184
void AddInternalQueue(Ptr< InternalQueue > queue)
Add an internal queue to the tail of the list of queues.
Definition: queue-disc.cc:573
uint32_t GetNPackets() const
Get the number of packets stored by the queue disc.
Definition: queue-disc.cc:432
uint32_t GetNBytes() const
Get the amount of bytes stored by the queue disc.
Definition: queue-disc.cc:439
Ptr< InternalQueue > GetInternalQueue(std::size_t i) const
Get the i-th internal queue.
Definition: queue-disc.cc:591
QueueSize GetCurrentSize() const
Get the current size of the queue disc in bytes, if operating in bytes mode, or packets,...
Definition: queue-disc.cc:515
void DropAfterDequeue(Ptr< const QueueDiscItem > item, const char *reason)
Perform the actions required when the queue disc is notified of a packet dropped after dequeue.
Definition: queue-disc.cc:759
std::size_t GetNQueueDiscClasses() const
Get the number of queue disc classes.
Definition: queue-disc.cc:661
QueueSize GetMaxSize() const
Get the maximum size of the queue disc.
Definition: queue-disc.cc:446
std::size_t GetNPacketFilters() const
Get the number of packet filters.
Definition: queue-disc.cc:618
bool SetMaxSize(QueueSize size)
Set the maximum size of the queue disc.
Definition: queue-disc.cc:474
std::size_t GetNInternalQueues() const
Get the number of internal queues.
Definition: queue-disc.cc:598
void DoDispose() override
Dispose of the object.
Definition: queue-disc.cc:376
bool Mark(Ptr< QueueDiscItem > item, const char *reason)
Marks the given packet and, if successful, updates the counters associated with the given reason.
Definition: queue-disc.cc:809
void DropBeforeEnqueue(Ptr< const QueueDiscItem > item, const char *reason)
Perform the actions required when the queue disc is notified of a packet dropped before enqueue.
Definition: queue-disc.cc:720
Class for representing queue sizes.
Definition: queue-size.h:96
AttributeValue implementation for QueueSize.
Definition: queue-size.h:221
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Hold variables of type string.
Definition: string.h:56
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:418
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
@ S
second
Definition: nstime.h:116
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition: nstime.h:297
AttributeValue implementation for Time.
Definition: nstime.h:1406
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
double GetValue(double min, double max)
Get the next random value drawn from the distribution.
#define DEFAULT_COBALT_LIMIT
#define REC_INV_SQRT_CACHE
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:43
Ptr< const AttributeChecker > MakeQueueSizeChecker()
Definition: queue-size.cc:29
Ptr< const AttributeAccessor > MakeQueueSizeAccessor(T1 a1)
Definition: queue-size.h:221
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
Ptr< T > CreateObjectWithAttributes(Args... args)
Allocate an Object on the heap and initialize with a set of attributes.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:46
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static int64_t CoDelGetTime()
Returns the current time translated in CoDel time representation.
static uint32_t ReciprocalDivide(uint32_t A, uint32_t R)
Performs a reciprocal divide, similar to the Linux kernel reciprocal_divide function.