A Discrete-Event Network Simulator
API
fq-cobalt-queue-disc-test-suite.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Universita' degli Studi di Napoli Federico II
3  * Copyright (c) 2020 NITK Surathkal (adapted for COBALT)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Authors: Pasquale Imputato <p.imputato@gmail.com>
19  * Stefano Avallone <stefano.avallone@unina.it>
20  * Modified by: Bhaskar Kataria <bhaskar.k7920@gmail.com> (COBALT changes)
21  */
22 
23 #include "ns3/cobalt-queue-disc.h"
24 #include "ns3/fq-cobalt-queue-disc.h"
25 #include "ns3/ipv4-address.h"
26 #include "ns3/ipv4-header.h"
27 #include "ns3/ipv4-packet-filter.h"
28 #include "ns3/ipv4-queue-disc-item.h"
29 #include "ns3/ipv6-header.h"
30 #include "ns3/ipv6-packet-filter.h"
31 #include "ns3/ipv6-queue-disc-item.h"
32 #include "ns3/pointer.h"
33 #include "ns3/simulator.h"
34 #include "ns3/string.h"
35 #include "ns3/tcp-header.h"
36 #include "ns3/test.h"
37 #include "ns3/udp-header.h"
38 
39 using namespace ns3;
40 
42 static int32_t g_hash;
43 
50 {
51  public:
56  static TypeId GetTypeId();
57 
59  ~Ipv4FqCobaltTestPacketFilter() override;
60 
61  private:
67  int32_t DoClassify(Ptr<QueueDiscItem> item) const override;
68 
74  bool CheckProtocol(Ptr<QueueDiscItem> item) const override;
75 };
76 
77 TypeId
79 {
80  static TypeId tid = TypeId("ns3::Ipv4FqCobaltTestPacketFilter")
82  .SetGroupName("Internet")
83  .AddConstructor<Ipv4FqCobaltTestPacketFilter>();
84  return tid;
85 }
86 
88 {
89 }
90 
92 {
93 }
94 
95 int32_t
97 {
98  return g_hash;
99 }
100 
101 bool
103 {
104  return true;
105 }
106 
113 {
114  public:
117 
118  private:
119  void DoRun() override;
120 };
121 
123  : TestCase("Test packets that are not classified by any filter")
124 {
125 }
126 
128 {
129 }
130 
131 void
133 {
134  // Packets that cannot be classified by the available filters should be dropped
135  Ptr<FqCobaltQueueDisc> queueDisc =
136  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(),
152  0,
153  "no flow queue should have been created");
154 
155  p = Create<Packet>(reinterpret_cast<const uint8_t*>("hello, world"), 12);
156  item = Create<Ipv6QueueDiscItem>(p, dest, 0, ipv6Header);
157  queueDisc->Enqueue(item);
158  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetNQueueDiscClasses(),
159  0,
160  "no flow queue should have been created");
161 
162  Simulator::Destroy();
163 }
164 
171 {
172  public:
175 
176  private:
177  void DoRun() override;
184 };
185 
187  : TestCase("Test IP flows separation and packet limit")
188 {
189 }
190 
193 {
194 }
195 
196 void
198  Ipv4Header hdr)
199 {
200  Ptr<Packet> p = Create<Packet>(100);
201  Address dest;
202  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem>(p, dest, 0, hdr);
203  queue->Enqueue(item);
204 }
205 
206 void
208 {
209  Ptr<FqCobaltQueueDisc> queueDisc =
210  CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize", StringValue("4p"));
211 
212  queueDisc->SetQuantum(1500);
213  queueDisc->Initialize();
214 
215  Ipv4Header hdr;
216  hdr.SetPayloadSize(100);
217  hdr.SetSource(Ipv4Address("10.10.1.1"));
218  hdr.SetDestination(Ipv4Address("10.10.1.2"));
219  hdr.SetProtocol(7);
220 
221  // Add three packets from the first flow
222  AddPacket(queueDisc, hdr);
223  AddPacket(queueDisc, hdr);
224  AddPacket(queueDisc, hdr);
225  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
226  3,
227  "unexpected number of packets in the queue disc");
228  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
229  3,
230  "unexpected number of packets in the flow queue");
231 
232  // Add two packets from the second flow
233  hdr.SetDestination(Ipv4Address("10.10.1.7"));
234  // Add the first packet
235  AddPacket(queueDisc, hdr);
236  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
237  4,
238  "unexpected number of packets in the queue disc");
239  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
240  3,
241  "unexpected number of packets in the flow queue");
242  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
243  1,
244  "unexpected number of packets in the flow queue");
245  // Add the second packet that causes two packets to be dropped from the fat flow (max backlog =
246  // 300, threshold = 150)
247  AddPacket(queueDisc, hdr);
248  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
249  3,
250  "unexpected number of packets in the queue disc");
251  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
252  1,
253  "unexpected number of packets in the flow queue");
254  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
255  2,
256  "unexpected number of packets in the flow queue");
257 
258  Simulator::Destroy();
259 }
260 
267 {
268  public:
270  ~FqCobaltQueueDiscDeficit() override;
271 
272  private:
273  void DoRun() override;
280 };
281 
283  : TestCase("Test credits and flows status")
284 {
285 }
286 
288 {
289 }
290 
291 void
293 {
294  Ptr<Packet> p = Create<Packet>(100);
295  Address dest;
296  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem>(p, dest, 0, hdr);
297  queue->Enqueue(item);
298 }
299 
300 void
302 {
303  Ptr<FqCobaltQueueDisc> queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc>();
304 
305  queueDisc->SetQuantum(90);
306  queueDisc->Initialize();
307 
308  Ipv4Header hdr;
309  hdr.SetPayloadSize(100);
310  hdr.SetSource(Ipv4Address("10.10.1.1"));
311  hdr.SetDestination(Ipv4Address("10.10.1.2"));
312  hdr.SetProtocol(7);
313 
314  // Add a packet from the first flow
315  AddPacket(queueDisc, hdr);
316  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
317  1,
318  "unexpected number of packets in the queue disc");
319  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
320  1,
321  "unexpected number of packets in the first flow queue");
322  Ptr<FqCobaltFlow> flow1 = StaticCast<FqCobaltFlow>(queueDisc->GetQueueDiscClass(0));
323  NS_TEST_ASSERT_MSG_EQ(flow1->GetDeficit(),
324  static_cast<int32_t>(queueDisc->GetQuantum()),
325  "the deficit of the first flow must equal the quantum");
326  NS_TEST_ASSERT_MSG_EQ(flow1->GetStatus(),
327  FqCobaltFlow::NEW_FLOW,
328  "the first flow must be in the list of new queues");
329  // Dequeue a packet
330  queueDisc->Dequeue();
331  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
332  0,
333  "unexpected number of packets in the queue disc");
334  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
335  0,
336  "unexpected number of packets in the first flow queue");
337  // the deficit for the first flow becomes 90 - (100+20) = -30
338  NS_TEST_ASSERT_MSG_EQ(flow1->GetDeficit(), -30, "unexpected deficit for the first flow");
339 
340  // Add two packets from the first flow
341  AddPacket(queueDisc, hdr);
342  AddPacket(queueDisc, hdr);
343  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
344  2,
345  "unexpected number of packets in the queue disc");
346  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
347  2,
348  "unexpected number of packets in the first flow queue");
349  NS_TEST_ASSERT_MSG_EQ(flow1->GetStatus(),
350  FqCobaltFlow::NEW_FLOW,
351  "the first flow must still be in the list of new queues");
352 
353  // Add two packets from the second flow
354  hdr.SetDestination(Ipv4Address("10.10.1.10"));
355  AddPacket(queueDisc, hdr);
356  AddPacket(queueDisc, hdr);
357  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
358  4,
359  "unexpected number of packets in the queue disc");
360  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
361  2,
362  "unexpected number of packets in the first flow queue");
363  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
364  2,
365  "unexpected number of packets in the second flow queue");
366  Ptr<FqCobaltFlow> flow2 = StaticCast<FqCobaltFlow>(queueDisc->GetQueueDiscClass(1));
367  NS_TEST_ASSERT_MSG_EQ(flow2->GetDeficit(),
368  static_cast<int32_t>(queueDisc->GetQuantum()),
369  "the deficit of the second flow must equal the quantum");
370  NS_TEST_ASSERT_MSG_EQ(flow2->GetStatus(),
371  FqCobaltFlow::NEW_FLOW,
372  "the second flow must be in the list of new queues");
373 
374  // Dequeue a packet (from the second flow, as the first flow has a negative deficit)
375  queueDisc->Dequeue();
376  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
377  3,
378  "unexpected number of packets in the queue disc");
379  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
380  2,
381  "unexpected number of packets in the first flow queue");
382  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
383  1,
384  "unexpected number of packets in the second flow queue");
385  // the first flow got a quantum of deficit (-30+90=60) and has been moved to the end of the list
386  // of old queues
387  NS_TEST_ASSERT_MSG_EQ(flow1->GetDeficit(), 60, "unexpected deficit for the first flow");
388  NS_TEST_ASSERT_MSG_EQ(flow1->GetStatus(),
389  FqCobaltFlow::OLD_FLOW,
390  "the first flow must be in the list of old queues");
391  // the second flow has a negative deficit (-30) and is still in the list of new queues
392  NS_TEST_ASSERT_MSG_EQ(flow2->GetDeficit(), -30, "unexpected deficit for the second flow");
393  NS_TEST_ASSERT_MSG_EQ(flow2->GetStatus(),
394  FqCobaltFlow::NEW_FLOW,
395  "the second flow must be in the list of new queues");
396 
397  // Dequeue a packet (from the first flow, as the second flow has a negative deficit)
398  queueDisc->Dequeue();
399  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
400  2,
401  "unexpected number of packets in the queue disc");
402  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
403  1,
404  "unexpected number of packets in the first flow queue");
405  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
406  1,
407  "unexpected number of packets in the second flow queue");
408  // the first flow has a negative deficit (60-(100+20)= -60) and stays in the list of old queues
409  NS_TEST_ASSERT_MSG_EQ(flow1->GetDeficit(), -60, "unexpected deficit for the first flow");
410  NS_TEST_ASSERT_MSG_EQ(flow1->GetStatus(),
411  FqCobaltFlow::OLD_FLOW,
412  "the first flow must be in the list of old queues");
413  // the second flow got a quantum of deficit (-30+90=60) and has been moved to the end of the
414  // list of old queues
415  NS_TEST_ASSERT_MSG_EQ(flow2->GetDeficit(), 60, "unexpected deficit for the second flow");
416  NS_TEST_ASSERT_MSG_EQ(flow2->GetStatus(),
417  FqCobaltFlow::OLD_FLOW,
418  "the second flow must be in the list of new queues");
419 
420  // Dequeue a packet (from the second flow, as the first flow has a negative deficit)
421  queueDisc->Dequeue();
422  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
423  1,
424  "unexpected number of packets in the queue disc");
425  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
426  1,
427  "unexpected number of packets in the first flow queue");
428  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
429  0,
430  "unexpected number of packets in the second flow queue");
431  // the first flow got a quantum of deficit (-60+90=30) and has been moved to the end of the list
432  // of old queues
433  NS_TEST_ASSERT_MSG_EQ(flow1->GetDeficit(), 30, "unexpected deficit for the first flow");
434  NS_TEST_ASSERT_MSG_EQ(flow1->GetStatus(),
435  FqCobaltFlow::OLD_FLOW,
436  "the first flow must be in the list of old queues");
437  // the second flow has a negative deficit (60-(100+20)= -60)
438  NS_TEST_ASSERT_MSG_EQ(flow2->GetDeficit(), -60, "unexpected deficit for the second flow");
439  NS_TEST_ASSERT_MSG_EQ(flow2->GetStatus(),
440  FqCobaltFlow::OLD_FLOW,
441  "the second flow must be in the list of new queues");
442 
443  // Dequeue a packet (from the first flow, as the second flow has a negative deficit)
444  queueDisc->Dequeue();
445  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
446  0,
447  "unexpected number of packets in the queue disc");
448  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
449  0,
450  "unexpected number of packets in the first flow queue");
451  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
452  0,
453  "unexpected number of packets in the second flow queue");
454  // the first flow has a negative deficit (30-(100+20)= -90)
455  NS_TEST_ASSERT_MSG_EQ(flow1->GetDeficit(), -90, "unexpected deficit for the first flow");
456  NS_TEST_ASSERT_MSG_EQ(flow1->GetStatus(),
457  FqCobaltFlow::OLD_FLOW,
458  "the first flow must be in the list of old queues");
459  // the second flow got a quantum of deficit (-60+90=30) and has been moved to the end of the
460  // list of old queues
461  NS_TEST_ASSERT_MSG_EQ(flow2->GetDeficit(), 30, "unexpected deficit for the second flow");
462  NS_TEST_ASSERT_MSG_EQ(flow2->GetStatus(),
463  FqCobaltFlow::OLD_FLOW,
464  "the second flow must be in the list of new queues");
465 
466  // Dequeue a packet
467  queueDisc->Dequeue();
468  // the first flow is at the head of the list of old queues but has a negative deficit, thus it
469  // gets a quantun of deficit (-90+90=0) and is moved to the end of the list of old queues. Then,
470  // the second flow (which has a positive deficit) is selected, but the second flow is empty and
471  // thus it is set to inactive. The first flow is reconsidered, but it has a null deficit, hence
472  // it gets another quantum of deficit (0+90=90). Then, the first flow is reconsidered again, now
473  // it has a positive deficit and hence it is selected. But, it is empty and therefore is set to
474  // inactive, too.
475  NS_TEST_ASSERT_MSG_EQ(flow1->GetDeficit(), 90, "unexpected deficit for the first flow");
476  NS_TEST_ASSERT_MSG_EQ(flow1->GetStatus(),
478  "the first flow must be inactive");
479  NS_TEST_ASSERT_MSG_EQ(flow2->GetDeficit(), 30, "unexpected deficit for the second flow");
480  NS_TEST_ASSERT_MSG_EQ(flow2->GetStatus(),
482  "the second flow must be inactive");
483 
484  Simulator::Destroy();
485 }
486 
493 {
494  public:
497 
498  private:
499  void DoRun() override;
506  void AddPacket(Ptr<FqCobaltQueueDisc> queue, Ipv4Header ipHdr, TcpHeader tcpHdr);
507 };
508 
510  : TestCase("Test TCP flows separation")
511 {
512 }
513 
515 {
516 }
517 
518 void
520  Ipv4Header ipHdr,
521  TcpHeader tcpHdr)
522 {
523  Ptr<Packet> p = Create<Packet>(100);
524  p->AddHeader(tcpHdr);
525  Address dest;
526  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem>(p, dest, 0, ipHdr);
527  queue->Enqueue(item);
528 }
529 
530 void
532 {
533  Ptr<FqCobaltQueueDisc> queueDisc =
534  CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize", StringValue("10p"));
535 
536  queueDisc->SetQuantum(1500);
537  queueDisc->Initialize();
538 
539  Ipv4Header hdr;
540  hdr.SetPayloadSize(100);
541  hdr.SetSource(Ipv4Address("10.10.1.1"));
542  hdr.SetDestination(Ipv4Address("10.10.1.2"));
543  hdr.SetProtocol(6);
544 
545  TcpHeader tcpHdr;
546  tcpHdr.SetSourcePort(7);
547  tcpHdr.SetDestinationPort(27);
548 
549  // Add three packets from the first flow
550  AddPacket(queueDisc, hdr, tcpHdr);
551  AddPacket(queueDisc, hdr, tcpHdr);
552  AddPacket(queueDisc, hdr, tcpHdr);
553  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
554  3,
555  "unexpected number of packets in the queue disc");
556  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
557  3,
558  "unexpected number of packets in the first flow queue");
559 
560  // Add a packet from the second flow
561  tcpHdr.SetSourcePort(8);
562  AddPacket(queueDisc, hdr, tcpHdr);
563  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
564  4,
565  "unexpected number of packets in the queue disc");
566  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
567  3,
568  "unexpected number of packets in the first flow queue");
569  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
570  1,
571  "unexpected number of packets in the second flow queue");
572 
573  // Add a packet from the third flow
574  tcpHdr.SetDestinationPort(28);
575  AddPacket(queueDisc, hdr, tcpHdr);
576  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
577  5,
578  "unexpected number of packets in the queue disc");
579  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
580  3,
581  "unexpected number of packets in the first flow queue");
582  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
583  1,
584  "unexpected number of packets in the second flow queue");
585  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(2)->GetQueueDisc()->GetNPackets(),
586  1,
587  "unexpected number of packets in the third flow queue");
588 
589  // Add two packets from the fourth flow
590  tcpHdr.SetSourcePort(7);
591  AddPacket(queueDisc, hdr, tcpHdr);
592  AddPacket(queueDisc, hdr, tcpHdr);
593  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
594  7,
595  "unexpected number of packets in the queue disc");
596  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
597  3,
598  "unexpected number of packets in the first flow queue");
599  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
600  1,
601  "unexpected number of packets in the second flow queue");
602  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(2)->GetQueueDisc()->GetNPackets(),
603  1,
604  "unexpected number of packets in the third flow queue");
605  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(3)->GetQueueDisc()->GetNPackets(),
606  2,
607  "unexpected number of packets in the third flow queue");
608 
609  Simulator::Destroy();
610 }
611 
618 {
619  public:
622 
623  private:
624  void DoRun() override;
631  void AddPacket(Ptr<FqCobaltQueueDisc> queue, Ipv4Header ipHdr, UdpHeader udpHdr);
632 };
633 
635  : TestCase("Test UDP flows separation")
636 {
637 }
638 
640 {
641 }
642 
643 void
645  Ipv4Header ipHdr,
646  UdpHeader udpHdr)
647 {
648  Ptr<Packet> p = Create<Packet>(100);
649  p->AddHeader(udpHdr);
650  Address dest;
651  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem>(p, dest, 0, ipHdr);
652  queue->Enqueue(item);
653 }
654 
655 void
657 {
658  Ptr<FqCobaltQueueDisc> queueDisc =
659  CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize", StringValue("10p"));
660 
661  queueDisc->SetQuantum(1500);
662  queueDisc->Initialize();
663 
664  Ipv4Header hdr;
665  hdr.SetPayloadSize(100);
666  hdr.SetSource(Ipv4Address("10.10.1.1"));
667  hdr.SetDestination(Ipv4Address("10.10.1.2"));
668  hdr.SetProtocol(17);
669 
670  UdpHeader udpHdr;
671  udpHdr.SetSourcePort(7);
672  udpHdr.SetDestinationPort(27);
673 
674  // Add three packets from the first flow
675  AddPacket(queueDisc, hdr, udpHdr);
676  AddPacket(queueDisc, hdr, udpHdr);
677  AddPacket(queueDisc, hdr, udpHdr);
678  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
679  3,
680  "unexpected number of packets in the queue disc");
681  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
682  3,
683  "unexpected number of packets in the first flow queue");
684 
685  // Add a packet from the second flow
686  udpHdr.SetSourcePort(8);
687  AddPacket(queueDisc, hdr, udpHdr);
688  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
689  4,
690  "unexpected number of packets in the queue disc");
691  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
692  3,
693  "unexpected number of packets in the first flow queue");
694  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
695  1,
696  "unexpected number of packets in the second flow queue");
697 
698  // Add a packet from the third flow
699  udpHdr.SetDestinationPort(28);
700  AddPacket(queueDisc, hdr, udpHdr);
701  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
702  5,
703  "unexpected number of packets in the queue disc");
704  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
705  3,
706  "unexpected number of packets in the first flow queue");
707  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
708  1,
709  "unexpected number of packets in the second flow queue");
710  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(2)->GetQueueDisc()->GetNPackets(),
711  1,
712  "unexpected number of packets in the third flow queue");
713 
714  // Add two packets from the fourth flow
715  udpHdr.SetSourcePort(7);
716  AddPacket(queueDisc, hdr, udpHdr);
717  AddPacket(queueDisc, hdr, udpHdr);
718  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
719  7,
720  "unexpected number of packets in the queue disc");
721  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
722  3,
723  "unexpected number of packets in the first flow queue");
724  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
725  1,
726  "unexpected number of packets in the second flow queue");
727  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(2)->GetQueueDisc()->GetNPackets(),
728  1,
729  "unexpected number of packets in the third flow queue");
730  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(3)->GetQueueDisc()->GetNPackets(),
731  2,
732  "unexpected number of packets in the third flow queue");
733 
734  Simulator::Destroy();
735 }
736 
758 {
759  public:
761  ~FqCobaltQueueDiscEcnMarking() override;
762 
763  private:
764  void DoRun() override;
774  Ipv4Header hdr,
775  uint32_t nPkt,
776  uint32_t nPktEnqueued,
777  uint32_t nQueueFlows);
783  void Dequeue(Ptr<FqCobaltQueueDisc> queue, uint32_t nPkt);
790  void DequeueWithDelay(Ptr<FqCobaltQueueDisc> queue, double delay, uint32_t nPkt);
796  void DropNextTracer(int64_t oldVal, int64_t newVal);
797  uint32_t m_dropNextCount;
798 };
799 
801  : TestCase("Test ECN marking")
802 {
803  m_dropNextCount = 0;
804 }
805 
807 {
808 }
809 
810 void
812  Ipv4Header hdr,
813  uint32_t nPkt,
814  uint32_t nPktEnqueued,
815  uint32_t nQueueFlows)
816 {
817  Address dest;
818  Ptr<Packet> p = Create<Packet>(100);
819  for (uint32_t i = 0; i < nPkt; i++)
820  {
821  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem>(p, dest, 0, hdr);
822  queue->Enqueue(item);
823  }
824  NS_TEST_EXPECT_MSG_EQ(queue->GetNQueueDiscClasses(),
825  nQueueFlows,
826  "unexpected number of flow queues");
827  NS_TEST_EXPECT_MSG_EQ(queue->GetNPackets(),
828  nPktEnqueued,
829  "unexpected number of enqueued packets");
830 }
831 
832 void
834 {
836  queue->GetQueueDiscClass(3)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
837 
838  // Trace DropNext after the first dequeue as m_dropNext value is set after the first dequeue
839  if (q3->GetNPackets() == 19)
840  {
841  q3->TraceConnectWithoutContext(
842  "DropNext",
844  }
845 
846  for (uint32_t i = 0; i < nPkt; i++)
847  {
848  Ptr<QueueDiscItem> item = queue->Dequeue();
849  }
850 }
851 
852 void
854  double delay,
855  uint32_t nPkt)
856 {
857  for (uint32_t i = 0; i < nPkt; i++)
858  {
859  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
861  this,
862  queue,
863  1);
864  }
865 }
866 
867 void
868 FqCobaltQueueDiscEcnMarking::DropNextTracer(int64_t /* oldVal */, int64_t /* newVal */)
869 {
870  m_dropNextCount++;
871 }
872 
873 void
875 {
876  // Test is divided into 3 sub test cases:
877  // 1) CeThreshold disabled
878  // 2) CeThreshold enabled
879  // 3) Same as 2 but with higher queue delay
880 
881  // Test case 1, CeThreshold disabled
882  Ptr<FqCobaltQueueDisc> queueDisc =
883  CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize",
884  StringValue("10240p"),
885  "UseEcn",
886  BooleanValue(true),
887  "Perturbation",
888  UintegerValue(0),
889  "BlueThreshold",
890  TimeValue(Time::Max()));
891 
892  queueDisc->SetQuantum(1514);
893  queueDisc->Initialize();
894  Ipv4Header hdr;
895  hdr.SetPayloadSize(100);
896  hdr.SetSource(Ipv4Address("10.10.1.1"));
897  hdr.SetDestination(Ipv4Address("10.10.1.2"));
898  hdr.SetProtocol(7);
899  hdr.SetEcn(Ipv4Header::ECN_ECT0);
900 
901  // Add 20 ECT0 (ECN capable) packets from the first flow
902  Simulator::Schedule(Time(Seconds(0)),
904  this,
905  queueDisc,
906  hdr,
907  20,
908  20,
909  1);
910 
911  // Add 20 ECT0 (ECN capable) packets from second flow
912  hdr.SetDestination(Ipv4Address("10.10.1.10"));
913  Simulator::Schedule(Time(Seconds(0)),
915  this,
916  queueDisc,
917  hdr,
918  20,
919  40,
920  2);
921 
922  // Add 20 ECT0 (ECN capable) packets from third flow
923  hdr.SetDestination(Ipv4Address("10.10.1.20"));
924  Simulator::Schedule(Time(Seconds(0)),
926  this,
927  queueDisc,
928  hdr,
929  20,
930  60,
931  3);
932 
933  // Add 20 NotECT packets from fourth flow
934  hdr.SetDestination(Ipv4Address("10.10.1.30"));
935  hdr.SetEcn(Ipv4Header::ECN_NotECT);
936  Simulator::Schedule(Time(Seconds(0)),
938  this,
939  queueDisc,
940  hdr,
941  20,
942  80,
943  4);
944 
945  // Add 20 NotECT packets from fifth flow
946  hdr.SetDestination(Ipv4Address("10.10.1.40"));
947  Simulator::Schedule(Time(Seconds(0)),
949  this,
950  queueDisc,
951  hdr,
952  20,
953  100,
954  5);
955 
956  // Dequeue 60 packets with delay 110ms to induce packet drops and keep some remaining packets in
957  // each queue
958  DequeueWithDelay(queueDisc, 0.11, 60);
959  Simulator::Run();
960  Simulator::Stop(Seconds(8.0));
962  queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
964  queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
966  queueDisc->GetQueueDiscClass(2)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
968  queueDisc->GetQueueDiscClass(3)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
970  queueDisc->GetQueueDiscClass(4)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
971 
972  // As packets in flow queues are ECN capable
973  NS_TEST_EXPECT_MSG_EQ(q0->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
974  19,
975  "There should be 19 marked packets."
976  "As there is no CoDel minBytes parameter so all the packets apart from "
977  "the first one gets marked. As q3 and q4 have"
978  "NotEct packets and the queue delay is much higher than 5ms so the queue "
979  "gets empty pretty quickly so more"
980  "packets from q0 can be dequeued.");
981  NS_TEST_EXPECT_MSG_EQ(q0->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
982  0,
983  "There should not be any dropped packets");
984  NS_TEST_EXPECT_MSG_EQ(q1->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
985  16,
986  "There should be 16 marked packets"
987  "As there is no CoDel minBytes parameter so all the packets apart from "
988  "the first one until no more packets are dequeued"
989  "are marked.");
990  NS_TEST_EXPECT_MSG_EQ(q1->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
991  0,
992  "There should not be any dropped packets");
993  NS_TEST_EXPECT_MSG_EQ(q2->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
994  12,
995  "There should be 12 marked packets"
996  "Each packet size is 120 bytes and the quantum is 1500 bytes so in the "
997  "first turn (1514/120 = 12.61) 13 packets are"
998  "dequeued and apart from the first one, all the packets are marked.");
999  NS_TEST_EXPECT_MSG_EQ(q2->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1000  0,
1001  "There should not be any dropped packets");
1002 
1003  // As packets in flow queues are not ECN capable
1004  NS_TEST_EXPECT_MSG_EQ(q3->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1006  "The number of drops should"
1007  "be equal to the number of times m_dropNext is updated");
1008  NS_TEST_EXPECT_MSG_EQ(q3->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
1009  0,
1010  "There should not be any marked packets");
1011  NS_TEST_EXPECT_MSG_EQ(q4->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1013  "The number of drops should"
1014  "be equal to the number of times m_dropNext is updated");
1015  NS_TEST_EXPECT_MSG_EQ(q4->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
1016  0,
1017  "There should not be any marked packets");
1018 
1019  Simulator::Destroy();
1020 
1021  // Test case 2, CeThreshold set to 2ms
1022  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize",
1023  StringValue("10240p"),
1024  "UseEcn",
1025  BooleanValue(true),
1026  "CeThreshold",
1027  TimeValue(MilliSeconds(2)));
1028  queueDisc->SetQuantum(1514);
1029  queueDisc->Initialize();
1030 
1031  // Add 20 ECT0 (ECN capable) packets from first flow
1032  hdr.SetDestination(Ipv4Address("10.10.1.2"));
1033  hdr.SetEcn(Ipv4Header::ECN_ECT0);
1034  Simulator::Schedule(Time(Seconds(0)),
1036  this,
1037  queueDisc,
1038  hdr,
1039  20,
1040  20,
1041  1);
1042 
1043  // Add 20 ECT0 (ECN capable) packets from second flow
1044  hdr.SetDestination(Ipv4Address("10.10.1.10"));
1045  Simulator::Schedule(Time(Seconds(0)),
1047  this,
1048  queueDisc,
1049  hdr,
1050  20,
1051  40,
1052  2);
1053 
1054  // Add 20 ECT0 (ECN capable) packets from third flow
1055  hdr.SetDestination(Ipv4Address("10.10.1.20"));
1056  Simulator::Schedule(Time(Seconds(0)),
1058  this,
1059  queueDisc,
1060  hdr,
1061  20,
1062  60,
1063  3);
1064 
1065  // Add 20 NotECT packets from fourth flow
1066  hdr.SetDestination(Ipv4Address("10.10.1.30"));
1067  hdr.SetEcn(Ipv4Header::ECN_NotECT);
1068  Simulator::Schedule(Time(Seconds(0)),
1070  this,
1071  queueDisc,
1072  hdr,
1073  20,
1074  80,
1075  4);
1076 
1077  // Add 20 NotECT packets from fifth flow
1078  hdr.SetDestination(Ipv4Address("10.10.1.40"));
1079  Simulator::Schedule(Time(Seconds(0)),
1081  this,
1082  queueDisc,
1083  hdr,
1084  20,
1085  100,
1086  5);
1087 
1088  // Dequeue 60 packets with delay 0.1ms to induce packet drops and keep some remaining packets in
1089  // each queue
1090  DequeueWithDelay(queueDisc, 0.0001, 60);
1091  Simulator::Run();
1092  Simulator::Stop(Seconds(8.0));
1093  q0 = queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1094  q1 = queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1095  q2 = queueDisc->GetQueueDiscClass(2)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1096  q3 = queueDisc->GetQueueDiscClass(3)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1097  q4 = queueDisc->GetQueueDiscClass(4)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1098 
1099  // As packets in flow queues are ECN capable
1100  NS_TEST_EXPECT_MSG_EQ(q0->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1101  0,
1102  "There should not be any dropped packets");
1104  q0->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1105  0,
1106  "There should not be any marked packets"
1107  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued. sojourn time of 13th "
1108  "packet is 1.3ms which is"
1109  "less than CE threshold");
1110  NS_TEST_EXPECT_MSG_EQ(q1->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1111  0,
1112  "There should not be any dropped packets");
1114  q1->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1115  6,
1116  "There should be 6 marked packets"
1117  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued. sojourn time of 8th "
1118  "packet is 2.1ms which is greater"
1119  "than CE threshold and subsequent packet also have sojourn time more 8th packet hence "
1120  "remaining packet are marked.");
1121  NS_TEST_EXPECT_MSG_EQ(q2->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1122  0,
1123  "There should not be any dropped packets");
1125  q2->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1126  13,
1127  "There should be 13 marked packets"
1128  "with quantum of 1514, 13 packets of size 120 bytes can be dequeued and all of them have "
1129  "sojourn time more than CE threshold");
1130 
1131  // As packets in flow queues are not ECN capable
1133  q3->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1134  0,
1135  "There should not be any marked packets");
1136  NS_TEST_EXPECT_MSG_EQ(q3->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1137  0,
1138  "There should not be any dropped packets");
1140  q4->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1141  0,
1142  "There should not be any marked packets");
1143  NS_TEST_EXPECT_MSG_EQ(q4->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1144  1,
1145  "There should 1 dropped packet. As the queue"
1146  "delay for the first dequeue is greater than the target (5ms), Cobalt "
1147  "overloads the m_dropNext field as an activity timeout"
1148  "and dropNext is to set to the current Time value so on the next dequeue "
1149  "a packet is dropped.");
1150 
1151  Simulator::Destroy();
1152 
1153  // Test case 3, CeThreshold set to 2ms with higher queue delay. This test is mainly to check
1154  // that the packets are not getting marked twice.
1155  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize",
1156  StringValue("10240p"),
1157  "UseEcn",
1158  BooleanValue(true),
1159  "CeThreshold",
1160  TimeValue(MilliSeconds(2)),
1161  "BlueThreshold",
1162  TimeValue(Time::Max()));
1163  queueDisc->SetQuantum(1514);
1164  queueDisc->Initialize();
1165 
1166  // Add 20 ECT0 (ECN capable) packets from first flow
1167  hdr.SetDestination(Ipv4Address("10.10.1.2"));
1168  hdr.SetEcn(Ipv4Header::ECN_ECT0);
1169  Simulator::Schedule(Time(Seconds(0)),
1171  this,
1172  queueDisc,
1173  hdr,
1174  20,
1175  20,
1176  1);
1177 
1178  // Add 20 ECT0 (ECN capable) packets from second flow
1179  hdr.SetDestination(Ipv4Address("10.10.1.10"));
1180  Simulator::Schedule(Time(Seconds(0)),
1182  this,
1183  queueDisc,
1184  hdr,
1185  20,
1186  40,
1187  2);
1188 
1189  // Add 20 ECT0 (ECN capable) packets from third flow
1190  hdr.SetDestination(Ipv4Address("10.10.1.20"));
1191  Simulator::Schedule(Time(Seconds(0)),
1193  this,
1194  queueDisc,
1195  hdr,
1196  20,
1197  60,
1198  3);
1199 
1200  // Add 20 NotECT packets from fourth flow
1201  hdr.SetDestination(Ipv4Address("10.10.1.30"));
1202  hdr.SetEcn(Ipv4Header::ECN_NotECT);
1203  Simulator::Schedule(Time(Seconds(0)),
1205  this,
1206  queueDisc,
1207  hdr,
1208  20,
1209  80,
1210  4);
1211 
1212  // Add 20 NotECT packets from fifth flow
1213  hdr.SetDestination(Ipv4Address("10.10.1.40"));
1214  Simulator::Schedule(Time(Seconds(0)),
1216  this,
1217  queueDisc,
1218  hdr,
1219  20,
1220  100,
1221  5);
1222 
1223  // Reset m_dropNextCount value;
1224  m_dropNextCount = 0;
1225 
1226  // Dequeue 60 packets with delay 110ms to induce packet drops and keep some remaining packets in
1227  // each queue
1228  DequeueWithDelay(queueDisc, 0.110, 60);
1229  Simulator::Run();
1230  Simulator::Stop(Seconds(8.0));
1231  q0 = queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1232  q1 = queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1233  q2 = queueDisc->GetQueueDiscClass(2)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1234  q3 = queueDisc->GetQueueDiscClass(3)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1235  q4 = queueDisc->GetQueueDiscClass(4)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1236 
1237  // As packets in flow queues are ECN capable
1238  NS_TEST_EXPECT_MSG_EQ(q0->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1239  0,
1240  "There should not be any dropped packets");
1242  q0->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
1243  q0->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
1244  20 - q0->GetNPackets(),
1245  "Number of CE threshold"
1246  " exceeded marks plus Number of Target exceeded marks should be equal to total number of "
1247  "packets dequeued");
1248  NS_TEST_EXPECT_MSG_EQ(q1->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1249  0,
1250  "There should not be any dropped packets");
1252  q1->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
1253  q1->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
1254  20 - q1->GetNPackets(),
1255  "Number of CE threshold"
1256  " exceeded marks plus Number of Target exceeded marks should be equal to total number of "
1257  "packets dequeued");
1258  NS_TEST_EXPECT_MSG_EQ(q2->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1259  0,
1260  "There should not be any dropped packets");
1262  q2->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK) +
1263  q2->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
1264  20 - q2->GetNPackets(),
1265  "Number of CE threshold"
1266  " exceeded marks plus Number of Target exceeded marks should be equal to total number of "
1267  "packets dequeued");
1268 
1269  // As packets in flow queues are not ECN capable
1271  q3->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1272  0,
1273  "There should not be any marked packets");
1274  NS_TEST_EXPECT_MSG_EQ(q3->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1276  "The number of drops should"
1277  "be equal to the number of times m_dropNext is updated");
1279  q4->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1280  0,
1281  "There should not be any marked packets");
1282  NS_TEST_EXPECT_MSG_EQ(q4->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1284  "The number of drops should"
1285  "be equal to the number of times m_dropNext is updated");
1286 
1287  Simulator::Destroy();
1288 }
1289 
1315 {
1316  public:
1319 
1320  private:
1321  void DoRun() override;
1327  void AddPacket(Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr);
1328 };
1329 
1331  : TestCase("Test credits and flows status")
1332 {
1333 }
1334 
1336 {
1337 }
1338 
1339 void
1341 {
1342  Ptr<Packet> p = Create<Packet>(100);
1343  Address dest;
1344  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem>(p, dest, 0, hdr);
1345  queue->Enqueue(item);
1346 }
1347 
1348 void
1350 {
1351  Ptr<FqCobaltQueueDisc> queueDisc =
1352  CreateObjectWithAttributes<FqCobaltQueueDisc>("EnableSetAssociativeHash",
1353  BooleanValue(true));
1354  queueDisc->SetQuantum(90);
1355  queueDisc->Initialize();
1356 
1357  Ptr<Ipv4FqCobaltTestPacketFilter> filter = CreateObject<Ipv4FqCobaltTestPacketFilter>();
1358  queueDisc->AddPacketFilter(filter);
1359 
1360  Ipv4Header hdr;
1361  hdr.SetPayloadSize(100);
1362  hdr.SetSource(Ipv4Address("10.10.1.1"));
1363  hdr.SetDestination(Ipv4Address("10.10.1.2"));
1364  hdr.SetProtocol(7);
1365 
1366  g_hash = 0;
1367  AddPacket(queueDisc, hdr);
1368  g_hash = 1;
1369  AddPacket(queueDisc, hdr);
1370  AddPacket(queueDisc, hdr);
1371  g_hash = 2;
1372  AddPacket(queueDisc, hdr);
1373  g_hash = 3;
1374  AddPacket(queueDisc, hdr);
1375  g_hash = 4;
1376  AddPacket(queueDisc, hdr);
1377  AddPacket(queueDisc, hdr);
1378  g_hash = 5;
1379  AddPacket(queueDisc, hdr);
1380  g_hash = 6;
1381  AddPacket(queueDisc, hdr);
1382  g_hash = 7;
1383  AddPacket(queueDisc, hdr);
1384  g_hash = 1024;
1385  AddPacket(queueDisc, hdr);
1386 
1387  NS_TEST_ASSERT_MSG_EQ(queueDisc->QueueDisc::GetNPackets(),
1388  11,
1389  "unexpected number of packets in the queue disc");
1390  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
1391  2,
1392  "unexpected number of packets in the first flow queue of set one");
1393  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetNPackets(),
1394  2,
1395  "unexpected number of packets in the second flow queue of set one");
1396  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(2)->GetQueueDisc()->GetNPackets(),
1397  1,
1398  "unexpected number of packets in the third flow queue of set one");
1399  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(3)->GetQueueDisc()->GetNPackets(),
1400  1,
1401  "unexpected number of packets in the fourth flow queue of set one");
1402  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(4)->GetQueueDisc()->GetNPackets(),
1403  2,
1404  "unexpected number of packets in the fifth flow queue of set one");
1405  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(5)->GetQueueDisc()->GetNPackets(),
1406  1,
1407  "unexpected number of packets in the sixth flow queue of set one");
1408  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(6)->GetQueueDisc()->GetNPackets(),
1409  1,
1410  "unexpected number of packets in the seventh flow queue of set one");
1411  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(7)->GetQueueDisc()->GetNPackets(),
1412  1,
1413  "unexpected number of packets in the eighth flow queue of set one");
1414  g_hash = 1025;
1415  AddPacket(queueDisc, hdr);
1416  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetNPackets(),
1417  3,
1418  "unexpected number of packets in the first flow of set one");
1419  g_hash = 10;
1420  AddPacket(queueDisc, hdr);
1421  NS_TEST_ASSERT_MSG_EQ(queueDisc->GetQueueDiscClass(8)->GetQueueDisc()->GetNPackets(),
1422  1,
1423  "unexpected number of packets in the first flow of set two");
1424  Simulator::Destroy();
1425 }
1426 
1443 {
1444  public:
1446  ~FqCobaltQueueDiscL4sMode() override;
1447 
1448  private:
1449  void DoRun() override;
1456  void AddPacket(Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr, uint32_t nPkt);
1465  Ipv4Header hdr,
1466  double delay,
1467  uint32_t nPkt);
1473  void Dequeue(Ptr<FqCobaltQueueDisc> queue, uint32_t nPkt);
1480  void DequeueWithDelay(Ptr<FqCobaltQueueDisc> queue, double delay, uint32_t nPkt);
1481 };
1482 
1484  : TestCase("Test L4S mode")
1485 {
1486 }
1487 
1489 {
1490 }
1491 
1492 void
1494 {
1495  Address dest;
1496  Ptr<Packet> p = Create<Packet>(100);
1497  for (uint32_t i = 0; i < nPkt; i++)
1498  {
1499  Ptr<Ipv4QueueDiscItem> item = Create<Ipv4QueueDiscItem>(p, dest, 0, hdr);
1500  queue->Enqueue(item);
1501  }
1502 }
1503 
1504 void
1506  Ipv4Header hdr,
1507  double delay,
1508  uint32_t nPkt)
1509 {
1510  for (uint32_t i = 0; i < nPkt; i++)
1511  {
1512  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
1514  this,
1515  queue,
1516  hdr,
1517  1);
1518  }
1519 }
1520 
1521 void
1523 {
1524  for (uint32_t i = 0; i < nPkt; i++)
1525  {
1526  Ptr<QueueDiscItem> item = queue->Dequeue();
1527  }
1528 }
1529 
1530 void
1532  double delay,
1533  uint32_t nPkt)
1534 {
1535  for (uint32_t i = 0; i < nPkt; i++)
1536  {
1537  Simulator::Schedule(Time(Seconds((i + 1) * delay)),
1539  this,
1540  queue,
1541  1);
1542  }
1543 }
1544 
1545 void
1547 {
1548  // Test is divided into 2 sub test cases:
1549  // 1) Without hash collisions
1550  // 2) With hash collisions
1551 
1552  // Test case 1, Without hash collisions
1553  Ptr<FqCobaltQueueDisc> queueDisc =
1554  CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize",
1555  StringValue("10240p"),
1556  "UseEcn",
1557  BooleanValue(true),
1558  "Perturbation",
1559  UintegerValue(0),
1560  "UseL4s",
1561  BooleanValue(true),
1562  "CeThreshold",
1563  TimeValue(MilliSeconds(2)));
1564 
1565  queueDisc->SetQuantum(1514);
1566  queueDisc->Initialize();
1567  Ipv4Header hdr;
1568  hdr.SetPayloadSize(100);
1569  hdr.SetSource(Ipv4Address("10.10.1.1"));
1570  hdr.SetDestination(Ipv4Address("10.10.1.2"));
1571  hdr.SetProtocol(7);
1572  hdr.SetEcn(Ipv4Header::ECN_ECT1);
1573 
1574  // Add 70 ECT1 (ECN capable) packets from the first flow
1575  // Set delay = 0.5ms
1576  double delay = 0.0005;
1577  Simulator::Schedule(Time(Seconds(0)),
1579  this,
1580  queueDisc,
1581  hdr,
1582  delay,
1583  70);
1584 
1585  // Add 70 ECT0 (ECN capable) packets from second flow
1586  hdr.SetEcn(Ipv4Header::ECN_ECT0);
1587  hdr.SetDestination(Ipv4Address("10.10.1.10"));
1588  Simulator::Schedule(Time(Seconds(0)),
1590  this,
1591  queueDisc,
1592  hdr,
1593  delay,
1594  70);
1595 
1596  // Dequeue 140 packets with delay 1ms
1597  delay = 0.001;
1598  DequeueWithDelay(queueDisc, delay, 140);
1599  Simulator::Run();
1600  Simulator::Stop(Seconds(8.0));
1602  queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1604  queueDisc->GetQueueDiscClass(1)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1605 
1607  q0->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1608  66,
1609  "There should be 66 marked packets"
1610  "4th packet is enqueued at 2ms and dequeued at 4ms hence the delay of 2ms which not "
1611  "greater than CE threshold"
1612  "5th packet is enqueued at 2.5ms and dequeued at 5ms hence the delay of 2.5ms and "
1613  "subsequent packet also do have delay"
1614  "greater than CE threshold so all the packets after 4th packet are marked");
1615  NS_TEST_EXPECT_MSG_EQ(q0->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1616  0,
1617  "There should not be any dropped packets");
1618  NS_TEST_EXPECT_MSG_EQ(q0->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
1619  0,
1620  "There should not be any marked packets");
1621  NS_TEST_EXPECT_MSG_EQ(q1->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
1622  2,
1623  "There should be 2 marked packets. Packets are dequeued"
1624  "from q0 first, which leads to delay greater than 5ms for the first "
1625  "dequeue from q1. Because of inactivity (started with high queue delay)"
1626  "Cobalt keeps drop_next as now and the next packet is marked. With "
1627  "second dequeue count increases to 2, drop_next becomes now plus around"
1628  "70ms which is less than the running time(140), and as the queue delay "
1629  "is persistently higher than 5ms, second packet is marked.");
1630  NS_TEST_EXPECT_MSG_EQ(q1->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1631  0,
1632  "There should not be any dropped packets");
1633 
1634  Simulator::Destroy();
1635 
1636  // Test case 2, With hash collisions
1637  queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize",
1638  StringValue("10240p"),
1639  "UseEcn",
1640  BooleanValue(true),
1641  "Perturbation",
1642  UintegerValue(0),
1643  "UseL4s",
1644  BooleanValue(true),
1645  "CeThreshold",
1646  TimeValue(MilliSeconds(2)));
1647 
1648  queueDisc->SetQuantum(1514);
1649  queueDisc->Initialize();
1650  hdr.SetPayloadSize(100);
1651  hdr.SetSource(Ipv4Address("10.10.1.1"));
1652  hdr.SetDestination(Ipv4Address("10.10.1.2"));
1653  hdr.SetProtocol(7);
1654  hdr.SetEcn(Ipv4Header::ECN_ECT1);
1655 
1656  // Add 70 ECT1 (ECN capable) packets from the first flow
1657  // Set delay = 1ms
1658  delay = 0.001;
1659  Simulator::Schedule(Time(Seconds(0.0005)),
1661  this,
1662  queueDisc,
1663  hdr,
1664  1);
1665  Simulator::Schedule(Time(Seconds(0.0005)),
1667  this,
1668  queueDisc,
1669  hdr,
1670  delay,
1671  69);
1672 
1673  // Add 70 ECT0 (ECN capable) packets from first flow
1674  hdr.SetEcn(Ipv4Header::ECN_ECT0);
1675  Simulator::Schedule(Time(Seconds(0)),
1677  this,
1678  queueDisc,
1679  hdr,
1680  delay,
1681  70);
1682 
1683  // Dequeue 140 packets with delay 1ms
1684  DequeueWithDelay(queueDisc, delay, 140);
1685  Simulator::Run();
1686  Simulator::Stop(Seconds(8.0));
1687  q0 = queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1688  q0 = queueDisc->GetQueueDiscClass(0)->GetQueueDisc()->GetObject<CobaltQueueDisc>();
1689 
1691  q0->GetStats().GetNMarkedPackets(CobaltQueueDisc::CE_THRESHOLD_EXCEEDED_MARK),
1692  68,
1693  "There should be 68 marked packets"
1694  "2nd ECT1 packet is enqueued at 1.5ms and dequeued at 3ms hence the delay of 1.5ms which "
1695  "not greater than CE threshold"
1696  "3rd packet is enqueued at 2.5ms and dequeued at 5ms hence the delay of 2.5ms and "
1697  "subsequent packet also do have delay"
1698  "greater than CE threshold so all the packets after 2nd packet are marked");
1699  NS_TEST_EXPECT_MSG_EQ(q0->GetStats().GetNDroppedPackets(CobaltQueueDisc::TARGET_EXCEEDED_DROP),
1700  0,
1701  "There should not be any dropped packets");
1702  NS_TEST_EXPECT_MSG_EQ(q0->GetStats().GetNMarkedPackets(CobaltQueueDisc::FORCED_MARK),
1703  1,
1704  "There should be 1 marked packets");
1705 
1706  Simulator::Destroy();
1707 }
1708 
1715 {
1716  public:
1718 };
1719 
1721  : TestSuite("fq-cobalt-queue-disc", UNIT)
1722 {
1723  AddTestCase(new FqCobaltQueueDiscNoSuitableFilter, TestCase::QUICK);
1725  AddTestCase(new FqCobaltQueueDiscDeficit, TestCase::QUICK);
1726  AddTestCase(new FqCobaltQueueDiscTCPFlowsSeparation, TestCase::QUICK);
1727  AddTestCase(new FqCobaltQueueDiscUDPFlowsSeparation, TestCase::QUICK);
1728  AddTestCase(new FqCobaltQueueDiscEcnMarking, TestCase::QUICK);
1729  AddTestCase(new FqCobaltQueueDiscSetLinearProbing, TestCase::QUICK);
1730  AddTestCase(new FqCobaltQueueDiscL4sMode, TestCase::QUICK);
1731 }
1732 
#define Max(a, b)
This class tests the deficit per flow.
void DoRun() override
Implementation to actually run this TestCase.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr)
Enqueue a packet.
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.
void DoRun() override
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.
void DoRun() override
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 DoRun() override
Implementation to actually run this TestCase.
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.
void DoRun() override
Implementation to actually run this TestCase.
This class tests linear probing, collision response, and set creation capability of set associative h...
void DoRun() override
Implementation to actually run this TestCase.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header hdr)
Enqueue a packet.
This class tests the TCP flows separation.
void DoRun() override
Implementation to actually run this TestCase.
void AddPacket(Ptr< FqCobaltQueueDisc > queue, Ipv4Header ipHdr, TcpHeader tcpHdr)
Enqueue a packet.
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.
void DoRun() override
Implementation to actually run this TestCase.
Simple test packet filter able to classify IPv4 packets.
int32_t DoClassify(Ptr< QueueDiscItem > item) const override
Classify a QueueDiscItem.
bool CheckProtocol(Ptr< QueueDiscItem > item) const override
Check the protocol.
static TypeId GetTypeId()
Get the type ID.
a polymophic address class
Definition: address.h:101
Cobalt packet queue disc.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
Packet header for IPv4.
Definition: ipv4-header.h:34
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:309
void SetPayloadSize(uint16_t size)
Definition: ipv4-header.cc:57
void SetEcn(EcnType ecn)
Set ECN Field.
Definition: ipv4-header.cc:100
void SetProtocol(uint8_t num)
Definition: ipv4-header.cc:288
void SetSource(Ipv4Address source)
Definition: ipv4-header.cc:295
Ipv4PacketFilter is the abstract base class for filters defined for IPv4 packets.
Packet header for IPv6.
Definition: ipv6-header.h:35
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Hold variables of type string.
Definition: string.h:56
Header for the Transmission Control Protocol.
Definition: tcp-header.h:47
void SetDestinationPort(uint16_t port)
Set the destination port.
Definition: tcp-header.cc:70
void SetSourcePort(uint16_t port)
Set the source port.
Definition: tcp-header.cc:64
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Packet header for UDP packets.
Definition: udp-header.h:41
void SetSourcePort(uint16_t port)
Definition: udp-header.cc:42
void SetDestinationPort(uint16_t port)
Definition: udp-header.cc:36
Hold an unsigned integer type.
Definition: uinteger.h:45
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:104
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:144
#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:251
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:839
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704