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 
43 static int32_t g_hash;
44 
51 public:
56  static TypeId GetTypeId (void);
57 
59  virtual ~Ipv4FqCobaltTestPacketFilter ();
60 
61 private:
67  virtual int32_t DoClassify (Ptr<QueueDiscItem> item) const;
68 
74  virtual bool CheckProtocol (Ptr<QueueDiscItem> item) const;
75 };
76 
77 TypeId
79 {
80  static TypeId tid = TypeId ("ns3::Ipv4FqCobaltTestPacketFilter")
82  .SetGroupName ("Internet")
83  .AddConstructor<Ipv4FqCobaltTestPacketFilter> ()
84  ;
85  return tid;
86 }
87 
89 {
90 }
91 
93 {
94 }
95 
96 int32_t
98 {
99  return g_hash;
100 }
101 
102 bool
104 {
105  return true;
106 }
107 
114 {
115 public:
118 
119 private:
120  virtual void DoRun (void);
121 };
122 
124  : TestCase ("Test packets that are not classified by any filter")
125 {
126 }
127 
129 {
130 }
131 
132 void
134 {
135  // Packets that cannot be classified by the available filters should be dropped
136  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("4p"));
137  Ptr<Ipv4FqCobaltTestPacketFilter> filter = CreateObject<Ipv4FqCobaltTestPacketFilter> ();
138  queueDisc->AddPacketFilter (filter);
139 
140  g_hash = -1;
141  queueDisc->SetQuantum (1500);
142  queueDisc->Initialize ();
143 
144  Ptr<Packet> p;
145  p = Create<Packet> ();
147  Ipv6Header ipv6Header;
148  Address dest;
149  item = Create<Ipv6QueueDiscItem> (p, dest, 0, ipv6Header);
150  queueDisc->Enqueue (item);
151  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetNQueueDiscClasses (), 0, "no flow queue should have been created");
152 
153  p = Create<Packet> (reinterpret_cast<const uint8_t*> ("hello, world"), 12);
154  item = Create<Ipv6QueueDiscItem> (p, dest, 0, ipv6Header);
155  queueDisc->Enqueue (item);
156  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetNQueueDiscClasses (), 0, "no flow queue should have been created");
157 
158  Simulator::Destroy ();
159 }
160 
167 {
168 public:
171 
172 private:
173  virtual void DoRun (void);
179  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr);
180 };
181 
183  : TestCase ("Test IP flows separation and packet limit")
184 {
185 }
186 
188 {
189 }
190 
191 void
193 {
194  Ptr<Packet> p = Create<Packet> (100);
195  Address dest;
196  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
197  queue->Enqueue (item);
198 }
199 
200 void
202 {
203  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("4p"));
204 
205  queueDisc->SetQuantum (1500);
206  queueDisc->Initialize ();
207 
208  Ipv4Header hdr;
209  hdr.SetPayloadSize (100);
210  hdr.SetSource (Ipv4Address ("10.10.1.1"));
211  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
212  hdr.SetProtocol (7);
213 
214  // Add three packets from the first flow
215  AddPacket (queueDisc, hdr);
216  AddPacket (queueDisc, hdr);
217  AddPacket (queueDisc, hdr);
218  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
219  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the flow queue");
220 
221  // Add two packets from the second flow
222  hdr.SetDestination (Ipv4Address ("10.10.1.7"));
223  // Add the first packet
224  AddPacket (queueDisc, hdr);
225  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
226  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the flow queue");
227  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the flow queue");
228  // Add the second packet that causes two packets to be dropped from the fat flow (max backlog = 300, threshold = 150)
229  AddPacket (queueDisc, hdr);
230  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
231  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the flow queue");
232  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the flow queue");
233 
234  Simulator::Destroy ();
235 }
236 
243 {
244 public:
246  virtual ~FqCobaltQueueDiscDeficit ();
247 
248 private:
249  virtual void DoRun (void);
255  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr);
256 };
257 
259  : TestCase ("Test credits and flows status")
260 {
261 }
262 
264 {
265 }
266 
267 void
269 {
270  Ptr<Packet> p = Create<Packet> (100);
271  Address dest;
272  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
273  queue->Enqueue (item);
274 }
275 
276 void
278 {
279  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ();
280 
281  queueDisc->SetQuantum (90);
282  queueDisc->Initialize ();
283 
284  Ipv4Header hdr;
285  hdr.SetPayloadSize (100);
286  hdr.SetSource (Ipv4Address ("10.10.1.1"));
287  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
288  hdr.SetProtocol (7);
289 
290  // Add a packet from the first flow
291  AddPacket (queueDisc, hdr);
292  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 1, "unexpected number of packets in the queue disc");
293  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
294  Ptr<FqCobaltFlow> flow1 = StaticCast<FqCobaltFlow> (queueDisc->GetQueueDiscClass (0));
295  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), static_cast<int32_t> (queueDisc->GetQuantum ()), "the deficit of the first flow must equal the quantum");
296  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::NEW_FLOW, "the first flow must be in the list of new queues");
297  // Dequeue a packet
298  queueDisc->Dequeue ();
299  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 0, "unexpected number of packets in the queue disc");
300  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the first flow queue");
301  // the deficit for the first flow becomes 90 - (100+20) = -30
302  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -30, "unexpected deficit for the first flow");
303 
304  // Add two packets from the first flow
305  AddPacket (queueDisc, hdr);
306  AddPacket (queueDisc, hdr);
307  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 2, "unexpected number of packets in the queue disc");
308  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
309  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::NEW_FLOW, "the first flow must still be in the list of new queues");
310 
311  // Add two packets from the second flow
312  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
313  AddPacket (queueDisc, hdr);
314  AddPacket (queueDisc, hdr);
315  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
316  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
317  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the second flow queue");
318  Ptr<FqCobaltFlow> flow2 = StaticCast<FqCobaltFlow> (queueDisc->GetQueueDiscClass (1));
319  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), static_cast<int32_t> (queueDisc->GetQuantum ()), "the deficit of the second flow must equal the quantum");
320  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::NEW_FLOW, "the second flow must be in the list of new queues");
321 
322  // Dequeue a packet (from the second flow, as the first flow has a negative deficit)
323  queueDisc->Dequeue ();
324  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
325  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the first flow queue");
326  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
327  // the first flow got a quantum of deficit (-30+90=60) and has been moved to the end of the list of old queues
328  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 60, "unexpected deficit for the first flow");
329  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::OLD_FLOW, "the first flow must be in the list of old queues");
330  // the second flow has a negative deficit (-30) and is still in the list of new queues
331  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), -30, "unexpected deficit for the second flow");
332  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::NEW_FLOW, "the second flow must be in the list of new queues");
333 
334  // Dequeue a packet (from the first flow, as the second flow has a negative deficit)
335  queueDisc->Dequeue ();
336  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 2, "unexpected number of packets in the queue disc");
337  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
338  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
339  // the first flow has a negative deficit (60-(100+20)= -60) and stays in the list of old queues
340  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -60, "unexpected deficit for the first flow");
341  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::OLD_FLOW, "the first flow must be in the list of old queues");
342  // the second flow got a quantum of deficit (-30+90=60) and has been moved to the end of the list of old queues
343  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 60, "unexpected deficit for the second flow");
344  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::OLD_FLOW, "the second flow must be in the list of new queues");
345 
346  // Dequeue a packet (from the second flow, as the first flow has a negative deficit)
347  queueDisc->Dequeue ();
348  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 1, "unexpected number of packets in the queue disc");
349  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the first flow queue");
350  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the second flow queue");
351  // the first flow got a quantum of deficit (-60+90=30) and has been moved to the end of the list of old queues
352  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 30, "unexpected deficit for the first flow");
353  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::OLD_FLOW, "the first flow must be in the list of old queues");
354  // the second flow has a negative deficit (60-(100+20)= -60)
355  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), -60, "unexpected deficit for the second flow");
356  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::OLD_FLOW, "the second flow must be in the list of new queues");
357 
358  // Dequeue a packet (from the first flow, as the second flow has a negative deficit)
359  queueDisc->Dequeue ();
360  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 0, "unexpected number of packets in the queue disc");
361  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the first flow queue");
362  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 0, "unexpected number of packets in the second flow queue");
363  // the first flow has a negative deficit (30-(100+20)= -90)
364  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), -90, "unexpected deficit for the first flow");
365  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::OLD_FLOW, "the first flow must be in the list of old queues");
366  // the second flow got a quantum of deficit (-60+90=30) and has been moved to the end of the list of old queues
367  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 30, "unexpected deficit for the second flow");
368  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::OLD_FLOW, "the second flow must be in the list of new queues");
369 
370  // Dequeue a packet
371  queueDisc->Dequeue ();
372  // the first flow is at the head of the list of old queues but has a negative deficit, thus it gets a quantun
373  // of deficit (-90+90=0) and is moved to the end of the list of old queues. Then, the second flow (which has a
374  // positive deficit) is selected, but the second flow is empty and thus it is set to inactive. The first flow is
375  // reconsidered, but it has a null deficit, hence it gets another quantum of deficit (0+90=90). Then, the first
376  // flow is reconsidered again, now it has a positive deficit and hence it is selected. But, it is empty and
377  // therefore is set to inactive, too.
378  NS_TEST_ASSERT_MSG_EQ (flow1->GetDeficit (), 90, "unexpected deficit for the first flow");
379  NS_TEST_ASSERT_MSG_EQ (flow1->GetStatus (), FqCobaltFlow::INACTIVE, "the first flow must be inactive");
380  NS_TEST_ASSERT_MSG_EQ (flow2->GetDeficit (), 30, "unexpected deficit for the second flow");
381  NS_TEST_ASSERT_MSG_EQ (flow2->GetStatus (), FqCobaltFlow::INACTIVE, "the second flow must be inactive");
382 
383  Simulator::Destroy ();
384 }
385 
392 {
393 public:
396 
397 private:
398  virtual void DoRun (void);
405  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header ipHdr, TcpHeader tcpHdr);
406 };
407 
409  : TestCase ("Test TCP flows separation")
410 {
411 }
412 
414 {
415 }
416 
417 void
419 {
420  Ptr<Packet> p = Create<Packet> (100);
421  p->AddHeader (tcpHdr);
422  Address dest;
423  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, ipHdr);
424  queue->Enqueue (item);
425 }
426 
427 void
429 {
430  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10p"));
431 
432  queueDisc->SetQuantum (1500);
433  queueDisc->Initialize ();
434 
435  Ipv4Header hdr;
436  hdr.SetPayloadSize (100);
437  hdr.SetSource (Ipv4Address ("10.10.1.1"));
438  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
439  hdr.SetProtocol (6);
440 
441  TcpHeader tcpHdr;
442  tcpHdr.SetSourcePort (7);
443  tcpHdr.SetDestinationPort (27);
444 
445  // Add three packets from the first flow
446  AddPacket (queueDisc, hdr, tcpHdr);
447  AddPacket (queueDisc, hdr, tcpHdr);
448  AddPacket (queueDisc, hdr, tcpHdr);
449  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
450  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
451 
452  // Add a packet from the second flow
453  tcpHdr.SetSourcePort (8);
454  AddPacket (queueDisc, hdr, tcpHdr);
455  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
456  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
457  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
458 
459  // Add a packet from the third flow
460  tcpHdr.SetDestinationPort (28);
461  AddPacket (queueDisc, hdr, tcpHdr);
462  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 5, "unexpected number of packets in the queue disc");
463  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
464  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
465  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
466 
467  // Add two packets from the fourth flow
468  tcpHdr.SetSourcePort (7);
469  AddPacket (queueDisc, hdr, tcpHdr);
470  AddPacket (queueDisc, hdr, tcpHdr);
471  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 7, "unexpected number of packets in the queue disc");
472  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
473  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
474  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
475  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the third flow queue");
476 
477  Simulator::Destroy ();
478 }
479 
486 {
487 public:
490 
491 private:
492  virtual void DoRun (void);
499  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header ipHdr, UdpHeader udpHdr);
500 };
501 
503  : TestCase ("Test UDP flows separation")
504 {
505 }
506 
508 {
509 }
510 
511 void
513 {
514  Ptr<Packet> p = Create<Packet> (100);
515  p->AddHeader (udpHdr);
516  Address dest;
517  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, ipHdr);
518  queue->Enqueue (item);
519 }
520 
521 void
523 {
524  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10p"));
525 
526  queueDisc->SetQuantum (1500);
527  queueDisc->Initialize ();
528 
529  Ipv4Header hdr;
530  hdr.SetPayloadSize (100);
531  hdr.SetSource (Ipv4Address ("10.10.1.1"));
532  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
533  hdr.SetProtocol (17);
534 
535  UdpHeader udpHdr;
536  udpHdr.SetSourcePort (7);
537  udpHdr.SetDestinationPort (27);
538 
539  // Add three packets from the first flow
540  AddPacket (queueDisc, hdr, udpHdr);
541  AddPacket (queueDisc, hdr, udpHdr);
542  AddPacket (queueDisc, hdr, udpHdr);
543  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 3, "unexpected number of packets in the queue disc");
544  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
545 
546  // Add a packet from the second flow
547  udpHdr.SetSourcePort (8);
548  AddPacket (queueDisc, hdr, udpHdr);
549  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 4, "unexpected number of packets in the queue disc");
550  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
551  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
552 
553  // Add a packet from the third flow
554  udpHdr.SetDestinationPort (28);
555  AddPacket (queueDisc, hdr, udpHdr);
556  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 5, "unexpected number of packets in the queue disc");
557  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
558  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
559  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
560 
561  // Add two packets from the fourth flow
562  udpHdr.SetSourcePort (7);
563  AddPacket (queueDisc, hdr, udpHdr);
564  AddPacket (queueDisc, hdr, udpHdr);
565  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 7, "unexpected number of packets in the queue disc");
566  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3, "unexpected number of packets in the first flow queue");
567  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the second flow queue");
568  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1, "unexpected number of packets in the third flow queue");
569  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 2, "unexpected number of packets in the third flow queue");
570 
571  Simulator::Destroy ();
572 }
573 
594 {
595 public:
597  virtual ~FqCobaltQueueDiscEcnMarking ();
598 
599 private:
600  virtual void DoRun (void);
609  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr, uint32_t nPkt, uint32_t nPktEnqueued, uint32_t nQueueFlows);
615  void Dequeue (Ptr<FqCobaltQueueDisc> queue, uint32_t nPkt);
622  void DequeueWithDelay (Ptr<FqCobaltQueueDisc> queue, double delay, uint32_t nPkt);
628  void DropNextTracer (int64_t oldVal, int64_t newVal);
629  uint32_t m_dropNextCount;
630 };
631 
633  : TestCase ("Test ECN marking")
634 {
635  m_dropNextCount = 0;
636 }
637 
639 {
640 }
641 
642 void
643 FqCobaltQueueDiscEcnMarking::AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr, uint32_t nPkt, uint32_t nPktEnqueued, uint32_t nQueueFlows)
644 {
645  Address dest;
646  Ptr<Packet> p = Create<Packet> (100);
647  for (uint32_t i = 0; i < nPkt; i++)
648  {
649  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
650  queue->Enqueue (item);
651  }
652  NS_TEST_EXPECT_MSG_EQ (queue->GetNQueueDiscClasses (), nQueueFlows, "unexpected number of flow queues");
653  NS_TEST_EXPECT_MSG_EQ (queue->GetNPackets (), nPktEnqueued, "unexpected number of enqueued packets");
654 }
655 
656 void
658 {
659  Ptr<CobaltQueueDisc> q3 = queue->GetQueueDiscClass (3)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
660 
661  // Trace DropNext after the first dequeue as m_dropNext value is set after the first dequeue
662  if (q3->GetNPackets () == 19)
663  {
664  q3->TraceConnectWithoutContext ("DropNext", MakeCallback (&FqCobaltQueueDiscEcnMarking::DropNextTracer, this));
665  }
666 
667  for (uint32_t i = 0; i < nPkt; i++)
668  {
669  Ptr<QueueDiscItem> item = queue->Dequeue ();
670  }
671 }
672 
673 void
675 {
676  for (uint32_t i = 0; i < nPkt; i++)
677  {
678  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &FqCobaltQueueDiscEcnMarking::Dequeue, this, queue, 1);
679  }
680 }
681 
682 void
683 FqCobaltQueueDiscEcnMarking::DropNextTracer ([[maybe_unused]] int64_t oldVal, [[maybe_unused]] int64_t newVal)
684 {
685  m_dropNextCount++;
686 }
687 
688 void
690 {
691  // Test is divided into 3 sub test cases:
692  // 1) CeThreshold disabled
693  // 2) CeThreshold enabled
694  // 3) Same as 2 but with higher queue delay
695 
696  // Test case 1, CeThreshold disabled
697  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
698  "Perturbation", UintegerValue (0), "BlueThreshold", TimeValue (Time::Max ()));
699 
700  queueDisc->SetQuantum (1514);
701  queueDisc->Initialize ();
702  Ipv4Header hdr;
703  hdr.SetPayloadSize (100);
704  hdr.SetSource (Ipv4Address ("10.10.1.1"));
705  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
706  hdr.SetProtocol (7);
707  hdr.SetEcn (Ipv4Header::ECN_ECT0);
708 
709  // Add 20 ECT0 (ECN capable) packets from the first flow
710  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 20, 1);
711 
712  // Add 20 ECT0 (ECN capable) packets from second flow
713  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
714  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 40, 2);
715 
716  // Add 20 ECT0 (ECN capable) packets from third flow
717  hdr.SetDestination (Ipv4Address ("10.10.1.20"));
718  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 60, 3);
719 
720  // Add 20 NotECT packets from fourth flow
721  hdr.SetDestination (Ipv4Address ("10.10.1.30"));
722  hdr.SetEcn (Ipv4Header::ECN_NotECT);
723  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 80, 4);
724 
725  // Add 20 NotECT packets from fifth flow
726  hdr.SetDestination (Ipv4Address ("10.10.1.40"));
727  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 100, 5);
728 
729  //Dequeue 60 packets with delay 110ms to induce packet drops and keep some remaining packets in each queue
730  DequeueWithDelay (queueDisc, 0.11, 60);
731  Simulator::Run ();
732  Simulator::Stop (Seconds (8.0));
733  Ptr<CobaltQueueDisc> q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
734  Ptr<CobaltQueueDisc> q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
735  Ptr<CobaltQueueDisc> q2 = queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
736  Ptr<CobaltQueueDisc> q3 = queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
737  Ptr<CobaltQueueDisc> q4 = queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
738 
739  // As packets in flow queues are ECN capable
740  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 19, "There should be 19 marked packets."
741  "As there is no CoDel minBytes parameter so all the packets apart from the first one gets marked. As q3 and q4 have"
742  "NotEct packets and the queue delay is much higher than 5ms so the queue gets empty pretty quickly so more"
743  "packets from q0 can be dequeued.");
744  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
745  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 16, "There should be 16 marked packets"
746  "As there is no CoDel minBytes parameter so all the packets apart from the first one until no more packets are dequeued"
747  "are marked.");
748  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
749  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 12, "There should be 12 marked packets"
750  "Each packet size is 120 bytes and the quantum is 1500 bytes so in the first turn (1514/120 = 12.61) 13 packets are"
751  "dequeued and apart from the first one, all the packets are marked.");
752  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
753 
754  // As packets in flow queues are not ECN capable
755  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), m_dropNextCount, "The number of drops should"
756  "be equal to the number of times m_dropNext is updated");
757  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 0, "There should not be any marked packets");
758  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), m_dropNextCount, "The number of drops should"
759  "be equal to the number of times m_dropNext is updated");
760  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 0, "There should not be any marked packets");
761 
762  Simulator::Destroy ();
763 
764  // Test case 2, CeThreshold set to 2ms
765  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
766  "CeThreshold", TimeValue (MilliSeconds (2)));
767  queueDisc->SetQuantum (1514);
768  queueDisc->Initialize ();
769 
770  // Add 20 ECT0 (ECN capable) packets from first flow
771  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
772  hdr.SetEcn (Ipv4Header::ECN_ECT0);
773  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 20, 1);
774 
775  // Add 20 ECT0 (ECN capable) packets from second flow
776  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
777  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 40, 2);
778 
779  // Add 20 ECT0 (ECN capable) packets from third flow
780  hdr.SetDestination (Ipv4Address ("10.10.1.20"));
781  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 60, 3);
782 
783  // Add 20 NotECT packets from fourth flow
784  hdr.SetDestination (Ipv4Address ("10.10.1.30"));
785  hdr.SetEcn (Ipv4Header::ECN_NotECT);
786  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 80, 4);
787 
788  // Add 20 NotECT packets from fifth flow
789  hdr.SetDestination (Ipv4Address ("10.10.1.40"));
790  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 100, 5);
791 
792  //Dequeue 60 packets with delay 0.1ms to induce packet drops and keep some remaining packets in each queue
793  DequeueWithDelay (queueDisc, 0.0001, 60);
794  Simulator::Run ();
795  Simulator::Stop (Seconds (8.0));
796  q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
797  q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
798  q2 = queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
799  q3 = queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
800  q4 = queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
801 
802  // As packets in flow queues are ECN capable
803  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
804  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets"
805  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued. sojourn time of 13th packet is 1.3ms which is"
806  "less than CE threshold");
807  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
808  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 6, "There should be 6 marked packets"
809  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued. sojourn time of 8th packet is 2.1ms which is greater"
810  "than CE threshold and subsequent packet also have sojourn time more 8th packet hence remaining packet are marked.");
811  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
812  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 13, "There should be 13 marked packets"
813  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued and all of them have sojourn time more than CE threshold");
814 
815  // As packets in flow queues are not ECN capable
816  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets");
817  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
818  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets");
819  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 1, "There should 1 dropped packet. As the queue"
820  "delay for the first dequeue is greater than the target (5ms), Cobalt overloads the m_dropNext field as an activity timeout"
821  "and dropNext is to set to the current Time value so on the next dequeue a packet is dropped.");
822 
823  Simulator::Destroy ();
824 
825  // 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.
826  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
827  "CeThreshold", TimeValue (MilliSeconds (2)), "BlueThreshold", TimeValue (Time::Max()));
828  queueDisc->SetQuantum (1514);
829  queueDisc->Initialize ();
830 
831  // Add 20 ECT0 (ECN capable) packets from first flow
832  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
833  hdr.SetEcn (Ipv4Header::ECN_ECT0);
834  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 20, 1);
835 
836  // Add 20 ECT0 (ECN capable) packets from second flow
837  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
838  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 40, 2);
839 
840  // Add 20 ECT0 (ECN capable) packets from third flow
841  hdr.SetDestination (Ipv4Address ("10.10.1.20"));
842  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 60, 3);
843 
844  // Add 20 NotECT packets from fourth flow
845  hdr.SetDestination (Ipv4Address ("10.10.1.30"));
846  hdr.SetEcn (Ipv4Header::ECN_NotECT);
847  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 80, 4);
848 
849  // Add 20 NotECT packets from fifth flow
850  hdr.SetDestination (Ipv4Address ("10.10.1.40"));
851  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscEcnMarking::AddPacket, this, queueDisc, hdr, 20, 100, 5);
852 
853  // Reset m_dropNextCount value;
854  m_dropNextCount = 0;
855 
856  //Dequeue 60 packets with delay 110ms to induce packet drops and keep some remaining packets in each queue
857  DequeueWithDelay (queueDisc, 0.110, 60);
858  Simulator::Run ();
859  Simulator::Stop (Seconds (8.0));
860  q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
861  q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
862  q2 = queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
863  q3 = queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
864  q4 = queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
865 
866  // As packets in flow queues are ECN capable
867  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
868  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
869  q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 20 - q0->GetNPackets (), "Number of CE threshold"
870  " exceeded marks plus Number of Target exceeded marks should be equal to total number of packets dequeued");
871  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
872  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
873  q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 20 - q1->GetNPackets (), "Number of CE threshold"
874  " exceeded marks plus Number of Target exceeded marks should be equal to total number of packets dequeued");
875  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
876  NS_TEST_EXPECT_MSG_EQ (q2->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
877  q2->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 20 - q2->GetNPackets (), "Number of CE threshold"
878  " exceeded marks plus Number of Target exceeded marks should be equal to total number of packets dequeued");
879 
880  // As packets in flow queues are not ECN capable
881  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets");
882  NS_TEST_EXPECT_MSG_EQ (q3->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), m_dropNextCount, "The number of drops should"
883  "be equal to the number of times m_dropNext is updated");
884  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 0, "There should not be any marked packets");
885  NS_TEST_EXPECT_MSG_EQ (q4->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), m_dropNextCount, "The number of drops should"
886  "be equal to the number of times m_dropNext is updated");
887 
888  Simulator::Destroy ();
889 }
890 
916 {
917 public:
920 private:
921  virtual void DoRun (void);
927  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr);
928 };
929 
931  : TestCase ("Test credits and flows status")
932 {
933 }
934 
936 {
937 }
938 
939 void
941 {
942  Ptr<Packet> p = Create<Packet> (100);
943  Address dest;
944  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
945  queue->Enqueue (item);
946 }
947 
948 void
950 {
951  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("EnableSetAssociativeHash", BooleanValue (true));
952  queueDisc->SetQuantum (90);
953  queueDisc->Initialize ();
954 
955  Ptr<Ipv4FqCobaltTestPacketFilter> filter = CreateObject<Ipv4FqCobaltTestPacketFilter> ();
956  queueDisc->AddPacketFilter (filter);
957 
958  Ipv4Header hdr;
959  hdr.SetPayloadSize (100);
960  hdr.SetSource (Ipv4Address ("10.10.1.1"));
961  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
962  hdr.SetProtocol (7);
963 
964  g_hash = 0;
965  AddPacket (queueDisc, hdr);
966  g_hash = 1;
967  AddPacket (queueDisc, hdr);
968  AddPacket (queueDisc, hdr);
969  g_hash = 2;
970  AddPacket (queueDisc, hdr);
971  g_hash = 3;
972  AddPacket (queueDisc, hdr);
973  g_hash = 4;
974  AddPacket (queueDisc, hdr);
975  AddPacket (queueDisc, hdr);
976  g_hash = 5;
977  AddPacket (queueDisc, hdr);
978  g_hash = 6;
979  AddPacket (queueDisc, hdr);
980  g_hash = 7;
981  AddPacket (queueDisc, hdr);
982  g_hash = 1024;
983  AddPacket (queueDisc, hdr);
984 
985  NS_TEST_ASSERT_MSG_EQ (queueDisc->QueueDisc::GetNPackets (), 11,
986  "unexpected number of packets in the queue disc");
987  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 2,
988  "unexpected number of packets in the first flow queue of set one");
989  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetNPackets (), 2,
990  "unexpected number of packets in the second flow queue of set one");
991  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (2)->GetQueueDisc ()->GetNPackets (), 1,
992  "unexpected number of packets in the third flow queue of set one");
993  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (3)->GetQueueDisc ()->GetNPackets (), 1,
994  "unexpected number of packets in the fourth flow queue of set one");
995  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (4)->GetQueueDisc ()->GetNPackets (), 2,
996  "unexpected number of packets in the fifth flow queue of set one");
997  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (5)->GetQueueDisc ()->GetNPackets (), 1,
998  "unexpected number of packets in the sixth flow queue of set one");
999  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (6)->GetQueueDisc ()->GetNPackets (), 1,
1000  "unexpected number of packets in the seventh flow queue of set one");
1001  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (7)->GetQueueDisc ()->GetNPackets (), 1,
1002  "unexpected number of packets in the eighth flow queue of set one");
1003  g_hash = 1025;
1004  AddPacket (queueDisc, hdr);
1005  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetNPackets (), 3,
1006  "unexpected number of packets in the first flow of set one");
1007  g_hash = 10;
1008  AddPacket (queueDisc, hdr);
1009  NS_TEST_ASSERT_MSG_EQ (queueDisc->GetQueueDiscClass (8)->GetQueueDisc ()->GetNPackets (), 1,
1010  "unexpected number of packets in the first flow of set two");
1011  Simulator::Destroy ();
1012 }
1013 
1014 
1032 {
1033 public:
1035  virtual ~FqCobaltQueueDiscL4sMode ();
1036 
1037 private:
1038  virtual void DoRun (void);
1045  void AddPacket (Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr, uint32_t nPkt);
1053  void AddPacketWithDelay (Ptr<FqCobaltQueueDisc> queue,Ipv4Header hdr, double delay, uint32_t nPkt);
1059  void Dequeue (Ptr<FqCobaltQueueDisc> queue, uint32_t nPkt);
1066  void DequeueWithDelay (Ptr<FqCobaltQueueDisc> queue, double delay, uint32_t nPkt);
1067 };
1068 
1070  : TestCase ("Test L4S mode")
1071 {
1072 }
1073 
1075 {
1076 }
1077 
1078 void
1080 {
1081  Address dest;
1082  Ptr<Packet> p = Create<Packet> (100);
1083  for (uint32_t i = 0; i < nPkt; i++)
1084  {
1085  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem> (p, dest, 0, hdr);
1086  queue->Enqueue (item);
1087  }
1088 }
1089 
1090 void
1092 {
1093  for (uint32_t i = 0; i < nPkt; i++)
1094  {
1095  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &FqCobaltQueueDiscL4sMode::AddPacket, this, queue, hdr, 1);
1096  }
1097 }
1098 
1099 void
1101 {
1102  for (uint32_t i = 0; i < nPkt; i++)
1103  {
1104  Ptr<QueueDiscItem> item = queue->Dequeue ();
1105  }
1106 }
1107 
1108 void
1110 {
1111  for (uint32_t i = 0; i < nPkt; i++)
1112  {
1113  Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &FqCobaltQueueDiscL4sMode::Dequeue, this, queue, 1);
1114  }
1115 }
1116 
1117 void
1119 {
1120  // Test is divided into 2 sub test cases:
1121  // 1) Without hash collisions
1122  // 2) With hash collisions
1123 
1124  // Test case 1, Without hash collisions
1125  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
1126  "Perturbation", UintegerValue (0), "UseL4s", BooleanValue (true),
1127  "CeThreshold", TimeValue (MilliSeconds (2)));
1128 
1129  queueDisc->SetQuantum (1514);
1130  queueDisc->Initialize ();
1131  Ipv4Header hdr;
1132  hdr.SetPayloadSize (100);
1133  hdr.SetSource (Ipv4Address ("10.10.1.1"));
1134  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
1135  hdr.SetProtocol (7);
1136  hdr.SetEcn (Ipv4Header::ECN_ECT1);
1137 
1138  // Add 70 ECT1 (ECN capable) packets from the first flow
1139  // Set delay = 0.5ms
1140  double delay = 0.0005;
1141  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
1142 
1143  // Add 70 ECT0 (ECN capable) packets from second flow
1144  hdr.SetEcn (Ipv4Header::ECN_ECT0);
1145  hdr.SetDestination (Ipv4Address ("10.10.1.10"));
1146  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
1147 
1148  //Dequeue 140 packets with delay 1ms
1149  delay = 0.001;
1150  DequeueWithDelay (queueDisc, delay, 140);
1151  Simulator::Run ();
1152  Simulator::Stop (Seconds (8.0));
1153  Ptr<CobaltQueueDisc> q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
1154  Ptr<CobaltQueueDisc> q1 = queueDisc->GetQueueDiscClass (1)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
1155 
1156  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 66, "There should be 66 marked packets"
1157  "4th packet is enqueued at 2ms and dequeued at 4ms hence the delay of 2ms which not greater than CE threshold"
1158  "5th packet is enqueued at 2.5ms and dequeued at 5ms hence the delay of 2.5ms and subsequent packet also do have delay"
1159  "greater than CE threshold so all the packets after 4th packet are marked");
1160  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
1161  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 0, "There should not be any marked packets");
1162  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 2, "There should be 2 marked packets. Packets are dequeued"
1163  "from q0 first, which leads to delay greater than 5ms for the first dequeue from q1. Because of inactivity (started with high queue delay)"
1164  "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"
1165  "70ms which is less than the running time(140), and as the queue delay is persistantly higher than 5ms, second packet is marked.");
1166  NS_TEST_EXPECT_MSG_EQ (q1->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
1167 
1168  Simulator::Destroy ();
1169 
1170  // Test case 2, With hash collisions
1171  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc> ("MaxSize", StringValue ("10240p"), "UseEcn", BooleanValue (true),
1172  "Perturbation", UintegerValue (0), "UseL4s", BooleanValue (true),
1173  "CeThreshold", TimeValue (MilliSeconds (2)));
1174 
1175  queueDisc->SetQuantum (1514);
1176  queueDisc->Initialize ();
1177  hdr.SetPayloadSize (100);
1178  hdr.SetSource (Ipv4Address ("10.10.1.1"));
1179  hdr.SetDestination (Ipv4Address ("10.10.1.2"));
1180  hdr.SetProtocol (7);
1181  hdr.SetEcn (Ipv4Header::ECN_ECT1);
1182 
1183  // Add 70 ECT1 (ECN capable) packets from the first flow
1184  // Set delay = 1ms
1185  delay = 0.001;
1186  Simulator::Schedule (Time (Seconds (0.0005)), &FqCobaltQueueDiscL4sMode::AddPacket, this, queueDisc, hdr, 1);
1187  Simulator::Schedule (Time (Seconds (0.0005)), &FqCobaltQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 69);
1188 
1189  // Add 70 ECT0 (ECN capable) packets from first flow
1190  hdr.SetEcn (Ipv4Header::ECN_ECT0);
1191  Simulator::Schedule (Time (Seconds (0)), &FqCobaltQueueDiscL4sMode::AddPacketWithDelay, this, queueDisc, hdr, delay, 70);
1192 
1193  //Dequeue 140 packets with delay 1ms
1194  DequeueWithDelay (queueDisc, delay, 140);
1195  Simulator::Run ();
1196  Simulator::Stop (Seconds (8.0));
1197  q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
1198  q0 = queueDisc->GetQueueDiscClass (0)->GetQueueDisc ()->GetObject <CobaltQueueDisc> ();
1199 
1200  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK), 68, "There should be 68 marked packets"
1201  "2nd ECT1 packet is enqueued at 1.5ms and dequeued at 3ms hence the delay of 1.5ms which not greater than CE threshold"
1202  "3rd packet is enqueued at 2.5ms and dequeued at 5ms hence the delay of 2.5ms and subsequent packet also do have delay"
1203  "greater than CE threshold so all the packets after 2nd packet are marked");
1204  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNDroppedPackets (CobaltQueueDisc::TARGET_EXCEEDED_DROP), 0, "There should not be any dropped packets");
1205  NS_TEST_EXPECT_MSG_EQ (q0->GetStats ().GetNMarkedPackets (CobaltQueueDisc::FORCED_MARK), 1, "There should be 1 marked packets");
1206 
1207  Simulator::Destroy ();
1208 
1209 }
1210 
1217 {
1218 public:
1220 };
1221 
1223  : TestSuite ("fq-cobalt-queue-disc", UNIT)
1224 {
1225  AddTestCase (new FqCobaltQueueDiscNoSuitableFilter, TestCase::QUICK);
1227  AddTestCase (new FqCobaltQueueDiscDeficit, TestCase::QUICK);
1228  AddTestCase (new FqCobaltQueueDiscTCPFlowsSeparation, TestCase::QUICK);
1229  AddTestCase (new FqCobaltQueueDiscUDPFlowsSeparation, TestCase::QUICK);
1230  AddTestCase (new FqCobaltQueueDiscEcnMarking, TestCase::QUICK);
1231  AddTestCase (new FqCobaltQueueDiscSetLinearProbing, TestCase::QUICK);
1232  AddTestCase (new FqCobaltQueueDiscL4sMode, TestCase::QUICK);
1233 }
1234 
#define Max(a, b)
This class tests the deficit per flow.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr)
Enqueue a packet.
virtual void DoRun(void)
Implementation to actually run this TestCase.
uint32_t m_dropNextCount
count the number of times m_dropNext is recalculated
void DequeueWithDelay(Ptr< FqCobaltQueueDisc > queue, double delay, uint32_t nPkt)
Dequeue the given number of packets at different times.
void Dequeue(Ptr< FqCobaltQueueDisc > queue, uint32_t nPkt)
Dequeue the given number of packets.
void DropNextTracer(int64_t oldVal, int64_t newVal)
Tracer for the DropNext attribute.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr, uint32_t nPkt, uint32_t nPktEnqueued, uint32_t nQueueFlows)
Enqueue the given number of packets.
virtual void DoRun(void)
Implementation to actually run this TestCase.
This class tests the IP flows separation and the packet limit.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr)
Enqueue a packet.
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual void DoRun(void)
Implementation to actually run this TestCase.
void DequeueWithDelay(Ptr< FqCobaltQueueDisc > queue, double delay, uint32_t nPkt)
Dequeue the given number of packets at different times.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr, uint32_t nPkt)
Enqueue the given number of packets.
void Dequeue(Ptr< FqCobaltQueueDisc > queue, uint32_t nPkt)
Dequeue the given number of packets.
void AddPacketWithDelay(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr, double delay, uint32_t nPkt)
Enqueue the given number of packets at different times.
This class tests packets for which there is no suitable filter.
virtual void DoRun(void)
Implementation to actually run this TestCase.
This class tests linear probing, collision response, and set creation capability of set associative h...
virtual void DoRun(void)
Implementation to actually run this TestCase.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr)
Enqueue a packet.
This class tests the TCP flows separation.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header ipHdr, TcpHeader tcpHdr)
Enqueue a packet.
virtual void DoRun(void)
Implementation to actually run this TestCase.
FQ-COBALT queue disc test suite.
This class tests the UDP flows separation.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header ipHdr, UdpHeader udpHdr)
Enqueue a packet.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Simple test packet filter able to classify IPv4 packets.
virtual int32_t DoClassify(Ptr< QueueDiscItem > item) const
Classify a QueueDiscItem.
static TypeId GetTypeId(void)
Get the type ID.
virtual bool CheckProtocol(Ptr< QueueDiscItem > item) const
Check the protocol.
a polymophic address class
Definition: address.h:91
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Cobalt packet queue disc.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:41
Packet header for IPv4.
Definition: ipv4-header.h:34
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:298
void SetPayloadSize(uint16_t size)
Definition: ipv4-header.cc:56
void SetEcn(EcnType ecn)
Set ECN Field.
Definition: ipv4-header.cc:97
void SetProtocol(uint8_t num)
Definition: ipv4-header.cc:278
void SetSource(Ipv4Address source)
Definition: ipv4-header.cc:285
Ipv4PacketFilter is the abstract base class for filters defined for IPv4 packets.
Packet header for IPv6.
Definition: ipv6-header.h:36
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
Hold variables of type string.
Definition: string.h:41
Header for the Transmission Control Protocol.
Definition: tcp-header.h:45
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition: tcp-header.cc:95
void SetSourcePort(uint16_t port)
Set the source port.
Definition: tcp-header.cc:89
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
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
AttributeValue implementation for Time.
Definition: nstime.h:1308
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Packet header for UDP packets.
Definition: udp-header.h:40
void SetSourcePort(uint16_t port)
Definition: udp-header.cc:60
void SetDestinationPort(uint16_t port)
Definition: udp-header.cc:55
Hold an unsigned integer type.
Definition: uinteger.h:44
static FqCobaltQueueDiscTestSuite g_fqCobaltQueueDiscTestSuite
Do not forget to allocate an instance of this TestSuite.
static int32_t g_hash
Variable to assign g_hash to a new packet's flow.
@ INACTIVE
Inactive Period or unslotted CSMA-CA.
Definition: lr-wpan-mac.h:93
#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
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1252
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:1648