A Discrete-Event Network Simulator
API
dctcp-example.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017-20 NITK Surathkal
3 * Copyright (c) 2020 Tom Henderson (better alignment with experiment)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Shravya K.S. <shravya.ks0@gmail.com>
19 * Apoorva Bhargava <apoorvabhargava13@gmail.com>
20 * Shikha Bakshi <shikhabakshi912@gmail.com>
21 * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
22 * Tom Henderson <tomh@tomh.org>
23 */
24
25// The network topology used in this example is based on Fig. 17 described in
26// Mohammad Alizadeh, Albert Greenberg, David A. Maltz, Jitendra Padhye,
27// Parveen Patel, Balaji Prabhakar, Sudipta Sengupta, and Murari Sridharan.
28// "Data Center TCP (DCTCP)." In ACM SIGCOMM Computer Communication Review,
29// Vol. 40, No. 4, pp. 63-74. ACM, 2010.
30
31// The topology is roughly as follows
32//
33// S1 S3
34// | | (1 Gbps)
35// T1 ------- T2 -- R1
36// | | (1 Gbps)
37// S2 R2
38//
39// The link between switch T1 and T2 is 10 Gbps. All other
40// links are 1 Gbps. In the SIGCOMM paper, there is a Scorpion switch
41// between T1 and T2, but it doesn't contribute another bottleneck.
42//
43// S1 and S3 each have 10 senders sending to receiver R1 (20 total)
44// S2 (20 senders) sends traffic to R2 (20 receivers)
45//
46// This sets up two bottlenecks: 1) T1 -> T2 interface (30 senders
47// using the 10 Gbps link) and 2) T2 -> R1 (20 senders using 1 Gbps link)
48//
49// RED queues configured for ECN marking are used at the bottlenecks.
50//
51// Figure 17 published results are that each sender in S1 gets 46 Mbps
52// and each in S3 gets 54 Mbps, while each S2 sender gets 475 Mbps, and
53// that these are within 10% of their fair-share throughputs (Jain index
54// of 0.99).
55//
56// This program runs the program by default for five seconds. The first
57// second is devoted to flow startup (all 40 TCP flows are stagger started
58// during this period). There is a three second convergence time where
59// no measurement data is taken, and then there is a one second measurement
60// interval to gather raw throughput for each flow. These time intervals
61// can be changed at the command line.
62//
63// The program outputs six files. The first three:
64// * dctcp-example-s1-r1-throughput.dat
65// * dctcp-example-s2-r2-throughput.dat
66// * dctcp-example-s3-r1-throughput.dat
67// provide per-flow throughputs (in Mb/s) for each of the forty flows, summed
68// over the measurement window. The fourth file,
69// * dctcp-example-fairness.dat
70// provides average throughputs for the three flow paths, and computes
71// Jain's fairness index for each flow group (i.e. across each group of
72// 10, 20, and 10 flows). It also sums the throughputs across each bottleneck.
73// The fifth and sixth:
74// * dctcp-example-t1-length.dat
75// * dctcp-example-t2-length.dat
76// report on the bottleneck queue length (in packets and microseconds
77// of delay) at 10 ms intervals during the measurement window.
78//
79// By default, the throughput averages are 23 Mbps for S1 senders, 471 Mbps
80// for S2 senders, and 74 Mbps for S3 senders, and the Jain index is greater
81// than 0.99 for each group of flows. The average queue delay is about 1ms
82// for the T2->R2 bottleneck, and about 200us for the T1->T2 bottleneck.
83//
84// The RED parameters (min_th and max_th) are set to the same values as
85// reported in the paper, but we observed that throughput distributions
86// and queue delays are very sensitive to these parameters, as was also
87// observed in the paper; it is likely that the paper's throughput results
88// could be achieved by further tuning of the RED parameters. However,
89// the default results show that DCTCP is able to achieve high link
90// utilization and low queueing delay and fairness across competing flows
91// sharing the same path.
92
93#include "ns3/applications-module.h"
94#include "ns3/core-module.h"
95#include "ns3/internet-module.h"
96#include "ns3/network-module.h"
97#include "ns3/point-to-point-module.h"
98#include "ns3/traffic-control-module.h"
99
100#include <iomanip>
101#include <iostream>
102
103using namespace ns3;
104
105std::stringstream filePlotQueue1;
106std::stringstream filePlotQueue2;
107std::ofstream rxS1R1Throughput;
108std::ofstream rxS2R2Throughput;
109std::ofstream rxS3R1Throughput;
110std::ofstream fairnessIndex;
111std::ofstream t1QueueLength;
112std::ofstream t2QueueLength;
113std::vector<uint64_t> rxS1R1Bytes;
114std::vector<uint64_t> rxS2R2Bytes;
115std::vector<uint64_t> rxS3R1Bytes;
116
117void
119{
120 std::cout << "Progress to " << std::fixed << std::setprecision(1)
121 << Simulator::Now().GetSeconds() << " seconds simulation time" << std::endl;
122 Simulator::Schedule(interval, &PrintProgress, interval);
123}
124
125void
126TraceS1R1Sink(std::size_t index, Ptr<const Packet> p, const Address& a)
127{
128 rxS1R1Bytes[index] += p->GetSize();
129}
130
131void
132TraceS2R2Sink(std::size_t index, Ptr<const Packet> p, const Address& a)
133{
134 rxS2R2Bytes[index] += p->GetSize();
135}
136
137void
138TraceS3R1Sink(std::size_t index, Ptr<const Packet> p, const Address& a)
139{
140 rxS3R1Bytes[index] += p->GetSize();
141}
142
143void
145{
146 for (std::size_t i = 0; i < 10; i++)
147 {
148 rxS1R1Bytes[i] = 0;
149 }
150 for (std::size_t i = 0; i < 20; i++)
151 {
152 rxS2R2Bytes[i] = 0;
153 }
154 for (std::size_t i = 0; i < 10; i++)
155 {
156 rxS3R1Bytes[i] = 0;
157 }
158}
159
160void
161PrintThroughput(Time measurementWindow)
162{
163 for (std::size_t i = 0; i < 10; i++)
164 {
165 rxS1R1Throughput << measurementWindow.GetSeconds() << "s " << i << " "
166 << (rxS1R1Bytes[i] * 8) / (measurementWindow.GetSeconds()) / 1e6
167 << std::endl;
168 }
169 for (std::size_t i = 0; i < 20; i++)
170 {
171 rxS2R2Throughput << Simulator::Now().GetSeconds() << "s " << i << " "
172 << (rxS2R2Bytes[i] * 8) / (measurementWindow.GetSeconds()) / 1e6
173 << std::endl;
174 }
175 for (std::size_t i = 0; i < 10; i++)
176 {
177 rxS3R1Throughput << Simulator::Now().GetSeconds() << "s " << i << " "
178 << (rxS3R1Bytes[i] * 8) / (measurementWindow.GetSeconds()) / 1e6
179 << std::endl;
180 }
181}
182
183// Jain's fairness index: https://en.wikipedia.org/wiki/Fairness_measure
184void
185PrintFairness(Time measurementWindow)
186{
187 double average = 0;
188 uint64_t sumSquares = 0;
189 uint64_t sum = 0;
190 double fairness = 0;
191 for (std::size_t i = 0; i < 10; i++)
192 {
193 sum += rxS1R1Bytes[i];
194 sumSquares += (rxS1R1Bytes[i] * rxS1R1Bytes[i]);
195 }
196 average = ((sum / 10) * 8 / measurementWindow.GetSeconds()) / 1e6;
197 fairness = static_cast<double>(sum * sum) / (10 * sumSquares);
198 fairnessIndex << "Average throughput for S1-R1 flows: " << std::fixed << std::setprecision(2)
199 << average << " Mbps; fairness: " << std::fixed << std::setprecision(3)
200 << fairness << std::endl;
201 average = 0;
202 sumSquares = 0;
203 sum = 0;
204 fairness = 0;
205 for (std::size_t i = 0; i < 20; i++)
206 {
207 sum += rxS2R2Bytes[i];
208 sumSquares += (rxS2R2Bytes[i] * rxS2R2Bytes[i]);
209 }
210 average = ((sum / 20) * 8 / measurementWindow.GetSeconds()) / 1e6;
211 fairness = static_cast<double>(sum * sum) / (20 * sumSquares);
212 fairnessIndex << "Average throughput for S2-R2 flows: " << std::fixed << std::setprecision(2)
213 << average << " Mbps; fairness: " << std::fixed << std::setprecision(3)
214 << fairness << std::endl;
215 average = 0;
216 sumSquares = 0;
217 sum = 0;
218 fairness = 0;
219 for (std::size_t i = 0; i < 10; i++)
220 {
221 sum += rxS3R1Bytes[i];
222 sumSquares += (rxS3R1Bytes[i] * rxS3R1Bytes[i]);
223 }
224 average = ((sum / 10) * 8 / measurementWindow.GetSeconds()) / 1e6;
225 fairness = static_cast<double>(sum * sum) / (10 * sumSquares);
226 fairnessIndex << "Average throughput for S3-R1 flows: " << std::fixed << std::setprecision(2)
227 << average << " Mbps; fairness: " << std::fixed << std::setprecision(3)
228 << fairness << std::endl;
229 sum = 0;
230 for (std::size_t i = 0; i < 10; i++)
231 {
232 sum += rxS1R1Bytes[i];
233 }
234 for (std::size_t i = 0; i < 20; i++)
235 {
236 sum += rxS2R2Bytes[i];
237 }
238 fairnessIndex << "Aggregate user-level throughput for flows through T1: "
239 << static_cast<double>(sum * 8) / 1e9 << " Gbps" << std::endl;
240 sum = 0;
241 for (std::size_t i = 0; i < 10; i++)
242 {
243 sum += rxS3R1Bytes[i];
244 }
245 for (std::size_t i = 0; i < 10; i++)
246 {
247 sum += rxS1R1Bytes[i];
248 }
249 fairnessIndex << "Aggregate user-level throughput for flows to R1: "
250 << static_cast<double>(sum * 8) / 1e9 << " Gbps" << std::endl;
251}
252
253void
255{
256 // 1500 byte packets
257 uint32_t qSize = queue->GetNPackets();
258 Time backlog = Seconds(static_cast<double>(qSize * 1500 * 8) / 1e10); // 10 Gb/s
259 // report size in units of packets and ms
260 t1QueueLength << std::fixed << std::setprecision(2) << Simulator::Now().GetSeconds() << " "
261 << qSize << " " << backlog.GetMicroSeconds() << std::endl;
262 // check queue size every 1/100 of a second
263 Simulator::Schedule(MilliSeconds(10), &CheckT1QueueSize, queue);
264}
265
266void
268{
269 uint32_t qSize = queue->GetNPackets();
270 Time backlog = Seconds(static_cast<double>(qSize * 1500 * 8) / 1e9); // 1 Gb/s
271 // report size in units of packets and ms
272 t2QueueLength << std::fixed << std::setprecision(2) << Simulator::Now().GetSeconds() << " "
273 << qSize << " " << backlog.GetMicroSeconds() << std::endl;
274 // check queue size every 1/100 of a second
275 Simulator::Schedule(MilliSeconds(10), &CheckT2QueueSize, queue);
276}
277
278int
279main(int argc, char* argv[])
280{
281 std::string outputFilePath = ".";
282 std::string tcpTypeId = "TcpDctcp";
283 Time flowStartupWindow = Seconds(1);
284 Time convergenceTime = Seconds(3);
285 Time measurementWindow = Seconds(1);
286 bool enableSwitchEcn = true;
287 Time progressInterval = MilliSeconds(100);
288
289 CommandLine cmd(__FILE__);
290 cmd.AddValue("tcpTypeId", "ns-3 TCP TypeId", tcpTypeId);
291 cmd.AddValue("flowStartupWindow",
292 "startup time window (TCP staggered starts)",
293 flowStartupWindow);
294 cmd.AddValue("convergenceTime", "convergence time", convergenceTime);
295 cmd.AddValue("measurementWindow", "measurement window", measurementWindow);
296 cmd.AddValue("enableSwitchEcn", "enable ECN at switches", enableSwitchEcn);
297 cmd.Parse(argc, argv);
298
299 Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::" + tcpTypeId));
300
301 Time startTime = Seconds(0);
302 Time stopTime = flowStartupWindow + convergenceTime + measurementWindow;
303
304 Time clientStartTime = startTime;
305
306 rxS1R1Bytes.reserve(10);
307 rxS2R2Bytes.reserve(20);
308 rxS3R1Bytes.reserve(10);
309
310 NodeContainer S1;
311 NodeContainer S2;
312 NodeContainer S3;
313 NodeContainer R2;
314 Ptr<Node> T1 = CreateObject<Node>();
315 Ptr<Node> T2 = CreateObject<Node>();
316 Ptr<Node> R1 = CreateObject<Node>();
317 S1.Create(10);
318 S2.Create(20);
319 S3.Create(10);
320 R2.Create(20);
321
322 Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(1448));
323 Config::SetDefault("ns3::TcpSocket::DelAckCount", UintegerValue(2));
324 GlobalValue::Bind("ChecksumEnabled", BooleanValue(false));
325
326 // Set default parameters for RED queue disc
327 Config::SetDefault("ns3::RedQueueDisc::UseEcn", BooleanValue(enableSwitchEcn));
328 // ARED may be used but the queueing delays will increase; it is disabled
329 // here because the SIGCOMM paper did not mention it
330 // Config::SetDefault ("ns3::RedQueueDisc::ARED", BooleanValue (true));
331 // Config::SetDefault ("ns3::RedQueueDisc::Gentle", BooleanValue (true));
332 Config::SetDefault("ns3::RedQueueDisc::UseHardDrop", BooleanValue(false));
333 Config::SetDefault("ns3::RedQueueDisc::MeanPktSize", UintegerValue(1500));
334 // Triumph and Scorpion switches used in DCTCP Paper have 4 MB of buffer
335 // If every packet is 1500 bytes, 2666 packets can be stored in 4 MB
336 Config::SetDefault("ns3::RedQueueDisc::MaxSize", QueueSizeValue(QueueSize("2666p")));
337 // DCTCP tracks instantaneous queue length only; so set QW = 1
338 Config::SetDefault("ns3::RedQueueDisc::QW", DoubleValue(1));
339 Config::SetDefault("ns3::RedQueueDisc::MinTh", DoubleValue(20));
340 Config::SetDefault("ns3::RedQueueDisc::MaxTh", DoubleValue(60));
341
342 PointToPointHelper pointToPointSR;
343 pointToPointSR.SetDeviceAttribute("DataRate", StringValue("1Gbps"));
344 pointToPointSR.SetChannelAttribute("Delay", StringValue("10us"));
345
346 PointToPointHelper pointToPointT;
347 pointToPointT.SetDeviceAttribute("DataRate", StringValue("10Gbps"));
348 pointToPointT.SetChannelAttribute("Delay", StringValue("10us"));
349
350 // Create a total of 62 links.
351 std::vector<NetDeviceContainer> S1T1;
352 S1T1.reserve(10);
353 std::vector<NetDeviceContainer> S2T1;
354 S2T1.reserve(20);
355 std::vector<NetDeviceContainer> S3T2;
356 S3T2.reserve(10);
357 std::vector<NetDeviceContainer> R2T2;
358 R2T2.reserve(20);
359 NetDeviceContainer T1T2 = pointToPointT.Install(T1, T2);
360 NetDeviceContainer R1T2 = pointToPointSR.Install(R1, T2);
361
362 for (std::size_t i = 0; i < 10; i++)
363 {
364 Ptr<Node> n = S1.Get(i);
365 S1T1.push_back(pointToPointSR.Install(n, T1));
366 }
367 for (std::size_t i = 0; i < 20; i++)
368 {
369 Ptr<Node> n = S2.Get(i);
370 S2T1.push_back(pointToPointSR.Install(n, T1));
371 }
372 for (std::size_t i = 0; i < 10; i++)
373 {
374 Ptr<Node> n = S3.Get(i);
375 S3T2.push_back(pointToPointSR.Install(n, T2));
376 }
377 for (std::size_t i = 0; i < 20; i++)
378 {
379 Ptr<Node> n = R2.Get(i);
380 R2T2.push_back(pointToPointSR.Install(n, T2));
381 }
382
384 stack.InstallAll();
385
386 TrafficControlHelper tchRed10;
387 // MinTh = 50, MaxTh = 150 recommended in ACM SIGCOMM 2010 DCTCP Paper
388 // This yields a target (MinTh) queue depth of 60us at 10 Gb/s
389 tchRed10.SetRootQueueDisc("ns3::RedQueueDisc",
390 "LinkBandwidth",
391 StringValue("10Gbps"),
392 "LinkDelay",
393 StringValue("10us"),
394 "MinTh",
395 DoubleValue(50),
396 "MaxTh",
397 DoubleValue(150));
398 QueueDiscContainer queueDiscs1 = tchRed10.Install(T1T2);
399
400 TrafficControlHelper tchRed1;
401 // MinTh = 20, MaxTh = 60 recommended in ACM SIGCOMM 2010 DCTCP Paper
402 // This yields a target queue depth of 250us at 1 Gb/s
403 tchRed1.SetRootQueueDisc("ns3::RedQueueDisc",
404 "LinkBandwidth",
405 StringValue("1Gbps"),
406 "LinkDelay",
407 StringValue("10us"),
408 "MinTh",
409 DoubleValue(20),
410 "MaxTh",
411 DoubleValue(60));
412 QueueDiscContainer queueDiscs2 = tchRed1.Install(R1T2.Get(1));
413 for (std::size_t i = 0; i < 10; i++)
414 {
415 tchRed1.Install(S1T1[i].Get(1));
416 }
417 for (std::size_t i = 0; i < 20; i++)
418 {
419 tchRed1.Install(S2T1[i].Get(1));
420 }
421 for (std::size_t i = 0; i < 10; i++)
422 {
423 tchRed1.Install(S3T2[i].Get(1));
424 }
425 for (std::size_t i = 0; i < 20; i++)
426 {
427 tchRed1.Install(R2T2[i].Get(1));
428 }
429
431 std::vector<Ipv4InterfaceContainer> ipS1T1;
432 ipS1T1.reserve(10);
433 std::vector<Ipv4InterfaceContainer> ipS2T1;
434 ipS2T1.reserve(20);
435 std::vector<Ipv4InterfaceContainer> ipS3T2;
436 ipS3T2.reserve(10);
437 std::vector<Ipv4InterfaceContainer> ipR2T2;
438 ipR2T2.reserve(20);
439 address.SetBase("172.16.1.0", "255.255.255.0");
440 Ipv4InterfaceContainer ipT1T2 = address.Assign(T1T2);
441 address.SetBase("192.168.0.0", "255.255.255.0");
442 Ipv4InterfaceContainer ipR1T2 = address.Assign(R1T2);
443 address.SetBase("10.1.1.0", "255.255.255.0");
444 for (std::size_t i = 0; i < 10; i++)
445 {
446 ipS1T1.push_back(address.Assign(S1T1[i]));
447 address.NewNetwork();
448 }
449 address.SetBase("10.2.1.0", "255.255.255.0");
450 for (std::size_t i = 0; i < 20; i++)
451 {
452 ipS2T1.push_back(address.Assign(S2T1[i]));
453 address.NewNetwork();
454 }
455 address.SetBase("10.3.1.0", "255.255.255.0");
456 for (std::size_t i = 0; i < 10; i++)
457 {
458 ipS3T2.push_back(address.Assign(S3T2[i]));
459 address.NewNetwork();
460 }
461 address.SetBase("10.4.1.0", "255.255.255.0");
462 for (std::size_t i = 0; i < 20; i++)
463 {
464 ipR2T2.push_back(address.Assign(R2T2[i]));
465 address.NewNetwork();
466 }
467
468 Ipv4GlobalRoutingHelper::PopulateRoutingTables();
469
470 // Each sender in S2 sends to a receiver in R2
471 std::vector<Ptr<PacketSink>> r2Sinks;
472 r2Sinks.reserve(20);
473 for (std::size_t i = 0; i < 20; i++)
474 {
475 uint16_t port = 50000 + i;
476 Address sinkLocalAddress(InetSocketAddress(Ipv4Address::GetAny(), port));
477 PacketSinkHelper sinkHelper("ns3::TcpSocketFactory", sinkLocalAddress);
478 ApplicationContainer sinkApp = sinkHelper.Install(R2.Get(i));
479 Ptr<PacketSink> packetSink = sinkApp.Get(0)->GetObject<PacketSink>();
480 r2Sinks.push_back(packetSink);
481 sinkApp.Start(startTime);
482 sinkApp.Stop(stopTime);
483
484 OnOffHelper clientHelper1("ns3::TcpSocketFactory", Address());
485 clientHelper1.SetAttribute("OnTime",
486 StringValue("ns3::ConstantRandomVariable[Constant=1]"));
487 clientHelper1.SetAttribute("OffTime",
488 StringValue("ns3::ConstantRandomVariable[Constant=0]"));
489 clientHelper1.SetAttribute("DataRate", DataRateValue(DataRate("1Gbps")));
490 clientHelper1.SetAttribute("PacketSize", UintegerValue(1000));
491
492 ApplicationContainer clientApps1;
493 AddressValue remoteAddress(InetSocketAddress(ipR2T2[i].GetAddress(0), port));
494 clientHelper1.SetAttribute("Remote", remoteAddress);
495 clientApps1.Add(clientHelper1.Install(S2.Get(i)));
496 clientApps1.Start(i * flowStartupWindow / 20 + clientStartTime + MilliSeconds(i * 5));
497 clientApps1.Stop(stopTime);
498 }
499
500 // Each sender in S1 and S3 sends to R1
501 std::vector<Ptr<PacketSink>> s1r1Sinks;
502 std::vector<Ptr<PacketSink>> s3r1Sinks;
503 s1r1Sinks.reserve(10);
504 s3r1Sinks.reserve(10);
505 for (std::size_t i = 0; i < 20; i++)
506 {
507 uint16_t port = 50000 + i;
508 Address sinkLocalAddress(InetSocketAddress(Ipv4Address::GetAny(), port));
509 PacketSinkHelper sinkHelper("ns3::TcpSocketFactory", sinkLocalAddress);
510 ApplicationContainer sinkApp = sinkHelper.Install(R1);
511 Ptr<PacketSink> packetSink = sinkApp.Get(0)->GetObject<PacketSink>();
512 if (i < 10)
513 {
514 s1r1Sinks.push_back(packetSink);
515 }
516 else
517 {
518 s3r1Sinks.push_back(packetSink);
519 }
520 sinkApp.Start(startTime);
521 sinkApp.Stop(stopTime);
522
523 OnOffHelper clientHelper1("ns3::TcpSocketFactory", Address());
524 clientHelper1.SetAttribute("OnTime",
525 StringValue("ns3::ConstantRandomVariable[Constant=1]"));
526 clientHelper1.SetAttribute("OffTime",
527 StringValue("ns3::ConstantRandomVariable[Constant=0]"));
528 clientHelper1.SetAttribute("DataRate", DataRateValue(DataRate("1Gbps")));
529 clientHelper1.SetAttribute("PacketSize", UintegerValue(1000));
530
531 ApplicationContainer clientApps1;
532 AddressValue remoteAddress(InetSocketAddress(ipR1T2.GetAddress(0), port));
533 clientHelper1.SetAttribute("Remote", remoteAddress);
534 if (i < 10)
535 {
536 clientApps1.Add(clientHelper1.Install(S1.Get(i)));
537 clientApps1.Start(i * flowStartupWindow / 10 + clientStartTime + MilliSeconds(i * 5));
538 }
539 else
540 {
541 clientApps1.Add(clientHelper1.Install(S3.Get(i - 10)));
542 clientApps1.Start((i - 10) * flowStartupWindow / 10 + clientStartTime +
543 MilliSeconds(i * 5));
544 }
545
546 clientApps1.Stop(stopTime);
547 }
548
549 rxS1R1Throughput.open("dctcp-example-s1-r1-throughput.dat", std::ios::out);
550 rxS1R1Throughput << "#Time(s) flow thruput(Mb/s)" << std::endl;
551 rxS2R2Throughput.open("dctcp-example-s2-r2-throughput.dat", std::ios::out);
552 rxS2R2Throughput << "#Time(s) flow thruput(Mb/s)" << std::endl;
553 rxS3R1Throughput.open("dctcp-example-s3-r1-throughput.dat", std::ios::out);
554 rxS3R1Throughput << "#Time(s) flow thruput(Mb/s)" << std::endl;
555 fairnessIndex.open("dctcp-example-fairness.dat", std::ios::out);
556 t1QueueLength.open("dctcp-example-t1-length.dat", std::ios::out);
557 t1QueueLength << "#Time(s) qlen(pkts) qlen(us)" << std::endl;
558 t2QueueLength.open("dctcp-example-t2-length.dat", std::ios::out);
559 t2QueueLength << "#Time(s) qlen(pkts) qlen(us)" << std::endl;
560 for (std::size_t i = 0; i < 10; i++)
561 {
562 s1r1Sinks[i]->TraceConnectWithoutContext("Rx", MakeBoundCallback(&TraceS1R1Sink, i));
563 }
564 for (std::size_t i = 0; i < 20; i++)
565 {
566 r2Sinks[i]->TraceConnectWithoutContext("Rx", MakeBoundCallback(&TraceS2R2Sink, i));
567 }
568 for (std::size_t i = 0; i < 10; i++)
569 {
570 s3r1Sinks[i]->TraceConnectWithoutContext("Rx", MakeBoundCallback(&TraceS3R1Sink, i));
571 }
572 Simulator::Schedule(flowStartupWindow + convergenceTime, &InitializeCounters);
573 Simulator::Schedule(flowStartupWindow + convergenceTime + measurementWindow,
575 measurementWindow);
576 Simulator::Schedule(flowStartupWindow + convergenceTime + measurementWindow,
578 measurementWindow);
579 Simulator::Schedule(progressInterval, &PrintProgress, progressInterval);
580 Simulator::Schedule(flowStartupWindow + convergenceTime, &CheckT1QueueSize, queueDiscs1.Get(0));
581 Simulator::Schedule(flowStartupWindow + convergenceTime, &CheckT2QueueSize, queueDiscs2.Get(0));
582 Simulator::Stop(stopTime + TimeStep(1));
583
584 Simulator::Run();
585
586 rxS1R1Throughput.close();
587 rxS2R2Throughput.close();
588 rxS3R1Throughput.close();
589 fairnessIndex.close();
590 t1QueueLength.close();
591 t2QueueLength.close();
592 Simulator::Destroy();
593 return 0;
594}
a polymophic address class
Definition: address.h:92
AttributeValue implementation for Address.
holds a vector of ns3::Application pointers.
Ptr< Application > Get(uint32_t i) const
Get the Ptr<Application> stored in this container at a given index.
void Start(Time start)
Arrange for all of the Applications in this container to Start() at the Time given as a parameter.
void Add(ApplicationContainer other)
Append the contents of another ApplicationContainer to the end of this container.
void Stop(Time stop)
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
Parse command-line arguments.
Definition: command-line.h:232
AttributeValue implementation for DataRate.
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
an Inet address class
aggregate IP/TCP/UDP functionality to existing Nodes.
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
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.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
A helper to make it easier to instantiate an ns3::OnOffApplication on a set of nodes.
Definition: on-off-helper.h:44
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
A helper to make it easier to instantiate an ns3::PacketSinkApplication on a set of nodes.
Receive and consume traffic generated to an IP address and port.
Definition: packet-sink.h:74
Build a set of PointToPointNetDevice objects.
void SetDeviceAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each NetDevice created by the helper.
void SetChannelAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each Channel created by the helper.
NetDeviceContainer Install(NodeContainer c)
Holds a vector of ns3::QueueDisc pointers.
Ptr< QueueDisc > Get(std::size_t i) const
Get the Ptr<QueueDisc> stored in this container at a given index.
uint32_t GetNPackets() const
Get the number of packets stored by the queue disc.
Definition: queue-disc.cc:436
Class for representing queue sizes.
Definition: queue-size.h:96
AttributeValue implementation for QueueSize.
Hold variables of type string.
Definition: string.h:42
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:402
Time TimeStep(uint64_t ts)
Scheduler interface.
Definition: nstime.h:1420
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:412
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.
Hold an unsigned integer type.
Definition: uinteger.h:45
void TraceS1R1Sink(std::size_t index, Ptr< const Packet > p, const Address &a)
std::ofstream rxS3R1Throughput
std::ofstream fairnessIndex
std::ofstream t1QueueLength
std::vector< uint64_t > rxS3R1Bytes
std::stringstream filePlotQueue1
void PrintFairness(Time measurementWindow)
void InitializeCounters()
void TraceS2R2Sink(std::size_t index, Ptr< const Packet > p, const Address &a)
std::vector< uint64_t > rxS2R2Bytes
void PrintThroughput(Time measurementWindow)
void CheckT1QueueSize(Ptr< QueueDisc > queue)
void PrintProgress(Time interval)
std::stringstream filePlotQueue2
std::ofstream rxS2R2Throughput
void TraceS3R1Sink(std::size_t index, Ptr< const Packet > p, const Address &a)
std::vector< uint64_t > rxS1R1Bytes
std::ofstream rxS1R1Throughput
std::ofstream t2QueueLength
void CheckT2QueueSize(Ptr< QueueDisc > queue)
uint16_t port
Definition: dsdv-manet.cc:45
Time stopTime
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:891
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs... bargs)
Make Callbacks with varying number of bound arguments.
Definition: callback.h:752
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:328
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
address
Definition: first.py:40
stack
Definition: first.py:37
Every class exported by the ns3 library is enclosed in the ns3 namespace.
cmd
Definition: second.py:33