Add a new 'flow-monitor' module.
This commit is contained in:
43
src/contrib/flow-monitor/design.txt
Normal file
43
src/contrib/flow-monitor/design.txt
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
* One FlowMonitor per simulation
|
||||
|
||||
* One FlowClassifier per simulation
|
||||
- Assigns integer simulation unique identifiers to each flow
|
||||
- Contains a classification method that maps parameters
|
||||
(e.g. packets or packet headers) to the corresponding flow
|
||||
identifier;
|
||||
- FlowClassifier is abstract, needs a concrete subclass
|
||||
> Ipv4FlowClassifier
|
||||
|
||||
* Typically (but not necessarily) one FlowProbe node
|
||||
- Is responsible for acquiring the packet data
|
||||
- Works with FlowClassifier
|
||||
- FlowProbe is abstract, needs a concrete subclass
|
||||
> Ipv4FlowProbe
|
||||
- Ipv4FlowProbe needs a matching classifier, Ipv4FlowClassifier
|
||||
|
||||
* One ProbeFlowStats object per simulation flow per FlowProbe
|
||||
- Indexed by the FlowId
|
||||
- Bytes
|
||||
- Packets
|
||||
- Delay from first probe until the packet is received in this probe
|
||||
|
||||
* One EndToEndFlowStats object per flow per FlowMonitor
|
||||
- Lost packets
|
||||
- Lost bytes
|
||||
- Bytes
|
||||
- Packets
|
||||
- End-to-end delays
|
||||
|
||||
|
||||
|
||||
|
||||
TODO:
|
||||
|
||||
1. Configurable time when to start/stop monitor. ***DONE***
|
||||
2. Possibly, detect packet losses also via "drop" trace sources
|
||||
3. FlowMonitor::FlowStats: add time duration metrics: first flow timestamp, last flow timestamp
|
||||
> to calculate bitrates... ***DONE***
|
||||
4. Measure delay jitter
|
||||
5. Histogram for delays/jitters/packet sizes
|
||||
|
||||
40
src/contrib/flow-monitor/flow-classifier.cc
Normal file
40
src/contrib/flow-monitor/flow-classifier.cc
Normal file
@@ -0,0 +1,40 @@
|
||||
/* -*- 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-classifier.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
FlowClassifier::FlowClassifier ()
|
||||
:
|
||||
m_lastNewFlowId (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FlowId
|
||||
FlowClassifier::GetNewFlowId ()
|
||||
{
|
||||
return ++m_lastNewFlowId;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
52
src/contrib/flow-monitor/flow-classifier.h
Normal file
52
src/contrib/flow-monitor/flow-classifier.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* -*- 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>
|
||||
//
|
||||
|
||||
#ifndef __FLOW_CLASSIFIER_H__
|
||||
#define __FLOW_CLASSIFIER_H__
|
||||
|
||||
#include "ns3/ref-count-base.h"
|
||||
#include <ostream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
typedef uint32_t FlowId;
|
||||
typedef uint32_t FlowPacketId;
|
||||
|
||||
|
||||
class FlowClassifier : public RefCountBase
|
||||
{
|
||||
FlowId m_lastNewFlowId;
|
||||
|
||||
public:
|
||||
|
||||
FlowClassifier ();
|
||||
|
||||
virtual void SerializeToXmlStream (std::ostream &os, int indent) const = 0;
|
||||
|
||||
protected:
|
||||
FlowId GetNewFlowId ();
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
|
||||
468
src/contrib/flow-monitor/flow-monitor.cc
Normal file
468
src/contrib/flow-monitor/flow-monitor.cc
Normal file
@@ -0,0 +1,468 @@
|
||||
/* -*- 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 INDENT(level) for (int __xpto = 0; __xpto < level; __xpto++) os << ' ';
|
||||
|
||||
#define PERIODIC_CHECK_INTERVAL (Seconds (1))
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("FlowMonitor");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (FlowMonitor);
|
||||
|
||||
|
||||
TypeId
|
||||
FlowMonitor::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::FlowMonitor")
|
||||
.SetParent<Object> ()
|
||||
.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),
|
||||
MakeDoubleChecker <double> ())
|
||||
.AddAttribute ("PacketSizeBinWidth", ("The width used in the packetSize histogram."),
|
||||
DoubleValue (20),
|
||||
MakeDoubleAccessor (&FlowMonitor::m_packetSizeBinWidth),
|
||||
MakeDoubleChecker <double> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
FlowMonitor::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
FlowMonitor::FlowMonitor ()
|
||||
: m_enabled (false)
|
||||
{
|
||||
// m_histogramBinWidth=DEFAULT_BIN_WIDTH;
|
||||
}
|
||||
|
||||
|
||||
inline FlowMonitor::FlowStats&
|
||||
FlowMonitor::GetStatsForFlow (FlowId flowId)
|
||||
{
|
||||
std::map<FlowId, FlowStats>::iterator iter;
|
||||
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);
|
||||
return ref;
|
||||
}
|
||||
else
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FlowMonitor::ReportFirstTx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
|
||||
{
|
||||
if (!m_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time now = Simulator::Now ();
|
||||
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
|
||||
<< ").");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FlowMonitor::ReportForwarding (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
|
||||
{
|
||||
if (!m_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
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
|
||||
<< ") but not known to be transmitted.");
|
||||
return;
|
||||
}
|
||||
|
||||
tracked->second.timesForwarded++;
|
||||
tracked->second.lastSeenTime = Simulator::Now ();
|
||||
|
||||
Time delay = (Simulator::Now () - tracked->second.firstSeenTime);
|
||||
probe->AddPacketStats (flowId, packetSize, delay);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FlowMonitor::ReportLastRx (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize)
|
||||
{
|
||||
if (!m_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
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
|
||||
<< ") but not known to be transmitted.");
|
||||
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))
|
||||
{
|
||||
stats.jitterSum += jitter;
|
||||
stats.jitterHistogram.AddValue (jitter.GetSeconds ());
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.jitterSum -= jitter;
|
||||
stats.jitterHistogram.AddValue (-jitter.GetSeconds());
|
||||
}
|
||||
}
|
||||
stats.lastDelay = delay;
|
||||
|
||||
stats.rxBytes += packetSize;
|
||||
stats.packetSizeHistogram.AddValue ((double) packetSize);
|
||||
stats.rxPackets++;
|
||||
if (stats.rxPackets == 1)
|
||||
{
|
||||
stats.timeFirstRxPacket = now;
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
void
|
||||
FlowMonitor::ReportDrop (Ptr<FlowProbe> probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize,
|
||||
uint32_t reasonCode)
|
||||
{
|
||||
if (!m_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<FlowId, FlowMonitor::FlowStats>
|
||||
FlowMonitor::GetFlowStats () const
|
||||
{
|
||||
return m_flowStats;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FlowMonitor::CheckForLostPackets (Time maxDelay)
|
||||
{
|
||||
Time now = Simulator::Now ();
|
||||
|
||||
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
|
||||
std::map<FlowId, FlowStats>::iterator
|
||||
flow = m_flowStats.find (iter->first.first);
|
||||
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);
|
||||
}
|
||||
|
||||
std::vector< Ptr<FlowProbe> >
|
||||
FlowMonitor::GetAllProbes () const
|
||||
{
|
||||
return m_flowProbes;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FlowMonitor::Start (const Time &time)
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Simulator::Cancel (m_startEvent);
|
||||
m_startEvent = Simulator::Schedule (time, &FlowMonitor::StartRightNow, Ptr<FlowMonitor> (this));
|
||||
}
|
||||
|
||||
void
|
||||
FlowMonitor::Stop (const Time &time)
|
||||
{
|
||||
if (!m_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Simulator::Cancel (m_stopEvent);
|
||||
m_stopEvent = Simulator::Schedule (time, &FlowMonitor::StopRightNow, Ptr<FlowMonitor> (this));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FlowMonitor::StartRightNow ()
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_enabled = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FlowMonitor::StopRightNow ()
|
||||
{
|
||||
if (!m_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_enabled = false;
|
||||
CheckForLostPackets ();
|
||||
}
|
||||
|
||||
void
|
||||
FlowMonitor::SetFlowClassifier (Ptr<FlowClassifier> classifier)
|
||||
{
|
||||
m_classifier = classifier;
|
||||
}
|
||||
|
||||
void
|
||||
FlowMonitor::SerializeToXmlStream (std::ostream &os, int indent, bool enableHistograms, bool enableProbes)
|
||||
{
|
||||
CheckForLostPackets ();
|
||||
|
||||
INDENT(indent); os << "<FlowMonitor>\n";
|
||||
indent += 2;
|
||||
INDENT(indent); os << "<FlowStats>\n";
|
||||
indent += 2;
|
||||
for (std::map<FlowId, FlowStats>::const_iterator flowI = m_flowStats.begin ();
|
||||
flowI != m_flowStats.end (); flowI++)
|
||||
{
|
||||
|
||||
INDENT(indent);
|
||||
#define ATTRIB(name) << " "#name"=\"" << flowI->second.name << "\""
|
||||
os << "<Flow flowId=\"" << flowI->first << "\""
|
||||
ATTRIB(timeFirstTxPacket)
|
||||
ATTRIB(timeFirstRxPacket)
|
||||
ATTRIB(timeLastTxPacket)
|
||||
ATTRIB(timeLastRxPacket)
|
||||
ATTRIB(delaySum)
|
||||
ATTRIB(jitterSum)
|
||||
ATTRIB(lastDelay)
|
||||
ATTRIB(txBytes)
|
||||
ATTRIB(rxBytes)
|
||||
ATTRIB(txPackets)
|
||||
ATTRIB(rxPackets)
|
||||
ATTRIB(lostPackets)
|
||||
ATTRIB(timesForwarded)
|
||||
<< ">\n";
|
||||
#undef ATTRIB
|
||||
|
||||
|
||||
indent += 2;
|
||||
for (uint32_t reasonCode = 0; reasonCode < flowI->second.packetsDropped.size (); reasonCode++)
|
||||
{
|
||||
INDENT(indent);
|
||||
os << "<packetsDropped reasonCode=\"" << reasonCode << "\""
|
||||
<< " number=\"" << flowI->second.packetsDropped[reasonCode]
|
||||
<< "\" />\n";
|
||||
}
|
||||
for (uint32_t reasonCode = 0; reasonCode < flowI->second.bytesDropped.size (); reasonCode++)
|
||||
{
|
||||
INDENT(indent);
|
||||
os << "<bytesDropped reasonCode=\"" << reasonCode << "\""
|
||||
<< " bytes=\"" << flowI->second.bytesDropped[reasonCode]
|
||||
<< "\" />\n";
|
||||
}
|
||||
if (enableHistograms)
|
||||
{
|
||||
flowI->second.delayHistogram.SerializeToXmlStream (os, indent, "delayHistogram");
|
||||
flowI->second.jitterHistogram.SerializeToXmlStream (os, indent, "jitterHistogram");
|
||||
flowI->second.packetSizeHistogram.SerializeToXmlStream (os, indent, "packetSizeHistogram");
|
||||
}
|
||||
indent -= 2;
|
||||
|
||||
INDENT(indent); os << "</Flow>\n";
|
||||
}
|
||||
indent -= 2;
|
||||
INDENT(indent); os << "</FlowStats>\n";
|
||||
|
||||
m_classifier->SerializeToXmlStream (os, indent);
|
||||
|
||||
if (enableProbes)
|
||||
{
|
||||
INDENT(indent); os << "<FlowProbes>\n";
|
||||
indent += 2;
|
||||
for (uint32_t i = 0; i < m_flowProbes.size (); i++)
|
||||
{
|
||||
m_flowProbes[i]->SerializeToXmlStream (os, indent, i);
|
||||
}
|
||||
indent -= 2;
|
||||
INDENT(indent); os << "</FlowProbes>\n";
|
||||
}
|
||||
|
||||
indent -= 2;
|
||||
INDENT(indent); os << "</FlowMonitor>\n";
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
FlowMonitor::SerializeToXmlString (int indent, bool enableHistograms, bool enableProbes)
|
||||
{
|
||||
std::ostringstream os;
|
||||
SerializeToXmlStream (os, indent, enableHistograms, enableProbes);
|
||||
return os.str ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FlowMonitor::SerializeToXmlFile (std::string fileName, bool enableHistograms, bool enableProbes)
|
||||
{
|
||||
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
|
||||
|
||||
138
src/contrib/flow-monitor/flow-monitor.h
Normal file
138
src/contrib/flow-monitor/flow-monitor.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/* -*- 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>
|
||||
//
|
||||
|
||||
#ifndef __FLOW_MONITOR_H__
|
||||
#define __FLOW_MONITOR_H__
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/flow-probe.h"
|
||||
#include "ns3/flow-classifier.h"
|
||||
#include "ns3/histogram.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/event-id.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
class FlowMonitor : public Object
|
||||
{
|
||||
public:
|
||||
|
||||
struct FlowStats
|
||||
{
|
||||
Time timeFirstTxPacket;
|
||||
Time timeFirstRxPacket;
|
||||
Time timeLastTxPacket;
|
||||
Time timeLastRxPacket;
|
||||
Time delaySum; // delayCount == rxPackets
|
||||
Time jitterSum; // jitterCount == rxPackets - 1
|
||||
Time lastDelay;
|
||||
uint64_t txBytes;
|
||||
uint64_t rxBytes;
|
||||
uint32_t txPackets;
|
||||
uint32_t rxPackets;
|
||||
uint32_t lostPackets;
|
||||
uint32_t timesForwarded; // number of times a packet was forwarded, summed for all received packets
|
||||
Histogram delayHistogram;
|
||||
Histogram jitterHistogram;
|
||||
Histogram packetSizeHistogram;
|
||||
std::vector<uint32_t> packetsDropped; // packetsDropped[reasonCode] => number of dropped packets
|
||||
std::vector<uint64_t> bytesDropped; // bytesDropped[reasonCode] => number of dropped bytes
|
||||
};
|
||||
|
||||
// --- basic methods ---
|
||||
static TypeId GetTypeId ();
|
||||
TypeId GetInstanceTypeId () const;
|
||||
FlowMonitor ();
|
||||
void SetFlowClassifier (Ptr<FlowClassifier> classifier);
|
||||
|
||||
void Start (const Time &time);
|
||||
void Stop (const Time &time);
|
||||
void StartRightNow ();
|
||||
void StopRightNow ();
|
||||
|
||||
// --- methods to be used by the FlowMonitorProbe's only ---
|
||||
void AddProbe (Ptr<FlowProbe> probe);
|
||||
void ReportFirstTx (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
|
||||
void ReportForwarding (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
|
||||
void ReportLastRx (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
|
||||
void ReportDrop (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId,
|
||||
uint32_t packetSize, uint32_t reasonCode);
|
||||
|
||||
|
||||
/// Check right now for packets that appear to be lost
|
||||
void CheckForLostPackets ();
|
||||
void CheckForLostPackets (Time maxDelay);
|
||||
|
||||
// --- methods to get the results ---
|
||||
// remember to call CheckForLostPackets first!
|
||||
std::map<FlowId, FlowStats> GetFlowStats () const;
|
||||
std::vector< Ptr<FlowProbe> > GetAllProbes () const;
|
||||
|
||||
void SerializeToXmlStream (std::ostream &os, int indent, bool enableHistograms, bool enableProbes);
|
||||
std::string SerializeToXmlString (int indent, bool enableHistograms, bool enableProbes);
|
||||
void SerializeToXmlFile (std::string fileName, bool enableHistograms, bool enableProbes);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
virtual void NotifyConstructionCompleted ();
|
||||
|
||||
private:
|
||||
|
||||
struct TrackedPacket
|
||||
{
|
||||
Time firstSeenTime; // absolute time when the packet was first seen by a probe
|
||||
Time lastSeenTime; // absolute time when the packet was last seen by a probe
|
||||
uint32_t timesForwarded; // number of times the packet was reportedly forwarded
|
||||
};
|
||||
|
||||
// FlowId --> FlowStats
|
||||
std::map<FlowId, FlowStats> m_flowStats;
|
||||
|
||||
// (FlowId,PacketId) --> TrackedPacket
|
||||
typedef std::map< std::pair<FlowId, FlowPacketId>, TrackedPacket> TrackedPacketMap;
|
||||
TrackedPacketMap m_trackedPackets;
|
||||
Time m_maxPerHopDelay;
|
||||
std::vector< Ptr<FlowProbe> > m_flowProbes;
|
||||
|
||||
// note: this is needed only for serialization
|
||||
Ptr<FlowClassifier> m_classifier;
|
||||
|
||||
EventId m_startEvent;
|
||||
EventId m_stopEvent;
|
||||
bool m_enabled;
|
||||
double m_delayBinWidth;
|
||||
double m_jitterBinWidth;
|
||||
double m_packetSizeBinWidth;
|
||||
|
||||
FlowStats& GetStatsForFlow (FlowId flowId);
|
||||
void PeriodicCheckForLostPackets ();
|
||||
};
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
|
||||
111
src/contrib/flow-monitor/flow-probe.cc
Normal file
111
src/contrib/flow-monitor/flow-probe.cc
Normal file
@@ -0,0 +1,111 @@
|
||||
/* -*- 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 "ns3/flow-probe.h"
|
||||
#include "ns3/flow-monitor.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
FlowProbe::~FlowProbe ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FlowProbe::FlowProbe (Ptr<FlowMonitor> flowMonitor)
|
||||
: m_flowMonitor (flowMonitor)
|
||||
{
|
||||
m_flowMonitor->AddProbe (this);
|
||||
}
|
||||
|
||||
void
|
||||
FlowProbe::AddPacketStats (FlowId flowId, uint32_t packetSize, Time delayFromFirstProbe)
|
||||
{
|
||||
FlowStats &flow = m_stats[flowId];
|
||||
flow.delayFromFirstProbeSum += delayFromFirstProbe;
|
||||
flow.bytes += packetSize;
|
||||
++flow.packets;
|
||||
}
|
||||
|
||||
void
|
||||
FlowProbe::AddPacketDropStats (FlowId flowId, uint32_t packetSize, uint32_t reasonCode)
|
||||
{
|
||||
FlowStats &flow = m_stats[flowId];
|
||||
|
||||
if (flow.packetsDropped.size () < reasonCode + 1)
|
||||
{
|
||||
flow.packetsDropped.resize (reasonCode + 1, 0);
|
||||
flow.bytesDropped.resize (reasonCode + 1, 0);
|
||||
}
|
||||
++flow.packetsDropped[reasonCode];
|
||||
flow.bytesDropped[reasonCode] += packetSize;
|
||||
}
|
||||
|
||||
FlowProbe::Stats
|
||||
FlowProbe::GetStats () const
|
||||
{
|
||||
return m_stats;
|
||||
}
|
||||
|
||||
void
|
||||
FlowProbe::SerializeToXmlStream (std::ostream &os, int indent, uint32_t index) const
|
||||
{
|
||||
#define INDENT(level) for (int __xpto = 0; __xpto < level; __xpto++) os << ' ';
|
||||
|
||||
INDENT(indent); os << "<FlowProbe index=\"" << index << "\">\n";
|
||||
|
||||
indent += 2;
|
||||
|
||||
for (Stats::const_iterator iter = m_stats.begin (); iter != m_stats.end (); iter++)
|
||||
{
|
||||
INDENT(indent);
|
||||
os << "<FlowStats "
|
||||
<< " flowId=\"" << iter->first << "\""
|
||||
<< " packets=\"" << iter->second.packets << "\""
|
||||
<< " bytes=\"" << iter->second.bytes << "\""
|
||||
<< " delayFromFirstProbeSum=\"" << iter->second.delayFromFirstProbeSum << "\""
|
||||
<< " >\n";
|
||||
indent += 2;
|
||||
for (uint32_t reasonCode = 0; reasonCode < iter->second.packetsDropped.size (); reasonCode++)
|
||||
{
|
||||
INDENT(indent);
|
||||
os << "<packetsDropped reasonCode=\"" << reasonCode << "\""
|
||||
<< " number=\"" << iter->second.packetsDropped[reasonCode]
|
||||
<< "\" />\n";
|
||||
}
|
||||
for (uint32_t reasonCode = 0; reasonCode < iter->second.bytesDropped.size (); reasonCode++)
|
||||
{
|
||||
INDENT(indent);
|
||||
os << "<bytesDropped reasonCode=\"" << reasonCode << "\""
|
||||
<< " bytes=\"" << iter->second.bytesDropped[reasonCode]
|
||||
<< "\" />\n";
|
||||
}
|
||||
indent -= 2;
|
||||
INDENT(indent); os << "</FlowStats>\n";
|
||||
}
|
||||
indent -= 2;
|
||||
INDENT(indent); os << "</FlowProbe>\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
74
src/contrib/flow-monitor/flow-probe.h
Normal file
74
src/contrib/flow-monitor/flow-probe.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* -*- 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>
|
||||
//
|
||||
|
||||
#ifndef __FLOW_PROBE_H__
|
||||
#define __FLOW_PROBE_H__
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "ns3/ref-count-base.h"
|
||||
#include "ns3/flow-classifier.h"
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class FlowMonitor;
|
||||
|
||||
|
||||
class FlowProbe : public RefCountBase
|
||||
{
|
||||
protected:
|
||||
|
||||
FlowProbe (Ptr<FlowMonitor> flowMonitor);
|
||||
|
||||
public:
|
||||
~FlowProbe ();
|
||||
|
||||
struct FlowStats
|
||||
{
|
||||
FlowStats () : delayFromFirstProbeSum (Seconds (0)), bytes (0), packets (0) {}
|
||||
|
||||
std::vector<uint32_t> packetsDropped; // packetsDropped[reasonCode] => number of dropped packets
|
||||
std::vector<uint64_t> bytesDropped; // bytesDropped[reasonCode] => number of dropped bytes
|
||||
Time delayFromFirstProbeSum; // divide by 'Scalar (packets)' to get the average delay
|
||||
uint64_t bytes;
|
||||
uint32_t packets;
|
||||
};
|
||||
|
||||
typedef std::map<FlowId, FlowStats> Stats;
|
||||
|
||||
void AddPacketStats (FlowId flowId, uint32_t packetSize, Time delayFromFirstProbe);
|
||||
void AddPacketDropStats (FlowId flowId, uint32_t packetSize, uint32_t reasonCode);
|
||||
Stats GetStats () const;
|
||||
|
||||
void SerializeToXmlStream (std::ostream &os, int indent, uint32_t index) const;
|
||||
|
||||
protected:
|
||||
Ptr<FlowMonitor> m_flowMonitor;
|
||||
Stats m_stats;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
|
||||
212
src/contrib/flow-monitor/histogram.cc
Normal file
212
src/contrib/flow-monitor/histogram.cc
Normal file
@@ -0,0 +1,212 @@
|
||||
/* -*- 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: Pedro Fortuna <pedro.fortuna@inescporto.pt> <pedro.fortuna@gmail.com>
|
||||
//
|
||||
|
||||
#include <math.h>
|
||||
#include "histogram.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
#define DEFAULT_BIN_WIDTH 1
|
||||
// #define RESERVED_BINS_INC 10
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("Histogram");
|
||||
|
||||
// uint32_t
|
||||
// Histogram::GetSize () const
|
||||
// {
|
||||
// return m_histogram.size ();
|
||||
// }
|
||||
|
||||
uint32_t
|
||||
Histogram::GetNBins () const
|
||||
{
|
||||
return m_histogram.size ();
|
||||
}
|
||||
|
||||
double
|
||||
Histogram::GetBinStart (uint32_t index)
|
||||
{
|
||||
return index*m_binWidth;
|
||||
}
|
||||
|
||||
double
|
||||
Histogram::GetBinEnd (uint32_t index)
|
||||
{
|
||||
return (index + 1) * m_binWidth;
|
||||
}
|
||||
|
||||
double
|
||||
Histogram::GetBinWidth (uint32_t index) const
|
||||
{
|
||||
return m_binWidth;
|
||||
}
|
||||
|
||||
void
|
||||
Histogram::SetDefaultBinWidth (double binWidth)
|
||||
{
|
||||
NS_ASSERT (m_histogram.size () == 0); //we can only change the bin width if no values were added
|
||||
m_binWidth = binWidth;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Histogram::GetBinCount (uint32_t index)
|
||||
{
|
||||
NS_ASSERT (index < m_histogram.size ());
|
||||
return m_histogram[index];
|
||||
}
|
||||
|
||||
void
|
||||
Histogram::AddValue (double value)
|
||||
{
|
||||
uint32_t index = floor (value/m_binWidth);
|
||||
|
||||
//check if we need to resize the vector
|
||||
NS_LOG_DEBUG ("AddValue: index=" << index << ", m_histogram.size()=" << m_histogram.size ());
|
||||
|
||||
if (index >= m_histogram.size ())
|
||||
{
|
||||
m_histogram.resize (index + 1, 0);
|
||||
}
|
||||
m_histogram[index]++;
|
||||
}
|
||||
|
||||
Histogram::Histogram (double binWidth)
|
||||
{
|
||||
m_binWidth = binWidth;
|
||||
}
|
||||
|
||||
Histogram::Histogram ()
|
||||
{
|
||||
Histogram (DEFAULT_BIN_WIDTH);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Histogram::SerializeToXmlStream (std::ostream &os, int indent, std::string elementName) const
|
||||
{
|
||||
#define INDENT(level) for (int __xpto = 0; __xpto < level; __xpto++) os << ' ';
|
||||
|
||||
INDENT(indent); os << "<" << elementName // << " binWidth=\"" << m_binWidth << "\""
|
||||
<< " nBins=\"" << m_histogram.size () << "\""
|
||||
<< " >\n";
|
||||
indent += 2;
|
||||
|
||||
#if 1 // two alternative forms of representing bin data, one more verbose than the other one
|
||||
for (uint32_t index = 0; index < m_histogram.size (); index++)
|
||||
{
|
||||
if (m_histogram[index])
|
||||
{
|
||||
INDENT(indent);
|
||||
os << "<bin"
|
||||
<< " index=\"" << (index) << "\""
|
||||
<< " start=\"" << (index*m_binWidth) << "\""
|
||||
<< " width=\"" << m_binWidth << "\""
|
||||
<< " count=\"" << m_histogram[index] << "\""
|
||||
<< " />\n";
|
||||
}
|
||||
}
|
||||
#else
|
||||
INDENT(indent + 2);
|
||||
for (uint32_t index = 0; index < m_histogram.size (); index++)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
os << " ";
|
||||
}
|
||||
os << m_histogram[index];
|
||||
}
|
||||
os << "\n";
|
||||
#endif
|
||||
indent -= 2;
|
||||
INDENT(indent); os << "</" << elementName << ">\n";
|
||||
#undef INDENT
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "ns3/test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class HistogramTest : public ns3::Test {
|
||||
private:
|
||||
public:
|
||||
HistogramTest ();
|
||||
virtual bool RunTests (void);
|
||||
|
||||
|
||||
};
|
||||
|
||||
HistogramTest::HistogramTest ()
|
||||
: ns3::Test ("Histogram")
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
HistogramTest::RunTests (void)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
Histogram h0(3.5);
|
||||
// Testing floating-point bin widths
|
||||
{
|
||||
for (int i=1; i<= 10; i++) h0.AddValue(3.4);
|
||||
for (int i=1; i<= 5; i++) h0.AddValue(3.6);
|
||||
|
||||
NS_TEST_ASSERT_EQUAL (h0.GetBinWidth (0), 3.5);
|
||||
NS_TEST_ASSERT_EQUAL (h0.GetNBins (), 2);
|
||||
NS_TEST_ASSERT_EQUAL (h0.GetBinStart(1), 3.5);
|
||||
NS_TEST_ASSERT_EQUAL (h0.GetBinCount(0), 10);
|
||||
NS_TEST_ASSERT_EQUAL (h0.GetBinCount(1), 5);
|
||||
}
|
||||
|
||||
{
|
||||
// Testing bin expansion
|
||||
h0.AddValue(74.3);
|
||||
|
||||
NS_TEST_ASSERT_EQUAL (h0.GetNBins (), 22);
|
||||
|
||||
/*for (uint32_t i=0; i < h0.GetSize () ; i++)
|
||||
{
|
||||
std::cout << i << ") BinStart:" << h0.GetBinStart (i) << " BinEnd:" << ((double) h0.GetBinStart (i) + h0.GetBinWidth (i)) << " BinCount: " << h0.GetBinCount (i) << std::endl;
|
||||
}*/
|
||||
|
||||
NS_TEST_ASSERT_EQUAL (h0.GetBinCount (21), 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HistogramTest gHistogramTest;
|
||||
|
||||
}; // namespace
|
||||
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
|
||||
64
src/contrib/flow-monitor/histogram.h
Normal file
64
src/contrib/flow-monitor/histogram.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* -*- 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: Pedro Fortuna <pedro.fortuna@inescporto.pt> <pedro.fortuna@gmail.com>
|
||||
//
|
||||
|
||||
#ifndef __NS3_HISTOGRAM_H__
|
||||
#define __NS3_HISTOGRAM_H__
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <ostream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Histogram
|
||||
{
|
||||
public:
|
||||
|
||||
// --- basic methods ---
|
||||
Histogram (double binWidth);
|
||||
Histogram ();
|
||||
|
||||
// Methods for Getting the Histogram Results
|
||||
uint32_t GetNBins () const;
|
||||
double GetBinStart (uint32_t index);
|
||||
double GetBinEnd (uint32_t index);
|
||||
double GetBinWidth (uint32_t index) const;
|
||||
void SetDefaultBinWidth (double binWidth);
|
||||
uint32_t GetBinCount (uint32_t index);
|
||||
|
||||
// Method for adding values
|
||||
void AddValue (double value);
|
||||
|
||||
|
||||
void SerializeToXmlStream (std::ostream &os, int indent, std::string elementName) const;
|
||||
|
||||
// TODO: add method(s) to estimate N, µ, and s² from the histogram,
|
||||
// see http://www.dspguide.com/ch2/4.htm
|
||||
|
||||
private:
|
||||
std::vector<uint32_t> m_histogram;
|
||||
double m_binWidth;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
|
||||
203
src/contrib/flow-monitor/ipv4-flow-classifier.cc
Normal file
203
src/contrib/flow-monitor/ipv4-flow-classifier.cc
Normal file
@@ -0,0 +1,203 @@
|
||||
/* -*- 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 "ns3/packet.h"
|
||||
|
||||
#include "ipv4-flow-classifier.h"
|
||||
#include "ns3/udp-header.h"
|
||||
#include "ns3/tcp-header.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/* see http://www.iana.org/assignments/protocol-numbers */
|
||||
const uint8_t TCP_PROT_NUMBER = 6;
|
||||
const uint8_t UDP_PROT_NUMBER = 17;
|
||||
|
||||
|
||||
|
||||
bool operator < (const Ipv4FlowClassifier::FiveTuple &t1,
|
||||
const Ipv4FlowClassifier::FiveTuple &t2)
|
||||
{
|
||||
if (t1.sourceAddress < t2.sourceAddress)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (t1.sourceAddress != t2.sourceAddress)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t1.destinationAddress < t2.destinationAddress)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (t1.destinationAddress != t2.destinationAddress)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t1.protocol < t2.protocol)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (t1.protocol != t2.protocol)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t1.sourcePort < t2.sourcePort)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (t1.sourcePort != t2.sourcePort)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t1.destinationPort < t2.destinationPort)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (t1.destinationPort != t2.destinationPort)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator == (const Ipv4FlowClassifier::FiveTuple &t1,
|
||||
const Ipv4FlowClassifier::FiveTuple &t2)
|
||||
{
|
||||
return (t1.sourceAddress == t2.sourceAddress &&
|
||||
t1.destinationAddress == t2.destinationAddress &&
|
||||
t1.protocol == t2.protocol &&
|
||||
t1.sourcePort == t2.sourcePort &&
|
||||
t1.destinationPort == t2.destinationPort);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ipv4FlowClassifier::Ipv4FlowClassifier ()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Ipv4FlowClassifier::Classify (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload,
|
||||
uint32_t *out_flowId, uint32_t *out_packetId)
|
||||
{
|
||||
if (ipHeader.GetDestination () == Ipv4Address::GetBroadcast ())
|
||||
{
|
||||
// we are not prepared to handle broadcast yet
|
||||
return false;
|
||||
}
|
||||
|
||||
FiveTuple tuple;
|
||||
tuple.sourceAddress = ipHeader.GetSource ();
|
||||
tuple.destinationAddress = ipHeader.GetDestination ();
|
||||
tuple.protocol = ipHeader.GetProtocol ();
|
||||
|
||||
switch (tuple.protocol)
|
||||
{
|
||||
case UDP_PROT_NUMBER:
|
||||
{
|
||||
UdpHeader udpHeader;
|
||||
ipPayload->PeekHeader (udpHeader);
|
||||
tuple.sourcePort = udpHeader.GetSourcePort ();
|
||||
tuple.destinationPort = udpHeader.GetDestinationPort ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TCP_PROT_NUMBER:
|
||||
{
|
||||
TcpHeader tcpHeader;
|
||||
ipPayload->PeekHeader (tcpHeader);
|
||||
tuple.sourcePort = tcpHeader.GetSourcePort ();
|
||||
tuple.destinationPort = tcpHeader.GetDestinationPort ();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// try to insert the tuple, but check if it already exists
|
||||
std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert
|
||||
= m_flowMap.insert (std::pair<FiveTuple, FlowId> (tuple, 0));
|
||||
|
||||
// if the insertion succeeded, we need to assign this tuple a new flow identifier
|
||||
if (insert.second)
|
||||
{
|
||||
insert.first->second = GetNewFlowId ();
|
||||
}
|
||||
|
||||
*out_flowId = insert.first->second;
|
||||
*out_packetId = ipHeader.GetIdentification ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Ipv4FlowClassifier::FiveTuple
|
||||
Ipv4FlowClassifier::FindFlow (FlowId flowId) const
|
||||
{
|
||||
for (std::map<FiveTuple, FlowId>::const_iterator
|
||||
iter = m_flowMap.begin (); iter != m_flowMap.end (); iter++)
|
||||
{
|
||||
if (iter->second == flowId)
|
||||
{
|
||||
return iter->first;
|
||||
}
|
||||
}
|
||||
NS_FATAL_ERROR ("Could not find the flow with ID " << flowId);
|
||||
FiveTuple retval = { Ipv4Address::GetZero (), Ipv4Address::GetZero (), 0, 0, 0 };
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4FlowClassifier::SerializeToXmlStream (std::ostream &os, int indent) const
|
||||
{
|
||||
#define INDENT(level) for (int __xpto = 0; __xpto < level; __xpto++) os << ' ';
|
||||
|
||||
INDENT(indent); os << "<Ipv4FlowClassifier>\n";
|
||||
|
||||
indent += 2;
|
||||
for (std::map<FiveTuple, FlowId>::const_iterator
|
||||
iter = m_flowMap.begin (); iter != m_flowMap.end (); iter++)
|
||||
{
|
||||
INDENT(indent);
|
||||
os << "<Flow flowId=\"" << iter->second << "\""
|
||||
<< " sourceAddress=\"" << iter->first.sourceAddress << "\""
|
||||
<< " destinationAddress=\"" << iter->first.destinationAddress << "\""
|
||||
<< " protocol=\"" << int(iter->first.protocol) << "\""
|
||||
<< " sourcePort=\"" << iter->first.sourcePort << "\""
|
||||
<< " destinationPort=\"" << iter->first.destinationPort << "\""
|
||||
<< " />\n";
|
||||
}
|
||||
|
||||
indent -= 2;
|
||||
INDENT(indent); os << "</Ipv4FlowClassifier>\n";
|
||||
|
||||
#undef INDENT
|
||||
}
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
74
src/contrib/flow-monitor/ipv4-flow-classifier.h
Normal file
74
src/contrib/flow-monitor/ipv4-flow-classifier.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* -*- 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>
|
||||
//
|
||||
|
||||
#ifndef __IPV4_FLOW_CLASSIFIER_H__
|
||||
#define __IPV4_FLOW_CLASSIFIER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
|
||||
#include "ns3/ipv4-header.h"
|
||||
#include "ns3/flow-classifier.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Packet;
|
||||
|
||||
class Ipv4FlowClassifier : public FlowClassifier
|
||||
{
|
||||
public:
|
||||
|
||||
struct FiveTuple
|
||||
{
|
||||
Ipv4Address sourceAddress;
|
||||
Ipv4Address destinationAddress;
|
||||
uint8_t protocol;
|
||||
uint16_t sourcePort;
|
||||
uint16_t destinationPort;
|
||||
};
|
||||
|
||||
Ipv4FlowClassifier ();
|
||||
|
||||
/// \brief try to classify the packet into flow-id and packet-id
|
||||
/// \return true if the packet was classified, false if not (i.e. it
|
||||
/// does not appear to be part of a flow).
|
||||
bool Classify (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload,
|
||||
uint32_t *out_flowId, uint32_t *out_packetId);
|
||||
|
||||
/// Searches for the FiveTuple corresponding to the given flowId
|
||||
FiveTuple FindFlow (FlowId flowId) const;
|
||||
|
||||
virtual void SerializeToXmlStream (std::ostream &os, int indent) const;
|
||||
|
||||
private:
|
||||
|
||||
std::map<FiveTuple, FlowId> m_flowMap;
|
||||
|
||||
};
|
||||
|
||||
|
||||
bool operator < (const Ipv4FlowClassifier::FiveTuple &t1, const Ipv4FlowClassifier::FiveTuple &t2);
|
||||
bool operator == (const Ipv4FlowClassifier::FiveTuple &t1, const Ipv4FlowClassifier::FiveTuple &t2);
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
|
||||
178
src/contrib/flow-monitor/ipv4-flow-probe.cc
Normal file
178
src/contrib/flow-monitor/ipv4-flow-probe.cc
Normal file
@@ -0,0 +1,178 @@
|
||||
/* -*- 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 "ns3/ipv4-flow-probe.h"
|
||||
#include "ns3/ipv4-flow-classifier.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/flow-monitor.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/pointer.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("Ipv4FlowProbe");
|
||||
|
||||
|
||||
Ipv4FlowProbe::~Ipv4FlowProbe ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Ipv4FlowProbe::Ipv4FlowProbe (Ptr<FlowMonitor> monitor,
|
||||
Ptr<Ipv4FlowClassifier> classifier,
|
||||
Ptr<Node> node)
|
||||
: FlowProbe (monitor),
|
||||
m_classifier (classifier)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << node->GetId ());
|
||||
|
||||
Ptr<Ipv4L3Protocol> ipv4 = node->GetObject<Ipv4L3Protocol> ();
|
||||
|
||||
if (!ipv4->TraceConnectWithoutContext ("SendOutgoing",
|
||||
MakeCallback (&Ipv4FlowProbe::SendOutgoingLogger, Ptr<Ipv4FlowProbe> (this))))
|
||||
{
|
||||
NS_FATAL_ERROR ("trace fail");
|
||||
}
|
||||
if (!ipv4->TraceConnectWithoutContext ("UnicastForward",
|
||||
MakeCallback (&Ipv4FlowProbe::ForwardLogger, Ptr<Ipv4FlowProbe> (this))))
|
||||
{
|
||||
NS_FATAL_ERROR ("trace fail");
|
||||
}
|
||||
if (!ipv4->TraceConnectWithoutContext ("LocalDeliver",
|
||||
MakeCallback (&Ipv4FlowProbe::ForwardUpLogger, Ptr<Ipv4FlowProbe> (this))))
|
||||
{
|
||||
NS_FATAL_ERROR ("trace fail");
|
||||
}
|
||||
|
||||
if (!ipv4->TraceConnectWithoutContext ("Drop",
|
||||
MakeCallback (&Ipv4FlowProbe::DropLogger, Ptr<Ipv4FlowProbe> (this))))
|
||||
{
|
||||
NS_FATAL_ERROR ("trace fail");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4FlowProbe::SendOutgoingLogger (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
|
||||
{
|
||||
FlowId flowId;
|
||||
FlowPacketId packetId;
|
||||
|
||||
if (m_classifier->Classify (ipHeader, ipPayload, &flowId, &packetId))
|
||||
{
|
||||
uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
|
||||
NS_LOG_DEBUG ("ReportFirstTx ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<"); "
|
||||
<< ipHeader << *ipPayload);
|
||||
m_flowMonitor->ReportFirstTx (this, flowId, packetId, size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4FlowProbe::ForwardLogger (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
|
||||
{
|
||||
FlowId flowId;
|
||||
FlowPacketId packetId;
|
||||
|
||||
if (m_classifier->Classify (ipHeader, ipPayload, &flowId, &packetId))
|
||||
{
|
||||
uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
|
||||
NS_LOG_DEBUG ("ReportForwarding ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<");");
|
||||
m_flowMonitor->ReportForwarding (this, flowId, packetId, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4FlowProbe::ForwardUpLogger (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
|
||||
{
|
||||
FlowId flowId;
|
||||
FlowPacketId packetId;
|
||||
|
||||
if (m_classifier->Classify (ipHeader, ipPayload, &flowId, &packetId))
|
||||
{
|
||||
uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
|
||||
NS_LOG_DEBUG ("ReportLastRx ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<");");
|
||||
m_flowMonitor->ReportLastRx (this, flowId, packetId, size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4FlowProbe::DropLogger (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload,
|
||||
Ipv4L3Protocol::DropReason reason, uint32_t ifIndex)
|
||||
{
|
||||
#if 0
|
||||
switch (reason)
|
||||
{
|
||||
case Ipv4L3Protocol::DROP_NO_ROUTE:
|
||||
break;
|
||||
|
||||
case Ipv4L3Protocol::DROP_TTL_EXPIRED:
|
||||
case Ipv4L3Protocol::DROP_BAD_CHECKSUM:
|
||||
Ipv4Address addri = m_ipv4->GetAddress (ifIndex);
|
||||
Ipv4Mask maski = m_ipv4->GetNetworkMask (ifIndex);
|
||||
Ipv4Address bcast = addri.GetSubnetDirectedBroadcast (maski);
|
||||
if (ipHeader.GetDestination () == bcast) // we don't want broadcast packets
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
FlowId flowId;
|
||||
FlowPacketId packetId;
|
||||
|
||||
if (m_classifier->Classify (ipHeader, ipPayload, &flowId, &packetId))
|
||||
{
|
||||
uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
|
||||
NS_LOG_DEBUG ("Drop ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<", " << reason
|
||||
<< ", destIp=" << ipHeader.GetDestination () << "); "
|
||||
<< "HDR: " << ipHeader << " PKT: " << *ipPayload);
|
||||
|
||||
DropReason myReason;
|
||||
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case Ipv4L3Protocol::DROP_TTL_EXPIRED:
|
||||
myReason = DROP_TTL_EXPIRE;
|
||||
NS_LOG_DEBUG ("DROP_TTL_EXPIRE");
|
||||
break;
|
||||
case Ipv4L3Protocol::DROP_NO_ROUTE:
|
||||
myReason = DROP_NO_ROUTE;
|
||||
NS_LOG_DEBUG ("DROP_NO_ROUTE");
|
||||
break;
|
||||
case Ipv4L3Protocol::DROP_BAD_CHECKSUM:
|
||||
myReason = DROP_BAD_CHECKSUM;
|
||||
NS_LOG_DEBUG ("DROP_BAD_CHECKSUM");
|
||||
break;
|
||||
default:
|
||||
myReason = DROP_INVALID_REASON;
|
||||
NS_FATAL_ERROR ("Unexpected drop reason code " << reason);
|
||||
}
|
||||
|
||||
m_flowMonitor->ReportDrop (this, flowId, packetId, size, myReason);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
64
src/contrib/flow-monitor/ipv4-flow-probe.h
Normal file
64
src/contrib/flow-monitor/ipv4-flow-probe.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* -*- 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>
|
||||
//
|
||||
|
||||
#ifndef __IPV4_FLOW_PROBE_H__
|
||||
#define __IPV4_FLOW_PROBE_H__
|
||||
|
||||
#include "ns3/flow-probe.h"
|
||||
#include "ns3/ipv4-flow-classifier.h"
|
||||
#include "ns3/ipv4-l3-protocol.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class FlowMonitor;
|
||||
class Node;
|
||||
|
||||
class Ipv4FlowProbe : public FlowProbe
|
||||
{
|
||||
|
||||
public:
|
||||
Ipv4FlowProbe (Ptr<FlowMonitor> monitor, Ptr<Ipv4FlowClassifier> classifier, Ptr<Node> node);
|
||||
~Ipv4FlowProbe ();
|
||||
|
||||
enum DropReason
|
||||
{
|
||||
DROP_NO_ROUTE = 0,
|
||||
DROP_TTL_EXPIRE,
|
||||
DROP_BAD_CHECKSUM,
|
||||
// DROP_QUEUE, // TODO: this is not easy to do
|
||||
DROP_INVALID_REASON,
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
void SendOutgoingLogger (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface);
|
||||
void ForwardLogger (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface);
|
||||
void ForwardUpLogger (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface);
|
||||
void DropLogger (const Ipv4Header &ipHeader, Ptr<const Packet> ipPayload,
|
||||
Ipv4L3Protocol::DropReason reason, uint32_t ifIndex);
|
||||
|
||||
Ptr<Ipv4FlowClassifier> m_classifier;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
|
||||
2
src/contrib/flow-monitor/waf
vendored
Executable file
2
src/contrib/flow-monitor/waf
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
#! /bin/sh
|
||||
exec "`dirname "$0"`"/../../../waf "$@"
|
||||
23
src/contrib/flow-monitor/wscript
Normal file
23
src/contrib/flow-monitor/wscript
Normal file
@@ -0,0 +1,23 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def build(bld):
|
||||
obj = bld.create_ns3_module('flow-monitor', ['internet-stack'])
|
||||
obj.source = [
|
||||
'flow-monitor.cc',
|
||||
'flow-classifier.cc',
|
||||
'flow-probe.cc',
|
||||
'ipv4-flow-classifier.cc',
|
||||
'ipv4-flow-probe.cc',
|
||||
'histogram.cc',
|
||||
]
|
||||
headers = bld.new_task_gen('ns3header')
|
||||
headers.module = 'flow-monitor'
|
||||
headers.source = [
|
||||
'flow-monitor.h',
|
||||
'flow-probe.h',
|
||||
'flow-classifier.h',
|
||||
'ipv4-flow-classifier.h',
|
||||
'ipv4-flow-probe.h',
|
||||
'histogram.h',
|
||||
]
|
||||
|
||||
110
src/helper/flow-monitor-helper.cc
Normal file
110
src/helper/flow-monitor-helper.cc
Normal file
@@ -0,0 +1,110 @@
|
||||
// -*- 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-helper.h"
|
||||
|
||||
#include "ns3/flow-monitor.h"
|
||||
#include "ns3/ipv4-flow-classifier.h"
|
||||
#include "ns3/ipv4-flow-probe.h"
|
||||
#include "ns3/ipv4-l3-protocol.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/node-list.h"
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
FlowMonitorHelper::FlowMonitorHelper ()
|
||||
{
|
||||
m_monitorFactory.SetTypeId ("ns3::FlowMonitor");
|
||||
}
|
||||
|
||||
void
|
||||
FlowMonitorHelper::SetMonitorAttribute (std::string n1, const AttributeValue &v1)
|
||||
{
|
||||
m_monitorFactory.Set (n1, v1);
|
||||
}
|
||||
|
||||
|
||||
Ptr<FlowMonitor>
|
||||
FlowMonitorHelper::GetMonitor ()
|
||||
{
|
||||
if (!m_flowMonitor)
|
||||
{
|
||||
m_flowMonitor = m_monitorFactory.Create<FlowMonitor> ();
|
||||
m_flowClassifier = Create<Ipv4FlowClassifier> ();
|
||||
m_flowMonitor->SetFlowClassifier (m_flowClassifier);
|
||||
}
|
||||
return m_flowMonitor;
|
||||
}
|
||||
|
||||
|
||||
Ptr<FlowClassifier>
|
||||
FlowMonitorHelper::GetClassifier ()
|
||||
{
|
||||
if (!m_flowClassifier)
|
||||
{
|
||||
m_flowClassifier = Create<Ipv4FlowClassifier> ();
|
||||
}
|
||||
return m_flowClassifier;
|
||||
}
|
||||
|
||||
|
||||
Ptr<FlowMonitor>
|
||||
FlowMonitorHelper::Install (Ptr<Node> node)
|
||||
{
|
||||
Ptr<FlowMonitor> monitor = GetMonitor ();
|
||||
Ptr<FlowClassifier> classifier = GetClassifier ();
|
||||
Ptr<Ipv4FlowProbe> probe = Create<Ipv4FlowProbe> (monitor,
|
||||
DynamicCast<Ipv4FlowClassifier> (classifier),
|
||||
node);
|
||||
return m_flowMonitor;
|
||||
}
|
||||
|
||||
|
||||
Ptr<FlowMonitor>
|
||||
FlowMonitorHelper::Install (NodeContainer nodes)
|
||||
{
|
||||
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
|
||||
{
|
||||
Ptr<Node> node = *i;
|
||||
if (node->GetObject<Ipv4L3Protocol> ())
|
||||
{
|
||||
Install (node);
|
||||
}
|
||||
}
|
||||
return m_flowMonitor;
|
||||
}
|
||||
|
||||
Ptr<FlowMonitor>
|
||||
FlowMonitorHelper::InstallAll ()
|
||||
{
|
||||
for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
|
||||
{
|
||||
Ptr<Node> node = *i;
|
||||
if (node->GetObject<Ipv4L3Protocol> ())
|
||||
{
|
||||
Install (node);
|
||||
}
|
||||
}
|
||||
return m_flowMonitor;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
56
src/helper/flow-monitor-helper.h
Normal file
56
src/helper/flow-monitor-helper.h
Normal file
@@ -0,0 +1,56 @@
|
||||
// -*- 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>
|
||||
//
|
||||
#ifndef FLOW_MONITOR_HELPER_H
|
||||
#define FLOW_MONITOR_HELPER_H
|
||||
|
||||
#include "node-container.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include "ns3/flow-monitor.h"
|
||||
#include "ns3/flow-classifier.h"
|
||||
#include <string>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class AttributeValue;
|
||||
class Ipv4FlowClassifier;
|
||||
|
||||
class FlowMonitorHelper
|
||||
{
|
||||
public:
|
||||
FlowMonitorHelper ();
|
||||
void SetMonitorAttribute (std::string n1, const AttributeValue &v1);
|
||||
|
||||
Ptr<FlowMonitor> Install (NodeContainer nodes);
|
||||
Ptr<FlowMonitor> Install (Ptr<Node> node);
|
||||
Ptr<FlowMonitor> InstallAll ();
|
||||
|
||||
Ptr<FlowMonitor> GetMonitor ();
|
||||
Ptr<FlowClassifier> GetClassifier ();
|
||||
|
||||
private:
|
||||
ObjectFactory m_monitorFactory;
|
||||
Ptr<FlowMonitor> m_flowMonitor;
|
||||
Ptr<FlowClassifier> m_flowClassifier;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
#endif /* FLOW_MONITOR_HELPER_H */
|
||||
@@ -35,6 +35,7 @@ def build(bld):
|
||||
'ipv6-list-routing-helper.cc',
|
||||
'ipv6-routing-helper.cc',
|
||||
'ping6-helper.cc',
|
||||
'flow-monitor-helper.cc',
|
||||
]
|
||||
|
||||
headers = bld.new_task_gen('ns3header')
|
||||
@@ -72,6 +73,7 @@ def build(bld):
|
||||
'ipv6-list-routing-helper.h',
|
||||
'ipv6-routing-helper.h',
|
||||
'ping6-helper.h',
|
||||
'flow-monitor-helper.h',
|
||||
]
|
||||
|
||||
env = bld.env_of_name('default')
|
||||
|
||||
@@ -38,6 +38,7 @@ all_modules = (
|
||||
'applications/v4ping',
|
||||
'applications/ping6',
|
||||
'applications/radvd',
|
||||
'contrib/flow-monitor',
|
||||
)
|
||||
|
||||
def set_options(opt):
|
||||
|
||||
Reference in New Issue
Block a user