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 
103 using namespace ns3;
104 
105 std::stringstream filePlotQueue1;
106 std::stringstream filePlotQueue2;
107 std::ofstream rxS1R1Throughput;
108 std::ofstream rxS2R2Throughput;
109 std::ofstream rxS3R1Throughput;
110 std::ofstream fairnessIndex;
111 std::ofstream t1QueueLength;
112 std::ofstream t2QueueLength;
113 std::vector<uint64_t> rxS1R1Bytes;
114 std::vector<uint64_t> rxS2R2Bytes;
115 std::vector<uint64_t> rxS3R1Bytes;
116 
117 void
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 
125 void
126 TraceS1R1Sink(std::size_t index, Ptr<const Packet> p, const Address& a)
127 {
128  rxS1R1Bytes[index] += p->GetSize();
129 }
130 
131 void
132 TraceS2R2Sink(std::size_t index, Ptr<const Packet> p, const Address& a)
133 {
134  rxS2R2Bytes[index] += p->GetSize();
135 }
136 
137 void
138 TraceS3R1Sink(std::size_t index, Ptr<const Packet> p, const Address& a)
139 {
140  rxS3R1Bytes[index] += p->GetSize();
141 }
142 
143 void
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 
160 void
161 PrintThroughput(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
184 void
185 PrintFairness(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 
253 void
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
264 }
265 
266 void
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
276 }
277 
278 int
279 main(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 
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,
577  &PrintFairness,
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();
593  return 0;
594 }
a polymophic address class
Definition: address.h:100
AttributeValue implementation for Address.
holds a vector of ns3::Application pointers.
void Start(Time start) const
Start all of the Applications in this container at the start time given as a parameter.
Ptr< Application > Get(uint32_t i) const
Get the Ptr<Application> stored in this container at a given index.
void Stop(Time stop) const
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter.
void Add(ApplicationContainer other)
Append the contents of another ApplicationContainer to the end of this container.
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
static void Bind(std::string name, const AttributeValue &value)
Iterate over the set of GlobalValues until a matching name is found and then set its value with Globa...
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.
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.
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.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:140
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static void Run()
Run the simulation.
Definition: simulator.cc:176
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:184
Hold variables of type string.
Definition: string.h:56
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
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:768
void(* DataRate)(DataRate oldValue, DataRate newValue)
TracedValue callback signature for DataRate.
Definition: data-rate.h:328
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1336
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1348
address
Definition: first.py:40
stack
Definition: first.py:37
Every class exported by the ns3 library is enclosed in the ns3 namespace.
cmd
Definition: second.py:33