Add a new 'flow-monitor' module.

This commit is contained in:
Gustavo J. A. M. Carneiro
2009-08-31 18:50:38 +01:00
parent 623726eeb0
commit b584261427
19 changed files with 1915 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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 */

View 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

View 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

View 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

View 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

View 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
View File

@@ -0,0 +1,2 @@
#! /bin/sh
exec "`dirname "$0"`"/../../../waf "$@"

View 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',
]

View 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

View 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 */

View File

@@ -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')

View File

@@ -38,6 +38,7 @@ all_modules = (
'applications/v4ping',
'applications/ping6',
'applications/radvd',
'contrib/flow-monitor',
)
def set_options(opt):