A Discrete-Event Network Simulator
API
prio-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 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: Stefano Avallone <stavallo@unina.it>
19  *
20  */
21 
22 #include "ns3/test.h"
23 #include "ns3/prio-queue-disc.h"
24 #include "ns3/fifo-queue-disc.h"
25 #include "ns3/packet-filter.h"
26 #include "ns3/packet.h"
27 #include "ns3/socket.h"
28 #include "ns3/string.h"
29 #include "ns3/log.h"
30 #include "ns3/simulator.h"
31 #include <array>
32 #include <queue>
33 
34 using namespace ns3;
35 
43 {
44 public:
52  PrioQueueDiscTestItem (Ptr<Packet> p, const Address & addr, uint8_t priority);
53  virtual ~PrioQueueDiscTestItem ();
54  virtual void AddHeader (void);
55  virtual bool Mark (void);
56 };
57 
59  : QueueDiscItem (p, addr, 0)
60 {
61  SocketPriorityTag priorityTag;
62  priorityTag.SetPriority (priority);
63  p->ReplacePacketTag (priorityTag);
64 }
65 
67 {
68 }
69 
70 void
72 {
73 }
74 
75 bool
77 {
78  return false;
79 }
80 
81 
89 {
90 public:
96  PrioQueueDiscTestFilter (bool cls);
97  virtual ~PrioQueueDiscTestFilter ();
103  void SetReturnValue (int32_t ret);
104 
105 private:
106  virtual bool CheckProtocol (Ptr<QueueDiscItem> item) const;
107  virtual int32_t DoClassify (Ptr<QueueDiscItem> item) const;
108 
109  bool m_cls;
110  int32_t m_ret;
111 };
112 
114  : m_cls (cls),
115  m_ret (0)
116 {
117 }
118 
120 {
121 }
122 
123 void
125 {
126  m_ret = ret;
127 }
128 
129 bool
131 {
132  return m_cls;
133 }
134 
135 int32_t
137 {
138  return m_ret;
139 }
140 
141 
149 {
150 public:
152  virtual void DoRun (void);
153 };
154 
156  : TestCase ("Sanity check on the prio queue disc implementation")
157 {
158 }
159 
160 void
162 {
163  Ptr<PrioQueueDisc> qdisc;
164  Ptr<QueueDiscItem> item;
165  std::string priomap ("0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3");
166  Address dest;
167  std::array<std::queue<uint64_t>,4> uids;
168 
169  /*
170  * Test 1: set priomap
171  */
172  qdisc = CreateObject<PrioQueueDisc> ();
173 
174  // add 4 child fifo queue discs
175  for (uint8_t i = 0; i < 4; i++)
176  {
177  Ptr<FifoQueueDisc> child = CreateObject<FifoQueueDisc> ();
178  child->Initialize ();
179  Ptr<QueueDiscClass> c = CreateObject<QueueDiscClass> ();
180  c->SetQueueDisc (child);
181  qdisc->AddQueueDiscClass (c);
182  }
183  qdisc->Initialize ();
184 
185  NS_TEST_ASSERT_MSG_EQ (qdisc->GetNQueueDiscClasses (), 4, "Verify that the queue disc has 4 child queue discs");
186 
187  NS_TEST_ASSERT_MSG_EQ (qdisc->SetAttributeFailSafe ("Priomap", StringValue (priomap)),
188  true, "Verify that we can actually set the attribute Priomap");
189 
190  StringValue sv;
191  NS_TEST_ASSERT_MSG_EQ (qdisc->GetAttributeFailSafe ("Priomap", sv),
192  true, "Verify that we can actually get the attribute Priomap");
193 
194  NS_TEST_ASSERT_MSG_EQ (sv.Get (), priomap, "Verify that the priomap has been correctly set");
195 
196  /*
197  * Test 2: classify packets based on priomap because no packet filter is installed
198  */
199 
200  // create packets with priorities from 0 to 3
201  for (uint16_t i = 0; i < 4; i++)
202  {
203  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
204  0, "There should be no packets in the child queue disc " << i);
205 
206  item = Create<PrioQueueDiscTestItem> (Create<Packet> (100), dest, i);
207  qdisc->Enqueue (item);
208  // packet is assigned band i
209  uids[i].push (item->GetPacket ()->GetUid ());
210 
211  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
212  1, "There should be one packet in the child queue disc " << i);
213  }
214 
215  /*
216  * Test 3: classify packets based on priomap because no packet filter able
217  * to classify packets is installed
218  */
219 
220  Ptr<PrioQueueDiscTestFilter> pf1 = CreateObject<PrioQueueDiscTestFilter> (false);
221  qdisc->AddPacketFilter (pf1);
222 
223  // create packets with priorities from 4 to 7
224  for (uint16_t i = 0; i < 4; i++)
225  {
226  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
227  1, "There should be one packet in the child queue disc " << i);
228 
229  item = Create<PrioQueueDiscTestItem> (Create<Packet> (100), dest, i+4);
230  qdisc->Enqueue (item);
231  // packet is assigned band i
232  uids[i].push (item->GetPacket ()->GetUid ());
233 
234  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
235  2, "There should be two packets in the child queue disc " << i);
236  }
237 
238  /*
239  * Test 4: classify packets based on the value returned by the installed packet filter
240  */
241 
242  Ptr<PrioQueueDiscTestFilter> pf2 = CreateObject<PrioQueueDiscTestFilter> (true);
243  qdisc->AddPacketFilter (pf2);
244 
245  // create packets with priority 0 (which is neglected by the prio queue disc)
246  for (uint16_t i = 0; i < 4; i++)
247  {
248  pf2->SetReturnValue (i);
249  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
250  2, "There should be two packets in the child queue disc " << i);
251 
252  item = Create<PrioQueueDiscTestItem> (Create<Packet> (100), dest, 0);
253  qdisc->Enqueue (item);
254  // packet is assigned band i
255  uids[i].push (item->GetPacket ()->GetUid ());
256 
257  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
258  3, "There should be three packets in the child queue disc " << i);
259  }
260 
261  /*
262  * Test 5: classify packets into the band specified by the first element of the
263  * priomap array because the value returned by the installed packet filter is
264  * not less than the number of bands
265  */
266 
267  // create packets with priority 1 (which is neglected by the prio queue disc)
268  for (uint16_t i = 0; i < 4; i++)
269  {
270  pf2->SetReturnValue (4+i);
271  NS_TEST_ASSERT_MSG_EQ (qdisc->GetBandForPriority (0), 0, "The band for priority 0 must be band 0");
272  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), i+3u,
273  "There should be " << i+3 << " packets in the child queue disc "
274  << qdisc->GetBandForPriority (0));
275 
276  item = Create<PrioQueueDiscTestItem> (Create<Packet> (100), dest, 1);
277  qdisc->Enqueue (item);
278  // packet is assigned band 0
279  uids[0].push (item->GetPacket ()->GetUid ());
280 
281  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), i+4u,
282  "There should be " << i+4 << " packets in the child queue disc "
283  << qdisc->GetBandForPriority (0));
284  }
285 
286  /*
287  * Test 6: dequeue packets starting from the highest priority band (band 0)
288  */
289 
290  while ((item = qdisc->Dequeue ()))
291  {
292  for (uint16_t i = 0; i < 4; i++)
293  {
294  if (uids[i].empty ())
295  {
296  NS_TEST_ASSERT_MSG_EQ (qdisc->GetQueueDiscClass (i)->GetQueueDisc ()->GetNPackets (),
297  0, "Band " << i << " should be empty");
298  continue;
299  }
300  NS_TEST_ASSERT_MSG_EQ (uids[i].front (), item->GetPacket ()->GetUid (),
301  "The dequeued packet is not the one we expected");
302  uids[i].pop ();
303  break;
304  }
305  }
306 
307  Simulator::Destroy ();
308 }
309 
316 static class PrioQueueDiscTestSuite : public TestSuite
317 {
318 public:
320  : TestSuite ("prio-queue-disc", UNIT)
321  {
322  AddTestCase (new PrioQueueDiscTestCase (), TestCase::QUICK);
323  }
Prio Queue Disc Test Case.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Prio Queue Disc Test Packet Filter.
PrioQueueDiscTestFilter(bool cls)
Constructor.
virtual bool CheckProtocol(Ptr< QueueDiscItem > item) const
Checks if the filter is able to classify a kind of items.
bool m_cls
whether this filter is able to classify a PrioQueueDiscTestItem
virtual int32_t DoClassify(Ptr< QueueDiscItem > item) const
Classify a packet.
void SetReturnValue(int32_t ret)
Set the value returned by DoClassify.
int32_t m_ret
the value that DoClassify returns if m_cls is true
Prio Queue Disc Test Item.
virtual void AddHeader(void)
Add the header to the packet.
PrioQueueDiscTestItem(Ptr< Packet > p, const Address &addr, uint8_t priority)
Constructor.
virtual bool Mark(void)
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
Prio Queue Disc Test Suite.
a polymophic address class
Definition: address.h:91
PacketFilter is the abstract base class for filters used by queue discs to classify packets.
Definition: packet-filter.h:34
bool ReplacePacketTag(Tag &tag)
Replace the value of a packet tag.
Definition: packet.cc:970
QueueDiscItem is the abstract base class for items that are stored in a queue disc.
Definition: queue-item.h:133
indicates whether the socket has a priority set.
Definition: socket.h:1309
void SetPriority(uint8_t priority)
Set the tag's priority.
Definition: socket.cc:842
Hold variables of type string.
Definition: string.h:41
std::string Get(void) const
Definition: string.cc:31
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
make Callback use a separate empty type
Definition: empty.h:34
#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
PrioQueueDiscTestSuite g_prioQueueTestSuite
the test suite
Every class exported by the ns3 library is enclosed in the ns3 namespace.