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 
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 == false)
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 
891  PointToPointHelper p2p;
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 TrafficControLayer 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.
941  TrafficControlHelper tchFq;
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 
957  Ipv4AddressHelper ipv4;
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 
1089  Simulator::Run();
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 
1118  if (g_validationFailed)
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:90
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.
void SetBase(Ipv4Address network, Ipv4Mask mask, Ipv4Address base="0.0.0.1")
Set the base network number, network mask and base address.
Ipv4InterfaceContainer Assign(const NetDeviceContainer &c)
Assign IP addresses to the net devices specified in the container based on the current network prefix...
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:43
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
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
A helper to make it easier to instantiate an ns3::PacketSinkApplication on a set of nodes.
void EnablePcapAll(std::string prefix, bool promiscuous=false)
Enable pcap output on each device (which is of the appropriate type) in the set of all nodes created ...
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.
void SetDeviceAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each NetDevice created by the helper.
void SetChannelAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each Channel created by the helper.
void SetQueue(std::string type, Ts &&... args)
Each point to point net device must have a queue to pass packets through.
NetDeviceContainer Install(NodeContainer c)
A Device for a Point to Point Network Link.
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:35
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:60
std::string GetName() const
Get the name.
Definition: type-id.cc:995
AttributeValue implementation for TypeId.
Definition: type-id.h:600
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:768
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:328
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
address
Definition: first.py:40
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:305
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:707
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: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.