A Discrete-Event Network Simulator
API
prio-queue-disc-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Authors: Stefano Avallone <stavallo@unina.it>
18  *
19  */
20 
21 #include "ns3/fifo-queue-disc.h"
22 #include "ns3/log.h"
23 #include "ns3/packet-filter.h"
24 #include "ns3/packet.h"
25 #include "ns3/prio-queue-disc.h"
26 #include "ns3/simulator.h"
27 #include "ns3/socket.h"
28 #include "ns3/string.h"
29 #include "ns3/test.h"
30 
31 #include <array>
32 #include <queue>
33 
34 using namespace ns3;
35 
42 {
43  public:
51  PrioQueueDiscTestItem(Ptr<Packet> p, const Address& addr, uint8_t priority);
52  void AddHeader() override;
53  bool Mark() override;
54 };
55 
57  : QueueDiscItem(p, addr, 0)
58 {
59  SocketPriorityTag priorityTag;
60  priorityTag.SetPriority(priority);
61  p->ReplacePacketTag(priorityTag);
62 }
63 
64 void
66 {
67 }
68 
69 bool
71 {
72  return false;
73 }
74 
81 {
82  public:
88  PrioQueueDiscTestFilter(bool cls);
89  ~PrioQueueDiscTestFilter() override;
95  void SetReturnValue(int32_t ret);
96 
97  private:
98  bool CheckProtocol(Ptr<QueueDiscItem> item) const override;
99  int32_t DoClassify(Ptr<QueueDiscItem> item) const override;
100 
101  bool m_cls;
102  int32_t m_ret;
103 };
104 
106  : m_cls(cls),
107  m_ret(0)
108 {
109 }
110 
112 {
113 }
114 
115 void
117 {
118  m_ret = ret;
119 }
120 
121 bool
123 {
124  return m_cls;
125 }
126 
127 int32_t
129 {
130  return m_ret;
131 }
132 
139 {
140  public:
142  void DoRun() override;
143 };
144 
146  : TestCase("Sanity check on the prio queue disc implementation")
147 {
148 }
149 
150 void
152 {
153  Ptr<PrioQueueDisc> qdisc;
154  Ptr<QueueDiscItem> item;
155  std::string priomap("0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3");
156  Address dest;
157  std::array<std::queue<uint64_t>, 4> uids;
158 
159  /*
160  * Test 1: set priomap
161  */
162  qdisc = CreateObject<PrioQueueDisc>();
163 
164  // add 4 child fifo queue discs
165  for (uint8_t i = 0; i < 4; i++)
166  {
167  Ptr<FifoQueueDisc> child = CreateObject<FifoQueueDisc>();
168  child->Initialize();
169  Ptr<QueueDiscClass> c = CreateObject<QueueDiscClass>();
170  c->SetQueueDisc(child);
171  qdisc->AddQueueDiscClass(c);
172  }
173  qdisc->Initialize();
174 
175  NS_TEST_ASSERT_MSG_EQ(qdisc->GetNQueueDiscClasses(),
176  4,
177  "Verify that the queue disc has 4 child queue discs");
178 
179  NS_TEST_ASSERT_MSG_EQ(qdisc->SetAttributeFailSafe("Priomap", StringValue(priomap)),
180  true,
181  "Verify that we can actually set the attribute Priomap");
182 
183  StringValue sv;
184  NS_TEST_ASSERT_MSG_EQ(qdisc->GetAttributeFailSafe("Priomap", sv),
185  true,
186  "Verify that we can actually get the attribute Priomap");
187 
188  NS_TEST_ASSERT_MSG_EQ(sv.Get(), priomap, "Verify that the priomap has been correctly set");
189 
190  /*
191  * Test 2: classify packets based on priomap because no packet filter is installed
192  */
193 
194  // create packets with priorities from 0 to 3
195  for (uint16_t i = 0; i < 4; i++)
196  {
197  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(i)->GetQueueDisc()->GetNPackets(),
198  0,
199  "There should be no packets in the child queue disc " << i);
200 
201  item = Create<PrioQueueDiscTestItem>(Create<Packet>(100), dest, i);
202  qdisc->Enqueue(item);
203  // packet is assigned band i
204  uids[i].push(item->GetPacket()->GetUid());
205 
206  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(i)->GetQueueDisc()->GetNPackets(),
207  1,
208  "There should be one packet in the child queue disc " << i);
209  }
210 
211  /*
212  * Test 3: classify packets based on priomap because no packet filter able
213  * to classify packets is installed
214  */
215 
216  Ptr<PrioQueueDiscTestFilter> pf1 = CreateObject<PrioQueueDiscTestFilter>(false);
217  qdisc->AddPacketFilter(pf1);
218 
219  // create packets with priorities from 4 to 7
220  for (uint16_t i = 0; i < 4; i++)
221  {
222  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(i)->GetQueueDisc()->GetNPackets(),
223  1,
224  "There should be one packet in the child queue disc " << i);
225 
226  item = Create<PrioQueueDiscTestItem>(Create<Packet>(100), dest, i + 4);
227  qdisc->Enqueue(item);
228  // packet is assigned band i
229  uids[i].push(item->GetPacket()->GetUid());
230 
231  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(i)->GetQueueDisc()->GetNPackets(),
232  2,
233  "There should be two packets in the child queue disc " << i);
234  }
235 
236  /*
237  * Test 4: classify packets based on the value returned by the installed packet filter
238  */
239 
240  Ptr<PrioQueueDiscTestFilter> pf2 = CreateObject<PrioQueueDiscTestFilter>(true);
241  qdisc->AddPacketFilter(pf2);
242 
243  // create packets with priority 0 (which is neglected by the prio queue disc)
244  for (uint16_t i = 0; i < 4; i++)
245  {
246  pf2->SetReturnValue(i);
247  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(i)->GetQueueDisc()->GetNPackets(),
248  2,
249  "There should be two packets in the child queue disc " << i);
250 
251  item = Create<PrioQueueDiscTestItem>(Create<Packet>(100), dest, 0);
252  qdisc->Enqueue(item);
253  // packet is assigned band i
254  uids[i].push(item->GetPacket()->GetUid());
255 
256  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(i)->GetQueueDisc()->GetNPackets(),
257  3,
258  "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),
272  0,
273  "The band for priority 0 must be band 0");
274  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
275  i + 3U,
276  "There should be " << i + 3 << " packets in the child queue disc "
277  << qdisc->GetBandForPriority(0));
278 
279  item = Create<PrioQueueDiscTestItem>(Create<Packet>(100), dest, 1);
280  qdisc->Enqueue(item);
281  // packet is assigned band 0
282  uids[0].push(item->GetPacket()->GetUid());
283 
284  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
285  i + 4U,
286  "There should be " << i + 4 << " packets in the child queue disc "
287  << qdisc->GetBandForPriority(0));
288  }
289 
290  /*
291  * Test 6: dequeue packets starting from the highest priority band (band 0)
292  */
293 
294  while ((item = qdisc->Dequeue()))
295  {
296  for (uint16_t i = 0; i < 4; i++)
297  {
298  if (uids[i].empty())
299  {
300  NS_TEST_ASSERT_MSG_EQ(qdisc->GetQueueDiscClass(i)->GetQueueDisc()->GetNPackets(),
301  0,
302  "Band " << i << " should be empty");
303  continue;
304  }
305  NS_TEST_ASSERT_MSG_EQ(uids[i].front(),
306  item->GetPacket()->GetUid(),
307  "The dequeued packet is not the one we expected");
308  uids[i].pop();
309  break;
310  }
311  }
312 
313  Simulator::Destroy();
314 }
315 
321 static class PrioQueueDiscTestSuite : public TestSuite
322 {
323  public:
325  : TestSuite("prio-queue-disc", UNIT)
326  {
327  AddTestCase(new PrioQueueDiscTestCase(), TestCase::QUICK);
328  }
Prio Queue Disc Test Case.
void DoRun() override
Implementation to actually run this TestCase.
Prio Queue Disc Test Packet Filter.
PrioQueueDiscTestFilter(bool cls)
Constructor.
bool m_cls
whether this filter is able to classify a PrioQueueDiscTestItem
int32_t DoClassify(Ptr< QueueDiscItem > item) const override
Classify a packet.
bool CheckProtocol(Ptr< QueueDiscItem > item) const override
Checks if the filter is able to classify a kind of items.
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.
bool Mark() override
Marks the packet as a substitute for dropping it, such as for Explicit Congestion Notification.
PrioQueueDiscTestItem(Ptr< Packet > p, const Address &addr, uint8_t priority)
Constructor.
void AddHeader() override
Add the header to the packet.
Prio Queue Disc Test Suite.
a polymophic address class
Definition: address.h:101
PacketFilter is the abstract base class for filters used by queue discs to classify packets.
Definition: packet-filter.h:35
bool ReplacePacketTag(Tag &tag)
Replace the value of a packet tag.
Definition: packet.cc:975
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:1316
void SetPriority(uint8_t priority)
Set the tag's priority.
Definition: socket.cc:854
Hold variables of type string.
Definition: string.h:56
std::string Get() const
Definition: string.cc:31
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:301
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
#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
PrioQueueDiscTestSuite g_prioQueueTestSuite
the test suite
Every class exported by the ns3 library is enclosed in the ns3 namespace.