2009-08-31 18:50:38 +01:00
|
|
|
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
|
|
|
//
|
|
|
|
|
// Copyright (c) 2009 INESC Porto
|
|
|
|
|
//
|
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License version 2 as
|
|
|
|
|
// published by the Free Software Foundation;
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
//
|
|
|
|
|
// Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt> <gjcarneiro@gmail.com>
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include "flow-monitor.h"
|
|
|
|
|
#include "ns3/simulator.h"
|
|
|
|
|
#include "ns3/log.h"
|
|
|
|
|
#include "ns3/double.h"
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
#define PERIODIC_CHECK_INTERVAL (Seconds (1))
|
|
|
|
|
|
2014-09-26 12:44:13 -07:00
|
|
|
namespace ns3 {
|
|
|
|
|
|
2014-09-26 15:51:00 -07:00
|
|
|
NS_LOG_COMPONENT_DEFINE ("FlowMonitor");
|
|
|
|
|
|
2014-03-05 17:06:59 -08:00
|
|
|
NS_OBJECT_ENSURE_REGISTERED (FlowMonitor);
|
2011-05-13 14:54:37 -04:00
|
|
|
|
2009-08-31 18:50:38 +01:00
|
|
|
TypeId
|
|
|
|
|
FlowMonitor::GetTypeId (void)
|
|
|
|
|
{
|
|
|
|
|
static TypeId tid = TypeId ("ns3::FlowMonitor")
|
|
|
|
|
.SetParent<Object> ()
|
2015-03-29 11:30:06 +02:00
|
|
|
.SetGroupName ("FlowMonitor")
|
2009-08-31 18:50:38 +01:00
|
|
|
.AddConstructor<FlowMonitor> ()
|
|
|
|
|
.AddAttribute ("MaxPerHopDelay", ("The maximum per-hop delay that should be considered. "
|
|
|
|
|
"Packets still not received after this delay are to be considered lost."),
|
|
|
|
|
TimeValue (Seconds (10.0)),
|
|
|
|
|
MakeTimeAccessor (&FlowMonitor::m_maxPerHopDelay),
|
|
|
|
|
MakeTimeChecker ())
|
|
|
|
|
.AddAttribute ("StartTime", ("The time when the monitoring starts."),
|
|
|
|
|
TimeValue (Seconds (0.0)),
|
|
|
|
|
MakeTimeAccessor (&FlowMonitor::Start),
|
|
|
|
|
MakeTimeChecker ())
|
|
|
|
|
.AddAttribute ("DelayBinWidth", ("The width used in the delay histogram."),
|
|
|
|
|
DoubleValue (0.001),
|
|
|
|
|
MakeDoubleAccessor (&FlowMonitor::m_delayBinWidth),
|
|
|
|
|
MakeDoubleChecker <double> ())
|
|
|
|
|
.AddAttribute ("JitterBinWidth", ("The width used in the jitter histogram."),
|
|
|
|
|
DoubleValue (0.001),
|
|
|
|
|
MakeDoubleAccessor (&FlowMonitor::m_jitterBinWidth),
|
2011-05-13 14:54:37 -04:00
|
|
|
MakeDoubleChecker <double> ())
|
2009-08-31 18:50:38 +01:00
|
|
|
.AddAttribute ("PacketSizeBinWidth", ("The width used in the packetSize histogram."),
|
|
|
|
|
DoubleValue (20),
|
|
|
|
|
MakeDoubleAccessor (&FlowMonitor::m_packetSizeBinWidth),
|
|
|
|
|
MakeDoubleChecker <double> ())
|
2010-03-19 11:28:49 +00:00
|
|
|
.AddAttribute ("FlowInterruptionsBinWidth", ("The width used in the flowInterruptions histogram."),
|
|
|
|
|
DoubleValue (0.250),
|
|
|
|
|
MakeDoubleAccessor (&FlowMonitor::m_flowInterruptionsBinWidth),
|
|
|
|
|
MakeDoubleChecker <double> ())
|
|
|
|
|
.AddAttribute ("FlowInterruptionsMinTime", ("The minimum inter-arrival time that is considered a flow interruption."),
|
|
|
|
|
TimeValue (Seconds (0.5)),
|
|
|
|
|
MakeTimeAccessor (&FlowMonitor::m_flowInterruptionsMinTime),
|
|
|
|
|
MakeTimeChecker ())
|
2011-05-13 14:54:37 -04:00
|
|
|
;
|
2009-08-31 18:50:38 +01:00
|
|
|
return tid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TypeId
|
|
|
|
|
FlowMonitor::GetInstanceTypeId (void) const
|
|
|
|
|
{
|
|
|
|
|
return GetTypeId ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FlowMonitor::FlowMonitor ()
|
2011-05-13 14:54:37 -04:00
|
|
|
: m_enabled (false)
|
2009-08-31 18:50:38 +01:00
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this);
|
2022-10-25 18:47:12 +08:00
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
m_lock.store (false, std::memory_order_relaxed);
|
|
|
|
|
#endif
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-29 01:29:08 -07:00
|
|
|
void
|
|
|
|
|
FlowMonitor::DoDispose (void)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
|
Simulator::Cancel (m_startEvent);
|
|
|
|
|
Simulator::Cancel (m_stopEvent);
|
2014-04-21 11:32:45 +02:00
|
|
|
for (std::list<Ptr<FlowClassifier> >::iterator iter = m_classifiers.begin ();
|
|
|
|
|
iter != m_classifiers.end ();
|
|
|
|
|
iter ++)
|
|
|
|
|
{
|
|
|
|
|
*iter = 0;
|
|
|
|
|
}
|
2013-04-29 01:29:08 -07:00
|
|
|
for (uint32_t i = 0; i < m_flowProbes.size (); i++)
|
|
|
|
|
{
|
|
|
|
|
m_flowProbes[i]->Dispose ();
|
|
|
|
|
m_flowProbes[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
Object::DoDispose ();
|
|
|
|
|
}
|
2009-08-31 18:50:38 +01:00
|
|
|
|
|
|
|
|
inline FlowMonitor::FlowStats&
|
|
|
|
|
FlowMonitor::GetStatsForFlow (FlowId flowId)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this);
|
2014-09-19 21:25:48 +02:00
|
|
|
FlowStatsContainerI iter;
|
2009-08-31 18:50:38 +01:00
|
|
|
iter = m_flowStats.find (flowId);
|
|
|
|
|
if (iter == m_flowStats.end ())
|
|
|
|
|
{
|
|
|
|
|
FlowMonitor::FlowStats &ref = m_flowStats[flowId];
|
|
|
|
|
ref.delaySum = Seconds (0);
|
|
|
|
|
ref.jitterSum = Seconds (0);
|
|
|
|
|
ref.lastDelay = Seconds (0);
|
|
|
|
|
ref.txBytes = 0;
|
|
|
|
|
ref.rxBytes = 0;
|
|
|
|
|
ref.txPackets = 0;
|
|
|
|
|
ref.rxPackets = 0;
|
|
|
|
|
ref.lostPackets = 0;
|
|
|
|
|
ref.timesForwarded = 0;
|
|
|
|
|
ref.delayHistogram.SetDefaultBinWidth (m_delayBinWidth);
|
|
|
|
|
ref.jitterHistogram.SetDefaultBinWidth (m_jitterBinWidth);
|
|
|
|
|
ref.packetSizeHistogram.SetDefaultBinWidth (m_packetSizeBinWidth);
|
2010-03-19 11:28:49 +00:00
|
|
|
ref.flowInterruptionsHistogram.SetDefaultBinWidth (m_flowInterruptionsBinWidth);
|
2009-08-31 18:50:38 +01:00
|
|
|
return ref;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return iter->second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::ReportFirstTx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this << probe << flowId << packetId << packetSize);
|
2009-08-31 18:50:38 +01:00
|
|
|
if (!m_enabled)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Time now = Simulator::Now ();
|
2022-10-25 18:47:12 +08:00
|
|
|
|
|
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
while (m_lock.exchange (true, std::memory_order_acquire))
|
|
|
|
|
;
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-08-31 18:50:38 +01:00
|
|
|
TrackedPacket &tracked = m_trackedPackets[std::make_pair (flowId, packetId)];
|
|
|
|
|
tracked.firstSeenTime = now;
|
|
|
|
|
tracked.lastSeenTime = tracked.firstSeenTime;
|
|
|
|
|
tracked.timesForwarded = 0;
|
|
|
|
|
NS_LOG_DEBUG ("ReportFirstTx: adding tracked packet (flowId=" << flowId << ", packetId=" << packetId
|
2011-05-13 14:54:37 -04:00
|
|
|
<< ").");
|
2009-08-31 18:50:38 +01:00
|
|
|
|
|
|
|
|
probe->AddPacketStats (flowId, packetSize, Seconds (0));
|
|
|
|
|
|
|
|
|
|
FlowStats &stats = GetStatsForFlow (flowId);
|
|
|
|
|
stats.txBytes += packetSize;
|
|
|
|
|
stats.txPackets++;
|
|
|
|
|
if (stats.txPackets == 1)
|
|
|
|
|
{
|
|
|
|
|
stats.timeFirstTxPacket = now;
|
|
|
|
|
}
|
|
|
|
|
stats.timeLastTxPacket = now;
|
2022-10-25 18:47:12 +08:00
|
|
|
|
|
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
m_lock.store (false, std::memory_order_release);
|
|
|
|
|
#endif
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::ReportForwarding (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this << probe << flowId << packetId << packetSize);
|
2009-08-31 18:50:38 +01:00
|
|
|
if (!m_enabled)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2022-10-25 18:47:12 +08:00
|
|
|
|
|
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
while (m_lock.exchange (true, std::memory_order_acquire))
|
|
|
|
|
;
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-08-31 18:50:38 +01:00
|
|
|
std::pair<FlowId, FlowPacketId> key (flowId, packetId);
|
|
|
|
|
TrackedPacketMap::iterator tracked = m_trackedPackets.find (key);
|
|
|
|
|
if (tracked == m_trackedPackets.end ())
|
|
|
|
|
{
|
|
|
|
|
NS_LOG_WARN ("Received packet forward report (flowId=" << flowId << ", packetId=" << packetId
|
2011-05-13 14:54:37 -04:00
|
|
|
<< ") but not known to be transmitted.");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tracked->second.timesForwarded++;
|
|
|
|
|
tracked->second.lastSeenTime = Simulator::Now ();
|
|
|
|
|
|
|
|
|
|
Time delay = (Simulator::Now () - tracked->second.firstSeenTime);
|
|
|
|
|
probe->AddPacketStats (flowId, packetSize, delay);
|
2022-10-25 18:47:12 +08:00
|
|
|
|
|
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
m_lock.store (false, std::memory_order_release);
|
|
|
|
|
#endif
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::ReportLastRx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this << probe << flowId << packetId << packetSize);
|
2009-08-31 18:50:38 +01:00
|
|
|
if (!m_enabled)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2022-10-25 18:47:12 +08:00
|
|
|
|
|
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
while (m_lock.exchange (true, std::memory_order_acquire))
|
|
|
|
|
;
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-08-31 18:50:38 +01:00
|
|
|
TrackedPacketMap::iterator tracked = m_trackedPackets.find (std::make_pair (flowId, packetId));
|
|
|
|
|
if (tracked == m_trackedPackets.end ())
|
|
|
|
|
{
|
|
|
|
|
NS_LOG_WARN ("Received packet last-tx report (flowId=" << flowId << ", packetId=" << packetId
|
2011-05-13 14:54:37 -04:00
|
|
|
<< ") but not known to be transmitted.");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Time now = Simulator::Now ();
|
|
|
|
|
Time delay = (now - tracked->second.firstSeenTime);
|
|
|
|
|
probe->AddPacketStats (flowId, packetSize, delay);
|
|
|
|
|
|
|
|
|
|
FlowStats &stats = GetStatsForFlow (flowId);
|
|
|
|
|
stats.delaySum += delay;
|
|
|
|
|
stats.delayHistogram.AddValue (delay.GetSeconds ());
|
|
|
|
|
if (stats.rxPackets > 0 )
|
|
|
|
|
{
|
|
|
|
|
Time jitter = stats.lastDelay - delay;
|
|
|
|
|
if (jitter > Seconds (0))
|
2011-05-13 14:54:37 -04:00
|
|
|
{
|
|
|
|
|
stats.jitterSum += jitter;
|
|
|
|
|
stats.jitterHistogram.AddValue (jitter.GetSeconds ());
|
|
|
|
|
}
|
2009-08-31 18:50:38 +01:00
|
|
|
else
|
2011-05-13 14:54:37 -04:00
|
|
|
{
|
|
|
|
|
stats.jitterSum -= jitter;
|
2011-05-22 23:18:47 -07:00
|
|
|
stats.jitterHistogram.AddValue (-jitter.GetSeconds ());
|
2011-05-13 14:54:37 -04:00
|
|
|
}
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
stats.lastDelay = delay;
|
2011-05-13 14:54:37 -04:00
|
|
|
|
2009-08-31 18:50:38 +01:00
|
|
|
stats.rxBytes += packetSize;
|
|
|
|
|
stats.packetSizeHistogram.AddValue ((double) packetSize);
|
|
|
|
|
stats.rxPackets++;
|
|
|
|
|
if (stats.rxPackets == 1)
|
|
|
|
|
{
|
|
|
|
|
stats.timeFirstRxPacket = now;
|
|
|
|
|
}
|
2010-03-19 11:28:49 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// measure possible flow interruptions
|
|
|
|
|
Time interArrivalTime = now - stats.timeLastRxPacket;
|
|
|
|
|
if (interArrivalTime > m_flowInterruptionsMinTime)
|
|
|
|
|
{
|
|
|
|
|
stats.flowInterruptionsHistogram.AddValue (interArrivalTime.GetSeconds ());
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-31 18:50:38 +01:00
|
|
|
stats.timeLastRxPacket = now;
|
|
|
|
|
stats.timesForwarded += tracked->second.timesForwarded;
|
|
|
|
|
|
|
|
|
|
NS_LOG_DEBUG ("ReportLastTx: removing tracked packet (flowId="
|
|
|
|
|
<< flowId << ", packetId=" << packetId << ").");
|
|
|
|
|
|
|
|
|
|
m_trackedPackets.erase (tracked); // we don't need to track this packet anymore
|
2022-10-25 18:47:12 +08:00
|
|
|
|
|
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
m_lock.store (false, std::memory_order_release);
|
|
|
|
|
#endif
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::ReportDrop (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize,
|
|
|
|
|
uint32_t reasonCode)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this << probe << flowId << packetId << packetSize << reasonCode);
|
2009-08-31 18:50:38 +01:00
|
|
|
if (!m_enabled)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 18:47:12 +08:00
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
while (m_lock.exchange (true, std::memory_order_acquire))
|
|
|
|
|
;
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-08-31 18:50:38 +01:00
|
|
|
probe->AddPacketDropStats (flowId, packetSize, reasonCode);
|
|
|
|
|
|
|
|
|
|
FlowStats &stats = GetStatsForFlow (flowId);
|
|
|
|
|
stats.lostPackets++;
|
|
|
|
|
if (stats.packetsDropped.size () < reasonCode + 1)
|
|
|
|
|
{
|
|
|
|
|
stats.packetsDropped.resize (reasonCode + 1, 0);
|
|
|
|
|
stats.bytesDropped.resize (reasonCode + 1, 0);
|
|
|
|
|
}
|
|
|
|
|
++stats.packetsDropped[reasonCode];
|
|
|
|
|
stats.bytesDropped[reasonCode] += packetSize;
|
|
|
|
|
NS_LOG_DEBUG ("++stats.packetsDropped[" << reasonCode<< "]; // becomes: " << stats.packetsDropped[reasonCode]);
|
|
|
|
|
|
|
|
|
|
TrackedPacketMap::iterator tracked = m_trackedPackets.find (std::make_pair (flowId, packetId));
|
|
|
|
|
if (tracked != m_trackedPackets.end ())
|
|
|
|
|
{
|
|
|
|
|
// we don't need to track this packet anymore
|
|
|
|
|
// FIXME: this will not necessarily be true with broadcast/multicast
|
|
|
|
|
NS_LOG_DEBUG ("ReportDrop: removing tracked packet (flowId="
|
|
|
|
|
<< flowId << ", packetId=" << packetId << ").");
|
|
|
|
|
m_trackedPackets.erase (tracked);
|
|
|
|
|
}
|
2022-10-25 18:47:12 +08:00
|
|
|
|
|
|
|
|
#ifdef NS3_MTP
|
|
|
|
|
m_lock.store (false, std::memory_order_release);
|
|
|
|
|
#endif
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
2014-09-19 21:25:48 +02:00
|
|
|
const FlowMonitor::FlowStatsContainer&
|
2009-08-31 18:50:38 +01:00
|
|
|
FlowMonitor::GetFlowStats () const
|
|
|
|
|
{
|
|
|
|
|
return m_flowStats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::CheckForLostPackets (Time maxDelay)
|
|
|
|
|
{
|
2020-03-27 13:43:49 -07:00
|
|
|
NS_LOG_FUNCTION (this << maxDelay.As (Time::S));
|
2009-08-31 18:50:38 +01:00
|
|
|
Time now = Simulator::Now ();
|
2011-05-13 14:54:37 -04:00
|
|
|
|
2009-08-31 18:50:38 +01:00
|
|
|
for (TrackedPacketMap::iterator iter = m_trackedPackets.begin ();
|
|
|
|
|
iter != m_trackedPackets.end (); )
|
|
|
|
|
{
|
|
|
|
|
if (now - iter->second.lastSeenTime >= maxDelay)
|
|
|
|
|
{
|
|
|
|
|
// packet is considered lost, add it to the loss statistics
|
2014-09-19 21:25:48 +02:00
|
|
|
FlowStatsContainerI flow = m_flowStats.find (iter->first.first);
|
2009-08-31 18:50:38 +01:00
|
|
|
NS_ASSERT (flow != m_flowStats.end ());
|
|
|
|
|
flow->second.lostPackets++;
|
|
|
|
|
|
|
|
|
|
// we won't track it anymore
|
|
|
|
|
m_trackedPackets.erase (iter++);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
iter++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::CheckForLostPackets ()
|
|
|
|
|
{
|
|
|
|
|
CheckForLostPackets (m_maxPerHopDelay);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::PeriodicCheckForLostPackets ()
|
|
|
|
|
{
|
|
|
|
|
CheckForLostPackets ();
|
|
|
|
|
Simulator::Schedule (PERIODIC_CHECK_INTERVAL, &FlowMonitor::PeriodicCheckForLostPackets, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::NotifyConstructionCompleted ()
|
|
|
|
|
{
|
|
|
|
|
Object::NotifyConstructionCompleted ();
|
|
|
|
|
Simulator::Schedule (PERIODIC_CHECK_INTERVAL, &FlowMonitor::PeriodicCheckForLostPackets, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::AddProbe (Ptr<FlowProbe> probe)
|
|
|
|
|
{
|
|
|
|
|
m_flowProbes.push_back (probe);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-19 21:25:48 +02:00
|
|
|
|
|
|
|
|
const FlowMonitor::FlowProbeContainer&
|
2009-08-31 18:50:38 +01:00
|
|
|
FlowMonitor::GetAllProbes () const
|
|
|
|
|
{
|
|
|
|
|
return m_flowProbes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::Start (const Time &time)
|
|
|
|
|
{
|
2020-03-27 13:43:49 -07:00
|
|
|
NS_LOG_FUNCTION (this << time.As (Time::S));
|
2009-08-31 18:50:38 +01:00
|
|
|
if (m_enabled)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_DEBUG ("FlowMonitor already enabled; returning");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Simulator::Cancel (m_startEvent);
|
2020-03-27 13:43:49 -07:00
|
|
|
NS_LOG_DEBUG ("Scheduling start at " << time.As (Time::S));
|
2013-04-29 01:29:08 -07:00
|
|
|
m_startEvent = Simulator::Schedule (time, &FlowMonitor::StartRightNow, this);
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::Stop (const Time &time)
|
|
|
|
|
{
|
2020-03-27 13:43:49 -07:00
|
|
|
NS_LOG_FUNCTION (this << time.As (Time::S));
|
2009-08-31 18:50:38 +01:00
|
|
|
Simulator::Cancel (m_stopEvent);
|
2020-03-27 13:43:49 -07:00
|
|
|
NS_LOG_DEBUG ("Scheduling stop at " << time.As (Time::S));
|
2013-04-29 01:29:08 -07:00
|
|
|
m_stopEvent = Simulator::Schedule (time, &FlowMonitor::StopRightNow, this);
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::StartRightNow ()
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this);
|
2009-08-31 18:50:38 +01:00
|
|
|
if (m_enabled)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_DEBUG ("FlowMonitor already enabled; returning");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_enabled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::StopRightNow ()
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this);
|
2009-08-31 18:50:38 +01:00
|
|
|
if (!m_enabled)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_DEBUG ("FlowMonitor not enabled; returning");
|
2009-08-31 18:50:38 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_enabled = false;
|
|
|
|
|
CheckForLostPackets ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2014-04-21 11:32:45 +02:00
|
|
|
FlowMonitor::AddFlowClassifier (Ptr<FlowClassifier> classifier)
|
2009-08-31 18:50:38 +01:00
|
|
|
{
|
2014-04-21 11:32:45 +02:00
|
|
|
m_classifiers.push_back (classifier);
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2016-11-12 01:03:56 +01:00
|
|
|
FlowMonitor::SerializeToXmlStream (std::ostream &os, uint16_t indent, bool enableHistograms, bool enableProbes)
|
2009-08-31 18:50:38 +01:00
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this << indent << enableHistograms << enableProbes);
|
2009-08-31 18:50:38 +01:00
|
|
|
CheckForLostPackets ();
|
2011-05-13 14:54:37 -04:00
|
|
|
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' ) << "<FlowMonitor>\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
indent += 2;
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' ) << "<FlowStats>\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
indent += 2;
|
2014-09-19 21:25:48 +02:00
|
|
|
for (FlowStatsContainerCI flowI = m_flowStats.begin ();
|
2009-08-31 18:50:38 +01:00
|
|
|
flowI != m_flowStats.end (); flowI++)
|
|
|
|
|
{
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' );
|
2011-05-13 14:54:37 -04:00
|
|
|
#define ATTRIB(name) << " " # name "=\"" << flowI->second.name << "\""
|
2021-09-12 16:19:14 +00:00
|
|
|
#define ATTRIB_TIME(name) << " " #name "=\"" << flowI->second.name.As (Time::NS) << "\""
|
2009-08-31 18:50:38 +01:00
|
|
|
os << "<Flow flowId=\"" << flowI->first << "\""
|
2021-09-12 16:19:14 +00:00
|
|
|
ATTRIB_TIME (timeFirstTxPacket)
|
|
|
|
|
ATTRIB_TIME (timeFirstRxPacket)
|
|
|
|
|
ATTRIB_TIME (timeLastTxPacket)
|
|
|
|
|
ATTRIB_TIME (timeLastRxPacket)
|
|
|
|
|
ATTRIB_TIME (delaySum)
|
|
|
|
|
ATTRIB_TIME (jitterSum)
|
|
|
|
|
ATTRIB_TIME (lastDelay)
|
2011-05-22 23:18:47 -07:00
|
|
|
ATTRIB (txBytes)
|
|
|
|
|
ATTRIB (rxBytes)
|
|
|
|
|
ATTRIB (txPackets)
|
|
|
|
|
ATTRIB (rxPackets)
|
|
|
|
|
ATTRIB (lostPackets)
|
|
|
|
|
ATTRIB (timesForwarded)
|
2011-05-22 22:28:15 -07:00
|
|
|
<< ">\n";
|
2021-09-12 16:19:14 +00:00
|
|
|
#undef ATTRIB_TIME
|
2009-08-31 18:50:38 +01:00
|
|
|
#undef ATTRIB
|
|
|
|
|
|
|
|
|
|
indent += 2;
|
|
|
|
|
for (uint32_t reasonCode = 0; reasonCode < flowI->second.packetsDropped.size (); reasonCode++)
|
|
|
|
|
{
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' );
|
2009-08-31 18:50:38 +01:00
|
|
|
os << "<packetsDropped reasonCode=\"" << reasonCode << "\""
|
2011-05-22 22:28:15 -07:00
|
|
|
<< " number=\"" << flowI->second.packetsDropped[reasonCode]
|
|
|
|
|
<< "\" />\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
for (uint32_t reasonCode = 0; reasonCode < flowI->second.bytesDropped.size (); reasonCode++)
|
|
|
|
|
{
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' );
|
2009-08-31 18:50:38 +01:00
|
|
|
os << "<bytesDropped reasonCode=\"" << reasonCode << "\""
|
2011-05-22 22:28:15 -07:00
|
|
|
<< " bytes=\"" << flowI->second.bytesDropped[reasonCode]
|
|
|
|
|
<< "\" />\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
if (enableHistograms)
|
|
|
|
|
{
|
|
|
|
|
flowI->second.delayHistogram.SerializeToXmlStream (os, indent, "delayHistogram");
|
|
|
|
|
flowI->second.jitterHistogram.SerializeToXmlStream (os, indent, "jitterHistogram");
|
|
|
|
|
flowI->second.packetSizeHistogram.SerializeToXmlStream (os, indent, "packetSizeHistogram");
|
2010-03-19 11:28:49 +00:00
|
|
|
flowI->second.flowInterruptionsHistogram.SerializeToXmlStream (os, indent, "flowInterruptionsHistogram");
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
indent -= 2;
|
|
|
|
|
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' ) << "</Flow>\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
indent -= 2;
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' ) << "</FlowStats>\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
|
2014-04-21 11:32:45 +02:00
|
|
|
for (std::list<Ptr<FlowClassifier> >::iterator iter = m_classifiers.begin ();
|
|
|
|
|
iter != m_classifiers.end ();
|
|
|
|
|
iter ++)
|
|
|
|
|
{
|
|
|
|
|
(*iter)->SerializeToXmlStream (os, indent);
|
|
|
|
|
}
|
2009-08-31 18:50:38 +01:00
|
|
|
|
|
|
|
|
if (enableProbes)
|
|
|
|
|
{
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' ) << "<FlowProbes>\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
indent += 2;
|
|
|
|
|
for (uint32_t i = 0; i < m_flowProbes.size (); i++)
|
|
|
|
|
{
|
|
|
|
|
m_flowProbes[i]->SerializeToXmlStream (os, indent, i);
|
|
|
|
|
}
|
|
|
|
|
indent -= 2;
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' ) << "</FlowProbes>\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
indent -= 2;
|
2017-01-22 16:50:12 +01:00
|
|
|
os << std::string ( indent, ' ' ) << "</FlowMonitor>\n";
|
2009-08-31 18:50:38 +01:00
|
|
|
}
|
2011-05-13 14:54:37 -04:00
|
|
|
|
2009-08-31 18:50:38 +01:00
|
|
|
|
|
|
|
|
std::string
|
2016-11-12 01:03:56 +01:00
|
|
|
FlowMonitor::SerializeToXmlString (uint16_t indent, bool enableHistograms, bool enableProbes)
|
2009-08-31 18:50:38 +01:00
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this << indent << enableHistograms << enableProbes);
|
2009-08-31 18:50:38 +01:00
|
|
|
std::ostringstream os;
|
|
|
|
|
SerializeToXmlStream (os, indent, enableHistograms, enableProbes);
|
|
|
|
|
return os.str ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FlowMonitor::SerializeToXmlFile (std::string fileName, bool enableHistograms, bool enableProbes)
|
|
|
|
|
{
|
2019-01-29 10:27:12 -08:00
|
|
|
NS_LOG_FUNCTION (this << fileName << enableHistograms << enableProbes);
|
2009-08-31 18:50:38 +01:00
|
|
|
std::ofstream os (fileName.c_str (), std::ios::out|std::ios::binary);
|
|
|
|
|
os << "<?xml version=\"1.0\" ?>\n";
|
|
|
|
|
SerializeToXmlStream (os, 0, enableHistograms, enableProbes);
|
|
|
|
|
os.close ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace ns3
|
|
|
|
|
|