A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
39using namespace ns3;
40
41/// Variable to assign g_hash to a new packet's flow
43
44/**
45 * \ingroup system-tests-tc
46 *
47 * Simple test packet filter able to classify IPv4 packets.
48 */
50{
51 public:
52 /**
53 * \brief Get the type ID.
54 * \return the object TypeId
55 */
56 static TypeId GetTypeId();
57
60
61 private:
62 /**
63 * Classify a QueueDiscItem
64 * \param item The item to classify (unused).
65 * \return a pre-set hash value.
66 */
67 int32_t DoClassify(Ptr<QueueDiscItem> item) const override;
68
69 /**
70 * Check the protocol.
71 * \param item The item to check (unused).
72 * \return true.
73 */
74 bool CheckProtocol(Ptr<QueueDiscItem> item) const override;
75};
76
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
97{
98 return g_hash;
99}
100
101bool
103{
104 return true;
105}
106
107/**
108 * \ingroup system-tests-tc
109 *
110 * This class tests packets for which there is no suitable filter.
111 */
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
131void
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
163}
164
165/**
166 * \ingroup system-tests-tc
167 *
168 * This class tests the IP flows separation and the packet limit.
169 */
171{
172 public:
175
176 private:
177 void DoRun() override;
178 /**
179 * Enqueue a packet.
180 * \param queue The queue disc.
181 * \param hdr The IPv4 header.
182 */
184};
185
187 : TestCase("Test IP flows separation and packet limit")
188{
189}
190
193{
194}
195
196void
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
206void
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
259}
260
261/**
262 * \ingroup system-tests-tc
263 *
264 * This class tests the deficit per flow.
265 */
267{
268 public:
270 ~FqCobaltQueueDiscDeficit() override;
271
272 private:
273 void DoRun() override;
274 /**
275 * Enqueue a packet.
276 * \param queue The queue disc.
277 * \param hdr The IPv4 header.
278 */
280};
281
283 : TestCase("Test credits and flows status")
284{
285}
286
288{
289}
290
291void
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
300void
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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
485}
486
487/**
488 * \ingroup system-tests-tc
489 *
490 * This class tests the TCP flows separation.
491 */
493{
494 public:
497
498 private:
499 void DoRun() override;
500 /**
501 * Enqueue a packet.
502 * \param queue The queue disc.
503 * \param ipHdr The IPv4 header.
504 * \param tcpHdr The TCP header.
505 */
506 void AddPacket(Ptr<FqCobaltQueueDisc> queue, Ipv4Header ipHdr, TcpHeader tcpHdr);
507};
508
510 : TestCase("Test TCP flows separation")
511{
512}
513
515{
516}
517
518void
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
530void
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
610}
611
612/**
613 * \ingroup system-tests-tc
614 *
615 * This class tests the UDP flows separation
616 */
618{
619 public:
622
623 private:
624 void DoRun() override;
625 /**
626 * Enqueue a packet.
627 * \param queue the queue disc
628 * \param ipHdr the IPv4 header
629 * \param udpHdr the UDP header
630 */
631 void AddPacket(Ptr<FqCobaltQueueDisc> queue, Ipv4Header ipHdr, UdpHeader udpHdr);
632};
633
635 : TestCase("Test UDP flows separation")
636{
637}
638
640{
641}
642
643void
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
655void
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
735}
736
737/**
738 * \ingroup system-tests-tc
739 *
740 * \brief This class tests ECN marking.
741 *
742 * The test is divided into 3 sub test cases.
743 * 1) CE threshold disabled
744 * This test enqueues 100 packets in the beginning of the test and dequeues 60 (some packets are
745 * dropped too) packets with the delay of 110ms. This test checks that ECT0 packets are marked and
746 * are marked appropriately and NotECT packets are dropped.
747 *
748 * 2) CE threshold enabled.
749 * This test enqueues 100 packets in the beginning of the test and dequeues 60 packets with delay of
750 * 1ms. This test checks that the ECT0 packets are marked appropriately at CE threshold.
751 *
752 * 3) CE threshold enabled with higher queue delay.
753 * This test is similar to the 2nd sub test cases just with higher queue delay and aims to test that
754 * the packets are not marked twice Any future classifier options (e.g. SetAssociativehash) should
755 * be disabled to prevent a hash collision on this test case.
756 */
758{
759 public:
762
763 private:
764 void DoRun() override;
765 /**
766 * Enqueue the given number of packets.
767 * \param queue The queue disc.
768 * \param hdr The IPv4 header.
769 * \param nPkt The number of packets.
770 * \param nPktEnqueued The expected number of enqueued packets.
771 * \param nQueueFlows The expected number of flow queues.
772 */
774 Ipv4Header hdr,
775 uint32_t nPkt,
776 uint32_t nPktEnqueued,
777 uint32_t nQueueFlows);
778 /**
779 * Dequeue the given number of packets.
780 * \param queue The queue disc.
781 * \param nPkt The number of packets.
782 */
783 void Dequeue(Ptr<FqCobaltQueueDisc> queue, uint32_t nPkt);
784 /**
785 * Dequeue the given number of packets at different times.
786 * \param queue The queue disc.
787 * \param delay The time between two consecutive dequeue operations.
788 * \param nPkt The number of packets.
789 */
790 void DequeueWithDelay(Ptr<FqCobaltQueueDisc> queue, double delay, uint32_t nPkt);
791 /**
792 * Tracer for the DropNext attribute
793 * \param oldVal Old value.
794 * \param newVal New value.
795 */
796 void DropNextTracer(int64_t oldVal, int64_t newVal);
797 uint32_t m_dropNextCount; ///< count the number of times m_dropNext is recalculated
798};
799
801 : TestCase("Test ECN marking")
802{
803 m_dropNextCount = 0;
804}
805
807{
808}
809
810void
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
832void
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
852void
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
867void
868FqCobaltQueueDiscEcnMarking::DropNextTracer(int64_t /* oldVal */, int64_t /* newVal */)
869{
871}
872
873void
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",
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);
900
901 // Add 20 ECT0 (ECN capable) packets from the first flow
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"));
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"));
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"));
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"));
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);
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
1020
1021 // Test case 2, CeThreshold set to 2ms
1022 queueDisc = CreateObjectWithAttributes<FqCobaltQueueDisc>("MaxSize",
1023 StringValue("10240p"),
1024 "UseEcn",
1025 BooleanValue(true),
1026 "CeThreshold",
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"));
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"));
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"));
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"));
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"));
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);
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
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",
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"));
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"));
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"));
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"));
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"));
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);
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
1288}
1289
1290/**
1291 * \ingroup system-tests-tc
1292 *
1293 * \brief This class tests linear probing, collision response, and set
1294 * creation capability of set associative hashing in FqCobalt.
1295 *
1296 * We modified DoClassify () and CheckProtocol () so that we could control
1297 * the hash returned for each packet. In the beginning, we use flow hashes
1298 * ranging from 0 to 7. These must go into different queues in the same set.
1299 * The set number for these is obtained using outerhash, which is 0.
1300 * When a new packet arrives with flow hash 1024, outerhash = 0 is obtained
1301 * and the first set is iteratively searched.
1302 * The packet is eventually added to queue 0 since the tags of queues
1303 * in the set do not match with the hash of the flow. The tag of queue 0 is
1304 * updated as 1024. When a packet with hash 1025 arrives, outerhash = 0
1305 * is obtained and the first set is iteratively searched.
1306 * Since there is no match, it is added to queue 0 and the tag of queue 0 is
1307 * updated to 1025.
1308 *
1309 * The variable outerhash stores the nearest multiple of 8 that is lesser than
1310 * the hash. When a flow hash of 20 arrives, the value of outerhash
1311 * is 16. Since m_flowIndices[16] wasn't previously allotted, a new flow
1312 * is created, and the tag corresponding to this queue is set to 20.
1313 */
1315{
1316 public:
1319
1320 private:
1321 void DoRun() override;
1322 /**
1323 * Enqueue a packet.
1324 * \param queue The queue disc.
1325 * \param hdr The IPv4 header.
1326 */
1328};
1329
1331 : TestCase("Test credits and flows status")
1332{
1333}
1334
1336{
1337}
1338
1339void
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
1348void
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");
1425}
1426
1427/**
1428 * \ingroup system-tests-tc
1429 *
1430 * \brief This class tests L4S mode.
1431 *
1432 * This test is divided to sub test one without hash collisions and so ECT0 and ECT1 flows are
1433 * classified into different flows.
1434 *
1435 * Sub Test 1
1436 * 70 packets are enqueued into both the flows with the delay of 0.5ms between two enqueues, and
1437 * dequeued with the delay of 1ms between two dequeues. Sub Test 2 140(70 ECT0 + 70 ECT1) packets
1438 * are enqueued such that ECT1 packets are enqueued at 0.5ms, 1.5ms, 2.5ms and so on, and ECT0
1439 * packets are enqueued are enqueued at 1ms, 2ms, 3ms and so on Any future classifier options (e.g.
1440 * SetAssociativehash) should be disabled to prevent a hash collision on this test case.
1441 */
1443{
1444 public:
1446 ~FqCobaltQueueDiscL4sMode() override;
1447
1448 private:
1449 void DoRun() override;
1450 /**
1451 * Enqueue the given number of packets.
1452 * \param queue The queue disc.
1453 * \param hdr The IPv4 header.
1454 * \param nPkt The number of packets.
1455 */
1456 void AddPacket(Ptr<FqCobaltQueueDisc> queue, Ipv4Header hdr, uint32_t nPkt);
1457 /**
1458 * Enqueue the given number of packets at different times.
1459 * \param queue The queue disc.
1460 * \param hdr The IPv4 header.
1461 * \param delay The time between two consecutive enqueue operations.
1462 * \param nPkt The number of packets.
1463 */
1465 Ipv4Header hdr,
1466 double delay,
1467 uint32_t nPkt);
1468 /**
1469 * Dequeue the given number of packets.
1470 * \param queue The queue disc.
1471 * \param nPkt The number of packets.
1472 */
1473 void Dequeue(Ptr<FqCobaltQueueDisc> queue, uint32_t nPkt);
1474 /**
1475 * Dequeue the given number of packets at different times.
1476 * \param queue The queue disc.
1477 * \param delay The time between two consecutive dequeue operations.
1478 * \param nPkt The number of packets.
1479 */
1480 void DequeueWithDelay(Ptr<FqCobaltQueueDisc> queue, double delay, uint32_t nPkt);
1481};
1482
1484 : TestCase("Test L4S mode")
1485{
1486}
1487
1489{
1490}
1491
1492void
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
1504void
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
1521void
1523{
1524 for (uint32_t i = 0; i < nPkt; i++)
1525 {
1526 Ptr<QueueDiscItem> item = queue->Dequeue();
1527 }
1528}
1529
1530void
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
1545void
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",
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);
1573
1574 // Add 70 ECT1 (ECN capable) packets from the first flow
1575 // Set delay = 0.5ms
1576 double delay = 0.0005;
1579 this,
1580 queueDisc,
1581 hdr,
1582 delay,
1583 70);
1584
1585 // Add 70 ECT0 (ECN capable) packets from second flow
1587 hdr.SetDestination(Ipv4Address("10.10.1.10"));
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);
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
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",
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);
1655
1656 // Add 70 ECT1 (ECN capable) packets from the first flow
1657 // Set delay = 1ms
1658 delay = 0.001;
1661 this,
1662 queueDisc,
1663 hdr,
1664 1);
1667 this,
1668 queueDisc,
1669 hdr,
1670 delay,
1671 69);
1672
1673 // Add 70 ECT0 (ECN capable) packets from first flow
1677 this,
1678 queueDisc,
1679 hdr,
1680 delay,
1681 70);
1682
1683 // Dequeue 140 packets with delay 1ms
1684 DequeueWithDelay(queueDisc, delay, 140);
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
1707}
1708
1709/**
1710 * \ingroup system-tests-tc
1711 *
1712 * FQ-COBALT queue disc test suite.
1713 */
1715{
1716 public:
1718};
1719
1721 : TestSuite("fq-cobalt-queue-disc", Type::UNIT)
1722{
1723 AddTestCase(new FqCobaltQueueDiscNoSuitableFilter, TestCase::Duration::QUICK);
1724 AddTestCase(new FqCobaltQueueDiscIPFlowsSeparationAndPacketLimit, TestCase::Duration::QUICK);
1725 AddTestCase(new FqCobaltQueueDiscDeficit, TestCase::Duration::QUICK);
1726 AddTestCase(new FqCobaltQueueDiscTCPFlowsSeparation, TestCase::Duration::QUICK);
1727 AddTestCase(new FqCobaltQueueDiscUDPFlowsSeparation, TestCase::Duration::QUICK);
1728 AddTestCase(new FqCobaltQueueDiscEcnMarking, TestCase::Duration::QUICK);
1729 AddTestCase(new FqCobaltQueueDiscSetLinearProbing, TestCase::Duration::QUICK);
1730 AddTestCase(new FqCobaltQueueDiscL4sMode, TestCase::Duration::QUICK);
1731}
1732
1733/// Do not forget to allocate an instance of this TestSuite.
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
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Cobalt packet queue disc.
static constexpr const char * CE_THRESHOLD_EXCEEDED_MARK
Sojourn time above CE threshold.
static constexpr const char * TARGET_EXCEEDED_DROP
Sojourn time above target.
static constexpr const char * FORCED_MARK
forced marks by Codel on ECN-enabled
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
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static void Run()
Run the simulation.
Definition: simulator.cc:178
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
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:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition: nstime.h:297
AttributeValue implementation for Time.
Definition: nstime.h:1413
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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.
#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:145
#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:252
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
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