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 default constructor, copy constructor and assignment operator to avoid misuse
60
61 virtual void AddHeader (void);
62 virtual bool Mark (void);
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{
93public:
95 virtual void DoRun (void);
96private:
103 void Enqueue (Ptr<TbfQueueDisc> queue, Address dest, uint32_t size);
110 void DequeueAndCheck (Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement);
115 void RunTbfTest (QueueSizeUnit mode);
116};
117
119 : TestCase ("Sanity check on the TBF queue implementation")
120{
121}
122
123void
125{
126 uint32_t pktSize = 1500;
127 // 1 for packets; pktSize for bytes
128 uint32_t modeSize = 1;
129 uint32_t qSize = 4;
130 uint32_t burst = 6000;
131 uint32_t mtu = 0;
132 DataRate rate = DataRate ("6KB/s");
133 DataRate peakRate = DataRate ("0KB/s");
134
135 Ptr<TbfQueueDisc> queue = CreateObject<TbfQueueDisc> ();
136
137 // test 1: Simple Enqueue/Dequeue with verification of attribute setting
138 /* 1. There is no second bucket since "peakRate" is set to 0.
139 2. A simple enqueue of five packets, each containing 1500B is followed by
140 the dequeue those five packets.
141 3. The subtraction of tokens from the first bucket to send out each of the
142 five packets is monitored and verified.
143 Note : The number of tokens in the first bucket is full at the beginning.
144 With the dequeuing of each packet, the number of tokens keeps decreasing.
145 So packets are dequeued as long as there are enough tokens in the bucket. */
146
147 if (mode == QueueSizeUnit::BYTES)
148 {
149 modeSize = pktSize;
150 qSize = qSize * modeSize;
151 }
152
153 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
154 true, "Verify that we can actually set the attribute MaxSize");
155 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
156 "Verify that we can actually set the attribute Burst");
157 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
158 "Verify that we can actually set the attribute Mtu");
159 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
160 "Verify that we can actually set the attribute Rate");
161 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
162 "Verify that we can actually set the attribute PeakRate");
163
164 Address dest;
165
166 Ptr<Packet> p1, p2, p3, p4, p5;
167 p1 = Create<Packet> (pktSize);
168 p2 = Create<Packet> (pktSize);
169 p3 = Create<Packet> (pktSize);
170 p4 = Create<Packet> (pktSize);
171 p5 = Create<Packet> (pktSize);
172
173 queue->Initialize ();
174 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 0 * modeSize, "There should be no packets in there");
175 queue->Enqueue (Create<TbfQueueDiscTestItem> (p1, dest));
176 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 1 * modeSize, "There should be one packet in there");
177 queue->Enqueue (Create<TbfQueueDiscTestItem> (p2, dest));
178 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 2 * modeSize, "There should be two packets in there");
179 queue->Enqueue (Create<TbfQueueDiscTestItem> (p3, dest));
180 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 3 * modeSize, "There should be three packets in there");
181 queue->Enqueue (Create<TbfQueueDiscTestItem> (p4, dest));
182 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 4 * modeSize, "There should be four packets in there");
183 queue->Enqueue (Create<TbfQueueDiscTestItem> (p5, dest));
184 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 4 * modeSize,
185 "There should still be four packets in there as this enqueue cannot happen since QueueLimit will be exceeded");
186
188 NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst, "The first token bucket should be full");
189 item = queue->Dequeue ();
190 NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the first packet");
191 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 3 * modeSize, "There should be three packets in there");
192 NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p1->GetUid (), "was this the first packet ?");
193 NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (1 * pktSize),
194 "The number of tokens in the first bucket should be one pktSize lesser");
195
196 item = queue->Dequeue ();
197 NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the second packet");
198 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 2 * modeSize, "There should be two packets in there");
199 NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p2->GetUid (), "Was this the second packet ?");
200 NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (2 * pktSize),
201 "The number of tokens in the first bucket should be two pktSizes lesser");
202
203 item = queue->Dequeue ();
204 NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the third packet");
205 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 1 * modeSize, "There should be one packet in there");
206 NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p3->GetUid (), "Was this the third packet ?");
207 NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (3 * pktSize),
208 "The number of tokens in the first bucket should be three pktSizes lesser");
209
210 item = queue->Dequeue ();
211 NS_TEST_ASSERT_MSG_EQ ((item != 0), true, "I want to remove the fourth packet");
212 NS_TEST_ASSERT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 0 * modeSize, "There should be zero packet in there");
213 NS_TEST_ASSERT_MSG_EQ (item->GetPacket ()->GetUid (), p4->GetUid (), "Was this the fourth packet ?");
214 NS_TEST_ASSERT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (4 * pktSize),
215 "The number of tokens in the first bucket should be four pktSizes lesser");
216
217 // test 2 : When DataRate == FirstBucketTokenRate; packets should pass smoothly.
218 queue = CreateObject<TbfQueueDisc> ();
219 qSize = 10;
220 pktSize = 1000;
221 burst = 10000;
222 mtu = 1000;
223 rate = DataRate ("10KB/s");
224 peakRate = DataRate ("100KB/s");
225 uint32_t nPkt = qSize;
226
227 if (mode == QueueSizeUnit::BYTES)
228 {
229 modeSize = pktSize;
230 qSize = qSize * modeSize;
231 }
232
233 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
234 true, "Verify that we can actually set the attribute MaxSize");
235 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
236 "Verify that we can actually set the attribute Burst");
237 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
238 "Verify that we can actually set the attribute Mtu");
239 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
240 "Verify that we can actually set the attribute Rate");
241 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
242 "Verify that we can actually set the attribute PeakRate");
243
244 queue->Initialize ();
245 double delay = 0.09;
246 for (uint32_t i = 1; i <= nPkt; i++)
247 {
248 Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
249 }
250 delay = 0.1;
251 for (uint32_t i = 1; i <= nPkt; i++)
252 {
253 Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
254 queue, true, "No packet should be blocked");
255 }
256 Simulator::Stop (Seconds (1));
257 Simulator::Run ();
258
259 // test 3 : When DataRate >>> FirstBucketTokenRate; some packets should get blocked and waking of queue should get scheduled.
260 /* 10 packets are enqueued and then dequeued. Since the token rate is less than the data rate, the last packet i.e the 10th
261 packet gets blocked and waking of queue is scheduled after a time when enough tokens will be available. At that time the
262 10th packet passes through. */
263 queue = CreateObject<TbfQueueDisc> ();
264
265 Config::SetDefault ("ns3::QueueDisc::Quota", UintegerValue (1));
266 NodeContainer nodesA;
267 nodesA.Create (2);
268 Ptr<SimpleNetDevice> txDevA = CreateObject<SimpleNetDevice> ();
269 nodesA.Get (0)->AddDevice (txDevA);
270 Ptr<SimpleNetDevice> rxDevA = CreateObject<SimpleNetDevice> ();
271 nodesA.Get (1)->AddDevice (rxDevA);
272 Ptr<SimpleChannel> channelA = CreateObject<SimpleChannel> ();
273 txDevA->SetChannel (channelA);
274 rxDevA->SetChannel (channelA);
275 txDevA->SetNode (nodesA.Get (0));
276 rxDevA->SetNode (nodesA.Get (1));
277
278 dest = txDevA->GetAddress ();
279
280 Ptr<TrafficControlLayer> tcA = CreateObject<TrafficControlLayer> ();
281 nodesA.Get (0)->AggregateObject (tcA);
282 tcA->SetRootQueueDiscOnDevice (txDevA, queue);
283 tcA->Initialize ();
284
285 burst = 5000;
286 mtu = 1000;
287 rate = DataRate ("5KB/s");
288 peakRate = DataRate ("100KB/s");
289
290 if (mode == QueueSizeUnit::BYTES)
291 {
292 modeSize = pktSize;
293 qSize = qSize * modeSize;
294 }
295
296 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
297 true, "Verify that we can actually set the attribute MaxSize");
298 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
299 "Verify that we can actually set the attribute Burst");
300 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
301 "Verify that we can actually set the attribute Mtu");
302 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
303 "Verify that we can actually set the attribute Rate");
304 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
305 "Verify that we can actually set the attribute PeakRate");
306
307 delay = 0.09;
308 for (uint32_t i = 1; i <= nPkt; i++)
309 {
310 Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
311 }
312 delay = 0.1;
313 for (uint32_t i = 1; i <= nPkt; i++)
314 {
315 if (i == 10)
316 {
317 Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
318 queue, false, "10th packet should be blocked");
319 }
320 else
321 {
322 Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
323 queue, true, "This packet should not be blocked");
324 }
325 }
326 Simulator::Stop (Seconds (1.3));
327 Simulator::Run ();
328
329 // test 4 : This test checks the peakRate control of packet dequeue, when DataRate < FirstBucketTokenRate.
330 /* 10 packets each of size 1000 bytes are enqueued followed by
331 their dequeue. The data rate (25 KB/s) is not sufficiently higher than the btokens rate (15 KB/s), so that in
332 the startup phase the first bucket is not empty. Hence when adequate tokens are present in the second (peak) bucket,
333 the packets get transmitted, otherwise they are blocked. So basically the transmission of packets falls under the
334 regulation of the second bucket since first bucket will always have excess tokens. TBF does not let all
335 the packets go smoothly without any control just because there are excess tokens in the first bucket. */
336 queue = CreateObject<TbfQueueDisc> ();
337
338 Config::SetDefault ("ns3::QueueDisc::Quota", UintegerValue (1));
339 NodeContainer nodesB;
340 nodesB.Create (2);
341 Ptr<SimpleNetDevice> txDevB = CreateObject<SimpleNetDevice> ();
342 nodesB.Get (0)->AddDevice (txDevB);
343 Ptr<SimpleNetDevice> rxDevB = CreateObject<SimpleNetDevice> ();
344 nodesB.Get (1)->AddDevice (rxDevB);
345 Ptr<SimpleChannel> channelB = CreateObject<SimpleChannel> ();
346 txDevB->SetChannel (channelB);
347 rxDevB->SetChannel (channelB);
348 txDevB->SetNode (nodesB.Get (0));
349 rxDevB->SetNode (nodesB.Get (1));
350
351 dest = txDevB->GetAddress ();
352
353 Ptr<TrafficControlLayer> tcB = CreateObject<TrafficControlLayer> ();
354 nodesB.Get (0)->AggregateObject (tcB);
355 tcB->SetRootQueueDiscOnDevice (txDevB, queue);
356 tcB->Initialize ();
357
358 burst = 15000;
359 mtu = 1000;
360 pktSize = 1000;
361 rate = DataRate ("15KB/s");
362 peakRate = DataRate ("20KB/s");
363
364 if (mode == QueueSizeUnit::BYTES)
365 {
366 modeSize = pktSize;
367 qSize = qSize * modeSize;
368 }
369
370 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
371 true, "Verify that we can actually set the attribute MaxSize");
372 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
373 "Verify that we can actually set the attribute Burst");
374 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
375 "Verify that we can actually set the attribute Mtu");
376 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
377 "Verify that we can actually set the attribute Rate");
378 NS_TEST_ASSERT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
379 "Verify that we can actually set the attribute PeakRate");
380
381 queue->Initialize ();
382 delay = 0.04;
383 for (uint32_t i = 1; i <= nPkt; i++)
384 {
385 Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
386 }
387
388 // The pattern being checked is a pattern of dequeue followed by blocked. The delay between enqueues is not sufficient
389 // to allow ptokens to refill befor the next dequeue. The first enqueue is at 1.08s in the future, and the attempted
390 // dequeue is at 1.10s in the future. The first dequeue will always succeed. The second enqueue is 1.12s and attempted
391 // 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
392 // at a peak rate of 20Kbps. The actual dequeue occurs at 0.01s further into the future when ptokens refills to 1000.
393 // To repeat the pattern, odd-numbered dequeue events should be spaced at intervals of at least 100ms, and the
394 // even-numbered dequeue events (that block) should be 0.04s (delay) following the last odd-numbered dequeue event.
395 double nextDelay = (2 * delay) + 0.02; // 20ms after first enqueue to attempt the first dequeue;
396 for (uint32_t i = 1; i <= nPkt; i++)
397 {
398 if (i % 2 == 1)
399 {
400 Simulator::Schedule (Seconds (nextDelay), &TbfQueueDiscTestCase::DequeueAndCheck, this,
401 queue, true, "1st packet should not be blocked");
402 nextDelay += 0.04;
403 }
404 else
405 {
406 Simulator::Schedule (Seconds (nextDelay), &TbfQueueDiscTestCase::DequeueAndCheck, this,
407 queue, false, "This packet should be blocked");
408 nextDelay += 0.06; // Need 0.04 + 0.06 seconds to allow the next packet to be dequeued without block
409 }
410 }
411 Simulator::Stop (Seconds (0.55));
412 Simulator::Run ();
413
414}
415
416void
418{
419 queue->Enqueue (Create<TbfQueueDiscTestItem> (Create<Packet> (size), dest));
420}
421
422void
423TbfQueueDiscTestCase::DequeueAndCheck (Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement)
424{
425 Ptr<QueueDiscItem> item = queue->Dequeue ();
426 NS_TEST_EXPECT_MSG_EQ ((item != 0), flag, printStatement);
427}
428
429void
431{
434 Simulator::Destroy ();
435
436}
437
444static class TbfQueueDiscTestSuite : public TestSuite
445{
446public:
448 : TestSuite ("tbf-queue-disc", UNIT)
449 {
450 AddTestCase (new TbfQueueDiscTestCase (), TestCase::QUICK);
451 }
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.
TbfQueueDiscTestItem()=delete
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