A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tbf-queue-disc-test-suite.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017 Kungliga Tekniska Högskolan
3 * 2017 Universita' degli Studi di Napoli Federico II
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Authors: Surya Seetharaman <suryaseetharaman.9@gmail.com>
8 * Stefano Avallone <stavallo@unina.it>
9 */
10
11#include "ns3/config.h"
12#include "ns3/double.h"
13#include "ns3/log.h"
14#include "ns3/node-container.h"
15#include "ns3/packet.h"
16#include "ns3/simple-channel.h"
17#include "ns3/simple-net-device.h"
18#include "ns3/simulator.h"
19#include "ns3/string.h"
20#include "ns3/tbf-queue-disc.h"
21#include "ns3/test.h"
22#include "ns3/traffic-control-layer.h"
23#include "ns3/uinteger.h"
24
25using namespace ns3;
26
27/**
28 * \ingroup traffic-control-test
29 *
30 * \brief Tbf Queue Disc Test Item
31 */
33{
34 public:
35 /**
36 * Constructor
37 *
38 * \param p the packet
39 * \param addr the address
40 */
42 ~TbfQueueDiscTestItem() override;
43
44 // Delete default constructor, copy constructor and assignment operator to avoid misuse
48
49 void AddHeader() override;
50 bool Mark() override;
51};
52
57
61
62void
66
67bool
69{
70 return false;
71}
72
73/**
74 * \ingroup traffic-control-test
75 *
76 * \brief Tbf Queue Disc Test Case
77 */
79{
80 public:
82 void DoRun() override;
83
84 private:
85 /**
86 * Enqueue function
87 * \param queue the queue disc into which enqueue needs to be done
88 * \param dest the destination address
89 * \param size the size of the packet in bytes to be enqueued
90 */
91 void Enqueue(Ptr<TbfQueueDisc> queue, Address dest, uint32_t size);
92 /**
93 * DequeueAndCheck function to check if a packet is blocked or not after dequeuing and verify
94 * against expected result
95 * \param queue the queue disc on which DequeueAndCheck needs to be done
96 * \param flag the boolean value against which the return value of dequeue ()
97 * has to be compared with
98 * \param printStatement the string to be printed in the NS_TEST_EXPECT_MSG_EQ
99 */
100 void DequeueAndCheck(Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement);
101 /**
102 * Run TBF test function
103 * \param mode the mode
104 */
105 void RunTbfTest(QueueSizeUnit mode);
106};
107
109 : TestCase("Sanity check on the TBF queue implementation")
110{
111}
112
113void
115{
116 uint32_t pktSize = 1500;
117 // 1 for packets; pktSize for bytes
118 uint32_t modeSize = 1;
119 uint32_t qSize = 4;
120 uint32_t burst = 6000;
121 uint32_t mtu = 0;
122 DataRate rate = DataRate("6KB/s");
123 DataRate peakRate = DataRate("0KB/s");
124
126
127 // test 1: Simple Enqueue/Dequeue with verification of attribute setting
128 /* 1. There is no second bucket since "peakRate" is set to 0.
129 2. A simple enqueue of five packets, each containing 1500B is followed by
130 the dequeue those five packets.
131 3. The subtraction of tokens from the first bucket to send out each of the
132 five packets is monitored and verified.
133 Note : The number of tokens in the first bucket is full at the beginning.
134 With the dequeuing of each packet, the number of tokens keeps decreasing.
135 So packets are dequeued as long as there are enough tokens in the bucket. */
136
137 if (mode == QueueSizeUnit::BYTES)
138 {
139 modeSize = pktSize;
140 qSize = qSize * modeSize;
141 }
142
144 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
145 true,
146 "Verify that we can actually set the attribute MaxSize");
147 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
148 true,
149 "Verify that we can actually set the attribute Burst");
150 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
151 true,
152 "Verify that we can actually set the attribute Mtu");
153 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
154 true,
155 "Verify that we can actually set the attribute Rate");
156 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
157 true,
158 "Verify that we can actually set the attribute PeakRate");
159
160 Address dest;
161
162 Ptr<Packet> p1;
163 Ptr<Packet> p2;
164 Ptr<Packet> p3;
165 Ptr<Packet> p4;
166 Ptr<Packet> p5;
172
173 queue->Initialize();
174 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
175 0 * modeSize,
176 "There should be no packets in there");
177 queue->Enqueue(Create<TbfQueueDiscTestItem>(p1, dest));
178 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
179 1 * modeSize,
180 "There should be one packet in there");
181 queue->Enqueue(Create<TbfQueueDiscTestItem>(p2, dest));
182 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
183 2 * modeSize,
184 "There should be two packets in there");
185 queue->Enqueue(Create<TbfQueueDiscTestItem>(p3, dest));
186 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
187 3 * modeSize,
188 "There should be three packets in there");
189 queue->Enqueue(Create<TbfQueueDiscTestItem>(p4, dest));
190 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
191 4 * modeSize,
192 "There should be four packets in there");
193 queue->Enqueue(Create<TbfQueueDiscTestItem>(p5, dest));
194 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
195 4 * modeSize,
196 "There should still be four packets in there as this enqueue cannot "
197 "happen since QueueLimit will be exceeded");
198
200 NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
201 burst,
202 "The first token bucket should be full");
203 item = queue->Dequeue();
204 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the first packet");
205 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
206 3 * modeSize,
207 "There should be three packets in there");
208 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p1->GetUid(), "was this the first packet ?");
209 NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
210 burst - (1 * pktSize),
211 "The number of tokens in the first bucket should be one pktSize lesser");
212
213 item = queue->Dequeue();
214 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the second packet");
215 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
216 2 * modeSize,
217 "There should be two packets in there");
218 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
219 p2->GetUid(),
220 "Was this the second packet ?");
221 NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
222 burst - (2 * pktSize),
223 "The number of tokens in the first bucket should be two pktSizes lesser");
224
225 item = queue->Dequeue();
226 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the third packet");
227 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
228 1 * modeSize,
229 "There should be one packet in there");
230 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p3->GetUid(), "Was this the third packet ?");
232 queue->GetFirstBucketTokens(),
233 burst - (3 * pktSize),
234 "The number of tokens in the first bucket should be three pktSizes lesser");
235
236 item = queue->Dequeue();
237 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the fourth packet");
238 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
239 0 * modeSize,
240 "There should be zero packet in there");
241 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
242 p4->GetUid(),
243 "Was this the fourth packet ?");
245 queue->GetFirstBucketTokens(),
246 burst - (4 * pktSize),
247 "The number of tokens in the first bucket should be four pktSizes lesser");
248
249 // test 2 : When DataRate == FirstBucketTokenRate; packets should pass smoothly.
251 qSize = 10;
252 pktSize = 1000;
253 burst = 10000;
254 mtu = 1000;
255 rate = DataRate("10KB/s");
256 peakRate = DataRate("100KB/s");
257 uint32_t nPkt = qSize;
258
259 if (mode == QueueSizeUnit::BYTES)
260 {
261 modeSize = pktSize;
262 qSize = qSize * modeSize;
263 }
264
266 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
267 true,
268 "Verify that we can actually set the attribute MaxSize");
269 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
270 true,
271 "Verify that we can actually set the attribute Burst");
272 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
273 true,
274 "Verify that we can actually set the attribute Mtu");
275 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
276 true,
277 "Verify that we can actually set the attribute Rate");
278 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
279 true,
280 "Verify that we can actually set the attribute PeakRate");
281
282 queue->Initialize();
283 double delay = 0.09;
284 for (uint32_t i = 1; i <= nPkt; i++)
285 {
286 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
288 this,
289 queue,
290 dest,
291 pktSize);
292 }
293 delay = 0.1;
294 for (uint32_t i = 1; i <= nPkt; i++)
295 {
296 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
298 this,
299 queue,
300 true,
301 "No packet should be blocked");
302 }
305
306 // test 3 : When DataRate >>> FirstBucketTokenRate; some packets should get blocked and waking
307 // of queue should get scheduled.
308 /* 10 packets are enqueued and then dequeued. Since the token rate is less than the data rate,
309 the last packet i.e the 10th packet gets blocked and waking of queue is scheduled after a
310 time when enough tokens will be available. At that time the 10th packet passes through. */
312
313 Config::SetDefault("ns3::QueueDisc::Quota", UintegerValue(1));
314 NodeContainer nodesA;
315 nodesA.Create(2);
317 nodesA.Get(0)->AddDevice(txDevA);
319 nodesA.Get(1)->AddDevice(rxDevA);
321 txDevA->SetChannel(channelA);
322 rxDevA->SetChannel(channelA);
323 txDevA->SetNode(nodesA.Get(0));
324 rxDevA->SetNode(nodesA.Get(1));
325
326 dest = txDevA->GetAddress();
327
329 nodesA.Get(0)->AggregateObject(tcA);
330 tcA->SetRootQueueDiscOnDevice(txDevA, queue);
331 tcA->Initialize();
332
333 burst = 5000;
334 mtu = 1000;
335 rate = DataRate("5KB/s");
336 peakRate = DataRate("100KB/s");
337
338 if (mode == QueueSizeUnit::BYTES)
339 {
340 modeSize = pktSize;
341 qSize = qSize * modeSize;
342 }
343
345 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
346 true,
347 "Verify that we can actually set the attribute MaxSize");
348 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
349 true,
350 "Verify that we can actually set the attribute Burst");
351 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
352 true,
353 "Verify that we can actually set the attribute Mtu");
354 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
355 true,
356 "Verify that we can actually set the attribute Rate");
357 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
358 true,
359 "Verify that we can actually set the attribute PeakRate");
360
361 delay = 0.09;
362 for (uint32_t i = 1; i <= nPkt; i++)
363 {
364 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
366 this,
367 queue,
368 dest,
369 pktSize);
370 }
371 delay = 0.1;
372 for (uint32_t i = 1; i <= nPkt; i++)
373 {
374 if (i == 10)
375 {
376 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
378 this,
379 queue,
380 false,
381 "10th packet should be blocked");
382 }
383 else
384 {
385 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
387 this,
388 queue,
389 true,
390 "This packet should not be blocked");
391 }
392 }
395
396 // test 4 : This test checks the peakRate control of packet dequeue, when DataRate <
397 // FirstBucketTokenRate.
398 /* 10 packets each of size 1000 bytes are enqueued followed by
399 their dequeue. The data rate (25 KB/s) is not sufficiently higher than the btokens rate (15
400 KB/s), so that in the startup phase the first bucket is not empty. Hence when adequate tokens
401 are present in the second (peak) bucket, the packets get transmitted, otherwise they are
402 blocked. So basically the transmission of packets falls under the regulation of the second
403 bucket since first bucket will always have excess tokens. TBF does not let all the packets go
404 smoothly without any control just because there are excess tokens in the first bucket. */
406
407 Config::SetDefault("ns3::QueueDisc::Quota", UintegerValue(1));
408 NodeContainer nodesB;
409 nodesB.Create(2);
411 nodesB.Get(0)->AddDevice(txDevB);
413 nodesB.Get(1)->AddDevice(rxDevB);
415 txDevB->SetChannel(channelB);
416 rxDevB->SetChannel(channelB);
417 txDevB->SetNode(nodesB.Get(0));
418 rxDevB->SetNode(nodesB.Get(1));
419
420 dest = txDevB->GetAddress();
421
423 nodesB.Get(0)->AggregateObject(tcB);
424 tcB->SetRootQueueDiscOnDevice(txDevB, queue);
425 tcB->Initialize();
426
427 burst = 15000;
428 mtu = 1000;
429 pktSize = 1000;
430 rate = DataRate("15KB/s");
431 peakRate = DataRate("20KB/s");
432
433 if (mode == QueueSizeUnit::BYTES)
434 {
435 modeSize = pktSize;
436 qSize = qSize * modeSize;
437 }
438
440 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
441 true,
442 "Verify that we can actually set the attribute MaxSize");
443 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
444 true,
445 "Verify that we can actually set the attribute Burst");
446 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
447 true,
448 "Verify that we can actually set the attribute Mtu");
449 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
450 true,
451 "Verify that we can actually set the attribute Rate");
452 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
453 true,
454 "Verify that we can actually set the attribute PeakRate");
455
456 queue->Initialize();
457 delay = 0.04;
458 for (uint32_t i = 1; i <= nPkt; i++)
459 {
460 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
462 this,
463 queue,
464 dest,
465 pktSize);
466 }
467
468 // The pattern being checked is a pattern of dequeue followed by blocked. The delay between
469 // enqueues is not sufficient to allow ptokens to refill before the next dequeue. The first
470 // enqueue is at 1.08s in the future, and the attempted dequeue is at 1.10s in the future. The
471 // first dequeue will always succeed. The second enqueue is 1.12s and attempted dequeue is
472 // at 1.14s in the future, but the last dequeue was 0.04s prior; only 800 tokens can be refilled
473 // in 0.04s at a peak rate of 20Kbps. The actual dequeue occurs at 0.01s further into the
474 // future when ptokens refills to 1000. To repeat the pattern, odd-numbered dequeue events
475 // should be spaced at intervals of at least 100ms, and the even-numbered dequeue events (that
476 // block) should be 0.04s (delay) following the last odd-numbered dequeue event.
477 double nextDelay = (2 * delay) + 0.02; // 20ms after first enqueue to attempt the first dequeue;
478 for (uint32_t i = 1; i <= nPkt; i++)
479 {
480 if (i % 2 == 1)
481 {
482 Simulator::Schedule(Seconds(nextDelay),
484 this,
485 queue,
486 true,
487 "1st packet should not be blocked");
488 nextDelay += 0.04;
489 }
490 else
491 {
492 Simulator::Schedule(Seconds(nextDelay),
494 this,
495 queue,
496 false,
497 "This packet should be blocked");
498 nextDelay += 0.06; // Need 0.04 + 0.06 seconds to allow the next packet to be dequeued
499 // without block
500 }
501 }
504}
505
506void
511
512void
514 bool flag,
515 std::string printStatement)
516{
517 Ptr<QueueDiscItem> item = queue->Dequeue();
518 NS_TEST_EXPECT_MSG_EQ((item != nullptr), flag, printStatement);
519}
520
521void
523{
524 RunTbfTest(QueueSizeUnit::PACKETS);
525 RunTbfTest(QueueSizeUnit::BYTES);
527}
528
529/**
530 * \ingroup traffic-control-test
531 *
532 * \brief Tbf Queue Disc Test Suite
533 */
534static class TbfQueueDiscTestSuite : public TestSuite
535{
536 public:
538 : TestSuite("tbf-queue-disc", Type::UNIT)
539 {
540 AddTestCase(new TbfQueueDiscTestCase(), TestCase::Duration::QUICK);
541 }
542} g_tbfQueueTestSuite; ///< the test suite
Tbf Queue Disc Test Case.
void RunTbfTest(QueueSizeUnit mode)
Run TBF test function.
void DoRun() override
Implementation to actually run this TestCase.
void Enqueue(Ptr< TbfQueueDisc > queue, Address dest, uint32_t size)
Enqueue function.
void DequeueAndCheck(Ptr< TbfQueueDisc > queue, bool flag, std::string printStatement)
DequeueAndCheck function to check if a packet is blocked or not after dequeuing and verify against ex...
Tbf Queue Disc Test Item.
TbfQueueDiscTestItem()=delete
bool Mark() override
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
TbfQueueDiscTestItem(const TbfQueueDiscTestItem &)=delete
void AddHeader() override
Add the header to the packet.
TbfQueueDiscTestItem & operator=(const TbfQueueDiscTestItem &)=delete
Tbf Queue Disc Test Suite.
a polymophic address class
Definition address.h:90
Class for representing data rates.
Definition data-rate.h:78
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition node.cc:124
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition object.cc:298
Smart pointer class similar to boost::intrusive_ptr.
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition queue-item.h:122
Class for representing queue sizes.
Definition queue-size.h:85
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
static constexpr auto UNIT
Definition test.h:1291
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
Hold an unsigned integer type.
Definition uinteger.h:34
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition queue-size.h:33
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#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:241
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition test.h:554
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
TbfQueueDiscTestSuite g_tbfQueueTestSuite
the test suite
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t pktSize
packet size used for the simulation (in bytes)