A Discrete-Event Network Simulator
API
fq-cobalt-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) 2016 Universita' degli Studi di Napoli Federico II
4  * Copyright (c) 2020 NITK Surathkal (adapted for COBALT)
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: Pasquale Imputato <p.imputato@gmail.com>
20  * Stefano Avallone <stefano.avallone@unina.it>
21  * Modified by: Bhaskar Kataria <bhaskar.k7920@gmail.com> (COBALT changes)
22  */
23 
24 #include "ns3/test.h"
25 #include "ns3/simulator.h"
26 #include "ns3/fq-cobalt-queue-disc.h"
27 #include "ns3/cobalt-queue-disc.h"
28 #include "ns3/ipv4-header.h"
29 #include "ns3/ipv4-packet-filter.h"
30 #include "ns3/ipv4-queue-disc-item.h"
31 #include "ns3/ipv4-address.h"
32 #include "ns3/ipv6-header.h"
33 #include "ns3/ipv6-packet-filter.h"
34 #include "ns3/ipv6-queue-disc-item.h"
35 #include "ns3/tcp-header.h"
36 #include "ns3/udp-header.h"
37 #include "ns3/string.h"
38 #include "ns3/pointer.h"
39 
40 using namespace ns3;
41 
42 // Variable to assign m_hash to a new packet's flow
43 int32_t m_hash;
44 
50 public:
55  static TypeId GetTypeId (void);
56 
58  virtual ~Ipv4FqCobaltTestPacketFilter ();
59 
60 private:
61  virtual int32_t DoClassify (Ptr<QueueDiscItem> item) const;
62  virtual bool CheckProtocol (Ptr<QueueDiscItem> item) const;
63 };
64 
65 TypeId
67 {
68  static TypeId tid = TypeId ("ns3::Ipv4FqCobaltTestPacketFilter")
70  .SetGroupName ("Internet")
71  .AddConstructor<Ipv4FqCobaltTestPacketFilter> ()
72  ;
73  return tid;
74 }
75 
77 {
78 }
79 
81 {
82 }
83 
84 int32_t
86 {
87  return m_hash;
88 }
89 
90 bool
92 {
93  return true;
94 }
95 
100 {
101 public:
104 
105 private:
106  virtual void DoRun (void);
107 };
108 
110  : TestCase ("Test packets that are not classified by any filter")
111 {
112 }
113 
115 {
116 }
117 
118 void
120 {
121  // Packets that cannot be classified by the available filters should be dropped
122  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("4p"));
123  Ptr<Ipv4FqCobaltTestPacketFilter> filter = CreateObject<Ipv4FqCobaltTestPacketFilter> ();
124  queueDisc->AddPacketFilter (filter);
125 
126  m_hash = -1;
127  queueDisc->SetQuantum (1500);
128  queueDisc->Initialize ();
129 
130  Ptr<Packet> p;
131  p = Create<Packet> ();
133  Ipv6Header ipv6Header;
134  Address dest;
135  item = Create<Ipv6QueueDiscItem> (p, dest, 0, ipv6Header);
136  queueDisc->Enqueue (item);
137  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetNQueueDiscClasses (), 0, "no flow queue should have been created");
138 
139  p = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello, world"), 12);
140  item = Create<Ipv6QueueDiscItem> (p, dest, 0, ipv6Header);
141  queueDisc->Enqueue (item);
142  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetNQueueDiscClasses (), 0, "no flow queue should have been created");
143 
144  Simulator::Destroy ();
145 }
146 
151 {
152 public:
155 
156 private:
157  virtual void DoRun (void);
158  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr);
159 };
160 
162  : TestCase ("Test IP flows separation and packet limit")
163 {
164 }
165 
167 {
168 }
169 
170 void
172 {
173  Ptr<Packet> p = Create<Packet> (100);
174  Address dest;
175  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
176  queue->Enqueue (item);
177 }
178 
179 void
181 {
182  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("4p"));
183 
184  queueDisc->SetQuantum (1500);
185  queueDisc->Initialize ();
186 
187  Ipv4Header hdr;
188  hdr.SetPayloadSize (100);
189  hdr.SetSource (Ipv4Address ("10.10.1.1"));
190  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
191  hdr.SetProtocol (7);
192 
193  // Add three packets from the first flow
194  AddPacket (queueDisc, hdr);
195  AddPacket (queueDisc, hdr);
196  AddPacket (queueDisc, hdr);
197  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
198  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the flow queue");
199 
200  // Add two packets from the second flow
201  hdr.SetDestination (Ipv4Address ("10.10.1.7"));
202  // Add the first packet
203  AddPacket (queueDisc, hdr);
204  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
205  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the flow queue");
206  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the flow queue");
207  // Add the second packet that causes two packets to be dropped from the fat flow (max backlog = 300, threshold = 150)
208  AddPacket (queueDisc, hdr);
209  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
210  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the flow queue");
211  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the flow queue");
212 
213  Simulator::Destroy ();
214 }
215 
220 {
221 public:
223  virtual ~FqCobaltQueueDiscDeficit ();
224 
225 private:
226  virtual void DoRun (void);
227  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr);
228 };
229 
231  : TestCase ("Test credits and flows status")
232 {
233 }
234 
236 {
237 }
238 
239 void
241 {
242  Ptr<Packet> p = Create<Packet> (100);
243  Address dest;
244  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
245  queue->Enqueue (item);
246 }
247 
248 void
250 {
251  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ();
252 
253  queueDisc->SetQuantum (90);
254  queueDisc->Initialize ();
255 
256  Ipv4Header hdr;
257  hdr.SetPayloadSize (100);
258  hdr.SetSource (Ipv4Address ("10.10.1.1"));
259  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
260  hdr.SetProtocol (7);
261 
262  // Add a packet from the first flow
263  AddPacket (queueDisc, hdr);
264  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 1, "unexpected number of packets in the queue disc");
265  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
266  Ptr<FqCobaltFlow> flow1 = StaticCast<FqCobaltFlow> (queueDisc->GetQueueDiscClass (0));
267  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), static_cast<int32_t> (queueDisc->GetQuantum ()), "the deficit of the first flow must equal the quantum");
268  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::NEW_FLOW, "the first flow must be in the list of new queues");
269  // Dequeue a packet
270  queueDisc->Dequeue ();
271  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 0, "unexpected number of packets in the queue disc");
272  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the first flow queue");
273  // the deficit for the first flow becomes 90 - (100+20) = -30
274  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -30, "unexpected deficit for the first flow");
275 
276  // Add two packets from the first flow
277  AddPacket (queueDisc, hdr);
278  AddPacket (queueDisc, hdr);
279  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 2, "unexpected number of packets in the queue disc");
280  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
281  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::NEW_FLOW, "the first flow must still be in the list of new queues");
282 
283  // Add two packets from the second flow
284  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
285  AddPacket (queueDisc, hdr);
286  AddPacket (queueDisc, hdr);
287  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
288  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
289  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the second flow queue");
290  Ptr<FqCobaltFlow> flow2 = StaticCast<FqCobaltFlow> (queueDisc->GetQueueDiscClass (1));
291  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), static_cast<int32_t> (queueDisc->GetQuantum ()), "the deficit of the second flow must equal the quantum");
292  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::NEW_FLOW, "the second flow must be in the list of new queues");
293 
294  // Dequeue a packet (from the second flow, as the first flow has a negative deficit)
295  queueDisc->Dequeue ();
296  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
297  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
298  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
299  // the first flow got a quantum of deficit (-30+90=60) and has been moved to the end of the list of old queues
300  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 60, "unexpected deficit for the first flow");
301  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::OLD_FLOW, "the first flow must be in the list of old queues");
302  // the second flow has a negative deficit (-30) and is still in the list of new queues
303  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), -30, "unexpected deficit for the second flow");
304  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::NEW_FLOW, "the second flow must be in the list of new queues");
305 
306  // Dequeue a packet (from the first flow, as the second flow has a negative deficit)
307  queueDisc->Dequeue ();
308  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 2, "unexpected number of packets in the queue disc");
309  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
310  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
311  // the first flow has a negative deficit (60-(100+20)= -60) and stays in the list of old queues
312  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -60, "unexpected deficit for the first flow");
313  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::OLD_FLOW, "the first flow must be in the list of old queues");
314  // the second flow got a quantum of deficit (-30+90=60) and has been moved to the end of the list of old queues
315  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 60, "unexpected deficit for the second flow");
316  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::OLD_FLOW, "the second flow must be in the list of new queues");
317 
318  // Dequeue a packet (from the second flow, as the first flow has a negative deficit)
319  queueDisc->Dequeue ();
320  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 1, "unexpected number of packets in the queue disc");
321  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
322  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the second flow queue");
323  // the first flow got a quantum of deficit (-60+90=30) and has been moved to the end of the list of old queues
324  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 30, "unexpected deficit for the first flow");
325  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::OLD_FLOW, "the first flow must be in the list of old queues");
326  // the second flow has a negative deficit (60-(100+20)= -60)
327  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), -60, "unexpected deficit for the second flow");
328  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::OLD_FLOW, "the second flow must be in the list of new queues");
329 
330  // Dequeue a packet (from the first flow, as the second flow has a negative deficit)
331  queueDisc->Dequeue ();
332  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 0, "unexpected number of packets in the queue disc");
333  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the first flow queue");
334  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the second flow queue");
335  // the first flow has a negative deficit (30-(100+20)= -90)
336  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -90, "unexpected deficit for the first flow");
337  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::OLD_FLOW, "the first flow must be in the list of old queues");
338  // the second flow got a quantum of deficit (-60+90=30) and has been moved to the end of the list of old queues
339  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 30, "unexpected deficit for the second flow");
340  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::OLD_FLOW, "the second flow must be in the list of new queues");
341 
342  // Dequeue a packet
343  queueDisc->Dequeue ();
344  // the first flow is at the head of the list of old queues but has a negative deficit, thus it gets a quantun
345  // of deficit (-90+90=0) and is moved to the end of the list of old queues. Then, the second flow (which has a
346  // positive deficit) is selected, but the second flow is empty and thus it is set to inactive. The first flow is
347  // reconsidered, but it has a null deficit, hence it gets another quantum of deficit (0+90=90). Then, the first
348  // flow is reconsidered again, now it has a positive deficit and hence it is selected. But, it is empty and
349  // therefore is set to inactive, too.
350  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 90, "unexpected deficit for the first flow");
351  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::INACTIVE, "the first flow must be inactive");
352  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 30, "unexpected deficit for the second flow");
353  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::INACTIVE, "the second flow must be inactive");
354 
355  Simulator::Destroy ();
356 }
357 
362 {
363 public:
366 
367 private:
368  virtual void DoRun (void);
369  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header ipHdr, TcpHeader tcpHdr);
370 };
371 
373  : TestCase ("Test TCP flows separation")
374 {
375 }
376 
378 {
379 }
380 
381 void
383 {
384  Ptr<Packet> p = Create<Packet> (100);
385  p->AddHeader (tcpHdr);
386  Address dest;
387  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, ipHdr);
388  queue->Enqueue (item);
389 }
390 
391 void
393 {
394  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10p"));
395 
396  queueDisc->SetQuantum (1500);
397  queueDisc->Initialize ();
398 
399  Ipv4Header hdr;
400  hdr.SetPayloadSize (100);
401  hdr.SetSource (Ipv4Address ("10.10.1.1"));
402  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
403  hdr.SetProtocol (6);
404 
405  TcpHeader tcpHdr;
406  tcpHdr.SetSourcePort (7);
407  tcpHdr.SetDestinationPort (27);
408 
409  // Add three packets from the first flow
410  AddPacket (queueDisc, hdr, tcpHdr);
411  AddPacket (queueDisc, hdr, tcpHdr);
412  AddPacket (queueDisc, hdr, tcpHdr);
413  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
414  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
415 
416  // Add a packet from the second flow
417  tcpHdr.SetSourcePort (8);
418  AddPacket (queueDisc, hdr, tcpHdr);
419  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
420  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
421  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
422 
423  // Add a packet from the third flow
424  tcpHdr.SetDestinationPort (28);
425  AddPacket (queueDisc, hdr, tcpHdr);
426  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 5, "unexpected number of packets in the queue disc");
427  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
428  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
429  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
430 
431  // Add two packets from the fourth flow
432  tcpHdr.SetSourcePort (7);
433  AddPacket (queueDisc, hdr, tcpHdr);
434  AddPacket (queueDisc, hdr, tcpHdr);
435  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 7, "unexpected number of packets in the queue disc");
436  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
437  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
438  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
439  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the third flow queue");
440 
441  Simulator::Destroy ();
442 }
443 
448 {
449 public:
452 
453 private:
454  virtual void DoRun (void);
455  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header ipHdr, UdpHeader udpHdr);
456 };
457 
459  : TestCase ("Test UDP flows separation")
460 {
461 }
462 
464 {
465 }
466 
467 void
469 {
470  Ptr<Packet> p = Create<Packet> (100);
471  p->AddHeader (udpHdr);
472  Address dest;
473  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, ipHdr);
474  queue->Enqueue (item);
475 }
476 
477 void
479 {
480  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10p"));
481 
482  queueDisc->SetQuantum (1500);
483  queueDisc->Initialize ();
484 
485  Ipv4Header hdr;
486  hdr.SetPayloadSize (100);
487  hdr.SetSource (Ipv4Address ("10.10.1.1"));
488  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
489  hdr.SetProtocol (17);
490 
491  UdpHeader udpHdr;
492  udpHdr.SetSourcePort (7);
493  udpHdr.SetDestinationPort (27);
494 
495  // Add three packets from the first flow
496  AddPacket (queueDisc, hdr, udpHdr);
497  AddPacket (queueDisc, hdr, udpHdr);
498  AddPacket (queueDisc, hdr, udpHdr);
499  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
500  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
501 
502  // Add a packet from the second flow
503  udpHdr.SetSourcePort (8);
504  AddPacket (queueDisc, hdr, udpHdr);
505  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
506  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
507  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
508 
509  // Add a packet from the third flow
510  udpHdr.SetDestinationPort (28);
511  AddPacket (queueDisc, hdr, udpHdr);
512  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 5, "unexpected number of packets in the queue disc");
513  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
514  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
515  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
516 
517  // Add two packets from the fourth flow
518  udpHdr.SetSourcePort (7);
519  AddPacket (queueDisc, hdr, udpHdr);
520  AddPacket (queueDisc, hdr, udpHdr);
521  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 7, "unexpected number of packets in the queue disc");
522  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
523  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
524  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
525  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the third flow queue");
526 
527  Simulator::Destroy ();
528 }
529 
547 {
548 public:
550  virtual ~FqCobaltQueueDiscEcnMarking ();
551 
552 private:
553  virtual void DoRun (void);
554  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr, u_int32_t nPkt, u_int32_t nPktEnqueued, u_int32_t nQueueFlows);
555  void Dequeue (Ptr<FqCobaltQueueDisc> queue, uint32_t nPkt);
556  void DequeueWithDelay (Ptr<FqCobaltQueueDisc> queue, double delay, uint32_t nPkt);
557  void DropNextTracer (int64_t oldVal, int64_t newVal);
558  uint32_t m_dropNextCount;
559 };
560 
562  : TestCase ("Test ECN marking")
563 {
564  m_dropNextCount = 0;
565 }
566 
568 {
569 }
570 
571 void
572 FqCobaltQueueDiscEcnMarking::AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr, u_int32_t nPkt, u_int32_t nPktEnqueued, u_int32_t nQueueFlows)
573 {
574  Address dest;
575  Ptr<Packet> p = Create<Packet> (100);
576  for (uint32_t i = 0; i < nPkt; i++)
577  {
578  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
579  queue->Enqueue (item);
580  }
581  NS_TEST_EXPECT_MSG_EQ (queue->GetNQueueDiscClasses (), nQueueFlows, "unexpected number of flow queues");
582  NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), nPktEnqueued, "unexpected number of enqueued packets");
583 }
584 
585 void
587 {
588  Ptr<CobaltQueueDisc> q3 = queue->GetQueueDiscClass (3)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
589 
590  // Trace DropNext after the first dequeue as m_dropNext value is set after the first dequeue
591  if (q3->GetNPackets () == 19)
592  {
594  }
595 
596  for (uint32_t i = 0; i < nPkt; i++)
597  {
598  Ptr<QueueDiscItem> item = queue->Dequeue ();
599  }
600 }
601 
602 void
604 {
605  for (uint32_t i = 0; i < nPkt; i++)
606  {
607  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &FqCobaltQueueDiscEcnMarking::Dequeue, this, queue, 1);
608  }
609 }
610 
611 void
612 FqCobaltQueueDiscEcnMarking::DropNextTracer (int64_t oldVal, int64_t newVal)
613 {
614  NS_UNUSED (oldVal);
615  NS_UNUSED (newVal);
616  m_dropNextCount++;
617 }
618 
619 void
621 {
622  // Test is divided into 3 sub test cases:
623  // 1) CeThreshold disabled
624  // 2) CeThreshold enabled
625  // 3) Same as 2 but with higher queue delay
626 
627  // Test case 1, CeThreshold disabled
628  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
629  "Perturbation", UintegerValue (0), "BlueThreshold", TimeValue (Time::Max ()));
630 
631  queueDisc->SetQuantum (1514);
632  queueDisc->Initialize ();
633  Ipv4Header hdr;
634  hdr.SetPayloadSize (100);
635  hdr.SetSource (Ipv4Address ("10.10.1.1"));
636  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
637  hdr.SetProtocol (7);
638  hdr.SetEcn (Ipv4Header::ECN_ECT0);
639 
640  // Add 20 ECT0 (ECN capable) packets from the first flow
641  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 20, 1);
642 
643  // Add 20 ECT0 (ECN capable) packets from second flow
644  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
645  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 40, 2);
646 
647  // Add 20 ECT0 (ECN capable) packets from third flow
648  hdr.SetDestination (Ipv4Address ("10.10.1.20"));
649  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 60, 3);
650 
651  // Add 20 NotECT packets from fourth flow
652  hdr.SetDestination (Ipv4Address ("10.10.1.30"));
653  hdr.SetEcn (Ipv4Header::ECN_NotECT);
654  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 80, 4);
655 
656  // Add 20 NotECT packets from fifth flow
657  hdr.SetDestination (Ipv4Address ("10.10.1.40"));
658  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 100, 5);
659 
660  //Dequeue 60 packets with delay 110ms to induce packet drops and keep some remaining packets in each queue
661  DequeueWithDelay (queueDisc, 0.11, 60);
662  Simulator::Run ();
663  Simulator::Stop (Seconds (8.0));
664  Ptr<CobaltQueueDisc> q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
665  Ptr<CobaltQueueDisc> q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
666  Ptr<CobaltQueueDisc> q2 = queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
667  Ptr<CobaltQueueDisc> q3 = queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
668  Ptr<CobaltQueueDisc> q4 = queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
669 
670  // As packets in flow queues are ECN capable
671  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 19, "There should be 19 marked packets."
672  "As there is no CoDel minBytes parameter so all the packets apart from the first one gets marked. As q3 and q4 have"
673  "NotEct packets and the queue delay is much higher than 5ms so the queue gets empty pretty quickly so more"
674  "packets from q0 can be dequeued.");
675  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
676  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 16, "There should be 16 marked packets"
677  "As there is no CoDel minBytes parameter so all the packets apart from the first one until no more packets are dequeued"
678  "are marked.");
679  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
680  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 12, "There should be 12 marked packets"
681  "Each packet size is 120 bytes and the quantum is 1500 bytes so in the first turn (1514/120 = 12.61) 13 packets are"
682  "dequeued and apart from the first one, all the packets are marked.");
683  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
684 
685  // As packets in flow queues are not ECN capable
686  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), m_dropNextCount, "The number of drops should"
687  "be equal to the number of times m_dropNext is updated");
688  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 0, "There should not be any marked packets");
689  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), m_dropNextCount, "The number of drops should"
690  "be equal to the number of times m_dropNext is updated");
691  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 0, "There should not be any marked packets");
692 
693  Simulator::Destroy ();
694 
695  // Test case 2, CeThreshold set to 2ms
696  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
697  "CeThreshold", TimeValue (MilliSeconds (2)));
698  queueDisc->SetQuantum (1514);
699  queueDisc->Initialize ();
700 
701  // Add 20 ECT0 (ECN capable) packets from first flow
702  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
703  hdr.SetEcn (Ipv4Header::ECN_ECT0);
704  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 20, 1);
705 
706  // Add 20 ECT0 (ECN capable) packets from second flow
707  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
708  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 40, 2);
709 
710  // Add 20 ECT0 (ECN capable) packets from third flow
711  hdr.SetDestination (Ipv4Address ("10.10.1.20"));
712  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 60, 3);
713 
714  // Add 20 NotECT packets from fourth flow
715  hdr.SetDestination (Ipv4Address ("10.10.1.30"));
716  hdr.SetEcn (Ipv4Header::ECN_NotECT);
717  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 80, 4);
718 
719  // Add 20 NotECT packets from fifth flow
720  hdr.SetDestination (Ipv4Address ("10.10.1.40"));
721  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 100, 5);
722 
723  //Dequeue 60 packets with delay 0.1ms to induce packet drops and keep some remaining packets in each queue
724  DequeueWithDelay (queueDisc, 0.0001, 60);
725  Simulator::Run ();
726  Simulator::Stop (Seconds (8.0));
727  q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
728  q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
729  q2 = queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
730  q3 = queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
731  q4 = queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
732 
733  // As packets in flow queues are ECN capable
734  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
735  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets"
736  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued. sojourn time of 13th packet is 1.3ms which is"
737  "less than CE threshold");
738  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
739  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 6, "There should be 6 marked packets"
740  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued. sojourn time of 8th packet is 2.1ms which is greater"
741  "than CE threshold and subsequent packet also have sojourn time more 8th packet hence remaining packet are marked.");
742  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
743  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 13, "There should be 13 marked packets"
744  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued and all of them have sojourn time more than CE threshold");
745 
746  // As packets in flow queues are not ECN capable
747  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets");
748  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
749  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets");
750  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 1, "There should 1 dropped packet. As the queue"
751  "delay for the first dequeue is greater than the target (5ms), Cobalt overloads the m_dropNext field as an activity timeout"
752  "and dropNext is to set to the current Time value so on the next dequeue a packet is dropped.");
753 
754  Simulator::Destroy ();
755 
756  // Test case 3, CeThreshold set to 2ms with higher queue delay. This test is mainly to check that the packets are not getting marked twice.
757  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
758  "CeThreshold", TimeValue (MilliSeconds (2)), "BlueThreshold", TimeValue (Time::Max()));
759  queueDisc->SetQuantum (1514);
760  queueDisc->Initialize ();
761 
762  // Add 20 ECT0 (ECN capable) packets from first flow
763  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
764  hdr.SetEcn (Ipv4Header::ECN_ECT0);
765  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 20, 1);
766 
767  // Add 20 ECT0 (ECN capable) packets from second flow
768  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
769  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 40, 2);
770 
771  // Add 20 ECT0 (ECN capable) packets from third flow
772  hdr.SetDestination (Ipv4Address ("10.10.1.20"));
773  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 60, 3);
774 
775  // Add 20 NotECT packets from fourth flow
776  hdr.SetDestination (Ipv4Address ("10.10.1.30"));
777  hdr.SetEcn (Ipv4Header::ECN_NotECT);
778  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 80, 4);
779 
780  // Add 20 NotECT packets from fifth flow
781  hdr.SetDestination (Ipv4Address ("10.10.1.40"));
782  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 100, 5);
783 
784  // Reset m_dropNextCount value;
785  m_dropNextCount = 0;
786 
787  //Dequeue 60 packets with delay 110ms to induce packet drops and keep some remaining packets in each queue
788  DequeueWithDelay (queueDisc, 0.110, 60);
789  Simulator::Run ();
790  Simulator::Stop (Seconds (8.0));
791  q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
792  q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
793  q2 = queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
794  q3 = queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
795  q4 = queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
796 
797  // As packets in flow queues are ECN capable
798  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
799  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
800  q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 20 - q0->GetNPackets (), "Number of CE threshold"
801  " exceeded marks plus Number of Target exceeded marks should be equal to total number of packets dequeued");
802  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
803  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
804  q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 20 - q1->GetNPackets (), "Number of CE threshold"
805  " exceeded marks plus Number of Target exceeded marks should be equal to total number of packets dequeued");
806  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
807  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
808  q2->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 20 - q2->GetNPackets (), "Number of CE threshold"
809  " exceeded marks plus Number of Target exceeded marks should be equal to total number of packets dequeued");
810 
811  // As packets in flow queues are not ECN capable
812  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets");
813  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), m_dropNextCount, "The number of drops should"
814  "be equal to the number of times m_dropNext is updated");
815  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets");
816  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), m_dropNextCount, "The number of drops should"
817  "be equal to the number of times m_dropNext is updated");
818 
819  Simulator::Destroy ();
820 }
821 
822 /*
823  * This class tests linear probing, collision response, and set
824  * creation capability of set associative hashing in FqCodel.
825  * We modified DoClassify () and CheckProtocol () so that we could control
826  * the hash returned for each packet. In the beginning, we use flow hashes
827  * ranging from 0 to 7. These must go into different queues in the same set.
828  * The set number for these is obtained using outerhash, which is 0.
829  * When a new packet arrives with flow hash 1024, outerhash = 0 is obtained
830  * and the first set is iteratively searched.
831  * The packet is eventually added to queue 0 since the tags of queues
832  * in the set do not match with the hash of the flow. The tag of queue 0 is
833  * updated as 1024. When a packet with hash 1025 arrives, outerhash = 0
834  * is obtained and the first set is iteratively searched.
835  * Since there is no match, it is added to queue 0 and the tag of queue 0 is
836  * updated to 1025.
837  *
838  * The variable outerhash stores the nearest multiple of 8 that is lesser than
839  * the hash. When a flow hash of 20 arrives, the value of outerhash
840  * is 16. Since m_flowIndices[16] wasn’t previously allotted, a new flow
841  * is created, and the tag corresponding to this queue is set to 20.
842 */
843 
845 {
846 public:
849 private:
850  virtual void DoRun (void);
851  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr);
852 };
853 
855  : TestCase ("Test credits and flows status")
856 {
857 }
858 
860 {
861 }
862 
863 void
865 {
866  Ptr<Packet> p = Create<Packet> (100);
867  Address dest;
868  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
869  queue->Enqueue (item);
870 }
871 
872 void
874 {
875  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("EnableSetAssociativeHash", BooleanValue (true));
876  queueDisc->SetQuantum (90);
877  queueDisc->Initialize ();
878 
879  Ptr<Ipv4FqCobaltTestPacketFilter> filter = CreateObject<Ipv4FqCobaltTestPacketFilter> ();
880  queueDisc->AddPacketFilter (filter);
881 
882  Ipv4Header hdr;
883  hdr.SetPayloadSize (100);
884  hdr.SetSource (Ipv4Address ("10.10.1.1"));
885  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
886  hdr.SetProtocol (7);
887 
888  m_hash = 0;
889  AddPacket (queueDisc, hdr);
890  m_hash = 1;
891  AddPacket (queueDisc, hdr);
892  AddPacket (queueDisc, hdr);
893  m_hash = 2;
894  AddPacket (queueDisc, hdr);
895  m_hash = 3;
896  AddPacket (queueDisc, hdr);
897  m_hash = 4;
898  AddPacket (queueDisc, hdr);
899  AddPacket (queueDisc, hdr);
900  m_hash = 5;
901  AddPacket (queueDisc, hdr);
902  m_hash = 6;
903  AddPacket (queueDisc, hdr);
904  m_hash = 7;
905  AddPacket (queueDisc, hdr);
906  m_hash = 1024;
907  AddPacket (queueDisc, hdr);
908 
909  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 11,
910  "unexpected number of packets in the queue disc");
911  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2,
912  "unexpected number of packets in the first flow queue of set one");
913  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2,
914  "unexpected number of packets in the second flow queue of set one");
915  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1,
916  "unexpected number of packets in the third flow queue of set one");
917  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 1,
918  "unexpected number of packets in the fourth flow queue of set one");
919  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetNPackets (), 2,
920  "unexpected number of packets in the fifth flow queue of set one");
921  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (5)->GetQueueDisc ()->GetNPackets (), 1,
922  "unexpected number of packets in the sixth flow queue of set one");
923  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (6)->GetQueueDisc ()->GetNPackets (), 1,
924  "unexpected number of packets in the seventh flow queue of set one");
925  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (7)->GetQueueDisc ()->GetNPackets (), 1,
926  "unexpected number of packets in the eighth flow queue of set one");
927  m_hash = 1025;
928  AddPacket (queueDisc, hdr);
929  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3,
930  "unexpected number of packets in the first flow of set one");
931  m_hash = 10;
932  AddPacket (queueDisc, hdr);
933  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (8)->GetQueueDisc ()->GetNPackets (), 1,
934  "unexpected number of packets in the first flow of set two");
935  Simulator::Destroy ();
936 }
937 
938 
951 {
952 public:
954  virtual ~FqCobaltQueueDiscL4sMode ();
955 
956 private:
957  virtual void DoRun (void);
958  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr, u_int32_t nPkt);
959  void AddPacketWithDelay (Ptr<FqCobaltQueueDisc> queue,Ipv4Header hdr, double delay, uint32_t nPkt);
960  void Dequeue (Ptr<FqCobaltQueueDisc> queue, uint32_t nPkt);
961  void DequeueWithDelay (Ptr<FqCobaltQueueDisc> queue, double delay, uint32_t nPkt);
962 };
963 
965  : TestCase ("Test L4S mode")
966 {
967 }
968 
970 {
971 }
972 
973 void
975 {
976  Address dest;
977  Ptr<Packet> p = Create<Packet> (100);
978  for (uint32_t i = 0; i < nPkt; i++)
979  {
980  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
981  queue->Enqueue (item);
982  }
983 }
984 
985 void
987 {
988  for (uint32_t i = 0; i < nPkt; i++)
989  {
990  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &FqCobaltQueueDiscL4sMode::AddPacket, this, queue, hdr, 1);
991  }
992 }
993 
994 void
996 {
997  for (uint32_t i = 0; i < nPkt; i++)
998  {
999  Ptr<QueueDiscItem> item = queue->Dequeue ();
1000  }
1001 }
1002 
1003 void
1005 {
1006  for (uint32_t i = 0; i < nPkt; i++)
1007  {
1008  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &FqCobaltQueueDiscL4sMode::Dequeue, this, queue, 1);
1009  }
1010 }
1011 
1012 void
1014 {
1015  // Test is divided into 2 sub test cases:
1016  // 1) Without hash collisions
1017  // 2) With hash collisions
1018 
1019  // Test case 1, Without hash collisions
1020  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
1021  "Perturbation", UintegerValue (0), "UseL4s", BooleanValue (true),
1022  "CeThreshold", TimeValue (MilliSeconds (2)));
1023 
1024  queueDisc->SetQuantum (1514);
1025  queueDisc->Initialize ();
1026  Ipv4Header hdr;
1027  hdr.SetPayloadSize (100);
1028  hdr.SetSource (Ipv4Address ("10.10.1.1"));
1029  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
1030  hdr.SetProtocol (7);
1031  hdr.SetEcn (Ipv4Header::ECN_ECT1);
1032 
1033  // Add 70 ECT1 (ECN capable) packets from the first flow
1034  // Set delay = 0.5ms
1035  double delay = 0.0005;
1036  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
1037 
1038  // Add 70 ECT0 (ECN capable) packets from second flow
1039  hdr.SetEcn (Ipv4Header::ECN_ECT0);
1040  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
1041  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
1042 
1043  //Dequeue 140 packets with delay 1ms
1044  delay = 0.001;
1045  DequeueWithDelay (queueDisc, delay, 140);
1046  Simulator::Run ();
1047  Simulator::Stop (Seconds (8.0));
1048  Ptr<CobaltQueueDisc> q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
1049  Ptr<CobaltQueueDisc> q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
1050 
1051  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 66, "There should be 66 marked packets"
1052  "4th packet is enqueued at 2ms and dequeued at 4ms hence the delay of 2ms which not greater than CE threshold"
1053  "5th packet is enqueued at 2.5ms and dequeued at 5ms hence the delay of 2.5ms and subsequent packet also do have delay"
1054  "greater than CE threshold so all the packets after 4th packet are marked");
1055  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
1056  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 0, "There should not be any marked packets");
1057  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 2, "There should be 2 marked packets. Packets are dequeued"
1058  "from q0 first, which leads to delay greater than 5ms for the first dequeue from q1. Because of inactivity (started with high queue delay)"
1059  "Cobalt keeps drop_next as now and the next packet is marked. With second dequeue count increases to 2, drop_next becomes now plus around"
1060  "70ms which is less than the running time(140), and as the queue delay is persistantly higher than 5ms, second packet is marked.");
1061  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
1062 
1063  Simulator::Destroy ();
1064 
1065  // Test case 2, With hash collisions
1066  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
1067  "Perturbation", UintegerValue (0), "UseL4s", BooleanValue (true),
1068  "CeThreshold", TimeValue (MilliSeconds (2)));
1069 
1070  queueDisc->SetQuantum (1514);
1071  queueDisc->Initialize ();
1072  hdr.SetPayloadSize (100);
1073  hdr.SetSource (Ipv4Address ("10.10.1.1"));
1074  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
1075  hdr.SetProtocol (7);
1076  hdr.SetEcn (Ipv4Header::ECN_ECT1);
1077 
1078  // Add 70 ECT1 (ECN capable) packets from the first flow
1079  // Set delay = 1ms
1080  delay = 0.001;
1081  Simulator::Schedule (Time (Seconds (0.0005)), &FqCobaltQueueDiscL4sMode::AddPacket, this, queueDisc, hdr, 1);
1082  Simulator::Schedule (Time (Seconds (0.0005)), &FqCobaltQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 69);
1083 
1084  // Add 70 ECT0 (ECN capable) packets from first flow
1085  hdr.SetEcn (Ipv4Header::ECN_ECT0);
1086  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
1087 
1088  //Dequeue 140 packets with delay 1ms
1089  DequeueWithDelay (queueDisc, delay, 140);
1090  Simulator::Run ();
1091  Simulator::Stop (Seconds (8.0));
1092  q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
1093  q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
1094 
1095  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 68, "There should be 68 marked packets"
1096  "2nd ECT1 packet is enqueued at 1.5ms and dequeued at 3ms hence the delay of 1.5ms which not greater than CE threshold"
1097  "3rd packet is enqueued at 2.5ms and dequeued at 5ms hence the delay of 2.5ms and subsequent packet also do have delay"
1098  "greater than CE threshold so all the packets after 2nd packet are marked");
1099  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
1100  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 1, "There should be 1 marked packets");
1101 
1102  Simulator::Destroy ();
1103 
1104 }
1105 
1107 {
1108 public:
1110 };
1111 
1113  : TestSuite ("fq-cobalt-queue-disc", UNIT)
1114 {
1115  AddTestCase (new FqCobaltQueueDiscNoSuitableFilter, TestCase::QUICK);
1117  AddTestCase (new FqCobaltQueueDiscDeficit, TestCase::QUICK);
1118  AddTestCase (new FqCobaltQueueDiscTCPFlowsSeparation, TestCase::QUICK);
1119  AddTestCase (new FqCobaltQueueDiscUDPFlowsSeparation, TestCase::QUICK);
1120  AddTestCase (new FqCobaltQueueDiscEcnMarking, TestCase::QUICK);
1121  AddTestCase (new FqCobaltQueueDiscSetLinearProbing, TestCase::QUICK);
1122  AddTestCase (new FqCobaltQueueDiscL4sMode, TestCase::QUICK);
1123 }
1124 
void SetSource(Ipv4Address source)
Definition: ipv4-header.cc:285
void SetPayloadSize(uint16_t size)
Definition: ipv4-header.cc:56
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
uint32_t GetNPackets(void) const
Get the number of packets stored by the queue disc.
Definition: queue-disc.cc:440
Packet header for IPv6.
Definition: ipv6-header.h:34
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:298
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
AttributeValue implementation for Boolean.
Definition: boolean.h:36
virtual void DoRun(void)
Implementation to actually run this TestCase.
bool Enqueue(Ptr< QueueDiscItem > item)
Pass a packet to store to the queue discipline.
Definition: queue-disc.cc:861
virtual int32_t DoClassify(Ptr< QueueDiscItem > item) const
Classify a packet.
Hold variables of type string.
Definition: string.h:41
A suite of tests to run.
Definition: test.h:1343
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header ipHdr, TcpHeader tcpHdr)
This class tests the TCP flows separation.
void SetDestinationPort(uint16_t port)
Definition: udp-header.cc:55
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
void DequeueWithDelay(Ptr< FqCobaltQueueDisc > queue, double delay, uint32_t nPkt)
#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:283
void SetSourcePort(uint16_t port)
Definition: udp-header.cc:60
#define NS_UNUSED(x)
Mark a local variable as unused.
Definition: unused.h:36
This class tests ECN marking The test is divided into 3 sub test cases.
void Dequeue(Ptr< FqCobaltQueueDisc > queue, uint32_t nPkt)
void SetQuantum(uint32_t quantum)
Set the quantum value.
void SetProtocol(uint8_t num)
Definition: ipv4-header.cc:278
encapsulates test code
Definition: test.h:1153
This class tests packets for which there is no suitable filter.
static FqCobaltQueueDiscTestSuite fqCobaltQueueDiscTestSuite
This class tests the IP flows separation and the packet limit.
a polymophic address class
Definition: address.h:90
virtual void DoRun(void)
Implementation to actually run this TestCase.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr, u_int32_t nPkt)
Packet header for IPv4.
Definition: ipv4-header.h:33
AttributeValue implementation for Time.
Definition: nstime.h:1353
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
Hold an unsigned integer type.
Definition: uinteger.h:44
uint32_t GetNDroppedPackets(std::string reason) const
Get the number of packets dropped for the given reason.
Definition: queue-disc.cc:110
#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:166
Simple test packet filter able to classify IPv4 packets.
virtual void DoRun(void)
Implementation to actually run this TestCase.
void Dequeue(Ptr< FqCobaltQueueDisc > queue, uint32_t nPkt)
#define Max(a, b)
Cobalt packet queue disc.
const Stats & GetStats(void)
Retrieve all the collected statistics.
Definition: queue-disc.cc:421
Ptr< QueueDiscClass > GetQueueDiscClass(std::size_t i) const
Get the i-th queue disc class.
Definition: queue-disc.cc:662
This class tests the deficit per flow.
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition: tcp-header.cc:95
Ptr< QueueDiscItem > Dequeue(void)
Extract from the queue disc the packet that has been dequeued by calling Peek, if any...
Definition: queue-disc.cc:896
virtual void DoRun(void)
Implementation to actually run this TestCase.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:293
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::size_t GetNQueueDiscClasses(void) const
Get the number of queue disc classes.
Definition: queue-disc.cc:669
Header for the Transmission Control Protocol.
Definition: tcp-header.h:44
void SetSourcePort(uint16_t port)
Set the source port.
Definition: tcp-header.cc:89
uint32_t GetNMarkedPackets(std::string reason) const
Get the number of packets marked for the given reason.
Definition: queue-disc.cc:152
Packet header for UDP packets.
Definition: udp-header.h:39
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr)
virtual void DoRun(void)
Implementation to actually run this TestCase.
void DropNextTracer(int64_t oldVal, int64_t newVal)
virtual bool CheckProtocol(Ptr< QueueDiscItem > item) const
Checks if the filter is able to classify a kind of items.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:41
void DequeueWithDelay(Ptr< FqCobaltQueueDisc > queue, double delay, uint32_t nPkt)
uint32_t GetQuantum(void) const
Get the quantum value.
void SetEcn(EcnType ecn)
Set ECN Field.
Definition: ipv4-header.cc:97
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header ipHdr, UdpHeader udpHdr)
Ipv4PacketFilter is the abstract base class for filters defined for IPv4 packets. ...
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1289
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr, u_int32_t nPkt, u_int32_t nPktEnqueued, u_int32_t nQueueFlows)
void AddPacketFilter(Ptr< PacketFilter > filter)
Add a packet filter to the tail of the list of filters used to classify packets.
Definition: queue-disc.cc:614
static TypeId GetTypeId(void)
Get the type ID.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr)
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr)
uint32_t m_dropNextCount
count the number of times m_dropNext is recalculated
void AddPacketWithDelay(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr, double delay, uint32_t nPkt)
a unique identifier for an interface.
Definition: type-id.h:58
virtual void DoRun(void)
Implementation to actually run this TestCase.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
Inactive Period or unslotted CSMA-CA.
Definition: lr-wpan-mac.h:93
This class tests the UDP flows separation.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1642
void Initialize(void)
Invoke DoInitialize on all Objects aggregated to this one.
Definition: object.cc:183
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual void DoRun(void)
Implementation to actually run this TestCase.