A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tcp-validation.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 Cable Television Laboratories, Inc.
3 * Copyright (c) 2020 Tom Henderson (adapted for DCTCP testing)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The names of the authors may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * Alternatively, provided that this notice is retained in full, this
18 * software may be distributed under the terms of the GNU General
19 * Public License ("GPL") version 2, in which case the provisions of the
20 * GPL apply INSTEAD OF those given above.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35// This program is designed to observe long-running TCP congestion control
36// behavior over a configurable bottleneck link. The program is also
37// instrumented to check program data against validated results, when
38// the validation option is enabled.
39//
40// ---> downstream (primary data transfer from servers to clients)
41// <--- upstream (return acks and ICMP echo response)
42//
43// ---- bottleneck link ----
44// servers ---| WR |--------------------| LR |--- clients
45// ---- ----
46// ns-3 node IDs:
47// nodes 0-2 3 4 5-7
48//
49// - The box WR is notionally a WAN router, aggregating all server links
50// - The box LR is notionally a LAN router, aggregating all client links
51// - Three servers are connected to WR, three clients are connected to LR
52//
53// clients and servers are configured for ICMP measurements and TCP throughput
54// and latency measurements in the downstream direction
55//
56// All link rates are enforced by a point-to-point (P2P) ns-3 model with full
57// duplex operation. Dynamic queue limits
58// (BQL) are enabled to allow for queueing to occur at the priority queue layer;
59// the notional P2P hardware device queue is limited to three packets.
60//
61// One-way link delays and link rates
62// -----------------------------------
63// (1) server to WR links, 1000 Mbps, 1us delay
64// (2) bottleneck link: configurable rate, configurable delay
65// (3) client to LR links, 1000 Mbps, 1us delay
66//
67// By default, ns-3 FQ-CoDel model is installed on all interfaces, but
68// the bottleneck queue uses CoDel by default and is configurable.
69//
70// The ns-3 FQ-CoDel model uses ns-3 defaults:
71// - 100ms interval
72// - 5ms target
73// - drop batch size of 64 packets
74// - minbytes of 1500
75//
76// Default simulation time is 70 sec. For single flow experiments, the flow is
77// started at simulation time 5 sec; if a second flow is used, it starts
78// at 15 sec.
79//
80// ping frequency is set at 100ms.
81//
82// A command-line option to enable a step-threshold CE threshold
83// from the CoDel queue model is provided.
84//
85// Measure:
86// - ping RTT
87// - TCP RTT estimate
88// - TCP throughput
89//
90// IPv4 addressing
91// ----------------------------
92// pingServer 10.1.1.2 (ping source)
93// firstServer 10.1.2.2 (data sender)
94// secondServer 10.1.3.2 (data sender)
95// pingClient 192.168.1.2
96// firstClient 192.168.2.2
97// secondClient 192.168.3.2
98//
99// Program Options:
100// ---------------
101// --firstTcpType: first TCP type (cubic, dctcp, or reno) [cubic]
102// --secondTcpType: second TCP type (cubic, dctcp, or reno) []
103// --queueType: bottleneck queue type (fq, codel, pie, or red) [codel]
104// --baseRtt: base RTT [+80ms]
105// --ceThreshold: CoDel CE threshold (for DCTCP) [+1ms]
106// --linkRate: data rate of bottleneck link [50000000bps]
107// --stopTime: simulation stop time [+1.16667min]
108// --queueUseEcn: use ECN on queue [false]
109// --enablePcap: enable Pcap [false]
110// --validate: validation case to run []
111//
112// validation cases (and syntax of how to run):
113// ------------
114// Case 'dctcp-10ms': DCTCP single flow, 10ms base RTT, 50 Mbps link, ECN enabled, CoDel:
115// ./ns3 run 'tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=10ms
116// --queueUseEcn=1 --stopTime=15s --validate=1 --validation=dctcp-10ms'
117// - Throughput between 48 Mbps and 49 Mbps for time greater than 5.6s
118// - DCTCP alpha below 0.1 for time greater than 5.4s
119// - DCTCP alpha between 0.06 and 0.085 for time greater than 7s
120//
121// Case 'dctcp-80ms': DCTCP single flow, 80ms base RTT, 50 Mbps link, ECN enabled, CoDel:
122// ./ns3 run 'tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=80ms
123// --queueUseEcn=1 --stopTime=40s --validate=1 --validation=dctcp-80ms'
124// - Throughput less than 20 Mbps for time less than 14s
125// - Throughput less than 48 Mbps for time less than 30s
126// - Throughput between 47.5 Mbps and 48.5 for time greater than 32s
127// - DCTCP alpha above 0.1 for time less than 7.5
128// - DCTCP alpha below 0.01 for time greater than 11 and less than 30
129// - DCTCP alpha between 0.015 and 0.025 for time greater than 34
130//
131// Case 'cubic-50ms-no-ecn': CUBIC single flow, 50ms base RTT, 50 Mbps link, ECN disabled, CoDel:
132// ./ns3 run 'tcp-validation --firstTcpType=cubic --linkRate=50Mbps --baseRtt=50ms
133// --queueUseEcn=0 --stopTime=20s --validate=1 --validation=cubic-50ms-no-ecn'
134// - Maximum value of cwnd is 511 segments at 5.4593 seconds
135// - cwnd decreases to 173 segments at 5.80304 seconds
136// - cwnd reaches another local maxima around 14.2815 seconds of 236 segments
137// - cwnd reaches a second maximum around 18.048 seconds of 234 segments
138//
139// Case 'cubic-50ms-ecn': CUBIC single flow, 50ms base RTT, 50 Mbps link, ECN enabled, CoDel:
140// ./ns3 run 'tcp-validation --firstTcpType=cubic --linkRate=50Mbps --baseRtt=50ms
141// --queueUseEcn=0 --stopTime=20s --validate=1 --validation=cubic-50ms-no-ecn'
142// - Maximum value of cwnd is 511 segments at 5.4593 seconds
143// - cwnd decreases to 173 segments at 5.7939 seconds
144// - cwnd reaches another local maxima around 14.3477 seconds of 236 segments
145// - cwnd reaches a second maximum around 18.064 seconds of 234 segments
146
147#include "ns3/applications-module.h"
148#include "ns3/core-module.h"
149#include "ns3/internet-apps-module.h"
150#include "ns3/internet-module.h"
151#include "ns3/network-module.h"
152#include "ns3/point-to-point-module.h"
153#include "ns3/traffic-control-module.h"
154
155#include <fstream>
156#include <iostream>
157#include <string>
158
159using namespace ns3;
160
161NS_LOG_COMPONENT_DEFINE("TcpValidation");
162
163// These variables are declared outside of main() so that they can
164// be used in trace sinks.
169std::string g_validate = "";
170bool g_validationFailed = false;
171
179void
180TraceFirstCwnd(std::ofstream* ofStream, uint32_t oldCwnd, uint32_t newCwnd)
181{
182 // TCP segment size is configured below to be 1448 bytes
183 // so that we can report cwnd in units of segments
184 if (g_validate.empty())
185 {
186 *ofStream << Simulator::Now().GetSeconds() << " " << static_cast<double>(newCwnd) / 1448
187 << std::endl;
188 }
189 // Validation checks; both the ECN enabled and disabled cases are similar
190 if (g_validate == "cubic-50ms-no-ecn" || g_validate == "cubic-50ms-ecn")
191 {
192 double now = Simulator::Now().GetSeconds();
193 double cwnd = static_cast<double>(newCwnd) / 1448;
194 if ((now > 5.43) && (now < 5.465) && (cwnd < 500))
195 {
196 NS_LOG_WARN("now " << Now().As(Time::S) << " cwnd " << cwnd << " (expected >= 500)");
197 g_validationFailed = true;
198 }
199 else if ((now > 5.795) && (now < 6) && (cwnd > 190))
200 {
201 NS_LOG_WARN("now " << Now().As(Time::S) << " cwnd " << cwnd << " (expected <= 190)");
202 g_validationFailed = true;
203 }
204 else if ((now > 14) && (now < 14.197) && (cwnd < 224))
205 {
206 NS_LOG_WARN("now " << Now().As(Time::S) << " cwnd " << cwnd << " (expected >= 224)");
207 g_validationFailed = true;
208 }
209 else if ((now > 17) && (now < 18.026) && (cwnd < 212))
210 {
211 NS_LOG_WARN("now " << Now().As(Time::S) << " cwnd " << cwnd << " (expected >= 212)");
212 g_validationFailed = true;
213 }
214 }
215}
216
225void
226TraceFirstDctcp(std::ofstream* ofStream, uint32_t bytesMarked, uint32_t bytesAcked, double alpha)
227{
228 if (g_validate.empty())
229 {
230 *ofStream << Simulator::Now().GetSeconds() << " " << alpha << std::endl;
231 }
232 // Validation checks
233 if (g_validate == "dctcp-80ms")
234 {
235 double now = Simulator::Now().GetSeconds();
236 if ((now < 7.5) && (alpha < 0.1))
237 {
238 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha << " (expected >= 0.1)");
239 g_validationFailed = true;
240 }
241 else if ((now > 11) && (now < 30) && (alpha > 0.01))
242 {
243 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha << " (expected <= 0.01)");
244 g_validationFailed = true;
245 }
246 else if ((now > 34) && (alpha < 0.015) && (alpha > 0.025))
247 {
248 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha
249 << " (expected 0.015 <= alpha <= 0.025)");
250 g_validationFailed = true;
251 }
252 }
253 else if (g_validate == "dctcp-10ms")
254 {
255 double now = Simulator::Now().GetSeconds();
256 if ((now > 5.6) && (alpha > 0.1))
257 {
258 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha << " (expected <= 0.1)");
259 g_validationFailed = true;
260 }
261 if ((now > 7) && ((alpha > 0.09) || (alpha < 0.055)))
262 {
263 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha
264 << " (expected 0.09 <= alpha <= 0.055)");
265 g_validationFailed = true;
266 }
267 }
268}
269
277void
278TraceFirstRtt(std::ofstream* ofStream, Time oldRtt, Time newRtt)
279{
280 if (g_validate.empty())
281 {
282 *ofStream << Simulator::Now().GetSeconds() << " " << newRtt.GetSeconds() * 1000
283 << std::endl;
284 }
285}
286
294void
295TraceSecondCwnd(std::ofstream* ofStream, uint32_t oldCwnd, uint32_t newCwnd)
296{
297 // TCP segment size is configured below to be 1448 bytes
298 // so that we can report cwnd in units of segments
299 if (g_validate.empty())
300 {
301 *ofStream << Simulator::Now().GetSeconds() << " " << static_cast<double>(newCwnd) / 1448
302 << std::endl;
303 }
304}
305
313void
314TraceSecondRtt(std::ofstream* ofStream, Time oldRtt, Time newRtt)
315{
316 if (g_validate.empty())
317 {
318 *ofStream << Simulator::Now().GetSeconds() << " " << newRtt.GetSeconds() * 1000
319 << std::endl;
320 }
321}
322
331void
332TraceSecondDctcp(std::ofstream* ofStream, uint32_t bytesMarked, uint32_t bytesAcked, double alpha)
333{
334 if (g_validate.empty())
335 {
336 *ofStream << Simulator::Now().GetSeconds() << " " << alpha << std::endl;
337 }
338}
339
346void
347TracePingRtt(std::ofstream* ofStream, uint16_t, Time rtt)
348{
349 if (g_validate.empty())
350 {
351 *ofStream << Simulator::Now().GetSeconds() << " " << rtt.GetSeconds() * 1000 << std::endl;
352 }
353}
354
361void
363{
364 g_firstBytesReceived += packet->GetSize();
365}
366
373void
375{
376 g_secondBytesReceived += packet->GetSize();
377}
378
385void
386TraceQueueDrop(std::ofstream* ofStream, Ptr<const QueueDiscItem> item)
387{
388 if (g_validate.empty())
389 {
390 *ofStream << Simulator::Now().GetSeconds() << " " << std::hex << item->Hash() << std::endl;
391 }
393}
394
402void
403TraceQueueMark(std::ofstream* ofStream, Ptr<const QueueDiscItem> item, const char* reason)
404{
405 if (g_validate.empty())
406 {
407 *ofStream << Simulator::Now().GetSeconds() << " " << std::hex << item->Hash() << std::endl;
408 }
410}
411
420void
421TraceQueueLength(std::ofstream* ofStream, DataRate queueLinkRate, uint32_t oldVal, uint32_t newVal)
422{
423 // output in units of ms
424 if (g_validate.empty())
425 {
426 *ofStream << Simulator::Now().GetSeconds() << " " << std::fixed
427 << static_cast<double>(newVal * 8) / (queueLinkRate.GetBitRate() / 1000)
428 << std::endl;
429 }
430}
431
438void
439TraceMarksFrequency(std::ofstream* ofStream, Time marksSamplingInterval)
440{
441 if (g_validate.empty())
442 {
443 *ofStream << Simulator::Now().GetSeconds() << " " << g_marksObserved << std::endl;
444 }
445 g_marksObserved = 0;
446 Simulator::Schedule(marksSamplingInterval,
448 ofStream,
449 marksSamplingInterval);
450}
451
458void
459TraceFirstThroughput(std::ofstream* ofStream, Time throughputInterval)
460{
461 double throughput = g_firstBytesReceived * 8 / throughputInterval.GetSeconds() / 1e6;
462 if (g_validate.empty())
463 {
464 *ofStream << Simulator::Now().GetSeconds() << " " << throughput << std::endl;
465 }
467 Simulator::Schedule(throughputInterval, &TraceFirstThroughput, ofStream, throughputInterval);
468 if (g_validate == "dctcp-80ms")
469 {
470 double now = Simulator::Now().GetSeconds();
471 if ((now < 14) && (throughput > 20))
472 {
473 NS_LOG_WARN("now " << Now().As(Time::S) << " throughput " << throughput
474 << " (expected <= 20)");
475 g_validationFailed = true;
476 }
477 if ((now < 30) && (throughput > 48))
478 {
479 NS_LOG_WARN("now " << Now().As(Time::S) << " throughput " << throughput
480 << " (expected <= 48)");
481 g_validationFailed = true;
482 }
483 if ((now > 32) && ((throughput < 47.5) || (throughput > 48.5)))
484 {
485 NS_LOG_WARN("now " << Now().As(Time::S) << " throughput " << throughput
486 << " (expected 47.5 <= throughput <= 48.5)");
487 g_validationFailed = true;
488 }
489 }
490 else if (g_validate == "dctcp-10ms")
491 {
492 double now = Simulator::Now().GetSeconds();
493 if ((now > 5.6) && ((throughput < 48) || (throughput > 49)))
494 {
495 NS_LOG_WARN("now " << Now().As(Time::S) << " throughput " << throughput
496 << " (expected 48 <= throughput <= 49)");
497 g_validationFailed = true;
498 }
499 }
500}
501
508void
509TraceSecondThroughput(std::ofstream* ofStream, Time throughputInterval)
510{
511 if (g_validate.empty())
512 {
513 *ofStream << Simulator::Now().GetSeconds() << " "
514 << g_secondBytesReceived * 8 / throughputInterval.GetSeconds() / 1e6 << std::endl;
515 }
517 Simulator::Schedule(throughputInterval, &TraceSecondThroughput, ofStream, throughputInterval);
518}
519
525void
527{
529 "/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
531}
532
538void
540{
541 Config::ConnectWithoutContextFailSafe("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/RTT",
542 MakeBoundCallback(&TraceFirstRtt, ofStream));
543}
544
550void
551ScheduleFirstDctcpTraceConnection(std::ofstream* ofStream)
552{
553 Config::ConnectWithoutContextFailSafe("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/"
554 "CongestionOps/$ns3::TcpDctcp/CongestionEstimate",
556}
557
563void
565{
566 Config::ConnectWithoutContextFailSafe("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/"
567 "CongestionOps/$ns3::TcpDctcp/CongestionEstimate",
569}
570
574void
576{
577 Config::ConnectWithoutContextFailSafe("/NodeList/6/ApplicationList/*/$ns3::PacketSink/Rx",
579}
580
586void
588{
589 Config::ConnectWithoutContext("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
591}
592
598void
600{
601 Config::ConnectWithoutContext("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/RTT",
603}
604
608void
610{
611 Config::ConnectWithoutContext("/NodeList/7/ApplicationList/*/$ns3::PacketSink/Rx",
613}
614
615int
616main(int argc, char* argv[])
617{
619 // variables not configured at command line //
621 uint32_t pingSize = 100; // bytes
622 bool enableSecondTcp = false;
623 bool enableLogging = false;
624 Time pingInterval = MilliSeconds(100);
625 Time marksSamplingInterval = MilliSeconds(100);
626 Time throughputSamplingInterval = MilliSeconds(200);
627 std::string pingTraceFile = "tcp-validation-ping.dat";
628 std::string firstTcpRttTraceFile = "tcp-validation-first-tcp-rtt.dat";
629 std::string firstTcpCwndTraceFile = "tcp-validation-first-tcp-cwnd.dat";
630 std::string firstDctcpTraceFile = "tcp-validation-first-dctcp-alpha.dat";
631 std::string firstTcpThroughputTraceFile = "tcp-validation-first-tcp-throughput.dat";
632 std::string secondTcpRttTraceFile = "tcp-validation-second-tcp-rtt.dat";
633 std::string secondTcpCwndTraceFile = "tcp-validation-second-tcp-cwnd.dat";
634 std::string secondTcpThroughputTraceFile = "tcp-validation-second-tcp-throughput.dat";
635 std::string secondDctcpTraceFile = "tcp-validation-second-dctcp-alpha.dat";
636 std::string queueMarkTraceFile = "tcp-validation-queue-mark.dat";
637 std::string queueDropTraceFile = "tcp-validation-queue-drop.dat";
638 std::string queueMarksFrequencyTraceFile = "tcp-validation-queue-marks-frequency.dat";
639 std::string queueLengthTraceFile = "tcp-validation-queue-length.dat";
640
642 // variables configured at command line //
644 std::string firstTcpType = "cubic";
645 std::string secondTcpType = "";
646 std::string queueType = "codel";
647 Time stopTime = Seconds(70);
648 Time baseRtt = MilliSeconds(80);
649 DataRate linkRate("50Mbps");
650 bool queueUseEcn = false;
651 Time ceThreshold = MilliSeconds(1);
652 bool enablePcap = false;
653
655 // Override ns-3 defaults //
657 Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(1448));
658 // Increase default buffer sizes to improve throughput over long delay paths
659 // Config::SetDefault ("ns3::TcpSocket::SndBufSize",UintegerValue (8192000));
660 // Config::SetDefault ("ns3::TcpSocket::RcvBufSize",UintegerValue (8192000));
661 Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(32768000));
662 Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(32768000));
663 Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10));
664 Config::SetDefault("ns3::TcpL4Protocol::RecoveryType",
666
668 // command-line argument parsing //
670 CommandLine cmd(__FILE__);
671 cmd.AddValue("firstTcpType", "first TCP type (cubic, dctcp, or reno)", firstTcpType);
672 cmd.AddValue("secondTcpType", "second TCP type (cubic, dctcp, or reno)", secondTcpType);
673 cmd.AddValue("queueType", "bottleneck queue type (fq, codel, pie, or red)", queueType);
674 cmd.AddValue("baseRtt", "base RTT", baseRtt);
675 cmd.AddValue("ceThreshold", "CoDel CE threshold (for DCTCP)", ceThreshold);
676 cmd.AddValue("linkRate", "data rate of bottleneck link", linkRate);
677 cmd.AddValue("stopTime", "simulation stop time", stopTime);
678 cmd.AddValue("queueUseEcn", "use ECN on queue", queueUseEcn);
679 cmd.AddValue("enablePcap", "enable Pcap", enablePcap);
680 cmd.AddValue("validate", "validation case to run", g_validate);
681 cmd.Parse(argc, argv);
682
683 // If validation is selected, perform some configuration checks
684 if (!g_validate.empty())
685 {
686 NS_ABORT_MSG_UNLESS(g_validate == "dctcp-10ms" || g_validate == "dctcp-80ms" ||
687 g_validate == "cubic-50ms-no-ecn" || g_validate == "cubic-50ms-ecn",
688 "Unknown test");
689 if (g_validate == "dctcp-10ms" || g_validate == "dctcp-80ms")
690 {
691 NS_ABORT_MSG_UNLESS(firstTcpType == "dctcp", "Incorrect TCP");
692 NS_ABORT_MSG_UNLESS(secondTcpType.empty(), "Incorrect TCP");
693 NS_ABORT_MSG_UNLESS(linkRate == DataRate("50Mbps"), "Incorrect data rate");
694 NS_ABORT_MSG_UNLESS(queueUseEcn == true, "Incorrect ECN configuration");
695 NS_ABORT_MSG_UNLESS(stopTime >= Seconds(15), "Incorrect stopTime");
696 if (g_validate == "dctcp-10ms")
697 {
698 NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(10), "Incorrect RTT");
699 }
700 else if (g_validate == "dctcp-80ms")
701 {
702 NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(80), "Incorrect RTT");
703 }
704 }
705 else if (g_validate == "cubic-50ms-no-ecn" || g_validate == "cubic-50ms-ecn")
706 {
707 NS_ABORT_MSG_UNLESS(firstTcpType == "cubic", "Incorrect TCP");
708 NS_ABORT_MSG_UNLESS(secondTcpType.empty(), "Incorrect TCP");
709 NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(50), "Incorrect RTT");
710 NS_ABORT_MSG_UNLESS(linkRate == DataRate("50Mbps"), "Incorrect data rate");
711 NS_ABORT_MSG_UNLESS(stopTime >= Seconds(20), "Incorrect stopTime");
712 if (g_validate == "cubic-50ms-no-ecn")
713 {
714 NS_ABORT_MSG_UNLESS(queueUseEcn == false, "Incorrect ECN configuration");
715 }
716 else if (g_validate == "cubic-50ms-ecn")
717 {
718 NS_ABORT_MSG_UNLESS(queueUseEcn == true, "Incorrect ECN configuration");
719 }
720 }
721 }
722
723 if (enableLogging)
724 {
726 "TcpSocketBase",
729 "TcpDctcp",
731 }
732
733 Time oneWayDelay = baseRtt / 2;
734
735 TypeId firstTcpTypeId;
736 if (firstTcpType == "reno")
737 {
738 firstTcpTypeId = TcpLinuxReno::GetTypeId();
739 }
740 else if (firstTcpType == "cubic")
741 {
742 firstTcpTypeId = TcpCubic::GetTypeId();
743 }
744 else if (firstTcpType == "dctcp")
745 {
746 firstTcpTypeId = TcpDctcp::GetTypeId();
747 Config::SetDefault("ns3::CoDelQueueDisc::CeThreshold", TimeValue(ceThreshold));
748 Config::SetDefault("ns3::FqCoDelQueueDisc::CeThreshold", TimeValue(ceThreshold));
749 if (!queueUseEcn)
750 {
751 std::cout << "Warning: using DCTCP with queue ECN disabled" << std::endl;
752 }
753 }
754 else
755 {
756 NS_FATAL_ERROR("Fatal error: tcp unsupported");
757 }
758 TypeId secondTcpTypeId;
759 if (secondTcpType == "reno")
760 {
761 enableSecondTcp = true;
762 secondTcpTypeId = TcpLinuxReno::GetTypeId();
763 }
764 else if (secondTcpType == "cubic")
765 {
766 enableSecondTcp = true;
767 secondTcpTypeId = TcpCubic::GetTypeId();
768 }
769 else if (secondTcpType == "dctcp")
770 {
771 enableSecondTcp = true;
772 secondTcpTypeId = TcpDctcp::GetTypeId();
773 }
774 else if (secondTcpType.empty())
775 {
776 enableSecondTcp = false;
777 NS_LOG_DEBUG("No second TCP selected");
778 }
779 else
780 {
781 NS_FATAL_ERROR("Fatal error: tcp unsupported");
782 }
783 TypeId queueTypeId;
784 if (queueType == "fq")
785 {
786 queueTypeId = FqCoDelQueueDisc::GetTypeId();
787 }
788 else if (queueType == "codel")
789 {
790 queueTypeId = CoDelQueueDisc::GetTypeId();
791 }
792 else if (queueType == "pie")
793 {
794 queueTypeId = PieQueueDisc::GetTypeId();
795 }
796 else if (queueType == "red")
797 {
798 queueTypeId = RedQueueDisc::GetTypeId();
799 }
800 else
801 {
802 NS_FATAL_ERROR("Fatal error: queueType unsupported");
803 }
804
805 if (queueUseEcn)
806 {
807 Config::SetDefault("ns3::CoDelQueueDisc::UseEcn", BooleanValue(true));
808 Config::SetDefault("ns3::FqCoDelQueueDisc::UseEcn", BooleanValue(true));
809 Config::SetDefault("ns3::PieQueueDisc::UseEcn", BooleanValue(true));
810 Config::SetDefault("ns3::RedQueueDisc::UseEcn", BooleanValue(true));
811 }
812 // Enable TCP to use ECN regardless
813 Config::SetDefault("ns3::TcpSocketBase::UseEcn", StringValue("On"));
814
815 // Report on configuration
816 if (enableSecondTcp)
817 {
818 NS_LOG_DEBUG("first TCP: " << firstTcpTypeId.GetName()
819 << "; second TCP: " << secondTcpTypeId.GetName()
820 << "; queue: " << queueTypeId.GetName()
821 << "; ceThreshold: " << ceThreshold.GetSeconds() * 1000 << "ms");
822 }
823 else
824 {
825 NS_LOG_DEBUG("first TCP: " << firstTcpTypeId.GetName()
826 << "; queue: " << queueTypeId.GetName()
827 << "; ceThreshold: " << ceThreshold.GetSeconds() * 1000 << "ms");
828 }
829
830 // Write traces only if we are not in validation mode (g_validate == "")
831 std::ofstream pingOfStream;
832 std::ofstream firstTcpRttOfStream;
833 std::ofstream firstTcpCwndOfStream;
834 std::ofstream firstTcpThroughputOfStream;
835 std::ofstream firstTcpDctcpOfStream;
836 std::ofstream secondTcpRttOfStream;
837 std::ofstream secondTcpCwndOfStream;
838 std::ofstream secondTcpThroughputOfStream;
839 std::ofstream secondTcpDctcpOfStream;
840 std::ofstream queueDropOfStream;
841 std::ofstream queueMarkOfStream;
842 std::ofstream queueMarksFrequencyOfStream;
843 std::ofstream queueLengthOfStream;
844 if (g_validate.empty())
845 {
846 pingOfStream.open(pingTraceFile, std::ofstream::out);
847 firstTcpRttOfStream.open(firstTcpRttTraceFile, std::ofstream::out);
848 firstTcpCwndOfStream.open(firstTcpCwndTraceFile, std::ofstream::out);
849 firstTcpThroughputOfStream.open(firstTcpThroughputTraceFile, std::ofstream::out);
850 if (firstTcpType == "dctcp")
851 {
852 firstTcpDctcpOfStream.open(firstDctcpTraceFile, std::ofstream::out);
853 }
854 if (enableSecondTcp)
855 {
856 secondTcpRttOfStream.open(secondTcpRttTraceFile, std::ofstream::out);
857 secondTcpCwndOfStream.open(secondTcpCwndTraceFile, std::ofstream::out);
858 secondTcpThroughputOfStream.open(secondTcpThroughputTraceFile, std::ofstream::out);
859 if (secondTcpType == "dctcp")
860 {
861 secondTcpDctcpOfStream.open(secondDctcpTraceFile, std::ofstream::out);
862 }
863 }
864 queueDropOfStream.open(queueDropTraceFile, std::ofstream::out);
865 queueMarkOfStream.open(queueMarkTraceFile, std::ofstream::out);
866 queueMarksFrequencyOfStream.open(queueMarksFrequencyTraceFile, std::ofstream::out);
867 queueLengthOfStream.open(queueLengthTraceFile, std::ofstream::out);
868 }
869
871 // scenario setup //
873 Ptr<Node> pingServer = CreateObject<Node>();
874 Ptr<Node> firstServer = CreateObject<Node>();
875 Ptr<Node> secondServer = CreateObject<Node>();
876 Ptr<Node> wanRouter = CreateObject<Node>();
877 Ptr<Node> lanRouter = CreateObject<Node>();
878 Ptr<Node> pingClient = CreateObject<Node>();
879 Ptr<Node> firstClient = CreateObject<Node>();
880 Ptr<Node> secondClient = CreateObject<Node>();
881
882 // Device containers
883 NetDeviceContainer pingServerDevices;
884 NetDeviceContainer firstServerDevices;
885 NetDeviceContainer secondServerDevices;
886 NetDeviceContainer wanLanDevices;
887 NetDeviceContainer pingClientDevices;
888 NetDeviceContainer firstClientDevices;
889 NetDeviceContainer secondClientDevices;
890
892 p2p.SetQueue("ns3::DropTailQueue", "MaxSize", QueueSizeValue(QueueSize("3p")));
893 p2p.SetDeviceAttribute("DataRate", DataRateValue(DataRate("1000Mbps")));
894 // Add delay only on the WAN links
895 p2p.SetChannelAttribute("Delay", TimeValue(MicroSeconds(1)));
896 pingServerDevices = p2p.Install(wanRouter, pingServer);
897 firstServerDevices = p2p.Install(wanRouter, firstServer);
898 secondServerDevices = p2p.Install(wanRouter, secondServer);
899 p2p.SetChannelAttribute("Delay", TimeValue(oneWayDelay));
900 wanLanDevices = p2p.Install(wanRouter, lanRouter);
901 p2p.SetQueue("ns3::DropTailQueue", "MaxSize", QueueSizeValue(QueueSize("3p")));
902 p2p.SetChannelAttribute("Delay", TimeValue(MicroSeconds(1)));
903 pingClientDevices = p2p.Install(lanRouter, pingClient);
904 firstClientDevices = p2p.Install(lanRouter, firstClient);
905 secondClientDevices = p2p.Install(lanRouter, secondClient);
906
907 // Limit the bandwidth on the wanRouter->lanRouter interface
908 Ptr<PointToPointNetDevice> p = wanLanDevices.Get(0)->GetObject<PointToPointNetDevice>();
909 p->SetAttribute("DataRate", DataRateValue(linkRate));
910
911 InternetStackHelper stackHelper;
912 stackHelper.Install(pingServer);
913 Ptr<TcpL4Protocol> proto;
914 stackHelper.Install(firstServer);
915 proto = firstServer->GetObject<TcpL4Protocol>();
916 proto->SetAttribute("SocketType", TypeIdValue(firstTcpTypeId));
917 stackHelper.Install(secondServer);
918 stackHelper.Install(wanRouter);
919 stackHelper.Install(lanRouter);
920 stackHelper.Install(pingClient);
921
922 stackHelper.Install(firstClient);
923 // Set the per-node TCP type here
924 proto = firstClient->GetObject<TcpL4Protocol>();
925 proto->SetAttribute("SocketType", TypeIdValue(firstTcpTypeId));
926 stackHelper.Install(secondClient);
927
928 if (enableSecondTcp)
929 {
930 proto = secondClient->GetObject<TcpL4Protocol>();
931 proto->SetAttribute("SocketType", TypeIdValue(secondTcpTypeId));
932 proto = secondServer->GetObject<TcpL4Protocol>();
933 proto->SetAttribute("SocketType", TypeIdValue(secondTcpTypeId));
934 }
935
936 // InternetStackHelper will install a base TrafficControlLayer on the node,
937 // but the Ipv4AddressHelper below will install the default FqCoDelQueueDisc
938 // on all single device nodes. The below code overrides the configuration
939 // that is normally done by the Ipv4AddressHelper::Install() method by
940 // instead explicitly configuring the queue discs we want on each device.
942 tchFq.SetRootQueueDisc("ns3::FqCoDelQueueDisc");
943 tchFq.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1ms"));
944 tchFq.Install(pingServerDevices);
945 tchFq.Install(firstServerDevices);
946 tchFq.Install(secondServerDevices);
947 tchFq.Install(wanLanDevices.Get(1));
948 tchFq.Install(pingClientDevices);
949 tchFq.Install(firstClientDevices);
950 tchFq.Install(secondClientDevices);
951 // Install queue for bottleneck link
952 TrafficControlHelper tchBottleneck;
953 tchBottleneck.SetRootQueueDisc(queueTypeId.GetName());
954 tchBottleneck.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1ms"));
955 tchBottleneck.Install(wanLanDevices.Get(0));
956
958 ipv4.SetBase("10.1.1.0", "255.255.255.0");
959 Ipv4InterfaceContainer pingServerIfaces = ipv4.Assign(pingServerDevices);
960 ipv4.SetBase("10.1.2.0", "255.255.255.0");
961 Ipv4InterfaceContainer firstServerIfaces = ipv4.Assign(firstServerDevices);
962 ipv4.SetBase("10.1.3.0", "255.255.255.0");
963 Ipv4InterfaceContainer secondServerIfaces = ipv4.Assign(secondServerDevices);
964 ipv4.SetBase("172.16.1.0", "255.255.255.0");
965 Ipv4InterfaceContainer wanLanIfaces = ipv4.Assign(wanLanDevices);
966 ipv4.SetBase("192.168.1.0", "255.255.255.0");
967 Ipv4InterfaceContainer pingClientIfaces = ipv4.Assign(pingClientDevices);
968 ipv4.SetBase("192.168.2.0", "255.255.255.0");
969 Ipv4InterfaceContainer firstClientIfaces = ipv4.Assign(firstClientDevices);
970 ipv4.SetBase("192.168.3.0", "255.255.255.0");
971 Ipv4InterfaceContainer secondClientIfaces = ipv4.Assign(secondClientDevices);
972
974
976 // application setup //
978 PingHelper pingHelper(Ipv4Address("192.168.1.2"));
979 pingHelper.SetAttribute("Interval", TimeValue(pingInterval));
980 pingHelper.SetAttribute("Size", UintegerValue(pingSize));
981 pingHelper.SetAttribute("VerboseMode", EnumValue(Ping::VerboseMode::SILENT));
982 ApplicationContainer pingContainer = pingHelper.Install(pingServer);
983 Ptr<Ping> ping = pingContainer.Get(0)->GetObject<Ping>();
984 ping->TraceConnectWithoutContext("Rtt", MakeBoundCallback(&TracePingRtt, &pingOfStream));
985 pingContainer.Start(Seconds(1));
986 pingContainer.Stop(stopTime - Seconds(1));
987
988 ApplicationContainer firstApp;
989 uint16_t firstPort = 5000;
990 BulkSendHelper tcp("ns3::TcpSocketFactory", Address());
991 // set to large value: e.g. 1000 Mb/s for 60 seconds = 7500000000 bytes
992 tcp.SetAttribute("MaxBytes", UintegerValue(7500000000));
993 // Configure first TCP client/server pair
994 InetSocketAddress firstDestAddress(firstClientIfaces.GetAddress(1), firstPort);
995 tcp.SetAttribute("Remote", AddressValue(firstDestAddress));
996 firstApp = tcp.Install(firstServer);
997 firstApp.Start(Seconds(5));
998 firstApp.Stop(stopTime - Seconds(1));
999
1000 Address firstSinkAddress(InetSocketAddress(Ipv4Address::GetAny(), firstPort));
1001 ApplicationContainer firstSinkApp;
1002 PacketSinkHelper firstSinkHelper("ns3::TcpSocketFactory", firstSinkAddress);
1003 firstSinkApp = firstSinkHelper.Install(firstClient);
1004 firstSinkApp.Start(Seconds(5));
1005 firstSinkApp.Stop(stopTime - MilliSeconds(500));
1006
1007 // Configure second TCP client/server pair
1008 if (enableSecondTcp)
1009 {
1010 BulkSendHelper tcp("ns3::TcpSocketFactory", Address());
1011 uint16_t secondPort = 5000;
1012 ApplicationContainer secondApp;
1013 InetSocketAddress secondDestAddress(secondClientIfaces.GetAddress(1), secondPort);
1014 tcp.SetAttribute("Remote", AddressValue(secondDestAddress));
1015 secondApp = tcp.Install(secondServer);
1016 secondApp.Start(Seconds(15));
1017 secondApp.Stop(stopTime - Seconds(1));
1018
1019 Address secondSinkAddress(InetSocketAddress(Ipv4Address::GetAny(), secondPort));
1020 PacketSinkHelper secondSinkHelper("ns3::TcpSocketFactory", secondSinkAddress);
1021 ApplicationContainer secondSinkApp;
1022 secondSinkApp = secondSinkHelper.Install(secondClient);
1023 secondSinkApp.Start(Seconds(15));
1024 secondSinkApp.Stop(stopTime - MilliSeconds(500));
1025 }
1026
1027 // Setup traces that can be hooked now
1029 Ptr<QueueDisc> qd;
1030 // Trace drops and marks for bottleneck
1031 tc = wanLanDevices.Get(0)->GetNode()->GetObject<TrafficControlLayer>();
1032 qd = tc->GetRootQueueDiscOnDevice(wanLanDevices.Get(0));
1033 qd->TraceConnectWithoutContext("Drop", MakeBoundCallback(&TraceQueueDrop, &queueDropOfStream));
1034 qd->TraceConnectWithoutContext("Mark", MakeBoundCallback(&TraceQueueMark, &queueMarkOfStream));
1036 "BytesInQueue",
1037 MakeBoundCallback(&TraceQueueLength, &queueLengthOfStream, linkRate));
1038
1039 // Setup scheduled traces; TCP traces must be hooked after socket creation
1042 &firstTcpRttOfStream);
1045 &firstTcpCwndOfStream);
1047 if (firstTcpType == "dctcp")
1048 {
1051 &firstTcpDctcpOfStream);
1052 }
1053 Simulator::Schedule(throughputSamplingInterval,
1055 &firstTcpThroughputOfStream,
1056 throughputSamplingInterval);
1057 if (enableSecondTcp)
1058 {
1059 // Setup scheduled traces; TCP traces must be hooked after socket creation
1062 &secondTcpRttOfStream);
1065 &secondTcpCwndOfStream);
1067 Simulator::Schedule(throughputSamplingInterval,
1069 &secondTcpThroughputOfStream,
1070 throughputSamplingInterval);
1071 if (secondTcpType == "dctcp")
1072 {
1075 &secondTcpDctcpOfStream);
1076 }
1077 }
1078 Simulator::Schedule(marksSamplingInterval,
1080 &queueMarksFrequencyOfStream,
1081 marksSamplingInterval);
1082
1083 if (enablePcap)
1084 {
1085 p2p.EnablePcapAll("tcp-validation", false);
1086 }
1087
1091
1092 if (g_validate.empty())
1093 {
1094 pingOfStream.close();
1095 firstTcpCwndOfStream.close();
1096 firstTcpRttOfStream.close();
1097 if (firstTcpType == "dctcp")
1098 {
1099 firstTcpDctcpOfStream.close();
1100 }
1101 firstTcpThroughputOfStream.close();
1102 if (enableSecondTcp)
1103 {
1104 secondTcpCwndOfStream.close();
1105 secondTcpRttOfStream.close();
1106 secondTcpThroughputOfStream.close();
1107 if (secondTcpType == "dctcp")
1108 {
1109 secondTcpDctcpOfStream.close();
1110 }
1111 }
1112 queueDropOfStream.close();
1113 queueMarkOfStream.close();
1114 queueMarksFrequencyOfStream.close();
1115 queueLengthOfStream.close();
1116 }
1117
1119 {
1120 NS_FATAL_ERROR("Validation failed");
1121 }
1122
1123 return 0;
1124}
a polymophic address class
Definition: address.h:100
AttributeValue implementation for Address.
holds a vector of ns3::Application pointers.
void Start(Time start) const
Start all of the Applications in this container at the start time given as a parameter.
Ptr< Application > Get(uint32_t i) const
Get the Ptr<Application> stored in this container at a given index.
void Stop(Time stop) const
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter.
AttributeValue implementation for Boolean.
Definition: boolean.h:37
A helper to make it easier to instantiate an ns3::BulkSendApplication on a set of nodes.
static TypeId GetTypeId()
Get the type ID.
Parse command-line arguments.
Definition: command-line.h:232
Class for representing data rates.
Definition: data-rate.h:89
uint64_t GetBitRate() const
Get the underlying bitrate.
Definition: data-rate.cc:305
AttributeValue implementation for DataRate.
Hold variables of type enum.
Definition: enum.h:56
static TypeId GetTypeId()
Get the type ID.
an Inet address class
aggregate IP/TCP/UDP functionality to existing Nodes.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
static Ipv4Address GetAny()
static void PopulateRoutingTables()
Build a routing database and initialize the routing tables of the nodes in the simulation.
holds a vector of std::pair of Ptr<Ipv4> and interface index.
Ipv4Address GetAddress(uint32_t i, uint32_t j=0) const
holds a vector of ns3::NetDevice pointers
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:311
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
A helper to make it easier to instantiate an ns3::PacketSinkApplication on a set of nodes.
static TypeId GetTypeId()
Get the type ID.
Create a ping application and associate it to a node.
Definition: ping-helper.h:48
This application behaves similarly to the Unix ping application, although with fewer options supporte...
Definition: ping.h:56
Build a set of PointToPointNetDevice objects.
A Device for a Point to Point Network Link.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
Class for representing queue sizes.
Definition: queue-size.h:96
AttributeValue implementation for QueueSize.
static TypeId GetTypeId()
Get the type ID.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:140
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static void Run()
Run the simulation.
Definition: simulator.cc:176
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:184
Hold variables of type string.
Definition: string.h:56
static TypeId GetTypeId()
Get the type ID.
Definition: tcp-cubic.cc:36
static TypeId GetTypeId()
Get the type ID.
Definition: tcp-dctcp.cc:36
TCP socket creation and multiplexing/demultiplexing.
static TypeId GetTypeId()
Get the type ID.
static TypeId GetTypeId()
Get the type ID.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
@ S
second
Definition: nstime.h:116
AttributeValue implementation for Time.
Definition: nstime.h:1423
Build a set of QueueDisc objects.
QueueDiscContainer Install(NetDeviceContainer c)
uint16_t SetRootQueueDisc(const std::string &type, Args &&... args)
Helper function used to set a root queue disc of the given type and with the given attributes.
void SetQueueLimits(std::string type, Args &&... args)
Helper function used to add a queue limits object to the transmission queues of the devices.
The Traffic Control layer aims at introducing an equivalent of the Linux Traffic Control infrastructu...
a unique identifier for an interface.
Definition: type-id.h:59
std::string GetName() const
Get the name.
Definition: type-id.cc:996
AttributeValue implementation for TypeId.
Definition: type-id.h:598
Hold an unsigned integer type.
Definition: uinteger.h:45
Time stopTime
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:891
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition: config.cc:951
bool ConnectWithoutContextFailSafe(std::string path, const CallbackBase &cb)
Definition: config.cc:961
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition: callback.h:763
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1360
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void LogComponentEnable(const std::string &name, LogLevel level)
Enable the logging output associated with that log component.
Definition: log.cc:302
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:702
LogLevel
Logging severity classes and levels.
Definition: log.h:94
@ LOG_LEVEL_ALL
Print everything.
Definition: log.h:116
@ LOG_PREFIX_FUNC
Prefix all trace prints with function.
Definition: log.h:118
@ LOG_PREFIX_TIME
Prefix all trace prints with simulation time.
Definition: log.h:119
@ LOG_PREFIX_NODE
Prefix all trace prints with simulation node.
Definition: log.h:120
ns cmd
Definition: second.py:33
void TracePingRtt(std::ofstream *ofStream, uint16_t, Time rtt)
Trace ping RTT.
void ScheduleSecondDctcpTraceConnection(std::ofstream *ofStream)
Schedule trace connection.
void TraceMarksFrequency(std::ofstream *ofStream, Time marksSamplingInterval)
Trace marks frequency.
void ScheduleSecondTcpRttTraceConnection(std::ofstream *ofStream)
Schedule trace connection.
void TraceSecondRtt(std::ofstream *ofStream, Time oldRtt, Time newRtt)
Trace second RTT.
void TraceSecondDctcp(std::ofstream *ofStream, uint32_t bytesMarked, uint32_t bytesAcked, double alpha)
Trace second TcpDctcp.
void TraceSecondThroughput(std::ofstream *ofStream, Time throughputInterval)
Trace the second throughput.
void TraceFirstThroughput(std::ofstream *ofStream, Time throughputInterval)
Trace the first throughput.
void ScheduleFirstDctcpTraceConnection(std::ofstream *ofStream)
Schedule trace connection.
void TraceSecondCwnd(std::ofstream *ofStream, uint32_t oldCwnd, uint32_t newCwnd)
Trace second congestion window.
void TraceQueueMark(std::ofstream *ofStream, Ptr< const QueueDiscItem > item, const char *reason)
Trace queue marks.
bool g_validationFailed
True if validation failed.
void ScheduleFirstPacketSinkConnection()
Schedule trace connection.
void TraceQueueLength(std::ofstream *ofStream, DataRate queueLinkRate, uint32_t oldVal, uint32_t newVal)
Trace queue length.
void TraceFirstRx(Ptr< const Packet > packet, const Address &address)
Trace first Rx.
void TraceFirstCwnd(std::ofstream *ofStream, uint32_t oldCwnd, uint32_t newCwnd)
Trace first congestion window.
void TraceQueueDrop(std::ofstream *ofStream, Ptr< const QueueDiscItem > item)
Trace queue drop.
uint32_t g_marksObserved
Number of marked packets observed.
void ScheduleSecondPacketSinkConnection()
Schedule trace connection.
void ScheduleSecondTcpCwndTraceConnection(std::ofstream *ofStream)
Schedule trace connection.
void TraceSecondRx(Ptr< const Packet > packet, const Address &address)
Trace second Rx.
void TraceFirstRtt(std::ofstream *ofStream, Time oldRtt, Time newRtt)
Trace first RTT.
uint32_t g_firstBytesReceived
First received packet size.
std::string g_validate
Empty string disables validation.
uint32_t g_secondBytesReceived
Second received packet size.
uint32_t g_dropsObserved
Number of dropped packets observed.
void TraceFirstDctcp(std::ofstream *ofStream, uint32_t bytesMarked, uint32_t bytesAcked, double alpha)
Trace first TcpDctcp.
void ScheduleFirstTcpRttTraceConnection(std::ofstream *ofStream)
Schedule trace connection.
void ScheduleFirstTcpCwndTraceConnection(std::ofstream *ofStream)
Schedule trace connection.