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