A Discrete-Event Network Simulator
API
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 
159 using namespace ns3;
160 
161 NS_LOG_COMPONENT_DEFINE("TcpValidation");
162 
163 // These variables are declared outside of main() so that they can
164 // be used in trace sinks.
165 uint32_t g_firstBytesReceived = 0;
166 uint32_t g_secondBytesReceived = 0;
167 uint32_t g_marksObserved = 0;
168 uint32_t g_dropsObserved = 0;
169 std::string g_validate = "";
170 bool g_validationFailed = false;
171 
179 void
180 TraceFirstCwnd(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 
225 void
226 TraceFirstDctcp(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 
277 void
278 TraceFirstRtt(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 
294 void
295 TraceSecondCwnd(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 
313 void
314 TraceSecondRtt(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 
331 void
332 TraceSecondDctcp(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 
346 void
347 TracePingRtt(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 
361 void
363 {
364  g_firstBytesReceived += packet->GetSize();
365 }
366 
373 void
375 {
376  g_secondBytesReceived += packet->GetSize();
377 }
378 
385 void
386 TraceQueueDrop(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  }
392  g_dropsObserved++;
393 }
394 
402 void
403 TraceQueueMark(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  }
409  g_marksObserved++;
410 }
411 
420 void
421 TraceQueueLength(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 
438 void
439 TraceMarksFrequency(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 
458 void
459 TraceFirstThroughput(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 
508 void
509 TraceSecondThroughput(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 
525 void
526 ScheduleFirstTcpCwndTraceConnection(std::ofstream* ofStream)
527 {
529  "/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
530  MakeBoundCallback(&TraceFirstCwnd, ofStream));
531 }
532 
538 void
539 ScheduleFirstTcpRttTraceConnection(std::ofstream* ofStream)
540 {
541  Config::ConnectWithoutContextFailSafe("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/RTT",
542  MakeBoundCallback(&TraceFirstRtt, ofStream));
543 }
544 
550 void
551 ScheduleFirstDctcpTraceConnection(std::ofstream* ofStream)
552 {
553  Config::ConnectWithoutContextFailSafe("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/"
554  "CongestionOps/$ns3::TcpDctcp/CongestionEstimate",
555  MakeBoundCallback(&TraceFirstDctcp, ofStream));
556 }
557 
563 void
564 ScheduleSecondDctcpTraceConnection(std::ofstream* ofStream)
565 {
566  Config::ConnectWithoutContextFailSafe("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/"
567  "CongestionOps/$ns3::TcpDctcp/CongestionEstimate",
568  MakeBoundCallback(&TraceSecondDctcp, ofStream));
569 }
570 
574 void
576 {
577  Config::ConnectWithoutContextFailSafe("/NodeList/6/ApplicationList/*/$ns3::PacketSink/Rx",
579 }
580 
586 void
587 ScheduleSecondTcpCwndTraceConnection(std::ofstream* ofStream)
588 {
589  Config::ConnectWithoutContext("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
590  MakeBoundCallback(&TraceSecondCwnd, ofStream));
591 }
592 
598 void
599 ScheduleSecondTcpRttTraceConnection(std::ofstream* ofStream)
600 {
601  Config::ConnectWithoutContext("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/RTT",
602  MakeBoundCallback(&TraceSecondRtt, ofStream));
603 }
604 
608 void
610 {
611  Config::ConnectWithoutContext("/NodeList/7/ApplicationList/*/$ns3::PacketSink/Rx",
613 }
614 
615 int
616 main(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  // Validation criteria were written for TCP Cubic without Reno-friendly behavior, so disable it
667  // for these tests
668  Config::SetDefault("ns3::TcpCubic::TcpFriendliness", BooleanValue(false));
669 
671  // command-line argument parsing //
673  CommandLine cmd(__FILE__);
674  cmd.AddValue("firstTcpType", "first TCP type (cubic, dctcp, or reno)", firstTcpType);
675  cmd.AddValue("secondTcpType", "second TCP type (cubic, dctcp, or reno)", secondTcpType);
676  cmd.AddValue("queueType", "bottleneck queue type (fq, codel, pie, or red)", queueType);
677  cmd.AddValue("baseRtt", "base RTT", baseRtt);
678  cmd.AddValue("ceThreshold", "CoDel CE threshold (for DCTCP)", ceThreshold);
679  cmd.AddValue("linkRate", "data rate of bottleneck link", linkRate);
680  cmd.AddValue("stopTime", "simulation stop time", stopTime);
681  cmd.AddValue("queueUseEcn", "use ECN on queue", queueUseEcn);
682  cmd.AddValue("enablePcap", "enable Pcap", enablePcap);
683  cmd.AddValue("validate", "validation case to run", g_validate);
684  cmd.Parse(argc, argv);
685 
686  // If validation is selected, perform some configuration checks
687  if (!g_validate.empty())
688  {
689  NS_ABORT_MSG_UNLESS(g_validate == "dctcp-10ms" || g_validate == "dctcp-80ms" ||
690  g_validate == "cubic-50ms-no-ecn" || g_validate == "cubic-50ms-ecn",
691  "Unknown test");
692  if (g_validate == "dctcp-10ms" || g_validate == "dctcp-80ms")
693  {
694  NS_ABORT_MSG_UNLESS(firstTcpType == "dctcp", "Incorrect TCP");
695  NS_ABORT_MSG_UNLESS(secondTcpType.empty(), "Incorrect TCP");
696  NS_ABORT_MSG_UNLESS(linkRate == DataRate("50Mbps"), "Incorrect data rate");
697  NS_ABORT_MSG_UNLESS(queueUseEcn == true, "Incorrect ECN configuration");
698  NS_ABORT_MSG_UNLESS(stopTime >= Seconds(15), "Incorrect stopTime");
699  if (g_validate == "dctcp-10ms")
700  {
701  NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(10), "Incorrect RTT");
702  }
703  else if (g_validate == "dctcp-80ms")
704  {
705  NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(80), "Incorrect RTT");
706  }
707  }
708  else if (g_validate == "cubic-50ms-no-ecn" || g_validate == "cubic-50ms-ecn")
709  {
710  NS_ABORT_MSG_UNLESS(firstTcpType == "cubic", "Incorrect TCP");
711  NS_ABORT_MSG_UNLESS(secondTcpType.empty(), "Incorrect TCP");
712  NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(50), "Incorrect RTT");
713  NS_ABORT_MSG_UNLESS(linkRate == DataRate("50Mbps"), "Incorrect data rate");
714  NS_ABORT_MSG_UNLESS(stopTime >= Seconds(20), "Incorrect stopTime");
715  if (g_validate == "cubic-50ms-no-ecn")
716  {
717  NS_ABORT_MSG_UNLESS(queueUseEcn == false, "Incorrect ECN configuration");
718  }
719  else if (g_validate == "cubic-50ms-ecn")
720  {
721  NS_ABORT_MSG_UNLESS(queueUseEcn == true, "Incorrect ECN configuration");
722  }
723  }
724  }
725 
726  if (enableLogging)
727  {
729  "TcpSocketBase",
732  "TcpDctcp",
734  }
735 
736  Time oneWayDelay = baseRtt / 2;
737 
738  TypeId firstTcpTypeId;
739  if (firstTcpType == "reno")
740  {
741  firstTcpTypeId = TcpLinuxReno::GetTypeId();
742  }
743  else if (firstTcpType == "cubic")
744  {
745  firstTcpTypeId = TcpCubic::GetTypeId();
746  }
747  else if (firstTcpType == "dctcp")
748  {
749  firstTcpTypeId = TcpDctcp::GetTypeId();
750  Config::SetDefault("ns3::CoDelQueueDisc::CeThreshold", TimeValue(ceThreshold));
751  Config::SetDefault("ns3::FqCoDelQueueDisc::CeThreshold", TimeValue(ceThreshold));
752  if (!queueUseEcn)
753  {
754  std::cout << "Warning: using DCTCP with queue ECN disabled" << std::endl;
755  }
756  }
757  else
758  {
759  NS_FATAL_ERROR("Fatal error: tcp unsupported");
760  }
761  TypeId secondTcpTypeId;
762  if (secondTcpType == "reno")
763  {
764  enableSecondTcp = true;
765  secondTcpTypeId = TcpLinuxReno::GetTypeId();
766  }
767  else if (secondTcpType == "cubic")
768  {
769  enableSecondTcp = true;
770  secondTcpTypeId = TcpCubic::GetTypeId();
771  }
772  else if (secondTcpType == "dctcp")
773  {
774  enableSecondTcp = true;
775  secondTcpTypeId = TcpDctcp::GetTypeId();
776  }
777  else if (secondTcpType.empty())
778  {
779  enableSecondTcp = false;
780  NS_LOG_DEBUG("No second TCP selected");
781  }
782  else
783  {
784  NS_FATAL_ERROR("Fatal error: tcp unsupported");
785  }
786  TypeId queueTypeId;
787  if (queueType == "fq")
788  {
789  queueTypeId = FqCoDelQueueDisc::GetTypeId();
790  }
791  else if (queueType == "codel")
792  {
793  queueTypeId = CoDelQueueDisc::GetTypeId();
794  }
795  else if (queueType == "pie")
796  {
797  queueTypeId = PieQueueDisc::GetTypeId();
798  }
799  else if (queueType == "red")
800  {
801  queueTypeId = RedQueueDisc::GetTypeId();
802  }
803  else
804  {
805  NS_FATAL_ERROR("Fatal error: queueType unsupported");
806  }
807 
808  if (queueUseEcn)
809  {
810  Config::SetDefault("ns3::CoDelQueueDisc::UseEcn", BooleanValue(true));
811  Config::SetDefault("ns3::FqCoDelQueueDisc::UseEcn", BooleanValue(true));
812  Config::SetDefault("ns3::PieQueueDisc::UseEcn", BooleanValue(true));
813  Config::SetDefault("ns3::RedQueueDisc::UseEcn", BooleanValue(true));
814  }
815  // Enable TCP to use ECN regardless
816  Config::SetDefault("ns3::TcpSocketBase::UseEcn", StringValue("On"));
817 
818  // Report on configuration
819  if (enableSecondTcp)
820  {
821  NS_LOG_DEBUG("first TCP: " << firstTcpTypeId.GetName()
822  << "; second TCP: " << secondTcpTypeId.GetName()
823  << "; queue: " << queueTypeId.GetName()
824  << "; ceThreshold: " << ceThreshold.GetSeconds() * 1000 << "ms");
825  }
826  else
827  {
828  NS_LOG_DEBUG("first TCP: " << firstTcpTypeId.GetName()
829  << "; queue: " << queueTypeId.GetName()
830  << "; ceThreshold: " << ceThreshold.GetSeconds() * 1000 << "ms");
831  }
832 
833  // Write traces only if we are not in validation mode (g_validate == "")
834  std::ofstream pingOfStream;
835  std::ofstream firstTcpRttOfStream;
836  std::ofstream firstTcpCwndOfStream;
837  std::ofstream firstTcpThroughputOfStream;
838  std::ofstream firstTcpDctcpOfStream;
839  std::ofstream secondTcpRttOfStream;
840  std::ofstream secondTcpCwndOfStream;
841  std::ofstream secondTcpThroughputOfStream;
842  std::ofstream secondTcpDctcpOfStream;
843  std::ofstream queueDropOfStream;
844  std::ofstream queueMarkOfStream;
845  std::ofstream queueMarksFrequencyOfStream;
846  std::ofstream queueLengthOfStream;
847  if (g_validate.empty())
848  {
849  pingOfStream.open(pingTraceFile, std::ofstream::out);
850  firstTcpRttOfStream.open(firstTcpRttTraceFile, std::ofstream::out);
851  firstTcpCwndOfStream.open(firstTcpCwndTraceFile, std::ofstream::out);
852  firstTcpThroughputOfStream.open(firstTcpThroughputTraceFile, std::ofstream::out);
853  if (firstTcpType == "dctcp")
854  {
855  firstTcpDctcpOfStream.open(firstDctcpTraceFile, std::ofstream::out);
856  }
857  if (enableSecondTcp)
858  {
859  secondTcpRttOfStream.open(secondTcpRttTraceFile, std::ofstream::out);
860  secondTcpCwndOfStream.open(secondTcpCwndTraceFile, std::ofstream::out);
861  secondTcpThroughputOfStream.open(secondTcpThroughputTraceFile, std::ofstream::out);
862  if (secondTcpType == "dctcp")
863  {
864  secondTcpDctcpOfStream.open(secondDctcpTraceFile, std::ofstream::out);
865  }
866  }
867  queueDropOfStream.open(queueDropTraceFile, std::ofstream::out);
868  queueMarkOfStream.open(queueMarkTraceFile, std::ofstream::out);
869  queueMarksFrequencyOfStream.open(queueMarksFrequencyTraceFile, std::ofstream::out);
870  queueLengthOfStream.open(queueLengthTraceFile, std::ofstream::out);
871  }
872 
874  // scenario setup //
876  Ptr<Node> pingServer = CreateObject<Node>();
877  Ptr<Node> firstServer = CreateObject<Node>();
878  Ptr<Node> secondServer = CreateObject<Node>();
879  Ptr<Node> wanRouter = CreateObject<Node>();
880  Ptr<Node> lanRouter = CreateObject<Node>();
881  Ptr<Node> pingClient = CreateObject<Node>();
882  Ptr<Node> firstClient = CreateObject<Node>();
883  Ptr<Node> secondClient = CreateObject<Node>();
884 
885  // Device containers
886  NetDeviceContainer pingServerDevices;
887  NetDeviceContainer firstServerDevices;
888  NetDeviceContainer secondServerDevices;
889  NetDeviceContainer wanLanDevices;
890  NetDeviceContainer pingClientDevices;
891  NetDeviceContainer firstClientDevices;
892  NetDeviceContainer secondClientDevices;
893 
895  p2p.SetQueue("ns3::DropTailQueue", "MaxSize", QueueSizeValue(QueueSize("3p")));
896  p2p.SetDeviceAttribute("DataRate", DataRateValue(DataRate("1000Mbps")));
897  // Add delay only on the WAN links
898  p2p.SetChannelAttribute("Delay", TimeValue(MicroSeconds(1)));
899  pingServerDevices = p2p.Install(wanRouter, pingServer);
900  firstServerDevices = p2p.Install(wanRouter, firstServer);
901  secondServerDevices = p2p.Install(wanRouter, secondServer);
902  p2p.SetChannelAttribute("Delay", TimeValue(oneWayDelay));
903  wanLanDevices = p2p.Install(wanRouter, lanRouter);
904  p2p.SetQueue("ns3::DropTailQueue", "MaxSize", QueueSizeValue(QueueSize("3p")));
905  p2p.SetChannelAttribute("Delay", TimeValue(MicroSeconds(1)));
906  pingClientDevices = p2p.Install(lanRouter, pingClient);
907  firstClientDevices = p2p.Install(lanRouter, firstClient);
908  secondClientDevices = p2p.Install(lanRouter, secondClient);
909 
910  // Limit the bandwidth on the wanRouter->lanRouter interface
911  Ptr<PointToPointNetDevice> p = wanLanDevices.Get(0)->GetObject<PointToPointNetDevice>();
912  p->SetAttribute("DataRate", DataRateValue(linkRate));
913 
914  InternetStackHelper stackHelper;
915  stackHelper.Install(pingServer);
916  Ptr<TcpL4Protocol> proto;
917  stackHelper.Install(firstServer);
918  proto = firstServer->GetObject<TcpL4Protocol>();
919  proto->SetAttribute("SocketType", TypeIdValue(firstTcpTypeId));
920  stackHelper.Install(secondServer);
921  stackHelper.Install(wanRouter);
922  stackHelper.Install(lanRouter);
923  stackHelper.Install(pingClient);
924 
925  stackHelper.Install(firstClient);
926  // Set the per-node TCP type here
927  proto = firstClient->GetObject<TcpL4Protocol>();
928  proto->SetAttribute("SocketType", TypeIdValue(firstTcpTypeId));
929  stackHelper.Install(secondClient);
930 
931  if (enableSecondTcp)
932  {
933  proto = secondClient->GetObject<TcpL4Protocol>();
934  proto->SetAttribute("SocketType", TypeIdValue(secondTcpTypeId));
935  proto = secondServer->GetObject<TcpL4Protocol>();
936  proto->SetAttribute("SocketType", TypeIdValue(secondTcpTypeId));
937  }
938 
939  // InternetStackHelper will install a base TrafficControlLayer on the node,
940  // but the Ipv4AddressHelper below will install the default FqCoDelQueueDisc
941  // on all single device nodes. The below code overrides the configuration
942  // that is normally done by the Ipv4AddressHelper::Install() method by
943  // instead explicitly configuring the queue discs we want on each device.
944  TrafficControlHelper tchFq;
945  tchFq.SetRootQueueDisc("ns3::FqCoDelQueueDisc");
946  tchFq.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1ms"));
947  tchFq.Install(pingServerDevices);
948  tchFq.Install(firstServerDevices);
949  tchFq.Install(secondServerDevices);
950  tchFq.Install(wanLanDevices.Get(1));
951  tchFq.Install(pingClientDevices);
952  tchFq.Install(firstClientDevices);
953  tchFq.Install(secondClientDevices);
954  // Install queue for bottleneck link
955  TrafficControlHelper tchBottleneck;
956  tchBottleneck.SetRootQueueDisc(queueTypeId.GetName());
957  tchBottleneck.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1ms"));
958  tchBottleneck.Install(wanLanDevices.Get(0));
959 
961  ipv4.SetBase("10.1.1.0", "255.255.255.0");
962  Ipv4InterfaceContainer pingServerIfaces = ipv4.Assign(pingServerDevices);
963  ipv4.SetBase("10.1.2.0", "255.255.255.0");
964  Ipv4InterfaceContainer firstServerIfaces = ipv4.Assign(firstServerDevices);
965  ipv4.SetBase("10.1.3.0", "255.255.255.0");
966  Ipv4InterfaceContainer secondServerIfaces = ipv4.Assign(secondServerDevices);
967  ipv4.SetBase("172.16.1.0", "255.255.255.0");
968  Ipv4InterfaceContainer wanLanIfaces = ipv4.Assign(wanLanDevices);
969  ipv4.SetBase("192.168.1.0", "255.255.255.0");
970  Ipv4InterfaceContainer pingClientIfaces = ipv4.Assign(pingClientDevices);
971  ipv4.SetBase("192.168.2.0", "255.255.255.0");
972  Ipv4InterfaceContainer firstClientIfaces = ipv4.Assign(firstClientDevices);
973  ipv4.SetBase("192.168.3.0", "255.255.255.0");
974  Ipv4InterfaceContainer secondClientIfaces = ipv4.Assign(secondClientDevices);
975 
977 
979  // application setup //
981  PingHelper pingHelper(Ipv4Address("192.168.1.2"));
982  pingHelper.SetAttribute("Interval", TimeValue(pingInterval));
983  pingHelper.SetAttribute("Size", UintegerValue(pingSize));
984  pingHelper.SetAttribute("VerboseMode", EnumValue(Ping::VerboseMode::SILENT));
985  ApplicationContainer pingContainer = pingHelper.Install(pingServer);
986  Ptr<Ping> ping = pingContainer.Get(0)->GetObject<Ping>();
987  ping->TraceConnectWithoutContext("Rtt", MakeBoundCallback(&TracePingRtt, &pingOfStream));
988  pingContainer.Start(Seconds(1));
989  pingContainer.Stop(stopTime - Seconds(1));
990 
991  ApplicationContainer firstApp;
992  uint16_t firstPort = 5000;
993  BulkSendHelper tcp("ns3::TcpSocketFactory", Address());
994  // set to large value: e.g. 1000 Mb/s for 60 seconds = 7500000000 bytes
995  tcp.SetAttribute("MaxBytes", UintegerValue(7500000000));
996  // Configure first TCP client/server pair
997  InetSocketAddress firstDestAddress(firstClientIfaces.GetAddress(1), firstPort);
998  tcp.SetAttribute("Remote", AddressValue(firstDestAddress));
999  firstApp = tcp.Install(firstServer);
1000  firstApp.Start(Seconds(5));
1001  firstApp.Stop(stopTime - Seconds(1));
1002 
1003  Address firstSinkAddress(InetSocketAddress(Ipv4Address::GetAny(), firstPort));
1004  ApplicationContainer firstSinkApp;
1005  PacketSinkHelper firstSinkHelper("ns3::TcpSocketFactory", firstSinkAddress);
1006  firstSinkApp = firstSinkHelper.Install(firstClient);
1007  firstSinkApp.Start(Seconds(5));
1008  firstSinkApp.Stop(stopTime - MilliSeconds(500));
1009 
1010  // Configure second TCP client/server pair
1011  if (enableSecondTcp)
1012  {
1013  BulkSendHelper tcp("ns3::TcpSocketFactory", Address());
1014  uint16_t secondPort = 5000;
1015  ApplicationContainer secondApp;
1016  InetSocketAddress secondDestAddress(secondClientIfaces.GetAddress(1), secondPort);
1017  tcp.SetAttribute("Remote", AddressValue(secondDestAddress));
1018  secondApp = tcp.Install(secondServer);
1019  secondApp.Start(Seconds(15));
1020  secondApp.Stop(stopTime - Seconds(1));
1021 
1022  Address secondSinkAddress(InetSocketAddress(Ipv4Address::GetAny(), secondPort));
1023  PacketSinkHelper secondSinkHelper("ns3::TcpSocketFactory", secondSinkAddress);
1024  ApplicationContainer secondSinkApp;
1025  secondSinkApp = secondSinkHelper.Install(secondClient);
1026  secondSinkApp.Start(Seconds(15));
1027  secondSinkApp.Stop(stopTime - MilliSeconds(500));
1028  }
1029 
1030  // Setup traces that can be hooked now
1032  Ptr<QueueDisc> qd;
1033  // Trace drops and marks for bottleneck
1034  tc = wanLanDevices.Get(0)->GetNode()->GetObject<TrafficControlLayer>();
1035  qd = tc->GetRootQueueDiscOnDevice(wanLanDevices.Get(0));
1036  qd->TraceConnectWithoutContext("Drop", MakeBoundCallback(&TraceQueueDrop, &queueDropOfStream));
1037  qd->TraceConnectWithoutContext("Mark", MakeBoundCallback(&TraceQueueMark, &queueMarkOfStream));
1039  "BytesInQueue",
1040  MakeBoundCallback(&TraceQueueLength, &queueLengthOfStream, linkRate));
1041 
1042  // Setup scheduled traces; TCP traces must be hooked after socket creation
1045  &firstTcpRttOfStream);
1048  &firstTcpCwndOfStream);
1050  if (firstTcpType == "dctcp")
1051  {
1054  &firstTcpDctcpOfStream);
1055  }
1056  Simulator::Schedule(throughputSamplingInterval,
1058  &firstTcpThroughputOfStream,
1059  throughputSamplingInterval);
1060  if (enableSecondTcp)
1061  {
1062  // Setup scheduled traces; TCP traces must be hooked after socket creation
1065  &secondTcpRttOfStream);
1068  &secondTcpCwndOfStream);
1070  Simulator::Schedule(throughputSamplingInterval,
1072  &secondTcpThroughputOfStream,
1073  throughputSamplingInterval);
1074  if (secondTcpType == "dctcp")
1075  {
1078  &secondTcpDctcpOfStream);
1079  }
1080  }
1081  Simulator::Schedule(marksSamplingInterval,
1083  &queueMarksFrequencyOfStream,
1084  marksSamplingInterval);
1085 
1086  if (enablePcap)
1087  {
1088  p2p.EnablePcapAll("tcp-validation", false);
1089  }
1090 
1092  Simulator::Run();
1094 
1095  if (g_validate.empty())
1096  {
1097  pingOfStream.close();
1098  firstTcpCwndOfStream.close();
1099  firstTcpRttOfStream.close();
1100  if (firstTcpType == "dctcp")
1101  {
1102  firstTcpDctcpOfStream.close();
1103  }
1104  firstTcpThroughputOfStream.close();
1105  if (enableSecondTcp)
1106  {
1107  secondTcpCwndOfStream.close();
1108  secondTcpRttOfStream.close();
1109  secondTcpThroughputOfStream.close();
1110  if (secondTcpType == "dctcp")
1111  {
1112  secondTcpDctcpOfStream.close();
1113  }
1114  }
1115  queueDropOfStream.close();
1116  queueMarkOfStream.close();
1117  queueMarksFrequencyOfStream.close();
1118  queueLengthOfStream.close();
1119  }
1120 
1121  if (g_validationFailed)
1122  {
1123  NS_FATAL_ERROR("Validation failed");
1124  }
1125 
1126  return 0;
1127 }
a polymophic address class
Definition: address.h:101
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.
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
Hold variables of type enum.
Definition: enum.h:62
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:315
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
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.
Class for representing queue sizes.
Definition: queue-size.h:96
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:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
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
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:403
@ S
second
Definition: nstime.h:116
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:991
Hold an unsigned integer type.
Definition: uinteger.h:45
Time stopTime
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:890
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition: config.cc:950
bool ConnectWithoutContextFailSafe(std::string path, const CallbackBase &cb)
Definition: config.cc:960
#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:765
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:327
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:305
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
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
address
Definition: first.py:47
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:704
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
cmd
Definition: second.py:40
std::ofstream throughput
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.