satellite-stats-delay-helper.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014 Magister Solutions
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  * Author: Budiarto Herman <budiarto.herman@magister.fi>
19  *
20  */
21 
23 
24 #include <ns3/application-delay-probe.h>
25 #include <ns3/application.h>
26 #include <ns3/boolean.h>
27 #include <ns3/callback.h>
28 #include <ns3/data-collection-object.h>
29 #include <ns3/distribution-collector.h>
30 #include <ns3/enum.h>
31 #include <ns3/inet-socket-address.h>
32 #include <ns3/ipv4.h>
33 #include <ns3/log.h>
34 #include <ns3/mac48-address.h>
35 #include <ns3/magister-gnuplot-aggregator.h>
36 #include <ns3/multi-file-aggregator.h>
37 #include <ns3/net-device.h>
38 #include <ns3/node-container.h>
39 #include <ns3/nstime.h>
40 #include <ns3/probe.h>
41 #include <ns3/satellite-helper.h>
42 #include <ns3/satellite-id-mapper.h>
43 #include <ns3/satellite-mac.h>
44 #include <ns3/satellite-net-device.h>
45 #include <ns3/satellite-orbiter-net-device.h>
46 #include <ns3/satellite-phy.h>
47 #include <ns3/satellite-time-tag.h>
48 #include <ns3/satellite-topology.h>
49 #include <ns3/scalar-collector.h>
50 #include <ns3/singleton.h>
51 #include <ns3/string.h>
52 #include <ns3/traffic-time-tag.h>
53 #include <ns3/unit-conversion-collector.h>
54 
55 #include <map>
56 #include <sstream>
57 #include <string>
58 #include <utility>
59 
60 NS_LOG_COMPONENT_DEFINE("SatStatsDelayHelper");
61 
62 namespace ns3
63 {
64 
65 NS_OBJECT_ENSURE_REGISTERED(SatStatsDelayHelper);
66 
67 SatStatsDelayHelper::SatStatsDelayHelper(Ptr<const SatHelper> satHelper)
68  : SatStatsHelper(satHelper),
69  m_averagingMode(false)
70 {
71  NS_LOG_FUNCTION(this << satHelper);
72 }
73 
75 {
76  NS_LOG_FUNCTION(this);
77 }
78 
79 TypeId // static
81 {
82  static TypeId tid =
83  TypeId("ns3::SatStatsDelayHelper")
84  .SetParent<SatStatsHelper>()
85  .AddAttribute("AveragingMode",
86  "If true, all samples will be averaged before passed to aggregator. "
87  "Only affects histogram, PDF, and CDF output types.",
88  BooleanValue(false),
89  MakeBooleanAccessor(&SatStatsDelayHelper::SetAveragingMode,
91  MakeBooleanChecker());
92  return tid;
93 }
94 
95 void
97 {
98  NS_LOG_FUNCTION(this << averagingMode);
99  m_averagingMode = averagingMode;
100 }
101 
102 bool
104 {
105  return m_averagingMode;
106 }
107 
108 void
110 {
111  NS_LOG_FUNCTION(this);
112 
113  switch (GetOutputType())
114  {
116  NS_FATAL_ERROR(GetOutputTypeName(GetOutputType())
117  << " is not a valid output type for this statistics.");
118  break;
119 
121  // Setup aggregator.
122  m_aggregator = CreateAggregator("ns3::MultiFileAggregator",
123  "OutputFileName",
124  StringValue(GetOutputFileName()),
125  "MultiFileMode",
126  BooleanValue(false),
127  "EnableContextPrinting",
128  BooleanValue(true),
129  "GeneralHeading",
130  StringValue(GetIdentifierHeading("delay_sec")));
131 
132  // Setup collectors.
133  m_terminalCollectors.SetType("ns3::ScalarCollector");
134  m_terminalCollectors.SetAttribute("InputDataType",
135  EnumValue(ScalarCollector::INPUT_DATA_TYPE_DOUBLE));
136  m_terminalCollectors.SetAttribute(
137  "OutputType",
138  EnumValue(ScalarCollector::OUTPUT_TYPE_AVERAGE_PER_SAMPLE));
140  m_terminalCollectors.ConnectToAggregator("Output",
141  m_aggregator,
142  &MultiFileAggregator::Write1d);
143  break;
144  }
145 
147  // Setup aggregator.
148  m_aggregator = CreateAggregator("ns3::MultiFileAggregator",
149  "OutputFileName",
150  StringValue(GetOutputFileName()),
151  "GeneralHeading",
152  StringValue(GetTimeHeading("delay_sec")));
153 
154  // Setup collectors.
155  m_terminalCollectors.SetType("ns3::UnitConversionCollector");
156  m_terminalCollectors.SetAttribute("ConversionType",
157  EnumValue(UnitConversionCollector::TRANSPARENT));
159  m_terminalCollectors.ConnectToAggregator("OutputTimeValue",
160  m_aggregator,
161  &MultiFileAggregator::Write2d);
162  break;
163  }
164 
168  if (m_averagingMode)
169  {
170  // Setup aggregator.
171  m_aggregator = CreateAggregator("ns3::MultiFileAggregator",
172  "OutputFileName",
173  StringValue(GetOutputFileName()),
174  "MultiFileMode",
175  BooleanValue(false),
176  "EnableContextPrinting",
177  BooleanValue(false),
178  "GeneralHeading",
179  StringValue(GetDistributionHeading("delay_sec")));
180  Ptr<MultiFileAggregator> fileAggregator =
181  m_aggregator->GetObject<MultiFileAggregator>();
182  NS_ASSERT(fileAggregator != nullptr);
183 
184  // Setup the final-level collector.
185  m_averagingCollector = CreateObject<DistributionCollector>();
186  DistributionCollector::OutputType_t outputType =
187  DistributionCollector::OUTPUT_TYPE_HISTOGRAM;
189  {
190  outputType = DistributionCollector::OUTPUT_TYPE_PROBABILITY;
191  }
193  {
194  outputType = DistributionCollector::OUTPUT_TYPE_CUMULATIVE;
195  }
196  m_averagingCollector->SetOutputType(outputType);
197  m_averagingCollector->SetName("0");
198  m_averagingCollector->TraceConnect(
199  "Output",
200  "0",
201  MakeCallback(&MultiFileAggregator::Write2d, fileAggregator));
202  m_averagingCollector->TraceConnect(
203  "OutputString",
204  "0",
205  MakeCallback(&MultiFileAggregator::AddContextHeading, fileAggregator));
206  m_averagingCollector->TraceConnect(
207  "Warning",
208  "0",
209  MakeCallback(&MultiFileAggregator::EnableContextWarning, fileAggregator));
210 
211  // Setup collectors.
212  m_terminalCollectors.SetType("ns3::ScalarCollector");
213  m_terminalCollectors.SetAttribute("InputDataType",
214  EnumValue(ScalarCollector::INPUT_DATA_TYPE_DOUBLE));
215  m_terminalCollectors.SetAttribute(
216  "OutputType",
217  EnumValue(ScalarCollector::OUTPUT_TYPE_AVERAGE_PER_SAMPLE));
219  Callback<void, double> callback =
220  MakeCallback(&DistributionCollector::TraceSinkDouble1, m_averagingCollector);
221  for (CollectorMap::Iterator it = m_terminalCollectors.Begin();
222  it != m_terminalCollectors.End();
223  ++it)
224  {
225  it->second->TraceConnectWithoutContext("Output", callback);
226  }
227  }
228  else
229  {
230  // Setup aggregator.
231  m_aggregator = CreateAggregator("ns3::MultiFileAggregator",
232  "OutputFileName",
233  StringValue(GetOutputFileName()),
234  "GeneralHeading",
235  StringValue(GetDistributionHeading("delay_sec")));
236 
237  // Setup collectors.
238  m_terminalCollectors.SetType("ns3::DistributionCollector");
239  DistributionCollector::OutputType_t outputType =
240  DistributionCollector::OUTPUT_TYPE_HISTOGRAM;
242  {
243  outputType = DistributionCollector::OUTPUT_TYPE_PROBABILITY;
244  }
246  {
247  outputType = DistributionCollector::OUTPUT_TYPE_CUMULATIVE;
248  }
249  m_terminalCollectors.SetAttribute("OutputType", EnumValue(outputType));
251  m_terminalCollectors.ConnectToAggregator("Output",
252  m_aggregator,
253  &MultiFileAggregator::Write2d);
254  m_terminalCollectors.ConnectToAggregator("OutputString",
255  m_aggregator,
256  &MultiFileAggregator::AddContextHeading);
257  m_terminalCollectors.ConnectToAggregator("Warning",
258  m_aggregator,
259  &MultiFileAggregator::EnableContextWarning);
260  }
261 
262  break;
263  }
264 
267  NS_FATAL_ERROR(GetOutputTypeName(GetOutputType())
268  << " is not a valid output type for this statistics.");
269  break;
270 
272  // Setup aggregator.
273  m_aggregator = CreateAggregator("ns3::MagisterGnuplotAggregator",
274  "OutputPath",
275  StringValue(GetOutputPath()),
276  "OutputFileName",
277  StringValue(GetName()));
278  Ptr<MagisterGnuplotAggregator> plotAggregator =
279  m_aggregator->GetObject<MagisterGnuplotAggregator>();
280  NS_ASSERT(plotAggregator != nullptr);
281  // plot->SetTitle ("");
282  plotAggregator->SetLegend("Time (in seconds)", "Packet delay (in seconds)");
283  plotAggregator->Set2dDatasetDefaultStyle(Gnuplot2dDataset::LINES);
284 
285  // Setup collectors.
286  m_terminalCollectors.SetType("ns3::UnitConversionCollector");
287  m_terminalCollectors.SetAttribute("ConversionType",
288  EnumValue(UnitConversionCollector::TRANSPARENT));
290  for (CollectorMap::Iterator it = m_terminalCollectors.Begin();
291  it != m_terminalCollectors.End();
292  ++it)
293  {
294  const std::string context = it->second->GetName();
295  plotAggregator->Add2dDataset(context, context);
296  }
297  m_terminalCollectors.ConnectToAggregator("OutputTimeValue",
298  m_aggregator,
299  &MagisterGnuplotAggregator::Write2d);
300  break;
301  }
302 
306  if (m_averagingMode)
307  {
308  // Setup aggregator.
309  m_aggregator = CreateAggregator("ns3::MagisterGnuplotAggregator",
310  "OutputPath",
311  StringValue(GetOutputPath()),
312  "OutputFileName",
313  StringValue(GetName()));
314  Ptr<MagisterGnuplotAggregator> plotAggregator =
315  m_aggregator->GetObject<MagisterGnuplotAggregator>();
316  NS_ASSERT(plotAggregator != nullptr);
317  // plot->SetTitle ("");
318  plotAggregator->SetLegend("Packet delay (in seconds)", "Frequency");
319  plotAggregator->Set2dDatasetDefaultStyle(Gnuplot2dDataset::LINES);
320  plotAggregator->Add2dDataset(GetName(), GetName());
322 
323  // Setup the final-level collector.
324  m_averagingCollector = CreateObject<DistributionCollector>();
325  DistributionCollector::OutputType_t outputType =
326  DistributionCollector::OUTPUT_TYPE_HISTOGRAM;
328  {
329  outputType = DistributionCollector::OUTPUT_TYPE_PROBABILITY;
330  }
332  {
333  outputType = DistributionCollector::OUTPUT_TYPE_CUMULATIVE;
334  }
335  m_averagingCollector->SetOutputType(outputType);
336  m_averagingCollector->SetName("0");
337  m_averagingCollector->TraceConnect(
338  "Output",
339  GetName(),
340  MakeCallback(&MagisterGnuplotAggregator::Write2d, plotAggregator));
342 
343  // Setup collectors.
344  m_terminalCollectors.SetType("ns3::ScalarCollector");
345  m_terminalCollectors.SetAttribute("InputDataType",
346  EnumValue(ScalarCollector::INPUT_DATA_TYPE_DOUBLE));
347  m_terminalCollectors.SetAttribute(
348  "OutputType",
349  EnumValue(ScalarCollector::OUTPUT_TYPE_AVERAGE_PER_SAMPLE));
351  Callback<void, double> callback =
352  MakeCallback(&DistributionCollector::TraceSinkDouble1, m_averagingCollector);
353  for (CollectorMap::Iterator it = m_terminalCollectors.Begin();
354  it != m_terminalCollectors.End();
355  ++it)
356  {
357  it->second->TraceConnectWithoutContext("Output", callback);
358  }
359  }
360  else
361  {
362  // Setup aggregator.
363  m_aggregator = CreateAggregator("ns3::MagisterGnuplotAggregator",
364  "OutputPath",
365  StringValue(GetOutputPath()),
366  "OutputFileName",
367  StringValue(GetName()));
368  Ptr<MagisterGnuplotAggregator> plotAggregator =
369  m_aggregator->GetObject<MagisterGnuplotAggregator>();
370  NS_ASSERT(plotAggregator != nullptr);
371  // plot->SetTitle ("");
372  plotAggregator->SetLegend("Packet delay (in seconds)", "Frequency");
373  plotAggregator->Set2dDatasetDefaultStyle(Gnuplot2dDataset::LINES);
374 
375  // Setup collectors.
376  m_terminalCollectors.SetType("ns3::DistributionCollector");
377  DistributionCollector::OutputType_t outputType =
378  DistributionCollector::OUTPUT_TYPE_HISTOGRAM;
380  {
381  outputType = DistributionCollector::OUTPUT_TYPE_PROBABILITY;
382  }
384  {
385  outputType = DistributionCollector::OUTPUT_TYPE_CUMULATIVE;
386  }
387  m_terminalCollectors.SetAttribute("OutputType", EnumValue(outputType));
389  for (CollectorMap::Iterator it = m_terminalCollectors.Begin();
390  it != m_terminalCollectors.End();
391  ++it)
392  {
393  const std::string context = it->second->GetName();
394  plotAggregator->Add2dDataset(context, context);
395  }
396  m_terminalCollectors.ConnectToAggregator("Output",
397  m_aggregator,
398  &MagisterGnuplotAggregator::Write2d);
399  }
400 
401  break;
402  }
403 
404  default:
405  NS_FATAL_ERROR("SatStatsDelayHelper - Invalid output type");
406  break;
407  }
408 
409  // Setup probes and connect them to the collectors.
410  InstallProbes();
411 
412 } // end of `void DoInstall ();`
413 
414 void
416 {
417  // The method below is supposed to be implemented by the child class.
418  DoInstallProbes();
419 }
420 
421 void
422 SatStatsDelayHelper::RxDelayCallback(const Time& delay, const Address& from)
423 {
424  // NS_LOG_FUNCTION (this << delay.GetSeconds () << from);
425 
426  if (from.IsInvalid())
427  {
428  NS_LOG_WARN(this << " discarding a packet delay of " << delay.GetSeconds()
429  << " from statistics collection because of"
430  << " invalid sender address");
431  }
432  else
433  {
434  // Determine the identifier associated with the sender address.
435  std::map<const Address, uint32_t>::const_iterator it = m_identifierMap.find(from);
436 
437  if (it != m_identifierMap.end())
438  {
439  PassSampleToCollector(delay, it->second);
440  }
441  else
442  {
443  NS_LOG_WARN(this << " discarding a packet delay of " << delay.GetSeconds()
444  << " from statistics collection because of"
445  << " unknown sender address " << from);
446  }
447  }
448 }
449 
450 bool
451 SatStatsDelayHelper::ConnectProbeToCollector(Ptr<Probe> probe, uint32_t identifier)
452 {
453  NS_LOG_FUNCTION(this << probe << probe->GetName() << identifier);
454 
455  bool ret = false;
456  switch (GetOutputType())
457  {
460  ret = m_terminalCollectors.ConnectWithProbe(probe,
461  "OutputSeconds",
462  identifier,
463  &ScalarCollector::TraceSinkDouble);
464  break;
465 
468  ret = m_terminalCollectors.ConnectWithProbe(probe,
469  "OutputSeconds",
470  identifier,
471  &UnitConversionCollector::TraceSinkDouble);
472  break;
473 
480  if (m_averagingMode)
481  {
482  ret = m_terminalCollectors.ConnectWithProbe(probe,
483  "OutputSeconds",
484  identifier,
485  &ScalarCollector::TraceSinkDouble);
486  }
487  else
488  {
489  ret = m_terminalCollectors.ConnectWithProbe(probe,
490  "OutputSeconds",
491  identifier,
492  &DistributionCollector::TraceSinkDouble);
493  }
494  break;
495 
496  default:
497  NS_FATAL_ERROR(GetOutputTypeName(GetOutputType())
498  << " is not a valid output type for this statistics.");
499  break;
500  }
501 
502  if (ret)
503  {
504  NS_LOG_INFO(this << " created probe " << probe->GetName() << ", connected to collector "
505  << identifier);
506  }
507  else
508  {
509  NS_LOG_WARN(this << " unable to connect probe " << probe->GetName() << " to collector "
510  << identifier);
511  }
512 
513  return ret;
514 }
515 
516 bool
517 SatStatsDelayHelper::DisconnectProbeFromCollector(Ptr<Probe> probe, uint32_t identifier)
518 {
519  NS_LOG_FUNCTION(this << probe << probe->GetName() << identifier);
520 
521  bool ret = false;
522  switch (GetOutputType())
523  {
526  ret = m_terminalCollectors.DisconnectWithProbe(probe,
527  "OutputSeconds",
528  identifier,
529  &ScalarCollector::TraceSinkDouble);
530  break;
531 
534  ret = m_terminalCollectors.DisconnectWithProbe(probe,
535  "OutputSeconds",
536  identifier,
537  &UnitConversionCollector::TraceSinkDouble);
538  break;
539 
546  if (m_averagingMode)
547  {
548  ret = m_terminalCollectors.DisconnectWithProbe(probe,
549  "OutputSeconds",
550  identifier,
551  &ScalarCollector::TraceSinkDouble);
552  }
553  else
554  {
555  ret = m_terminalCollectors.DisconnectWithProbe(probe,
556  "OutputSeconds",
557  identifier,
558  &DistributionCollector::TraceSinkDouble);
559  }
560  break;
561 
562  default:
563  NS_FATAL_ERROR(GetOutputTypeName(GetOutputType())
564  << " is not a valid output type for this statistics.");
565  break;
566  }
567 
568  if (ret)
569  {
570  NS_LOG_INFO(this << " probe " << probe->GetName() << ", disconnected from collector "
571  << identifier);
572  }
573  else
574  {
575  NS_LOG_WARN(this << " unable to disconnect probe " << probe->GetName() << " from collector "
576  << identifier);
577  }
578 
579  return ret;
580 }
581 
582 void
583 SatStatsDelayHelper::PassSampleToCollector(const Time& delay, uint32_t identifier)
584 {
585  // NS_LOG_FUNCTION (this << delay.GetSeconds () << identifier);
586 
587  Ptr<DataCollectionObject> collector = m_terminalCollectors.Get(identifier);
588  NS_ASSERT_MSG(collector != nullptr, "Unable to find collector with identifier " << identifier);
589 
590  switch (GetOutputType())
591  {
594  Ptr<ScalarCollector> c = collector->GetObject<ScalarCollector>();
595  NS_ASSERT(c != nullptr);
596  c->TraceSinkDouble(0.0, delay.GetSeconds());
597  break;
598  }
599 
602  Ptr<UnitConversionCollector> c = collector->GetObject<UnitConversionCollector>();
603  NS_ASSERT(c != nullptr);
604  c->TraceSinkDouble(0.0, delay.GetSeconds());
605  break;
606  }
607 
614  if (m_averagingMode)
615  {
616  Ptr<ScalarCollector> c = collector->GetObject<ScalarCollector>();
617  NS_ASSERT(c != nullptr);
618  c->TraceSinkDouble(0.0, delay.GetSeconds());
619  }
620  else
621  {
622  Ptr<DistributionCollector> c = collector->GetObject<DistributionCollector>();
623  NS_ASSERT(c != nullptr);
624  c->TraceSinkDouble(0.0, delay.GetSeconds());
625  }
626  break;
627 
628  default:
629  NS_FATAL_ERROR(GetOutputTypeName(GetOutputType())
630  << " is not a valid output type for this statistics.");
631  break;
632 
633  } // end of `switch (GetOutputType ())`
634 
635 } // end of `void PassSampleToCollector (Time, uint32_t)`
636 
637 // FORWARD LINK APPLICATION-LEVEL /////////////////////////////////////////////
638 
639 NS_OBJECT_ENSURE_REGISTERED(SatStatsFwdAppDelayHelper);
640 
642  : SatStatsDelayHelper(satHelper)
643 {
644  NS_LOG_FUNCTION(this << satHelper);
645 }
646 
648 {
649  NS_LOG_FUNCTION(this);
650 }
651 
652 TypeId // static
654 {
655  static TypeId tid = TypeId("ns3::SatStatsFwdAppDelayHelper").SetParent<SatStatsDelayHelper>();
656  return tid;
657 }
658 
659 void
661 {
662  NS_LOG_FUNCTION(this);
663  NodeContainer utUsers = Singleton<SatTopology>::Get()->GetUtUserNodes();
664 
665  for (NodeContainer::Iterator it = utUsers.Begin(); it != utUsers.End(); ++it)
666  {
667  const int32_t utUserId = GetUtUserId(*it);
668  NS_ASSERT_MSG(utUserId > 0, "Node " << (*it)->GetId() << " is not a valid UT user");
669  const uint32_t identifier = GetIdentifierForUtUser(*it);
670 
671  for (uint32_t i = 0; i < (*it)->GetNApplications(); i++)
672  {
673  Ptr<Application> app = (*it)->GetApplication(i);
674  bool isConnected = false;
675 
676  /*
677  * Some applications support RxDelay trace sources, and some other
678  * applications support Rx trace sources. Below we support both ways.
679  */
680  if (app->GetInstanceTypeId().LookupTraceSourceByName("RxDelay") != nullptr)
681  {
682  NS_LOG_INFO(this << " attempt to connect using RxDelay");
683 
684  // Create the probe.
685  std::ostringstream probeName;
686  probeName << utUserId << "-" << i;
687  Ptr<ApplicationDelayProbe> probe = CreateObject<ApplicationDelayProbe>();
688  probe->SetName(probeName.str());
689 
690  // Connect the object to the probe.
691  if (probe->ConnectByObject("RxDelay", app))
692  {
693  isConnected = ConnectProbeToCollector(probe, identifier);
694  m_probes.insert(
695  std::make_pair(probe->GetObject<Probe>(), std::make_pair(*it, identifier)));
696  }
697  }
698  else if (app->GetInstanceTypeId().LookupTraceSourceByName("Rx") != nullptr)
699  {
700  NS_LOG_INFO(this << " attempt to connect using Rx");
701  Callback<void, Ptr<const Packet>, const Address&> rxCallback =
702  MakeBoundCallback(&SatStatsFwdAppDelayHelper::RxCallback, this, identifier);
703  isConnected = app->TraceConnectWithoutContext("Rx", rxCallback);
704  }
705 
706  if (isConnected)
707  {
708  NS_LOG_INFO(this << " successfully connected"
709  << " with node ID " << (*it)->GetId() << " application #" << i);
710  }
711  else
712  {
713  /*
714  * We're being tolerant here by only logging a warning, because
715  * not every kind of Application is equipped with the expected
716  * RxDelay or Rx trace source.
717  */
718  NS_LOG_WARN(this << " unable to connect"
719  << " with node ID " << (*it)->GetId() << " application #" << i);
720  }
721 
722  } // end of `for (i = 0; i < (*it)->GetNApplications (); i++)`
723 
724  } // end of `for (it = utUsers.Begin(); it != utUsers.End (); ++it)`
725 
726  /*
727  * Some sender applications might need a special attribute to be enabled
728  * before delay statistics can be computed. We enable it here.
729  */
730  NodeContainer gwUsers = Singleton<SatTopology>::Get()->GetGwUserNodes();
731  for (NodeContainer::Iterator it = gwUsers.Begin(); it != gwUsers.End(); ++it)
732  {
733  for (uint32_t i = 0; i < (*it)->GetNApplications(); i++)
734  {
735  Ptr<Application> app = (*it)->GetApplication(i);
736 
737  if (!app->SetAttributeFailSafe("EnableStatisticsTags", BooleanValue(true)))
738  {
739  NS_LOG_WARN(this << " node ID " << (*it)->GetId() << " application #" << i
740  << " might not produce the required tags"
741  << " in the packets it transmits,"
742  << " thus preventing delay statistics"
743  << " from this application");
744  }
745 
746  } // end of `for (i = 0; i < (*it)->GetNApplications (); i++)`
747 
748  } // end of `for (it = gwUsers.Begin(); it != gwUsers.End (); ++it)`
749 
750 } // end of `void DoInstallProbes ();`
751 
752 void // static
753 SatStatsFwdAppDelayHelper::RxCallback(Ptr<SatStatsFwdAppDelayHelper> helper,
754  uint32_t identifier,
755  Ptr<const Packet> packet,
756  const Address& from)
757 {
758  NS_LOG_FUNCTION(helper << identifier << packet << packet->GetSize() << from);
759 
760  // bool isTagged = false;
761  // ByteTagIterator it = packet->GetByteTagIterator ();
762  //
763  // while (!isTagged && it.HasNext ())
764  // {
765  // ByteTagIterator::Item item = it.Next ();
766  //
767  // if (item.GetTypeId () == TrafficTimeTag::GetTypeId ())
768  // {
769  // NS_LOG_DEBUG ("Contains a TrafficTimeTag tag:"
770  // << " start=" << item.GetStart ()
771  // << " end=" << item.GetEnd ());
772  // TrafficTimeTag timeTag;
773  // item.GetTag (timeTag);
774  // const Time delay = Simulator::Now () - timeTag.GetSenderTimestamp ();
775  // helper->PassSampleToCollector (delay, identifier);
776  // isTagged = true; // this will exit the while loop.
777  // }
778  // }
779  //
780  // if (!isTagged)
781  // {
782  // NS_LOG_WARN ("Discarding a packet of " << packet->GetSize ()
783  // << " from statistics collection"
784  // << " because it does not contain any TrafficTimeTag");
785  // }
786 
787  TrafficTimeTag timeTag;
788  if (packet->PeekPacketTag(timeTag))
789  {
790  NS_LOG_DEBUG("Contains a TrafficTimeTag tag");
791  const Time delay = Simulator::Now() - timeTag.GetSenderTimestamp();
792  helper->PassSampleToCollector(delay, identifier);
793  }
794  else
795  {
796  NS_LOG_WARN("Discarding a packet of " << packet->GetSize() << " from statistics collection"
797  << " because it does not contain any TrafficTimeTag");
798  }
799 }
800 
801 void
803 {
804  NS_LOG_FUNCTION(this);
805 
806  std::map<Ptr<Probe>, std::pair<Ptr<Node>, uint32_t>>::iterator it;
807 
808  for (it = m_probes.begin(); it != m_probes.end(); it++)
809  {
810  Ptr<Probe> probe = it->first;
811  Ptr<Node> node = it->second.first;
812  uint32_t identifier = it->second.second;
813 
814  if (!DisconnectProbeFromCollector(probe, identifier))
815  {
816  NS_FATAL_ERROR("Error disconnecting trace file on handover");
817  }
818 
819  identifier = GetIdentifierForUtUser(node);
820 
821  if (!ConnectProbeToCollector(probe, identifier))
822  {
823  NS_FATAL_ERROR("Error connecting trace file on handover");
824  }
825 
826  it->second.second = identifier;
827  }
828 } // end of `void UpdateIdentifierOnProbes ();`
829 
830 // FORWARD LINK DEVICE-LEVEL //////////////////////////////////////////////////
831 
832 NS_OBJECT_ENSURE_REGISTERED(SatStatsFwdDevDelayHelper);
833 
835  : SatStatsDelayHelper(satHelper)
836 {
837  NS_LOG_FUNCTION(this << satHelper);
838 }
839 
841 {
842  NS_LOG_FUNCTION(this);
843 }
844 
845 TypeId // static
847 {
848  static TypeId tid = TypeId("ns3::SatStatsFwdDevDelayHelper").SetParent<SatStatsDelayHelper>();
849  return tid;
850 }
851 
852 void
854 {
855  NS_LOG_FUNCTION(this);
856  NodeContainer uts = Singleton<SatTopology>::Get()->GetUtNodes();
857 
858  for (NodeContainer::Iterator it = uts.Begin(); it != uts.End(); ++it)
859  {
860  const int32_t utId = GetUtId(*it);
861  NS_ASSERT_MSG(utId > 0, "Node " << (*it)->GetId() << " is not a valid UT");
862  const uint32_t identifier = GetIdentifierForUt(*it);
863 
864  // Create the probe.
865  std::ostringstream probeName;
866  probeName << utId;
867  Ptr<ApplicationDelayProbe> probe = CreateObject<ApplicationDelayProbe>();
868  probe->SetName(probeName.str());
869 
870  Ptr<NetDevice> dev = GetUtSatNetDevice(*it);
871 
872  // Connect the object to the probe.
873  if (probe->ConnectByObject("RxDelay", dev) && ConnectProbeToCollector(probe, identifier))
874  {
875  m_probes.insert(
876  std::make_pair(probe->GetObject<Probe>(), std::make_pair(*it, identifier)));
877 
878  // Enable statistics-related tags and trace sources on the device.
879  dev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
880  }
881  else
882  {
883  NS_FATAL_ERROR("Error connecting to RxDelay trace source of SatNetDevice"
884  << " at node ID " << (*it)->GetId() << " device #2");
885  }
886 
887  } // end of `for (it = uts.Begin(); it != uts.End (); ++it)`
888 
889  // Enable statistics-related tags on the transmitting device.
890  NodeContainer gws = Singleton<SatTopology>::Get()->GetGwNodes();
891  for (NodeContainer::Iterator it = gws.Begin(); it != gws.End(); ++it)
892  {
893  NetDeviceContainer devs = GetGwSatNetDevice(*it);
894 
895  for (NetDeviceContainer::Iterator itDev = devs.Begin(); itDev != devs.End(); ++itDev)
896  {
897  NS_ASSERT((*itDev)->GetObject<SatNetDevice>() != nullptr);
898  (*itDev)->SetAttribute("EnableStatisticsTags", BooleanValue(true));
899  }
900  }
901 
902 } // end of `void DoInstallProbes ();`
903 
904 void
906 {
907  NS_LOG_FUNCTION(this);
908 
909  std::map<Ptr<Probe>, std::pair<Ptr<Node>, uint32_t>>::iterator it;
910 
911  for (it = m_probes.begin(); it != m_probes.end(); it++)
912  {
913  Ptr<Probe> probe = it->first;
914  Ptr<Node> node = it->second.first;
915  uint32_t identifier = it->second.second;
916 
917  if (!DisconnectProbeFromCollector(probe, identifier))
918  {
919  NS_FATAL_ERROR("Error disconnecting trace file on handover");
920  }
921 
922  identifier = GetIdentifierForUt(node);
923 
924  if (!ConnectProbeToCollector(probe, identifier))
925  {
926  NS_FATAL_ERROR("Error connecting trace file on handover");
927  }
928 
929  it->second.second = identifier;
930  }
931 } // end of `void UpdateIdentifierOnProbes ();`
932 
933 // FORWARD LINK MAC-LEVEL /////////////////////////////////////////////////////
934 
935 NS_OBJECT_ENSURE_REGISTERED(SatStatsFwdMacDelayHelper);
936 
938  : SatStatsDelayHelper(satHelper)
939 {
940  NS_LOG_FUNCTION(this << satHelper);
941 }
942 
944 {
945  NS_LOG_FUNCTION(this);
946 }
947 
948 TypeId // static
950 {
951  static TypeId tid = TypeId("ns3::SatStatsFwdMacDelayHelper").SetParent<SatStatsDelayHelper>();
952  return tid;
953 }
954 
955 void
957 {
958  NS_LOG_FUNCTION(this);
959  NodeContainer uts = Singleton<SatTopology>::Get()->GetUtNodes();
960 
961  for (NodeContainer::Iterator it = uts.Begin(); it != uts.End(); ++it)
962  {
963  const int32_t utId = GetUtId(*it);
964  NS_ASSERT_MSG(utId > 0, "Node " << (*it)->GetId() << " is not a valid UT");
965  const uint32_t identifier = GetIdentifierForUt(*it);
966 
967  // Create the probe.
968  std::ostringstream probeName;
969  probeName << utId;
970  Ptr<ApplicationDelayProbe> probe = CreateObject<ApplicationDelayProbe>();
971  probe->SetName(probeName.str());
972 
973  Ptr<NetDevice> dev = GetUtSatNetDevice(*it);
974  Ptr<SatNetDevice> satDev = dev->GetObject<SatNetDevice>();
975  NS_ASSERT(satDev != nullptr);
976  Ptr<SatMac> satMac = satDev->GetMac();
977  NS_ASSERT(satMac != nullptr);
978 
979  // Connect the object to the probe.
980  if (probe->ConnectByObject("RxDelay", satMac) && ConnectProbeToCollector(probe, identifier))
981  {
982  m_probes.insert(
983  std::make_pair(probe->GetObject<Probe>(), std::make_pair(*it, identifier)));
984 
985  // Enable statistics-related tags and trace sources on the device.
986  satDev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
987  satMac->SetAttribute("EnableStatisticsTags", BooleanValue(true));
988  }
989  else
990  {
991  NS_FATAL_ERROR("Error connecting to RxDelay trace source of satMac"
992  << " at node ID " << (*it)->GetId() << " device #2");
993  }
994 
995  } // end of `for (it = uts.Begin(); it != uts.End (); ++it)`
996 
997  // Enable statistics-related tags on the transmitting device.
998  NodeContainer gws = Singleton<SatTopology>::Get()->GetGwNodes();
999  for (NodeContainer::Iterator it = gws.Begin(); it != gws.End(); ++it)
1000  {
1001  NetDeviceContainer devs = GetGwSatNetDevice(*it);
1002 
1003  for (NetDeviceContainer::Iterator itDev = devs.Begin(); itDev != devs.End(); ++itDev)
1004  {
1005  Ptr<SatNetDevice> satDev = (*itDev)->GetObject<SatNetDevice>();
1006  NS_ASSERT(satDev != nullptr);
1007  Ptr<SatMac> satMac = satDev->GetMac();
1008  NS_ASSERT(satMac != nullptr);
1009 
1010  satDev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1011  satMac->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1012  }
1013  }
1014 
1015 } // end of `void DoInstallProbes ();`
1016 
1017 void
1019 {
1020  NS_LOG_FUNCTION(this);
1021 
1022  std::map<Ptr<Probe>, std::pair<Ptr<Node>, uint32_t>>::iterator it;
1023 
1024  for (it = m_probes.begin(); it != m_probes.end(); it++)
1025  {
1026  Ptr<Probe> probe = it->first;
1027  Ptr<Node> node = it->second.first;
1028  uint32_t identifier = it->second.second;
1029 
1030  if (!DisconnectProbeFromCollector(probe, identifier))
1031  {
1032  NS_FATAL_ERROR("Error disconnecting trace file on handover");
1033  }
1034 
1035  identifier = GetIdentifierForUt(node);
1036 
1037  if (!ConnectProbeToCollector(probe, identifier))
1038  {
1039  NS_FATAL_ERROR("Error connecting trace file on handover");
1040  }
1041 
1042  it->second.second = identifier;
1043  }
1044 } // end of `void UpdateIdentifierOnProbes ();`
1045 
1046 // FORWARD LINK PHY-LEVEL /////////////////////////////////////////////////////
1047 
1048 NS_OBJECT_ENSURE_REGISTERED(SatStatsFwdPhyDelayHelper);
1049 
1051  : SatStatsDelayHelper(satHelper)
1052 {
1053  NS_LOG_FUNCTION(this << satHelper);
1054 }
1055 
1057 {
1058  NS_LOG_FUNCTION(this);
1059 }
1060 
1061 TypeId // static
1063 {
1064  static TypeId tid = TypeId("ns3::SatStatsFwdPhyDelayHelper").SetParent<SatStatsDelayHelper>();
1065  return tid;
1066 }
1067 
1068 void
1070 {
1071  NS_LOG_FUNCTION(this);
1072 
1073  NodeContainer sats = Singleton<SatTopology>::Get()->GetOrbiterNodes();
1074 
1075  for (NodeContainer::Iterator it = sats.Begin(); it != sats.End(); ++it)
1076  {
1077  Ptr<NetDevice> dev = GetSatSatOrbiterNetDevice(*it);
1078  Ptr<SatOrbiterNetDevice> satOrbiterDev = dev->GetObject<SatOrbiterNetDevice>();
1079  NS_ASSERT(satOrbiterDev != nullptr);
1080  std::map<uint32_t, Ptr<SatPhy>> satOrbiterFeederPhys = satOrbiterDev->GetFeederPhy();
1081  Ptr<SatPhy> satPhy;
1082  for (std::map<uint32_t, Ptr<SatPhy>>::iterator it2 = satOrbiterFeederPhys.begin();
1083  it2 != satOrbiterFeederPhys.end();
1084  ++it2)
1085  {
1086  satPhy = it2->second;
1087  NS_ASSERT(satPhy != nullptr);
1088  satPhy->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1089  }
1090  std::map<uint32_t, Ptr<SatPhy>> satOrbiterUserPhys = satOrbiterDev->GetUserPhy();
1091  for (std::map<uint32_t, Ptr<SatPhy>>::iterator it2 = satOrbiterUserPhys.begin();
1092  it2 != satOrbiterUserPhys.end();
1093  ++it2)
1094  {
1095  satPhy = it2->second;
1096  NS_ASSERT(satPhy != nullptr);
1097  satPhy->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1098  }
1099  } // end of `for (it = sats.Begin(); it != sats.End (); ++it)`
1100 
1101  NodeContainer uts = Singleton<SatTopology>::Get()->GetUtNodes();
1102 
1103  for (NodeContainer::Iterator it = uts.Begin(); it != uts.End(); ++it)
1104  {
1105  const int32_t utId = GetUtId(*it);
1106  NS_ASSERT_MSG(utId > 0, "Node " << (*it)->GetId() << " is not a valid UT");
1107  const uint32_t identifier = GetIdentifierForUt(*it);
1108 
1109  // Create the probe.
1110  std::ostringstream probeName;
1111  probeName << utId;
1112  Ptr<ApplicationDelayProbe> probe = CreateObject<ApplicationDelayProbe>();
1113  probe->SetName(probeName.str());
1114 
1115  Ptr<NetDevice> dev = GetUtSatNetDevice(*it);
1116  Ptr<SatNetDevice> satDev = dev->GetObject<SatNetDevice>();
1117  NS_ASSERT(satDev != nullptr);
1118  Ptr<SatPhy> satPhy = satDev->GetPhy();
1119  NS_ASSERT(satPhy != nullptr);
1120 
1121  // Connect the object to the probe.
1122  if (probe->ConnectByObject("RxDelay", satPhy) && ConnectProbeToCollector(probe, identifier))
1123  {
1124  m_probes.insert(
1125  std::make_pair(probe->GetObject<Probe>(), std::make_pair(*it, identifier)));
1126 
1127  // Enable statistics-related tags and trace sources on the device.
1128  satDev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1129  satPhy->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1130  }
1131  else
1132  {
1133  NS_FATAL_ERROR("Error connecting to RxDelay trace source of SatPhy"
1134  << " at node ID " << (*it)->GetId() << " device #2");
1135  }
1136 
1137  } // end of `for (it = uts.Begin(); it != uts.End (); ++it)`
1138 
1139  // Enable statistics-related tags on the transmitting device.
1140  NodeContainer gws = Singleton<SatTopology>::Get()->GetGwNodes();
1141  for (NodeContainer::Iterator it = gws.Begin(); it != gws.End(); ++it)
1142  {
1143  NetDeviceContainer devs = GetGwSatNetDevice(*it);
1144 
1145  for (NetDeviceContainer::Iterator itDev = devs.Begin(); itDev != devs.End(); ++itDev)
1146  {
1147  Ptr<SatNetDevice> satDev = (*itDev)->GetObject<SatNetDevice>();
1148  NS_ASSERT(satDev != nullptr);
1149  Ptr<SatPhy> satPhy = satDev->GetPhy();
1150  NS_ASSERT(satPhy != nullptr);
1151 
1152  satDev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1153  satPhy->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1154  }
1155  }
1156 
1157 } // end of `void DoInstallProbes ();`
1158 
1159 void
1161 {
1162  NS_LOG_FUNCTION(this);
1163 
1164  std::map<Ptr<Probe>, std::pair<Ptr<Node>, uint32_t>>::iterator it;
1165 
1166  for (it = m_probes.begin(); it != m_probes.end(); it++)
1167  {
1168  Ptr<Probe> probe = it->first;
1169  Ptr<Node> node = it->second.first;
1170  uint32_t identifier = it->second.second;
1171 
1172  if (!DisconnectProbeFromCollector(probe, identifier))
1173  {
1174  NS_FATAL_ERROR("Error disconnecting trace file on handover");
1175  }
1176 
1177  identifier = GetIdentifierForUt(node);
1178 
1179  if (!ConnectProbeToCollector(probe, identifier))
1180  {
1181  NS_FATAL_ERROR("Error connecting trace file on handover");
1182  }
1183 
1184  it->second.second = identifier;
1185  }
1186 } // end of `void UpdateIdentifierOnProbes ();`
1187 
1188 // RETURN LINK APPLICATION-LEVEL //////////////////////////////////////////////
1189 
1190 NS_OBJECT_ENSURE_REGISTERED(SatStatsRtnAppDelayHelper);
1191 
1193  : SatStatsDelayHelper(satHelper)
1194 {
1195  NS_LOG_FUNCTION(this << satHelper);
1196 }
1197 
1199 {
1200  NS_LOG_FUNCTION(this);
1201 }
1202 
1203 TypeId // static
1205 {
1206  static TypeId tid = TypeId("ns3::SatStatsRtnAppDelayHelper").SetParent<SatStatsDelayHelper>();
1207  return tid;
1208 }
1209 
1210 void
1212 {
1213  NS_LOG_FUNCTION(this);
1214 
1215  NodeContainer utUsers = Singleton<SatTopology>::Get()->GetUtUserNodes();
1216  for (NodeContainer::Iterator it = utUsers.Begin(); it != utUsers.End(); ++it)
1217  {
1218  // Create a map of UT user addresses and identifiers.
1220 
1221  /*
1222  * Some sender applications might need a special attribute to be enabled
1223  * before delay statistics can be computed. We enable it here.
1224  */
1225  for (uint32_t i = 0; i < (*it)->GetNApplications(); i++)
1226  {
1227  Ptr<Application> app = (*it)->GetApplication(i);
1228 
1229  if (!app->SetAttributeFailSafe("EnableStatisticsTags", BooleanValue(true)))
1230  {
1231  NS_LOG_WARN(this << " node ID " << (*it)->GetId() << " application #" << i
1232  << " might not produce the required tags"
1233  << " in the transmitted packets,"
1234  << " thus preventing delay statistics"
1235  << " from this sender application");
1236  }
1237 
1238  } // end of `for (i = 0; i < (*it)->GetNApplications (); i++)`
1239 
1240  } // end of `for (NodeContainer::Iterator it: utUsers)`
1241 
1242  // Connect to trace sources at GW user node's applications.
1243 
1244  NodeContainer gwUsers = Singleton<SatTopology>::Get()->GetGwUserNodes();
1245  Callback<void, const Time&, const Address&> rxDelayCallback =
1246  MakeCallback(&SatStatsRtnAppDelayHelper::Ipv4Callback, this);
1247  Callback<void, Ptr<const Packet>, const Address&> rxCallback =
1248  MakeCallback(&SatStatsRtnAppDelayHelper::RxCallback, this);
1249 
1250  for (NodeContainer::Iterator it = gwUsers.Begin(); it != gwUsers.End(); ++it)
1251  {
1252  for (uint32_t i = 0; i < (*it)->GetNApplications(); i++)
1253  {
1254  Ptr<Application> app = (*it)->GetApplication(i);
1255  bool isConnected = false;
1256 
1257  /*
1258  * Some applications support RxDelay trace sources, and some other
1259  * applications support Rx trace sources. Below we support both ways.
1260  */
1261  if (app->GetInstanceTypeId().LookupTraceSourceByName("RxDelay") != nullptr)
1262  {
1263  isConnected = app->TraceConnectWithoutContext("RxDelay", rxDelayCallback);
1264  }
1265  else if (app->GetInstanceTypeId().LookupTraceSourceByName("Rx") != nullptr)
1266  {
1267  isConnected = app->TraceConnectWithoutContext("Rx", rxCallback);
1268  }
1269 
1270  if (isConnected)
1271  {
1272  NS_LOG_INFO(this << " successfully connected"
1273  << " with node ID " << (*it)->GetId() << " application #" << i);
1274  }
1275  else
1276  {
1277  /*
1278  * We're being tolerant here by only logging a warning, because
1279  * not every kind of Application is equipped with the expected
1280  * RxDelay or Rx trace source.
1281  */
1282  NS_LOG_WARN(this << " unable to connect"
1283  << " with node ID " << (*it)->GetId() << " application #" << i);
1284  }
1285 
1286  } // end of `for (i = 0; i < (*it)->GetNApplications (); i++)`
1287 
1288  } // end of `for (NodeContainer::Iterator it: gwUsers)`
1289 
1290 } // end of `void DoInstallProbes ();`
1291 
1292 void
1293 SatStatsRtnAppDelayHelper::RxCallback(Ptr<const Packet> packet, const Address& from)
1294 {
1295  // NS_LOG_FUNCTION (this << packet << packet->GetSize () << from);
1296 
1297  // bool isTagged = false;
1298  // ByteTagIterator it = packet->GetByteTagIterator ();
1299  //
1300  // while (!isTagged && it.HasNext ())
1301  // {
1302  // ByteTagIterator::Item item = it.Next ();
1303  //
1304  // if (item.GetTypeId () == TrafficTimeTag::GetTypeId ())
1305  // {
1306  // NS_LOG_DEBUG ("Contains a TrafficTimeTag tag:"
1307  // << " start=" << item.GetStart ()
1308  // << " end=" << item.GetEnd ());
1309  // TrafficTimeTag timeTag;
1310  // item.GetTag (timeTag);
1311  // const Time delay = Simulator::Now () - timeTag.GetSenderTimestamp ();
1312  // helper->PassSampleToCollector (delay, identifier);
1313  // isTagged = true; // this will exit the while loop.
1314  // }
1315  // }
1316  //
1317  // if (!isTagged)
1318  // {
1319  // NS_LOG_WARN ("Discarding a packet of " << packet->GetSize ()
1320  // << " from statistics collection"
1321  // << " because it does not contain any TrafficTimeTag");
1322  // }
1323 
1324  TrafficTimeTag timeTag;
1325  if (packet->PeekPacketTag(timeTag))
1326  {
1327  NS_LOG_DEBUG(this << " contains a TrafficTimeTag tag");
1328  Ipv4Callback(Simulator::Now() - timeTag.GetSenderTimestamp(), from);
1329  }
1330  else
1331  {
1332  NS_LOG_WARN(this << " discarding a packet of " << packet->GetSize()
1333  << " from statistics collection"
1334  << " because it does not contain any TrafficTimeTag");
1335  }
1336 
1337 } // end of `void RxCallback (Ptr<const Packet>, const Address);`
1338 
1339 void
1340 SatStatsRtnAppDelayHelper::Ipv4Callback(const Time& delay, const Address& from)
1341 {
1342  // NS_LOG_FUNCTION (this << Time.GetSeconds () << from);
1343 
1344  if (InetSocketAddress::IsMatchingType(from))
1345  {
1346  // Determine the identifier associated with the sender address.
1347  const Address ipv4Addr = InetSocketAddress::ConvertFrom(from).GetIpv4();
1348  std::map<const Address, uint32_t>::const_iterator it1 = m_identifierMap.find(ipv4Addr);
1349 
1350  if (it1 == m_identifierMap.end())
1351  {
1352  NS_LOG_WARN(this << " discarding a packet delay of " << delay.GetSeconds()
1353  << " from statistics collection because of"
1354  << " unknown sender IPV4 address " << ipv4Addr);
1355  }
1356  else
1357  {
1358  PassSampleToCollector(delay, it1->second);
1359  }
1360  }
1361  else
1362  {
1363  NS_LOG_WARN(this << " discarding a packet delay of " << delay.GetSeconds()
1364  << " from statistics collection"
1365  << " because it comes from sender " << from
1366  << " without valid InetSocketAddress");
1367  }
1368 }
1369 
1370 void
1372 {
1373  NS_LOG_FUNCTION(this << utUserNode->GetId());
1374 
1375  Ptr<Ipv4> ipv4 = utUserNode->GetObject<Ipv4>();
1376 
1377  if (ipv4 == nullptr)
1378  {
1379  NS_LOG_INFO(this << " Node " << utUserNode->GetId() << " does not support IPv4 protocol");
1380  }
1381  else if (ipv4->GetNInterfaces() >= 2)
1382  {
1383  const uint32_t identifier = GetIdentifierForUtUser(utUserNode);
1384 
1385  /*
1386  * Assuming that #0 is for loopback interface and #1 is for subscriber
1387  * network interface.
1388  */
1389  for (uint32_t i = 0; i < ipv4->GetNAddresses(1); i++)
1390  {
1391  const Address addr = ipv4->GetAddress(1, i).GetLocal();
1392  m_identifierMap[addr] = identifier;
1393  NS_LOG_INFO(this << " associated address " << addr << " with identifier "
1394  << identifier);
1395  }
1396  }
1397  else
1398  {
1399  NS_LOG_WARN(this << " Node " << utUserNode->GetId() << " is not a valid UT user");
1400  }
1401 }
1402 
1403 // RETURN LINK DEVICE-LEVEL ///////////////////////////////////////////////////
1404 
1405 NS_OBJECT_ENSURE_REGISTERED(SatStatsRtnDevDelayHelper);
1406 
1408  : SatStatsDelayHelper(satHelper)
1409 {
1410  NS_LOG_FUNCTION(this << satHelper);
1411 }
1412 
1414 {
1415  NS_LOG_FUNCTION(this);
1416 }
1417 
1418 TypeId // static
1420 {
1421  static TypeId tid = TypeId("ns3::SatStatsRtnDevDelayHelper").SetParent<SatStatsDelayHelper>();
1422  return tid;
1423 }
1424 
1425 void
1427 {
1428  NS_LOG_FUNCTION(this);
1429 
1430  NodeContainer uts = Singleton<SatTopology>::Get()->GetUtNodes();
1431  for (NodeContainer::Iterator it = uts.Begin(); it != uts.End(); ++it)
1432  {
1433  // Create a map of UT addresses and identifiers.
1435 
1436  // Enable statistics-related tags and trace sources on the device.
1437  Ptr<NetDevice> dev = GetUtSatNetDevice(*it);
1438  dev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1439  }
1440 
1441  // Connect to trace sources at GW nodes.
1442 
1443  NodeContainer gws = Singleton<SatTopology>::Get()->GetGwNodes();
1444  Callback<void, const Time&, const Address&> callback =
1445  MakeCallback(&SatStatsRtnDevDelayHelper::RxDelayCallback, this);
1446 
1447  for (NodeContainer::Iterator it = gws.Begin(); it != gws.End(); ++it)
1448  {
1449  NetDeviceContainer devs = GetGwSatNetDevice(*it);
1450 
1451  for (NetDeviceContainer::Iterator itDev = devs.Begin(); itDev != devs.End(); ++itDev)
1452  {
1453  NS_ASSERT((*itDev)->GetObject<SatNetDevice>() != nullptr);
1454 
1455  if ((*itDev)->TraceConnectWithoutContext("RxDelay", callback))
1456  {
1457  NS_LOG_INFO(this << " successfully connected with node ID " << (*it)->GetId()
1458  << " device #" << (*itDev)->GetIfIndex());
1459 
1460  // Enable statistics-related tags and trace sources on the device.
1461  (*itDev)->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1462  }
1463  else
1464  {
1465  NS_FATAL_ERROR("Error connecting to RxDelay trace source of SatNetDevice"
1466  << " at node ID " << (*it)->GetId() << " device #"
1467  << (*itDev)->GetIfIndex());
1468  }
1469 
1470  } // end of `for (NetDeviceContainer::Iterator itDev = devs)`
1471 
1472  } // end of `for (NodeContainer::Iterator it = gws)`
1473 
1474 } // end of `void DoInstallProbes ();`
1475 
1476 // RETURN LINK MAC-LEVEL //////////////////////////////////////////////////////
1477 
1478 NS_OBJECT_ENSURE_REGISTERED(SatStatsRtnMacDelayHelper);
1479 
1481  : SatStatsDelayHelper(satHelper)
1482 {
1483  NS_LOG_FUNCTION(this << satHelper);
1484 }
1485 
1487 {
1488  NS_LOG_FUNCTION(this);
1489 }
1490 
1491 TypeId // static
1493 {
1494  static TypeId tid = TypeId("ns3::SatStatsRtnMacDelayHelper").SetParent<SatStatsDelayHelper>();
1495  return tid;
1496 }
1497 
1498 void
1500 {
1501  NS_LOG_FUNCTION(this);
1502 
1503  NodeContainer uts = Singleton<SatTopology>::Get()->GetUtNodes();
1504  for (NodeContainer::Iterator it = uts.Begin(); it != uts.End(); ++it)
1505  {
1506  // Create a map of UT addresses and identifiers.
1508 
1509  // Enable statistics-related tags and trace sources on the device.
1510  Ptr<NetDevice> dev = GetUtSatNetDevice(*it);
1511  Ptr<SatNetDevice> satDev = dev->GetObject<SatNetDevice>();
1512  NS_ASSERT(satDev != nullptr);
1513  Ptr<SatMac> satMac = satDev->GetMac();
1514  NS_ASSERT(satMac != nullptr);
1515  satDev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1516  satMac->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1517  }
1518 
1519  // Connect to trace sources at GW nodes.
1520 
1521  NodeContainer gws = Singleton<SatTopology>::Get()->GetGwNodes();
1522  Callback<void, const Time&, const Address&> callback =
1523  MakeCallback(&SatStatsRtnMacDelayHelper::RxDelayCallback, this);
1524 
1525  for (NodeContainer::Iterator it = gws.Begin(); it != gws.End(); ++it)
1526  {
1527  NetDeviceContainer devs = GetGwSatNetDevice(*it);
1528 
1529  for (NetDeviceContainer::Iterator itDev = devs.Begin(); itDev != devs.End(); ++itDev)
1530  {
1531  Ptr<SatNetDevice> satDev = (*itDev)->GetObject<SatNetDevice>();
1532  NS_ASSERT(satDev != nullptr);
1533  Ptr<SatMac> satMac = satDev->GetMac();
1534  NS_ASSERT(satMac != nullptr);
1535 
1536  // Connect the object to the probe.
1537  if (satMac->TraceConnectWithoutContext("RxDelay", callback))
1538  {
1539  NS_LOG_INFO(this << " successfully connected with node ID " << (*it)->GetId()
1540  << " device #" << satDev->GetIfIndex());
1541 
1542  // Enable statistics-related tags and trace sources on the device.
1543  satDev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1544  satMac->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1545  }
1546  else
1547  {
1548  NS_FATAL_ERROR("Error connecting to RxDelay trace source of SatNetDevice"
1549  << " at node ID " << (*it)->GetId() << " device #"
1550  << satDev->GetIfIndex());
1551  }
1552 
1553  } // end of `for (NetDeviceContainer::Iterator itDev = devs)`
1554 
1555  } // end of `for (NodeContainer::Iterator it = gws)`
1556 
1557 } // end of `void DoInstallProbes ();`
1558 
1559 // RETURN LINK PHY-LEVEL //////////////////////////////////////////////////////
1560 
1561 NS_OBJECT_ENSURE_REGISTERED(SatStatsRtnPhyDelayHelper);
1562 
1564  : SatStatsDelayHelper(satHelper)
1565 {
1566  NS_LOG_FUNCTION(this << satHelper);
1567 }
1568 
1570 {
1571  NS_LOG_FUNCTION(this);
1572 }
1573 
1574 TypeId // static
1576 {
1577  static TypeId tid = TypeId("ns3::SatStatsRtnPhyDelayHelper").SetParent<SatStatsDelayHelper>();
1578  return tid;
1579 }
1580 
1581 void
1583 {
1584  NS_LOG_FUNCTION(this);
1585 
1586  NodeContainer sats = Singleton<SatTopology>::Get()->GetOrbiterNodes();
1587 
1588  for (NodeContainer::Iterator it = sats.Begin(); it != sats.End(); ++it)
1589  {
1590  Ptr<SatPhy> satPhy;
1591  Ptr<NetDevice> dev = GetSatSatOrbiterNetDevice(*it);
1592  Ptr<SatOrbiterNetDevice> satOrbiterDev = dev->GetObject<SatOrbiterNetDevice>();
1593  NS_ASSERT(satOrbiterDev != nullptr);
1594  std::map<uint32_t, Ptr<SatPhy>> satOrbiterFeederPhys = satOrbiterDev->GetFeederPhy();
1595  for (std::map<uint32_t, Ptr<SatPhy>>::iterator it2 = satOrbiterFeederPhys.begin();
1596  it2 != satOrbiterFeederPhys.end();
1597  ++it2)
1598  {
1599  satPhy = it2->second;
1600  NS_ASSERT(satPhy != nullptr);
1601  satPhy->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1602  }
1603  std::map<uint32_t, Ptr<SatPhy>> satOrbiterUserPhys = satOrbiterDev->GetUserPhy();
1604  for (std::map<uint32_t, Ptr<SatPhy>>::iterator it2 = satOrbiterUserPhys.begin();
1605  it2 != satOrbiterUserPhys.end();
1606  ++it2)
1607  {
1608  satPhy = it2->second;
1609  NS_ASSERT(satPhy != nullptr);
1610  satPhy->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1611  }
1612  } // end of `for (it = sats.Begin(); it != sats.End (); ++it)`
1613 
1614  NodeContainer uts = Singleton<SatTopology>::Get()->GetUtNodes();
1615  for (NodeContainer::Iterator it = uts.Begin(); it != uts.End(); ++it)
1616  {
1617  // Create a map of UT addresses and identifiers.
1619 
1620  // Enable statistics-related tags and trace sources on the device.
1621  Ptr<NetDevice> dev = GetUtSatNetDevice(*it);
1622  Ptr<SatNetDevice> satDev = dev->GetObject<SatNetDevice>();
1623  NS_ASSERT(satDev != nullptr);
1624  Ptr<SatPhy> satPhy = satDev->GetPhy();
1625  NS_ASSERT(satPhy != nullptr);
1626  satDev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1627  satPhy->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1628  }
1629 
1630  // Connect to trace sources at GW nodes.
1631 
1632  NodeContainer gws = Singleton<SatTopology>::Get()->GetGwNodes();
1633  Callback<void, const Time&, const Address&> callback =
1634  MakeCallback(&SatStatsRtnPhyDelayHelper::RxDelayCallback, this);
1635 
1636  for (NodeContainer::Iterator it = gws.Begin(); it != gws.End(); ++it)
1637  {
1638  NetDeviceContainer devs = GetGwSatNetDevice(*it);
1639 
1640  for (NetDeviceContainer::Iterator itDev = devs.Begin(); itDev != devs.End(); ++itDev)
1641  {
1642  Ptr<SatNetDevice> satDev = (*itDev)->GetObject<SatNetDevice>();
1643  NS_ASSERT(satDev != nullptr);
1644  Ptr<SatPhy> satPhy = satDev->GetPhy();
1645  NS_ASSERT(satPhy != nullptr);
1646 
1647  // Connect the object to the probe.
1648  if (satPhy->TraceConnectWithoutContext("RxDelay", callback))
1649  {
1650  NS_LOG_INFO(this << " successfully connected with node ID " << (*it)->GetId()
1651  << " device #" << satDev->GetIfIndex());
1652 
1653  // Enable statistics-related tags and trace sources on the device.
1654  satDev->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1655  satPhy->SetAttribute("EnableStatisticsTags", BooleanValue(true));
1656  }
1657  else
1658  {
1659  NS_FATAL_ERROR("Error connecting to RxDelay trace source of SatNetDevice"
1660  << " at node ID " << (*it)->GetId() << " device #"
1661  << satDev->GetIfIndex());
1662  }
1663 
1664  } // end of `for (NetDeviceContainer::Iterator itDev = devs)`
1665 
1666  } // end of `for (NodeContainer::Iterator it = gws)`
1667 
1668 } // end of `void DoInstallProbes ();`
1669 
1670 } // end of namespace ns3
SatNetDevice to be utilized in the UT and GW nodes.
SatOrbiterNetDevice to be utilized in geostationary satellite.
Base class for delay statistics helpers.
CollectorMap m_terminalCollectors
Maintains a list of collectors created by this helper.
void InstallProbes()
Set up several probes or other means of listeners and connect them to the collectors.
void SetAveragingMode(bool averagingMode)
void DoInstall()
Install the probes, collectors, and aggregators necessary to produce the statistics output.
void RxDelayCallback(const Time &delay, const Address &from)
Receive inputs from trace sources and determine the right collector to forward the inputs to.
virtual void DoInstallProbes()=0
void PassSampleToCollector(const Time &delay, uint32_t identifier)
Find a collector with the right identifier and pass a sample data to it.
Ptr< DataCollectionObject > m_aggregator
The aggregator created by this helper.
static TypeId GetTypeId()
inherited from ObjectBase base class
bool m_averagingMode
AveragingMode attribute.
Ptr< DistributionCollector > m_averagingCollector
The final collector utilized in averaged output (histogram, PDF, and CDF).
bool DisconnectProbeFromCollector(Ptr< Probe > probe, uint32_t identifier)
Disconnect the probe from the right collector.
SatStatsDelayHelper(Ptr< const SatHelper > satHelper)
virtual ~SatStatsDelayHelper()
/ Destructor.
bool ConnectProbeToCollector(Ptr< Probe > probe, uint32_t identifier)
Connect the probe to the right collector.
Produce forward link application-level delay statistics from a satellite module simulation.
static TypeId GetTypeId()
inherited from ObjectBase base class
virtual void UpdateIdentifierOnProbes()
Change identifier used on probes, when handovers occur.
static void RxCallback(Ptr< SatStatsFwdAppDelayHelper > helper, uint32_t identifier, Ptr< const Packet > packet, const Address &from)
Receive inputs from trace sources and determine the right collector to forward the inputs to.
SatStatsFwdAppDelayHelper(Ptr< const SatHelper > satHelper)
std::map< Ptr< Probe >, std::pair< Ptr< Node >, uint32_t > > m_probes
Maintains a list of probes created by this helper.
virtual ~SatStatsFwdAppDelayHelper()
Destructor for SatStatsFwdAppDelayHelper.
Produce forward link device-level delay statistics from a satellite module simulation.
SatStatsFwdDevDelayHelper(Ptr< const SatHelper > satHelper)
std::map< Ptr< Probe >, std::pair< Ptr< Node >, uint32_t > > m_probes
Maintains a list of probes created by this helper.
virtual void UpdateIdentifierOnProbes()
Change identifier used on probes, when handovers occur.
static TypeId GetTypeId()
inherited from ObjectBase base class
Produce forward link MAC-level delay statistics from a satellite module simulation.
std::map< Ptr< Probe >, std::pair< Ptr< Node >, uint32_t > > m_probes
Maintains a list of probes created by this helper.
SatStatsFwdMacDelayHelper(Ptr< const SatHelper > satHelper)
static TypeId GetTypeId()
inherited from ObjectBase base class
virtual void UpdateIdentifierOnProbes()
Change identifier used on probes, when handovers occur.
Produce forward link PHY-level delay statistics from a satellite module simulation.
virtual void UpdateIdentifierOnProbes()
Change identifier used on probes, when handovers occur.
std::map< Ptr< Probe >, std::pair< Ptr< Node >, uint32_t > > m_probes
Maintains a list of probes created by this helper.
static TypeId GetTypeId()
inherited from ObjectBase base class
SatStatsFwdPhyDelayHelper(Ptr< const SatHelper > satHelper)
Parent abstract class of all satellite statistics helpers.
static Ptr< NetDevice > GetSatSatOrbiterNetDevice(Ptr< Node > satNode)
uint32_t GetIdentifierForUtUser(Ptr< Node > utUserNode) const
static NetDeviceContainer GetGwSatNetDevice(Ptr< Node > gwNode)
virtual void SaveAddressAndIdentifier(Ptr< Node > utNode)
Save the address and the proper identifier from the given UT node.
static std::string GetOutputTypeName(OutputType_t outputType)
virtual std::string GetIdentifierHeading(std::string dataLabel) const
virtual std::string GetOutputPath() const
Ptr< DataCollectionObject > CreateAggregator(std::string aggregatorTypeId, std::string n1="", const AttributeValue &v1=EmptyAttributeValue(), std::string n2="", const AttributeValue &v2=EmptyAttributeValue(), std::string n3="", const AttributeValue &v3=EmptyAttributeValue(), std::string n4="", const AttributeValue &v4=EmptyAttributeValue(), std::string n5="", const AttributeValue &v5=EmptyAttributeValue())
Create the aggregator according to the output type.
virtual std::string GetOutputFileName() const
Compute the path and file name where statistics output should be written to.
uint32_t GetUtId(Ptr< Node > utNode) const
uint32_t CreateCollectorPerIdentifier(CollectorMap &collectorMap) const
Create one collector instance for each identifier in the simulation.
static Ptr< NetDevice > GetUtSatNetDevice(Ptr< Node > utNode)
OutputType_t GetOutputType() const
uint32_t GetIdentifierForUt(Ptr< Node > utNode) const
std::map< const Address, uint32_t > m_identifierMap
Map of address and the identifier associated with it.
uint32_t GetUtUserId(Ptr< Node > utUserNode) const
std::string GetName() const
virtual std::string GetTimeHeading(std::string dataLabel) const
virtual std::string GetDistributionHeading(std::string dataLabel) const
Produce return link application-level delay statistics from a satellite module simulation.
static TypeId GetTypeId()
inherited from ObjectBase base class
void Ipv4Callback(const Time &delay, const Address &from)
Receive inputs from trace sources and determine the right collector to forward the inputs to.
void RxCallback(Ptr< const Packet > packet, const Address &from)
Receive inputs from trace sources and determine the right collector to forward the inputs to.
SatStatsRtnAppDelayHelper(Ptr< const SatHelper > satHelper)
void SaveIpv4AddressAndIdentifier(Ptr< Node > utUserNode)
Save the IPv4 address and the proper identifier from the given UT user node.
Produce return link device-level delay statistics from a satellite module simulation.
SatStatsRtnDevDelayHelper(Ptr< const SatHelper > satHelper)
static TypeId GetTypeId()
inherited from ObjectBase base class
Produce return link MAC-level delay statistics from a satellite module simulation.
SatStatsRtnMacDelayHelper(Ptr< const SatHelper > satHelper)
static TypeId GetTypeId()
inherited from ObjectBase base class
Produce return link PHY-level delay statistics from a satellite module simulation.
static TypeId GetTypeId()
inherited from ObjectBase base class
SatStatsRtnPhyDelayHelper(Ptr< const SatHelper > satHelper)
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.