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