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