A Discrete-Event Network Simulator
API
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 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Surya Seetharaman <suryaseetharaman.9@gmail.com>
19 * Stefano Avallone <stavallo@unina.it>
20 */
21
22#include "ns3/config.h"
23#include "ns3/double.h"
24#include "ns3/log.h"
25#include "ns3/node-container.h"
26#include "ns3/packet.h"
27#include "ns3/simple-channel.h"
28#include "ns3/simple-net-device.h"
29#include "ns3/simulator.h"
30#include "ns3/string.h"
31#include "ns3/tbf-queue-disc.h"
32#include "ns3/test.h"
33#include "ns3/traffic-control-layer.h"
34#include "ns3/uinteger.h"
35
36using namespace ns3;
37
45{
46 public:
54 ~TbfQueueDiscTestItem() override;
55
56 // Delete default constructor, copy constructor and assignment operator to avoid misuse
60
61 void AddHeader() override;
62 bool Mark() override;
63};
64
66 : QueueDiscItem(p, addr, 0)
67{
68}
69
71{
72}
73
74void
76{
77}
78
79bool
81{
82 return false;
83}
84
92{
93 public:
95 void DoRun() override;
96
97 private:
104 void Enqueue(Ptr<TbfQueueDisc> queue, Address dest, uint32_t size);
113 void DequeueAndCheck(Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement);
118 void RunTbfTest(QueueSizeUnit mode);
119};
120
122 : TestCase("Sanity check on the TBF queue implementation")
123{
124}
125
126void
128{
129 uint32_t pktSize = 1500;
130 // 1 for packets; pktSize for bytes
131 uint32_t modeSize = 1;
132 uint32_t qSize = 4;
133 uint32_t burst = 6000;
134 uint32_t mtu = 0;
135 DataRate rate = DataRate("6KB/s");
136 DataRate peakRate = DataRate("0KB/s");
137
138 Ptr<TbfQueueDisc> queue = CreateObject<TbfQueueDisc>();
139
140 // test 1: Simple Enqueue/Dequeue with verification of attribute setting
141 /* 1. There is no second bucket since "peakRate" is set to 0.
142 2. A simple enqueue of five packets, each containing 1500B is followed by
143 the dequeue those five packets.
144 3. The subtraction of tokens from the first bucket to send out each of the
145 five packets is monitored and verified.
146 Note : The number of tokens in the first bucket is full at the beginning.
147 With the dequeuing of each packet, the number of tokens keeps decreasing.
148 So packets are dequeued as long as there are enough tokens in the bucket. */
149
150 if (mode == QueueSizeUnit::BYTES)
151 {
152 modeSize = pktSize;
153 qSize = qSize * modeSize;
154 }
155
157 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
158 true,
159 "Verify that we can actually set the attribute MaxSize");
160 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
161 true,
162 "Verify that we can actually set the attribute Burst");
163 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
164 true,
165 "Verify that we can actually set the attribute Mtu");
166 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
167 true,
168 "Verify that we can actually set the attribute Rate");
169 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
170 true,
171 "Verify that we can actually set the attribute PeakRate");
172
173 Address dest;
174
175 Ptr<Packet> p1;
176 Ptr<Packet> p2;
177 Ptr<Packet> p3;
178 Ptr<Packet> p4;
179 Ptr<Packet> p5;
180 p1 = Create<Packet>(pktSize);
181 p2 = Create<Packet>(pktSize);
182 p3 = Create<Packet>(pktSize);
183 p4 = Create<Packet>(pktSize);
184 p5 = Create<Packet>(pktSize);
185
186 queue->Initialize();
187 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
188 0 * modeSize,
189 "There should be no packets in there");
190 queue->Enqueue(Create<TbfQueueDiscTestItem>(p1, dest));
191 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
192 1 * modeSize,
193 "There should be one packet in there");
194 queue->Enqueue(Create<TbfQueueDiscTestItem>(p2, dest));
195 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
196 2 * modeSize,
197 "There should be two packets in there");
198 queue->Enqueue(Create<TbfQueueDiscTestItem>(p3, dest));
199 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
200 3 * modeSize,
201 "There should be three packets in there");
202 queue->Enqueue(Create<TbfQueueDiscTestItem>(p4, dest));
203 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
204 4 * modeSize,
205 "There should be four packets in there");
206 queue->Enqueue(Create<TbfQueueDiscTestItem>(p5, dest));
207 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
208 4 * modeSize,
209 "There should still be four packets in there as this enqueue cannot "
210 "happen since QueueLimit will be exceeded");
211
213 NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
214 burst,
215 "The first token bucket should be full");
216 item = queue->Dequeue();
217 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the first packet");
218 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
219 3 * modeSize,
220 "There should be three packets in there");
221 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p1->GetUid(), "was this the first packet ?");
222 NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
223 burst - (1 * pktSize),
224 "The number of tokens in the first bucket should be one pktSize lesser");
225
226 item = queue->Dequeue();
227 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the second packet");
228 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
229 2 * modeSize,
230 "There should be two packets in there");
231 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
232 p2->GetUid(),
233 "Was this the second packet ?");
234 NS_TEST_ASSERT_MSG_EQ(queue->GetFirstBucketTokens(),
235 burst - (2 * pktSize),
236 "The number of tokens in the first bucket should be two pktSizes lesser");
237
238 item = queue->Dequeue();
239 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the third packet");
240 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
241 1 * modeSize,
242 "There should be one packet in there");
243 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(), p3->GetUid(), "Was this the third packet ?");
245 queue->GetFirstBucketTokens(),
246 burst - (3 * pktSize),
247 "The number of tokens in the first bucket should be three pktSizes lesser");
248
249 item = queue->Dequeue();
250 NS_TEST_ASSERT_MSG_NE(item, nullptr, "I want to remove the fourth packet");
251 NS_TEST_ASSERT_MSG_EQ(queue->GetCurrentSize().GetValue(),
252 0 * modeSize,
253 "There should be zero packet in there");
254 NS_TEST_ASSERT_MSG_EQ(item->GetPacket()->GetUid(),
255 p4->GetUid(),
256 "Was this the fourth packet ?");
258 queue->GetFirstBucketTokens(),
259 burst - (4 * pktSize),
260 "The number of tokens in the first bucket should be four pktSizes lesser");
261
262 // test 2 : When DataRate == FirstBucketTokenRate; packets should pass smoothly.
263 queue = CreateObject<TbfQueueDisc>();
264 qSize = 10;
265 pktSize = 1000;
266 burst = 10000;
267 mtu = 1000;
268 rate = DataRate("10KB/s");
269 peakRate = DataRate("100KB/s");
270 uint32_t nPkt = qSize;
271
272 if (mode == QueueSizeUnit::BYTES)
273 {
274 modeSize = pktSize;
275 qSize = qSize * modeSize;
276 }
277
279 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
280 true,
281 "Verify that we can actually set the attribute MaxSize");
282 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
283 true,
284 "Verify that we can actually set the attribute Burst");
285 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
286 true,
287 "Verify that we can actually set the attribute Mtu");
288 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
289 true,
290 "Verify that we can actually set the attribute Rate");
291 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
292 true,
293 "Verify that we can actually set the attribute PeakRate");
294
295 queue->Initialize();
296 double delay = 0.09;
297 for (uint32_t i = 1; i <= nPkt; i++)
298 {
299 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
301 this,
302 queue,
303 dest,
304 pktSize);
305 }
306 delay = 0.1;
307 for (uint32_t i = 1; i <= nPkt; i++)
308 {
309 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
311 this,
312 queue,
313 true,
314 "No packet should be blocked");
315 }
316 Simulator::Stop(Seconds(1));
317 Simulator::Run();
318
319 // test 3 : When DataRate >>> FirstBucketTokenRate; some packets should get blocked and waking
320 // of queue should get scheduled.
321 /* 10 packets are enqueued and then dequeued. Since the token rate is less than the data rate,
322 the last packet i.e the 10th packet gets blocked and waking of queue is scheduled after a
323 time when enough tokens will be available. At that time the 10th packet passes through. */
324 queue = CreateObject<TbfQueueDisc>();
325
326 Config::SetDefault("ns3::QueueDisc::Quota", UintegerValue(1));
327 NodeContainer nodesA;
328 nodesA.Create(2);
329 Ptr<SimpleNetDevice> txDevA = CreateObject<SimpleNetDevice>();
330 nodesA.Get(0)->AddDevice(txDevA);
331 Ptr<SimpleNetDevice> rxDevA = CreateObject<SimpleNetDevice>();
332 nodesA.Get(1)->AddDevice(rxDevA);
333 Ptr<SimpleChannel> channelA = CreateObject<SimpleChannel>();
334 txDevA->SetChannel(channelA);
335 rxDevA->SetChannel(channelA);
336 txDevA->SetNode(nodesA.Get(0));
337 rxDevA->SetNode(nodesA.Get(1));
338
339 dest = txDevA->GetAddress();
340
341 Ptr<TrafficControlLayer> tcA = CreateObject<TrafficControlLayer>();
342 nodesA.Get(0)->AggregateObject(tcA);
343 tcA->SetRootQueueDiscOnDevice(txDevA, queue);
344 tcA->Initialize();
345
346 burst = 5000;
347 mtu = 1000;
348 rate = DataRate("5KB/s");
349 peakRate = DataRate("100KB/s");
350
351 if (mode == QueueSizeUnit::BYTES)
352 {
353 modeSize = pktSize;
354 qSize = qSize * modeSize;
355 }
356
358 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
359 true,
360 "Verify that we can actually set the attribute MaxSize");
361 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
362 true,
363 "Verify that we can actually set the attribute Burst");
364 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
365 true,
366 "Verify that we can actually set the attribute Mtu");
367 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
368 true,
369 "Verify that we can actually set the attribute Rate");
370 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
371 true,
372 "Verify that we can actually set the attribute PeakRate");
373
374 delay = 0.09;
375 for (uint32_t i = 1; i <= nPkt; i++)
376 {
377 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
379 this,
380 queue,
381 dest,
382 pktSize);
383 }
384 delay = 0.1;
385 for (uint32_t i = 1; i <= nPkt; i++)
386 {
387 if (i == 10)
388 {
389 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
391 this,
392 queue,
393 false,
394 "10th packet should be blocked");
395 }
396 else
397 {
398 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
400 this,
401 queue,
402 true,
403 "This packet should not be blocked");
404 }
405 }
406 Simulator::Stop(Seconds(1.3));
407 Simulator::Run();
408
409 // test 4 : This test checks the peakRate control of packet dequeue, when DataRate <
410 // FirstBucketTokenRate.
411 /* 10 packets each of size 1000 bytes are enqueued followed by
412 their dequeue. The data rate (25 KB/s) is not sufficiently higher than the btokens rate (15
413 KB/s), so that in the startup phase the first bucket is not empty. Hence when adequate tokens
414 are present in the second (peak) bucket, the packets get transmitted, otherwise they are
415 blocked. So basically the transmission of packets falls under the regulation of the second
416 bucket since first bucket will always have excess tokens. TBF does not let all the packets go
417 smoothly without any control just because there are excess tokens in the first bucket. */
418 queue = CreateObject<TbfQueueDisc>();
419
420 Config::SetDefault("ns3::QueueDisc::Quota", UintegerValue(1));
421 NodeContainer nodesB;
422 nodesB.Create(2);
423 Ptr<SimpleNetDevice> txDevB = CreateObject<SimpleNetDevice>();
424 nodesB.Get(0)->AddDevice(txDevB);
425 Ptr<SimpleNetDevice> rxDevB = CreateObject<SimpleNetDevice>();
426 nodesB.Get(1)->AddDevice(rxDevB);
427 Ptr<SimpleChannel> channelB = CreateObject<SimpleChannel>();
428 txDevB->SetChannel(channelB);
429 rxDevB->SetChannel(channelB);
430 txDevB->SetNode(nodesB.Get(0));
431 rxDevB->SetNode(nodesB.Get(1));
432
433 dest = txDevB->GetAddress();
434
435 Ptr<TrafficControlLayer> tcB = CreateObject<TrafficControlLayer>();
436 nodesB.Get(0)->AggregateObject(tcB);
437 tcB->SetRootQueueDiscOnDevice(txDevB, queue);
438 tcB->Initialize();
439
440 burst = 15000;
441 mtu = 1000;
442 pktSize = 1000;
443 rate = DataRate("15KB/s");
444 peakRate = DataRate("20KB/s");
445
446 if (mode == QueueSizeUnit::BYTES)
447 {
448 modeSize = pktSize;
449 qSize = qSize * modeSize;
450 }
451
453 queue->SetAttributeFailSafe("MaxSize", QueueSizeValue(QueueSize(mode, qSize))),
454 true,
455 "Verify that we can actually set the attribute MaxSize");
456 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Burst", UintegerValue(burst)),
457 true,
458 "Verify that we can actually set the attribute Burst");
459 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Mtu", UintegerValue(mtu)),
460 true,
461 "Verify that we can actually set the attribute Mtu");
462 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("Rate", DataRateValue(rate)),
463 true,
464 "Verify that we can actually set the attribute Rate");
465 NS_TEST_ASSERT_MSG_EQ(queue->SetAttributeFailSafe("PeakRate", DataRateValue(peakRate)),
466 true,
467 "Verify that we can actually set the attribute PeakRate");
468
469 queue->Initialize();
470 delay = 0.04;
471 for (uint32_t i = 1; i <= nPkt; i++)
472 {
473 Simulator::Schedule(Time(Seconds((i + 1) * delay)),
475 this,
476 queue,
477 dest,
478 pktSize);
479 }
480
481 // The pattern being checked is a pattern of dequeue followed by blocked. The delay between
482 // enqueues is not sufficient to allow ptokens to refill befor the next dequeue. The first
483 // enqueue is at 1.08s in the future, and the attempted dequeue is at 1.10s in the future. The
484 // first dequeue will always succeed. The second enqueue is 1.12s and attempted dequeue is
485 // at 1.14s in the future, but the last dequeue was 0.04s prior; only 800 tokens can be refilled
486 // in 0.04s at a peak rate of 20Kbps. The actual dequeue occurs at 0.01s further into the
487 // future when ptokens refills to 1000. To repeat the pattern, odd-numbered dequeue events
488 // should be spaced at intervals of at least 100ms, and the even-numbered dequeue events (that
489 // block) should be 0.04s (delay) following the last odd-numbered dequeue event.
490 double nextDelay = (2 * delay) + 0.02; // 20ms after first enqueue to attempt the first dequeue;
491 for (uint32_t i = 1; i <= nPkt; i++)
492 {
493 if (i % 2 == 1)
494 {
495 Simulator::Schedule(Seconds(nextDelay),
497 this,
498 queue,
499 true,
500 "1st packet should not be blocked");
501 nextDelay += 0.04;
502 }
503 else
504 {
505 Simulator::Schedule(Seconds(nextDelay),
507 this,
508 queue,
509 false,
510 "This packet should be blocked");
511 nextDelay += 0.06; // Need 0.04 + 0.06 seconds to allow the next packet to be dequeued
512 // without block
513 }
514 }
515 Simulator::Stop(Seconds(0.55));
516 Simulator::Run();
517}
518
519void
521{
522 queue->Enqueue(Create<TbfQueueDiscTestItem>(Create<Packet>(size), dest));
523}
524
525void
527 bool flag,
528 std::string printStatement)
529{
530 Ptr<QueueDiscItem> item = queue->Dequeue();
531 NS_TEST_EXPECT_MSG_EQ((item != nullptr), flag, printStatement);
532}
533
534void
536{
539 Simulator::Destroy();
540}
541
548static class TbfQueueDiscTestSuite : public TestSuite
549{
550 public:
552 : TestSuite("tbf-queue-disc", UNIT)
553 {
554 AddTestCase(new TbfQueueDiscTestCase(), TestCase::QUICK);
555 }
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:92
Class for representing data rates.
Definition: data-rate.h:90
AttributeValue implementation for DataRate.
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:138
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:259
uint64_t GetUid() const
Returns the packet's Uid.
Definition: packet.cc:412
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:133
Class for representing queue sizes.
Definition: queue-size.h:96
AttributeValue implementation for QueueSize.
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
Hold an unsigned integer type.
Definition: uinteger.h:45
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:891
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:328
QueueSizeUnit
Enumeration of the operating modes of queues.
Definition: queue-size.h:44
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:46
@ PACKETS
Use number of packets for queue size.
Definition: queue-size.h:45
#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:144
#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:251
#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:564
TbfQueueDiscTestSuite g_tbfQueueTestSuite
the test suite
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:850
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t pktSize
packet size used for the simulation (in bytes)