A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tcp-validation.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 Cable Television Laboratories, Inc.
3 * Copyright (c) 2020 Tom Henderson (adapted for DCTCP testing)
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8// This program is designed to observe long-running TCP congestion control
9// behavior over a configurable bottleneck link. The program is also
10// instrumented to check program data against validated results, when
11// the validation option is enabled.
12//
13// ---> downstream (primary data transfer from servers to clients)
14// <--- upstream (return acks and ICMP echo response)
15//
16// ---- bottleneck link ----
17// servers ---| WR |--------------------| LR |--- clients
18// ---- ----
19// ns-3 node IDs:
20// nodes 0-2 3 4 5-7
21//
22// - The box WR is notionally a WAN router, aggregating all server links
23// - The box LR is notionally a LAN router, aggregating all client links
24// - Three servers are connected to WR, three clients are connected to LR
25//
26// clients and servers are configured for ICMP measurements and TCP throughput
27// and latency measurements in the downstream direction
28//
29// All link rates are enforced by a point-to-point (P2P) ns-3 model with full
30// duplex operation. Dynamic queue limits
31// (BQL) are enabled to allow for queueing to occur at the priority queue layer;
32// the notional P2P hardware device queue is limited to three packets.
33//
34// One-way link delays and link rates
35// -----------------------------------
36// (1) server to WR links, 1000 Mbps, 1us delay
37// (2) bottleneck link: configurable rate, configurable delay
38// (3) client to LR links, 1000 Mbps, 1us delay
39//
40// By default, ns-3 FQ-CoDel model is installed on all interfaces, but
41// the bottleneck queue uses CoDel by default and is configurable.
42//
43// The ns-3 FQ-CoDel model uses ns-3 defaults:
44// - 100ms interval
45// - 5ms target
46// - drop batch size of 64 packets
47// - minbytes of 1500
48//
49// Default simulation time is 70 sec. For single flow experiments, the flow is
50// started at simulation time 5 sec; if a second flow is used, it starts
51// at 15 sec.
52//
53// ping frequency is set at 100ms.
54//
55// A command-line option to enable a step-threshold CE threshold
56// from the CoDel queue model is provided.
57//
58// Measure:
59// - ping RTT
60// - TCP RTT estimate
61// - TCP throughput
62//
63// IPv4 addressing
64// ----------------------------
65// pingServer 10.1.1.2 (ping source)
66// firstServer 10.1.2.2 (data sender)
67// secondServer 10.1.3.2 (data sender)
68// pingClient 192.168.1.2
69// firstClient 192.168.2.2
70// secondClient 192.168.3.2
71//
72// Program Options:
73// ---------------
74// --firstTcpType: first TCP type (cubic, dctcp, or reno) [cubic]
75// --secondTcpType: second TCP type (cubic, dctcp, or reno) []
76// --queueType: bottleneck queue type (fq, codel, pie, or red) [codel]
77// --baseRtt: base RTT [+80ms]
78// --ceThreshold: CoDel CE threshold (for DCTCP) [+1ms]
79// --linkRate: data rate of bottleneck link [50000000bps]
80// --stopTime: simulation stop time [+1.16667min]
81// --queueUseEcn: use ECN on queue [false]
82// --enablePcap: enable Pcap [false]
83// --validate: validation case to run []
84//
85// validation cases (and syntax of how to run):
86// ------------
87// Case 'dctcp-10ms': DCTCP single flow, 10ms base RTT, 50 Mbps link, ECN enabled, CoDel:
88// ./ns3 run 'tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=10ms
89// --queueUseEcn=1 --stopTime=15s --validate=1 --validation=dctcp-10ms'
90// - Throughput between 48 Mbps and 49 Mbps for time greater than 5.6s
91// - DCTCP alpha below 0.1 for time greater than 5.4s
92// - DCTCP alpha between 0.06 and 0.085 for time greater than 7s
93//
94// Case 'dctcp-80ms': DCTCP single flow, 80ms base RTT, 50 Mbps link, ECN enabled, CoDel:
95// ./ns3 run 'tcp-validation --firstTcpType=dctcp --linkRate=50Mbps --baseRtt=80ms
96// --queueUseEcn=1 --stopTime=40s --validate=1 --validation=dctcp-80ms'
97// - Throughput less than 20 Mbps for time less than 14s
98// - Throughput less than 48 Mbps for time less than 30s
99// - Throughput between 47.5 Mbps and 48.5 for time greater than 32s
100// - DCTCP alpha above 0.1 for time less than 7.5
101// - DCTCP alpha below 0.01 for time greater than 11 and less than 30
102// - DCTCP alpha between 0.015 and 0.025 for time greater than 34
103//
104// Case 'cubic-50ms-no-ecn': CUBIC single flow, 50ms base RTT, 50 Mbps link, ECN disabled, CoDel:
105// ./ns3 run 'tcp-validation --firstTcpType=cubic --linkRate=50Mbps --baseRtt=50ms
106// --queueUseEcn=0 --stopTime=20s --validate=1 --validation=cubic-50ms-no-ecn'
107// - Maximum value of cwnd is 511 segments at 5.4593 seconds
108// - cwnd decreases to 173 segments at 5.80304 seconds
109// - cwnd reaches another local maxima around 14.2815 seconds of 236 segments
110// - cwnd reaches a second maximum around 18.048 seconds of 234 segments
111//
112// Case 'cubic-50ms-ecn': CUBIC single flow, 50ms base RTT, 50 Mbps link, ECN enabled, CoDel:
113// ./ns3 run 'tcp-validation --firstTcpType=cubic --linkRate=50Mbps --baseRtt=50ms
114// --queueUseEcn=0 --stopTime=20s --validate=1 --validation=cubic-50ms-no-ecn'
115// - Maximum value of cwnd is 511 segments at 5.4593 seconds
116// - cwnd decreases to 173 segments at 5.7939 seconds
117// - cwnd reaches another local maxima around 14.3477 seconds of 236 segments
118// - cwnd reaches a second maximum around 18.064 seconds of 234 segments
119
120#include "ns3/applications-module.h"
121#include "ns3/core-module.h"
122#include "ns3/internet-apps-module.h"
123#include "ns3/internet-module.h"
124#include "ns3/network-module.h"
125#include "ns3/point-to-point-module.h"
126#include "ns3/traffic-control-module.h"
127
128#include <fstream>
129#include <iostream>
130#include <string>
131
132using namespace ns3;
133
134NS_LOG_COMPONENT_DEFINE("TcpValidation");
135
136// These variables are declared outside of main() so that they can
137// be used in trace sinks.
138uint32_t g_firstBytesReceived = 0; //!< First received packet size.
139uint32_t g_secondBytesReceived = 0; //!< Second received packet size.
140uint32_t g_marksObserved = 0; //!< Number of marked packets observed.
141uint32_t g_dropsObserved = 0; //!< Number of dropped packets observed.
142std::string g_validate = ""; //!< Empty string disables validation.
143bool g_validationFailed = false; //!< True if validation failed.
144
145/**
146 * Trace first congestion window.
147 *
148 * \param ofStream Output filestream.
149 * \param oldCwnd Old value.
150 * \param newCwnd new value.
151 */
152void
153TraceFirstCwnd(std::ofstream* ofStream, uint32_t oldCwnd, uint32_t newCwnd)
154{
155 // TCP segment size is configured below to be 1448 bytes
156 // so that we can report cwnd in units of segments
157 if (g_validate.empty())
158 {
159 *ofStream << Simulator::Now().GetSeconds() << " " << static_cast<double>(newCwnd) / 1448
160 << std::endl;
161 }
162 // Validation checks; both the ECN enabled and disabled cases are similar
163 if (g_validate == "cubic-50ms-no-ecn" || g_validate == "cubic-50ms-ecn")
164 {
165 double now = Simulator::Now().GetSeconds();
166 double cwnd = static_cast<double>(newCwnd) / 1448;
167 if ((now > 5.43) && (now < 5.465) && (cwnd < 500))
168 {
169 NS_LOG_WARN("now " << Now().As(Time::S) << " cwnd " << cwnd << " (expected >= 500)");
170 g_validationFailed = true;
171 }
172 else if ((now > 5.795) && (now < 6) && (cwnd > 190))
173 {
174 NS_LOG_WARN("now " << Now().As(Time::S) << " cwnd " << cwnd << " (expected <= 190)");
175 g_validationFailed = true;
176 }
177 else if ((now > 14) && (now < 14.197) && (cwnd < 224))
178 {
179 NS_LOG_WARN("now " << Now().As(Time::S) << " cwnd " << cwnd << " (expected >= 224)");
180 g_validationFailed = true;
181 }
182 else if ((now > 17) && (now < 18.026) && (cwnd < 212))
183 {
184 NS_LOG_WARN("now " << Now().As(Time::S) << " cwnd " << cwnd << " (expected >= 212)");
185 g_validationFailed = true;
186 }
187 }
188}
189
190/**
191 * Trace first TcpDctcp.
192 *
193 * \param ofStream Output filestream.
194 * \param bytesMarked Bytes marked.
195 * \param bytesAcked Bytes ACKed.
196 * \param alpha Alpha.
197 */
198void
199TraceFirstDctcp(std::ofstream* ofStream, uint32_t bytesMarked, uint32_t bytesAcked, double alpha)
200{
201 if (g_validate.empty())
202 {
203 *ofStream << Simulator::Now().GetSeconds() << " " << alpha << std::endl;
204 }
205 // Validation checks
206 if (g_validate == "dctcp-80ms")
207 {
208 double now = Simulator::Now().GetSeconds();
209 if ((now < 7.5) && (alpha < 0.1))
210 {
211 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha << " (expected >= 0.1)");
212 g_validationFailed = true;
213 }
214 else if ((now > 11) && (now < 30) && (alpha > 0.01))
215 {
216 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha << " (expected <= 0.01)");
217 g_validationFailed = true;
218 }
219 else if ((now > 34) && (alpha < 0.015) && (alpha > 0.025))
220 {
221 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha
222 << " (expected 0.015 <= alpha <= 0.025)");
223 g_validationFailed = true;
224 }
225 }
226 else if (g_validate == "dctcp-10ms")
227 {
228 double now = Simulator::Now().GetSeconds();
229 if ((now > 5.6) && (alpha > 0.1))
230 {
231 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha << " (expected <= 0.1)");
232 g_validationFailed = true;
233 }
234 if ((now > 7) && ((alpha > 0.09) || (alpha < 0.049)))
235 {
236 NS_LOG_WARN("now " << Now().As(Time::S) << " alpha " << alpha
237 << " (expected 0.09 <= alpha <= 0.049)");
238 g_validationFailed = true;
239 }
240 }
241}
242
243/**
244 * Trace first RTT.
245 *
246 * \param ofStream Output filestream.
247 * \param oldRtt Old value.
248 * \param newRtt New value.
249 */
250void
251TraceFirstRtt(std::ofstream* ofStream, Time oldRtt, Time newRtt)
252{
253 if (g_validate.empty())
254 {
255 *ofStream << Simulator::Now().GetSeconds() << " " << newRtt.GetSeconds() * 1000
256 << std::endl;
257 }
258}
259
260/**
261 * Trace second congestion window.
262 *
263 * \param ofStream Output filestream.
264 * \param oldCwnd Old value.
265 * \param newCwnd new value.
266 */
267void
268TraceSecondCwnd(std::ofstream* ofStream, uint32_t oldCwnd, uint32_t newCwnd)
269{
270 // TCP segment size is configured below to be 1448 bytes
271 // so that we can report cwnd in units of segments
272 if (g_validate.empty())
273 {
274 *ofStream << Simulator::Now().GetSeconds() << " " << static_cast<double>(newCwnd) / 1448
275 << std::endl;
276 }
277}
278
279/**
280 * Trace second RTT.
281 *
282 * \param ofStream Output filestream.
283 * \param oldRtt Old value.
284 * \param newRtt New value.
285 */
286void
287TraceSecondRtt(std::ofstream* ofStream, Time oldRtt, Time newRtt)
288{
289 if (g_validate.empty())
290 {
291 *ofStream << Simulator::Now().GetSeconds() << " " << newRtt.GetSeconds() * 1000
292 << std::endl;
293 }
294}
295
296/**
297 * Trace second TcpDctcp.
298 *
299 * \param ofStream Output filestream.
300 * \param bytesMarked Bytes marked.
301 * \param bytesAcked Bytes ACKed.
302 * \param alpha Alpha.
303 */
304void
305TraceSecondDctcp(std::ofstream* ofStream, uint32_t bytesMarked, uint32_t bytesAcked, double alpha)
306{
307 if (g_validate.empty())
308 {
309 *ofStream << Simulator::Now().GetSeconds() << " " << alpha << std::endl;
310 }
311}
312
313/**
314 * Trace ping RTT.
315 *
316 * \param ofStream Output filestream.
317 * \param rtt RTT value.
318 */
319void
320TracePingRtt(std::ofstream* ofStream, uint16_t, Time rtt)
321{
322 if (g_validate.empty())
323 {
324 *ofStream << Simulator::Now().GetSeconds() << " " << rtt.GetSeconds() * 1000 << std::endl;
325 }
326}
327
328/**
329 * Trace first Rx.
330 *
331 * \param packet The packet.
332 * \param address The sender address.
333 */
334void
336{
337 g_firstBytesReceived += packet->GetSize();
338}
339
340/**
341 * Trace second Rx.
342 *
343 * \param packet The packet.
344 * \param address The sender address.
345 */
346void
348{
349 g_secondBytesReceived += packet->GetSize();
350}
351
352/**
353 * Trace queue drop.
354 *
355 * \param ofStream Output filestream.
356 * \param item The dropped QueueDiscItem.
357 */
358void
359TraceQueueDrop(std::ofstream* ofStream, Ptr<const QueueDiscItem> item)
360{
361 if (g_validate.empty())
362 {
363 *ofStream << Simulator::Now().GetSeconds() << " " << std::hex << item->Hash() << std::endl;
364 }
366}
367
368/**
369 * Trace queue marks.
370 *
371 * \param ofStream Output filestream.
372 * \param item The marked QueueDiscItem.
373 * \param reason The reason.
374 */
375void
376TraceQueueMark(std::ofstream* ofStream, Ptr<const QueueDiscItem> item, const char* reason)
377{
378 if (g_validate.empty())
379 {
380 *ofStream << Simulator::Now().GetSeconds() << " " << std::hex << item->Hash() << std::endl;
381 }
383}
384
385/**
386 * Trace queue length.
387 *
388 * \param ofStream Output filestream.
389 * \param queueLinkRate Queue link rate.
390 * \param oldVal Old value.
391 * \param newVal New value.
392 */
393void
394TraceQueueLength(std::ofstream* ofStream, DataRate queueLinkRate, uint32_t oldVal, uint32_t newVal)
395{
396 // output in units of ms
397 if (g_validate.empty())
398 {
399 *ofStream << Simulator::Now().GetSeconds() << " " << std::fixed
400 << static_cast<double>(newVal * 8) / (queueLinkRate.GetBitRate() / 1000)
401 << std::endl;
402 }
403}
404
405/**
406 * Trace marks frequency.
407 *
408 * \param ofStream Output filestream.
409 * \param marksSamplingInterval The mark sampling interval.
410 */
411void
412TraceMarksFrequency(std::ofstream* ofStream, Time marksSamplingInterval)
413{
414 if (g_validate.empty())
415 {
416 *ofStream << Simulator::Now().GetSeconds() << " " << g_marksObserved << std::endl;
417 }
418 g_marksObserved = 0;
419 Simulator::Schedule(marksSamplingInterval,
421 ofStream,
422 marksSamplingInterval);
423}
424
425/**
426 * Trace the first throughput.
427 *
428 * \param ofStream Output filestream.
429 * \param throughputInterval The throughput interval.
430 */
431void
432TraceFirstThroughput(std::ofstream* ofStream, Time throughputInterval)
433{
434 double throughput = g_firstBytesReceived * 8 / throughputInterval.GetSeconds() / 1e6;
435 if (g_validate.empty())
436 {
437 *ofStream << Simulator::Now().GetSeconds() << " " << throughput << std::endl;
438 }
440 Simulator::Schedule(throughputInterval, &TraceFirstThroughput, ofStream, throughputInterval);
441 if (g_validate == "dctcp-80ms")
442 {
443 double now = Simulator::Now().GetSeconds();
444 if ((now < 14) && (throughput > 20))
445 {
446 NS_LOG_WARN("now " << Now().As(Time::S) << " throughput " << throughput
447 << " (expected <= 20)");
448 g_validationFailed = true;
449 }
450 if ((now < 30) && (throughput > 48))
451 {
452 NS_LOG_WARN("now " << Now().As(Time::S) << " throughput " << throughput
453 << " (expected <= 48)");
454 g_validationFailed = true;
455 }
456 if ((now > 32) && ((throughput < 47.5) || (throughput > 48.5)))
457 {
458 NS_LOG_WARN("now " << Now().As(Time::S) << " throughput " << throughput
459 << " (expected 47.5 <= throughput <= 48.5)");
460 g_validationFailed = true;
461 }
462 }
463 else if (g_validate == "dctcp-10ms")
464 {
465 double now = Simulator::Now().GetSeconds();
466 if ((now > 5.6) && ((throughput < 48) || (throughput > 49)))
467 {
468 NS_LOG_WARN("now " << Now().As(Time::S) << " throughput " << throughput
469 << " (expected 48 <= throughput <= 49)");
470 g_validationFailed = true;
471 }
472 }
473}
474
475/**
476 * Trace the second throughput.
477 *
478 * \param ofStream Output filestream.
479 * \param throughputInterval The throughput interval.
480 */
481void
482TraceSecondThroughput(std::ofstream* ofStream, Time throughputInterval)
483{
484 if (g_validate.empty())
485 {
486 *ofStream << Simulator::Now().GetSeconds() << " "
487 << g_secondBytesReceived * 8 / throughputInterval.GetSeconds() / 1e6 << std::endl;
488 }
490 Simulator::Schedule(throughputInterval, &TraceSecondThroughput, ofStream, throughputInterval);
491}
492
493/**
494 * Schedule trace connection.
495 *
496 * \param ofStream Output filestream.
497 */
498void
500{
502 "/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
504}
505
506/**
507 * Schedule trace connection.
508 *
509 * \param ofStream Output filestream.
510 */
511void
513{
514 Config::ConnectWithoutContextFailSafe("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/RTT",
515 MakeBoundCallback(&TraceFirstRtt, ofStream));
516}
517
518/**
519 * Schedule trace connection.
520 *
521 * \param ofStream Output filestream.
522 */
523void
524ScheduleFirstDctcpTraceConnection(std::ofstream* ofStream)
525{
526 Config::ConnectWithoutContextFailSafe("/NodeList/1/$ns3::TcpL4Protocol/SocketList/0/"
527 "CongestionOps/$ns3::TcpDctcp/CongestionEstimate",
529}
530
531/**
532 * Schedule trace connection.
533 *
534 * \param ofStream Output filestream.
535 */
536void
538{
539 Config::ConnectWithoutContextFailSafe("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/"
540 "CongestionOps/$ns3::TcpDctcp/CongestionEstimate",
542}
543
544/**
545 * Schedule trace connection.
546 */
547void
549{
550 Config::ConnectWithoutContextFailSafe("/NodeList/6/ApplicationList/*/$ns3::PacketSink/Rx",
552}
553
554/**
555 * Schedule trace connection.
556 *
557 * \param ofStream Output filestream.
558 */
559void
561{
562 Config::ConnectWithoutContext("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
564}
565
566/**
567 * Schedule trace connection.
568 *
569 * \param ofStream Output filestream.
570 */
571void
573{
574 Config::ConnectWithoutContext("/NodeList/2/$ns3::TcpL4Protocol/SocketList/0/RTT",
576}
577
578/**
579 * Schedule trace connection.
580 */
581void
583{
584 Config::ConnectWithoutContext("/NodeList/7/ApplicationList/*/$ns3::PacketSink/Rx",
586}
587
588int
589main(int argc, char* argv[])
590{
591 ////////////////////////////////////////////////////////////
592 // variables not configured at command line //
593 ////////////////////////////////////////////////////////////
594 uint32_t pingSize = 100; // bytes
595 bool enableSecondTcp = false;
596 bool enableLogging = false;
597 Time pingInterval = MilliSeconds(100);
598 Time marksSamplingInterval = MilliSeconds(100);
599 Time throughputSamplingInterval = MilliSeconds(200);
600 std::string pingTraceFile = "tcp-validation-ping.dat";
601 std::string firstTcpRttTraceFile = "tcp-validation-first-tcp-rtt.dat";
602 std::string firstTcpCwndTraceFile = "tcp-validation-first-tcp-cwnd.dat";
603 std::string firstDctcpTraceFile = "tcp-validation-first-dctcp-alpha.dat";
604 std::string firstTcpThroughputTraceFile = "tcp-validation-first-tcp-throughput.dat";
605 std::string secondTcpRttTraceFile = "tcp-validation-second-tcp-rtt.dat";
606 std::string secondTcpCwndTraceFile = "tcp-validation-second-tcp-cwnd.dat";
607 std::string secondTcpThroughputTraceFile = "tcp-validation-second-tcp-throughput.dat";
608 std::string secondDctcpTraceFile = "tcp-validation-second-dctcp-alpha.dat";
609 std::string queueMarkTraceFile = "tcp-validation-queue-mark.dat";
610 std::string queueDropTraceFile = "tcp-validation-queue-drop.dat";
611 std::string queueMarksFrequencyTraceFile = "tcp-validation-queue-marks-frequency.dat";
612 std::string queueLengthTraceFile = "tcp-validation-queue-length.dat";
613
614 ////////////////////////////////////////////////////////////
615 // variables configured at command line //
616 ////////////////////////////////////////////////////////////
617 std::string firstTcpType = "cubic";
618 std::string secondTcpType = "";
619 std::string queueType = "codel";
620 Time stopTime = Seconds(70);
621 Time baseRtt = MilliSeconds(80);
622 DataRate linkRate("50Mbps");
623 bool queueUseEcn = false;
624 Time ceThreshold = MilliSeconds(1);
625 bool enablePcap = false;
626
627 ////////////////////////////////////////////////////////////
628 // Override ns-3 defaults //
629 ////////////////////////////////////////////////////////////
630 Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(1448));
631 // Increase default buffer sizes to improve throughput over long delay paths
632 // Config::SetDefault ("ns3::TcpSocket::SndBufSize",UintegerValue (8192000));
633 // Config::SetDefault ("ns3::TcpSocket::RcvBufSize",UintegerValue (8192000));
634 Config::SetDefault("ns3::TcpSocket::SndBufSize", UintegerValue(32768000));
635 Config::SetDefault("ns3::TcpSocket::RcvBufSize", UintegerValue(32768000));
636 Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10));
637 Config::SetDefault("ns3::TcpL4Protocol::RecoveryType",
639 // Validation criteria were written for TCP Cubic without Reno-friendly behavior, so disable it
640 // for these tests
641 Config::SetDefault("ns3::TcpCubic::TcpFriendliness", BooleanValue(false));
642
643 ////////////////////////////////////////////////////////////
644 // command-line argument parsing //
645 ////////////////////////////////////////////////////////////
646 CommandLine cmd(__FILE__);
647 cmd.AddValue("firstTcpType", "first TCP type (cubic, dctcp, or reno)", firstTcpType);
648 cmd.AddValue("secondTcpType", "second TCP type (cubic, dctcp, or reno)", secondTcpType);
649 cmd.AddValue("queueType", "bottleneck queue type (fq, codel, pie, or red)", queueType);
650 cmd.AddValue("baseRtt", "base RTT", baseRtt);
651 cmd.AddValue("ceThreshold", "CoDel CE threshold (for DCTCP)", ceThreshold);
652 cmd.AddValue("linkRate", "data rate of bottleneck link", linkRate);
653 cmd.AddValue("stopTime", "simulation stop time", stopTime);
654 cmd.AddValue("queueUseEcn", "use ECN on queue", queueUseEcn);
655 cmd.AddValue("enablePcap", "enable Pcap", enablePcap);
656 cmd.AddValue("validate", "validation case to run", g_validate);
657 cmd.Parse(argc, argv);
658
659 // If validation is selected, perform some configuration checks
660 if (!g_validate.empty())
661 {
662 NS_ABORT_MSG_UNLESS(g_validate == "dctcp-10ms" || g_validate == "dctcp-80ms" ||
663 g_validate == "cubic-50ms-no-ecn" || g_validate == "cubic-50ms-ecn",
664 "Unknown test");
665 if (g_validate == "dctcp-10ms" || g_validate == "dctcp-80ms")
666 {
667 NS_ABORT_MSG_UNLESS(firstTcpType == "dctcp", "Incorrect TCP");
668 NS_ABORT_MSG_UNLESS(secondTcpType.empty(), "Incorrect TCP");
669 NS_ABORT_MSG_UNLESS(linkRate == DataRate("50Mbps"), "Incorrect data rate");
670 NS_ABORT_MSG_UNLESS(queueUseEcn == true, "Incorrect ECN configuration");
671 NS_ABORT_MSG_UNLESS(stopTime >= Seconds(15), "Incorrect stopTime");
672 if (g_validate == "dctcp-10ms")
673 {
674 NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(10), "Incorrect RTT");
675 }
676 else if (g_validate == "dctcp-80ms")
677 {
678 NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(80), "Incorrect RTT");
679 }
680 }
681 else if (g_validate == "cubic-50ms-no-ecn" || g_validate == "cubic-50ms-ecn")
682 {
683 NS_ABORT_MSG_UNLESS(firstTcpType == "cubic", "Incorrect TCP");
684 NS_ABORT_MSG_UNLESS(secondTcpType.empty(), "Incorrect TCP");
685 NS_ABORT_MSG_UNLESS(baseRtt == MilliSeconds(50), "Incorrect RTT");
686 NS_ABORT_MSG_UNLESS(linkRate == DataRate("50Mbps"), "Incorrect data rate");
687 NS_ABORT_MSG_UNLESS(stopTime >= Seconds(20), "Incorrect stopTime");
688 if (g_validate == "cubic-50ms-no-ecn")
689 {
690 NS_ABORT_MSG_UNLESS(queueUseEcn == false, "Incorrect ECN configuration");
691 }
692 else if (g_validate == "cubic-50ms-ecn")
693 {
694 NS_ABORT_MSG_UNLESS(queueUseEcn == true, "Incorrect ECN configuration");
695 }
696 }
697 }
698
699 if (enableLogging)
700 {
702 "TcpSocketBase",
705 "TcpDctcp",
707 }
708
709 Time oneWayDelay = baseRtt / 2;
710
711 TypeId firstTcpTypeId;
712 if (firstTcpType == "reno")
713 {
714 firstTcpTypeId = TcpLinuxReno::GetTypeId();
715 }
716 else if (firstTcpType == "cubic")
717 {
718 firstTcpTypeId = TcpCubic::GetTypeId();
719 }
720 else if (firstTcpType == "dctcp")
721 {
722 firstTcpTypeId = TcpDctcp::GetTypeId();
723 Config::SetDefault("ns3::CoDelQueueDisc::CeThreshold", TimeValue(ceThreshold));
724 Config::SetDefault("ns3::FqCoDelQueueDisc::CeThreshold", TimeValue(ceThreshold));
725 if (!queueUseEcn)
726 {
727 std::cout << "Warning: using DCTCP with queue ECN disabled" << std::endl;
728 }
729 }
730 else
731 {
732 NS_FATAL_ERROR("Fatal error: tcp unsupported");
733 }
734 TypeId secondTcpTypeId;
735 if (secondTcpType == "reno")
736 {
737 enableSecondTcp = true;
738 secondTcpTypeId = TcpLinuxReno::GetTypeId();
739 }
740 else if (secondTcpType == "cubic")
741 {
742 enableSecondTcp = true;
743 secondTcpTypeId = TcpCubic::GetTypeId();
744 }
745 else if (secondTcpType == "dctcp")
746 {
747 enableSecondTcp = true;
748 secondTcpTypeId = TcpDctcp::GetTypeId();
749 }
750 else if (secondTcpType.empty())
751 {
752 enableSecondTcp = false;
753 NS_LOG_DEBUG("No second TCP selected");
754 }
755 else
756 {
757 NS_FATAL_ERROR("Fatal error: tcp unsupported");
758 }
759 TypeId queueTypeId;
760 if (queueType == "fq")
761 {
762 queueTypeId = FqCoDelQueueDisc::GetTypeId();
763 }
764 else if (queueType == "codel")
765 {
766 queueTypeId = CoDelQueueDisc::GetTypeId();
767 }
768 else if (queueType == "pie")
769 {
770 queueTypeId = PieQueueDisc::GetTypeId();
771 }
772 else if (queueType == "red")
773 {
774 queueTypeId = RedQueueDisc::GetTypeId();
775 }
776 else
777 {
778 NS_FATAL_ERROR("Fatal error: queueType unsupported");
779 }
780
781 if (queueUseEcn)
782 {
783 Config::SetDefault("ns3::CoDelQueueDisc::UseEcn", BooleanValue(true));
784 Config::SetDefault("ns3::FqCoDelQueueDisc::UseEcn", BooleanValue(true));
785 Config::SetDefault("ns3::PieQueueDisc::UseEcn", BooleanValue(true));
786 Config::SetDefault("ns3::RedQueueDisc::UseEcn", BooleanValue(true));
787 }
788 // Enable TCP to use ECN regardless
789 Config::SetDefault("ns3::TcpSocketBase::UseEcn", StringValue("On"));
790
791 // Report on configuration
792 if (enableSecondTcp)
793 {
794 NS_LOG_DEBUG("first TCP: " << firstTcpTypeId.GetName()
795 << "; second TCP: " << secondTcpTypeId.GetName()
796 << "; queue: " << queueTypeId.GetName()
797 << "; ceThreshold: " << ceThreshold.GetSeconds() * 1000 << "ms");
798 }
799 else
800 {
801 NS_LOG_DEBUG("first TCP: " << firstTcpTypeId.GetName()
802 << "; queue: " << queueTypeId.GetName()
803 << "; ceThreshold: " << ceThreshold.GetSeconds() * 1000 << "ms");
804 }
805
806 // Write traces only if we are not in validation mode (g_validate == "")
807 std::ofstream pingOfStream;
808 std::ofstream firstTcpRttOfStream;
809 std::ofstream firstTcpCwndOfStream;
810 std::ofstream firstTcpThroughputOfStream;
811 std::ofstream firstTcpDctcpOfStream;
812 std::ofstream secondTcpRttOfStream;
813 std::ofstream secondTcpCwndOfStream;
814 std::ofstream secondTcpThroughputOfStream;
815 std::ofstream secondTcpDctcpOfStream;
816 std::ofstream queueDropOfStream;
817 std::ofstream queueMarkOfStream;
818 std::ofstream queueMarksFrequencyOfStream;
819 std::ofstream queueLengthOfStream;
820 if (g_validate.empty())
821 {
822 pingOfStream.open(pingTraceFile, std::ofstream::out);
823 firstTcpRttOfStream.open(firstTcpRttTraceFile, std::ofstream::out);
824 firstTcpCwndOfStream.open(firstTcpCwndTraceFile, std::ofstream::out);
825 firstTcpThroughputOfStream.open(firstTcpThroughputTraceFile, std::ofstream::out);
826 if (firstTcpType == "dctcp")
827 {
828 firstTcpDctcpOfStream.open(firstDctcpTraceFile, std::ofstream::out);
829 }
830 if (enableSecondTcp)
831 {
832 secondTcpRttOfStream.open(secondTcpRttTraceFile, std::ofstream::out);
833 secondTcpCwndOfStream.open(secondTcpCwndTraceFile, std::ofstream::out);
834 secondTcpThroughputOfStream.open(secondTcpThroughputTraceFile, std::ofstream::out);
835 if (secondTcpType == "dctcp")
836 {
837 secondTcpDctcpOfStream.open(secondDctcpTraceFile, std::ofstream::out);
838 }
839 }
840 queueDropOfStream.open(queueDropTraceFile, std::ofstream::out);
841 queueMarkOfStream.open(queueMarkTraceFile, std::ofstream::out);
842 queueMarksFrequencyOfStream.open(queueMarksFrequencyTraceFile, std::ofstream::out);
843 queueLengthOfStream.open(queueLengthTraceFile, std::ofstream::out);
844 }
845
846 ////////////////////////////////////////////////////////////
847 // scenario setup //
848 ////////////////////////////////////////////////////////////
849 Ptr<Node> pingServer = CreateObject<Node>();
850 Ptr<Node> firstServer = CreateObject<Node>();
851 Ptr<Node> secondServer = CreateObject<Node>();
852 Ptr<Node> wanRouter = CreateObject<Node>();
853 Ptr<Node> lanRouter = CreateObject<Node>();
854 Ptr<Node> pingClient = CreateObject<Node>();
855 Ptr<Node> firstClient = CreateObject<Node>();
856 Ptr<Node> secondClient = CreateObject<Node>();
857
858 // Device containers
859 NetDeviceContainer pingServerDevices;
860 NetDeviceContainer firstServerDevices;
861 NetDeviceContainer secondServerDevices;
862 NetDeviceContainer wanLanDevices;
863 NetDeviceContainer pingClientDevices;
864 NetDeviceContainer firstClientDevices;
865 NetDeviceContainer secondClientDevices;
866
868 p2p.SetQueue("ns3::DropTailQueue", "MaxSize", QueueSizeValue(QueueSize("3p")));
869 p2p.SetDeviceAttribute("DataRate", DataRateValue(DataRate("1000Mbps")));
870 // Add delay only on the WAN links
871 p2p.SetChannelAttribute("Delay", TimeValue(MicroSeconds(1)));
872 pingServerDevices = p2p.Install(wanRouter, pingServer);
873 firstServerDevices = p2p.Install(wanRouter, firstServer);
874 secondServerDevices = p2p.Install(wanRouter, secondServer);
875 p2p.SetChannelAttribute("Delay", TimeValue(oneWayDelay));
876 wanLanDevices = p2p.Install(wanRouter, lanRouter);
877 p2p.SetQueue("ns3::DropTailQueue", "MaxSize", QueueSizeValue(QueueSize("3p")));
878 p2p.SetChannelAttribute("Delay", TimeValue(MicroSeconds(1)));
879 pingClientDevices = p2p.Install(lanRouter, pingClient);
880 firstClientDevices = p2p.Install(lanRouter, firstClient);
881 secondClientDevices = p2p.Install(lanRouter, secondClient);
882
883 // Limit the bandwidth on the wanRouter->lanRouter interface
884 Ptr<PointToPointNetDevice> p = wanLanDevices.Get(0)->GetObject<PointToPointNetDevice>();
885 p->SetAttribute("DataRate", DataRateValue(linkRate));
886
887 InternetStackHelper stackHelper;
888 stackHelper.Install(pingServer);
889 Ptr<TcpL4Protocol> proto;
890 stackHelper.Install(firstServer);
891 proto = firstServer->GetObject<TcpL4Protocol>();
892 proto->SetAttribute("SocketType", TypeIdValue(firstTcpTypeId));
893 stackHelper.Install(secondServer);
894 stackHelper.Install(wanRouter);
895 stackHelper.Install(lanRouter);
896 stackHelper.Install(pingClient);
897
898 stackHelper.Install(firstClient);
899 // Set the per-node TCP type here
900 proto = firstClient->GetObject<TcpL4Protocol>();
901 proto->SetAttribute("SocketType", TypeIdValue(firstTcpTypeId));
902 stackHelper.Install(secondClient);
903
904 if (enableSecondTcp)
905 {
906 proto = secondClient->GetObject<TcpL4Protocol>();
907 proto->SetAttribute("SocketType", TypeIdValue(secondTcpTypeId));
908 proto = secondServer->GetObject<TcpL4Protocol>();
909 proto->SetAttribute("SocketType", TypeIdValue(secondTcpTypeId));
910 }
911
912 // InternetStackHelper will install a base TrafficControlLayer on the node,
913 // but the Ipv4AddressHelper below will install the default FqCoDelQueueDisc
914 // on all single device nodes. The below code overrides the configuration
915 // that is normally done by the Ipv4AddressHelper::Install() method by
916 // instead explicitly configuring the queue discs we want on each device.
918 tchFq.SetRootQueueDisc("ns3::FqCoDelQueueDisc");
919 tchFq.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1ms"));
920 tchFq.Install(pingServerDevices);
921 tchFq.Install(firstServerDevices);
922 tchFq.Install(secondServerDevices);
923 tchFq.Install(wanLanDevices.Get(1));
924 tchFq.Install(pingClientDevices);
925 tchFq.Install(firstClientDevices);
926 tchFq.Install(secondClientDevices);
927 // Install queue for bottleneck link
928 TrafficControlHelper tchBottleneck;
929 tchBottleneck.SetRootQueueDisc(queueTypeId.GetName());
930 tchBottleneck.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("1ms"));
931 tchBottleneck.Install(wanLanDevices.Get(0));
932
934 ipv4.SetBase("10.1.1.0", "255.255.255.0");
935 Ipv4InterfaceContainer pingServerIfaces = ipv4.Assign(pingServerDevices);
936 ipv4.SetBase("10.1.2.0", "255.255.255.0");
937 Ipv4InterfaceContainer firstServerIfaces = ipv4.Assign(firstServerDevices);
938 ipv4.SetBase("10.1.3.0", "255.255.255.0");
939 Ipv4InterfaceContainer secondServerIfaces = ipv4.Assign(secondServerDevices);
940 ipv4.SetBase("172.16.1.0", "255.255.255.0");
941 Ipv4InterfaceContainer wanLanIfaces = ipv4.Assign(wanLanDevices);
942 ipv4.SetBase("192.168.1.0", "255.255.255.0");
943 Ipv4InterfaceContainer pingClientIfaces = ipv4.Assign(pingClientDevices);
944 ipv4.SetBase("192.168.2.0", "255.255.255.0");
945 Ipv4InterfaceContainer firstClientIfaces = ipv4.Assign(firstClientDevices);
946 ipv4.SetBase("192.168.3.0", "255.255.255.0");
947 Ipv4InterfaceContainer secondClientIfaces = ipv4.Assign(secondClientDevices);
948
950
951 ////////////////////////////////////////////////////////////
952 // application setup //
953 ////////////////////////////////////////////////////////////
954 PingHelper pingHelper(Ipv4Address("192.168.1.2"));
955 pingHelper.SetAttribute("Interval", TimeValue(pingInterval));
956 pingHelper.SetAttribute("Size", UintegerValue(pingSize));
957 pingHelper.SetAttribute("VerboseMode", EnumValue(Ping::VerboseMode::SILENT));
958 ApplicationContainer pingContainer = pingHelper.Install(pingServer);
959 Ptr<Ping> ping = pingContainer.Get(0)->GetObject<Ping>();
960 ping->TraceConnectWithoutContext("Rtt", MakeBoundCallback(&TracePingRtt, &pingOfStream));
961 pingContainer.Start(Seconds(1));
962 pingContainer.Stop(stopTime - Seconds(1));
963
964 ApplicationContainer firstApp;
965 uint16_t firstPort = 5000;
966 BulkSendHelper tcp("ns3::TcpSocketFactory", Address());
967 // set to large value: e.g. 1000 Mb/s for 60 seconds = 7500000000 bytes
968 tcp.SetAttribute("MaxBytes", UintegerValue(7500000000));
969 // Configure first TCP client/server pair
970 InetSocketAddress firstDestAddress(firstClientIfaces.GetAddress(1), firstPort);
971 tcp.SetAttribute("Remote", AddressValue(firstDestAddress));
972 firstApp = tcp.Install(firstServer);
973 firstApp.Start(Seconds(5));
974 firstApp.Stop(stopTime - Seconds(1));
975
976 Address firstSinkAddress(InetSocketAddress(Ipv4Address::GetAny(), firstPort));
977 ApplicationContainer firstSinkApp;
978 PacketSinkHelper firstSinkHelper("ns3::TcpSocketFactory", firstSinkAddress);
979 firstSinkApp = firstSinkHelper.Install(firstClient);
980 firstSinkApp.Start(Seconds(5));
981 firstSinkApp.Stop(stopTime - MilliSeconds(500));
982
983 // Configure second TCP client/server pair
984 if (enableSecondTcp)
985 {
986 BulkSendHelper tcp("ns3::TcpSocketFactory", Address());
987 uint16_t secondPort = 5000;
988 ApplicationContainer secondApp;
989 InetSocketAddress secondDestAddress(secondClientIfaces.GetAddress(1), secondPort);
990 tcp.SetAttribute("Remote", AddressValue(secondDestAddress));
991 secondApp = tcp.Install(secondServer);
992 secondApp.Start(Seconds(15));
993 secondApp.Stop(stopTime - Seconds(1));
994
995 Address secondSinkAddress(InetSocketAddress(Ipv4Address::GetAny(), secondPort));
996 PacketSinkHelper secondSinkHelper("ns3::TcpSocketFactory", secondSinkAddress);
997 ApplicationContainer secondSinkApp;
998 secondSinkApp = secondSinkHelper.Install(secondClient);
999 secondSinkApp.Start(Seconds(15));
1000 secondSinkApp.Stop(stopTime - MilliSeconds(500));
1001 }
1002
1003 // Setup traces that can be hooked now
1005 Ptr<QueueDisc> qd;
1006 // Trace drops and marks for bottleneck
1007 tc = wanLanDevices.Get(0)->GetNode()->GetObject<TrafficControlLayer>();
1008 qd = tc->GetRootQueueDiscOnDevice(wanLanDevices.Get(0));
1009 qd->TraceConnectWithoutContext("Drop", MakeBoundCallback(&TraceQueueDrop, &queueDropOfStream));
1010 qd->TraceConnectWithoutContext("Mark", MakeBoundCallback(&TraceQueueMark, &queueMarkOfStream));
1012 "BytesInQueue",
1013 MakeBoundCallback(&TraceQueueLength, &queueLengthOfStream, linkRate));
1014
1015 // Setup scheduled traces; TCP traces must be hooked after socket creation
1018 &firstTcpRttOfStream);
1021 &firstTcpCwndOfStream);
1023 if (firstTcpType == "dctcp")
1024 {
1027 &firstTcpDctcpOfStream);
1028 }
1029 Simulator::Schedule(throughputSamplingInterval,
1031 &firstTcpThroughputOfStream,
1032 throughputSamplingInterval);
1033 if (enableSecondTcp)
1034 {
1035 // Setup scheduled traces; TCP traces must be hooked after socket creation
1038 &secondTcpRttOfStream);
1041 &secondTcpCwndOfStream);
1043 Simulator::Schedule(throughputSamplingInterval,
1045 &secondTcpThroughputOfStream,
1046 throughputSamplingInterval);
1047 if (secondTcpType == "dctcp")
1048 {
1051 &secondTcpDctcpOfStream);
1052 }
1053 }
1054 Simulator::Schedule(marksSamplingInterval,
1056 &queueMarksFrequencyOfStream,
1057 marksSamplingInterval);
1058
1059 if (enablePcap)
1060 {
1061 p2p.EnablePcapAll("tcp-validation", false);
1062 }
1063
1067
1068 if (g_validate.empty())
1069 {
1070 pingOfStream.close();
1071 firstTcpCwndOfStream.close();
1072 firstTcpRttOfStream.close();
1073 if (firstTcpType == "dctcp")
1074 {
1075 firstTcpDctcpOfStream.close();
1076 }
1077 firstTcpThroughputOfStream.close();
1078 if (enableSecondTcp)
1079 {
1080 secondTcpCwndOfStream.close();
1081 secondTcpRttOfStream.close();
1082 secondTcpThroughputOfStream.close();
1083 if (secondTcpType == "dctcp")
1084 {
1085 secondTcpDctcpOfStream.close();
1086 }
1087 }
1088 queueDropOfStream.close();
1089 queueMarkOfStream.close();
1090 queueMarksFrequencyOfStream.close();
1091 queueLengthOfStream.close();
1092 }
1093
1095 {
1096 NS_FATAL_ERROR("Validation failed");
1097 }
1098
1099 return 0;
1100}
a polymophic address class
Definition address.h:90
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.
Class for representing data rates.
Definition data-rate.h:78
uint64_t GetBitRate() const
Get the underlying bitrate.
Definition data-rate.cc:234
Hold variables of type enum.
Definition enum.h:52
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.
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.
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:31
This application behaves similarly to the Unix ping application, although with fewer options supporte...
Definition ping.h:45
Build a set of PointToPointNetDevice objects.
A Device for a Point to Point Network Link.
Smart pointer class similar to boost::intrusive_ptr.
Class for representing queue sizes.
Definition queue-size.h:85
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:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Hold variables of type string.
Definition string.h:45
static TypeId GetTypeId()
Get the type ID.
Definition tcp-cubic.cc:25
static TypeId GetTypeId()
Get the type ID.
Definition tcp-dctcp.cc:25
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:94
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
@ S
second
Definition nstime.h:105
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:48
std::string GetName() const
Get the name.
Definition type-id.cc:1061
Hold an unsigned integer type.
Definition uinteger.h:34
Time stopTime
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
void ConnectWithoutContext(std::string path, const CallbackBase &cb)
Definition config.cc:943
bool ConnectWithoutContextFailSafe(std::string path, const CallbackBase &cb)
Definition config.cc:953
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:250
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition callback.h:745
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition simulator.cc:294
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
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:291
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:684
LogLevel
Logging severity classes and levels.
Definition log.h:83
@ LOG_LEVEL_ALL
Print everything.
Definition log.h:105
@ LOG_PREFIX_FUNC
Prefix all trace prints with function.
Definition log.h:107
@ LOG_PREFIX_TIME
Prefix all trace prints with simulation time.
Definition log.h:108
@ LOG_PREFIX_NODE
Prefix all trace prints with simulation node.
Definition log.h:109
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.